Files
member-console/status/milestones.md

27 KiB
Raw Blame History

Milestones

Completed

# Name Description
1 Governance spine Identity + organization. Person → org → workspace with auto-provisioning.
2 Grant-based FedWiki access Entitlements + minimal billing. Admin grants → numeric site limits.
3 UI/UX alignment Progressive disclosure, operator tools, validation, entitlement/product management.
4 Stripe Integration Stripe as billing execution engine. Schema, webhook pipeline, customer/product/subscription/invoice sync, operator UI. Phases 01e.

Detailed artifacts for completed milestones are in openspec/changes/archive/.


Milestone 5: Public Tier

Complete the FedWiki Public Service tier — a free entry point for any human user to explore FedWiki.

Goal: Anyone can sign up and get a working FedWiki site with appropriate limits, without requiring membership or payment.

Phase Status Name Scope
5a Done Default entitlements Capability to configure and auto-provision default grants to personal orgs on creation (e.g., 1 site, 16 MB storage).
5b Done Integration boundary Documented member-console vs. external site responsibilities; signup flow works via existing /register → IDP → AutoProvision.
5c Done Entitlement & usage UI Members see their active entitlements, limits, and usage; public products are discoverable.

MVP Checkpoint: A new user can create an account, get a personal org with a single FedWiki site (16 MB), and understand their service tier.


Milestone 6: Plan Management Foundation

Framework-level plan depth. Member-console gains first-class support for plan ladders, supersession semantics, and the operator configuration UI needed to administer plans. Builds on the structural foundations imported in design commit 732197a (plan ladders, GiST-exclusion-enforced mutual exclusion per pool per ladder) and unblocks M7's member-facing upgrade/downgrade flows.

Goal: Operators can configure plan ladders, auto-provisioning rules, and issue trials through the member-console; the member-console enforces one-active-plan-per-pool via supersession; transitions are auditable.

Phase Status Name Scope
6a Done Ladder schema Migrations for billing.plan_ladders, billing.plan_ladder_tiers, entitlements.pool_provision_ladders (composite PK, denormalized columns, GiST exclusion on tstzrange(activated_at, ended_at) WHERE status='active', AFTER UPDATE sync trigger), and entitlements.pool_provision_transitions audit table. Per Doc 31 Amendment #3: narrow billing.products.product_type domain to {addon, usage, one_time} and make it nullable (plans carry NULL; kind derived structurally via billing.product_kinds VIEW from plan_ladder_tiers membership); add lifecycle_status column (draft/published/retired).
6b Done Transition primitive Generic Transition(pool, target_tier) workflow covering initiate, upgrade, downgrade, and end using end-and-re-apply semantics (no dormant status — prior provision is ended, replacement is freshly applied). Downgrade/end paths delegate to ReapplyDefaultsForPool to re-apply the org-type default when configured. Stripe subscription.created / subscription.deleted webhook handlers delegate to the primitive with actor_type='webhook'.
6c Done Operator ladder catalog UI CRUD for plan_ladders and plan_ladder_tiers; rank reordering; product-management pages gain a "ladders this product is on" view; validation that structural invariants hold (no orphan plan products, no non-plan tiers).
6d Done Operator auto-provisioning config UI Configure default grants issued on org creation: which product, which org type, on-ladder vs off-ladder. Each operator chooses their free-tier policy through the UI rather than in seed data. Backfill action for existing orgs via ReapplyDefaultsForPool with row-level locking and idempotency.
6e Done Operator enrollment & transition tools Per-org view: current tier, transition history; manual actions (force-transition, issue trial grant, revoke). New entitlements.pool_provision_transitions audit log surfaced here.
6f Done Member tier-aware read view Minimal member-facing change: the existing entitlement UI (M5c) becomes tier-aware, showing "you are on ." Full compare/Checkout UX stays in M7.

