feat(schemas): add repository settings and user restore token fields

- Add allow_forking, allow_merge_commit, allow_rebase_merge, allow_squash_merge fields to repo schemas
- Add delete_branch_on_merge field to repository models and schemas
- Add has_issues, has_pull_requests, has_wiki, homepage fields to repo schemas
- Add topics array field to repository schemas and models
- Add restore_token_expires_at and restore_token_hash fields to user schemas
- Remove UserAvatarResponse and UploadUserAvatarParams schemas completely
- Update CreateRepoParams and UpdateRepoParams with new repository settings
- Modify CreateTemplateParams and UpdateTemplateParams with notification template fields
- Remove description from SetBranchProtectionParams schema
- Delete App.css and auth.css files completely
- Update App.tsx with routing migration notes
This commit is contained in:
zhenyi
2026-06-11 23:12:24 +08:00
parent defde2bca9
commit d7c4bc7c8e
582 changed files with 49188 additions and 3037 deletions
+338
View File
@@ -0,0 +1,338 @@
## Language
Always respond in Chinese (中文). Use the user's language for all conversations and explanations. Code, commands, and technical terms can remain in English.
页面内容(UI 文案、标签、提示、错误信息)默认使用 **英语**。仅当用户明确要求时才做多语言。
# Project Guidelines — appwebks
## Tech Stack
- **Runtime**: Bun (packageManager, scripts, lockfile)
- **Framework**: React 19, TypeScript 6.0, Vite 8.0
- **Styling**: Tailwind CSS 4.3 + clsx + tailwind-mergeCVA 变体模式)
- **State**: @tanstack/react-query v5(服务端状态)+ URL search/path params(客户端状态)
- **Routing**: react-router-dom v7
- **HTTP**: ky(优先)+ axios
- **Validation**: zod v4
- **Icons**: lucide-react
## Project Structure
```
src/
pages/ # 页面组件,每个 page 一个文件夹
components/ # 共享组件,按功能域分文件夹
hooks/ # 自定义 hooks(含 react-query hooks
client/ # 自动生成 API 代码(只读!)
lib/ # 工具函数、常量
types/ # 共享类型定义
```
## Routing
使用 React Router v7 **Data Mode**`createBrowserRouter` + Route Object 配置。
- 路由配置集中在 `src/routes.ts`,通过 `createBrowserRouter` 组装
- 每个路由模块(Component + loader + action)为独立文件,放在 `src/pages/`
- 路由文件不容纳 JSX,只 export RouteObject[]
```ts
// src/routes.ts — 路由配置,只组装不渲染
import { createBrowserRouter } from 'react-router';
import { RepoListPage } from '@/pages/RepoList/RepoListPage';
import { RepoDetailPage } from '@/pages/RepoDetail/RepoDetailPage';
import { RootLayout } from '@/pages/RootLayout';
export const router = createBrowserRouter([
{
path: '/',
Component: RootLayout,
children: [
{ index: true, Component: RepoListPage },
{ path: 'repo/:id', Component: RepoDetailPage },
],
},
]);
```
```tsx
// src/pages/RepoList/RepoListPage.tsx — 路由模块
export function RepoListPage() {
const { data } = useRepoList();
return <div>...</div>;
}
```
## Code Style
### File Naming
- React 组件文件:**PascalCase**`Button.tsx``UserList.tsx`
- Hooks / utils / types 文件:**camelCase**`useAuth.ts``formatDate.ts`
- 页面文件夹:**PascalCase**`UserProfile/``RepoList/`
### Component Conventions
- 组件用 **function 声明**,不用 arrow function
- Props 类型用 **interface**,写在组件文件顶部,不单独导出:
```tsx
interface ButtonProps {
size?: 'sm' | 'md' | 'lg';
variant?: 'primary' | 'secondary';
children: React.ReactNode;
}
export function Button({ size = 'md', variant = 'primary', children }: ButtonProps) {
// ...
}
```
- 原生 HTML 元素 Props 用 `React.ComponentProps<'button'>` 派生
- 单文件不超过 **200 行**,函数不超过 **50 行**
- 复杂逻辑抽成 hooks
### Import Order
Biome 的 `organizeImports` 会自动按以下顺序排列 import,组间空行分隔:
1. React / React Router / react-query 等核心库
2. 第三方 UI / 工具库(lucide-react、clsx、zod...
3. `@/` 别名导入
4. 相对路径导入(`./`、`../`
```tsx
import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Link } from 'react-router-dom';
import { Search, Plus } from 'lucide-react';
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
import { repoService } from '@/client/services/RepoService';
import { Button } from '@/components/ui/Button';
import { useRepoList } from './useRepoList';
```
## Styling
### Tailwind + CVA
用 `clsx` + `tailwind-merge` 管理组件变体,按 CVA 模式组织:
```tsx
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
function cn(...inputs: (string | undefined | false | null)[]) {
return twMerge(clsx(inputs));
}
const variants = {
size: {
sm: 'px-2 py-1 text-sm',
md: 'px-4 py-2 text-base',
lg: 'px-6 py-3 text-lg',
},
variant: {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
},
} as const;
interface ButtonProps {
size?: keyof typeof variants.size;
variant?: keyof typeof variants.variant;
}
export function Button({ size = 'md', variant = 'primary', ... }: ButtonProps) {
return <button className={cn(variants.size[size], variants.variant[variant])} ... />;
}
```
- **禁止新增任何 `.css` 文件**。项目只保留一个全局入口 CSS(`src/index.css`),仅用于:
- `@import "tailwindcss"`
- CSS 自定义属性(主题变量)
- 全局 reset
- 组件样式**必须**使用 Tailwind 原子类,不得引用局部 CSS 文件
- 禁止 `@apply` 抽取类名
- `cn()` 函数放在 `@/lib/cn.ts` 中统一导入
## State Management
### URL-Driven State
- UI 状态(分页、筛选、排序、tab 切换)**必须**编码到 URL search/path params
- 用 `useSearchParams()` 读写,组件内部 `useState` 最小化
- 好处:可分享、可书签、浏览器前进后退自然工作
### Server State (react-query)
- 所有 API 调用必须通过 react-query hooks`useQuery` / `useMutation`
- 禁止在组件中直接调用 `src/client/` 的服务方法
- Query key 约定:`['domain', 'action', ...params]`,如 `['repos', 'list', { page, q }]`
**注意**TanStack Query v5 已移除 `useQuery` 上的 `onError` / `onSuccess` / `onSettled` 回调:
- `useQuery` 错误处理:组件内检查 `error` 状态,或全局通过 `QueryClient.setDefaultOptions` 配置
- `useMutation` 错误处理:`onError` 回调仍然可用
```tsx
// useQuery — 错误在 error 字段上处理
import { useQuery } from '@tanstack/react-query';
const { data, error, isLoading } = useQuery({
queryKey: ['repos', 'list', { page }],
queryFn: () => repoService.listRepos({ page }),
});
// useMutation — onError 仍然可用
import { useMutation } from '@tanstack/react-query';
import { toast } from 'sonner';
const mutation = useMutation({
mutationFn: (params) => repoService.createRepo(params),
onError: (error) => toast.error(error.message),
});
```
## API Layer
### Generated Codesrc/client/
- **视为只读**,禁止手动修改任何 `src/client/` 下的文件
- 需要变更时修改 `openapi.json` 或 `genapi.js`,然后运行 `bun run genapi` 重新生成
### Custom Hooks 封装
每个业务域在 `src/hooks/` 下创建对应的 react-query hook 文件:
```
src/hooks/
useRepoList.ts # useQuery: repo list + filters
useRepoDetail.ts # useQuery: single repo
useCreateRepo.ts # useMutation: create repo
useBranchList.ts # useQuery: branch list
```
hook 职责:
- 组装 queryKey(如 `['repos', 'list', { page, q }]`
- 调用 `src/client/` 服务方法
- 转换入参(筛选条件 → API 参数)、归一化错误
- **默认返回 React Query 原始结果**:不隐藏 `isPending` / `isFetching` / `error` / `refetch` 等状态
```tsx
// src/hooks/useRepoList.ts — 典型范式
import { useQuery, keepPreviousData } from '@tanstack/react-query';
import { repoService } from '@/client/services/RepoService';
export function useRepoList(filters: RepoFilters) {
return useQuery({
queryKey: ['repos', 'list', filters],
queryFn: ({ signal }) => repoService.listRepos({ ...filters }, { signal }),
placeholderData: keepPreviousData,
});
}
// 组件侧直接解构:const { data, isPending, isFetching, error, refetch } = useRepoList(filters);
```
### Error Handling
- 全局 **ErrorBoundary** 捕获 React 渲染错误
- `useMutation` 的 API 错误通过 `onError` 回调统一分发 toast
- `useQuery` 的 API 错误通过组件内判断 `error` 状态处理,或使用全局 `throwOnError` + ErrorBoundary
- 禁止在组件中 try/catch API 调用后自己做 UI 错误展示
```tsx
// 全局 QueryClient 配置(在 App 入口)
import { QueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
throwOnError: true, // Query 抛错 → ErrorBoundary 捕获
},
mutations: {
onError: (error) => toast.error(error.message),
},
},
});
```
## Git
### Branching
- **Trunk-based**:直接在 `main` 上做小而频繁的提交
- 不做长期 feature 分支,未完成功能用 feature flag 或路由守卫控制
- 需要时可以从 main 拉短期分支,但合入后立即删除
### Commits
- **Conventional Commits**`feat` / `fix` / `refactor` / `docs` / `test` / `chore`
- 原子提交:一个 commit 只做一件事
- 禁止 force push 到 main
## FormatterBiome
项目使用 **Biome** 作为唯一的格式化 & lint 工具。配置见 `biome.json`。
### 格式化规则
| 配置项 | 值 |
|--------|-----|
| 缩进 | 2 空格 |
| 引号 | 单引号(JS/TS),双引号(JSX) |
| 分号 | 总是 |
| 尾逗号 | 总是 |
| 行宽 | 100 |
| 换行符 | LF |
| 箭头函数括号 | 总是保留 |
### 命令
```bash
bun run format # 格式化 src/ 下所有文件
bun run lint # 仅 lint 检查,不修改
bun run check # 格式化 + lint,写入修复
```
### Lint 规则
- 启用 **recommended** 规则集
- `noUnusedVariables`: error — 禁止未使用变量
- `useHookAtTopLevel`: error — React hooks 必须在顶层调用
- `noParameterAssign`: error — 禁止给参数重新赋值
- `useConst`: error — 能用 const 就别用 let
- `useTemplate`: warn — 字符串拼接改用模板字符串
## Quality Gate
AI 助手完成代码修改后,**必须依次运行以下命令**确保通过:
```bash
bun run check # Biome 格式化 + lint
bun run build # TypeScript 类型检查 + Vite 构建
```
任一步骤失败不允许提交。
## Testing
当前阶段 **不强制写测试**,快速迭代优先。后续需要时优先补关键路径的单元测试(vitest)。
## Environment Variables
- **禁止**在业务代码中直接读取 `import.meta.env.*`
- 所有环境变量必须通过 `@/lib/env` 集中访问,统一提供默认值与类型安全
```ts
// src/lib/env.ts
export const env = {
API_BASE_URL: import.meta.env.VITE_API_BASE_URL ?? '/api',
DEV: import.meta.env.DEV,
MODE: import.meta.env.MODE,
} as const;
```
## Import Discipline
- **禁止**页面组件直接导入 `@/client/**`
- 只有 `src/hooks/**` 或 `src/features/**/api/**` 可以导入 generated client
- 页面通过自定义 hook 访问 API 数据,不接触底层 client
```
✅ src/hooks/useRepoList.ts → import { RepoService } from '@/client/services/RepoService'
✅ src/features/repos/api.ts → import { RepoService } from '@/client/services/RepoService'
❌ src/pages/RepoList.tsx → import { RepoService } from '@/client/services/RepoService'
```
## Safety
- 禁止硬编码 secrets / API keys / tokens
- 所有用户输入必须验证(zod schema)
- 错误必须显式处理,禁止 silent failure
- 禁止使用 `// ── xxxx ──────────` 分隔注释
## Reference
- `hooks.txt` — 项目已安装依赖的完整 Hooks 清单
- `biome.json` — Biome 格式化 / Lint 配置
- `openapi.json` — API Schema(用于生成 `src/client/`
- `genapi.js` — API 代码生成脚本(`bun run genapi`