Claude Code 从空目录到完整 API 全记录前几篇分别在老项目上改功能、重构、写测试。这篇更进一步——从一个空目录开始。我要建一个书签管理 API。收藏网页、打标签、搜索、导出。需求不复杂但涉及模型设计、路由分层、测试、Docker 部署、文档。从头手写大概半个下午。这次全交给 Claude Code看看一个空目录能变成什么。需求描述在一个空目录下启动 Claude Code输入我要建一个书签管理 REST API技术栈 FastAPI SQLite SQLAlchemy。功能POST /bookmarks — 添加书签url, title, tags 数组GET /bookmarks — 获取所有书签支持 ?tagpython 过滤GET /bookmarks/{id} — 获取单个书签DELETE /bookmarks/{id} — 删除书签GET /bookmarks/export — 导出为 JSONGET /health — 健康检查要求URL 要做基本验证http/https 开头tags 去重带 pytest 测试用 parametrizeDockerfile docker-compose.ymlREADME.md 包含安装和使用说明所有测试通过后才能算完成第一步设计架构Claude Code 没有直接撸代码。它先做了规划→ Project: bookmark-api → Plan: 1. Project structure: bookmark_api/ ├── main.py # FastAPI app entry ├── models.py # SQLAlchemy Bookmark model ├── schemas.py # Pydantic request/response schemas ├── database.py # DB connection session ├── routes.py # API endpoints ├── requirements.txt ├── Dockerfile ├── docker-compose.yml ├── README.md └── tests/ ├── conftest.py # fixtures (test client, test DB) └── test_bookmarks.py 2. Data model: Bookmark: id, url, title, tags (JSON array), created_at 3. Key decisions: - tags stored as JSON string in SQLite (no separate tags table for simplicity — this is a lightweight personal tool) - URL validation via Pydantic field validator - Test DB uses SQLite in-memory with session override这个架构选择值得注意tags 用 JSON 字符串存而不是独立表。Claude Code 给的判断依据是轻量个人工具不需要复杂关系查询。如果是一个团队协作的标签系统它会用第三范式。第二步一层一层建Claude Code 从底层往上层建每建一层跑一次验证。database.py — 数据库连接层[] bookmark_api/database.py - SQLAlchemy engine with SQLite - SessionLocal factory - get_db dependency - Base declarative basemodels.py — 数据模型[] bookmark_api/models.py class Bookmark(Base): id: int (PK) url: str (uniqueTrue, indexed) title: str tags: str (JSON-encoded) created_at: datetime (default utcnow)建完 modelClaude Code 立刻验证表能正常创建→ Tool: Bash $ python -c from bookmark_api.database import engine, Base; \ Base.metadata.create_all(engine); print(Tables created OK) → Tables created OKschemas.py — 请求/响应模型[] bookmark_api/schemas.py BookmarkCreate: url (HttpUrl), title (str, 1-200), tags (list[str]) BookmarkResponse: id, url, title, tags, created_at → URL validation via Pydantic HttpUrl type → tags deduplication in model validator用了 Pydantic 的HttpUrl类型做 URL 验证tag 去重用set()在 validator 里处理。routes.py — API 路由[] bookmark_api/routes.py POST /bookmarks — create bookmark, return 201 GET /bookmarks — list all, ?tag filter GET /bookmarks/{id} — get by ID, 404 if missing DELETE /bookmarks/{id} — delete, 404 if missing GET /bookmarks/export — export all as JSON with metadata GET /health — {status: ok}GET /bookmarks的 tag 过滤是这样实现的app.get(/bookmarks)deflist_bookmarks(tag:str|NoneNone,db:SessionDepends(get_db)):querydb.query(Bookmark)iftag:queryquery.filter(Bookmark.tags.contains(f{tag}))returnquery.order_by(Bookmark.created_at.desc()).all()没有用原始的LIKE %tag%而是contains(f{tag})——因为 tags 存的是[python, web]这种 JSON 字符串用引号包裹匹配避免了 “py” 匹配到 “python” 的部分字符串问题。main.py — 入口[] bookmark_api/main.py - FastAPI app with CORS middleware - Include router - Startup event: create tables第三步写测试每个路由都配了测试。Claude Code 用了conftest.py里的 fixture 来管理测试数据库和应用客户端。[] tests/conftest.py - app fixture: creates FastAPI test app - client fixture: TestClient for HTTP testing - db_session fixture: overrides get_db with in-memory SQLite [] tests/test_bookmarks.py test_create_bookmark_success — 正常创建验证 201 test_create_bookmark_invalid_url — 非法 URL → 422 test_create_bookmark_empty_title — 空标题 → 422 test_create_bookmark_duplicate_url — 重复 URL → 409 test_list_bookmarks_empty — 空数据库 → 空列表 test_list_bookmarks_with_data — 有数据 → 返回列表 test_list_bookmarks_filter_by_tag — tag 过滤 test_get_bookmark_by_id — 按 ID 查 test_get_bookmark_404 — 不存在 → 404 test_delete_bookmark — 删除成功 → 204 test_delete_bookmark_404 — 删除不存在 → 404 test_export_bookmarks — 导出 JSON → 验证结构 test_health_check — 健康检查跑测试→ pytest tests/ -v 13 passed in 0.47s13 个测试一次全绿。第四步Docker 和文档代码和测试都好了。Claude Code 接着建了部署和文档。DockerfileFROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD [uvicorn, bookmark_api.main:app, --host, 0.0.0.0, --port, 8000]docker-compose.ymlservices:api:build:.ports:-8000:8000volumes:-./data:/app/dataenvironment:-DATABASE_URLsqlite:///data/bookmarks.dbREADME.md不是那种 “A simple bookmark API” 两行就算了的 README。它包含了项目简介、技术栈、安装步骤、API 端点表格含请求/响应示例、Docker 部署命令、测试运行指令、项目结构树。最终的项目结构bookmark-api/ ├── bookmark_api/ │ ├── __init__.py │ ├── main.py (16 lines — FastAPI app) │ ├── database.py (22 lines — SQLAlchemy config) │ ├── models.py (18 lines — Bookmark model) │ ├── schemas.py (35 lines — Pydantic schemas) │ └── routes.py (68 lines — CRUD export health) ├── tests/ │ ├── __init__.py │ ├── conftest.py (35 lines — fixtures) │ └── test_bookmarks.py (112 lines — 13 tests) ├── requirements.txt (4 dependencies) ├── Dockerfile ├── docker-compose.yml └── README.md (55 lines)总代码量~360 行 Python 配置。从空目录到完整项目大约 20 分钟。跑起来$ docker-compose up -d $ curl http://localhost:8000/health {status: ok} $ curl -X POST http://localhost:8000/bookmarks \ -H Content-Type: application/json \ -d {url: https://fastapi.tiangolo.com, title: FastAPI Docs, tags: [python, web]} {id: 1, url: https://fastapi.tiangolo.com, ...} $ curl http://localhost:8000/bookmarks?tagpython [{id: 1, ...}] $ curl http://localhost:8000/bookmarks/export {exported_at: 2026-05-11T..., count: 1, bookmarks: [...]}Claude Code 在从零搭建中的几个亮点先规划再动手。它不是收到需求就开始写main.py。先分析了模型关系、存储方案、目录结构然后才动刀。这个设计方案→征求认可→执行的过程跟团队里的技术方案评审很像。从底层往上层建。database → models → schemas → routes → tests。每一层建完都做验证确保依赖正确。这种顺序跟你手写时的思路一致——你不会先写 Controller 再写 Model。细节经得起看。contains(f{tag})这个 JSON 标签匹配方式说明了它理解了 tags 的存储格式JSON 数组以及 LIKE 匹配的陷阱。这不是写完就行是写好才行。文档质量。README 不是模板填空。有具体的 curl 示例、docker-compose 命令、API 表格。一个接手的人看 README 就能跑起来。踩到的坑1. 第一次架构方案要审核Claude Code 提案的架构我会快速扫一眼。这次 tags 用 JSON 存储的方案我认同——如果不同意在这步纠正比重写代码省太多时间。2. 需求描述里的不做什么同样重要我在需求里写了范围6 个端点Claude Code 不会自己加东西。如果只说书签 API它可能加上用户认证、分页、全文搜索——功能蔓延。明确边界比写详细需求更重要。3. 分步验证比一次性全部建完靠谱建一个模块、跑一下、确认没问题、继续。虽然 Claude Code 也支持一次性生成全部代码但分层验证每一层都能拦住问题。什么样的项目适合 AI 从零建不是所有项目都适合这么搞。能成功的场景有几个共同点范围明确——你知道要什么。需求不明确的时候AI 会帮你想需求但想出来的跟你真正需要的差距可能很大。模式常见——REST API、CRUD、数据库操作。AI 见过的模式越多代码质量越高。如果你的需求涉及一个冷门协议或者公司内部框架AI 帮不上忙。规模不大——单服务应用几个到十几个文件。微服务架构、多仓库协同的复杂项目不是 AI 现在能独立搞定的。下一篇从需求描述到项目落地prompt 的质量直接影响结果。下一篇聊 Prompt Engineering——CLAUDE.md 怎么配、怎么给 AI 设定代码风格、上下文管理的实战技巧。欢迎大家评论区交流