MVP Checkpoint: An operator can configure a plan ladder with three tiers through the UI, set auto-provisioning to issue a default grant at rank 0, issue a manual trial grant at rank 1 for a test org, observe the trial supersede the default (prior provision ended; trial provision active), and watch the org-type default be re-applied via ReapplyDefaultsForPool when the trial ends. All transitions visible in the operator audit UI. No Stripe required for the checkpoint — the transition primitive is exercised end-to-end with operator-issued grants; Stripe webhook coupling is validated in 6b but end-to-end member flows land in M7.

Documentation deliverable: new docs/plan-management.md (frontmatter audience: operators) covering ladder configuration, auto-provisioning policy, manual transitions, trial grants, and enrollment audit.


Milestone 7: Operator UX Foundation

Rework the operator panel from an organically-grown SPA into a multi-page application with a coherent information architecture, design system, and accessibility baseline. Fixes accumulated UX debt (cross-tab event web, ?tab= URL hack, inconsistent form/confirm/feedback patterns) and lays the foundations every later UX milestone reuses (member-side plan catalog, upgrade/downgrade flows, network-usage views).

Goal: Operators can complete every existing capability via a discoverable, URL-addressable, accessible interface; future operator and member UX work inherits a documented design system and convention set rather than starting from scratch.

Phase Status Name Vehicle Scope
7a Done Operator surface inventory & walkthrough 7a.1 docs/operator-ux-research.md (done 2026-05-08); 7a.2 docs/operator-ux-walkthrough-evidence/; 7a.3 docs/operator-ux-walkthrough-task.md + docs/operator-ux-walkthroughs/{agent}.md Three tracks. 7a.1 Code archaeology — route + capability inventory, dependency direction, hot paths, pain-point synthesis (done). 7a.2 Deterministic capture — chrome-devtools-mcp single pass over every operator screen: screenshots, console errors, CSP violations, Lighthouse a11y/perf JSON, DOM a11y tree, tab order, forced 4xx/5xx + empty-state HTTP responses, HTMX swap timings. Reproducible after code changes; one run, no LLM judgment. 7a.3 Subjective walkthrough (multi-LLM) — briefing doc plus per-agent walkthrough outputs against a fixed rubric (visual hierarchy, copy clarity, destructive-affordance obviousness, cross-screen pattern drift, hot-path friction). Convergence/divergence across agents is signal handed to 7b/7c. No code changes.
7b Done Information architecture docs/operator-ia.md + OpenSpec change operator-ia (archived 2026-05-12 as archive/2026-05-12-operator-ia; modified operator-panel-navigation) Group capabilities by mental model rather than current tab order; define route hierarchy, breadcrumbs, default landing page. Specced because the IA is a contract future tabs have to honor.
7c Planned Design system foundation code + docs/design-system.md Component primitives (forms, tables, empty/error states, confirm modals, toasts); spacing/typography tokens; WCAG 2.1 AA baseline; CSS structure that survives across pages. No spec.
7d Planned SPA → MPA conversion OpenSpec change operator-mpa-conversion (modifies operator-panel-navigation, BREAKING ?tab=) Each capability becomes a real route under the 7b IA; hx-boost for navigation; data-switch-tab, ?tab=, mutation-event web all retired.
7e Planned Form & action patterns docs/operator-ux-conventions.md Standardize confirmation modals, destructive-action guards, inline validation, optimistic-update rules, success/failure feedback. Replace ad-hoc patterns. No spec.
7f Planned Audit & docs a11y report + final pass on docs from 7a/7b/7c/7e axe + lighthouse audit; keyboard-nav pass; convention-drift guard. Closes the milestone.

MVP Checkpoint: Opening /operator lands on a curated home with the highest-frequency tasks one click away; every existing operator capability is reachable on its own URL via the 7b IA; every page passes the 7f a11y audit; the 7c design system is documented and consistently applied.

Foundations laid for future UX work: the docs in 7a/7b/7c/7e and the design system in 7c are reused for member-side milestones (M8 plan catalog/upgrade/downgrade, M9 usage views) so member UX doesn't relitigate IA, components, or accessibility from zero.


