commit 29d60fbd0a011f0b169c9fc409d4f8dbf9a5faa5 Author: baozaotumao Date: Mon Jun 1 20:28:07 2026 -0700 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..63f4171 --- /dev/null +++ b/README.md @@ -0,0 +1,352 @@ +# scaffold + +基于 [Copier](https://copier.readthedocs.io/) 的工程脚手架,一键生成含完整质量门禁的 FastAPI + React 项目,并随选型自动定制 Claude Code 约束规则。 + +--- + +## 核心设计 + +### 两层规则体系 + +脚手架内置的 Claude Code 规则文件分为两层,职责不同: + +| 层级 | 规则文件 | 加载方式 | 说明 | +|------|---------|---------|------| +| **原理层** | `architecture.md` / `ddd.md` / `design-discipline.md` 等 10 个 | 全局恒加载 | 六边形架构、DDD、SOLID、TDD 等通用原则,换项目不变 | +| **落地层** | `backend*.md` / `agent*.md` / `frontend*.md` | 按 `paths` 按需加载 | 原理在本项目具体服务中的落地约束,**随选型生成** | + +落地层规则根据问卷答案**动态生成或选择**,而非固定复制: + +``` +问卷选择 生成的落地层规则 +──────────────────────────────────────────────────────────────────── +include_agent=true + llm_provider=gemini-cli → agent.md + agent-concurrency.md + + agent-llm-pty.md(PTY/CLI 规范) + llm_provider=openai-api → agent.md + agent-concurrency.md + + agent-llm-api.md(API 流式规范) + llm_provider=anthropic-api → 同上(agent-llm-api.md) + +include_agent=false → 所有 agent*.md 全部排除 + +database=sqlite → backend-db.md(SQLite + WAL 模式) +database=postgresql → backend-db.md(asyncpg + 连接池 + pg 迁移注意) + +include_backend=false → 所有 backend*.md 排除 +include_frontend=false → 所有 frontend*.md 排除 +──────────────────────────────────────────────────────────────────── +``` + +--- + +## 脚手架内容 + +``` +scaffold/ +├── copier.yml ← 问卷变量 + 条件排除逻辑 +├── README.md +├── scripts/ +│ ├── verify.sh ← 工具链合规检查(幂等只读) +│ └── retrofit.sh ← 补装工具链到已有项目 +└── template/ + ├── .pre-commit-config.yaml.jinja ← 按服务条件生成 hooks + ├── .github/workflows/ci.yml.jinja ← 按服务条件生成 CI jobs + ├── docker-compose.yml.jinja + ├── CLAUDE.md.jinja ← 项目说明参数化 + ├── .claude/rules/ + │ ├── # 原理层(10 个,静态,始终复制) + │ ├── architecture.md / ddd.md / design-discipline.md ... + │ │ + │ ├── # 落地层:静态但条件复制(按服务选择) + │ ├── agent-dag.md ← DAG 模式(不随 LLM 选型变) + │ ├── agent-extension-points.md ← 扩展点模式(不随 LLM 选型变) + │ ├── agent-llm-pty.md ← LLM CLI/PTY 规范(仅 gemini-cli) + │ ├── agent-llm-api.md ← LLM API/SDK 规范(非 gemini-cli) + │ ├── backend.md / backend-concurrency.md + │ ├── frontend.md / frontend-runtime.md + │ ├── communication-catalog.md / error-codes.md / observability.md + │ │ + │ └── # 落地层:动态渲染(.jinja,内容随选型变化) + │ ├── agent.md.jinja ← 技术栈表 / 依赖 / 目录 / 配置 / 测试 + │ ├── agent-concurrency.md.jinja ← PTY 并发节 vs API 并发节 + │ └── backend-db.md.jinja ← SQLite 配置 vs PostgreSQL 配置 + ├── backend/ pyproject.toml / Dockerfile / .env.example / src/ + ├── agent/ 同上 + └── frontend/ package.json / tsconfig / eslint / prettier / vitest / vite +``` + +--- + +## 前置依赖 + +```bash +pip install copier # 或 uv tool install copier +``` + +--- + +## 生成新项目 + +### 交互式问卷(推荐首次使用) + +```bash +copier copy git+https://github.com/your-org/scaffold.git my-new-project +``` + +问卷包含以下选择: + +| 变量 | 类型 | 默认 | 说明 | +|------|------|------|------| +| `project_name` | str | My Awesome Service | 项目显示名称 | +| `project_slug` | str | 自动派生 | snake_case 包名 | +| `org_name` | str | my-org | GitHub 组织名 | +| `description` | str | — | 一行项目描述 | +| `include_backend` | bool | true | 包含 FastAPI backend | +| `include_agent` | bool | false | 包含 LLM Agent 服务 | +| `include_frontend` | bool | true | 包含 React + Vite 前端 | +| `backend_port` | int | 8000 | Backend 端口 | +| `agent_port` | int | 8001 | Agent 端口 | +| `frontend_port` | int | 5173 | 前端端口 | +| `python_version` | choice | 3.12 | 3.11 / 3.12 / 3.13 | +| `database` | choice | sqlite | `sqlite` / `postgresql` | +| `node_version` | choice | 22 | 20 / 22 | +| `llm_provider` | choice | gemini-cli | `gemini-cli` / `openai-api` / `anthropic-api` / `custom` | + +> `llm_provider` 仅在 `include_agent=true` 时出现。 + +### 静默生成(CI / 脚本中) + +```bash +# 全栈 + OpenAI API + PostgreSQL +copier copy git+https://github.com/your-org/scaffold.git my-project \ + --data project_name="My Service" \ + --data include_backend=true \ + --data include_agent=true \ + --data include_frontend=true \ + --data database=postgresql \ + --data llm_provider=openai-api + +# 仅 API(backend only,SQLite) +copier copy git+https://github.com/your-org/scaffold.git my-api \ + --data include_backend=true \ + --data include_agent=false \ + --data include_frontend=false + +# 本地模板调试 +copier copy ./scaffold /tmp/test-project +``` + +--- + +## 模板更新(推送给已有项目) + +```bash +cd my-existing-project + +# 复用上次答案,自动三路合并 +copier update --defaults + +# 修改某个答案(如切换数据库) +copier update --data database=postgresql + +# 查看更新预览(不实际写入) +copier update --defaults --pretend +``` + +`.copier-answers.yml` 由 Copier 自动维护,记录模板版本和答案,**不要手动修改**。 + +--- + +## 工具脚本 + +### `verify.sh` — 合规检查 + +检查项目工具链配置是否符合 scaffold 规范。**只读幂等,不修改任何文件,可重复运行。** + +``` +用法:./scripts/verify.sh [OPTIONS] [PROJECT_PATH] + +选项: + -h, --help 显示帮助信息 + -v, --verbose 详细输出(显示所有通过项和跳过项) + -s, --strict 严格模式:警告(△)也视为失败,退出码 1 + +退出码: + 0 全部通过(严格模式下无警告) + 1 存在失败项 + 2 参数错误 +``` + +```bash +# 检查当前目录 +./scripts/verify.sh + +# 详细模式(显示每项通过/跳过的路径) +./scripts/verify.sh -v + +# 严格模式(CI 中使用,警告也阻断) +./scripts/verify.sh -s /path/to/project + +# 详细 + 严格(组合简写) +./scripts/verify.sh -vs . +``` + +**智能检查内容:** + +- 自动读取 `.copier-answers.yml` 获取 `llm_provider` 和 `database` 配置 +- 按存在的目录(`backend/` / `agent/` / `frontend/`)决定检查哪些服务 +- **LLM 驱动规则互斥验证**:`gemini-cli` 时检查 `agent-llm-pty.md` 存在且 `agent-llm-api.md` 不存在(反之同理),两个同时存在时输出 WARN +- Claude 规则文件完整性检查(全局规则 + 对应落地层规则) +- 工具链可用性检查(uv / pnpm / pre-commit / copier 版本) + +**汇总输出示例:** + +``` +═══════════════════════════════════════════════════════════════ +分类 通过 警告 失败 +根目录 6 1 0 +Backend 8 0 0 +Agent 7 0 0 +Frontend 9 0 0 +Pre-commit 钩子 4 0 0 +Claude 规则文件 18 0 0 +工具链可用性 4 0 0 +─────────────────────────────────────────────────────────────── +合计 56 1 0 +═══════════════════════════════════════════════════════════════ +✓ 核心检查全部通过 △ 1 项警告(建议修复) +``` + +--- + +### `retrofit.sh` — 补装工具链到已有项目 + +对未经 copier 创建的已有项目,叠加 scaffold 模板。**全部步骤幂等,重复运行安全。** + +``` +用法:./scripts/retrofit.sh [OPTIONS] [PROJECT_PATH] + +选项: + -h, --help 显示帮助信息 + -n, --dry-run 预览所有操作,不实际执行任何命令 + -f, --force 强制覆盖配置文件(移除 _skip_if_exists 保护,慎用) + --no-deps 跳过依赖安装,仅运行 copier copy + --scaffold URL 指定 scaffold 来源(覆盖 $SCAFFOLD_URL) + +环境变量: + SCAFFOLD_URL scaffold 来源(默认:git+https://github.com/your-org/scaffold.git) +``` + +```bash +# 补装工具链到当前目录 +./scripts/retrofit.sh + +# 先预览将执行哪些步骤(不实际运行) +./scripts/retrofit.sh --dry-run /path/to/project + +# 使用本地 scaffold(开发调试) +SCAFFOLD_URL=./scaffold ./scripts/retrofit.sh /path/to/project + +# 使用远程 scaffold,仅运行 copier(跳过 uv/pnpm) +./scripts/retrofit.sh --scaffold git+https://github.com/your-org/scaffold.git --no-deps . + +# 补装后立即验证 +./scripts/retrofit.sh . && ./scripts/verify.sh . +``` + +**幂等性保证:** + +| 步骤 | 幂等机制 | +|------|---------| +| Copier 模版叠加 | `_skip_if_exists` 保护 `src/` 代码不被覆盖 | +| `uv sync` | `--frozen` 保证锁文件一致;已安装时仅校验,不重装 | +| `pnpm install` | `--frozen-lockfile` 保证锁文件一致 | +| Pre-commit 安装 | 检测 `.git/hooks/pre-commit` 已存在时 SKIP,`--force` 才重装 | + +**步骤汇总输出示例:** + +``` +═══════════════════════════════════════════════════════════════ +Retrofit 步骤汇总: /path/to/project +─────────────────────────────────────────────────────────────── +步骤 状态 +Copier 模版叠加 ✓ 完成 +Backend uv sync ✓ 完成 +Agent uv sync – 跳过 +Frontend pnpm install ✓ 完成 +Pre-commit 钩子 – 跳过(已安装,幂等) +─────────────────────────────────────────────────────────────── +完成: 3 跳过: 2 警告: 0 失败: 0 +═══════════════════════════════════════════════════════════════ + +后续步骤: + • 运行 ./scripts/verify.sh /path/to/project 验证最终结果 +``` + +--- + +## 典型组合示例 + +```bash +# 1. 全栈 AI 项目(默认 gemini-cli PTY 模式) +copier copy ./scaffold /tmp/test-full \ + --data include_backend=true --data include_agent=true --data include_frontend=true + +# 2. 全栈 AI 项目(OpenAI API 模式,生成 agent-llm-api.md 而非 agent-llm-pty.md) +copier copy ./scaffold /tmp/test-openai \ + --data include_backend=true --data include_agent=true --data include_frontend=true \ + --data llm_provider=openai-api --data database=postgresql + +# 3. 仅 API 服务(无前端,无 agent) +copier copy ./scaffold /tmp/test-api \ + --data include_backend=true --data include_agent=false --data include_frontend=false + +# 4. 验证生成结果(详细模式) +./scripts/verify.sh -v /tmp/test-full +``` + +--- + +## 发布到团队 + +```bash +cd /Users/maxta/Downloads/scaffold +git init && git add . && git commit -m "chore: initial scaffold" + +git remote add origin git@github.com:your-org/scaffold.git +git push -u origin main + +# 打版本 tag(copier update 按 tag 追踪) +git tag v1.0.0 && git push --tags +``` + +之后团队成员只需: + +```bash +pip install copier +copier copy git+https://github.com/your-org/scaffold.git my-project +``` + +--- + +## 贡献模板 + +1. 修改 `template/` 下的 `.jinja` 文件或静态规则文件 +2. 本地测试:`copier copy . /tmp/test && cd /tmp/test && pre-commit run --all-files` +3. 用 `verify.sh` 验证生成项目合规性:`./scripts/verify.sh -v /tmp/test` +4. 打 semver tag:`git tag v1.1.0 && git push --tags` +5. 已有项目运行 `copier update --defaults` 三路合并收到更新 + +### 添加新的 LLM provider 支持 + +1. 在 `copier.yml` 的 `llm_provider.choices` 中增加新选项 +2. 在 `template/.claude/rules/agent.md.jinja` 中添加对应 `{% elif llm_provider == '...' %}` 分支 +3. 在 `template/.claude/rules/agent-concurrency.md.jinja` 中视需要添加分支 +4. 若新 provider 使用不同机制(非 API SDK),按需新建对应规则文件并在 `copier.yml` 的 `_exclude` 中添加互斥条件 +5. 更新 `scripts/verify.sh` 中 `agent/pyproject.toml` 的 SDK 包名检查 + +### 添加新的数据库支持 + +1. 在 `copier.yml` 的 `database.choices` 中增加新选项 +2. 在 `template/.claude/rules/backend-db.md.jinja` 中添加对应 `{% elif database == '...' %}` 分支 +3. 在 `scripts/verify.sh` 的 `local_driver` 映射中添加新数据库的驱动包名