AI-assisted learning plan generator built with Next.js 16.2, React 19, TypeScript, Drizzle, Supabase Postgres, PostgreSQL RLS, Clerk Auth, Stripe, and OpenRouter.
- Creates structured learning plans with ordered modules and tasks
- Streams AI generation progress to the client over SSE
- Tracks generation attempts, failure classifications, and retryability
- Enforces tenant isolation with PostgreSQL Row Level Security (RLS)
- Supports Google Calendar OAuth token storage and disconnect flows
- Applies usage limits, rate limiting, and subscription gating server-side
- Framework: Next.js 16.2.4 + React 19
- Language: TypeScript (strict mode)
- Database: Supabase local Postgres / hosted Supabase Postgres via Drizzle ORM
- Auth: Clerk for UI, route protection, and server session reads
- AI: OpenRouter via
@openrouter/sdkand the Vercel AI SDK - Payments: Stripe
- Testing: Vitest + Testing Library + Testcontainers
Install dependencies and run the development server:
pnpm install
pnpm devIf you want to bring up the Supabase local stack and app together:
pnpm dev:fullUse pnpm db:dev:start and pnpm db:dev:stop to control the Supabase local stack, and pnpm db:dev:reset to recreate the local Supabase database from committed migrations and seed data.
Open http://localhost:3000 in your browser.
Quickstart:
pnpm install
pnpm dev # Turbopack app only
pnpm dev:full # local DB + app
pnpm check:full # lint + type-check (runs check:lint + check:type)
pnpm test # lightweight changed bundle (same as test:changed)Full script reference — flags, scoped test runners, database helpers: docs/development/commands.md.
On commit, Husky runs lint-staged (Oxlint --fix + Prettier on staged files only). Pre-push runs pnpm check:full (full Oxlint + typecheck).
src/
├── app/ # App Router pages + API routes
├── components/ # Shared UI and feature components
├── hooks/ # Client hooks
├── lib/
│ ├── ai/ # Providers, orchestration, parsing, streaming
│ ├── api/ # Auth wrappers, errors, rate limiting, helpers
│ ├── auth/ # Auth server/client wiring
│ ├── config/ # Typed environment access
│ ├── db/ # Query modules and shared DB types
│ ├── integrations/ # OAuth token/state utilities
│ ├── logging/ # Server/client logging helpers
│ └── ...
└── types/ # Shared application types
supabase/
├── schema/ # Drizzle schema, relations, and policy definitions
├── migrations/ # Committed DB migrations
├── rls.ts # RLS client factory
├── runtime.ts # Request-scoped DB resolver
└── service-role.ts # Service-role DB client for tests/workers
- Request handlers use
getDb()from@supabase/runtimeinside auth wrappers - Tests, workers, and migrations use the service-role client only where appropriate
- RLS policies are explicitly scoped to
authenticated - OAuth state tokens are hashed before persistence
- Error responses flow through the canonical API error contract
The default pnpm test command runs a lightweight changed-only bundle: unit tests plus integration-class tests filtered to changed files. Integration-class coverage includes DB/API integration tests and the Workflow SDK Vitest harness.
Use the explicit scoped commands for day-to-day work, and prefer targeted integration runs instead of the full suite whenever possible:
pnpm test:changed
pnpm test:unit:changed
pnpm test:integration:changed
pnpm test:workflowFor direct file targeting:
pnpm exec tsx scripts/tests/run.ts changed
pnpm exec tsx scripts/tests/run.ts unit path/to/file.spec.ts
pnpm exec tsx scripts/tests/run.ts integration tests/integration/path/to/file.spec.tsIntegration tests normally rely on Testcontainers. If you intentionally want to point at an existing Supabase-compatible database, set SKIP_TESTCONTAINERS=true and provide a valid POSTGRES_URL.
- Do not access
process.envdirectly outsidesrc/lib/config/env.ts - Use grouped config exports such as
databaseEnv,clerkAuthEnv,stripeEnv,aiEnv,openRouterEnv, andloggingEnv - Do not use
console.*in application code — use the logging utilities insrc/lib/logging/
AGENTS.mddocs/architecture/auth-and-data-layer.mddocs/architecture/plan-generation-architecture.mddocs/architecture/internal-worker-routes.mddocs/architecture/regeneration-worker-runbook.mddocs/architecture/retention-cleanup-runbook.mddocs/api/error-contract.mddocs/database/schema-overview.md