86 Commits
Author SHA1 Message Date
cgalo5758 b7a0e15574 Record Stripe environment on mappings and verify ids under the current
key
2026-09-20 01:51:45 -05:00
cgalo5758 3727ff31d8 Add entitlement set rule change ledger and preview flow
Add an append-only ledger of entitlement set rule changes with per-pool
effect rows, a preview-and-commit rule change flow, and an automatic
drain that settles deferred recomputations. Rules gain a tier reduction
policy, resource keys declare over-limit behavior, and the materializer
now lowers limits when a rule stops applying.
Add entitlement set rule change ledger and preview flow

Add an append-only ledger of entitlement set rule changes with a
preview-and-commit operator flow. Rule writes now go through an enclosed
`core.commit_rule_change` function that files an act row and one
obligation per carrying pool, with a drain workflow settling deferred
recomputations. The preview dry-runs the materializer with a rule
overlay and renders per-pool buckets, reduction-policy disclosures, and
provider over-limit consequences. Materializing transactions take a
shared advisory rendezvous that rule changes hold exclusively, enforced
by a possession assertion. Add History and Entitlement changes surfaces,
a rule-less warning on five product-selection surfaces, and a
`tier_reduction_policy` column that gates FedWiki parking.
2026-09-15 03:53:28 -05:00
cgalo5758 782ca8f326 Derive Stripe mode from API key and refine disabled controls
Derive Stripe test/live mode from the API key prefix at boot, failing on
unrecognized prefixes, and drop the separate `stripe-mode` config key.

Refine disabled controls to render through the shared `disabledControl`
part with the not-allowed cursor, and add a lint rule refusing
hand-rolled disabled buttons.

Adjust plan cards to offer no purchase control on free rungs, fix bound
checkbox Bool handling, and rename "Public/Private" to "Listed/Unlisted"
with enhanced readiness verdicts.
2026-09-13 16:59:12 -05:00
cgalo5758 ea4fee18b6 Fix five findings from security audit run 2
- Rotate the session token at the OIDC callback and restore the full
  lifetime; cap pre-auth sessions at 15 minutes and write no session
  for bare anonymous requests
- Treat db-dsn as a secret: accept db-dsn-file, log only host, port,
  database and user, and never echo a malformed DSN in an error
- Guard the logout callback with a state cookie so a forged visit
  cannot end a live session
- Collapse FedWiki site actions on a foreign tenant's domain to the
  not-found answer, as for a domain that does not exist
2026-09-09 20:53:31 -05:00
cgalo5758 0b28a9dc29 Remediate security audit findings
- Replace gorilla/csrf with net/http CrossOriginProtection
- Require valkey-password and add TLS options for session store
- End session at /logout and revoke refresh tokens
- Re-derive identity and roles from provider every five minutes
- Process each Stripe webhook event in its own Temporal workflow
- Give each outbox entry its own workflow with Temporal retries
- Guard against stale Stripe events with provider timestamps
- Derive transport security from base-url scheme
2026-09-09 13:25:43 -05:00
cgalo5758 074702c8bc Seed ledger demo via shared grant act helpers
Extract ExtendGrantTx, RevokeGrantTx, and ExpireGrantTx into
internal/entitlements so the operator handlers, expiry activity, and
demo seed all run the same conferral path. The seed plays a five-grant
history on Carlos's org; pin-timestamps now uses dense-rank offsets
and transition list ordering ties break by transition_id.
2026-09-07 00:51:49 -05:00
cgalo5758 88db730fcc Add dual licensing and SPDX headers
Introduce a commercial license option alongside AGPL-3.0-only, require a
CLA for contributors, and document the terms in COMMERCIAL.md and
NOTICE. Add a script to stamp SPDX headers on Go files and apply it
across the tree.
2026-09-06 02:29:42 -05:00
cgalo5758 e581bf81c3 Add typed config keys and config CLI
Parse every config value through a single declared type at save, boot,
and validate, and expose the settings seam from the terminal so
operators can list, set, clear, and validate overrides without SQL.
2026-09-05 17:47:04 -05:00
cgalo5758 9ff516ba95 Introduce the forms library and migrate all forms
Every form on both surfaces is now a declared FormSpec in
internal/forms, rendered through the shared form part and parsed
by its handler through the same declaration. Create and edit
share one field list, refusals answer 422 with values carried
back, and layout, buttons and errors come from one part.