Milestone 8: Standard Service

The core FedWiki Standard Service — cooperative membership with full hosting. Builds on the transition primitive and ladder schema from M6, the Stripe foundation from M4, and the UX foundation from M7.

Goal: Clear path from Public → Standard; members can discover, purchase, and manage their plan entirely through member-console.

Phase Status Name Scope
8a Planned Member plan catalog & comparison Members view available plans, compare tiers, see current enrollment. Reads ladders from M6a; no new schema. Invoice/payment history surfaced. Built on M7 design system.
8b Planned Upgrade flow Public → Standard via Stripe Checkout. Domain retention UX. Subscription activation delegates to the M6b transition primitive, which supersedes the default grant.
8c Planned Downgrade flow Standard → Public via subscription cancellation. Site-selection UX (1 active, others read-only), storage compliance check. Cancellation delegates to the M6b transition primitive, which re-applies the org-type default via ReapplyDefaultsForPool.

MVP Checkpoint: A Public tier member can click "Upgrade to Standard," complete Stripe Checkout, and immediately have their quotas increased to Standard limits (16 sites, 256 MB) via the M6 transition primitive. Canceling later returns them cleanly to Public tier with the org-type default re-applied via ReapplyDefaultsForPool.


Milestone 9: Network Limits & Flexible Service

Advanced capabilities for resource metering and custom requirements.

Goal: Enforce network egress limits; enable hourly-billed custom services.

Phase Status Name Scope
9a Planned Network egress metering Track egress per site/org; expose usage in UI; alerts at threshold.
9b Planned Network limit enforcement Block or throttle when limits exceeded; grace periods for Standard tier.
9c Planned Custom domain support DNS + SSL automation for Standard tier custom domains.
9d Planned Flexible service tracking Time-tracking integration; hourly billing for custom work; add-on management UI.
9e Planned Usage-based billing Metered subscriptions; pending charge → InvoiceItem sweep for overage.

Milestone 10: Integration / Extension Architecture (proposed)

Standardize how external services plug into the member-console. Today the codebase treats FedWiki as the only integration; the operator UI, template structure, and resource-key conventions all bake that assumption in. The next integrations on the horizon (NextCloud, Discourse) need a shared contract so each one is not bespoke. This milestone designs that contract and migrates FedWiki to be the first conforming integration rather than a hardcoded one.

Goal: Adding a second integration (and a third) requires only conforming to the extension contract — not reshaping the operator panel, the entitlement display layer, or the auto-provisioning flow.

Phase Status Name Scope
10a Proposed Extension model design Define the contract: integration manifest, resource-key namespacing (<integration>.<resource>), per-integration entitlement display contributions, admin-surface registration patterns, and the boundary between member-console-owned state and integration-owned state. Output is a design doc, no code.
10b Proposed Operator IA — Integrations section Move FedWiki out of the catalog/runtime tab cluster and into a dedicated Integrations section of the operator panel. Each integration is one entry; FedWiki is the first. Co-ordinated with M7's IA work — M7 reserves the URL real estate, M10b populates it.
10c Proposed FedWiki migration to extension contract Refactor FedWikiHandler / FedWikiPartialsHandler, fedwiki_sites.html templates, and FedWiki-specific resource keys (sites, storage_mb) to conform to the 10a contract. No user-visible feature change; this is the conformance work.
10d Proposed Second-integration trial Bring up one of NextCloud or Discourse as the second conforming integration. The choice depends on member-coop priorities at the time. The point of this phase is to validate the contract — anywhere the second integration cannot fit cleanly is a contract bug to fix in 10a.

MVP Checkpoint: A new external service can be added by writing an extension manifest and a small set of conforming handlers, without modifying the operator panel chrome, the entitlement display layer, or the auto-provisioning code path.

