agentsclimarketplace

Scaffold

Skill TNT-Likely/honeycomb/plugins/fastapi-vite-saas/skills/scaffold

当用户要起一个 FastAPI 后端 + Vite SPA 前端 + Docker + GitHub Actions 的单仓双端 SaaS 项目时使用。一个 docker run 就跑起来的自托管 SaaS / 内部工具骨架,脱胎于 BeeCount-Cloud 生产实践。触发关键词:"scaffold FastAPI + Vite 项目"、"新建一个 SaaS 单仓"、"起一个 FastAPI Docker monorepo"、"按 fastapi-vite-saas / BeeCount-Cloud 风格建项目"、"create a fastapi vite saas template"、"new selfhost monorepo with FastAPI and Vite"。不适用于纯前端项目、纯 CLI 工具、纯库项目。From its SKILL.md

Install
npx -y skills add TNT-Likely/honeycomb --skill scaffold

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
  • runs commandsInstructs the agent to run 6 commands, including `git init && git add -A && git commit -m "feat: fastapi-vite-saas 脚手架初始化"` and 5 more.

SKILL.md

13.6 KB, ~4.4k tokens by cl100k_base, as published. Nobody here has run it

FastAPI + Vite SaaS 脚手架技能

这套架构是什么

一个单仓双端的全栈应用骨架:Python 后端 + 前端 SPA 共住一个 git 仓库,通过多阶段 Docker 构建打成单一镜像,GitHub Actions 自动发版。核心定位:用一个 docker run 就能跑起来的自托管 SaaS。

技术选型(每一项都解释为什么):