Also adds the form registry with its invariant and route-mapping
tests, the raw-form, filler-copy and Go em-dash lint rules,
declared action triggers, and the capture-coverage cross-check.
The forms-library change is archived under
openspec/changes/archive/2026-09-05-forms-library.
2026-09-05 03:16:45 -05:00
cgalo5758 8608c871de Apply the acceptance fixes and archive the change (10k.4)
Six review rounds on the September walk's 40 findings, executed as the
acceptance-fixes change (design D1 to D31) and archived as
openspec/changes/archive/2026-09-03-acceptance-fixes/ with its 20
deltas synced into openspec/specs.

Shell and conventions: the location trail on every page rooted at the
surface; click-opened help popovers; buttons by role with the pressed
rule retired and tertiary openers with a rotating plus; the code chip
and white card headers; Remove versus Delete on row actions.

Operator surface: three overview tiles, one Integrations card, the
getting-started banner as the first instance setting
(core.instance_settings, migration 00015); record creation on its own
page for products, entitlement sets, and plan ladders; Visibility as
one Public checkbox; the Stripe provider page; the plan ladder
validation page retired and ranks ascending; org-types default change
with dispositions, Discard, and the settle-cloning fix; the rebuilt
composite billing card; hints instead of placeholders; the person page's
identity-provider glyph on its field labels; non-UUID ids answer 404.

Found by review and fixed: a session now ends when its person no longer
exists (the foreign-key failure on a ladder reorder after a snapshot
rebuild); the CSRF cookie lives as long as the session and its toast
says the page is out of date; htmx's settle delay is 0 app-wide.

Verification: unit suites, browser walkthroughs, the screens baseline
(31 screens, accepted), and Lighthouse at 100 on both widths, recorded
in docs/operator-a11y-baseline.md. Three stale issue entries archived.
2026-09-03 17:00:14 -05:00
cgalo5758 ee23d31c97 Complete anatomy sweep across all surfaces
Rebuild every operator, member, and integration template on the shared
page-anatomy parts, empty the lint allowlist, and move the confirm modal
into both shells. Replace back links with location trails and make row
identifiers the primary link. Make screen captures deterministic by
resetting the app database from a pinned demo snapshot. Send the logout
id_token_hint only while valid.
2026-08-31 18:11:09 -05:00
cgalo5758 408fa6f5a6 Add page anatomy parts and UI quality gate
- Add shared ui_*.html parts (pageHeader, sectionHeader, statusBadge,
  emptyState) parsed into every template set
- Add anatomy lint rules with a shrinking allowlist and screen-coverage
  check
- Add make screens capture harness with contact sheets and baseline diff
- Compose member and FedWiki regions server-side so pages arrive
  complete
- Rebuild Domains and Integrations on the parts as pilots
2026-08-30 04:05:31 -05:00
cgalo5758 dd3962990b Adopt entity keys and add invoice numbers
Replace the entity slugs on organizations, workspaces, resource pools,
and
plan ladders with nullable `key` columns and add keys to products,
prices,
and entitlement sets. Rename `providers.slug` to `provider` and add
partial
unique indexes for system and org role names.

Assign invoice numbers per billing account from a gapless transactional
counter; Stripe's number moves to the invoice mapping as an external
reference.

Seeds, fixtures, and the operator lookup address rows by key, and the
returning-login resync no longer blanks a display name when the IdP
sends
no `name` claim.
2026-08-29 20:12:04 -05:00
cgalo5758 8e3c68c6be Make UI surfaces honestly reflect system state
- Add deployment-name branding to titles, mastheads, and OG tags
- Share one grant delivery-state query with lineage across grants
  surfaces
- Show pool status/usage, org owners, and config readiness
- Make billing views projection-aware with recency and sync vocabulary
- Guard FedWiki creation without domains and render route-aware 404s
2026-08-23 01:45:52 -05:00
cgalo5758 ad7a219adf Enforce schema and boot invariants
Enforce 10j's verified gaps (schema-hardening change):

- Migration 00010: partial unique indexes for one default pool and one
  primary assignment per workspace, plus CHECKs pinning
  pool/provider/subscription vocabularies and provider lifecycle
  timestamps.
- Workspace creation shares a transactional provisioning function;
  extension validates its target pool; last-tier deletion of a defaulted
  ladder is guarded; signup completes plan-less on a broken ladder.
- Boot asserts integration slug parity and validates declared config
  enums; Stripe invoice amounts are range-checked; domain cancellation
  runs a final evidence probe; rule authoring is additive-only.
