# 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.
