Skip to content

Workspace billing status runbook

Seed, inspect, observe, and roll back the provider-neutral workspace billing status page.

This runbook covers the dashboard Billing page (/{-$locale}/billing) and its provider-neutral status read model. It is status metadata only: it does not collect payment details, run checkout, enforce seats, or replace a future provider integration.

  • workspace_billing_status is a dedicated global DB_0 table. Commercial metadata is kept separate from workspace identity in entities; entities.status and entities.termination_at remain the operational lifecycle source of truth.
  • Statuses are unconfigured, trialing, active, grace_period, past_due, scheduled_cancel, and canceled.
  • The page derives an effective state of active, trial, ending, ended, or attention_required. An unconfigured record is shown as Misconfigured; a read failure is shown as Unknown with retry.
  • Archived workspaces or workspaces whose termination date has passed are ended, regardless of billing status. A future termination date makes access ending and is called out beside the billing state. Billing data is retained for reference.
  • Workspace members may read the current workspace status. Workspace admins/owners may use the controlled bootstrap form on the current workspace. Superadmins may inspect and update a selected workspace from Dashboard → Admin → Workspace Settings → Billing status.
  • The server functions authorize against the authenticated workspace context. Clients cannot select another workspace through the current-workspace read function.
  1. Apply migration 0047_workspace_billing_status to DB_0 using the managed migration runner.
  2. Open the admin workspace management page, select Billing status, and load the selected workspace.
  3. Enter the provider/source label (manual is the default), plan key and name, subscription status, interval, relevant dates, cancellation intent, and optional seat counts.
  4. Save, then open the workspace Billing page and confirm the displayed derived state. Use unconfigured with blank plan fields for an intentionally unconfigured workspace.
  5. Do not put card numbers, provider secrets, or the raw provider snapshot into this form. A future provider-sync path must write the same read model through a separately reviewed server path.

Configured statuses require a plan key and plan name. Period dates are optional, but an end date before a start date is rejected. The initial feature does not change entitlements or block product operations based on seats.

Billing reads and updates use the dashboard server-function telemetry seam. Structured route metrics include the workspace ID, subscription status, effective access state, provider/source, configuration flag, and duration. Update activity is emitted as workspace.billing.status.updated with workspace_id, old_status, new_status, plan_key, effective_at, and source: "manual_admin".

  • Unknown / unavailable: check the dashboard Worker logs for source=workspace-billing and operation read or update. Confirm migration 0047 exists on publications-db-0 (DB_0). GlitchTip captures the underlying exception; retry after the binding or database issue is fixed.
  • Misconfigured: this is a valid empty state, not a database failure. Seed the status through the admin path after confirming the workspace and plan identity with the owner.
  • Past due, grace period, canceled, or ending: compare the recorded status and dates with the authoritative commercial record. The page intentionally reports the stored status and workspace lifecycle; it does not reconcile or change access policy.
  • Missing activity event: the status write remains successful, but the event failure is captured in GlitchTip and the warning is visible in Worker logs. Re-run the save after fixing the activity/AOA dependency and verify the activity trail.

Roll out additively: apply the DB_0 migration, deploy the dashboard, seed one configured and one intentionally unconfigured workspace, and verify both page states plus the route/activity logs. Keep the billing navigation entry enabled only after the migration and the read path are healthy.

To roll back the application without deleting data, deploy the previous dashboard or hide the Billing route/nav entry and disable bootstrap writes. Keep workspace_billing_status in place so stored status is available when the corrected route returns.

Only remove the table after the dashboard read/write path is disabled and any required status snapshot has been exported. Execute migrations/rollback/0047_workspace_billing_status.sql on DB_0; it drops the billing indexes/table and does not alter entities or workspace lifecycle records. Re-apply the additive migration before re-enabling the feature.

Provider webhooks, reconciliation jobs, checkout, invoices, and a dedicated billing Worker are future work. If signed callbacks or reconciliation are introduced, add a billing-ingress Worker that writes this same read model and preserves the event contract before changing the dashboard DTO.