docs(readme): 重写为面向人类用户的版本
原版本以工程术语堆砌(强约定 / 契约优先 / 不变量等)开篇,对新人不友好。重写以"是什么 → 为什么 → 怎么跑 → 怎么扩 → 怎么部署 → 参考"为线索: - 开篇一句话讲清单二进制部署的核心卖点 - 新增"为什么用这个"突出 4 条价值点 - 新增"目录结构"帮助导航 - "加功能"步骤补充粗体小标题,每步意图一目了然 - 部署、脚本、端点全部表格化,便于扫读 - 删除对 AGENTS.md 的引用(人类读者无关)
This commit is contained in:
@@ -1,64 +1,110 @@
|
|||||||
# fullstack-starter
|
# fullstack-starter
|
||||||
|
|
||||||
强约定的单二进制全栈 starter。Bun + TanStack Start(React 19 SSR)+ ORPC(契约优先)+ Drizzle + PostgreSQL,编译为单个可执行文件部署。
|
一个**单二进制**的全栈应用 starter——`bun run compile` 出来的 `./server` 文件就是你要部署的全部产物,自带 HTTP 服务、SSR、API、嵌入式 SQL 迁移,运行时不依赖 Node、不依赖源码、不依赖外部 migration 目录。
|
||||||
|
|
||||||
> Agent 笔记与非显而易见的不变量见 [AGENTS.md](./AGENTS.md)。改结构前先读。
|
技术栈:Bun · TanStack Start (React 19 SSR) · ORPC(契约优先 API)· Drizzle ORM · PostgreSQL · Tailwind v4 · Biome。
|
||||||
|
|
||||||
|
## 为什么用这个
|
||||||
|
|
||||||
|
- **部署最简**:发布只拷一个二进制文件。先 `./server migrate` 再 `./server`,完事。
|
||||||
|
- **契约优先**:在 `*.contract.ts` 用 Zod 定义一次,前端、后端、OpenAPI 文档自动同步。
|
||||||
|
- **类型严格**:TypeScript strict,杜绝 `any` / `@ts-ignore` / `as any` 等类型逃逸。
|
||||||
|
- **开箱可跑**:路径别名、文件路由、ORPC 接线、Tailwind、热重载、错误页全部预接好。
|
||||||
|
|
||||||
## 快速开始
|
## 快速开始
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp .env.example .env
|
cp .env.example .env # 把里面的 DATABASE_URL 改成你的 Postgres
|
||||||
bun install
|
bun install
|
||||||
bun run db:push # 开发期:同步 schema 不生成 migration 文件
|
bun run db:push # 开发期:把 schema 直接同步到 DB(不写 migration 文件)
|
||||||
bun run dev # http://localhost:3000
|
bun run dev # http://localhost:3000
|
||||||
```
|
```
|
||||||
|
|
||||||
RPC 入口:`/api/rpc` · OpenAPI 文档:`/api/docs` · Spec:`/api/spec.json` · 存活探针:`/health`。
|
打开浏览器:
|
||||||
|
|
||||||
## 脚本
|
- `http://localhost:3000/` — Todo 示例页
|
||||||
|
- `http://localhost:3000/api/docs` — Scalar 渲染的 API 文档
|
||||||
|
|
||||||
| 命令 | 作用 |
|
## 目录结构(你需要关心的部分)
|
||||||
| --- | --- |
|
|
||||||
| `bun run dev` | Vite 开发服务器,3000 端口(strict) |
|
|
||||||
| `bun run build` | 构建到 `.output/` |
|
|
||||||
| `bun run compile` | `bun build --compile` 生成单二进制 `out/server-<target>` |
|
|
||||||
| `bun run cli <cmd>` | 源码态运行 CLI 子命令(`serve`、`migrate`) |
|
|
||||||
| `bun run typecheck` | `tsc --noEmit` |
|
|
||||||
| `bun run test` | `bun test`(同目录 `*.test.ts`) |
|
|
||||||
| `bun run fix` | Biome lint + format + 整理 imports |
|
|
||||||
| `bun run db:push` | 仅开发期 schema 同步(不写 migration 文件) |
|
|
||||||
| `bun run db:generate` | 把 SQL migration 写到 `./drizzle/` 并重生 `migrations.gen.ts` |
|
|
||||||
| `bun run db:embed` | 仅从 `./drizzle/` 重生 `src/server/db/migrations.gen.ts`(手改 SQL 后用) |
|
|
||||||
| `bun run db:migrate` | 通过 drizzle-kit 本地应用 migration(开发便利) |
|
|
||||||
| `bun run db:studio` | Drizzle Studio |
|
|
||||||
|
|
||||||
跨平台编译:`bun run compile:{linux,darwin,windows}[:arch]`。
|
```
|
||||||
|
src/
|
||||||
|
├── routes/ # 文件路由:页面 + API 端点
|
||||||
|
├── server/
|
||||||
|
│ ├── api/
|
||||||
|
│ │ ├── contracts/ # Zod 契约(client / server 共享)
|
||||||
|
│ │ └── routers/ # 业务实现
|
||||||
|
│ └── db/ # Drizzle schema + 嵌入式 migrations
|
||||||
|
├── client/ # 前端 hooks、ORPC 客户端
|
||||||
|
└── components/ # UI 组件
|
||||||
|
```
|
||||||
|
|
||||||
## 新增一个功能(以 `post` 为例)
|
## 加一个功能(以 `post` 为例)
|
||||||
|
|
||||||
契约优先、纯增量。按以下顺序建/改文件:
|
每一步都很短,按顺序填即可:
|
||||||
|
|
||||||
1. `src/server/db/schema/post.ts` — 定义 `postTable`,展开 `...generatedFields`。
|
1. **建表**:`src/server/db/schema/post.ts` 定义 `postTable`,记得展开 `...generatedFields`(自动注入 `id` / `createdAt` / `updatedAt`)。
|
||||||
2. `src/server/db/schema/index.ts` — `export * from './post'`。
|
2. **导出表**:在 `src/server/db/schema/index.ts` 加 `export * from './post'`。
|
||||||
3. `src/server/api/contracts/post.contract.ts` — 通过 `drizzle-zod` 从表派生 Zod schema。
|
3. **写契约**:`src/server/api/contracts/post.contract.ts` 用 `drizzle-zod` 从表派生 Zod schema。
|
||||||
4. `src/server/api/contracts/index.ts` — 把 `post` 加进 `contract` 对象。
|
4. **挂契约**:在 `src/server/api/contracts/index.ts` 把 `post` 加进 `contract` 对象。
|
||||||
5. `src/server/api/routers/post.router.ts` — 实现 `os.post.*.handler(...)`。
|
5. **写实现**:`src/server/api/routers/post.router.ts` 实现 `os.post.*.handler(...)`。
|
||||||
6. `src/server/api/routers/index.ts` — 把 `post` 加进 `router` 对象。
|
6. **挂路由**:在 `src/server/api/routers/index.ts` 把 `post` 加进 `router` 对象。
|
||||||
7. `src/client/queries/post.ts` — 导出 `useInvalidatePosts`(或更细粒度 helper),用于失效受影响的 list key。
|
7. **写前端 hook**:`src/client/queries/post.ts` 导出 `useInvalidatePosts` 等失效辅助。
|
||||||
8. `src/routes/<page>.tsx` — 用 `useSuspenseQuery` + loader `ensureQueryData`;mutation 的 `onSuccess` 调用上一步的 helper。
|
8. **写页面**:`src/routes/<page>.tsx` 用 `useSuspenseQuery` 读、`mutate` 写;mutation 的 `onSuccess` 调用第 7 步的 helper。
|
||||||
9. `bun run db:generate` — 写 SQL migration 到 `./drizzle/` 并嵌入 `src/server/db/migrations.gen.ts`。
|
9. **生成 migration**:`bun run db:generate` 把 SQL 写到 `./drizzle/` 并嵌入二进制。
|
||||||
|
|
||||||
|
完工。`bun run dev` 已自动热重载。
|
||||||
|
|
||||||
## 部署
|
## 部署
|
||||||
|
|
||||||
永远 **先 migrate 再 serve**。Migration 已嵌入二进制,二进制是你唯一发布的产物。
|
**永远先 migrate 再 serve**。Migration 已嵌入二进制;部署只发一个 `./server` 文件。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./server migrate # 用 $DATABASE_URL 应用嵌入式 migration
|
./server migrate # 应用嵌入式 migration(用 $DATABASE_URL)
|
||||||
./server # 启动 HTTP 服务器(默认子命令)
|
./server # 启动 HTTP 服务(默认子命令)
|
||||||
|
./server --help # 列出所有子命令
|
||||||
```
|
```
|
||||||
|
|
||||||
`compose.yaml` 把这个模式编排了出来:一次性 `migrate` 服务,`app` 通过 `service_completed_successfully` 等它完成。Kubernetes 上:把 `./server migrate` 放进 initContainer 或 Helm `pre-upgrade` Job。
|
仓库自带 `compose.yaml`(一次性 `migrate` 服务先跑完,再启动 `app`):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose up --build
|
docker compose up --build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Kubernetes 上:把 `./server migrate` 放进 initContainer 或 Helm `pre-upgrade` Job,主容器跑 `./server`。
|
||||||
|
|
||||||
|
## 脚本一览
|
||||||
|
|
||||||
|
| 命令 | 作用 |
|
||||||
|
| --- | --- |
|
||||||
|
| `bun run dev` | Vite 开发服务器(端口 3000,strict) |
|
||||||
|
| `bun run build` | 构建到 `.output/`(`bun run compile` 会用到) |
|
||||||
|
| `bun run compile` | 生成单二进制 `out/server-<target>` |
|
||||||
|
| `bun run typecheck` | TypeScript 类型检查 |
|
||||||
|
| `bun run test` | 运行所有 `*.test.ts` |
|
||||||
|
| `bun run fix` | Biome 格式化 + lint + 整理 imports |
|
||||||
|
| `bun run db:push` | 开发期:直接同步 schema 到 DB(不写 migration 文件) |
|
||||||
|
| `bun run db:generate` | 写 SQL migration 到 `./drizzle/` 并嵌入二进制 |
|
||||||
|
| `bun run db:embed` | 仅重生 `migrations.gen.ts`(手改了 `./drizzle/*.sql` 后用) |
|
||||||
|
| `bun run db:migrate` | 通过 drizzle-kit 在本地应用 migration(开发便利) |
|
||||||
|
| `bun run db:studio` | Drizzle Studio(可视化 DB) |
|
||||||
|
|
||||||
|
跨平台编译:`bun run compile:{linux,darwin,windows}[:arch]`。
|
||||||
|
|
||||||
|
## 端点
|
||||||
|
|
||||||
|
| 路径 | 用途 |
|
||||||
|
| --- | --- |
|
||||||
|
| `/` | Todo 示例 UI |
|
||||||
|
| `/health` | 存活探针(不查 DB,纯文本 `ok`) |
|
||||||
|
| `/api/rpc` | ORPC RPC 端点(client 直连) |
|
||||||
|
| `/api/docs` | Scalar 渲染的 API 文档 |
|
||||||
|
| `/api/spec.json` | OpenAPI spec |
|
||||||
|
|
||||||
|
## 提交前
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run fix && bun run typecheck && bun run test
|
||||||
|
```
|
||||||
|
|
||||||
|
没有 CI、没有 pre-commit hook——上面三条由你自觉跑。
|
||||||
|
|||||||
Reference in New Issue
Block a user