3.7 KiB
No-Plan Subscription Gate Implementation Plan
For agentic workers: REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Block app interaction when an authenticated organization has no active plan, while directing the user to checkout for Solo, Team, or Founder.
Architecture: Reuse the existing global upgrade blocker in the frontend, extending it to handle a no_plan state in addition to expired-trial blocking. Reinforce the UI gate with backend mutation guards for API-driven writes and frontend mutation guards for direct-Supabase task writes.
Tech Stack: React, TanStack Query, Hono, Supabase, Vitest
Chunk 1: Frontend global blocker
Task 1: Model the no-plan blocked state
Files:
-
Modify:
apps/main/src/contexts/UpgradeBlockContext.tsx -
Modify:
apps/main/src/hooks/stripe.ts -
Test:
apps/main/src/components/TrialUpsellModal.test.ts -
Add a failing test or helper assertions for the new no-plan blocking condition.
-
Implement a shared blocker state that distinguishes
trial_expiredfromno_plan. -
Verify blocker logic stays non-blocking for paid organizations.
Task 2: Update the blocking modal
Files:
-
Modify:
apps/main/src/components/UpgradePanel.tsx -
Test:
apps/main/src/components/TrialUpsellModal.test.ts -
Add a failing test for the no-plan upsell content if the component is already covered, otherwise cover the extracted logic.
-
Update the blocker UI copy to explain that a subscription is required and expose Solo, Team, and Founder checkout actions.
-
Keep sign-out accessible and preserve the billing-owner restriction messaging.
Task 3: Prevent task creation/update from bypassing the blocker
Files:
-
Modify:
apps/main/src/hooks/tasks.ts -
Test:
apps/main/src/pages/tablo-details.layout.test.tsxor a new focused hook/component test if needed -
Add a failing test for task mutation attempts while blocked for
no_plan. -
Short-circuit direct-Supabase task mutations with a user-facing error when the app is in the blocked state.
-
Re-run targeted frontend tests.
Chunk 2: Backend mutation guards
Task 4: Add a no-plan middleware
Files:
-
Modify:
apps/api/src/middlewares/middleware.ts -
Modify:
apps/api/src/helpers/billing.ts -
Test:
apps/api/src/__tests__/middlewares/middlewares.test.ts -
Add failing middleware tests for rejecting users whose organization has no active plan.
-
Implement a middleware that resolves organization billing state and rejects interactive writes when
active_subscription_planis missing. -
Ensure Stripe checkout routes remain exempt.
Task 5: Apply the middleware to write routes
Files:
-
Modify:
apps/api/src/routers/tablo.ts -
Modify:
apps/api/src/routers/tablo_data.ts -
Modify:
apps/api/src/routers/user.ts -
Test:
apps/api/src/__tests__/routes/tablo_data.test.ts -
Test:
apps/api/src/__tests__/routes/tablo.test.ts -
Add failing tests for no-plan users being blocked from key writes like tablo creation and file deletion/upload.
-
Apply the no-plan middleware to interactive write endpoints while leaving read-only and billing endpoints alone.
-
Verify existing paid-plan and temporary-user behaviors still pass.
Chunk 3: Verification
Task 6: Run focused and broad verification
Files:
-
No code changes
-
Run targeted frontend tests for the blocker and signup/checkout paths.
-
Run targeted API middleware/route tests for no-plan rejection.
-
Run
pnpm --filter @xtablo/api testand any focused@xtablo/maintest suites touched by this work. -
Summarize any remaining warnings separately from pass/fail results.