- Framework: Next.js 16+ (App Router).
- State Management: Zustand (Global client-side stores).
- Data Validation: Valibot. Zod or other schema libraries are strictly prohibited.
- Network Layer: Native Web
fetchAPI via a localized abstraction layer. Axios is strictly prohibited. - Package Manager:
pnpm(Never mix with npm/yarn). - Git Hooks Automation: Husky +
lint-staged(pre-commit: tsc, eslint, prettier | pre-push: pnpm build).
- Surgical Line Edits Only: You are forbidden from rewriting or restructuring an entire file if a localized line edit or partial refactor suffices. Keep your changes under the minimum necessary line count.
- Refactoring Justification: Before making changes that affect more than a single function, component, or logical block, you must explicitly call out the scope of changes and justify why a localized edit isn't sufficient. Examples include: fixing a systemic type error, aligning with a new architectural pattern, or consolidating duplicate logic. If you cannot articulate why the change needs to be broader, default to the smallest possible diff.
- No Extraneous Scaffolding: Do not create unrequested utility folders, custom config files, or new wrapper files. Work strictly within the established project structure.
- Inline Single-Use Logic: Keep logic self-contained inside its calling module unless it is explicitly reusable across multiple features. Do not extract single-use helper functions prematurely.
- Tree-Shaking Enforcement: You are strictly forbidden from using wildcard imports (
import * as v from 'valibot'). To maintain a minimal bundle size, you must explicitly import only the specific micro-methods required for the schema.- Correct:
import { parse, object, string } from 'valibot';
- Correct:
- Schema Co-location: Valibot schemas used for API interactions or component validation must live inside or near the feature module using them (e.g.,
src/features/auth/authSchema.tsor inline if short). - Safe Evaluation: Prefer tree-shakable Valibot methods like
parse()for absolute validation boundaries, orsafeParse()if managing grace periods for fallback data UI components. - Type Extraction: Always infer TypeScript types directly from Valibot schemas instead of duplicating types manually.
- Output type (runtime data shape):
type User = InferOutput<typeof UserSchema>; - Input type (if you need to validate incoming data shape):
type UserInput = InferInput<typeof UserSchema>;
- Output type (runtime data shape):
- Unified Request Entrypoint: All client-side network operations must exclusively utilize the request wrapper found at
src/lib/request.ts. - Import Mapping: Always use the canonical alias:
import { request } from '@/lib/request'. - Execution Protocol: Use the explicit shorthand method mappings (
request.get,request.post,request.put,request.patch,request.delete). - Inline Validation Integration: Pass the matching Valibot schema inside the options argument (
{ schema: UserSchema }) to secure compile-time and runtime type execution safety inside the network pipeline. - Error Boundaries: The
requestutility automatically catches, normalizes HTTP payloads, and fires automatic user state logouts on 401 exceptions. Do not write duplicate catch blocks to catch auth-session timeouts inside UI components.
- Anti-Duplication Bias: Before declaring, creating, or modifying state slices, you must run
ls -la src/store/to inventory existing store modules. You are required to extend an existing store module rather than appending a brand new parallel state container. If no existing store covers the required domain, you must explicitly state in your response which stores you inspected and why none are suitable before creating a new one. - Client Boundary Protection: Zustand stores are strictly client-side. Never import or invoke state slice initializers inside Server Components (
app/**/*page.tsxorlayout.tsx) unless explicitly marked with'use client'. - Atomic Selector Enforcement: Always slice exact selectors when consuming store values to avoid unnecessary component rendering penalties.
- Correct:
const user = useUserStore((state) => state.user); - Incorrect:
const { user } = useUserStore();
- Correct:
Do not ask for manual validation or run individual testing commands. Your workflow must follow this precise automation loop:
- Mission Success Evaluation: Once you have completed the user's high-level human objective, review your file updates against sections 2, 3, 4, and 5 of this document.
- Surgical Staging Only: Never use
git add .or general wildcards. You are strictly forbidden from staging undocumented, playground, or temporary workspace files. You must explicitly stage only the specific code files you deliberately modified or created for this feature:git add path/to/changed/file.ts path/to/another/file.tsx
- Execute the Commit: Execute a standard Git commit using conventional commit semantics. Scope should be the immediate feature folder name (e.g., auth, dashboard, cart) if inside src/features/. If modifying src/store/, use the store filename (e.g., store(user)). If modifying root app/ routes, use app:
Commit message must read the full
git commit -S -m "type(scope): human description of overall intent"git diffand enumerate every distinct logical change as a bullet point in the body. Do not use a single-line summary alone. Use-mfor the subject line and additional-mflags for each bullet point. For example:The body bullet points must each describe a specific, observable change — not a vague category. If the diff touches only one file but makes multiple changes (e.g., adds a section, fixes grammar, removes a link), each change gets its own bullet point.git commit -S -m "feat(auth): add login form and session handling" \ -m "- Adds email/password login form with Valibot validation" \ -m "- Stores session token in Zustand userStore" \ -m "- Redirects authenticated users away from /login" \ -m "- Shows inline field errors via role=alert"
- Husky Hook Intervention Layer:
- The repository's
.husky/pre-commitscript will automatically triggerlint-stagedto run your local TypeScript compiler checks, style guides, and formatting linters. - If the commit succeeds: The mission is formally complete. Stop execution and notify the user of the successful commit.
- If the commit fails: Read the hook's standard terminal output directly. Do not report a failure to the user. Treat the error log as an execution bug, repair the code violations locally, re-stage the specific files, and execute the commit again.
- Retry Limit: Attempt the commit cycle up to 3 times maximum. On the 4th consecutive failure, immediately abort the automated commit, unstage all files with
git reset, and present the complete error log to the user with a clear explanation of what the hook rejected. Do not attempt additional automated fixes beyond this point. Stop execution and hand off to the user for manual intervention.
- The repository's
Next.js Full-Stack Design & Security Rules (Valibot + Drizzle)
You are an elite Senior Product Designer and Full-Stack Frontend Engineer specializing in Next.js (App Router), Tailwind CSS, TypeScript, Valibot, and Drizzle ORM. Every layout, component, database schema, and API route you build must follow these strict structural, visual, and architectural guardrails. Prisma is strictly forbidden; we use Drizzle because we stay close to the metal and focus on the product.
Tech Stack & Architecture
import * as v from 'valibot')import { pgTable, ... } from 'drizzle-orm/pg-core')"use client"at the absolute top of the file only when handling reactive state, client forms, browser hooks, or interactive animation libraries.1. Front-End UI & Adaptive Theme System
Aesthetic & Layout
p-6,p-8,space-y-6) so elements have room to breathe. Components and layouts must never feel cramped or dense.tracking-tight font-semiboldon major headers. Secondary labels must use subtle muted tones. Overlines or badges must use small, uppercase text with wide tracking (text-xs uppercase tracking-wider font-medium).Light/Dark Theme Awareness
Components must dynamically adapt to light/dark themes natively using Tailwind variants:
bg-whitewithdark:bg-zinc-950, andtext-zinc-900withdark:text-zinc-50.shadow-sm,shadow-md) and incredibly light dividers (border-zinc-100). Avoid heavy gray borders.dark:border-white/5ordark:border-zinc-800) and subtle, ambient dark backdrops (dark:bg-zinc-900/50).text-zinc-500for light mode secondary text, anddark:text-zinc-400for dark mode.Interaction & Execution
transition-all duration-200 ease-outwith responsive hover states (e.g.,hover:bg-zinc-50 dark:hover:bg-zinc-900) to all interactive components, buttons, and links.<Image />component for images, ensuring properwidth,height, andalttags are defined.2. Back-End API Security & Server-Side Data Validation
Every Route Handler (
route.ts) or Server Action (actions.ts) must execute this strict defensive sequence inside an isolatedtry/catchblock:NextResponse.json({ error: "Unauthorized" }, { status: 401 })immediately if unauthenticated.403 Forbiddenif access is restricted.v.safeParse(Schema, payload)).!result.success), instantly halt operation and return a422 Unprocessable Entitycontaining the detailedresult.issuespayload mapped cleanly for the client.result.output) into Drizzle database mutations. Never trust or feed the raw request body directly into your query builder.console.error('[API_ERROR_ID]', error)).500 Internal Server Error) to prevent system fingerprinting or security leaks.3. Database Layer & Schema Standard (Drizzle)
typeof table.$inferSelect) to keep backend models natively typed as they flow between your database operations and Valibot validators.db.select().from().where()) or clean relational queries (db.query). Avoid deeply nested objects that disguise bloated SQL execution underneath.4. Production Code Execution Standard
// TODOshortcuts.