Sequencing notes: 10b depends on M7 having landed (the IA refactor needs to exist before there is a place for an "Integrations" section); 10a can begin in parallel with M7. 10c and 10d depend on 10a + 10b. Slotting M10 between M9 and backlog is provisional — it may be worth pulling earlier if the appetite for adding NextCloud or Discourse outpaces the appetite for network metering. Reorder as needed.

Milestone 11: Audit Log & Observability (proposed)

A unified story for "who did what when, and how is the system behaving while they do it." Today the member-console has no operator-action log (UX research in M7 phase 7a had to estimate frequency from code shape because there is no data) and no observability stack beyond request IDs and slog. M6a's entitlements.pool_provision_transitions was deliberately designed as a view-shaped projection of a future generic audit.log — that future is what this milestone delivers.

This milestone supersedes the "Audit trail" entry in the Backlog (which proposed an audit module with five tables, auto-logged via triggers) and absorbs the operator-action telemetry concern surfaced during M7 phase 7a (which was deferred because no immediate consumer exists). Both fold cleanly into a single architectural conversation about what gets recorded, where it lives, who reads it, and how it ages out.

Goal: Any privileged action in the member-console — operator or webhook-driven — is recorded in a queryable, retention-policied, PII-reviewed audit log. The system's runtime behavior (latency, error rates, request volume) is observable from a metrics surface. Operators can answer "who changed X on Y at time Z?" through a UI, and on-call can answer "is anything degrading right now?" from a dashboard.

Phase Status Name Scope
11a Proposed Audit log schema Design the audit log architecture — pick between (a) a single generic audit.log table with a JSON payload, (b) typed projection tables per domain (extending the pool_provision_transitions pattern), or (c) a union-view over typed tables presented as a generic log. M6a committed to the view-shape contract in option (c) for transitions; 11a confirms or revises that direction at the module level. Define record shape (resource_type, resource_id, actor_type, actor_id, action, occurred_at, recorded_at, payload), retention defaults, and the PII review checklist for each domain.
11b Proposed Auto-instrumentation middleware Middleware that writes an audit row per mutating route invocation: route, method, actor (from session), target resource (from path params), status code, request ID, timestamps. Covers operator actions, member self-service actions, and webhook-driven mutations. Subsumes the M7-7a "action-counter middleware" idea (which was deferred for lack of an immediate consumer). Existing typed projections (pool_provision_transitions, subscription_changes) continue to be written by their domain code paths; this middleware is the catch-all for everything not already covered.
11c Proposed Observability stack Pick and wire a metrics surface — request latency, error rates, per-route volume, queue depth for the Stripe outbox and Temporal workers. Stack choice (Prometheus + Grafana, OpenTelemetry, hosted, etc.) is part of 11c scope, not pre-decided here. Dashboards for ops-on-call land alongside.
11d Proposed Operator audit UI Per-resource history views: "show me everything that ever happened to this org / this product / this grant." Built on M7's design system. The per-org transition history already shipped in M6e is the first conforming consumer; 11d generalizes it to every resource type covered by 11a. Reads only — mutations belong in their domain handlers.
11e Proposed Retention, PII, alerting Retention policies per audit category (e.g., financial events vs. ephemeral lookups have different retention floors and ceilings). PII scrubbing review — audit payloads must not leak sensitive material into the log. Alerting on observability signals (error-rate spikes, queue backlog, webhook delivery failures).

MVP Checkpoint: An operator can ask "who changed entitlement X on org Y at time Z, and what was the actor's context?" through a UI and get an authoritative answer. On-call can open one dashboard and see whether the system is healthy. The action-counter need from M7 phase 7a is satisfied retroactively — frequency data exists and is queryable.

Sequencing notes: 11a is the load-bearing architectural decision; everything else depends on it. 11a can begin once M6a has landed (the pool_provision_transitions design is the existence proof for the typed-projection pattern). 11b can run in parallel with 11d, but 11d benefits from M7 being complete (audit UI lives in the operator IA M7 establishes). 11c is independent of the others and can run earlier or later depending on operational pressure. 11e is the closeout phase and depends on 11a + 11b being stable.

