Skip to content

Commit 2ddc5dc

Browse files
committed
Merge feature/stripe-monetization into main
2 parents d6679cb + 8c3531a commit 2ddc5dc

37 files changed

Lines changed: 2801 additions & 307 deletions

‎CLAUDE.md‎

Lines changed: 176 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,26 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Project Overview
66

7-
DebateLab is an AI-powered debate preparation suite. It uses **Supabase Edge Functions** as the backend for all AI calls (keys are never exposed to the browser). Authentication is via Supabase Auth with Google OAuth.
7+
DebateLab is an AI-powered debate preparation suite for competitive debaters. It combines multiple AI providers (OpenAI, Google Gemini, Anthropic) with real-time web research via Jina AI. Uses **Supabase Edge Functions** as the backend so API keys are never exposed to the browser. Authentication is via Supabase Auth with Google OAuth.
88

99
**Live URL:** https://debate.pi-stack.org
10+
**Hosting:** Raspberry Pi + Docker + Cloudflare Tunnel
11+
12+
## Tech Stack
13+
14+
| Layer | Technology |
15+
|-------|------------|
16+
| Frontend | React 18, TypeScript, Vite 5 |
17+
| Styling | TailwindCSS + shadcn/ui (51+ components) |
18+
| State | Zustand with localStorage persistence |
19+
| Forms | React Hook Form + Zod validation |
20+
| Routing | React Router v6 |
21+
| Backend | Supabase Edge Functions (Deno runtime) |
22+
| Auth | Supabase Auth (Google OAuth) |
23+
| Database | Supabase PostgreSQL (15 tables, RLS enabled) |
24+
| AI Providers | OpenAI, Google Gemini, Anthropic Claude |
25+
| Web Search | Jina AI (Search + Reader) |
26+
| CI/CD | GitHub Actions + Docker Hub + Watchtower |
1027

1128
## Common Commands
1229

@@ -15,79 +32,203 @@ DebateLab is an AI-powered debate preparation suite. It uses **Supabase Edge Fun
1532
npm install # Install dependencies
1633
npm run dev # Start dev server on port 8080
1734
npm run build # Production build to dist/
35+
npm run build:dev # Dev build with source maps
36+
npm run preview # Preview production build
1837

1938
# Quality
2039
npm run lint # Run ESLint
21-
npm test # Run tests with Vitest
40+
npm test # Run tests with Vitest (39 tests)
41+
npm run test:watch # Run tests in watch mode
2242

