TanStack Start Architecture Enforcement
Overview
Enforces hypercore TanStack Start architecture rules with 100% compliance. Validates project structure, then applies strict layer/route/hook/convention rules to every code change.
This skill is RIGID. Follow exactly. No exceptions.
REQUIRED: When working on TanStack Start projects, ALWAYS use this skill together with
to guarantee 100% architecture compliance. Ralph's persistence loop ensures every rule is verified and no violation slips through.
Step 1: Project Validation
Before any work, confirm TanStack Start project:
bash
# Check for TanStack Start indicators (ANY of these)
ls app.config.ts 2>/dev/null # TanStack Start config
grep -r "@tanstack/react-start" package.json 2>/dev/null
grep -r "@tanstack/react-router" package.json 2>/dev/null
ls src/routes/__root.tsx 2>/dev/null
If NONE found: STOP. This skill does not apply. Inform user.
If found: proceed with architecture enforcement.
Step 2: Read Architecture Rules
Load the detailed rules reference:
REQUIRED: Read
in this skill directory before writing any code.
For detailed patterns and examples, also read the relevant reference files:
- - Code conventions (naming, TypeScript, imports, comments)
- - Route structure (folder rules, patterns, loaders)
- - Server Functions (schemas, queries, mutations, middleware)
- - Custom Hook patterns (separation rules, internal order)
Step 3: Pre-Change Validation Checklist
Before writing ANY code, verify your planned change against these gates:
Gate 1: Layer Violations
Routes -> Server Functions -> Features -> Database
| Check | Rule |
|---|
| Route accessing DB directly? | BLOCKED. Must go through Server Functions -> Features |
| Route calling Prisma? | BLOCKED. Use Server Functions |
| Server Function skipping Features? | ALLOWED only for simple CRUD |
| Client calling Server Function directly? | BLOCKED. Use TanStack Query (exception: / run server-side, can call directly) |
Gate 2: Route Structure
| Check | Rule |
|---|
| Flat file route? () | BLOCKED. Use folder () |
| Missing folder? | BLOCKED. Every page needs it |
| Missing folder? | BLOCKED. Every page needs it |
| Missing folder? | BLOCKED. Every page needs it |
| without ? | BLOCKED. Must be |
| Logic in page component? | BLOCKED. Extract to |
| Layout route missing ? | BLOCKED. Routes needing beforeLoad/loader must have |
| Route with search params but no ? | BLOCKED. Must use with |
| Route without ? | WARNING. Recommended for all routes with loaders |
Gate 3: Server Functions
| Check | Rule |
|---|
| POST/PUT/PATCH without ? | BLOCKED |
| Auth-required without ? | BLOCKED |
| Using instead of ? | BLOCKED. does not exist |
| handler not last in chain? | BLOCKED. handler must ALWAYS be last (middleware/inputValidator order is flexible) |
| Missing adapter for search params? | BLOCKED. Use from |
| Direct server function call in component? | BLOCKED. Use hook from |
| barrel export? | BLOCKED. Tree shaking failure |
Gate 4: Hooks
| Check | Rule |
|---|
| Hook inside page component? | BLOCKED. Must be in folder |
| Wrong hook order? | BLOCKED. State -> Global -> Server Fns -> Query -> Handlers -> Memo -> Effect |
| Missing return type interface? | BLOCKED |
| camelCase hook filename? | BLOCKED. Use |
Gate 5: Conventions
| Check | Rule |
|---|
| camelCase filename? | BLOCKED. Use kebab-case |
| keyword? | BLOCKED. Use const arrow function |
| type? | BLOCKED. Use |
| Missing explicit return type? | BLOCKED |
| Wrong import order? | BLOCKED. External -> @/ -> Relative -> Type |
| Missing Korean block comments? | BLOCKED for code groups |
| Using pattern? | BLOCKED. Use Zod 4.x directly |
Step 4: Implementation (with Ralph)
When used with ralph, every PRD story MUST include these acceptance criteria:
- [ ] Layer architecture respected (no layer skipping)
- [ ] Route uses folder structure with -components/, -hooks/, -functions/
- [ ] export const Route = createFileRoute(...) used
- [ ] Server Functions use correct chaining (handler always last, middleware/inputValidator flexible)
- [ ] Search params use zodValidator from @tanstack/zod-adapter
- [ ] Custom Hooks in -hooks/ with correct internal order
- [ ] All filenames kebab-case
- [ ] Korean block comments present
- [ ] const arrow functions with explicit return types
Step 5: Post-Change Verification
After writing code, verify:
- Structure check: the route folder - confirm , , exist
- Export check: grep for in route files
- Layer check: no Prisma imports in route files
- Convention check: no camelCase filenames, no keyword declarations
- Hook order check: read hook files, verify State -> Global -> Server Fns -> Query -> Handlers -> Memo -> Effect
Quick Reference: Folder Structure
src/
├── routes/ # File-based routing
│ └── <page>/
│ ├── index.tsx # Page (UI only)
│ ├── route.tsx # Layout (beforeLoad, loader)
│ ├── -components/ # REQUIRED: page components
│ ├── -hooks/ # REQUIRED: page hooks (ALL logic here)
│ ├── -functions/ # REQUIRED: page server functions
│ └── -sections/ # Optional: 200+ line pages
├── features/<domain>/ # Internal domain (Prisma queries)
│ ├── schemas.ts
│ ├── queries.ts
│ └── mutations.ts
├── services/<provider>/ # External SDK wrappers
├── functions/ # Global server functions (NO index.ts!)
│ └── middlewares/
├── database/ # Prisma client singleton
├── stores/ # Zustand stores
├── hooks/ # Global hooks
├── components/ # Shared UI
│ ├── ui/ # shadcn/ui
│ ├── layout/ # Header, Sidebar, Footer
│ └── shared/ # Common components
├── types/ # Global types
├── env/ # t3-env validation
├── config/ # auth, query-client, sentry
└── lib/ # Utilities
├── utils/
├── constants/
└── validators/
Common Mistakes
| Mistake | Fix |
|---|
| |
const Route = createFileRoute(...)
| export const Route = createFileRoute(...)
|
| |
| Logic in page component | Extract to |
| or folders | Use and |
| barrel | Import directly from individual files |
| Hook with mixed order | Follow: State -> Global -> Server Fns -> Query -> Handlers -> Memo -> Effect |
| filename | |
| const doThing = (): ReturnType => {}
|
| Direct Zod schema in | Use from |
| Server function call without | Use in components |
| without options | Use createMiddleware({ type: 'function' })
|
| Missing on route | Add for loading state |
Red Flags - STOP and Fix
- Route file importing from directly
- Missing on
- Page component with , etc. inline (not in hook)
- Server function using instead of
- type anywhere
- camelCase filenames
- route handlers (use Server Functions)
- Missing folder in any route
- Route using search params without
- Component calling server function directly (not through )
- without option