2026-08-22 18:02:46 -05:00
cgalo5758 efe3f1528d Restrict member surfaces to published products
Add lifecycle_status = 'published' to the public-catalog queries
(plans and add-ons listings) and reject checkout before any Stripe
call unless the product behind the price clears the shared member
gate (published + active + public). The currently-enrolled ladder
rung stays renderable even if its product is later drafted or
retired, fetched directly so members keep seeing what they are on.

Introduce a single evaluateMemberGate definition shared by the
catalog paths and the operator readiness panel so the surfaces
cannot disagree about what is publishable for members.
2026-08-22 12:58:05 -05:00
cgalo5758 494f25860c Stabilize demo operator walkthroughs
Configure the personal org-type default ladder and floor vacant pools so
the seeded dataset survives grant revocation. Let the modal mechanics
test
fall back to plan-ladder action triggers in full-suite order.
2026-08-01 18:53:28 -05:00
cgalo5758 6dbce6140f Type the ConfigSpec seam and move the connect target to core
Register bool and duration ConfigSpec keys from the Default's type, move
fedwiki's four sync knobs and discourse's two into their integrations'
ConfigSpecs, and replace core's read of fedwiki-custom-domain-target
with a core domains-connect-target key resolved once and threaded
through server and worker config.

Generate init's optional-integration scaffold sections from each
registered ConfigSpec instead of the hand-maintained list, and reword
the Temporal boot warning generically.

Archives the integration-config-parity change; status bookkeeping and
the verify-skill doc follow with the test-stack commit.
2026-08-01 04:13:48 -05:00
cgalo5758 c4bb1ba585 Harden domain claim expiry and carving
Sweep stranded pending claims at boot and on a Temporal schedule while
preserving evidence-based abandonment semantics.

Apply occupancy and name-policy checks to carves by operator-root owners
without affecting direct operator placements.
2026-07-25 04:10:34 -05:00
cgalo5758 c85ac6acdc Add domain claim lifecycle safeguards
Make claim windows and workspace caps configurable, and enforce
initiation
and abandonment budgets without penalizing DNS evidence or system
failures.
Add operator visibility into live claims and default verification to 24
hours.
2026-07-25 00:40:24 -05:00
cgalo5758 8d05934e93 Add domains registry with claims and placements
Domain names become an allocatable resource with one authority. A new
core module (schema `domains`, own migration stream between core and the
integrations) owns claims — a DNS node plus its whole subtree, mutually
disjoint: operator shared-domain roots, member claims carved from them,
and bring-your-own names proven by TXT verification — and placements,
which bind a name inside a claim to a provider slug and resource ref.

Verification moves to the claim and decouples from creation. A member
proves control of a domain once; afterwards every name inside it places
instantly, wildcard-CNAME friendly, with no further DNS work. The claim
workflow activates the claim and stops — it no longer creates a site —
so the sites list offers a one-click create once a domain verifies.

/domains/ask answers from placements and is registered by core rather
than the FedWiki adapter; its HTTP contract is unchanged. A configured
`domains-ask-fallback-url` forwards names the registry does not know to
a legacy answerer, the strangler seam wiki.cafe's migration needs; a
name the registry knows but has archived is refused locally.

FedWiki's create saga reserves the name before the farm call, carrying a
workflow-minted site id so retries are idempotent, and compensates on
failure. Sync places only names it owns, never stealing a member's;
lifecycle transitions and the retention purge maintain servability. An
unconditional boot pass seeds operator roots, releases orphaned
placements, and adopts pre-existing sites — grandfathering member-owned
external domains shortest-name-first, and skipping name policy, so a
live single-letter site cannot lose its certificate.

Members manage domains at /domains: claims with verification status, DNS
records including an optional wildcard row, check-now, cancel, release.
Name policy (reserved, blocked, premium, plus a single-letter guard) is
operator data; refusals collapse to a plain "unavailable" so the console
never becomes an oracle for who holds what.

BREAKING (pre-release): `fedwiki.custom_domain_verifications` and
`sites.is_custom_domain` are dropped, the flag now derived from the
placement's claim kind; resource key `fedwiki_custom_domains` migrates
to the platform-owned `external_domain_claims`; running
verify-custom-domain workflows must be terminated before deploy.
2026-07-24 21:25:40 -05:00
cgalo5758 259c935981 Unify operator integration management
List every provider kind with direct settings and admin links, move
FedWiki
under the integrations route, and add in-shell operator 404s.