Open architectural questions for 11a:

  • Does the audit log live in its own schema (audit.log, etc.) or per-module? The view-shape contract suggests per-module typed tables with a generic union view; the original Backlog "Audit trail" framing assumed a single audit schema with five tables auto-logged via triggers. 11a picks.
  • Triggers vs. application-level writes. Triggers are easier to make exhaustive but harder to give meaningful actor attribution; application writes give attribution but require discipline. Most likely answer: triggers for low-level state changes, application writes for actor-bearing events. 11a confirms.
  • How do typed projections like pool_provision_transitions and subscription_changes relate to the generic log? Canonical-for-domain + projected-into-generic, or generic-canonical + typed-projection-is-a-view? M6a's design notes lean toward the former; 11a confirms or revises.

M12 — Public REST API (proposed)

Goal: Make every privileged member-console mutation reachable through a stable, documented, versioned HTTP API independent of the operator UI. Today the operator HTMX endpoints under /partials/operator/* are the only programmatic way to mutate state, and they return HTML fragments coupled to a specific UI shape — they are not an API. M12 adds a separate /api/v1/* surface intended for: external automation, CLI tooling, the M7-phase-7a seed-demo seeder (which today must use internal Go packages directly because no API exists — see proposed change member-console-demo-seeder), future external integrations beyond FedWiki, and proper contract testing.

Why this is its own milestone, not a stretch goal: an API is a permanent contract. Auth model (operator session vs API token vs OAuth client-credentials), resource shape, versioning policy, error envelope, pagination, idempotency keys, rate limiting, and OpenAPI spec generation all have to be picked deliberately. None of those decisions are reversible cheaply once external callers exist.

Why this is proposed and not next: there is no external caller queued up demanding it. The two near-term consumers — the seed-demo seeder and any internal CLI — can be served by internal-package calls. M12 unlocks future scope (external integrations, third-party migration tooling, support self-service) but is not blocking anything currently scheduled. Slot it after the platform milestones (M9 metering, M10 integrations, M11 audit) settle.

Out of scope: the operator HTMX endpoints stay as they are. M12 does NOT propose retiring them or rewiring the operator UI to consume the new API — that would conflate "build the API" with "rewrite the frontend" and double the risk. The two surfaces coexist; the operator UI continues to use HTMX partials, the API serves everyone else.

Phase Status Name Scope
12a Proposed API design & auth model OpenSpec change api-v1-design. Pick: REST vs JSON:RPC vs typed-RPC (likely REST + OpenAPI); resource hierarchy and URL shape (mirrors internal domain modules — entitlements, billing, fedwiki, etc., not the operator UI's tab structure); auth (API tokens issued through operator UI? OAuth client-credentials via Keycloak? both?); error envelope; pagination convention; idempotency key handling. Output: a design doc and a spec for /api/v1/health only — one trivial endpoint to validate the decisions before expanding the surface.
12b Proposed Catalog endpoints OpenSpec change api-v1-catalog. Read + mutate org types, products (+ Stripe mapping visibility), entitlement sets (+ rules), plan ladders (+ tiers, including the high-criticality tier-rank reorder). Mirrors operator catalog-axis screens from M7.
12c Proposed Runtime endpoints OpenSpec change api-v1-runtime. Read + mutate persons, organizations, grants (both paths — see 7a.2 finding on the grant-path radio), per-org composite view (the route 7a.1 identified as missing — at the API level too).
12d Proposed Billing & integrations endpoints OpenSpec change api-v1-billing-integrations. Read-only over Stripe-driven surfaces (accounts, subscriptions, invoices, payments) — these are mirror state, not mutable through the API. Integration endpoints (FedWiki today; shape informed by M10) for sites + provisioning workflows.
12e Proposed OpenAPI publication + client generation docs/api/openapi.yaml checked into the repo and generated/validated in CI; first official typed client (Go, generated) used by the M7-7a seed-demo seeder as proof-of-end-to-end.
12f Proposed API audit, rate limits, retention Integrate with M11's audit log; pick rate limits per auth principal; lock down public-API exposure under the same CSP/CORS posture as the operator UI.

MVP Checkpoint: An external script with an API token can: list orgs, look up the per-org composite state, issue a grant, retire a product. The seed-demo seeder is rewritten as an API client to validate end-to-end. The OpenAPI spec is published and a curl-based smoke suite runs in CI.

Sequencing notes. 12a is the load-bearing decision phase — picking auth model and error envelope wrong is the expensive mistake. 12b12d are independent within themselves and could be parallelized once 12a lands. 12e is a payoff phase that lets future agents (and the seed-demo seeder) hit the API instead of reaching into internal packages. 12f should land before any external party gets API tokens.

Relationship to M10 (Integrations). M10 designs the contract between the member-console and an integration plug-in (FedWiki, Discourse, NextCloud). M12 designs the contract between the member-console and a programmatic caller (script, CLI, tooling). These are different contracts with different audiences; they shouldn't be conflated. M10 may consume parts of M12 (an integration plug-in might call the API) but doesn't depend on it.

Open architectural questions for 12a:

  • API tokens issued through the operator UI vs OAuth client-credentials via Keycloak. The Keycloak path is already used for the Temporal SA — same pattern would extend cleanly. Operator-UI-issued tokens are friendlier for ops staff but add a parallel auth system.
  • Resource shape: domain-first (/api/v1/entitlements/sets/{id}) or UI-first (/api/v1/operator/entitlement-sets/{id}). Domain-first is the right call but the internal package boundaries don't all match clean URL segments yet.
  • Versioning: URL-path (/v1/), header, or both. Most likely path — easiest to cache and route.
  • Error envelope: RFC 7807 problem details vs custom. Probably 7807.

Backlog

Capabilities we want but don't yet fit into a milestone. Items graduate to milestones when triggered by need or capacity.

Capability Why We Want It Current Thinking
Forum integration Public tier has "community-only" support (read, no post); Standard tier unlocks posting rights. Discourse SSO + group sync based on membership status.
Backup self-service Members can restore from backup without operator intervention. Integration with backup system; point-in-time restore UI.
Site replication Standard tier can host replicas of external sites for higher availability. FedWiki farm configuration; origin→mirror sync workflow.
Voting rights management Cooperative governance — membership classes have voting rights per Bylaws. Link subscription status to voter registry; maybe separate from member-console.
Credit system Prepaid credits for Flexible services or usage-based billing. credit_grants + credit_transactions tables; apply to invoices.
Coupons & promotion codes Discounts for promotions, referrals, etc. coupon_mappings, promotion_code_mappings, sync core coupons to Stripe.
Refunds & disputes Handle customer refunds and dispute resolution. refund_mappings, dispute_mappings, bidirectional handling.
Credit application Apply credit grants to Stripe Customer Balance. Integration with Stripe Customer Balance API.
Invitations & team management Orgs can invite additional members to collaborate on sites. Organization invitations; role-based access within workspace.
Service accounts & API tokens Programmatic access to member-console APIs. Personal access tokens scoped to workspace.
Webhook integrations External systems can push/pull events from member-console. integration.webhook_events + integration_outbox.
Auth status endpoint External sites check session state to show dynamic CTAs ("Sign in" vs "Console"). GET /auth/status returning {authenticated}, CORS allowlist, parent-domain session cookie.
Hosted landing page Co-ops without a separate website get a configurable front door with tier info. Unauthenticated / renders configurable welcome page; links to /register and /login; optional pre-registration email capture.
Post-registration redirect Return users to the originating site after signup. ?return_to= param on /register, stashed in session, origin allowlist to prevent open redirect.