TenantAtlas/specs/274-billing-subscription-truth/tasks.md
ahmido 35b59eb628 274: Billing subscription truth - add workspace subscription model & tests (#326)
Automated PR: commit all local changes and add feature 274-billing-subscription-truth.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #326
2026-05-04 21:15:57 +00:00

16 KiB

description
Task list for Billing & Subscription Truth Layer v1

Tasks: Billing & Subscription Truth Layer v1

Input: Design documents from specs/274-billing-subscription-truth/
Prerequisites: specs/274-billing-subscription-truth/spec.md, specs/274-billing-subscription-truth/plan.md, specs/274-billing-subscription-truth/checklists/requirements.md, specs/274-billing-subscription-truth/research.md, specs/274-billing-subscription-truth/data-model.md, specs/274-billing-subscription-truth/quickstart.md, specs/274-billing-subscription-truth/contracts/workspace-billing-subscription-truth.logical.openapi.yaml

Tests: REQUIRED (Pest). Keep proof bounded to one new Unit family under tests/Unit/Entitlements/ plus focused extensions to current Feature families for system, settings, onboarding, and review-pack behavior. Operations: Reuse the existing WorkspaceCommercialLifecycleResolver and current review-pack OperationRun path. No new run type, no queue family, and no direct subscription gate outside lifecycle are allowed. RBAC: Non-members and wrong-plane actors remain 404; in-scope actors missing capability remain 403. /system owns mutation; /admin remains read-only or contextual for subscription truth. Shared Pattern Reuse: Reuse WorkspaceEntitlementResolver, WorkspaceCommercialLifecycleResolver, ViewWorkspace, WorkspaceSettings, ManagedTenantOnboardingWizard, ReviewPackService, and the current audit foundation. Do not create a second commercial control plane. Filament / Panel Guardrails: Filament remains v5 on Livewire v4. Provider registration remains unchanged in apps/platform/bootstrap/providers.php. No new panel, no new globally searchable resource, and no new asset strategy are allowed. Organization: Tasks are grouped by user story so the source-of-truth entity, lifecycle continuity, and read-only admin summary remain independently implementable and testable. This package is a bounded follow-through over Specs 247 and 251, not a billing-engine rewrite. Review Outcome: acceptable-special-case Workflow Outcome: keep Test-governance Outcome: keep

Test Governance Checklist

  • Lane assignment stays fast-feedback and confidence and remains the narrowest sufficient proof.
  • New or changed tests stay in the existing apps/platform/tests/Unit/Entitlements/, apps/platform/tests/Feature/System/, apps/platform/tests/Feature/Filament/Settings/, apps/platform/tests/Feature/Onboarding/, and apps/platform/tests/Feature/ReviewPack/ families.
  • Shared helpers stay cheap by default; only one new factory is expected.
  • Planned validation commands cover subscription truth, lifecycle precedence, admin summary, and gate continuity without widening into browser or heavy-governance lanes.
  • The declared surface test profile remains standard-native-filament, shared-detail-family, and monitoring-state-page only.
  • Any drift toward providers, invoices, a portal, or a second runtime gate resolves as reject-or-split, not hidden scope.

Phase 1: Setup (Shared Context)

Purpose: Confirm the current commercial truth seams before any implementation change.

  • T001 Review specs/274-billing-subscription-truth/spec.md, specs/274-billing-subscription-truth/plan.md, specs/274-billing-subscription-truth/checklists/requirements.md, specs/274-billing-subscription-truth/research.md, specs/274-billing-subscription-truth/data-model.md, specs/274-billing-subscription-truth/quickstart.md, specs/247-plans-entitlements-billing-readiness/spec.md, and specs/251-commercial-entitlements-billing-state/spec.md together so the slice stays on the current commercial foundations.
  • T002 [P] Confirm the current lifecycle and admin/system surface seams in apps/platform/app/Filament/System/Pages/Directory/ViewWorkspace.php and apps/platform/app/Filament/Pages/Settings/WorkspaceSettings.php.
  • T003 [P] Confirm the current runtime gate seams in apps/platform/app/Services/Entitlements/WorkspaceCommercialLifecycleResolver.php, apps/platform/app/Filament/Pages/Workspaces/ManagedTenantOnboardingWizard.php, and apps/platform/app/Services/ReviewPackService.php.
  • T004 [P] Confirm the current audit and authorization seams in apps/platform/app/Services/Audit/WorkspaceAuditLogger.php, apps/platform/app/Support/Auth/PlatformCapabilities.php, and apps/platform/app/Services/Settings/SettingsWriter.php.

Phase 2: Foundational (Blocking Prerequisites)

Purpose: Lock the new persisted source of truth and shared mapping before surface changes begin.

Critical: No user-story work should begin until this phase is complete.

  • T005 [P] Add failing unit coverage in apps/platform/tests/Unit/Entitlements/WorkspaceSubscriptionResolverTest.php and extend apps/platform/tests/Unit/Entitlements/WorkspaceCommercialLifecycleResolverTest.php to prove state validation, lifecycle mapping, fallback precedence, and review-required date behavior.
  • T006 [P] Extend apps/platform/tests/Feature/System/ViewWorkspaceEntitlementsTest.php, apps/platform/tests/Feature/System/Spec113/AuthorizationSemanticsTest.php, and apps/platform/tests/Feature/Filament/Settings/WorkspaceEntitlementsSettingsPageTest.php to lock the system mutation surface, admin read-only summary, and plane semantics.
  • T007 [P] Extend apps/platform/tests/Feature/Onboarding/ManagedTenantOnboardingEntitlementTest.php, apps/platform/tests/Feature/ReviewPack/ReviewPackEntitlementEnforcementTest.php, and apps/platform/tests/Feature/ReviewPack/ReviewPackGenerationTest.php to prove subscription-backed lifecycle continuity and no-run behavior on blocked starts.
  • T008 Create apps/platform/database/migrations/*_create_workspace_subscriptions_table.php, apps/platform/app/Models/WorkspaceSubscription.php, apps/platform/database/factories/WorkspaceSubscriptionFactory.php, and the Workspace relation so one current subscription record exists per workspace.
  • T009 Implement apps/platform/app/Services/Entitlements/WorkspaceSubscriptionResolver.php to expose current subscription summary, fallback status, next relevant date, and derived lifecycle mapping.
  • T010 Refactor apps/platform/app/Services/Entitlements/WorkspaceCommercialLifecycleResolver.php so subscription truth becomes the upstream lifecycle source when present and existing manual lifecycle state remains the fallback when absent.

Checkpoint: One persisted current subscription source exists and the shared lifecycle resolver can consume it without changing any surface yet.


Phase 3: User Story 1 - Record one current workspace subscription truth centrally (Priority: P1)

Goal: Authorized platform users can create or update one current subscription record from the existing system workspace detail page.

Independent Test: Open the system workspace detail page, save subscription truth, and verify summary plus audit output update without touching onboarding or review-pack flows.

Tests for User Story 1

  • T011 [P] [US1] Extend apps/platform/tests/Feature/System/ViewWorkspaceEntitlementsTest.php to prove create, update, validation, explicit confirmation, fallback visibility, and derived lifecycle rendering on the system page.
  • T012 [P] [US1] Extend apps/platform/tests/Feature/System/Spec113/AuthorizationSemanticsTest.php to prove wrong-plane or non-member requests remain 404 and in-scope actors missing the dedicated capability remain 403.

Implementation for User Story 1

  • T013 [US1] Update apps/platform/app/Filament/System/Pages/Directory/ViewWorkspace.php so the page renders current subscription truth, derived lifecycle, next relevant date, stale-date needs-review visibility, and one bounded confirmation-protected Update subscription truth action.
  • T014 [US1] Extend apps/platform/app/Services/Audit/WorkspaceAuditLogger.php and related audit metadata so subscription changes are attributable with old state, new state, actor, and status reason.
  • T015 [US1] Narrow or hide the existing manual lifecycle mutation affordance on the system page whenever a current subscription record exists, preserving the existing confirmation-protected Change commercial state action only as explicit fallback behavior when no subscription record is present.

Checkpoint: The system workspace detail page becomes the one durable commercial source surface.


Phase 4: User Story 2 - Keep current runtime gates but source them from subscription truth when present (Priority: P1)

Goal: Existing onboarding and review-pack behavior remains on one lifecycle gate while subscription-backed workspaces stop relying on manual lifecycle state.

Independent Test: Seed one subscription-backed workspace and one fallback workspace, then confirm both current gate families still use one lifecycle decision with the correct source and no second gate.

Tests for User Story 2

  • T016 [P] [US2] Extend apps/platform/tests/Feature/Onboarding/ManagedTenantOnboardingEntitlementTest.php to prove subscription-backed lifecycle mapping, fallback continuity, and business-state messaging on the completion step.
  • T017 [P] [US2] Extend apps/platform/tests/Feature/ReviewPack/ReviewPackEntitlementEnforcementTest.php, apps/platform/tests/Feature/ReviewPack/ReviewPackGenerationTest.php, apps/platform/tests/Feature/ReviewPack/ReviewPackDownloadTest.php, and apps/platform/tests/Feature/Reviews/CustomerReviewWorkspacePackAccessTest.php to prove subscription-backed lifecycle mapping, no-run behavior on blocked starts, suppressed queued or terminal notifications when blocked, unchanged queued-start UX when allowed, and unchanged current pack view or download access.

Implementation for User Story 2

  • T018 [US2] Update apps/platform/app/Filament/Pages/Workspaces/ManagedTenantOnboardingWizard.php so the current completion summary identifies subscription-backed versus fallback lifecycle truth without adding direct subscription checks.
  • T019 [US2] Update apps/platform/app/Services/ReviewPackService.php and any current review-pack start helpers so the existing lifecycle gate consumes the new source but keeps current start semantics unchanged.
  • T020 [US2] Review all in-scope gate surfaces and remove any local or duplicate subscription-state checks so lifecycle remains the only runtime gate.

Checkpoint: Subscription truth changes the upstream lifecycle source only; runtime gates stay singular and unchanged in shape.


Phase 5: User Story 3 - Show a read-only commercial summary on workspace settings (Priority: P2)

Goal: Workspace operators can inspect the current commercial posture without gaining billing controls.

Independent Test: Open workspace settings as an authorized member and verify the summary shows subscription-backed or fallback-backed truth, the next relevant date, and no mutation controls.

Tests for User Story 3

  • T021 [P] [US3] Extend apps/platform/tests/Feature/Filament/Settings/WorkspaceEntitlementsSettingsPageTest.php to prove the new read-only subscription summary, fallback indicator, and absence of admin-plane mutation controls.

Implementation for User Story 3

  • T022 [US3] Update apps/platform/app/Filament/Pages/Settings/WorkspaceSettings.php so the existing page renders the read-only subscription summary using the shared resolver output.
  • T023 [US3] Confirm the admin-plane summary stays read-only and does not create a second commercial mutation surface or local commercial vocabulary.

Checkpoint: Workspace operators can understand the current posture without inheriting a new billing UI.


Phase 6: Polish & Cross-Cutting Validation

Purpose: Validate the bounded slice and stop without widening scope.

  • T024 [P] Run export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Entitlements/WorkspaceSubscriptionResolverTest.php tests/Unit/Entitlements/WorkspaceCommercialLifecycleResolverTest.php.
  • T025 [P] Run export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/System/ViewWorkspaceEntitlementsTest.php tests/Feature/System/Spec113/AuthorizationSemanticsTest.php tests/Feature/Filament/Settings/WorkspaceEntitlementsSettingsPageTest.php.
  • T026 [P] Run export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Onboarding/ManagedTenantOnboardingEntitlementTest.php tests/Feature/ReviewPack/ReviewPackEntitlementEnforcementTest.php tests/Feature/ReviewPack/ReviewPackGenerationTest.php tests/Feature/ReviewPack/ReviewPackDownloadTest.php tests/Feature/Reviews/CustomerReviewWorkspacePackAccessTest.php.
  • T027 [P] Run export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent.
  • T028 [P] Review touched code to confirm Filament stays on Livewire v4, provider registration remains unchanged in apps/platform/bootstrap/providers.php, no globally searchable resource is added, no asset strategy changes appear, and no second runtime gate slipped in.
  • T029 [P] Record the final guardrail and test-governance outcome in the active feature close-out without reopening provider sync, invoices, portal work, or a second control plane.

Dependencies & Execution Order

Phase Dependencies

  • Phase 1 (Setup): no dependencies; start immediately.
  • Phase 2 (Foundational): depends on Phase 1 and blocks all user stories.
  • Phase 3 (US1): depends on Phase 2 and establishes the durable source of truth.
  • Phase 4 (US2): depends on Phase 2 and should land with US1 so the new source and current runtime gates stay aligned.
  • Phase 5 (US3): depends on Phase 2 and should land after US1 so the admin summary consumes the finished shared resolver.
  • Phase 6 (Polish): depends on all desired user stories being complete.

User Story Dependencies

  • US1 (P1): independently testable after Phase 2 and delivers the central source-of-truth surface.
  • US2 (P1): independently testable after Phase 2 and should ship with US1 so subscription truth actually changes runtime source.
  • US3 (P2): independently testable after Phase 2 and can follow US1 once the shared resolver output is stable.

Within Each User Story

  • Write the listed Pest coverage first and make it fail for the intended gap.
  • Keep implementation inside the current model, resolver, system page, settings page, onboarding, review-pack, and audit seams named above.
  • Re-run the narrowest relevant validation command after each story checkpoint before moving on.

Implementation Strategy

Suggested MVP Scope

  • MVP = US1 + US2 together. The feature is only useful when a current subscription source exists and the existing lifecycle gate actually consumes it.

Incremental Delivery

  1. Complete Phase 1 and Phase 2.
  2. Deliver US1 so the durable source and system mutation surface exist.
  3. Deliver US2 so current gates become subscription-backed where appropriate.
  4. Add US3 as the read-only admin summary.
  5. Finish with the focused validation and drift-review tasks in Phase 6.

Team Strategy

  1. Settle persistence and resolver shape first.
  2. Parallelize failing tests within each story before runtime edits.
  3. Serialize merges around ViewWorkspace, WorkspaceCommercialLifecycleResolver, and WorkspaceSettings so the commercial vocabulary stays coherent.

Deferred Follow-Ups / Non-Goals

  • payment-provider or webhook synchronization
  • invoice or payment ledger persistence
  • customer-facing billing portal or workspace self-serve billing controls
  • schedule-driven trial or period-end transitions
  • a historical subscription browser or multi-record billing timeline