Tech Stack
Doc Status: Good | ✓ Clear summary | ✓ Easy to read | ✓ Matches code | ✓ Good structure | ✓ Professional look | ✓ Visual components
Core Stack
| Layer | Technology | Notes |
|---|
| Website / Admin | Next.js 16 (App Router) + Tailwind CSS v4 | Static export → CF Workers |
| Mobile | Expo + Expo Router + NativeWind | Auth via Convex Auth + expo-secure-store |
| UI | shadcn/ui + class-variance-authority (cva) | Type-safe component variants |
| App backend | Convex (queries / mutations / actions) | End-to-end TS, realtime, transactional |
| External APIs | Vendor SDK or fetch from a Convex action | Lark, Meta CAPI, ZNS — no shared contract |
| Webhook workers | Cloudflare Workers + Hono | HTTP entry points only — verify + forward |
| Database | Convex DB (managed schema diff) | No Drizzle, no D1, no Postgres |
| Auth | Convex Auth (@convex-dev/auth) | Replaced Clerk on 2026-05-08 |
| Marketing CMS | Sanity | Blog, hero, FAQ, instructor bios |
| File storage | Convex (small) + R2 (heavy) + Sanity CDN (mktg) | CI guard blocks wrong folder |
| Deploy (web) | Cloudflare Workers Static Assets | Vercel deprecated |
Frontend (Website / Admin)
| Category | Choice | Rationale |
|---|
| Framework | Next.js 16 (App Router) | RSC, static export friendly |
| Styling | Tailwind CSS v4 | CSS variables via @theme inline |
| UI Components | shadcn/ui + cva | Type-safe component variants |
| Class merging | cn helper (clsx + twMerge) | Mandatory — never concatenate classNames |
| Deployment | Cloudflare Workers Static Assets | Static export + Workers |
Mobile
| Category | Choice | Rationale |
|---|
| Framework | Expo + Expo Router | Faster dev, better tooling |
| Styling | NativeWind | Tailwind for React Native |
| Auth | ConvexAuthProvider + expo-secure-store | Tokens in Keychain / EncryptedSharedPreferences |
Client State
| Category | Choice | Rationale |
|---|
| Immutable state | immer | Mandatory — paired with Zustand / useState |
| Custom hooks | usehooks-ts | Use library instead of re-implementing |
| URL param state | nuqs | Type-safe ?key=value state |
| Forms | React Hook Form + Zod | Schema-validated forms |
| Global state | Zustand + Immer middleware | Cart, auth flags, modal |
Backend
| Category | Choice | Rationale |
|---|
| App data | Convex | End-to-end TS types, realtime |
| External APIs | Vendor SDK or fetch from a Convex action | Lark, Meta CAPI, ZNS |
| Webhook workers | Cloudflare Workers + Hono | apps/lark-sync, apps/meta-conversions-worker only |
| Realtime | Convex subscriptions (useQuery) | Auto-subscribes to data changes |
Auth
| Category | Choice | Rationale |
|---|
| Provider | Convex Auth (@convex-dev/auth) | First-party, runs inside Convex deployment |
Replaced Clerk on 2026-05-08.
Content
| Category | Choice | Rationale |
|---|
| Marketing CMS | Sanity | Blog, hero, FAQ, instructor bios, product content |
| Operational | Convex | Students, courses, sessions, attendance, payments, product operational |
Storage
| Category | Choice | Rationale |
|---|
| Small admin uploads | Convex storage | Auth-gated, transactional with the row |
| Heavy media | Cloudflare R2 | Bandwidth + CDN reach |
| Marketing assets | Sanity CDN | PM/marketing edits via Studio |
| UI primitives | public/images/{logos,icons,branding} | Cache-friendly, version-controlled |
Forbidden Technologies
| Category | BANNED |
|---|
| Frontend | Angular, Vue, Svelte |
| State (Web) | Redux, MobX, Recoil |
| App data API | fetch/axios, tRPC, OpenAPI/generated SDKs, Hono for new app data |
| Backend | Express, NestJS standalone, Drizzle / D1 / Postgres for app data |
| Database ORM | Prisma, TypeORM, Drizzle |
| Schema Valid. | Yup, Joi, class-validator (use convex/values for Convex; Zod for forms) |
| Styling | CSS-in-JS, inline styles |
| Deploy (web) | Vercel (deprecated for this project) |