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.
- Restructure operator sidebar into a flat task list with indented
children; fold plan topology into plan ladders
- Expand member catalog non-plan section to all published non-tier
products; require recurring Stripe-mapped prices for purchase
- Add operator domains placements and terminal-claims ledger; redirect
/domains to the FedWiki Sites Domains anchor
- Apply canonical vocabulary and chrome/form conventions; migrate seeded
FedWiki Sites display name
- 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
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.
Put the fedwiki chain (init, render, farm, caddy) behind a fedwiki
compose profile symmetric with discourse's; the default composition is
neither, selected via COMPOSE_PROFILES in test/.env, so a default stack
no longer binds host 443.
Guard every script and walkthrough on service presence: shared
skipUnlessIntegrationEndpointReachable helper, seed-stack presence
checks (also repairing its unsourced .env and container-native render
invocation), generic root-owned testdata reclaim in teardown, discourse
coverage in verify-stack-isolation, and fedwiki's 8090 base in the port
probe.
Update stack docs and finalize status bookkeeping for all three
changes; archives the test-stack-integration-profiles change.
Guard cluster-global CREATE ROLE in all five migration streams with
pg_roles checks so multiple databases can migrate in one cluster, and
tolerate still-referenced roles on Down.
Add test/reset-test-db.sh to drop and recreate member_console_test and
member_console_e2e per run, emit their DSNs from bootstrap, and add a
make test target that resets then runs the suite serialized; parallel
unit packages sharing one database still interfered even after the e2e
split.
Fix customdomain_db_test.go, stale since 0affda7 and previously passing
only through pollution. Bootstrap and the Makefile carry small forward
references to the compose-profile knob introduced next.
Archives the test-db-isolation change.
Run Docker runtime stage as non-root user app (UID 65532).
Add styled full-page 404/500 error rendering for navigation requests
while preserving plain-text responses for HTMX partials.
Reuse recent unconsumed OIDC login state to avoid state mismatch on
parallel login hits, and merge resource_access in role extraction.
Re-level template headings, add autocomplete tokens, and resolve
catalog resource display names.
Self-label test-stack secrets and document CSRF secret rotation.
Replace domain claims with open invoices, show monthly recurring
revenue,
count team organizations, and add more informative trend captions.
Use standard bordered cards and add a README screenshot with reversible
sample-data tooling.
Include profiled services during teardown and recover stale Compose
projects
when the generated environment file is missing.
Record claim lifecycle safeguards and mark custom domain code complete
with
only the production adoption cutover remaining.
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.
Resume only app-paused schedules so operator pauses survive restarts.
Apply dormancy handling to Discourse and FedWiki.
Remove the unused pool-scoped grant route, hide internal transition
errors, and update specs and tests to use the canonical grant endpoint.
Render grant extension controls only for active grant-backed provisions.
Scan for valid walkthrough subjects and skip when Discourse is
unreachable.
Add a fresh-stack target and document the supported e2e workflow.
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.
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.
Run group sync every minute with immediate triggering, and disable
first-post
typing heuristics that silence test users. Document how stale usernames
can
poison batch group convergence.
Classify resource keys as boolean or numeric, adapt the operator form to
the selected key, and derive rule types server-side to prevent
wrong-shape rules.
Deliver forum posting entitlements through managed group membership with
identity linkage, periodic reconciliation, webhook handling, and an
operator mapping surface.
Include fake and live test environments, setup documentation,
migrations,
and end-to-end coverage.
Preview affected orgs by position source and require keep or migrate for
default-sourced positions. Commit deletion, renumbering, and holder
reconciliation atomically while preserving other-source delivery.
Classify rank-zero changes for default ladders and require operators to
grandfather or migrate affected organizations before applying ranks.
Fix operator attribution during tier induction backfills and make the
grant
extension walkthrough's optional-form check panic-safe.
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.
Fix the rank-collision UX bug at the source.
- Append-at-end: CreatePlanLadderTier INSERT uses COALESCE(MAX(rank)+1, 0);
handler drops the rank input and template shows a drag-to-position hint.
- Renumber-on-delete: DeletePlanLadderTier renumbers remaining tiers inline
so ranks stay contiguous after deletion.
- Confirm dialog copy is now honest: deleting the top tier explicitly
promotes the next tier to the new-org default.
- Friendly errors: map duplicate-product and rank-collision constraints
to 422 field errors via web.FieldErrorsFromDB.
- All fixtures updated for append-at-end order.
Closes: openspec/changes/ladder-tier-append
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.
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.
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.
Replace absolute rank edits with a SortableJS row reorder route that
posts the
full product order and renumbers ranks transactionally with temporary
negative
values. Share the sortable initializer with topology column ordering.
- Add SortableJS drag-to-reorder for ladder columns on the topology
overview page
- Remove the manual "Sort order" input from the ladder edit form
- Add SetPlanLadderSortOrder SQL query and remove sort_order from
UpdatePlanLadder
- Update templates, CSS, specs, and tests to support the new flow
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.
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.
farm
Replace wiki-security-passportjs with wiki-security-social across
FedWiki configuration, docs, and workflows, and introduce a Caddy TLS
proxy so browser login works over HTTPS with Secure cookies. Update
Keycloak OIDC discovery URLs, OAuth2 identity mapping, and test-stack
HTTPS handling while preserving the existing owner.json and API
contracts.
Add a read-only operator surface at GET /operator/plan-topology with a
server-rendered cross-ladder grid (ladders by sort_order × ranks).
Include
shared-product detection via a new sqlc query (ListSharedTierProducts),
sticky rank-column CSS, add-on strip, org-type provisioning summary, and
a
reverse index of shared memberships. Register route/nav, add handler,
template, tests, specs, and docs.
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
Introduce shared test helpers and several operator walkthroughs:
products, plan_ladders, org_types, lookup, entitlement_sets. Add
github.com/go-rod/rod to go.mod/go.sum as an indirect dependency.
Add delivery-aware queries and wire them into server, templates,
and tests. Treat grants.status as lifecycle and use pool_provisions
joins for "currently delivering" semantics. Enable 422 validation
swaps and an error toast trigger; update docs and milestones.
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).
POST /admin/realms/{realm}/users silently drops the `id` field on
Keycloak 26.x. Switch user creation in seed-keycloak.sh to
POST /admin/realms/{realm}/partialImport, which preserves the pinned
id (verified by round-trip). This restores deterministic UUIDs for
alice/bob/carlos/diana and unblocks downstream consumers that depend
on stable `sub` claims (FedWiki owner.json references, demo seeder
person rows).
Add a fedwiki-render compose service and render.sh to resolve real
Keycloak user UUIDs and render .tpl templates into testdata on compose
up.
Convert hardcoded FedWiki testdata into templates, add seed-stack.sh
helper,
and update compose/env and .gitignore to run seeding before starting
fedwiki.