Governed operator lists (organizations, grants, people, billing×4) gain
server-side search, status filters, and 50-row pages with true totals
from count(*) OVER(); state is URL-addressable, out-of-range pages
clamp,
and no-match is distinct from true-empty.
People is the eighth flat sidebar entry: /operator/persons lists persons
newest-joined first (excluding the reserved system person), rows linking
to the existing detail.
Billing gains an operator invoice detail at
/operator/billing/invoices/{invoiceID} reusing the member projection;
open invoices past due present as Overdue (derived, filterable, stored
status untouched); all four views lead with the linked organization and
mute object IDs.
Grants filter over the derived Live/Superseded/Inactive state, the SQL
HAVING predicate pinned to the Go derivation by test. Embedded lists
(org composite ledger, Tier changes) adopt the shared controls under
namespaced params with sibling-state-preserving URLs and scoped htmx
swaps that hold the viewport.
Review corrections: blocked ladder Delete renders disabled with tooltip
and mutations fire toasts; collapse triggers paint their open state;
sections use outside headings; plan topology drops the orphan-product
check; domains policy collapses behind a disclosure.
Implement the ux-first-run change: a state-derived setup checklist on
/operator/setup with a landing region that recedes once required steps
are done, and empty states that distinguish blocked from empty across
operator and member surfaces. Also add production deployment and
environment reference docs, plus a config-key completeness test.
- 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
Replace product-kind branching and direct position writes with enclosed
database functions driven by structural product shape.
Migrate grant and provision data, unify operator issuance, update
subscription and expiry flows, and add migration and integration proofs.
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.
Squash the pre-production migration history into fresh core, fedwiki,
and stripe baselines and reduce the canonical source list to those
three streams.
Update sqlc configs, generated queries, raw SQL, tests, and docs while
keeping provider tables schema-qualified.
BREAKING: existing local database volumes must be wiped because goose
version history restarts from the new baselines.
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.
Add first-class default-price support: a product has a single default price
that readiness, the member catalog, and checkout all track.
- Migration 00016: is_default column + partial unique index (one default per
product) + backfill (oldest active price per product).
- New queries: GetDefaultPriceByProduct, ClearDefaultPrice, MarkDefaultPrice,
DeactivatePrice (guarded by is_default = FALSE).
- CreatePrice: first price for a product auto-becomes default (NOT EXISTS probe);
success copy differentiates auto-default from subsequent non-default prices.
- Per-row price affordances: Sync (posts price_id, hx-vals), Make default
(clear-then-set transaction), Deactivate (default-price guard).
- computePriceReadiness tracks the default price; resolvePurchasable documented
as the shared purchasability gate.
- SyncProductToStripe: selectable price (explicit price_id or default);
product-idempotent — product-synced guard prevents duplicate Stripe products.
- All error paths route through web.FieldErrorsFromDB (422) or slog+generic text,
never err.Error().
- Render tests for default badge, per-row affordance visibility, form-level
FieldErrors alert.
Closes: openspec/changes/multi-price-support
Gate Stripe readiness on real credentials, surface dead-lettered syncs
as
failed with retry, and add header-safe toast JSON encoding.
Switch the test Keycloak realm references to `test` and document the
OpenSpec change.
Provide addressable composite pages for products, plan ladders, and
entitlement sets. Rewire list/topology navigation to boosted links and
update mutation re-renders to refresh the composite body.
Enqueue product and active price mappings from the readiness panel with
guards for unconfigured, pending, and already-synced states.
Show sync/not-configured guidance, stop auto-enqueueing price syncs, and
omit empty Stripe product descriptions to avoid dead-lettering.
Add per-field validation UI (is-invalid + invalid-feedback) and
propagate FieldErrors in view models. Replace HTMX "Back" buttons with
regular links. Initialize web.New() for collecting form errors. Register
a /partials/ 404 handler to prevent accidental dashboard swaps during
HTMX partial requests.
Replace inline success alert banners with HX-Trigger-driven toasts.
Introduce fireSuccessToast helper and call it from renderers instead of
injecting Success into templates. Add backfill dry-run support and
preview
button plus UI text tweaks for org-type backfills.
Delete internal/embeds/static/operator-tabs.js and its include in
operator.html. Replace data-switch-tab triggers with plain /operator
links.
Retire legacy GET /partials/operator/* pane loaders and remove the
tabstrip
branch in templates; collapse dispatch to BodyTemplate/landing. Simplify
GetOperatorPage to 301 legacy ?tab bookmarks and update tests/openspec.
Add operator_billing.html wrapper and four GetBilling*Page handlers.
Extract loadBilling*/loadSubscriptions*/loadInvoices*/loadPaymentsData
helpers used by both legacy partial endpoints and the new pages.
Register new /operator/billing/* routes and add legacyTabRedirects
entry.
Add a no-op renderBody stub in fedwiki_partials to satisfy template
parse.