2343
# Docker
2444
docker build -t debate-trainer .
2545
docker run -d -p 3001:80 --name debate-app debate-trainer
46+
47+
# Supabase
48+
npx supabase functions deploy ai # Deploy AI function
49+
npx supabase functions deploy admin # Deploy admin function
50+
npx supabase functions deploy share # Deploy share function
2651
```
2752

2853
## Architecture
2954

30-
### Backend: Supabase Edge Functions
55+
### Backend: 3 Supabase Edge Functions
56+
57+
1. **`supabase/functions/ai/index.ts`** (~888 lines) - Main AI proxy
58+
- JWT authentication required
59+
- API keys stored as Supabase secrets (OPENAI_API_KEY, GOOGLE_API_KEY, ANTHROPIC_API_KEY, JINA_API_KEY)
60+
- Input sanitization with prompt injection pattern detection
61+
- Deep research with Jina AI (multi-round search, content reading, URL verification)
62+
- Rate limiting per authenticated user
63+
- Multi-provider routing (OpenAI, Google, Anthropic)
3164

32-
All AI calls go through `supabase/functions/ai/index.ts`:
33-
- JWT authentication required
34-
- API keys stored as Supabase secrets
35-
- Input sanitization for prompt injection
36-
- Deep research with Jina AI (multi-search, URL verification)
65+
2. **`supabase/functions/admin/index.ts`** (~329 lines) - Admin API
66+
- Admin role verification
67+
- User management, usage stats
68+
69+
3. **`supabase/functions/share/index.ts`** (~131 lines) - Share link creation
70+
- Unique share code generation with collision detection
3771

3872
### Frontend: React + Zustand
3973

74+
**AI Client** (`src/lib/ai/client.ts`):
75+
- Calls Edge Function via `fetch` with JWT Bearer token
76+
- Custom error hierarchy: `AIError`, `AIAuthError`, `AIRateLimitError`, `AIProviderError`, `AIResponseError`, `TimeoutError`
77+
- Type guards for error handling
78+
4079
**Session Store** (`src/lib/stores/session-store.ts`):
41-
- Active results for each feature
42-
- History arrays (savedCases, savedAttacks, etc.)
80+
- Active results for each feature (generateResult, attackResult, etc.)
81+
- History arrays (savedCases, savedAttacks, savedBrainstorms, savedFactoids, savedChats)
4382
- Source Library for knowledge base grounding
83+
- Persistence key: `debate-trainer-storage`
4484

4585
**Settings Store** (`src/lib/stores/settings-store.ts`):
46-
- Per-feature AI provider configuration
47-
- Theme, language, admin mode
86+
- Per-feature AI provider configuration (provider, model, temperature)
87+
- Theme (light/dark/system), language (en/es)
88+
- Admin mode, custom system prompt
89+
- Persistence key: `debate-settings`
4890

4991
### State Persistence
5092
- All data stored in browser localStorage via Zustand persist
5193
- Auth state in Supabase session
5294

95+
## Project Structure
96+
97+
```
98+
src/
99+
├── components/
100+
│ ├── auth/ # Auth-related components
101+
│ ├── features/ # Feature-specific components (9 folders)
102+
│ ├── landing/ # Landing page components (11 files)
103+
│ ├── layout/ # AppLayout, Sidebar, MobileNav
104+
│ └── ui/ # shadcn/ui components (51 files)
105+
├── hooks/ # use-mobile, use-speech-to-text, use-toast
106+
├── lib/
107+
│ ├── ai/
108+
│ │ ├── client.ts # AI integration (Edge Function calls)
109+
│ │ └── schemas/ # Zod validation (ask, attack, brainstorm, factoids, generate)
110+
│ ├── stores/ # Zustand stores
111+
│ ├── supabase/ # Client + AuthProvider
112+
│ └── validation/ # URL validation
113+
├── pages/ # 14 route pages
114+
└── test/ # Tests (39 passing across 8 files)
115+
116+
supabase/functions/ # Edge Functions (ai, admin, share)
117+
```
118+
53119
## Feature Organization
54120

55-
Five main features under `src/components/features/`:
56-
- **generate/**: Case generation
57-
- **attack/**: Critical analysis
58-
- **brainstorm/**: Idea generation
59-
- **factoids/**: Evidence research with web search
60-
- **ask/**: Coach chat
121+
Main features under `src/components/features/`:
122+
- **generate/**: Case generation (4-6-6-3 tournament format, contentions with CWI structure)
123+
- **attack/**: Critical analysis with fallacy detection and severity ratings
124+
- **brainstorm/**: Multi-mode ideation (mindmap, buckets, top-5)
125+
- **factoids/**: Deep research with multi-round Jina search, URL verification, content reading
126+
- **ask/**: Coach chat with conversation memory, source grounding, voice input
127+
128+
Each follows: `FeatureForm.tsx` -> `FeatureResults.tsx` pattern.
129+
130+
Additional features:
131+
- **Source Library** (`/library`): Persistent knowledge base (URL reading, manual text, response saving)
132+
- **Debate Timer** (`/timer`): Presets for constructive (4m), rebuttal (6m), cross-ex (6m), summary (3m)
133+
- **Word/PDF Export**: Download cases as .docx or formatted PDF
134+
- **Google Docs Export**: Direct export via Google Docs API
135+
- **Argument Flowcharts**: Visual debate flow with React Flow
136+
137+
## Routes
138+
139+
| Path | Page | Description |
140+
|------|------|-------------|
141+
| `/` | GeneratePage | Case generation |
142+
| `/attack` | AttackPage | Case critique |
143+
| `/brainstorm` | BrainstormPage | Idea generation |
144+
| `/factoids` | FactoidsPage | Research |
145+
| `/ask` | AskPage | Chat coaching |
146+
| `/library` | LibraryPage | Source library |
147+
| `/history` | HistoryPage | Saved items |
148+
| `/timer` | TimerPage | Debate stopwatch |
149+
| `/settings` | SettingsPage | Configuration |
150+
| `/login` | LoginPage | Authentication |
151+
152+
## Database Schema (15 tables)
61153

62-
Each follows: `FeatureForm.tsx` → `FeatureResults.tsx` pattern.
154+
Tables with RLS enabled: `user_settings`, `cases`, `attacks`, `brainstorms`, `factoids`, `chats`, `messages`, `sources`, `source_files`, `ai_requests`, `api_keys`, `shared_items`, `user_roles`, `rate_limits`, `global_prompts`
155+
156+
All RLS policies use optimized `(SELECT auth.uid())` pattern.
63157

64158
## Security
65159

66160
| Layer | Implementation |
67161
|-------|----------------|
68-
| API Keys | Supabase Edge Function secrets |
69-
| Auth | Supabase Auth + JWT |
70-
| Input Validation | Prompt injection sanitization |
71-
| Nginx | CSP headers, block sensitive files |
72-
73-
## Critical Files
74-
75-
- **Edge Function**: `supabase/functions/ai/index.ts` - All AI logic
76-
- **Supabase Client**: `src/lib/supabase/client.ts`
77-
- **State**: `src/lib/stores/session-store.ts`, `settings-store.ts`
78-
- **Schemas**: `src/lib/ai/schemas/` - Zod validation
79-
- **Deployment**: `Dockerfile`, `nginx.conf`
162+
| API Keys | Supabase Edge Function secrets (never in browser) |
163+
| Auth | Supabase Auth + JWT verification |
164+
| Input Validation | Prompt injection regex patterns, MAX_INPUT_LENGTH=50000 |
165+
| CORS | Strict allowlist (debate.pi-stack.org + localhost) |
166+
| Nginx | CSP headers, HSTS, X-Frame-Options, block sensitive files |
167+
| URL Validation | Block javascript:, data:, vbscript:, file: protocols |
168+
| File Validation | 10MB limit, allowed extensions only |
169+
| RLS | All 15 tables protected with row-level security |
170+
171+
## Environment Variables
172+
173+
| Variable | Location | Description |
174+
|----------|----------|-------------|
175+
| `VITE_SUPABASE_URL` | Frontend (.env) | Supabase project URL |
176+
| `VITE_SUPABASE_ANON_KEY` | Frontend (.env) | Supabase anonymous key |
177+
| `OPENAI_API_KEY` | Supabase secrets | OpenAI API key |
178+
| `GOOGLE_API_KEY` | Supabase secrets | Google AI API key |
179+
| `ANTHROPIC_API_KEY` | Supabase secrets | Anthropic API key |
180+
| `JINA_API_KEY` | Supabase secrets | Jina AI API key |
181+
| `AI_DEFAULT_PROVIDER` | Supabase secrets | Default provider (google) |
182+
| `AI_DEFAULT_MODEL` | Supabase secrets | Default model (gemini-2.0-flash) |
80183

81184
## Deployment
82185

83186
Docker two-stage build:
84-
1. Node builder: `npm ci → npm run build`
85-
2. nginx runtime: serves static files
187+
1. Node builder (`node:20-alpine`): `npm ci` -> `npm run build`
188+
2. Nginx runtime (`nginx:alpine`): serves static files from `dist/`
189+
190+
Production: Raspberry Pi + Watchtower for auto-updates from Docker Hub + Cloudflare Tunnel.
191+
192+
CI/CD: GitHub Actions on push to main -> build + push multi-arch Docker image.
193+
194+
## Adding a New Feature
86195

87-
Production uses Watchtower for auto-updates from Docker Hub.
196+
1. Create Zod schema: `src/lib/ai/schemas/newfeature.ts`
197+
2. Update Edge Function: `supabase/functions/ai/index.ts` (add feature case)
198+
3. Create form component: `src/components/features/newfeature/NewFeatureForm.tsx`
199+
4. Create results component: `src/components/features/newfeature/NewFeatureResults.tsx`
200+
5. Create page: `src/pages/NewFeaturePage.tsx`
201+
6. Add route: `src/App.tsx`
202+
7. Update stores: `src/lib/stores/session-store.ts`
203+
204+
## Coding Conventions
205+
206+
- 2-space indentation
207+
- Named exports preferred
208+
- `@/` alias for `src/` imports
209+
- PascalCase.tsx for components, kebab-case.ts for utilities
210+
- Functional components with hooks
211+
- React Hook Form for forms, Zod for runtime validation
212+
- shadcn/ui for UI components, TailwindCSS for styling
88213

89214
## Admin Mode
90215

91216
Code `debate2026` in Settings unlocks:
92217
- Global custom system prompt
93-
- Database reset
218+
- Database reset functionality
219+
- Advanced configuration options
220+
221+
## Known Technical Debt
222+
223+
- TypeScript strict mode disabled in `tsconfig.app.json` (TD-01, high priority)
224+
- Bundle size warnings: GeneratePage (360KB), vendor-charts/Recharts (400KB)
225+
- Test coverage measurement blocked by peer dep conflict (@vitest/coverage-v8)
226+
- Deep research may approach Edge Function timeout limits
227+
228+
## Upcoming Features (Roadmap)
229+
230+
**Next up:**
231+
- Practice Mode / Sparring Partner (AI plays opponent, turn-based with timer)
232+
- Debate Wiki integration (WikiDebate, NDCA caselist)
233+
- Stripe payments (free trial -> $5/mo Pro tier, promo code system)
234+
- Native mobile apps (Capacitor or React Native)

‎STRIPE_PROGRESS.md‎

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# Stripe Implementation Progress
2+
3+
**Last Updated:** 2026-02-10
4+
**Status:** Code complete, not deployed
5+
6+
## What's Done (All code written, lint/test passing)
7+
8+
### Database
9+
- `supabase/migrations/20260208000000_stripe_schema.sql` — Creates `subscriptions`, `promo_codes`, `user_promos` tables, adds `subscription_tier`/`daily_limit_override`/`trial_ends_at`/`grace_period_ends_at` columns to `user_settings`, sets up RLS policies, and migrates existing users to `legacy_free` with 30-day grace period.
10+
11+
### Backend (Supabase Edge Functions)
12+
| Function | Path | Status |
13+
|---|---|---|
14+
| `stripe-webhook` | `supabase/functions/stripe-webhook/index.ts` | New — handles checkout.session.completed, invoice.payment_succeeded/failed, subscription deleted/updated |
15+
| `create-checkout` | `supabase/functions/create-checkout/index.ts` | New — creates Stripe Checkout Sessions with promo code support |
16+
| `create-portal` | `supabase/functions/create-portal/index.ts` | New — creates Stripe Customer Portal sessions |
17+
| `redeem-promo` | `supabase/functions/redeem-promo/index.ts` | New — validates and applies promo codes (extended_trial, extra_limit, free_month, discount) |
18+
| `ai` | `supabase/functions/ai/index.ts` | Updated — added `getSubscriptionInfo()`, `PRO_MODELS` set, subscription-aware `checkRateLimit()` that returns 402/403 |
19+
| `admin` | `supabase/functions/admin/index.ts` | Updated — added `promo-codes`, `create-promo`, `toggle-promo`, `subscribers` endpoints |
20+
21+
### Frontend
22+
| File | Status | Description |
23+
|---|---|---|
24+
| `src/hooks/use-subscription.ts` | New | Hook providing tier, isPro, dailyLimit, dailyUsed, trialEndsAt, refresh() |
25+
| `src/hooks/use-subscription-error.ts` | New | Hook that detects 402/403 errors and opens correct modal |
26+
| `src/lib/stripe.ts` | New | `redirectToCheckout()`, `redirectToPortal()`, `redeemPromoCode()` helpers |
27+
| `src/lib/ai/client.ts` | Updated | Added `AISubscriptionError`, `AIModelRestrictionError`, type guards, error parsing |
28+
| `src/lib/ai/providers/types.ts` | Updated | Added `isProOnly` flag to `AIModel`, marked pro models |
29+
| `src/components/features/subscription/PricingModal.tsx` | New | Free vs Pro comparison, Stripe checkout redirect, promo code input |
30+
| `src/components/features/subscription/LimitReachedModal.tsx` | New | Daily limit / trial expired modal with upgrade CTA |
31+
| `src/components/features/subscription/ModelRestrictedModal.tsx` | New | Pro model restriction modal |
32+
| `src/pages/SettingsPage.tsx` | Updated | Added subscription status card, usage bar, manage/upgrade buttons, model gating |
33+
| `src/pages/GeneratePage.tsx` | Updated | Integrated subscription error modals |
34+
| `src/pages/AttackPage.tsx` | Updated | Integrated subscription error modals |
35+
| `src/pages/BrainstormPage.tsx` | Updated | Integrated subscription error modals |
36+
| `src/pages/FactoidsPage.tsx` | Updated | Integrated subscription error modals |
37+
| `src/pages/AskPage.tsx` | Updated | Integrated subscription error modals |
38+
| `src/pages/AdminPage.tsx` | Updated | Added Promo Codes tab (create/toggle) + Subscribers tab |
39+
| `package.json` | Updated | Added `@stripe/stripe-js` dependency |
40+
41+
## What's NOT Done (Requires Manual Steps / Deploy)
42+
43+
### 1. Stripe Dashboard Setup (Manual — see stripe_implementation.md Section 2)
44+
- Create DebateLab Pro product ($5/mo) in Stripe Dashboard
45+
- Copy the Price ID (starts with `price_...`)
46+
- Enable Customer Portal
47+
- Add webhook endpoint pointing to `https://<project-ref>.supabase.co/functions/v1/stripe-webhook`
48+
- Copy webhook signing secret
49+
50+
### 2. Environment Variables
51+
- Add to Supabase secrets:
52+
- `STRIPE_SECRET_KEY` — from Stripe Dashboard
53+
- `STRIPE_WEBHOOK_SECRET` — from webhook endpoint
54+
- Add to frontend `.env`:
55+
- `VITE_STRIPE_PRICE_ID` — the Price ID from step 1
56+
57+
### 3. Deploy
58+
- Run the migration SQL against Supabase DB
59+
- Deploy all 6 edge functions: `ai`, `admin`, `stripe-webhook`, `create-checkout`, `create-portal`, `redeem-promo`
60+
- Deploy frontend (build already succeeds)
61+
62+
### 4. Landing Page Pricing Section
63+
- `LandingPage.tsx` doesn't have a pricing section yet (low priority, users can see pricing in the PricingModal from Settings)
64+
65+
### 5. Stripe Tax Configuration
66+
- Enable Stripe Tax in Dashboard settings if desired
67+
- `create-checkout` already has `automatic_tax: { enabled: true }` set
68+
69+
## Architecture Notes
70+
71+
### Subscription Tiers
72+
| Tier | Daily Limit | Pro Models | When |
73+
|---|---|---|---|
74+
| `trial` | 5 | No | New users, first 3 days |
75+
| `pro` | 50 | Yes | Active Stripe subscription |
76+
| `legacy_free` | 50 | Yes | Existing users during 30-day grace |
77+
| `expired` | 0 | No | Trial/grace expired, no subscription |
78+
79+
### Error Codes from AI Function
80+
| HTTP | Code | Meaning | Frontend Action |
81+
|---|---|---|---|
82+
| 402 | `trial_expired` | Trial ended, no sub | Shows LimitReachedModal (trial_expired) |
83+
| 402 | `limit_reached` | Daily requests used up | Shows LimitReachedModal (limit_reached) |
84+
| 403 | `upgrade_required` | Pro model selected by free user | Shows ModelRestrictedModal |
85+
86+
### Pro Models (Gated on Backend)
87+
`gpt-4o`, `claude-3-5-sonnet-latest`, `claude-3-opus-20240229`, `gemini-1.5-pro`, `gemini-2.0-pro-exp`, `gemini-3-pro-preview`
88+
89+
### Promo Code Types
90+
| Type | Effect |
91+
|---|---|
92+
| `extended_trial` | Sets `trial_ends_at` to now + X days |
93+
| `extra_limit` | Sets `daily_limit_override` to X |
94+
| `free_month` | Sets tier to `pro` + grace period 30 days |
95+
| `discount` | Applied at Stripe checkout (not redeemed server-side) |

‎Stripe_ai_claude.txt‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
▐▛███▜▌ Claude Code v2.1.38
3+
▝▜█████▛▘ Opus 4.6 · Claude Pro
4+
▘▘ ▝▝ ~/Code/innovation_fair_2026/MVP-Stripe-Prototype
5+
6+
✻ Conversation compacted (ctrl+o for history)
7+
8+
⎿  Read STRIPE_PROGRESS.md (96 lines)
9+
⎿  Referenced file stripe_implementation.md
10+
⎿  Read src/pages/GeneratePage.tsx (240 lines)
11+
⎿  Read src/pages/AskPage.tsx (129 lines)
12+
⎿  Read src/pages/FactoidsPage.tsx (138 lines)
13+
⎿  You're out of extra usage · resets 4pm (Europe/Madrid)
14+
/upgrade or /extra-usage to finish what you’re working on.
15+
16+
✻ Churned for 18m 40s
17+
18+
❯ Unknown skill: rate-limit-options

0 commit comments

Comments
 (0)