xtablo-source/docs/superpowers/plans/2026-03-24-no-plan-subscription-gate.md
2026-03-24 21:41:38 +01:00

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_expired from no_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.tsx or 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_plan is 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 test and any focused @xtablo/main test suites touched by this work.

  • Summarize any remaining warnings separately from pass/fail results.