diff --git a/AGENTS.md b/AGENTS.md index 34078d2..11bc1ea 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,281 +1,237 @@ # AGENTS.md - AI Coding Agent Guidelines -This document provides comprehensive guidelines for AI coding agents working in this TanStack Start fullstack starter codebase. +本文档为 AI 编程助手提供此 TanStack Start 全栈项目的开发规范和指南。 -## Project Overview +## 项目概览 -- **Framework**: TanStack Start (React SSR framework with file-based routing) -- **Runtime**: Bun -- **Language**: TypeScript (strict mode, ESNext) -- **Styling**: Tailwind CSS v4 -- **Database**: PostgreSQL with Drizzle ORM -- **State Management**: TanStack Query -- **Routing**: TanStack Router (file-based) -- **RPC**: ORPC (type-safe RPC with contract-first design) -- **Build Tool**: Vite -- **Linter/Formatter**: Biome -- **Desktop Shell** (Optional): Tauri v2 (see `src-tauri/AGENTS.md` for desktop-specific guidelines) +- **框架**: TanStack Start (React SSR 框架,文件路由) +- **运行时**: Bun +- **语言**: TypeScript (strict mode, ESNext) +- **样式**: Tailwind CSS v4 +- **数据库**: PostgreSQL + Drizzle ORM +- **状态管理**: TanStack Query +- **路由**: TanStack Router (文件路由) +- **RPC**: ORPC (类型安全 RPC,契约优先) +- **构建工具**: Vite + Turbo +- **代码质量**: Biome (格式化 + Lint) +- **桌面壳** (可选): Tauri v2 (详见 `src-tauri/AGENTS.md`) -## Build, Lint, and Test Commands +## 构建、Lint 和测试命令 -### Development +### 开发 ```bash -bun dev # Start development server -bun db:studio # Open Drizzle Studio for database management +bun dev # 使用 Turbo 并行启动 Tauri + Vite 开发服务器 +bun dev:vite # 仅启动 Vite 开发服务器 (localhost:3000) +bun dev:tauri # 启动 Tauri 桌面应用 +bun db:studio # 打开 Drizzle Studio 数据库管理界面 ``` -### Building +### 构建 ```bash -bun build # Build for production (outputs to .output/) -bun compile # Compile to standalone executable (out/server) -bun serve # Preview production build +bun build # 完整构建 (Vite → 编译 → Tauri 打包) +bun build:vite # 仅构建 Vite (输出到 .output/) +bun build:compile # 编译为独立可执行文件 (使用 build.ts) +bun build:tauri # 构建 Tauri 桌面安装包 ``` -### Code Quality +### 代码质量 ```bash -bun typecheck # Run TypeScript compiler (tsc -b) -bun fix # Run Biome linter and formatter (auto-fix issues) -biome check . # Check without auto-fix -biome format --write . # Format code only +bun typecheck # 运行 TypeScript 编译器检查 (tsc -b) +bun fix # 运行 Biome 自动修复格式和 Lint 问题 +biome check . # 检查但不自动修复 +biome format --write . # 仅格式化代码 ``` -### Database +### 数据库 ```bash -bun db:generate # Generate migration files from schema -bun db:migrate # Run migrations -bun db:push # Push schema changes directly (dev only) +bun db:generate # 从 schema 生成迁移文件 +bun db:migrate # 执行数据库迁移 +bun db:push # 直接推送 schema 变更 (仅开发环境) ``` -### Testing -**Note**: No test framework is currently configured. When adding tests: -- Use Vitest or Bun's built-in test runner -- Run single test file: `bun test path/to/test.ts` -- Run specific test: `bun test -t "test name pattern"` +### 测试 +**注意**: 当前未配置测试框架。添加测试时: +- 使用 Vitest 或 Bun 内置测试运行器 +- 运行单个测试文件: `bun test path/to/test.ts` +- 运行特定测试: `bun test -t "测试名称模式"` -## Code Style Guidelines +## 代码风格指南 -### Formatting (Biome) +### 格式化 (Biome) -**Indentation**: 2 spaces (not tabs) -**Line Endings**: LF (Unix-style) -**Quotes**: Single quotes for strings -**Semicolons**: As needed (ASI - automatic semicolon insertion) -**Arrow Parens**: Always use parentheses `(x) => x` +**缩进**: 2 空格 (不使用 tab) +**换行符**: LF (Unix 风格) +**引号**: 单引号 `'string'` +**分号**: 按需 (ASI - 自动分号插入) +**箭头函数括号**: 始终使用 `(x) => x` -Example: +示例: ```typescript const myFunc = (value: string) => { return value.toUpperCase() } ``` -### Import Organization +### 导入组织 -Imports are auto-organized by Biome. Order: -1. External dependencies -2. Internal imports using `@/*` alias -3. Type imports (use `type` keyword when importing only types) +Biome 自动组织导入。顺序: +1. 外部依赖 +2. 内部导入 (使用 `@/*` 别名) +3. 类型导入 (仅导入类型时使用 `type` 关键字) -Example: +示例: ```typescript import { createFileRoute } from '@tanstack/react-router' -import { createServerFn } from '@tanstack/react-start' +import { oc } from '@orpc/contract' +import { z } from 'zod' import { db } from '@/db' +import { todoTable } from '@/db/schema' import type { ReactNode } from 'react' ``` ### TypeScript -**Strict Mode**: Enabled with additional strictness flags +**严格模式**: 启用了额外的严格检查 - `strict: true` -- `noUncheckedIndexedAccess: true` - Array/object indexing returns `T | undefined` +- `noUncheckedIndexedAccess: true` - 数组/对象索引返回 `T | undefined` - `noImplicitOverride: true` - `noFallthroughCasesInSwitch: true` -**Module Resolution**: `bundler` mode with `verbatimModuleSyntax` -- Always use `.ts`/`.tsx` extensions in imports -- Use `@/*` path alias for `src/*` +**模块解析**: `bundler` 模式 + `verbatimModuleSyntax` +- 导入时始终使用 `.ts`/`.tsx` 扩展名 +- 使用 `@/*` 路径别名指向 `src/*` -**Type Annotations**: -- Always annotate function parameters and return types for public APIs -- Prefer explicit types over `any` -- Use `type` for object shapes, `interface` for extendable contracts -- Use `Readonly` for immutable props +**类型注解**: +- 公共 API 的函数参数和返回类型必须注解 +- 优先使用显式类型而非 `any` +- 对象形状用 `type`,可扩展契约用 `interface` +- 不可变 props 使用 `Readonly` -Example: -```typescript -function getTodos(): Promise { - return db.query.todoTable.findMany() -} +### 命名规范 -type Props = Readonly<{ - children: ReactNode -}> -``` - -### Naming Conventions - -- **Files**: kebab-case for utilities, PascalCase for components +- **文件**: 工具函数用 kebab-case,组件用 PascalCase - `utils.ts`, `todo.tsx`, `NotFound.tsx` -- **Routes**: Use TanStack Router conventions +- **路由**: 遵循 TanStack Router 约定 - `routes/index.tsx` → `/` - - `routes/todo.tsx` → `/todo` - - `routes/__root.tsx` → Root layout -- **Components**: PascalCase function declarations -- **Functions**: camelCase -- **Constants**: UPPER_SNAKE_CASE for true constants, camelCase for config objects -- **Types/Interfaces**: PascalCase + - `routes/__root.tsx` → 根布局 +- **组件**: PascalCase 箭头函数 (Biome 规则 `useArrowFunction` 强制) +- **函数**: camelCase +- **常量**: 真常量用 UPPER_SNAKE_CASE,配置对象用 camelCase +- **类型/接口**: PascalCase -### React Patterns +### React 模式 -**Components**: Use arrow functions (enforced by Biome rule `useArrowFunction`) +**组件**: 使用箭头函数 ```typescript const MyComponent = ({ title }: { title: string }) => { return
{title}
} ``` -**Server Functions**: Use TanStack Start's `createServerFn` +**路由**: 使用 `createFileRoute` 定义路由 ```typescript -const getTodos = createServerFn({ method: 'GET' }).handler(async () => { - const todos = await db.query.todoTable.findMany() - return todos +export const Route = createFileRoute('/')({ + component: Home, }) ``` -**Routing**: Use `createFileRoute` for route definitions -```typescript -export const Route = createFileRoute('/todo')({ - component: Todo, -}) -``` +**数据获取**: 使用 TanStack Query hooks +- `useSuspenseQuery` - 保证有数据 +- `useQuery` - 数据可能为空 -**Data Fetching**: Use TanStack Query hooks -- `useSuspenseQuery` for guaranteed data -- `useQuery` when data might be optional +**Props**: 禁止直接修改 props (Biome 规则 `noReactPropAssignments`) -**Props**: No direct prop mutations (enforced by `noReactPropAssignments`) +### 数据库 Schema (Drizzle) -### Database Schema (Drizzle) +- 在 `src/db/schema/*.ts` 定义 schema +- 从 `src/db/schema/index.ts` 导出 +- 使用 `drizzle-orm/pg-core` 的 PostgreSQL 类型 +- 主键使用 `uuidv7()` (需要 PostgreSQL 扩展) +- 始终包含 `createdAt` 和 `updatedAt` 时间戳 -- Define schemas in `src/db/schema/*.ts` -- Export from `src/db/schema/index.ts` -- Use PostgreSQL types from `drizzle-orm/pg-core` -- Use `uuidv7()` for primary keys (requires PostgreSQL extension) -- Always include `createdAt` and `updatedAt` timestamps - -Example: +示例: ```typescript import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core' import { sql } from 'drizzle-orm' export const myTable = pgTable('my_table', { - id: uuid('id').primaryKey().default(sql`uuidv7()`), - name: text('name').notNull(), - createdAt: timestamp('created_at', { withTimezone: true }) - .notNull() - .defaultNow(), - updatedAt: timestamp('updated_at', { withTimezone: true }) - .notNull() - .defaultNow() - .$onUpdateFn(() => new Date()), + id: uuid().primaryKey().default(sql`uuidv7()`), + name: text().notNull(), + createdAt: timestamp({ withTimezone: true }).notNull().defaultNow(), + updatedAt: timestamp({ withTimezone: true }).notNull().defaultNow().$onUpdateFn(() => new Date()), }) ``` -### Environment Variables +### 环境变量 -- Use `@t3-oss/env-core` for type-safe env validation -- Define schema in `src/env.ts` -- Server vars: No prefix -- Client vars: Must have `VITE_` prefix -- Always validate with Zod schemas +- 使用 `@t3-oss/env-core` 进行类型安全的环境变量验证 +- 在 `src/env.ts` 定义 schema +- 服务端变量: 无前缀 +- 客户端变量: 必须有 `VITE_` 前缀 +- 使用 Zod schema 验证 -### Error Handling +### 错误处理 -- Use try-catch for async operations -- Throw errors with descriptive messages -- Prefer Result types or error boundaries for user-facing errors -- Log errors appropriately (avoid logging sensitive data) +- 异步操作使用 try-catch +- 抛出带有描述性消息的错误 +- 用户界面错误优先使用 Result 类型或错误边界 +- 适当记录错误 (避免记录敏感数据) -### Styling (Tailwind CSS) +### 样式 (Tailwind CSS) -- Use Tailwind v4 utility classes -- Import styles via `@/styles.css?url` -- Prefer composition over custom CSS -- Use responsive modifiers: `sm:`, `md:`, `lg:` -- Use Chinese text for UI when appropriate (as seen in codebase) +- 使用 Tailwind v4 工具类 +- 通过 `@/styles.css?url` 导入样式 +- 优先使用组合而非自定义 CSS +- 响应式修饰符: `sm:`, `md:`, `lg:` +- UI 文本适当使用中文 -## File Structure +## 目录结构 ``` src/ -├── components/ # Reusable React components +├── components/ # 可复用 React 组件 ├── db/ -│ ├── schema/ # Drizzle schema definitions -│ └── index.ts # Database instance -├── lib/ # Utility functions -├── orpc/ # ORPC (RPC layer) -│ ├── contracts/ # Contract definitions (input/output schemas) -│ ├── handlers/ # Server-side procedure implementations -│ ├── middlewares/ # Middleware (e.g., DB provider) -│ ├── contract.ts # Contract aggregation -│ ├── router.ts # Router composition -│ ├── server.ts # Server instance -│ ├── client.ts # Isomorphic client -│ └── types.ts # Type utilities -├── routes/ # TanStack Router file-based routes -│ ├── __root.tsx # Root layout -│ ├── index.tsx # Home page -│ └── api/rpc.$.ts # ORPC HTTP endpoint -├── env.ts # Environment variable validation -├── index.ts # Application entry point -├── router.tsx # Router configuration -├── routeTree.gen.ts # Auto-generated (DO NOT EDIT) -└── styles.css # Global styles +│ ├── schema/ # Drizzle schema 定义 +│ └── index.ts # 数据库实例 +├── integrations/ # 第三方集成 (TanStack Query/Router) +├── lib/ # 工具函数 +├── orpc/ # ORPC (RPC 层) +│ ├── contracts/ # 契约定义 (input/output schemas) +│ ├── handlers/ # 服务端过程实现 +│ ├── middlewares/ # 中间件 (如 DB provider) +│ ├── contract.ts # 契约聚合 +│ ├── router.ts # 路由组合 +│ ├── server.ts # 服务端实例 +│ └── client.ts # 同构客户端 +├── routes/ # TanStack Router 文件路由 +│ ├── __root.tsx # 根布局 +│ ├── index.tsx # 首页 +│ └── api/rpc.$.ts # ORPC HTTP 端点 +├── env.ts # 环境变量验证 +└── router.tsx # 路由配置 ``` -## Important Notes +## 重要提示 -- **DO NOT** edit `src/routeTree.gen.ts` - it's auto-generated -- **DO NOT** commit `.env` files - use `.env.example` for templates -- **DO** run `bun fix` before committing to ensure code quality -- **DO** use the `@/*` path alias instead of relative imports -- **DO** leverage React Compiler (babel-plugin-react-compiler) - avoid manual memoization +- **禁止** 编辑 `src/routeTree.gen.ts` - 自动生成 +- **禁止** 提交 `.env` 文件 - 使用 `.env.example` 作为模板 +- **必须** 在提交前运行 `bun fix` +- **必须** 使用 `@/*` 路径别名而非相对导入 +- **必须** 利用 React Compiler (babel-plugin-react-compiler) - 避免手动 memoization -## Git Workflow +## Git 工作流 -1. Make changes following the style guidelines above -2. Run `bun fix` to auto-format and lint -3. Run `bun typecheck` to ensure type safety -4. Test changes locally with `bun dev` -5. Commit with clear, descriptive messages +1. 按照上述风格指南进行修改 +2. 运行 `bun fix` 自动格式化和 lint +3. 运行 `bun typecheck` 确保类型安全 +4. 使用 `bun dev` 本地测试变更 +5. 使用清晰的描述性消息提交 -## Common Patterns +## 常见模式 -### Adding a New Route -1. Create `src/routes/my-route.tsx` -2. Export route with `createFileRoute` -3. Route tree auto-updates on save +### 创建 ORPC 过程 -### Adding Database Table -1. Create schema in `src/db/schema/my-table.ts` -2. Export from `src/db/schema/index.ts` -3. Run `bun db:generate` to create migration -4. Run `bun db:migrate` to apply migration - -### Creating Server Function -```typescript -const myServerFn = createServerFn({ method: 'POST' }) - .validator((data) => mySchema.parse(data)) - .handler(async ({ data }) => { - // Server-side logic here - return result - }) -``` - -### Creating ORPC Procedures - -**Step 1: Define Contract** (`src/orpc/contracts/my-feature.ts`) +**步骤 1: 定义契约** (`src/orpc/contracts/my-feature.ts`) ```typescript import { oc } from '@orpc/contract' import { z } from 'zod' @@ -286,7 +242,7 @@ export const myContract = { } ``` -**Step 2: Implement Handler** (`src/orpc/handlers/my-feature.ts`) +**步骤 2: 实现处理器** (`src/orpc/handlers/my-feature.ts`) ```typescript import { os } from '@/orpc/server' import { dbProvider } from '@/orpc/middlewares' @@ -294,24 +250,21 @@ import { dbProvider } from '@/orpc/middlewares' export const get = os.myFeature.get .use(dbProvider) .handler(async ({ context, input }) => { - const item = await context.db.query.myTable.findFirst(...) - return item + return await context.db.query.myTable.findFirst(...) }) ``` -**Step 3: Register in Contract & Router** +**步骤 3: 注册到契约和路由** ```typescript // src/orpc/contract.ts -export const contract = { - myFeature: myContract, -} +export const contract = { myFeature: myContract } // src/orpc/router.ts import * as myFeature from './handlers/my-feature' export const router = os.router({ myFeature }) ``` -**Step 4: Use in Component** +**步骤 4: 在组件中使用** ```typescript import { orpc } from '@/orpc' const query = useSuspenseQuery(orpc.myFeature.get.queryOptions({ id })) @@ -320,5 +273,5 @@ const mutation = useMutation(orpc.myFeature.create.mutationOptions()) --- -**Last Updated**: 2026-01-18 -**Project Version**: Based on package.json dependencies +**最后更新**: 2026-01-18 +**项目版本**: 基于 package.json 依赖版本