Report sync health from Temporal schedule executions and clear one-shot
settings feedback parameters after display.
2026-07-23 00:14:21 -05:00
cgalo5758 296236a721 Add operator-managed integration settings
Persist non-secret ConfigSpec overrides in core and apply them at boot
ahead of environment values and defaults. Validate typed and enum
values,
show pending restart state, and remove Stripe's unused provider config
table.
2026-07-22 22:17:58 -05:00
cgalo5758 2816c1e0b0 Make member dashboard registry-driven
Render generic HTMX card shells from integration declarations. Move the
FedWiki UI into its partial, add Discourse forum status, and label
member
entitlements with provider attribution.
2026-07-21 22:50:52 -05:00
cgalo5758 1a8e13f880 Extract integrations into registered trees
Add an explicit registry with capability hooks for migrations, routes,
workflows, config, and UI assets. Move FedWiki fully and Stripe's
separable
store, workflow, and webhook pieces under internal/integrations.

Drive startup wiring from declarations, including config validation,
secret
file pairs, CSRF exemptions, UI composition, and workflow startup. Move
integration DB roles and grants into their owning migration streams, and
route outbox writes through a shared enqueue helper.
2026-07-06 11:01:07 -05:00
cgalo5758 8514df5b50 Remediate operator UX audit findings
Fix HTMX expired-session handling, CSP-blocked form behaviors, reorder
recovery, billing currency display, plan/checkout guards, FedWiki quota
edge cases, and operator/member empty/error states.

Add entitlement uniqueness migrations, canonical migration source
wiring,
and regression coverage for the remediated flows. Update status docs
with
the audit triage and model inventory.
2026-07-03 11:58:03 -05:00
cgalo5758 255c3c1afc Improve first-run auth and config setup
Seed Keycloak into a dedicated wikicafe app realm and repoint the
test OIDC, Temporal, and FedWiki wiring to it.

Label test credentials as throwaway, remove the unused realm export from
tracking, and have init write the embedded starter config.
2026-07-01 22:36:18 -05:00
cgalo5758 7bff4ac603 Validate startup config and retry Temporal
Fail fast with aggregated config errors after resolving secret files,
before services initialize. Add Valkey session config, remove the unused
session-secret, and fix the production CSP env key.

Retry initial Temporal dials with bounded backoff and gate the test
Temporal service on healthy DB and Keycloak dependencies.
2026-07-01 19:04:26 -05:00
cgalo5758 3e1290e1d0 Gate FedWiki active rotations by cooldown
Add a configurable cooldown window and route restores, reactivations,
and swaps through the same rotation check to close the archive/restore
bypass while preserving headroom and no-reserve activations.
2026-06-24 03:09:26 -05:00
cgalo5758 d0a06492e7 Ensure system tenant at boot
Create the singleton System organization/workspace by natural key and
use it
as the FedWiki sync default workspace. Remove the configured workspace
UUID
and holding-workspace seed, and cover creation/adoption with tests.
2026-06-24 01:28:12 -05:00
cgalo5758 d7839aa526 Add provider registry contract
Register FedWiki and Stripe providers at boot, persist provider
operations, and stamp owned resource keys.

Rename the FedWiki entitlement key from `sites` to `fedwiki_sites`
and drive the operator integration nav from provisioning providers.
2026-06-15 22:31:51 -05:00
cgalo5758 af8603b3cf Add billing sweep schedule and proration preview
Create Temporal billing sweep schedule, workflow and activities and
register them in the worker/start initialization. Add an HTMX preview
route and banner for plan switches (switch button now GETs a preview;
Confirm posts the switch). Extend the Stripe test mock to support
invoice previews and add integration tests for PreviewSwitch behavior.
2026-05-30 01:16:58 -05:00
cgalo5758 ee8568e28c feat(billing): reconcile Stripe subscriptions from the API
Replace the order-dependent, payload-trusting webhook fulfillment with a single
idempotent ReconcileSubscription (internal/fulfillment) that refetches
authoritative subscription state from the Stripe API and converges core records
and pool entitlements via the plan-transitions primitive. checkout.session.completed
and customer.subscription.* become thin triggers; the post-checkout return path
reconciles eagerly. This fixes paid upgrades provisioning zero entitlement, caused
by reading the empty line_items the webhook payload never carries.

- internal/fulfillment: ReconcileSubscription + ReconcileLatestSubscriptionForCustomer,
  advisory-locked, convergent/idempotent, with unit + DB-gated integration tests