选型为什么
Web frameworkFastAPIPydantic v2 校验直接当 schema、async 原生、OpenAPI 自动生成
ORMSQLAlchemy 2.x久经考验、async 支持成熟、Alembic 配套迁移成熟
MigrationsAlembic不要自己搞 schema_migrations 表
AuthJWT(PyJWT)+ passlib + 可选 pyotp 2FA无状态、单镜像无 redis 依赖
调度APScheduler BackgroundSchedulerin-process,不引入额外服务;线程池避免阻塞事件循环
备份加密pyzipper(AES-256 zip)stdlib zipfile 的 ZipCrypto 已破,pyzipper 是 drop-in 替换
对象存储rclone subprocess一个二进制覆盖 S3/R2/WebDAV/B2/GDrive/OneDrive
Lint/Type/Testruff + mypy + pytest标配,启动快
Frontendpnpm workspace + Vite + (React/Vue 任选)apps/* + packages/* 拆分清晰
构建产物单一 Docker 镜像多阶段:Node build 前端 → Python 运行时拷 dist/ 当静态
CIGitHub Actionsci.yml(test/lint/build)+ release.yml(tag 触发 → docker hub)
编排Makefile不引入 just/task,Makefile 一份所有人都会读

仓库布局(基线)

<project>/
├── .github/
│   └── workflows/
│       ├── ci.yml              # PR/push: ruff + mypy + pytest + frontend build
│       └── release.yml          # tag 'v*': build & push docker image
├── .docs/                       # 内部设计文档(不发布)
├── docs/                        # 用户向文档(随发版打入镜像/网站)
├── alembic/
│   ├── env.py
│   ├── script.py.mako
│   └── versions/
├── data/                        # 运行时数据(gitignored,.gitkeep 占位)
│   └── .gitkeep
├── frontend/
│   ├── pnpm-workspace.yaml
│   ├── package.json             # 仅 workspace 根
│   ├── apps/
│   │   └── web/                 # Vite SPA
│   └── packages/
│       ├── api-client/          # 类型化 API client(从 OpenAPI 生成)
│       ├── ui/                  # 共享组件
│       └── features/            # 跨页可复用业务组件
├── scripts/                     # 运维脚本(seed/backup/grant-admin/...)
├── src/                         # Python package(直接 import,不再嵌一层)
│   ├── __init__.py
│   ├── main.py                  # FastAPI app + lifespan
│   ├── config.py                # pydantic-settings,所有 env 集中定义
│   ├── database.py              # engine / session / Base
│   ├── deps.py                  # FastAPI Depends 工厂(get_db / get_user / ...)
│   ├── models.py                # SQLAlchemy ORM(小项目放一起,大了再拆)
│   ├── schemas.py               # Pydantic schemas(同上)
│   ├── security.py              # 密码哈希 + JWT 签发/校验 + 可选 TOTP
│   ├── error_handling.py        # 全局异常 → JSON 响应映射
│   ├── observability.py         # structured logging + metrics
│   └── routers/
│       └── <group>/
│           ├── __init__.py      # 聚合 APIRouter,main.py import 不变
│           ├── _shared.py       # 共享 imports/helpers/router 实例;__all__ 显式
│           └── <entity>.py      # 单一资源的 POST/PATCH/DELETE 或一组 GET
├── tests/                       # pytest,与 src/ 对称
├── .env.example                 # 所有 env 的注释样本(.env 进 gitignore)
├── .gitignore
├── alembic.ini
├── docker-compose.yml           # 生产 compose(用户拿去 deploy)
├── docker-compose.postgres.yml  # overlay,可选切换 Postgres
├── Dockerfile                   # 多阶段:frontend-builder → python:3.12-slim
├── Makefile                     # 唯一的命令编排入口
├── mypy.ini
├── pytest.ini
├── README.md / README.en.md     # 双语
├── requirements.txt             # 不用 pyproject — 简单项目 requirements 更直白
├── ruff.toml
└── server.py                    # 极简 entry:from src.main import app

几个不显眼但关键的设计:

  • server.py 在仓根:让 uvicorn server:app 能直接跑。生产 Dockerfile 也用这个,本地 dev 也用这个,统一入口避免本地/生产两套启动方式。
  • src/ 不再嵌套包名:小项目里 <project>/src/<project>/foo.py 是没必要的间接层。直接 src/foo.py,Python path 设 .(PYTHONPATH=.)即可。
  • 路由用包不用文件:每个 routers/<group>/ 是包,_shared.py 集中共享导入和 router 实例。新增 endpoint 只动单个 entity 文件,改共享逻辑只动 _shared.py不要把业务塞进 __init__.py,它只做聚合。
  • /data 是唯一持久化目录:DB、备份、附件、用户上传 — 全部走 DATA_DIR env,默认 /data(docker)或 ./data(本地)。容器部署只挂一个 volume 就能整体备份。
  • .docs/ vs docs/:点前缀的不发布(内部设计/复盘),无点前缀的对外。明确分流。

用户工作流(Makefile 是核心)

scaffold 完成后,用户应该能直接:

make setup-backend   # 建 venv + pip install + 拷 .env.example → .env
make migrate         # alembic upgrade head
make seed-demo       # 灌种子数据(可选)
make dev-api         # uvicorn --reload --host 0.0.0.0
make dev-web         # pnpm install + vite dev
make dev-db          # docker compose up postgres(如果切到 PG)
make test            # pytest
make lint            # ruff check
make typecheck       # mypy src
make wipe-local      # 清本地 dev 数据(保留 .gitkeep 和指定的构建产物)

dev-api 必须 --host 0.0.0.0:模拟器/真机经 WiFi 用 IP 访问时,uvicorn 默认绑 127.0.0.1 会 Connection refused。这条踩过,scaffold 时直接写好。

scaffold 流程(AI 执行步骤)

当用户说"按 fastapi-vite-saas 起一个新项目叫 Foo"时,按以下顺序执行:

Step 1: 收集参数

如果用户没给全,问清楚(一次性问,不要来回往返):

  • 项目名(kebab-case,如 foo-cloud)→ 同时确定 Python 包名(snake_case)、Docker image 名、env 前缀
  • 目标路径(默认 ~/code/mine/<project-name>)
  • 前端框架:React / Vue / Svelte(默认 React,跟 BeeCount-Cloud 一致)
  • 默认数据库:SQLite(单镜像零依赖)/ Postgres(团队/生产强一致需求)— 默认 SQLite,Postgres 通过 overlay compose 切换
  • 是否需要 2FA(默认否,简化首版)
  • 是否需要备份模块(rclone + 加密 zip,默认否,有需要再加)
  • GitHub owner(用户名/组织名,写进 Dockerfile/README/CI)

Step 2: 创建目录树 + 生成基础文件

按上面的"仓库布局"创建空目录(包括 .gitkeep 占位)。

然后生成以下文件,所有 {{project_name}} / {{python_pkg}} / {{github_owner}} / {{image_name}} 替换成 Step 1 参数:

  1. requirements.txt — 基线依赖(从这个 skill 同目录的 templates/requirements.txt 拷,见下面"模板文件")
  2. src/main.py — FastAPI app 骨架,挂 CORS、健康检查 /healthz、版本端点 /api/v1/version
  3. src/config.py — pydantic-settings,声明所有 env(DATABASE_URL, JWT_SECRET, DATA_DIR, CORS_ORIGINS, APP_ENV, APP_VERSION)
  4. src/database.py — engine(根据 DATABASE_URL 自动判 sqlite/pg)+ SessionLocal + Base
  5. src/deps.py — get_db / get_current_user 占位
  6. src/security.py — passlib CryptContext + JWT encode/decode
  7. src/models.py — User 模型占位
  8. src/schemas.py — UserCreate/UserRead/Token 占位
  9. src/error_handling.py — 把常见异常映射成 JSON(401/403/404/422/500)
  10. src/routers/auth/__init__.py + _shared.py + register.py + login.py — 完整可跑的注册登录端点
  11. alembic.ini + alembic/env.py + 第一个 migration(创建 users 表)
  12. server.py — 一行:from src.main import app
  13. Makefile — 全套 dev/test/lint/typecheck/wipe-local
  14. Dockerfile — 多阶段构建(参考 BeeCount-Cloud,删掉 docs-index 那一段,普通项目不需要 RAG 索引)
  15. docker-compose.yml — 单服务,挂 ./data:/data,暴露端口可参数化(默认 8080 → host)
  16. docker-compose.postgres.yml — overlay,定义 db service + 覆盖 DATABASE_URL
  17. .env.example — 所有 env 的注释样本,JWT_SECRET 写 change-me-32-bytes-strong-random
  18. .gitignore — Python + Node + venv + .env + data/* (保留 .gitkeep) + IDE
  19. ruff.toml / mypy.ini / pytest.ini — 直接抄 BeeCount-Cloud 的配置
  20. .github/workflows/ci.yml — matrix: backend(ruff + mypy + pytest)+ frontend(pnpm install + build)
  21. .github/workflows/release.yml — tag 触发,build docker → push docker hub(用 {{github_owner}}/{{image_name}})
  22. README.md + README.en.md — 模板文档(项目简介、quickstart、deploy、env 说明)
  23. frontend/pnpm-workspace.yaml + frontend/package.json
  24. frontend/apps/web/ — Vite + React/Vue 模板(用 pnpm create vite 思路,生成最小可跑)
  25. frontend/packages/api-client/ — 占位 + 注释说明"从 OpenAPI 用 openapi-typescript 生成"
  26. frontend/packages/ui/ + frontend/packages/features/ — 占位 + 一个 hello 组件

Step 3: 初始化 git + 装依赖 + 跑一次自检

cd <target>
git init && git add -A && git commit -m "feat: fastapi-vite-saas 脚手架初始化"
make setup-backend
make migrate
make test  # 期望:0 个测试,exit 0
cd frontend && pnpm install
pnpm -C apps/web build  # 期望:dist/ 产出

任何一步失败,立即停下报错给用户,不要试图绕过。

Step 4: 提示下一步

最后给用户一份"接下来要干的 5 件事"清单:

  1. .env.exampleJWT_SECRET 为真随机串(给一行 openssl rand -hex 32 命令)
  2. 把仓库推到 GitHub:gh repo create {{github_owner}}/{{project_name}} --public --source . --push
  3. 配 Docker Hub secrets(DOCKERHUB_USERNAME / DOCKERHUB_TOKEN)让 release.yml 能 push 镜像
  4. 改 README 里的 placeholder(项目简介、screenshot)
  5. 起第一个业务实体:跟 AI 说"加一个 <实体名> 资源",AI 应该按 routers/<group>/ + models.py + schemas.py + alembic migration 这套流程加

不要从 BeeCount-Cloud 抄过来的部分

以下是 BeeCount-Cloud 的领域逻辑,新项目里不要默认带上:

  • sync_changes + read_*_projection + sync_applier.py 那套多端同步架构(只在需要"移动端离线 + 多设备同步"时才搭)
  • AI 文档 Q&A / RAG / numpy cosine search / docs-index.*.sqlite(只在产品本身要做文档搜索时才搭)
  • mcp/ 目录 MCP server(只在要给 LLM 工具调用时才搭)
  • pyzipper / rclone / apscheduler 备份链(在用户明确说要做"自助备份到对象存储"时才搭)
  • pyotp / TOTP 2FA(只在 step 1 用户明确说要 2FA 时才搭)
  • openpyxl Excel 导入(域特定,不要默认装)

每一项都增加运行时复杂度。默认 scaffold 是最小可跑的 FastAPI + Vite + Docker,其它当 add-on 按需启用。

模板文件位置

与 SKILL.md 同目录,有一个 templates/ 子目录,里面是上面 Step 2 列出的所有文件的实际模板内容(用 {{var}} 占位)。AI 执行时:

  1. templates/<filename> 内容
  2. 用 Step 1 收集的参数做字符串替换
  3. 写到 <target>/<filename>

模板暂未填充时,AI 可以基于 BeeCount-Cloud 对应文件现场改写(把 beecount / BeeCount / 8869 / sunxiao0721 等字面量替换成新项目参数)。后续版本会把模板固化进 templates/,减少现场改写的随机性。

反模式(已踩过的坑)

  • ❌ 不要在 server.py 里写业务,它只能是 from src.main import app 一行 — 否则本地/生产入口分裂
  • ❌ 不要用硬编码 SQL CREATE TABLE ... AS SELECT 做迁移,全走 Alembic
  • ❌ 不要在 Drift/Alembic 之外维护自己的 schema_migrations
  • ❌ Dockerfile 里不要在 frontend builder 阶段就 COPY frontend/ 全量 — 先只拷 package.json + lock,装完依赖再 COPY 全量,Docker layer cache 才能命中
  • ❌ 不要把 data/ 留在仓里跟构建产物混(docs-index.*.sqlite 是个例外:它是从兄弟仓 build 出来 commit 进去的索引)
  • ❌ HEALTHCHECK 不要打 /api/v1/healthz,挂在根 /healthz,避免被前缀路由拦掉

升级与变体

  • 切 Postgres:docker-compose -f docker-compose.yml -f docker-compose.postgres.yml up,.envDATABASE_URL=postgresql+psycopg://...
  • 切 Vue/Svelte:Step 1 选项分支,生成 frontend/apps/web/ 时换模板
  • 加 MCP server:用 mcp>=1.27.0 装 FastMCP,挂在 /api/v1/mcp,PAT 鉴权
  • 加备份模块:装 pyzipper + apscheduler,起一个 src/backup/ 包,scripts/backup_sqlite.sh 兜底 CLI

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.