react-best-practices
npx skills add https://github.com/trsoliu/react-best-practices --skill react-best-practices
Agent 安装分布
Skill 文档
React 项ç®å¼åå ¨æµç¨æå
1. ææ¯æ éåæå
| é¢å | éå | çç± |
|---|---|---|
| è¯è¨ | TypeScript 5.xï¼strict modeï¼ | ç±»åå®å ¨ï¼åå°è¿è¡æ¶é误 |
| UI æ¡æ¶ | React 18/19 | çææçï¼ç¤¾åºæ´»è· |
| å 管ç | pnpm | workspace åçæ¯æï¼ç£çæçé«ï¼ä¸¥æ ¼ä¾èµé离 |
| Monorepo | Turborepo | å¢éæå»ºãä»»å¡ç¼æãè¿ç¨ç¼åï¼ä¸ pnpm æ·±åº¦éæ |
| 客æ·ç«¯ç¶æ | Zustand | è½»éï¼~1KBï¼ï¼API ç®æ´ï¼æ Provider åµå¥ |
| æå¡ç«¯ç¶æ | TanStack Query | ç¼åãéè¯ãä¹è§æ´æ°ãåå°å·æ°ä¸ç«å¼è§£å³ |
| è·¯ç± | React Router v7 | éç¨ SPA è·¯ç±ï¼ç±»åå®å ¨ï¼æ°æ®å è½½å ç½® |
| æ ·å¼ | Tailwind CSS + CSS Modules | ååå CSS ææ + 模ååé离 |
| 表å | React Hook Form + Zod | é忧髿§è½ + schema éªè¯å¤ç¨ |
| HTTP | Axios / ky | æ¦æªå¨ãåæ¶è¯·æ±ï¼é å TanStack Query |
| æå»º | Vite | æé HMRï¼ESM åçæ¯æ |
| åå /ç»ä»¶æµè¯ | Vitest + Testing Library | Vite çæåçï¼API å ¼å®¹ Jest |
| E2E æµè¯ | Playwright | 夿µè§å¨ãèªå¨çå¾ ãtrace è°è¯ |
| 代ç è´¨é | ESLint + Prettier + typescript-eslint | ç»ä¸é£æ ¼ï¼èªå¨æ ¼å¼å |
| Git Hooks | Husky + lint-staged + commitlint | æäº¤åèªå¨æ£æ¥ï¼è§è commit message |
| çæ¬ç®¡ç | Changesets | åçæ¯æ monorepo å¤å çæ¬ï¼èªå¨çæ CHANGELOG |
2. Monorepo é¡¹ç®æ¶æè§è
éç¨ pnpm workspace + Turborepoï¼æ¨èç®å½ç»æï¼
my-react-app/
âââ pnpm-workspace.yaml # workspace é
ç½®
âââ turbo.json # Turborepo ä»»å¡ç®¡éé
ç½®
âââ package.json # æ ¹ package.jsonï¼scripts + devDepsï¼
âââ .changeset/ # Changesets é
ç½®
âââ .husky/ # Git hooks
âââ apps/ # åºç¨å±
â âââ web/ # 主 Web åºç¨
â â âââ src/
â â â âââ app/ # å
¥å£ãè·¯ç±é
ç½®ãå
¨å± Provider
â â â âââ features/ # æåè½æ¨¡åç»ç»ï¼æ ¸å¿ï¼
â â â â âââ auth/
â â â â âââ components/
â â â â âââ hooks/
â â â â âââ api/
â â â â âââ stores/
â â â â âââ types/
â â â â âââ index.ts
â â â âââ components/ # åºç¨çº§éç¨ç»ä»¶
â â â âââ hooks/ # åºç¨çº§éç¨ hooks
â â â âââ lib/ # å·¥å
·å½æ°ãAPI 客æ·ç«¯ãQuery é
ç½®
â â â âââ test/ # æµè¯å·¥å
·ãsetupãmocks
â â âââ e2e/ # Playwright E2E æµè¯
â â âââ vite.config.ts
â â âââ package.json
â âââ docs/ # ææ¡£ç«ï¼å¯éï¼
âââ packages/ # å
±äº«å
â âââ ui/ # å
±äº« UI ç»ä»¶åº
â â âââ src/
â â âââ package.json
â â âââ tsconfig.json
â âââ utils/ # å
±äº«å·¥å
·å½æ°
â âââ tsconfig/ # å
±äº« TypeScript é
ç½®
â â âââ base.json
â â âââ react.json
â â âââ package.json
â âââ eslint-config/ # å
±äº« ESLint é
ç½®
â âââ index.js
â âââ package.json
âââ docs/ # é¡¹ç®ææ¡£ï¼éæ±/设计/ADR/æåï¼
âââ tooling/ # å·¥å
·é
ç½®ï¼å¯éï¼
âââ prettier-config/
å ³é®é 置示ä¾
pnpm-workspace.yamlï¼
packages:
- "apps/*"
- "packages/*"
- "tooling/*"
turbo.jsonï¼
{
"tasks": {
"build": { "dependsOn": ["^build"], "outputs": ["dist/**"] },
"lint": { "dependsOn": ["^build"] },
"typecheck": { "dependsOn": ["^build"] },
"test": { "dependsOn": ["^build"] },
"dev": { "cache": false, "persistent": true }
}
}
å é´ä¾èµï¼package.jsonï¼ï¼
{
"dependencies": {
"@my-app/ui": "workspace:*",
"@my-app/utils": "workspace:*"
}
}
3. åºç¨å æ¶æè§èï¼feature-basedï¼
æ¯ä¸ª app å 鍿åè½æ¨¡åç»ç»ï¼éµå¾ªä»¥ä¸å½åè§èï¼
| ç±»å | å½åè§å | ç¤ºä¾ |
|---|---|---|
| ç»ä»¶ | PascalCase | UserProfile.tsx |
| Hooks | camelCase + use åç¼ |
useAuth.ts |
| Stores | camelCase + use åç¼ + Store åç¼ |
useAuthStore.ts |
| å·¥å ·å½æ° | camelCase | formatDate.ts |
| ç±»åæä»¶ | PascalCase | User.ts |
| 常é | UPPER_SNAKE_CASE | API_BASE_URL |
| æµè¯æä»¶ | 䏿ºæä»¶åå + .test |
useAuth.test.ts |
Import æåºè§å
// 1. å¤é¨ä¾èµ
import { useState } from 'react'
import { useQuery } from '@tanstack/react-query'
// 2. å
é¨å
ï¼monorepoï¼
import { Button } from '@my-app/ui'
// 3. ç¸å¯¹è·¯å¾
import { useAuthStore } from '../stores/useAuthStore'
// 4. ç±»å导å
¥
import type { User } from '../types/User'
Barrel file çç¥
- æ¯ä¸ª feature 模åæä¾
index.tsä½ä¸ºå ¬å ± API åºå£ - ç¦æ¢è·¨ feature ç´æ¥å¼ç¨å
鍿件ï¼å¿
é¡»éè¿
index.ts packages/ä¸çå ±äº«å å¿ é¡»æindex.ts导åº- 大å项ç®é¿å æ·±å±åµå¥ç barrel re-exportï¼å½±å tree-shakingï¼
4. å¼å约æä¸è§è
TypeScript ä¸¥æ ¼é ç½®
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true,
"exactOptionalPropertyTypes": true
}
}
ç¼ç è§å
- ç¦æ¢ä½¿ç¨
anyï¼ç¨unknown+ ç±»åå®å«æ¿ä»£ interfaceç¨äºç»ä»¶ Props åå¯¹è±¡ç»æï¼typeç¨äºèåç±»ååå·¥å ·ç±»å- ä¼å
使ç¨å½å导åºï¼
export functionï¼ï¼é¿å é»è®¤å¯¼åº - ç»ä»¶æä»¶ä¸è¶ è¿ 200 è¡ï¼è¶ åºåæååç»ä»¶ææå Hook
- è¶ è¿ 10 è¡çé»è¾æå为èªå®ä¹ Hook
- 使ç¨å¤å«èåï¼discriminated unionsï¼ç®¡çå¤æç¶æ
Zustand è§è
// â
æ¨èï¼å store åé¢åï¼actions ä¸ state å离
interface AuthState {
user: User | null
token: string | null
isAuthenticated: boolean
}
interface AuthActions {
login: (user: User, token: string) => void
logout: () => void
}
export const useAuthStore = create<AuthState & AuthActions>()(
devtools(
persist(
(set) => ({
user: null,
token: null,
isAuthenticated: false,
login: (user, token) => set({ user, token, isAuthenticated: true }),
logout: () => set({ user: null, token: null, isAuthenticated: false }),
}),
{ name: 'auth-storage' }
)
)
)
// â
ä½¿ç¨ selector 鲿¢ä¸å¿
è¦ç re-render
const user = useAuthStore((s) => s.user)
TanStack Query è§è
// â
Query Key Factory 模å¼
export const userKeys = {
all: ['users'] as const,
lists: () => [...userKeys.all, 'list'] as const,
list: (filters: UserFilters) => [...userKeys.lists(), filters] as const,
details: () => [...userKeys.all, 'detail'] as const,
detail: (id: string) => [...userKeys.details(), id] as const,
}
// â
èªå®ä¹ Hook å°è£
export function useUser(id: string) {
return useQuery({
queryKey: userKeys.detail(id),
queryFn: () => fetchUser(id),
staleTime: 5 * 60 * 1000, // 5 åé
})
}
5. Git æäº¤çº¦å®
Conventional Commits æ ¼å¼
<type>(<scope>): <description>
[å¯é body]
[å¯é footer]
Type ç±»å
| Type | 说æ |
|---|---|
feat |
æ°åè½ |
fix |
Bug ä¿®å¤ |
refactor |
éæï¼ä¸æ¹ååè½ï¼ |
perf |
æ§è½ä¼å |
test |
æµè¯ç¸å ³ |
docs |
ææ¡£åæ´ |
style |
ä»£ç æ ¼å¼ï¼ä¸å½±åé»è¾ï¼ |
chore |
æå»º/å·¥å ·/ä¾èµåæ´ |
ci |
CI/CD é ç½®åæ´ |
Scope å®ä¹ï¼React 项ç®ï¼
auth, ui, api, store, test, config, deps, router, i18n
ä¸æç¤ºä¾
feat(auth): æ·»å ç¨æ·ç»å½åè½
fix(cart): ä¿®å¤è´ç©è½¦æ°éæ´æ°ç«ææ¡ä»¶
refactor(api): å°éªè¯é»è¾æåå°ä¸é´ä»¶
test(user): æ·»å ç¨æ·æ³¨ååå
æµè¯
chore(deps): å级 React è³ v19
perf(list): 大å表添å èææ»å¨ä¼å
忝å½å
feature/<scope>-<description>â æ°åè½fix/<scope>-<description>â Bug ä¿®å¤hotfix/<description>â ç´§æ¥ä¿®å¤refactor/<description>â éædocs/<description>â ææ¡£test/<description>â æµè¯
Husky + commitlint + lint-staged é ç½®
// package.jsonï¼æ ¹ç®å½ï¼
{
"scripts": {
"prepare": "husky"
},
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{json,md,yaml}": ["prettier --write"]
}
}
// commitlint.config.js
export default {
extends: ['@commitlint/config-conventional'],
rules: {
'scope-enum': [2, 'always', ['auth', 'ui', 'api', 'store', 'test', 'config', 'deps', 'router', 'i18n']],
},
}
6. Changelog 管çè§è
å·¥å ·éåï¼Changesets
Changesets åçæ¯æ monorepo å¤å çæ¬ç®¡çï¼ä¸ pnpm workspace 深度éæã
åå§å
pnpm add -Dw @changesets/cli
pnpm changeset init
æ¥å¸¸æµç¨
# 1. å¼å宿åï¼æ·»å åæ´è®°å½
pnpm changeset
# 交äºå¼éæ©ï¼å½±åçå
â çæ¬ç±»åï¼patch/minor/majorï¼â åæ´æè¿°
# 2. åçæ¶ï¼æ¶è´¹åæ´è®°å½
pnpm changeset version
# èªå¨æ´æ°åå
package.json çæ¬å· + çæ CHANGELOG.md
# 3. åå¸
pnpm changeset publish
çæ¬å·è§åï¼SemVerï¼
| åæ´ç±»å | çæ¬å· | ç¤ºä¾ |
|---|---|---|
| Breaking Change | major | 1.0.0 â 2.0.0 |
| æ°åè½ | minor | 1.0.0 â 1.1.0 |
| Bug ä¿®å¤ | patch | 1.0.0 â 1.0.1 |
CI/CD éæï¼GitHub Actionsï¼
# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- run: pnpm install --frozen-lockfile
- uses: changesets/action@v1
with:
publish: pnpm changeset publish
version: pnpm changeset version
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
7. æµè¯çç¥
æµè¯éåå¡
âââââââââââ
â E2E â Playwright â å
³é®ç¨æ·æµç¨
âââââââââââ¤
â ç»ä»¶æµè¯ â Vitest + Testing Library â ç»ä»¶äº¤äº
âââââââââââ¤
â åå
æµè¯ â Vitest â å·¥å
·å½æ°ãhooksãstores
âââââââââââ
è¦ççç®æ
- åå æµè¯ï¼80%+
- ç»ä»¶æµè¯ï¼70%+
- E2Eï¼è¦çææå ³é®ç¨æ·è·¯å¾
Vitest é ç½®
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
globals: true,
setupFiles: ['./src/test/setup.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'lcov'],
exclude: ['node_modules/', 'src/test/', '**/*.d.ts'],
},
},
})
Testing Library è§è
// src/test/test-utils.tsx â èªå®ä¹ renderï¼æ³¨å
¥ææ Providerï¼
import { render } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { MemoryRouter } from 'react-router'
function createTestQueryClient() {
return new QueryClient({ defaultOptions: { queries: { retry: false } } })
}
export function renderWithProviders(ui: React.ReactElement) {
const queryClient = createTestQueryClient()
return render(
<QueryClientProvider client={queryClient}>
<MemoryRouter>{ui}</MemoryRouter>
</QueryClientProvider>
)
}
æ¥è¯¢ä¼å
çº§ï¼ getByRole > getByLabelText > getByText > getByTestId
äºä»¶ï¼ ä½¿ç¨ userEvent èé fireEvent
API Mockï¼ ä½¿ç¨ MSWï¼Mock Service Workerï¼
Zustand Store æµè¯
import { renderHook, act } from '@testing-library/react'
import { useAuthStore } from './useAuthStore'
beforeEach(() => {
useAuthStore.setState({ user: null, token: null, isAuthenticated: false })
})
it('should login user', () => {
const { result } = renderHook(() => useAuthStore())
act(() => { result.current.login(mockUser, 'token-123') })
expect(result.current.isAuthenticated).toBe(true)
})
Playwright E2E é ç½®
// playwright.config.ts
import { defineConfig } from '@playwright/test'
export default defineConfig({
testDir: './e2e',
baseURL: 'http://localhost:5173',
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
webServer: {
command: 'pnpm dev',
port: 5173,
reuseExistingServer: !process.env.CI,
},
})
Monorepo æµè¯ç¼æ
# Turborepo å¢éæµè¯ï¼åªæµè¯åå½±åçå
ï¼
turbo run test --filter=...[HEAD~1]
# å
¨éæµè¯
turbo run test
# åå
æµè¯
turbo run test --filter=@my-app/web
8. 代ç å®¡æ¥æ¸ å
åè½
- åè½æ¯å¦æéæ±æ£ç¡®å®ç°
- è¾¹çæ åµæ¯å¦å¤çï¼ç©ºå¼ã空æ°ç»ãè¶ é¿è¾å ¥ï¼
- éè¯¯ç¶ææ¯å¦ä¼é å¤çï¼loading / error / emptyï¼
- æ¯å¦æå¯¹åºçéæ±ææ¡£æ issue å ³è
代ç è´¨é
- æ
anyç±»åä½¿ç¨ - ç»ä»¶èè´£åä¸ï¼ä¸è¶ è¿ 200 è¡
- æ ä¸å¿ è¦ç re-renderï¼æ£æ¥ selectorãmemo 使ç¨ï¼
- 夿é»è¾å·²æå为èªå®ä¹ Hook
- æ 硬ç¼ç çéæ³æ°å/åç¬¦ä¸²ï¼æå为常éï¼
- å½åæ¸ æ°ï¼ç¬¦åå½åè§è
æ§è½
- 大å表使ç¨èæåï¼å¦ @tanstack/react-virtualï¼
- å¾çä½¿ç¨æå è½½
- é¿å ä¸å¿ è¦ç useEffect
- useMemo/useCallback ç¨äºæè´µè®¡ç®å稳å®å¼ç¨
- é¿å å¨ render ä¸å建æ°å¯¹è±¡/æ°ç»
æµè¯
- æ°åè½æå¯¹åºæµè¯
- æµè¯è¦ççæªä¸é
- æµè¯å½åæè¿°è¡ä¸ºèéå®ç°
- Mock èå´æå°å
æ éç¢
- è¯ä¹å HTML æ ç¾ï¼buttonãnavãmainãsectionï¼
- é®çå¯å¯¼èªï¼TabãEnterãEscapeï¼
- ARIA æ ç¾å®æ´ï¼aria-labelãroleï¼
- é¢è²å¯¹æ¯åº¦è¾¾æ ï¼WCAG AA 4.5:1ï¼
9. å ç½®å·¥ä½æµ
åè½å¼å工使µï¼Feature Workflowï¼
éæ±ç¡®è®¤ â åå»ºåæ¯ â [ç¼å ADR] â ç¼ç â æµè¯ â èªæ¥ â PR â CI â Review â åå¹¶
- ç¡®è®¤éæ±ææ¡£ï¼PRDï¼å·²è¯å®¡éè¿
- ä»
mainå建feature/<scope>-<desc>忝 - 妿¶åæ¶æåæ´ï¼å ç¼å ADR
- ç¼ç å®ç°ï¼éµå¾ªç¬¬ 3ã4 ç« è§èï¼
- ç¼åæµè¯ï¼éµå¾ªç¬¬ 7 ç« çç¥ï¼
- å¯¹ç §ç¬¬ 8 ç« ä»£ç å®¡æ¥æ¸ åèªæ¥
pnpm changesetæ·»å åæ´è®°å½- æäº¤ PRï¼å¡«å PR 模æ¿
- CI èªå¨è¿è¡ï¼lint â typecheck â test â build
- Code Review éè¿ååå¹¶
Bug ä¿®å¤å·¥ä½æµï¼Bugfix Workflowï¼
å¤ç° â åå»ºåæ¯ â å失败æµè¯ â ä¿®å¤ â åå½ â PR â åå¹¶
- å¤ç°é®é¢ï¼è®°å½å¤ç°æ¥éª¤
- ä»
mainå建fix/<scope>-<desc>忝 - å åä¸ä¸ªè½å¤ç° bug ç失败æµè¯ç¨ä¾
- ä¿®å¤ä»£ç 使æµè¯éè¿
- è¿è¡å彿µè¯ç¡®è®¤æ å¯ä½ç¨
pnpm changesetï¼patch çæ¬ï¼- æäº¤ PR â åå¹¶
åç工使µï¼Release Workflowï¼
changeset version â æ´æ°çæ¬ â CI â tag â åå¸ â éç¥
pnpm changeset versionâ æ´æ°çæ¬å·å CHANGELOG- æäº¤çæ¬åæ´ commit
- CI èªå¨æå»º + å ¨éæµè¯
- æ git tag
- GitHub Release åå¸ï¼èªå¨/æå¨ï¼
- éç¥ç¸å ³æ¹ï¼Slack/é£ä¹¦/é®ä»¶ï¼
CI/CD Pipeline 工使µ
# PR 触å
lint â typecheck â unit test â build â preview deploy
# åå¹¶ main 触å
full test â build â staging deploy
# tag 触å
build â production deploy
GitHub Actions 模æ¿ï¼Monorepo éé ï¼ï¼
# .github/workflows/ci.yml
name: CI
on:
pull_request:
branches: [main]
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- run: pnpm turbo lint typecheck test build
10. å¼åææ¡£ç®¡çè§è
ææ¡£ç®å½ç»æ
docs/
âââ requirements/ # éæ±ææ¡£
â âââ 000-template.md # éæ±ææ¡£æ¨¡æ¿
â âââ PRD-001-user-auth.md # 产åéæ±ææ¡£
â âââ BRD-001-payment.md # ä¸å¡éæ±ææ¡£
âââ design/ # æ¹æ¡è®¾è®¡
â âââ 000-template.md # è®¾è®¡ææ¡£æ¨¡æ¿
â âââ HLD-001-system-arch.md # æ¦è¦è®¾è®¡
â âââ LLD-001-auth-flow.md # 详ç»è®¾è®¡
â âââ API-001-user.md # API æ¥å£è®¾è®¡
âââ adr/ # æ¶æå³çè®°å½
â âââ 000-template.md # ADR 模æ¿
â âââ 001-use-zustand.md
â âââ 002-monorepo-setup.md
âââ guides/ # å¼åæå
â âââ getting-started.md # å¿«é䏿
â âââ development.md # å¼åç¯å¢æå»º
â âââ contributing.md # è´¡ç®æå
â âââ deployment.md # é¨ç½²æå
âââ specs/ # ææ¯è§æ ¼
â âââ api-design.md
âââ decisions/ # ææ¯éåè®°å½
âââ tech-stack.md
éæ±ææ¡£è§èï¼PRD/BRDï¼
ç¼å·è§åï¼ <ç±»å>-<åºå·>-<ç®è¿°> å¦ PRD-001-user-auth
PRD 模æ¿ï¼
# PRD-XXX: <åè½åç§°>
- ç¶æï¼è稿 | è¯å®¡ä¸ | 已确认 | å¼åä¸ | 已宿
- ä½è
ï¼
- æ¥æï¼
## èæ¯
为ä»ä¹è¦åè¿ä¸ªåè½ï¼
## ç®æ ç¨æ·
è°ä¼ä½¿ç¨è¿ä¸ªåè½ï¼
## åè½éæ±
### æ ¸å¿åè½
### è¾¹çæ
åµ
## éåè½éæ±
æ§è½ãå®å
¨ãå
¼å®¹æ§è¦æ±
## éªæ¶æ å
- [ ] æ å 1
- [ ] æ å 2
## ä¼å
级
P0/P1/P2/P3
BRD 模æ¿ï¼
# BRD-XXX: <ä¸å¡éæ±åç§°>
- ç¶æï¼è稿 | è¯å®¡ä¸ | 已确认
## ä¸å¡èæ¯
## ä¸å¡ç®æ
## ä¸å¡æµç¨
## æåææ ï¼KPIï¼
## é£é©ä¸ä¾èµ
æ¹æ¡è®¾è®¡ææ¡£è§è
æ¦è¦è®¾è®¡ï¼HLDï¼æ¨¡æ¿ï¼
# HLD-XXX: <ç³»ç»/模ååç§°>
- ç¶æï¼è稿 | è¯å®¡ä¸ | å·²æ¹å
- å
³èéæ±ï¼PRD-XXX
## ç³»ç»æ¶æå¾
## 模ååå
## ææ¯éå
## æ°æ®æµè®¾è®¡
## é¨ç½²æ¹æ¡
## é£é©è¯ä¼°
详ç»è®¾è®¡ï¼LLDï¼æ¨¡æ¿ï¼
# LLD-XXX: <åè½åç§°>
- å
³è HLDï¼HLD-XXX
## ç»ä»¶è®¾è®¡ï¼ç»ä»¶å¾ï¼
## æ¥å£å®ä¹
## ç¶æç®¡ç设计
## å¼å¸¸å¤ç
## æ§è½èé
## æµè¯æ¹æ¡
API 设计模æ¿ï¼
# API-XXX: <æ¥å£åç§°>
## æ¥å£è·¯å¾
`POST /api/v1/users/login`
## è¯·æ±æ ¼å¼
## ååºæ ¼å¼
## é误ç
## é´ææ¹å¼
## è°ç¨ç¤ºä¾
设计è¯å®¡ Checklistï¼
- æ¯å¦æ»¡è¶³ PRD ä¸çææéæ±
- æ©å±æ§ï¼æªæ¥éæ±åæ´æ¯å¦å®¹æéé
- å®å ¨æ§ï¼æ¯å¦æ XSS/CSRF/æ³¨å ¥é£é©
- æ§è½ï¼æ¯å¦èèäºå¤§æ°æ®éåºæ¯
- 坿µè¯æ§ï¼æ¯å¦æ¹ä¾¿ç¼åæµè¯
ADRï¼æ¶æå³çè®°å½ï¼è§è
使¶å ADRï¼ å¼å ¥æ°ä¾èµãåæ´æ¶ææ¨¡å¼ãéæ©ææ¯æ¹æ¡æ¶
ADR 模æ¿ï¼
# ADR-XXX: <å³çæ é¢>
- ç¶æï¼æè®® | å·²æ¥å | å·²åºå¼ | å·²æ¿ä»£
- æ¥æï¼
- æ¿ä»£ï¼ADR-YYYï¼å¦éç¨ï¼
## èæ¯
ä»ä¹é®é¢éè¦å³çï¼
## å³ç
æä»¬éæ©äºä»ä¹æ¹æ¡ï¼
## å¤éæ¹æ¡
èèè¿åªäºå
¶ä»æ¹æ¡ï¼ä¸ºä»ä¹æ²¡éï¼
## åæ
è¿ä¸ªå³ç带æ¥çæ£é¢åè´é¢å½±åã
ææ¡£ç»´æ¤è§å
- æ°åè½å¼ååå¿ é¡»æå¯¹åºçéæ±ææ¡£ï¼PRDï¼
- æ¶åæ¶æåæ´çåè½å¿ é¡»ææ¹æ¡è®¾è®¡ææ¡£ï¼HLD/LLDï¼
- å¼å ¥æ°ææ¯/ä¾èµå¿ é¡»æ ADR
- æ°åè½å®æåå¿ é¡»æ´æ°ç¸å ³å¼åæå
- README ä¿æææ°çå¿«é䏿æå¼
- API åæ´åæ¥æ´æ° specs å design ææ¡£
- æ¯æ¬¡åçæ£æ¥ææ¡£æ¯å¦éè¦æ´æ°
- ææ¡£ä¸ä»£ç åä»ç®¡çï¼PR ä¸åæ¥æäº¤