- internal/stripetest: in-process stripe.Backend mock for offline reconcile tests
- thin webhook handlers; eager reconcile on /?checkout=success (best-effort)
- stripe.Key set process-wide before the Temporal worker starts (cmd/start.go)
- OpenSpec change stripe-fulfillment-reconcile; archive completed member-upgrade-flow
  now that its paid-upgrade demonstration (§5.3) is satisfied
2026-05-23 21:47:38 -05:00
cgalo5758 ed88ac8ce2 Add operator walkthrough e2e tests and lint flag 2026-05-18 03:21:09 -05:00
cgalo5758 1a1649ba53 Add operatorURL helper and template linter
Introduce cmd/lint to statically verify operator templates vs routes
(internal/lint). Replace interpolated hx-* URL strings with operatorURL
calls in partials, register operatorURL in the template FuncMap,
add server/operator_url.go with unit tests, and update go.mod.
Add routeURL helper and template linter
2026-05-18 01:36:18 -05:00
cgalo5758 9d11ee0328 Add member-console demo seeder with person seeding
Add a `seed-demo` subcommand (cmd/seed_demo.go + internal/demoseed/)
that inserts a fixed reference catalog into the member-console DB so
the operator panel has rows to walk through for UX research. Catalog:
6 demo-* products (4 by product_type + 2 extra plans), 1 plan ladder
with 3 tiers, 1 entitlement set with 2 rules (limit + boolean), and 1
grant on Alice's personal org (once she's logged in).

Person rows for bob/carlos/diana are seeded via provisioning.AutoProvision
keyed on the pinned Keycloak UUIDs — no longer fragile now that
seed-keycloak.sh's partialImport switch preserves the pinned id. Alice
is intentionally NOT pre-seeded so the lazy-creation OIDC flow stays
exercised on every fresh stack.

Idempotency: list+filter by `name` for catalog rows, by `oidc_subject`
for persons. Re-running is a no-op for created rows; warns + skips
the grant if alice hasn't logged in yet.

Host-side invocation only — run `./test/seed-demo.sh` after
bootstrap-stack.sh. Mirrors how member-console itself runs on the
host (config + secrets live under test/).

Two OpenSpec changes folded in: 2026-05-10-member-console-demo-seeder
(the seeder) and 2026-05-11-demo-seeder-persons (the persons follow-up
unlocked by the Keycloak fix).
2026-05-11 10:55:14 -05:00
cgalo5758 be91b73dbd Stripe Operator UI 2026-04-06 03:15:20 -05:00
cgalo5758 786657eea3 Start Stripe workflows and handle webhooks
Expose /webhooks/stripe as a public path (signature-verified)

Verify webhook signatures with ConstructEventWithOptions and
IgnoreAPIVersionMismatch=true, and log API version mismatches.
Start two Temporal workflows: stripe-webhook-processor and
stripe-outbox-poller; workflow start failures are non-fatal.
2026-04-05 21:25:26 -05:00
cgalo5758 1f1540d7e0 Use plain DB connection for migrations
Add ConnectPlain to open the DB without the custom search_path and
switch migration and CLI flows to run on that plain connection.
Wrap multi-statement goose migrations with StatementBegin/End to
ensure statements are executed atomically. Move Stripe price outbox
seeding into a dedicated stripe migration.
2026-04-05 18:25:05 -05:00
cgalo5758 7ef1d32529 Stripe subcription creation 2026-04-05 02:00:07 -05:00
cgalo5758 3aad9268df Stripe Billing Plumbing 2026-04-03 19:25:24 -05:00
cgalo5758 cd232130f2 Introduce per-module PostgreSQL schemas 2026-04-03 03:27:48 -05:00
cgalo5758 6330ae7a42 Grants management! 2026-03-24 17:35:14 -05:00
cgalo5758 f737dd0314 Identity and organization modules. 2026-03-23 17:28:14 -05:00
cgalo5758 5b7c2c6d2d Use session key constants and typed accessors. Fixes issues with
previous commit.
2026-02-02 22:37:06 -06:00
cgalo5758 2d579b377c Move from sqlite to postgres. 2026-02-02 22:19:16 -06:00
cgalo5758 b1282c7488 Make site ownership work correctly for fucks sake. 2026-01-01 22:07:11 -06:00
cgalo5758 c07487e324 Implement FedWiki site synchronization workflow and related configurations 2025-12-29 19:24:52 -06:00
cgalo5758 8512f368fb Implement Temporal OAuth2 authentication support and configuration 2025-12-24 16:46:54 -06:00
cgalo5758 74002e424f Rough FedWiki Site management through temporal workflows! 2025-12-18 01:05:55 -06:00