boilerplate-stack/ ├── app/ │ ├── [locale]/ # Locale-based routing │ │ ├── (admin)/ # Admin sections │ │ │ ├── admin-dashboard/ # Platform super-admin │ │ │ └── org-dashboard/ # Organization admin (B2B) │ │ ├── (auth)/ # Authentication pages │ │ ├── (frontend)/ # Public pages │ │ └── (private)/ # Private dashboard │ ├── api/ # API route handlers │ ├── docs/ # User-facing /docs site (MDX + nav) │ ├── layout.tsx # Root layout │ ├── manifest.ts # Dynamic PWA manifest │ ├── sitemap.ts # Dynamic sitemap.xml │ └── robots.ts # Dynamic robots.txt ├── components/ │ ├── admin/ # Admin components │ ├── billing/ # Pricing, credits │ ├── chat/ # AI chat interface │ └── ui/ # shadcn/ui components ├── config/ # Declarative source of truth │ ├── affiliates.ts # Affiliate tiers, commission rates, hold period │ ├── ai.ts # LLM providers, models, agents, embeddings │ ├── app.ts # Branding, business model, feature flags, logs │ ├── email.ts # Email provider selection + credentials │ ├── pricing.ts # Plans, packs, licenses, currencies, Stripe IDs │ ├── referral.ts # Referral program (trigger, rewards, codes) │ └── workspace.ts # Workspace defaults, signup bonus, slug rules ├── content/ # MDX source for /docs pages ├── core/ # Domain layer (queries + mutations + error codes) │ ├── accounts/ # Personal + workspace accounts, memberships │ ├── affiliates/ # Partner program (conversions, payouts) │ ├── ai/ # Stream gating, post-stream accounting │ ├── billing/ # Stripe webhook business logic, credits │ ├── changelog/ # Changelog entries CRUD │ ├── chat/ # Chat sessions + messages │ ├── cron/ # pg_cron schedule sync helpers │ ├── documents/ # RAG documents + chunk metadata │ ├── licenses/ # One-shot license records + features/limits │ ├── logs/ # Error-log admin reads │ ├── organizations/ # Admin org/user CRUD │ ├── referrals/ # Referral program (codes, attributions, qualify) │ └── roles/ # Dynamic role definitions ├── hooks/ # React hooks (use-chat, use-account, etc.) ├── i18n/ # BCP-47 locale config + messages ├── lib/ # Cross-cutting utilities (auth, security, supabase, etc.) ├── public/ # Static assets (icons, fonts, legacy /docs/index.html) ├── scripts/ # init-project.js, sync-ai-rules.sh, etc. ├── supabase/ # schema.sql, cms-schema.sql, migrations/, functions/ ├── tests/ # Playwright (a11y, responsive, E2E) ├── __tests__/ # Vitest unit tests (i18n parity, sanitize) ├── types/ # TypeScript types ├── instrumentation.ts # Next.js instrumentation hook (Sentry, OTel) └── proxy.ts # Middleware: locale routing, auth gates, CSRF
Layered architecture
Per .claude/rules/architecture.md, every request flows through the same layers. Keep route handlers thin; push business logic into core/; read config from config/*; never bypass RLS without a deliberate createServiceClient() call.
app/[locale]/(group)/page.tsx ← presentation only, thin
app/api/<resource>/route.ts ← orchestration: auth gate + Zod + call core/
core/<domain>/queries.ts ← read functions (cached where safe)
core/<domain>/mutations.ts ← write functions (server actions)
core/<domain>/error-codes.ts ← typed error enum + class
lib/<cross-cutting>/ ← supabase, security, stripe, ai, email, etc.
config/*.ts ← declarative source of truth
supabase/schema.sql + migrations/ ← both must stay in syncA route handler does four things and nothing more: enter through apiSecurity.* / withSecurity(), parse + Zod-validate the body, call a core/<domain>/{queries,mutations}.ts function, then map the result to an HTTP response with a code from error-codes.ts. If a route handler holds raw Supabase calls and ad-hoc business logic, refactor it into core/.
core/ exists so the same domain function can be reused across route handlers, server actions, jobs, and tests — a single place to apply caching tags, Zod parsers, and error codes, with clear RLS-vs-service-role decisions per function.