[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6QWHB10V10PW20MP7MJC8SM":3,"skill-same:01M6QWHB10V10PW20MP7MJC8SM":130},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":34,"publishedAt":55,"linkOnly":56,"markdownContent":57,"markdownBody":58,"frontMatter":59,"refName":72,"commitSha":73,"skillDirectory":74,"forksCount":75,"repositoryHtmlUrl":76,"repositoryHomepageUrl":77,"ownerHtmlUrl":78,"ownerBlogUrl":79,"ownerDescription":80,"updatedAt":81,"install":82,"resources":95},"01M6QWHB10V10PW20MP7MJC8SM","fullstack-dev",null,"Full-stack backend architecture and frontend-backend integration guide.\nTRIGGER when: building a full-stack app, creating REST API with frontend, scaffolding backend service,\nbuilding todo app, building CRUD app, building real-time app, building chat app,\nExpress + React, Next.js API, Node.js backend, Python backend, Go backend,\ndesigning service layers, implementing error handling, managing config\u002Fauth,\nsetting up API clients, implementing auth flows, handling file uploads,\nadding real-time features (SSE\u002FWebSocket), hardening for production.\nDO NOT TRIGGER when: pure frontend UI work, pure CSS\u002Fstyling, database schema only.","VRIL-LABS\u002Fskill-jam","VRIL-LABS","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F272046472?v=4","01M6QR9PNWM28WZYJJASER1RG2","𝗩𝗥𝗜𝗟 𝗟𝗔𝗕𝗦","01M6QR9PT6Q6JDCQ97EQBDX6E4",2,"MIT","https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fai-ml\u002Fminimax-ai-skills-fullstack-dev-1.0.1\u002FSKILL.md",[18,23,26,29],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":27,"categoryName":28,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":30,"categoryName":31,"taxonomyType":32,"taxonomyTypeDesc":33},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54],"fullstack dev","fullstack","dev","clean","implementing","app","database schema","express","time","go backend","todo","testing","sre","stack","release","architecture","react","css","design","frontend","2026-11-10 10:12:30",false,"---\nname: fullstack-dev\ndescription: |\n  Full-stack backend architecture and frontend-backend integration guide.\n  TRIGGER when: building a full-stack app, creating REST API with frontend, scaffolding backend service,\n  building todo app, building CRUD app, building real-time app, building chat app,\n  Express + React, Next.js API, Node.js backend, Python backend, Go backend,\n  designing service layers, implementing error handling, managing config\u002Fauth,\n  setting up API clients, implementing auth flows, handling file uploads,\n  adding real-time features (SSE\u002FWebSocket), hardening for production.\n  DO NOT TRIGGER when: pure frontend UI work, pure CSS\u002Fstyling, database schema only.\nlicense: MIT\nmetadata:\n  category: full-stack\n  version: \"1.0.0\"\n  sources:\n    - The Twelve-Factor App (12factor.net)\n    - Clean Architecture (Robert C. Martin)\n    - Domain-Driven Design (Eric Evans)\n    - Patterns of Enterprise Application Architecture (Martin Fowler)\n    - Martin Fowler (Testing Pyramid, Contract Tests)\n    - Google SRE Handbook (Release Engineering)\n    - ThoughtWorks Technology Radar\n---\n\n# Full-Stack Development Practices\n\n## MANDATORY WORKFLOW — Follow These Steps In Order\n\n**When this skill is triggered, you MUST follow this workflow before writing any code.**\n\n### Step 0: Gather Requirements\n\nBefore scaffolding anything, ask the user to clarify (or infer from context):\n\n1. **Stack**: Language\u002Fframework for backend and frontend (e.g., Express + React, Django + Vue, Go + HTMX)\n2. **Service type**: API-only, full-stack monolith, or microservice?\n3. **Database**: SQL (PostgreSQL, SQLite, MySQL) or NoSQL (MongoDB, Redis)?\n4. **Integration**: REST, GraphQL, tRPC, or gRPC?\n5. **Real-time**: Needed? If yes — SSE, WebSocket, or polling?\n6. **Auth**: Needed? If yes — JWT, session, OAuth, or third-party (Clerk, Auth.js)?\n\nIf the user has already specified these in their request, skip asking and proceed.\n\n### Step 1: Architectural Decisions\n\nBased on requirements, make and state these decisions before coding:\n\n| Decision | Options | Reference |\n|----------|---------|-----------|\n| Project structure | Feature-first (recommended) vs layer-first | [Section 1](#1-project-structure--layering-critical) |\n| API client approach | Typed fetch \u002F React Query \u002F tRPC \u002F OpenAPI codegen | [Section 5](#5-api-client-patterns-medium) |\n| Auth strategy | JWT + refresh \u002F session \u002F third-party | [Section 6](#6-authentication--middleware-high) |\n| Real-time method | Polling \u002F SSE \u002F WebSocket | [Section 11](#11-real-time-patterns-medium) |\n| Error handling | Typed error hierarchy + global handler | [Section 3](#3-error-handling--resilience-high) |\n\nBriefly explain each choice (1 sentence per decision).\n\n### Step 2: Scaffold with Checklist\n\nUse the appropriate checklist below. Ensure ALL checked items are implemented — do not skip any.\n\n### Step 3: Implement Following Patterns\n\nWrite code following the patterns in this document. Reference specific sections as you implement each part.\n\n### Step 4: Test & Verify\n\nAfter implementation, run these checks before claiming completion:\n\n1. **Build check**: Ensure both backend and frontend compile without errors\n   ```bash\n   # Backend\n   cd server && npm run build\n   # Frontend\n   cd client && npm run build\n   ```\n2. **Start & smoke test**: Start the server, verify key endpoints return expected responses\n   ```bash\n   # Start server, then test\n   curl http:\u002F\u002Flocalhost:3000\u002Fhealth\n   curl http:\u002F\u002Flocalhost:3000\u002Fapi\u002F\u003Cresource>\n   ```\n3. **Integration check**: Verify frontend can connect to backend (CORS, API base URL, auth flow)\n4. **Real-time check** (if applicable): Open two browser tabs, verify changes sync\n\nIf any check fails, fix the issue before proceeding.\n\n### Step 5: Handoff Summary\n\nProvide a brief summary to the user:\n\n- **What was built**: List of implemented features and endpoints\n- **How to run**: Exact commands to start backend and frontend\n- **What's missing \u002F next steps**: Any deferred items, known limitations, or recommended improvements\n- **Key files**: List the most important files the user should know about\n\n---\n\n## Scope\n\n**USE this skill when:**\n- Building a full-stack application (backend + frontend)\n- Scaffolding a new backend service or API\n- Designing service layers and module boundaries\n- Implementing database access, caching, or background jobs\n- Writing error handling, logging, or configuration management\n- Reviewing backend code for architectural issues\n- Hardening for production\n- Setting up API clients, auth flows, file uploads, or real-time features\n\n**NOT for:**\n- Pure frontend\u002FUI concerns (use your frontend framework's docs)\n- Pure database schema design without backend context\n\n---\n\n## Quick Start — New Backend Service Checklist\n\n- [ ] Project scaffolded with **feature-first** structure\n- [ ] Configuration **centralized**, env vars **validated at startup** (fail fast)\n- [ ] **Typed error hierarchy** defined (not generic `Error`)\n- [ ] **Global error handler** middleware\n- [ ] **Structured JSON logging** with request ID propagation\n- [ ] Database: **migrations** set up, **connection pooling** configured\n- [ ] **Input validation** on all endpoints (Zod \u002F Pydantic \u002F Go validator)\n- [ ] **Authentication middleware** in place\n- [ ] **Health check** endpoints (`\u002Fhealth`, `\u002Fready`)\n- [ ] **Graceful shutdown** handling (SIGTERM)\n- [ ] **CORS** configured (explicit origins, not `*`)\n- [ ] **Security headers** (helmet or equivalent)\n- [ ] `.env.example` committed (no real secrets)\n\n## Quick Start — Frontend-Backend Integration Checklist\n\n- [ ] **API client** configured (typed fetch wrapper, React Query, tRPC, or OpenAPI generated)\n- [ ] **Base URL** from environment variable (not hardcoded)\n- [ ] **Auth token** attached to requests automatically (interceptor \u002F middleware)\n- [ ] **Error handling** — API errors mapped to user-facing messages\n- [ ] **Loading states** handled (skeleton\u002Fspinner, not blank screen)\n- [ ] **Type safety** across the boundary (shared types, OpenAPI, or tRPC)\n- [ ] **CORS** configured with explicit origins (not `*` in production)\n- [ ] **Refresh token** flow implemented (httpOnly cookie + transparent retry on 401)\n\n---\n\n## Quick Navigation\n\n| Need to… | Jump to |\n|----------|---------|\n| Organize project folders | [1. Project Structure](#1-project-structure--layering-critical) |\n| Manage config + secrets | [2. Configuration](#2-configuration--environment-critical) |\n| Handle errors properly | [3. Error Handling](#3-error-handling--resilience-high) |\n| Write database code | [4. Database Access Patterns](#4-database-access-patterns-high) |\n| Set up API client from frontend | [5. API Client Patterns](#5-api-client-patterns-medium) |\n| Add auth middleware | [6. Auth & Middleware](#6-authentication--middleware-high) |\n| Set up logging | [7. Logging & Observability](#7-logging--observability-medium-high) |\n| Add background jobs | [8. Background Jobs](#8-background-jobs--async-medium) |\n| Implement caching | [9. Caching](#9-caching-patterns-medium) |\n| Upload files (presigned URL, multipart) | [10. File Upload Patterns](#10-file-upload-patterns-medium) |\n| Add real-time features (SSE, WebSocket) | [11. Real-Time Patterns](#11-real-time-patterns-medium) |\n| Handle API errors in frontend UI | [12. Cross-Boundary Error Handling](#12-cross-boundary-error-handling-medium) |\n| Harden for production | [13. Production Hardening](#13-production-hardening-medium) |\n| Design API endpoints | [API Design](references\u002Fapi-design.md) |\n| Design database schema | [Database Schema](references\u002Fdb-schema.md) |\n| Auth flow (JWT, refresh, Next.js SSR, RBAC) | [references\u002Fauth-flow.md](references\u002Fauth-flow.md) |\n| CORS, env vars, environment management | [references\u002Fenvironment-management.md](references\u002Fenvironment-management.md) |\n\n---\n\n## Core Principles (7 Iron Rules)\n\n```\n1. ✅ Organize by FEATURE, not by technical layer\n2. ✅ Controllers never contain business logic\n3. ✅ Services never import HTTP request\u002Fresponse types\n4. ✅ All config from env vars, validated at startup, fail fast\n5. ✅ Every error is typed, logged, and returns consistent format\n6. ✅ All input validated at the boundary — trust nothing from client\n7. ✅ Structured JSON logging with request ID — not console.log\n```\n\n---\n\n## 1. Project Structure & Layering (CRITICAL)\n\n### Feature-First Organization\n\n```\n✅ Feature-first                    ❌ Layer-first\nsrc\u002F                                src\u002F\n  orders\u002F                             controllers\u002F\n    order.controller.ts                 order.controller.ts\n    order.service.ts                    user.controller.ts\n    order.repository.ts               services\u002F\n    order.dto.ts                        order.service.ts\n    order.test.ts                       user.service.ts\n  users\u002F                              repositories\u002F\n    user.controller.ts                  ...\n    user.service.ts\n  shared\u002F\n    database\u002F\n    middleware\u002F\n```\n\n### Three-Layer Architecture\n\n```\nController (HTTP) → Service (Business Logic) → Repository (Data Access)\n```\n\n| Layer | Responsibility | ❌ Never |\n|-------|---------------|---------|\n| Controller | Parse request, validate, call service, format response | Business logic, DB queries |\n| Service | Business rules, orchestration, transaction mgmt | HTTP types (req\u002Fres), direct DB |\n| Repository | Database queries, external API calls | Business logic, HTTP types |\n\n### Dependency Injection (All Languages)\n\n**TypeScript:**\n```typescript\nclass OrderService {\n  constructor(\n    private readonly orderRepo: OrderRepository,    \u002F\u002F ✅ injected interface\n    private readonly emailService: EmailService,\n  ) {}\n}\n```\n\n**Python:**\n```python\nclass OrderService:\n    def __init__(self, order_repo: OrderRepository, email_service: EmailService):\n        self.order_repo = order_repo                 # ✅ injected\n        self.email_service = email_service\n```\n\n**Go:**\n```go\ntype OrderService struct {\n    orderRepo    OrderRepository                      \u002F\u002F ✅ interface\n    emailService EmailService\n}\n\nfunc NewOrderService(repo OrderRepository, email EmailService) *OrderService {\n    return &OrderService{orderRepo: repo, emailService: email}\n}\n```\n\n---\n\n## 2. Configuration & Environment (CRITICAL)\n\n### Centralized, Typed, Fail-Fast\n\n**TypeScript:**\n```typescript\nconst config = {\n  port: parseInt(process.env.PORT || '3000', 10),\n  database: { url: requiredEnv('DATABASE_URL'), poolSize: intEnv('DB_POOL_SIZE', 10) },\n  auth: { jwtSecret: requiredEnv('JWT_SECRET'), expiresIn: process.env.JWT_EXPIRES_IN || '1h' },\n} as const;\n\nfunction requiredEnv(name: string): string {\n  const value = process.env[name];\n  if (!value) throw new Error(`Missing required env var: ${name}`);  \u002F\u002F fail fast\n  return value;\n}\n```\n\n**Python:**\n```python\nfrom pydantic_settings import BaseSettings\n\nclass Settings(BaseSettings):\n    database_url: str                        # required — app won't start without it\n    jwt_secret: str                          # required\n    port: int = 3000                         # optional with default\n    db_pool_size: int = 10\n    class Config:\n        env_file = \".env\"\n\nsettings = Settings()                        # fails fast if DATABASE_URL missing\n```\n\n### Rules\n\n```\n✅ All config via environment variables (Twelve-Factor)\n✅ Validate required vars at startup — fail fast\n✅ Type-cast at config layer, not at usage sites\n✅ Commit .env.example with dummy values\n\n❌ Never hardcode secrets, URLs, or credentials\n❌ Never commit .env files\n❌ Never scatter process.env \u002F os.environ throughout code\n```\n\n---\n\n## 3. Error Handling & Resilience (HIGH)\n\n### Typed Error Hierarchy\n\n```typescript\n\u002F\u002F Base (TypeScript)\nclass AppError extends Error {\n  constructor(\n    message: string,\n    public readonly code: string,\n    public readonly statusCode: number,\n    public readonly isOperational: boolean = true,\n  ) { super(message); }\n}\nclass NotFoundError extends AppError {\n  constructor(resource: string, id: string) {\n    super(`${resource} not found: ${id}`, 'NOT_FOUND', 404);\n  }\n}\nclass ValidationError extends AppError {\n  constructor(public readonly errors: FieldError[]) {\n    super('Validation failed', 'VALIDATION_ERROR', 422);\n  }\n}\n```\n\n```python\n# Base (Python)\nclass AppError(Exception):\n    def __init__(self, message: str, code: str, status_code: int):\n        self.message, self.code, self.status_code = message, code, status_code\n\nclass NotFoundError(AppError):\n    def __init__(self, resource: str, id: str):\n        super().__init__(f\"{resource} not found: {id}\", \"NOT_FOUND\", 404)\n```\n\n### Global Error Handler\n\n```typescript\n\u002F\u002F TypeScript (Express)\napp.use((err, req, res, next) => {\n  if (err instanceof AppError && err.isOperational) {\n    return res.status(err.statusCode).json({\n      title: err.code, status: err.statusCode,\n      detail: err.message, request_id: req.id,\n    });\n  }\n  logger.error('Unexpected error', { error: err.message, stack: err.stack, request_id: req.id });\n  res.status(500).json({ title: 'Internal Error', status: 500, request_id: req.id });\n});\n```\n\n### Rules\n\n```\n✅ Typed, domain-specific error classes\n✅ Global error handler catches everything\n✅ Operational errors → structured response\n✅ Programming errors → log + generic 500\n✅ Retry transient failures with exponential backoff\n\n❌ Never catch and ignore errors silently\n❌ Never return stack traces to client\n❌ Never throw generic Error('something')\n```\n\n---\n\n## 4. Database Access Patterns (HIGH)\n\n### Migrations Always\n\n```bash\n# TypeScript (Prisma)           # Python (Alembic)              # Go (golang-migrate)\nnpx prisma migrate dev          alembic revision --autogenerate  migrate -source file:\u002F\u002Fmigrations\nnpx prisma migrate deploy       alembic upgrade head             migrate -database $DB up\n```\n\n```\n✅ Schema changes via migrations, never manual SQL\n✅ Migrations must be reversible\n✅ Review migration SQL before production\n❌ Never modify production schema manually\n```\n\n### N+1 Prevention\n\n```typescript\n\u002F\u002F ❌ N+1: 1 query + N queries\nconst orders = await db.order.findMany();\nfor (const o of orders) { o.items = await db.item.findMany({ where: { orderId: o.id } }); }\n\n\u002F\u002F ✅ Single JOIN query\nconst orders = await db.order.findMany({ include: { items: true } });\n```\n\n### Transactions for Multi-Step Writes\n\n```typescript\nawait db.$transaction(async (tx) => {\n  const order = await tx.order.create({ data: orderData });\n  await tx.inventory.decrement({ productId, quantity });\n  await tx.payment.create({ orderId: order.id, amount });\n});\n```\n\n### Connection Pooling\n\nPool size = `(CPU cores × 2) + spindle_count` (start with 10-20). Always set connection timeout. Use PgBouncer for serverless.\n\n---\n\n## 5. API Client Patterns (MEDIUM)\n\nThe \"glue layer\" between frontend and backend. Choose the approach that fits your team and stack.\n\n### Option A: Typed Fetch Wrapper (Simple, No Dependencies)\n\n```typescript\n\u002F\u002F lib\u002Fapi-client.ts\nconst BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http:\u002F\u002Flocalhost:3001';\n\nclass ApiError extends Error {\n  constructor(public status: number, public body: any) {\n    super(body?.detail || body?.message || `API error ${status}`);\n  }\n}\n\nasync function api\u003CT>(path: string, options: RequestInit = {}): Promise\u003CT> {\n  const token = getAuthToken();  \u002F\u002F from cookie \u002F memory \u002F context\n\n  const res = await fetch(`${BASE_URL}${path}`, {\n    ...options,\n    headers: {\n      'Content-Type': 'application\u002Fjson',\n      ...(token ? { Authorization: `Bearer ${token}` } : {}),\n      ...options.headers,\n    },\n  });\n\n  if (!res.ok) {\n    const body = await res.json().catch(() => null);\n    throw new ApiError(res.status, body);\n  }\n\n  if (res.status === 204) return undefined as T;\n  return res.json();\n}\n\nexport const apiClient = {\n  get: \u003CT>(path: string) => api\u003CT>(path),\n  post: \u003CT>(path: string, data: unknown) => api\u003CT>(path, { method: 'POST', body: JSON.stringify(data) }),\n  put: \u003CT>(path: string, data: unknown) => api\u003CT>(path, { method: 'PUT', body: JSON.stringify(data) }),\n  patch: \u003CT>(path: string, data: unknown) => api\u003CT>(path, { method: 'PATCH', body: JSON.stringify(data) }),\n  delete: \u003CT>(path: string) => api\u003CT>(path, { method: 'DELETE' }),\n};\n```\n\n### Option B: React Query + Typed Client (Recommended for React)\n\n```typescript\n\u002F\u002F hooks\u002Fuse-orders.ts\nimport { useQuery, useMutation, useQueryClient } from '@tanstack\u002Freact-query';\nimport { apiClient } from '@\u002Flib\u002Fapi-client';\n\ninterface Order { id: string; total: number; status: string; }\ninterface CreateOrderInput { items: { productId: string; quantity: number }[] }\n\nexport function useOrders() {\n  return useQuery({\n    queryKey: ['orders'],\n    queryFn: () => apiClient.get\u003C{ data: Order[] }>('\u002Fapi\u002Forders'),\n    staleTime: 1000 * 60,  \u002F\u002F 1 min\n  });\n}\n\nexport function useCreateOrder() {\n  const queryClient = useQueryClient();\n  return useMutation({\n    mutationFn: (data: CreateOrderInput) =>\n      apiClient.post\u003C{ data: Order }>('\u002Fapi\u002Forders', data),\n    onSuccess: () => {\n      queryClient.invalidateQueries({ queryKey: ['orders'] });\n    },\n  });\n}\n\n\u002F\u002F Usage in component:\nfunction OrdersPage() {\n  const { data, isLoading, error } = useOrders();\n  const createOrder = useCreateOrder();\n  if (isLoading) return \u003CSkeleton \u002F>;\n  if (error) return \u003CErrorBanner error={error} \u002F>;\n  \u002F\u002F ...\n}\n```\n\n### Option C: tRPC (Same Team Owns Both Sides)\n\n```typescript\n\u002F\u002F server: trpc\u002Frouter.ts\nexport const appRouter = router({\n  orders: router({\n    list: publicProcedure.query(async () => {\n      return db.order.findMany({ include: { items: true } });\n    }),\n    create: protectedProcedure\n      .input(z.object({ items: z.array(orderItemSchema) }))\n      .mutation(async ({ input, ctx }) => {\n        return orderService.create(ctx.user.id, input);\n      }),\n  }),\n});\nexport type AppRouter = typeof appRouter;\n\n\u002F\u002F client: automatic type safety, no code generation\nconst { data } = trpc.orders.list.useQuery();\nconst createOrder = trpc.orders.create.useMutation();\n```\n\n### Option D: OpenAPI Generated Client (Public \u002F Multi-Consumer APIs)\n\n```bash\nnpx openapi-typescript-codegen \\\n  --input http:\u002F\u002Flocalhost:3001\u002Fapi\u002Fopenapi.json \\\n  --output src\u002Fgenerated\u002Fapi \\\n  --client axios\n```\n\n### Decision: Which API Client?\n\n| Approach | When | Type Safety | Effort |\n|----------|------|-------------|--------|\n| Typed fetch wrapper | Simple apps, small teams | Manual types | Low |\n| React Query + fetch | React apps, server state | Manual types | Medium |\n| tRPC | Same team, TypeScript both sides | Automatic | Low |\n| OpenAPI generated | Public API, multi-consumer | Automatic | Medium |\n| GraphQL codegen | GraphQL APIs | Automatic | Medium |\n\n---\n\n## 6. Authentication & Middleware (HIGH)\n\n> **Full reference:** [references\u002Fauth-flow.md](references\u002Fauth-flow.md) — JWT bearer flow, automatic token refresh, Next.js server-side auth, RBAC pattern, backend middleware order.\n\n### Standard Middleware Order\n\n```\nRequest → 1.RequestID → 2.Logging → 3.CORS → 4.RateLimit → 5.BodyParse\n       → 6.Auth → 7.Authz → 8.Validation → 9.Handler → 10.ErrorHandler → Response\n```\n\n### JWT Rules\n\n```\n✅ Short expiry access token (15min) + refresh token (server-stored)\n✅ Minimal claims: userId, roles (not entire user object)\n✅ Rotate signing keys periodically\n\n❌ Never store tokens in localStorage (XSS risk)\n❌ Never pass tokens in URL query params\n```\n\n### RBAC Pattern\n\n```typescript\nfunction authorize(...roles: Role[]) {\n  return (req, res, next) => {\n    if (!req.user) throw new UnauthorizedError();\n    if (!roles.some(r => req.user.roles.includes(r))) throw new ForbiddenError();\n    next();\n  };\n}\nrouter.delete('\u002Fusers\u002F:id', authenticate, authorize('admin'), deleteUser);\n```\n\n### Auth Token Automatic Refresh\n\n```typescript\n\u002F\u002F lib\u002Fapi-client.ts — transparent refresh on 401\nasync function apiWithRefresh\u003CT>(path: string, options: RequestInit = {}): Promise\u003CT> {\n  try {\n    return await api\u003CT>(path, options);\n  } catch (err) {\n    if (err instanceof ApiError && err.status === 401) {\n      const refreshed = await api\u003C{ accessToken: string }>('\u002Fapi\u002Fauth\u002Frefresh', {\n        method: 'POST',\n        credentials: 'include',  \u002F\u002F send httpOnly cookie\n      });\n      setAuthToken(refreshed.accessToken);\n      return api\u003CT>(path, options);  \u002F\u002F retry\n    }\n    throw err;\n  }\n}\n```\n\n---\n\n## 7. Logging & Observability (MEDIUM-HIGH)\n\n### Structured JSON Logging\n\n```typescript\n\u002F\u002F ✅ Structured — parseable, filterable, alertable\nlogger.info('Order created', {\n  orderId: order.id, userId: user.id, total: order.total,\n  items: order.items.length, duration_ms: Date.now() - startTime,\n});\n\u002F\u002F Output: {\"level\":\"info\",\"msg\":\"Order created\",\"orderId\":\"ord_123\",...}\n\n\u002F\u002F ❌ Unstructured — useless at scale\nconsole.log(`Order created for user ${user.id} with total ${order.total}`);\n```\n\n### Log Levels\n\n| Level | When | Production? |\n|-------|------|------------|\n| error | Requires immediate attention | ✅ Always |\n| warn | Unexpected but handled | ✅ Always |\n| info | Normal operations, audit trail | ✅ Always |\n| debug | Dev troubleshooting | ❌ Dev only |\n\n### Rules\n\n```\n✅ Request ID in every log entry (propagated via middleware)\n✅ Log at layer boundaries (request in, response out, external call)\n❌ Never log passwords, tokens, PII, or secrets\n❌ Never use console.log in production code\n```\n\n---\n\n## 8. Background Jobs & Async (MEDIUM)\n\n### Rules\n\n```\n✅ All jobs must be IDEMPOTENT (same job running twice = same result)\n✅ Failed jobs → retry (max 3) → dead letter queue → alert\n✅ Workers run as SEPARATE processes (not threads in API server)\n\n❌ Never put long-running tasks in request handlers\n❌ Never assume job runs exactly once\n```\n\n### Idempotent Job Pattern\n\n```typescript\nasync function processPayment(data: { orderId: string }) {\n  const order = await orderRepo.findById(data.orderId);\n  if (order.paymentStatus === 'completed') return;  \u002F\u002F already processed\n  await paymentGateway.charge(order);\n  await orderRepo.updatePaymentStatus(order.id, 'completed');\n}\n```\n\n---\n\n## 9. Caching Patterns (MEDIUM)\n\n### Cache-Aside (Lazy Loading)\n\n```typescript\nasync function getUser(id: string): Promise\u003CUser> {\n  const cached = await redis.get(`user:${id}`);\n  if (cached) return JSON.parse(cached);\n\n  const user = await userRepo.findById(id);\n  if (!user) throw new NotFoundError('User', id);\n\n  await redis.set(`user:${id}`, JSON.stringify(user), 'EX', 900);  \u002F\u002F 15min TTL\n  return user;\n}\n```\n\n### Rules\n\n```\n✅ ALWAYS set TTL — never cache without expiry\n✅ Invalidate on write (delete cache key after update)\n✅ Use cache for reads, never for authoritative state\n\n❌ Never cache without TTL (stale data is worse than slow data)\n```\n\n| Data Type | Suggested TTL |\n|-----------|---------------|\n| User profile | 5-15 min |\n| Product catalog | 1-5 min |\n| Config \u002F feature flags | 30-60 sec |\n| Session | Match session duration |\n\n---\n\n## 10. File Upload Patterns (MEDIUM)\n\n### Option A: Presigned URL (Recommended for Large Files)\n\n```\nClient → GET \u002Fapi\u002Fuploads\u002Fpresign?filename=photo.jpg&type=image\u002Fjpeg\nServer → { uploadUrl: \"https:\u002F\u002Fs3...\u002Fpresigned\", fileKey: \"uploads\u002Fabc123.jpg\" }\nClient → PUT uploadUrl (direct to S3, bypasses your server)\nClient → POST \u002Fapi\u002Fphotos { fileKey: \"uploads\u002Fabc123.jpg\" }  (save reference)\n```\n\n**Backend:**\n```typescript\napp.get('\u002Fapi\u002Fuploads\u002Fpresign', authenticate, async (req, res) => {\n  const { filename, type } = req.query;\n  const key = `uploads\u002F${crypto.randomUUID()}-${filename}`;\n  const url = await s3.getSignedUrl('putObject', {\n    Bucket: process.env.S3_BUCKET, Key: key,\n    ContentType: type, Expires: 300,  \u002F\u002F 5 min\n  });\n  res.json({ uploadUrl: url, fileKey: key });\n});\n```\n\n**Frontend:**\n```typescript\nasync function uploadFile(file: File) {\n  const { uploadUrl, fileKey } = await apiClient.get\u003CPresignResponse>(\n    `\u002Fapi\u002Fuploads\u002Fpresign?filename=${file.name}&type=${file.type}`\n  );\n  await fetch(uploadUrl, { method: 'PUT', body: file, headers: { 'Content-Type': file.type } });\n  return apiClient.post('\u002Fapi\u002Fphotos', { fileKey });\n}\n```\n\n### Option B: Multipart (Small Files \u003C 10MB)\n\n```typescript\n\u002F\u002F Frontend\nconst formData = new FormData();\nformData.append('file', file);\nformData.append('description', 'Profile photo');\nconst res = await fetch('\u002Fapi\u002Fupload', { method: 'POST', body: formData });\n\u002F\u002F Note: do NOT set Content-Type header — browser sets boundary automatically\n```\n\n### Decision\n\n| Method | File Size | Server Load | Complexity |\n|--------|-----------|-------------|------------|\n| Presigned URL | Any (recommended > 5MB) | None (direct to storage) | Medium |\n| Multipart | \u003C 10MB | High (streams through server) | Low |\n| Chunked \u002F Resumable | > 100MB | Medium | High |\n\n---\n\n## 11. Real-Time Patterns (MEDIUM)\n\n### Option A: Server-Sent Events (SSE) — One-Way Server → Client\n\nBest for: notifications, live feeds, streaming AI responses.\n\n**Backend (Express):**\n```typescript\napp.get('\u002Fapi\u002Fevents', authenticate, (req, res) => {\n  res.writeHead(200, {\n    'Content-Type': 'text\u002Fevent-stream',\n    'Cache-Control': 'no-cache',\n    Connection: 'keep-alive',\n  });\n  const send = (event: string, data: unknown) => {\n    res.write(`event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n  };\n  const unsubscribe = eventBus.subscribe(req.user.id, (event) => {\n    send(event.type, event.payload);\n  });\n  req.on('close', () => unsubscribe());\n});\n```\n\n**Frontend:**\n```typescript\nfunction useServerEvents(userId: string) {\n  useEffect(() => {\n    const source = new EventSource(`\u002Fapi\u002Fevents?userId=${userId}`);\n    source.addEventListener('notification', (e) => {\n      showToast(JSON.parse(e.data).message);\n    });\n    source.onerror = () => { source.close(); setTimeout(() => \u002F* reconnect *\u002F, 3000); };\n    return () => source.close();\n  }, [userId]);\n}\n```\n\n### Option B: WebSocket — Bidirectional\n\nBest for: chat, collaborative editing, gaming.\n\n**Backend (ws library):**\n```typescript\nimport { WebSocketServer } from 'ws';\nconst wss = new WebSocketServer({ server: httpServer, path: '\u002Fws' });\nwss.on('connection', (ws, req) => {\n  const userId = authenticateWs(req);\n  if (!userId) { ws.close(4001, 'Unauthorized'); return; }\n  ws.on('message', (raw) => handleMessage(userId, JSON.parse(raw.toString())));\n  ws.on('close', () => cleanupUser(userId));\n  const interval = setInterval(() => ws.ping(), 30000);\n  ws.on('pong', () => { \u002F* alive *\u002F });\n  ws.on('close', () => clearInterval(interval));\n});\n```\n\n**Frontend:**\n```typescript\nfunction useWebSocket(url: string) {\n  const [ws, setWs] = useState\u003CWebSocket | null>(null);\n  useEffect(() => {\n    const socket = new WebSocket(url);\n    socket.onopen = () => setWs(socket);\n    socket.onclose = () => setTimeout(() => \u002F* reconnect *\u002F, 3000);\n    return () => socket.close();\n  }, [url]);\n  const send = useCallback((data: unknown) => ws?.send(JSON.stringify(data)), [ws]);\n  return { ws, send };\n}\n```\n\n### Option C: Polling (Simplest, No Infrastructure)\n\n```typescript\nfunction useOrderStatus(orderId: string) {\n  return useQuery({\n    queryKey: ['order-status', orderId],\n    queryFn: () => apiClient.get\u003COrder>(`\u002Fapi\u002Forders\u002F${orderId}`),\n    refetchInterval: (query) => {\n      if (query.state.data?.status === 'completed') return false;\n      return 5000;\n    },\n  });\n}\n```\n\n### Decision\n\n| Method | Direction | Complexity | When |\n|--------|-----------|------------|------|\n| Polling | Client → Server | Low | Simple status checks, \u003C 10 clients |\n| SSE | Server → Client | Medium | Notifications, feeds, AI streaming |\n| WebSocket | Bidirectional | High | Chat, collaboration, gaming |\n\n---\n\n## 12. Cross-Boundary Error Handling (MEDIUM)\n\n### API Error → User-Facing Message\n\n```typescript\n\u002F\u002F lib\u002Ferror-handler.ts\nexport function getErrorMessage(error: unknown): string {\n  if (error instanceof ApiError) {\n    switch (error.status) {\n      case 401: return 'Please log in to continue.';\n      case 403: return 'You don\\'t have permission to do this.';\n      case 404: return 'The item you\\'re looking for doesn\\'t exist.';\n      case 409: return 'This conflicts with an existing item.';\n      case 422:\n        const fields = error.body?.errors;\n        if (fields?.length) return fields.map((f: any) => f.message).join('. ');\n        return 'Please check your input.';\n      case 429: return 'Too many requests. Please wait a moment.';\n      default: return 'Something went wrong. Please try again.';\n    }\n  }\n  if (error instanceof TypeError && error.message === 'Failed to fetch') {\n    return 'Cannot connect to server. Check your internet connection.';\n  }\n  return 'An unexpected error occurred.';\n}\n```\n\n### React Query Global Error Handler\n\n```typescript\nconst queryClient = new QueryClient({\n  defaultOptions: {\n    mutations: { onError: (error) => toast.error(getErrorMessage(error)) },\n    queries: {\n      retry: (failureCount, error) => {\n        if (error instanceof ApiError && error.status \u003C 500) return false;\n        return failureCount \u003C 3;\n      },\n    },\n  },\n});\n```\n\n### Rules\n\n```\n✅ Map every API error code to a human-readable message\n✅ Show field-level validation errors next to form inputs\n✅ Auto-retry on 5xx (max 3, with backoff), never on 4xx\n✅ Redirect to login on 401 (after refresh attempt fails)\n✅ Show \"offline\" banner when fetch fails with TypeError\n\n❌ Never show raw API error messages to users (\"NullPointerException\")\n❌ Never silently swallow errors (show toast or log)\n❌ Never retry 4xx errors (client is wrong, retrying won't help)\n```\n\n### Integration Decision Tree\n\n```\nSame team owns frontend + backend?\n│\n├─ YES, both TypeScript\n│   └─ tRPC (end-to-end type safety, zero codegen)\n│\n├─ YES, different languages\n│   └─ OpenAPI spec → generated client (type safety via codegen)\n│\n├─ NO, public API\n│   └─ REST + OpenAPI → generated SDKs for consumers\n│\n└─ Complex data needs, multiple frontends\n    └─ GraphQL + codegen (flexible queries per client)\n\nReal-time needed?\n│\n├─ Server → Client only (notifications, feeds, AI streaming)\n│   └─ SSE (simplest, auto-reconnect, works through proxies)\n│\n├─ Bidirectional (chat, collaboration)\n│   └─ WebSocket (need heartbeat + reconnection logic)\n│\n└─ Simple status polling (\u003C 10 clients)\n    └─ React Query refetchInterval (no infrastructure needed)\n```\n\n---\n\n## 13. Production Hardening (MEDIUM)\n\n### Health Checks\n\n```typescript\napp.get('\u002Fhealth', (req, res) => res.json({ status: 'ok' }));           \u002F\u002F liveness\napp.get('\u002Fready', async (req, res) => {                                   \u002F\u002F readiness\n  const checks = {\n    database: await checkDb(), redis: await checkRedis(), \n  };\n  const ok = Object.values(checks).every(c => c.status === 'ok');\n  res.status(ok ? 200 : 503).json({ status: ok ? 'ok' : 'degraded', checks });\n});\n```\n\n### Graceful Shutdown\n\n```typescript\nprocess.on('SIGTERM', async () => {\n  logger.info('SIGTERM received');\n  server.close();              \u002F\u002F stop new connections\n  await drainConnections();    \u002F\u002F finish in-flight\n  await closeDatabase();\n  process.exit(0);\n});\n```\n\n### Security Checklist\n\n```\n✅ CORS: explicit origins (never '*' in production)\n✅ Security headers (helmet \u002F equivalent)\n✅ Rate limiting on public endpoints\n✅ Input validation on ALL endpoints (trust nothing)\n✅ HTTPS enforced\n❌ Never expose internal errors to clients\n```\n\n---\n\n## Anti-Patterns\n\n| # | ❌ Don't | ✅ Do Instead |\n|---|---------|--------------|\n| 1 | Business logic in routes\u002Fcontrollers | Move to service layer |\n| 2 | `process.env` scattered everywhere | Centralized typed config |\n| 3 | `console.log` for logging | Structured JSON logger |\n| 4 | Generic `Error('oops')` | Typed error hierarchy |\n| 5 | Direct DB calls in controllers | Repository pattern |\n| 6 | No input validation | Validate at boundary (Zod\u002FPydantic) |\n| 7 | Catching errors silently | Log + rethrow or return error |\n| 8 | No health check endpoints | `\u002Fhealth` + `\u002Fready` |\n| 9 | Hardcoded config\u002Fsecrets | Environment variables |\n| 10 | No graceful shutdown | Handle SIGTERM properly |\n| 11 | Hardcode API URL in frontend | Environment variable (`NEXT_PUBLIC_API_URL`) |\n| 12 | Store JWT in localStorage | Memory + httpOnly refresh cookie |\n| 13 | Show raw API errors to users | Map to human-readable messages |\n| 14 | Retry 4xx errors | Only retry 5xx (server failures) |\n| 15 | Skip loading states | Skeleton\u002Fspinner while fetching |\n| 16 | Upload large files through API server | Presigned URL → direct to S3 |\n| 17 | Poll for real-time data | SSE or WebSocket |\n| 18 | Duplicate types frontend + backend | Shared types, tRPC, or OpenAPI codegen |\n\n---\n\n## Common Issues\n\n### Issue 1: \"Where does this business rule go?\"\n\n**Rule:** If it involves HTTP (request parsing, status codes, headers) → controller. If it involves business decisions (pricing, permissions, rules) → service. If it touches the database → repository.\n\n### Issue 2: \"Service is getting too big\"\n\n**Symptom:** One service file > 500 lines with 20+ methods.\n\n**Fix:** Split by sub-domain. `OrderService` → `OrderCreationService` + `OrderFulfillmentService` + `OrderQueryService`. Each focused on one workflow.\n\n### Issue 3: \"Tests are slow because they hit the database\"\n\n**Fix:** Unit tests mock the repository layer (fast). Integration tests use test containers or transaction rollback (real DB, still fast). Never mock the service layer in integration tests.\n\n---\n\n## Reference Documents\n\nThis skill includes deep-dive references for specialized topics. Read the relevant reference when you need detailed guidance.\n\n| Need to… | Reference |\n|----------|-----------|\n| Write backend tests (unit, integration, e2e, contract, performance) | [references\u002Ftesting-strategy.md](references\u002Ftesting-strategy.md) |\n| Validate a release before deployment (6-gate checklist) | [references\u002Frelease-checklist.md](references\u002Frelease-checklist.md) |\n| Choose a tech stack (language, framework, database, infra) | [references\u002Ftechnology-selection.md](references\u002Ftechnology-selection.md) |\n| Build with Django \u002F DRF (models, views, serializers, admin) | [references\u002Fdjango-best-practices.md](references\u002Fdjango-best-practices.md) |\n| Design REST\u002FGraphQL\u002FgRPC endpoints (URLs, status codes, pagination) | [references\u002Fapi-design.md](references\u002Fapi-design.md) |\n| Design database schema, indexes, migrations, multi-tenancy | [references\u002Fdb-schema.md](references\u002Fdb-schema.md) |\n| Auth flow (JWT bearer, token refresh, Next.js SSR, RBAC, middleware order) | [references\u002Fauth-flow.md](references\u002Fauth-flow.md) |\n| CORS config, env vars per environment, common CORS issues | [references\u002Fenvironment-management.md](references\u002Fenvironment-management.md) |\n","# Full-Stack Development Practices\n\n## MANDATORY WORKFLOW — Follow These Steps In Order\n\n**When this skill is triggered, you MUST follow this workflow before writing any code.**\n\n### Step 0: Gather Requirements\n\nBefore scaffolding anything, ask the user to clarify (or infer from context):\n\n1. **Stack**: Language\u002Fframework for backend and frontend (e.g., Express + React, Django + Vue, Go + HTMX)\n2. **Service type**: API-only, full-stack monolith, or microservice?\n3. **Database**: SQL (PostgreSQL, SQLite, MySQL) or NoSQL (MongoDB, Redis)?\n4. **Integration**: REST, GraphQL, tRPC, or gRPC?\n5. **Real-time**: Needed? If yes — SSE, WebSocket, or polling?\n6. **Auth**: Needed? If yes — JWT, session, OAuth, or third-party (Clerk, Auth.js)?\n\nIf the user has already specified these in their request, skip asking and proceed.\n\n### Step 1: Architectural Decisions\n\nBased on requirements, make and state these decisions before coding:\n\n| Decision | Options | Reference |\n|----------|---------|-----------|\n| Project structure | Feature-first (recommended) vs layer-first | [Section 1](#1-project-structure--layering-critical) |\n| API client approach | Typed fetch \u002F React Query \u002F tRPC \u002F OpenAPI codegen | [Section 5](#5-api-client-patterns-medium) |\n| Auth strategy | JWT + refresh \u002F session \u002F third-party | [Section 6](#6-authentication--middleware-high) |\n| Real-time method | Polling \u002F SSE \u002F WebSocket | [Section 11](#11-real-time-patterns-medium) |\n| Error handling | Typed error hierarchy + global handler | [Section 3](#3-error-handling--resilience-high) |\n\nBriefly explain each choice (1 sentence per decision).\n\n### Step 2: Scaffold with Checklist\n\nUse the appropriate checklist below. Ensure ALL checked items are implemented — do not skip any.\n\n### Step 3: Implement Following Patterns\n\nWrite code following the patterns in this document. Reference specific sections as you implement each part.\n\n### Step 4: Test & Verify\n\nAfter implementation, run these checks before claiming completion:\n\n1. **Build check**: Ensure both backend and frontend compile without errors\n   ```bash\n   # Backend\n   cd server && npm run build\n   # Frontend\n   cd client && npm run build\n   ```\n2. **Start & smoke test**: Start the server, verify key endpoints return expected responses\n   ```bash\n   # Start server, then test\n   curl http:\u002F\u002Flocalhost:3000\u002Fhealth\n   curl http:\u002F\u002Flocalhost:3000\u002Fapi\u002F\u003Cresource>\n   ```\n3. **Integration check**: Verify frontend can connect to backend (CORS, API base URL, auth flow)\n4. **Real-time check** (if applicable): Open two browser tabs, verify changes sync\n\nIf any check fails, fix the issue before proceeding.\n\n### Step 5: Handoff Summary\n\nProvide a brief summary to the user:\n\n- **What was built**: List of implemented features and endpoints\n- **How to run**: Exact commands to start backend and frontend\n- **What's missing \u002F next steps**: Any deferred items, known limitations, or recommended improvements\n- **Key files**: List the most important files the user should know about\n\n---\n\n## Scope\n\n**USE this skill when:**\n- Building a full-stack application (backend + frontend)\n- Scaffolding a new backend service or API\n- Designing service layers and module boundaries\n- Implementing database access, caching, or background jobs\n- Writing error handling, logging, or configuration management\n- Reviewing backend code for architectural issues\n- Hardening for production\n- Setting up API clients, auth flows, file uploads, or real-time features\n\n**NOT for:**\n- Pure frontend\u002FUI concerns (use your frontend framework's docs)\n- Pure database schema design without backend context\n\n---\n\n## Quick Start — New Backend Service Checklist\n\n- [ ] Project scaffolded with **feature-first** structure\n- [ ] Configuration **centralized**, env vars **validated at startup** (fail fast)\n- [ ] **Typed error hierarchy** defined (not generic `Error`)\n- [ ] **Global error handler** middleware\n- [ ] **Structured JSON logging** with request ID propagation\n- [ ] Database: **migrations** set up, **connection pooling** configured\n- [ ] **Input validation** on all endpoints (Zod \u002F Pydantic \u002F Go validator)\n- [ ] **Authentication middleware** in place\n- [ ] **Health check** endpoints (`\u002Fhealth`, `\u002Fready`)\n- [ ] **Graceful shutdown** handling (SIGTERM)\n- [ ] **CORS** configured (explicit origins, not `*`)\n- [ ] **Security headers** (helmet or equivalent)\n- [ ] `.env.example` committed (no real secrets)\n\n## Quick Start — Frontend-Backend Integration Checklist\n\n- [ ] **API client** configured (typed fetch wrapper, React Query, tRPC, or OpenAPI generated)\n- [ ] **Base URL** from environment variable (not hardcoded)\n- [ ] **Auth token** attached to requests automatically (interceptor \u002F middleware)\n- [ ] **Error handling** — API errors mapped to user-facing messages\n- [ ] **Loading states** handled (skeleton\u002Fspinner, not blank screen)\n- [ ] **Type safety** across the boundary (shared types, OpenAPI, or tRPC)\n- [ ] **CORS** configured with explicit origins (not `*` in production)\n- [ ] **Refresh token** flow implemented (httpOnly cookie + transparent retry on 401)\n\n---\n\n## Quick Navigation\n\n| Need to… | Jump to |\n|----------|---------|\n| Organize project folders | [1. Project Structure](#1-project-structure--layering-critical) |\n| Manage config + secrets | [2. Configuration](#2-configuration--environment-critical) |\n| Handle errors properly | [3. Error Handling](#3-error-handling--resilience-high) |\n| Write database code | [4. Database Access Patterns](#4-database-access-patterns-high) |\n| Set up API client from frontend | [5. API Client Patterns](#5-api-client-patterns-medium) |\n| Add auth middleware | [6. Auth & Middleware](#6-authentication--middleware-high) |\n| Set up logging | [7. Logging & Observability](#7-logging--observability-medium-high) |\n| Add background jobs | [8. Background Jobs](#8-background-jobs--async-medium) |\n| Implement caching | [9. Caching](#9-caching-patterns-medium) |\n| Upload files (presigned URL, multipart) | [10. File Upload Patterns](#10-file-upload-patterns-medium) |\n| Add real-time features (SSE, WebSocket) | [11. Real-Time Patterns](#11-real-time-patterns-medium) |\n| Handle API errors in frontend UI | [12. Cross-Boundary Error Handling](#12-cross-boundary-error-handling-medium) |\n| Harden for production | [13. Production Hardening](#13-production-hardening-medium) |\n| Design API endpoints | [API Design](references\u002Fapi-design.md) |\n| Design database schema | [Database Schema](references\u002Fdb-schema.md) |\n| Auth flow (JWT, refresh, Next.js SSR, RBAC) | [references\u002Fauth-flow.md](references\u002Fauth-flow.md) |\n| CORS, env vars, environment management | [references\u002Fenvironment-management.md](references\u002Fenvironment-management.md) |\n\n---\n\n## Core Principles (7 Iron Rules)\n\n```\n1. ✅ Organize by FEATURE, not by technical layer\n2. ✅ Controllers never contain business logic\n3. ✅ Services never import HTTP request\u002Fresponse types\n4. ✅ All config from env vars, validated at startup, fail fast\n5. ✅ Every error is typed, logged, and returns consistent format\n6. ✅ All input validated at the boundary — trust nothing from client\n7. ✅ Structured JSON logging with request ID — not console.log\n```\n\n---\n\n## 1. Project Structure & Layering (CRITICAL)\n\n### Feature-First Organization\n\n```\n✅ Feature-first                    ❌ Layer-first\nsrc\u002F                                src\u002F\n  orders\u002F                             controllers\u002F\n    order.controller.ts                 order.controller.ts\n    order.service.ts                    user.controller.ts\n    order.repository.ts               services\u002F\n    order.dto.ts                        order.service.ts\n    order.test.ts                       user.service.ts\n  users\u002F                              repositories\u002F\n    user.controller.ts                  ...\n    user.service.ts\n  shared\u002F\n    database\u002F\n    middleware\u002F\n```\n\n### Three-Layer Architecture\n\n```\nController (HTTP) → Service (Business Logic) → Repository (Data Access)\n```\n\n| Layer | Responsibility | ❌ Never |\n|-------|---------------|---------|\n| Controller | Parse request, validate, call service, format response | Business logic, DB queries |\n| Service | Business rules, orchestration, transaction mgmt | HTTP types (req\u002Fres), direct DB |\n| Repository | Database queries, external API calls | Business logic, HTTP types |\n\n### Dependency Injection (All Languages)\n\n**TypeScript:**\n```typescript\nclass OrderService {\n  constructor(\n    private readonly orderRepo: OrderRepository,    \u002F\u002F ✅ injected interface\n    private readonly emailService: EmailService,\n  ) {}\n}\n```\n\n**Python:**\n```python\nclass OrderService:\n    def __init__(self, order_repo: OrderRepository, email_service: EmailService):\n        self.order_repo = order_repo                 # ✅ injected\n        self.email_service = email_service\n```\n\n**Go:**\n```go\ntype OrderService struct {\n    orderRepo    OrderRepository                      \u002F\u002F ✅ interface\n    emailService EmailService\n}\n\nfunc NewOrderService(repo OrderRepository, email EmailService) *OrderService {\n    return &OrderService{orderRepo: repo, emailService: email}\n}\n```\n\n---\n\n## 2. Configuration & Environment (CRITICAL)\n\n### Centralized, Typed, Fail-Fast\n\n**TypeScript:**\n```typescript\nconst config = {\n  port: parseInt(process.env.PORT || '3000', 10),\n  database: { url: requiredEnv('DATABASE_URL'), poolSize: intEnv('DB_POOL_SIZE', 10) },\n  auth: { jwtSecret: requiredEnv('JWT_SECRET'), expiresIn: process.env.JWT_EXPIRES_IN || '1h' },\n} as const;\n\nfunction requiredEnv(name: string): string {\n  const value = process.env[name];\n  if (!value) throw new Error(`Missing required env var: ${name}`);  \u002F\u002F fail fast\n  return value;\n}\n```\n\n**Python:**\n```python\nfrom pydantic_settings import BaseSettings\n\nclass Settings(BaseSettings):\n    database_url: str                        # required — app won't start without it\n    jwt_secret: str                          # required\n    port: int = 3000                         # optional with default\n    db_pool_size: int = 10\n    class Config:\n        env_file = \".env\"\n\nsettings = Settings()                        # fails fast if DATABASE_URL missing\n```\n\n### Rules\n\n```\n✅ All config via environment variables (Twelve-Factor)\n✅ Validate required vars at startup — fail fast\n✅ Type-cast at config layer, not at usage sites\n✅ Commit .env.example with dummy values\n\n❌ Never hardcode secrets, URLs, or credentials\n❌ Never commit .env files\n❌ Never scatter process.env \u002F os.environ throughout code\n```\n\n---\n\n## 3. Error Handling & Resilience (HIGH)\n\n### Typed Error Hierarchy\n\n```typescript\n\u002F\u002F Base (TypeScript)\nclass AppError extends Error {\n  constructor(\n    message: string,\n    public readonly code: string,\n    public readonly statusCode: number,\n    public readonly isOperational: boolean = true,\n  ) { super(message); }\n}\nclass NotFoundError extends AppError {\n  constructor(resource: string, id: string) {\n    super(`${resource} not found: ${id}`, 'NOT_FOUND', 404);\n  }\n}\nclass ValidationError extends AppError {\n  constructor(public readonly errors: FieldError[]) {\n    super('Validation failed', 'VALIDATION_ERROR', 422);\n  }\n}\n```\n\n```python\n# Base (Python)\nclass AppError(Exception):\n    def __init__(self, message: str, code: str, status_code: int):\n        self.message, self.code, self.status_code = message, code, status_code\n\nclass NotFoundError(AppError):\n    def __init__(self, resource: str, id: str):\n        super().__init__(f\"{resource} not found: {id}\", \"NOT_FOUND\", 404)\n```\n\n### Global Error Handler\n\n```typescript\n\u002F\u002F TypeScript (Express)\napp.use((err, req, res, next) => {\n  if (err instanceof AppError && err.isOperational) {\n    return res.status(err.statusCode).json({\n      title: err.code, status: err.statusCode,\n      detail: err.message, request_id: req.id,\n    });\n  }\n  logger.error('Unexpected error', { error: err.message, stack: err.stack, request_id: req.id });\n  res.status(500).json({ title: 'Internal Error', status: 500, request_id: req.id });\n});\n```\n\n### Rules\n\n```\n✅ Typed, domain-specific error classes\n✅ Global error handler catches everything\n✅ Operational errors → structured response\n✅ Programming errors → log + generic 500\n✅ Retry transient failures with exponential backoff\n\n❌ Never catch and ignore errors silently\n❌ Never return stack traces to client\n❌ Never throw generic Error('something')\n```\n\n---\n\n## 4. Database Access Patterns (HIGH)\n\n### Migrations Always\n\n```bash\n# TypeScript (Prisma)           # Python (Alembic)              # Go (golang-migrate)\nnpx prisma migrate dev          alembic revision --autogenerate  migrate -source file:\u002F\u002Fmigrations\nnpx prisma migrate deploy       alembic upgrade head             migrate -database $DB up\n```\n\n```\n✅ Schema changes via migrations, never manual SQL\n✅ Migrations must be reversible\n✅ Review migration SQL before production\n❌ Never modify production schema manually\n```\n\n### N+1 Prevention\n\n```typescript\n\u002F\u002F ❌ N+1: 1 query + N queries\nconst orders = await db.order.findMany();\nfor (const o of orders) { o.items = await db.item.findMany({ where: { orderId: o.id } }); }\n\n\u002F\u002F ✅ Single JOIN query\nconst orders = await db.order.findMany({ include: { items: true } });\n```\n\n### Transactions for Multi-Step Writes\n\n```typescript\nawait db.$transaction(async (tx) => {\n  const order = await tx.order.create({ data: orderData });\n  await tx.inventory.decrement({ productId, quantity });\n  await tx.payment.create({ orderId: order.id, amount });\n});\n```\n\n### Connection Pooling\n\nPool size = `(CPU cores × 2) + spindle_count` (start with 10-20). Always set connection timeout. Use PgBouncer for serverless.\n\n---\n\n## 5. API Client Patterns (MEDIUM)\n\nThe \"glue layer\" between frontend and backend. Choose the approach that fits your team and stack.\n\n### Option A: Typed Fetch Wrapper (Simple, No Dependencies)\n\n```typescript\n\u002F\u002F lib\u002Fapi-client.ts\nconst BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http:\u002F\u002Flocalhost:3001';\n\nclass ApiError extends Error {\n  constructor(public status: number, public body: any) {\n    super(body?.detail || body?.message || `API error ${status}`);\n  }\n}\n\nasync function api\u003CT>(path: string, options: RequestInit = {}): Promise\u003CT> {\n  const token = getAuthToken();  \u002F\u002F from cookie \u002F memory \u002F context\n\n  const res = await fetch(`${BASE_URL}${path}`, {\n    ...options,\n    headers: {\n      'Content-Type': 'application\u002Fjson',\n      ...(token ? { Authorization: `Bearer ${token}` } : {}),\n      ...options.headers,\n    },\n  });\n\n  if (!res.ok) {\n    const body = await res.json().catch(() => null);\n    throw new ApiError(res.status, body);\n  }\n\n  if (res.status === 204) return undefined as T;\n  return res.json();\n}\n\nexport const apiClient = {\n  get: \u003CT>(path: string) => api\u003CT>(path),\n  post: \u003CT>(path: string, data: unknown) => api\u003CT>(path, { method: 'POST', body: JSON.stringify(data) }),\n  put: \u003CT>(path: string, data: unknown) => api\u003CT>(path, { method: 'PUT', body: JSON.stringify(data) }),\n  patch: \u003CT>(path: string, data: unknown) => api\u003CT>(path, { method: 'PATCH', body: JSON.stringify(data) }),\n  delete: \u003CT>(path: string) => api\u003CT>(path, { method: 'DELETE' }),\n};\n```\n\n### Option B: React Query + Typed Client (Recommended for React)\n\n```typescript\n\u002F\u002F hooks\u002Fuse-orders.ts\nimport { useQuery, useMutation, useQueryClient } from '@tanstack\u002Freact-query';\nimport { apiClient } from '@\u002Flib\u002Fapi-client';\n\ninterface Order { id: string; total: number; status: string; }\ninterface CreateOrderInput { items: { productId: string; quantity: number }[] }\n\nexport function useOrders() {\n  return useQuery({\n    queryKey: ['orders'],\n    queryFn: () => apiClient.get\u003C{ data: Order[] }>('\u002Fapi\u002Forders'),\n    staleTime: 1000 * 60,  \u002F\u002F 1 min\n  });\n}\n\nexport function useCreateOrder() {\n  const queryClient = useQueryClient();\n  return useMutation({\n    mutationFn: (data: CreateOrderInput) =>\n      apiClient.post\u003C{ data: Order }>('\u002Fapi\u002Forders', data),\n    onSuccess: () => {\n      queryClient.invalidateQueries({ queryKey: ['orders'] });\n    },\n  });\n}\n\n\u002F\u002F Usage in component:\nfunction OrdersPage() {\n  const { data, isLoading, error } = useOrders();\n  const createOrder = useCreateOrder();\n  if (isLoading) return \u003CSkeleton \u002F>;\n  if (error) return \u003CErrorBanner error={error} \u002F>;\n  \u002F\u002F ...\n}\n```\n\n### Option C: tRPC (Same Team Owns Both Sides)\n\n```typescript\n\u002F\u002F server: trpc\u002Frouter.ts\nexport const appRouter = router({\n  orders: router({\n    list: publicProcedure.query(async () => {\n      return db.order.findMany({ include: { items: true } });\n    }),\n    create: protectedProcedure\n      .input(z.object({ items: z.array(orderItemSchema) }))\n      .mutation(async ({ input, ctx }) => {\n        return orderService.create(ctx.user.id, input);\n      }),\n  }),\n});\nexport type AppRouter = typeof appRouter;\n\n\u002F\u002F client: automatic type safety, no code generation\nconst { data } = trpc.orders.list.useQuery();\nconst createOrder = trpc.orders.create.useMutation();\n```\n\n### Option D: OpenAPI Generated Client (Public \u002F Multi-Consumer APIs)\n\n```bash\nnpx openapi-typescript-codegen \\\n  --input http:\u002F\u002Flocalhost:3001\u002Fapi\u002Fopenapi.json \\\n  --output src\u002Fgenerated\u002Fapi \\\n  --client axios\n```\n\n### Decision: Which API Client?\n\n| Approach | When | Type Safety | Effort |\n|----------|------|-------------|--------|\n| Typed fetch wrapper | Simple apps, small teams | Manual types | Low |\n| React Query + fetch | React apps, server state | Manual types | Medium |\n| tRPC | Same team, TypeScript both sides | Automatic | Low |\n| OpenAPI generated | Public API, multi-consumer | Automatic | Medium |\n| GraphQL codegen | GraphQL APIs | Automatic | Medium |\n\n---\n\n## 6. Authentication & Middleware (HIGH)\n\n> **Full reference:** [references\u002Fauth-flow.md](references\u002Fauth-flow.md) — JWT bearer flow, automatic token refresh, Next.js server-side auth, RBAC pattern, backend middleware order.\n\n### Standard Middleware Order\n\n```\nRequest → 1.RequestID → 2.Logging → 3.CORS → 4.RateLimit → 5.BodyParse\n       → 6.Auth → 7.Authz → 8.Validation → 9.Handler → 10.ErrorHandler → Response\n```\n\n### JWT Rules\n\n```\n✅ Short expiry access token (15min) + refresh token (server-stored)\n✅ Minimal claims: userId, roles (not entire user object)\n✅ Rotate signing keys periodically\n\n❌ Never store tokens in localStorage (XSS risk)\n❌ Never pass tokens in URL query params\n```\n\n### RBAC Pattern\n\n```typescript\nfunction authorize(...roles: Role[]) {\n  return (req, res, next) => {\n    if (!req.user) throw new UnauthorizedError();\n    if (!roles.some(r => req.user.roles.includes(r))) throw new ForbiddenError();\n    next();\n  };\n}\nrouter.delete('\u002Fusers\u002F:id', authenticate, authorize('admin'), deleteUser);\n```\n\n### Auth Token Automatic Refresh\n\n```typescript\n\u002F\u002F lib\u002Fapi-client.ts — transparent refresh on 401\nasync function apiWithRefresh\u003CT>(path: string, options: RequestInit = {}): Promise\u003CT> {\n  try {\n    return await api\u003CT>(path, options);\n  } catch (err) {\n    if (err instanceof ApiError && err.status === 401) {\n      const refreshed = await api\u003C{ accessToken: string }>('\u002Fapi\u002Fauth\u002Frefresh', {\n        method: 'POST',\n        credentials: 'include',  \u002F\u002F send httpOnly cookie\n      });\n      setAuthToken(refreshed.accessToken);\n      return api\u003CT>(path, options);  \u002F\u002F retry\n    }\n    throw err;\n  }\n}\n```\n\n---\n\n## 7. Logging & Observability (MEDIUM-HIGH)\n\n### Structured JSON Logging\n\n```typescript\n\u002F\u002F ✅ Structured — parseable, filterable, alertable\nlogger.info('Order created', {\n  orderId: order.id, userId: user.id, total: order.total,\n  items: order.items.length, duration_ms: Date.now() - startTime,\n});\n\u002F\u002F Output: {\"level\":\"info\",\"msg\":\"Order created\",\"orderId\":\"ord_123\",...}\n\n\u002F\u002F ❌ Unstructured — useless at scale\nconsole.log(`Order created for user ${user.id} with total ${order.total}`);\n```\n\n### Log Levels\n\n| Level | When | Production? |\n|-------|------|------------|\n| error | Requires immediate attention | ✅ Always |\n| warn | Unexpected but handled | ✅ Always |\n| info | Normal operations, audit trail | ✅ Always |\n| debug | Dev troubleshooting | ❌ Dev only |\n\n### Rules\n\n```\n✅ Request ID in every log entry (propagated via middleware)\n✅ Log at layer boundaries (request in, response out, external call)\n❌ Never log passwords, tokens, PII, or secrets\n❌ Never use console.log in production code\n```\n\n---\n\n## 8. Background Jobs & Async (MEDIUM)\n\n### Rules\n\n```\n✅ All jobs must be IDEMPOTENT (same job running twice = same result)\n✅ Failed jobs → retry (max 3) → dead letter queue → alert\n✅ Workers run as SEPARATE processes (not threads in API server)\n\n❌ Never put long-running tasks in request handlers\n❌ Never assume job runs exactly once\n```\n\n### Idempotent Job Pattern\n\n```typescript\nasync function processPayment(data: { orderId: string }) {\n  const order = await orderRepo.findById(data.orderId);\n  if (order.paymentStatus === 'completed') return;  \u002F\u002F already processed\n  await paymentGateway.charge(order);\n  await orderRepo.updatePaymentStatus(order.id, 'completed');\n}\n```\n\n---\n\n## 9. Caching Patterns (MEDIUM)\n\n### Cache-Aside (Lazy Loading)\n\n```typescript\nasync function getUser(id: string): Promise\u003CUser> {\n  const cached = await redis.get(`user:${id}`);\n  if (cached) return JSON.parse(cached);\n\n  const user = await userRepo.findById(id);\n  if (!user) throw new NotFoundError('User', id);\n\n  await redis.set(`user:${id}`, JSON.stringify(user), 'EX', 900);  \u002F\u002F 15min TTL\n  return user;\n}\n```\n\n### Rules\n\n```\n✅ ALWAYS set TTL — never cache without expiry\n✅ Invalidate on write (delete cache key after update)\n✅ Use cache for reads, never for authoritative state\n\n❌ Never cache without TTL (stale data is worse than slow data)\n```\n\n| Data Type | Suggested TTL |\n|-----------|---------------|\n| User profile | 5-15 min |\n| Product catalog | 1-5 min |\n| Config \u002F feature flags | 30-60 sec |\n| Session | Match session duration |\n\n---\n\n## 10. File Upload Patterns (MEDIUM)\n\n### Option A: Presigned URL (Recommended for Large Files)\n\n```\nClient → GET \u002Fapi\u002Fuploads\u002Fpresign?filename=photo.jpg&type=image\u002Fjpeg\nServer → { uploadUrl: \"https:\u002F\u002Fs3...\u002Fpresigned\", fileKey: \"uploads\u002Fabc123.jpg\" }\nClient → PUT uploadUrl (direct to S3, bypasses your server)\nClient → POST \u002Fapi\u002Fphotos { fileKey: \"uploads\u002Fabc123.jpg\" }  (save reference)\n```\n\n**Backend:**\n```typescript\napp.get('\u002Fapi\u002Fuploads\u002Fpresign', authenticate, async (req, res) => {\n  const { filename, type } = req.query;\n  const key = `uploads\u002F${crypto.randomUUID()}-${filename}`;\n  const url = await s3.getSignedUrl('putObject', {\n    Bucket: process.env.S3_BUCKET, Key: key,\n    ContentType: type, Expires: 300,  \u002F\u002F 5 min\n  });\n  res.json({ uploadUrl: url, fileKey: key });\n});\n```\n\n**Frontend:**\n```typescript\nasync function uploadFile(file: File) {\n  const { uploadUrl, fileKey } = await apiClient.get\u003CPresignResponse>(\n    `\u002Fapi\u002Fuploads\u002Fpresign?filename=${file.name}&type=${file.type}`\n  );\n  await fetch(uploadUrl, { method: 'PUT', body: file, headers: { 'Content-Type': file.type } });\n  return apiClient.post('\u002Fapi\u002Fphotos', { fileKey });\n}\n```\n\n### Option B: Multipart (Small Files \u003C 10MB)\n\n```typescript\n\u002F\u002F Frontend\nconst formData = new FormData();\nformData.append('file', file);\nformData.append('description', 'Profile photo');\nconst res = await fetch('\u002Fapi\u002Fupload', { method: 'POST', body: formData });\n\u002F\u002F Note: do NOT set Content-Type header — browser sets boundary automatically\n```\n\n### Decision\n\n| Method | File Size | Server Load | Complexity |\n|--------|-----------|-------------|------------|\n| Presigned URL | Any (recommended > 5MB) | None (direct to storage) | Medium |\n| Multipart | \u003C 10MB | High (streams through server) | Low |\n| Chunked \u002F Resumable | > 100MB | Medium | High |\n\n---\n\n## 11. Real-Time Patterns (MEDIUM)\n\n### Option A: Server-Sent Events (SSE) — One-Way Server → Client\n\nBest for: notifications, live feeds, streaming AI responses.\n\n**Backend (Express):**\n```typescript\napp.get('\u002Fapi\u002Fevents', authenticate, (req, res) => {\n  res.writeHead(200, {\n    'Content-Type': 'text\u002Fevent-stream',\n    'Cache-Control': 'no-cache',\n    Connection: 'keep-alive',\n  });\n  const send = (event: string, data: unknown) => {\n    res.write(`event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n  };\n  const unsubscribe = eventBus.subscribe(req.user.id, (event) => {\n    send(event.type, event.payload);\n  });\n  req.on('close', () => unsubscribe());\n});\n```\n\n**Frontend:**\n```typescript\nfunction useServerEvents(userId: string) {\n  useEffect(() => {\n    const source = new EventSource(`\u002Fapi\u002Fevents?userId=${userId}`);\n    source.addEventListener('notification', (e) => {\n      showToast(JSON.parse(e.data).message);\n    });\n    source.onerror = () => { source.close(); setTimeout(() => \u002F* reconnect *\u002F, 3000); };\n    return () => source.close();\n  }, [userId]);\n}\n```\n\n### Option B: WebSocket — Bidirectional\n\nBest for: chat, collaborative editing, gaming.\n\n**Backend (ws library):**\n```typescript\nimport { WebSocketServer } from 'ws';\nconst wss = new WebSocketServer({ server: httpServer, path: '\u002Fws' });\nwss.on('connection', (ws, req) => {\n  const userId = authenticateWs(req);\n  if (!userId) { ws.close(4001, 'Unauthorized'); return; }\n  ws.on('message', (raw) => handleMessage(userId, JSON.parse(raw.toString())));\n  ws.on('close', () => cleanupUser(userId));\n  const interval = setInterval(() => ws.ping(), 30000);\n  ws.on('pong', () => { \u002F* alive *\u002F });\n  ws.on('close', () => clearInterval(interval));\n});\n```\n\n**Frontend:**\n```typescript\nfunction useWebSocket(url: string) {\n  const [ws, setWs] = useState\u003CWebSocket | null>(null);\n  useEffect(() => {\n    const socket = new WebSocket(url);\n    socket.onopen = () => setWs(socket);\n    socket.onclose = () => setTimeout(() => \u002F* reconnect *\u002F, 3000);\n    return () => socket.close();\n  }, [url]);\n  const send = useCallback((data: unknown) => ws?.send(JSON.stringify(data)), [ws]);\n  return { ws, send };\n}\n```\n\n### Option C: Polling (Simplest, No Infrastructure)\n\n```typescript\nfunction useOrderStatus(orderId: string) {\n  return useQuery({\n    queryKey: ['order-status', orderId],\n    queryFn: () => apiClient.get\u003COrder>(`\u002Fapi\u002Forders\u002F${orderId}`),\n    refetchInterval: (query) => {\n      if (query.state.data?.status === 'completed') return false;\n      return 5000;\n    },\n  });\n}\n```\n\n### Decision\n\n| Method | Direction | Complexity | When |\n|--------|-----------|------------|------|\n| Polling | Client → Server | Low | Simple status checks, \u003C 10 clients |\n| SSE | Server → Client | Medium | Notifications, feeds, AI streaming |\n| WebSocket | Bidirectional | High | Chat, collaboration, gaming |\n\n---\n\n## 12. Cross-Boundary Error Handling (MEDIUM)\n\n### API Error → User-Facing Message\n\n```typescript\n\u002F\u002F lib\u002Ferror-handler.ts\nexport function getErrorMessage(error: unknown): string {\n  if (error instanceof ApiError) {\n    switch (error.status) {\n      case 401: return 'Please log in to continue.';\n      case 403: return 'You don\\'t have permission to do this.';\n      case 404: return 'The item you\\'re looking for doesn\\'t exist.';\n      case 409: return 'This conflicts with an existing item.';\n      case 422:\n        const fields = error.body?.errors;\n        if (fields?.length) return fields.map((f: any) => f.message).join('. ');\n        return 'Please check your input.';\n      case 429: return 'Too many requests. Please wait a moment.';\n      default: return 'Something went wrong. Please try again.';\n    }\n  }\n  if (error instanceof TypeError && error.message === 'Failed to fetch') {\n    return 'Cannot connect to server. Check your internet connection.';\n  }\n  return 'An unexpected error occurred.';\n}\n```\n\n### React Query Global Error Handler\n\n```typescript\nconst queryClient = new QueryClient({\n  defaultOptions: {\n    mutations: { onError: (error) => toast.error(getErrorMessage(error)) },\n    queries: {\n      retry: (failureCount, error) => {\n        if (error instanceof ApiError && error.status \u003C 500) return false;\n        return failureCount \u003C 3;\n      },\n    },\n  },\n});\n```\n\n### Rules\n\n```\n✅ Map every API error code to a human-readable message\n✅ Show field-level validation errors next to form inputs\n✅ Auto-retry on 5xx (max 3, with backoff), never on 4xx\n✅ Redirect to login on 401 (after refresh attempt fails)\n✅ Show \"offline\" banner when fetch fails with TypeError\n\n❌ Never show raw API error messages to users (\"NullPointerException\")\n❌ Never silently swallow errors (show toast or log)\n❌ Never retry 4xx errors (client is wrong, retrying won't help)\n```\n\n### Integration Decision Tree\n\n```\nSame team owns frontend + backend?\n│\n├─ YES, both TypeScript\n│   └─ tRPC (end-to-end type safety, zero codegen)\n│\n├─ YES, different languages\n│   └─ OpenAPI spec → generated client (type safety via codegen)\n│\n├─ NO, public API\n│   └─ REST + OpenAPI → generated SDKs for consumers\n│\n└─ Complex data needs, multiple frontends\n    └─ GraphQL + codegen (flexible queries per client)\n\nReal-time needed?\n│\n├─ Server → Client only (notifications, feeds, AI streaming)\n│   └─ SSE (simplest, auto-reconnect, works through proxies)\n│\n├─ Bidirectional (chat, collaboration)\n│   └─ WebSocket (need heartbeat + reconnection logic)\n│\n└─ Simple status polling (\u003C 10 clients)\n    └─ React Query refetchInterval (no infrastructure needed)\n```\n\n---\n\n## 13. Production Hardening (MEDIUM)\n\n### Health Checks\n\n```typescript\napp.get('\u002Fhealth', (req, res) => res.json({ status: 'ok' }));           \u002F\u002F liveness\napp.get('\u002Fready', async (req, res) => {                                   \u002F\u002F readiness\n  const checks = {\n    database: await checkDb(), redis: await checkRedis(), \n  };\n  const ok = Object.values(checks).every(c => c.status === 'ok');\n  res.status(ok ? 200 : 503).json({ status: ok ? 'ok' : 'degraded', checks });\n});\n```\n\n### Graceful Shutdown\n\n```typescript\nprocess.on('SIGTERM', async () => {\n  logger.info('SIGTERM received');\n  server.close();              \u002F\u002F stop new connections\n  await drainConnections();    \u002F\u002F finish in-flight\n  await closeDatabase();\n  process.exit(0);\n});\n```\n\n### Security Checklist\n\n```\n✅ CORS: explicit origins (never '*' in production)\n✅ Security headers (helmet \u002F equivalent)\n✅ Rate limiting on public endpoints\n✅ Input validation on ALL endpoints (trust nothing)\n✅ HTTPS enforced\n❌ Never expose internal errors to clients\n```\n\n---\n\n## Anti-Patterns\n\n| # | ❌ Don't | ✅ Do Instead |\n|---|---------|--------------|\n| 1 | Business logic in routes\u002Fcontrollers | Move to service layer |\n| 2 | `process.env` scattered everywhere | Centralized typed config |\n| 3 | `console.log` for logging | Structured JSON logger |\n| 4 | Generic `Error('oops')` | Typed error hierarchy |\n| 5 | Direct DB calls in controllers | Repository pattern |\n| 6 | No input validation | Validate at boundary (Zod\u002FPydantic) |\n| 7 | Catching errors silently | Log + rethrow or return error |\n| 8 | No health check endpoints | `\u002Fhealth` + `\u002Fready` |\n| 9 | Hardcoded config\u002Fsecrets | Environment variables |\n| 10 | No graceful shutdown | Handle SIGTERM properly |\n| 11 | Hardcode API URL in frontend | Environment variable (`NEXT_PUBLIC_API_URL`) |\n| 12 | Store JWT in localStorage | Memory + httpOnly refresh cookie |\n| 13 | Show raw API errors to users | Map to human-readable messages |\n| 14 | Retry 4xx errors | Only retry 5xx (server failures) |\n| 15 | Skip loading states | Skeleton\u002Fspinner while fetching |\n| 16 | Upload large files through API server | Presigned URL → direct to S3 |\n| 17 | Poll for real-time data | SSE or WebSocket |\n| 18 | Duplicate types frontend + backend | Shared types, tRPC, or OpenAPI codegen |\n\n---\n\n## Common Issues\n\n### Issue 1: \"Where does this business rule go?\"\n\n**Rule:** If it involves HTTP (request parsing, status codes, headers) → controller. If it involves business decisions (pricing, permissions, rules) → service. If it touches the database → repository.\n\n### Issue 2: \"Service is getting too big\"\n\n**Symptom:** One service file > 500 lines with 20+ methods.\n\n**Fix:** Split by sub-domain. `OrderService` → `OrderCreationService` + `OrderFulfillmentService` + `OrderQueryService`. Each focused on one workflow.\n\n### Issue 3: \"Tests are slow because they hit the database\"\n\n**Fix:** Unit tests mock the repository layer (fast). Integration tests use test containers or transaction rollback (real DB, still fast). Never mock the service layer in integration tests.\n\n---\n\n## Reference Documents\n\nThis skill includes deep-dive references for specialized topics. Read the relevant reference when you need detailed guidance.\n\n| Need to… | Reference |\n|----------|-----------|\n| Write backend tests (unit, integration, e2e, contract, performance) | [references\u002Ftesting-strategy.md](references\u002Ftesting-strategy.md) |\n| Validate a release before deployment (6-gate checklist) | [references\u002Frelease-checklist.md](references\u002Frelease-checklist.md) |\n| Choose a tech stack (language, framework, database, infra) | [references\u002Ftechnology-selection.md](references\u002Ftechnology-selection.md) |\n| Build with Django \u002F DRF (models, views, serializers, admin) | [references\u002Fdjango-best-practices.md](references\u002Fdjango-best-practices.md) |\n| Design REST\u002FGraphQL\u002FgRPC endpoints (URLs, status codes, pagination) | [references\u002Fapi-design.md](references\u002Fapi-design.md) |\n| Design database schema, indexes, migrations, multi-tenancy | [references\u002Fdb-schema.md](references\u002Fdb-schema.md) |\n| Auth flow (JWT bearer, token refresh, Next.js SSR, RBAC, middleware order) | [references\u002Fauth-flow.md](references\u002Fauth-flow.md) |\n| CORS config, env vars per environment, common CORS issues | [references\u002Fenvironment-management.md](references\u002Fenvironment-management.md) |\n",{"name":5,"license":15,"metadata":60,"description":71},{"sources":61,"version":69,"category":70},[62,63,64,65,66,67,68],"The Twelve-Factor App (12factor.net)","Clean Architecture (Robert C. Martin)","Domain-Driven Design (Eric Evans)","Patterns of Enterprise Application Architecture (Martin Fowler)","Martin Fowler (Testing Pyramid, Contract Tests)","Google SRE Handbook (Release Engineering)","ThoughtWorks Technology Radar","1.0.0","full-stack","Full-stack backend architecture and frontend-backend integration guide.\nTRIGGER when: building a full-stack app, creating REST API with frontend, scaffolding backend service,\nbuilding todo app, building CRUD app, building real-time app, building chat app,\nExpress + React, Next.js API, Node.js backend, Python backend, Go backend,\ndesigning service layers, implementing error handling, managing config\u002Fauth,\nsetting up API clients, implementing auth flows, handling file uploads,\nadding real-time features (SSE\u002FWebSocket), hardening for production.\nDO NOT TRIGGER when: pure frontend UI work, pure CSS\u002Fstyling, database schema only.\n","main","5b00ad8b9f0787969474ff5e9ec417bb55f23827","skills\u002Fai-ml\u002Fminimax-ai-skills-fullstack-dev-1.0.1",0,"https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam","https:\u002F\u002Fvril.li","https:\u002F\u002Fgithub.com\u002FVRIL-LABS","vril.li","𝗥𝗲𝘀𝗲𝗮𝗿𝗰𝗵 𝗮𝗻𝗱 𝗗𝗲𝘃𝗲𝗹𝗼𝗽𝗺𝗲𝗻𝘁 𝗖𝗼𝗻𝘀𝗼𝗿𝘁𝗶𝘂𝗺","2026-08-24 09:21:38",{"source":8,"skillName":5,"commands":83,"prompt":93,"zipAvailable":94},[84,87,90],{"tool":85,"command":86},"npx","npx skills add VRIL-LABS\u002Fskill-jam --skill fullstack-dev",{"tool":88,"command":89},"bunx","bunx skills add VRIL-LABS\u002Fskill-jam --skill fullstack-dev",{"tool":91,"command":92},"pnpm","pnpm dlx skills add VRIL-LABS\u002Fskill-jam --skill fullstack-dev","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fai-ml\u002Fminimax-ai-skills-fullstack-dev-1.0.1\u002FSKILL.md",true,[96,102,106,110,114,118,122,126],{"path":97,"resourceType":98,"resourceTypeDesc":99,"sizeBytes":100,"sourceHtmlUrl":101},"references\u002Fapi-design.md","REFERENCE","参考文档",13910,"https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fai-ml\u002Fminimax-ai-skills-fullstack-dev-1.0.1\u002Freferences\u002Fapi-design.md",{"path":103,"resourceType":98,"resourceTypeDesc":99,"sizeBytes":104,"sourceHtmlUrl":105},"references\u002Fauth-flow.md",4566,"https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fai-ml\u002Fminimax-ai-skills-fullstack-dev-1.0.1\u002Freferences\u002Fauth-flow.md",{"path":107,"resourceType":98,"resourceTypeDesc":99,"sizeBytes":108,"sourceHtmlUrl":109},"references\u002Fdb-schema.md",23400,"https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fai-ml\u002Fminimax-ai-skills-fullstack-dev-1.0.1\u002Freferences\u002Fdb-schema.md",{"path":111,"resourceType":98,"resourceTypeDesc":99,"sizeBytes":112,"sourceHtmlUrl":113},"references\u002Fdjango-best-practices.md",13052,"https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fai-ml\u002Fminimax-ai-skills-fullstack-dev-1.0.1\u002Freferences\u002Fdjango-best-practices.md",{"path":115,"resourceType":98,"resourceTypeDesc":99,"sizeBytes":116,"sourceHtmlUrl":117},"references\u002Fenvironment-management.md",2309,"https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fai-ml\u002Fminimax-ai-skills-fullstack-dev-1.0.1\u002Freferences\u002Fenvironment-management.md",{"path":119,"resourceType":98,"resourceTypeDesc":99,"sizeBytes":120,"sourceHtmlUrl":121},"references\u002Frelease-checklist.md",7841,"https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fai-ml\u002Fminimax-ai-skills-fullstack-dev-1.0.1\u002Freferences\u002Frelease-checklist.md",{"path":123,"resourceType":98,"resourceTypeDesc":99,"sizeBytes":124,"sourceHtmlUrl":125},"references\u002Ftechnology-selection.md",9223,"https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fai-ml\u002Fminimax-ai-skills-fullstack-dev-1.0.1\u002Freferences\u002Ftechnology-selection.md",{"path":127,"resourceType":98,"resourceTypeDesc":99,"sizeBytes":128,"sourceHtmlUrl":129},"references\u002Ftesting-strategy.md",11818,"https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fai-ml\u002Fminimax-ai-skills-fullstack-dev-1.0.1\u002Freferences\u002Ftesting-strategy.md",[131,161,175,188,215,238],{"skillNo":132,"name":133,"nameZh":6,"description":134,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":135,"categories":136,"keywords":140,"publishedAt":55},"01M6R2CQRG190P09DAHMF8M5QP","three-best-practices","Three.js performance optimization and best practices guidelines. Use when writing, reviewing, or optimizing Three.js code. Triggers on tasks involving 3D scenes, WebGL\u002FWebGPU rendering, geometries, materials, textures, lighting, shaders, or TSL.","https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fweb-frontend\u002Fneversight-skills_feed-three-best-practices-1.0.2\u002FSKILL.md",[137],{"categoryNo":138,"categoryName":139,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160],"best practices","three","three best practices","writing","performance","webgpu","guidelines","tasks","code","shaders","Optimization","3D","use","agent-skills","scenes","lighting","triggers","rendering","when","best practices guidelines",{"skillNo":162,"name":163,"nameZh":6,"description":164,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":165,"categories":166,"keywords":167,"publishedAt":55},"01M6R2BPMDYK9XKWPARY0S5MS3","javascript-best-practices","Modern JavaScript best practices and performance optimization guidelines. Use when writing, reviewing, or refactoring JavaScript code to ensure optimal performance, maintainability, and modern patterns.","https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fweb-frontend\u002Fneversight-skills_feed-javascript-best-practices-1.0.2\u002FSKILL.md",[],[168,141,169,144,145,147,149,151,170,171,153,172,173,174,159],"javascript","JavaScript Best Practices","refactoring","performance optimization","patterns","maintainability","name",{"skillNo":176,"name":177,"nameZh":6,"description":178,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":179,"categories":180,"keywords":182,"publishedAt":55},"01M6R2B41BN09FYH76BAC5FT7X","css-best-practices","Guidelines for building modern, performant, and accessible CSS using MDN best practices. Use this when styling components, fixing layout shifts, or optimizing CSS performance.","https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fweb-frontend\u002Fneversight-skills_feed-css-best-practices-1.0.3\u002FSKILL.md",[181],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[52,141,183,145,184,147,153,185,186,187,159],"css best practices","components","styling","layout","for",{"skillNo":189,"name":190,"nameZh":6,"description":191,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":192,"categories":193,"keywords":202,"publishedAt":55},"01M6R2A1CEF123TZCNM1XJ2XQ4","frontend-dev","Full-stack frontend development combining premium UI design, cinematic animations,\nAI-generated media assets, persuasive copywriting, and visual art. Builds complete,\nvisually striking web pages with real media, advanced motion, and compelling copy.\nUse when: building landing pages, marketing sites, product pages, dashboards,\ngenerating media assets (image\u002Fvideo\u002Faudio\u002Fmusic), writing conversion copy,\ncreating generative art, or implementing cinematic scroll animations.","https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fweb-frontend\u002Fminimax-ai-skills-frontend-dev-1.0.1\u002FSKILL.md",[194,195,198,201],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":196,"categoryName":197,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":199,"categoryName":200,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体",{"categoryNo":30,"categoryName":31,"taxonomyType":32,"taxonomyTypeDesc":33},[54,37,203,53,144,204,52,51,205,206,207,208,209,48,210,211,212,39,213,214],"frontend dev","image","ui","Video","Media","Audio","Tailwind","music","aida","framer motion","framer","generative",{"skillNo":216,"name":217,"nameZh":6,"description":218,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":219,"categories":220,"keywords":221,"publishedAt":55},"01M6R20VQ98KDX4J37TGE0FNHW","exa-rate-limits","Implement Exa rate limiting, backoff, and idempotency patterns.\nUse when handling rate limit errors, implementing retry logic,\nor optimizing API request throughput for Exa.\nTrigger with phrases like \"exa rate limit\", \"exa throttling\",\n\"exa 429\", \"exa retry\", \"exa backoff\".","https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fsearch-research\u002Fjeremylongshore-claude-code-plugins-plus-skills-exa-rate-limits-1.0.0\u002FSKILL.md",[],[222,223,224,225,226,227,228,229,230,172,231,232,233,234,235,39,187,236,237,159],"exa","exa rate limits","rate","limits","throttling","api","read","write","edit","io","throughput","retry","errors","limit","rate limit","request",{"skillNo":239,"name":240,"nameZh":6,"description":241,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":242,"categories":243,"keywords":247,"publishedAt":55},"01M6R20FV0TM7ZZTZNG7JQ1A82","exa-deploy-integration","Deploy Exa integrations to Vercel, Fly.io, and Cloud Run platforms.\nUse when deploying Exa-powered applications to production,\nconfiguring platform-specific secrets, or setting up deployment pipelines.\nTrigger with phrases like \"deploy exa\", \"exa Vercel\",\n\"exa production deploy\", \"exa Cloud Run\", \"exa Fly.io\".","https:\u002F\u002Fgithub.com\u002FVRIL-LABS\u002Fskill-jam\u002Fblob\u002Fmain\u002Fskills\u002Fsearch-research\u002Fjeremylongshore-claude-code-plugins-plus-skills-exa-deploy-integration-1.0.0\u002FSKILL.md",[244],{"categoryNo":245,"categoryName":246,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000011","运维与部署",[248,249,222,250,251,252,253,254,255,256,228,229,230,257,258,259,231,260,261,159],"deploy","integration","exa deploy integration","deployment","run","secrets","fly","Bash","integrations","vercel","up","platform","trigger","cloud run"]