# 简洁 TypeScript 项目蓝图

这是一份可复用的决策指南，而非必须照搬的脚手架。它保留了 Study Buddy 仓库中有效的工程做法，移除了所有产品工作流、服务、领域和凭据细节。

## 1. 以首个真实需求决定项目形态

当浏览器应用需要由服务端持有数据时，默认从一个 Next.js 全栈模块化单体开始：

```text
src/
  app/          Next.js 路由、页面、布局、Server Action／Route Handler
  app/admin/    仅在当前确有管理需求时，放置同域、受服务端权限保护的管理页面
  components/   当前产品实际使用的界面组件；`ui/` 可放 shadcn/ui 组件
  server/       业务服务、身份与外部集成；不被客户端组件导入
  db/           数据库连接、Schema 与查询边界
drizzle/        选择 Drizzle 时的生成迁移
prisma/         选择 Prisma 时的 Schema 与生成迁移
docs/           可导航的工程事实来源
scripts/        确有需要的本地、迁移、配置和部署操作
```

推荐技术基线是 Next.js、TypeScript、Tailwind CSS、shadcn/ui、PostgreSQL、Docker，以及 Drizzle／Prisma 二选一。Drizzle 适合希望贴近 SQL、显式控制查询与迁移的团队；Prisma 适合更重视 Schema 驱动 Client、工具链和快速建模的团队。Redis 只在跨实例缓存、限流、分布式协调、队列或 Pub/Sub 有真实需求时加入，不是为了凑齐技术栈而启动的默认服务。

上面的 `drizzle/` 与 `prisma/` 是互斥示例，项目只保留所选 ORM 对应的目录。`app/admin/` 也不是预建目录：小型项目出现管理需求后，在同一 Next.js 应用、同一域名和同一认证上下文中增加受服务端权限保护的路由即可；不要仅以隐藏菜单代替鉴权。小项目无需先建立 workspace、`apps/api`、独立后台或 `packages/*`。只有出现独立部署的 API、多个客户端、独立 Worker、真实跨应用复用，或独立后台的组织／安全边界已经成立时，再演进为：

```text
apps/
  web/          Next.js 应用
  api/          仅在独立 API 边界已经成立时存在
  admin/        仅在独立管理后台边界已经成立时存在
packages/
  contracts/    真实跨应用协议上的共享 schema 与类型
  db/           确有多个服务共同使用时的数据访问基础
```

将因同一原因变化的代码放在一起。`contracts` 适合共享请求／结果约束，不应演变成杂物区；`db` 负责 Schema 和迁移机制，不能承接业务授权。仅当任务确实需要跨越 HTTP 请求持续执行时再增加 Worker。整体采用渐进式架构：先让单体内的业务模块承担变化，只有调用者、部署、数据安全或运行节奏确实分离时才拆包或拆服务。没有当前用途时，不要引入微服务、队列、向量库或插件系统。没有图片／文件需求时不预建对象存储；一旦需要用户上传或运行时资源，则使用 OSS／S3 兼容对象存储，不退回 Git 或应用本地目录。

不要把全栈产品做成只有界面可看的前端 Demo：凡是需要账号、业务数据、提交、审批、支付、文件处理或其他业务副作用的界面，都要接入真实服务端操作及对应开发数据源。临时样例必须明确标识，不能伪装成后端已经实现。性能优化同样不单独预留“性能模块”：先以请求数、查询耗时、首屏／交互等待或成本等证据定位瓶颈，再在所属模块减少重复工作、缩小读取范围或做局部优化；缓存、队列和额外基础设施只在证据表明必要时引入。

## 2. 在业务边界收拢权威性

浏览器与模型输出只能表达用户意图，不能证明身份、归属、完成状态、价格或 Tool 结果。服务端获取可信身份后，调用的业务操作应统一拥有：

- 授权与参数校验；
- 事务与版本／冲突语义；
- 可能重试的请求和任务的幂等性；
- 持久化状态变化与稳定的失败类别。

HTTP 路由、Worker handler 与 Agent Tool 只将各自协议适配到该操作，不能复制该操作的授权或写入顺序。不要让调用方协调一连串所有者检查、加锁、写入和清理步骤。数据库与文件存储的分布式写入无法原子化时，先保全已提交引用；只有确认不存在持久引用时才删除上传对象。若无法确认，则保留对象供诊断，而不能冒数据丢失风险。

## 3. 让本地使用可复现且无破坏性

锁定依赖并使用冻结安装。外部容器镜像固定版本或 digest。若网络或组织要求特定包／镜像源，应写入项目配置，而不是假定 Agent 的全局环境。

提供聚焦的启动、重启、停止、状态、生成迁移、执行迁移和相关 smoke 命令。本地启动器应：

1. 缺失时从已批准的本地来源创建运行时配置，但绝不覆盖已有配置；
2. 仅启动本项目基础设施并执行其迁移；
3. 按工作目录和入口识别自身进程，而非只按端口；
4. 等待真实就绪后才报告成功；
5. 停止或重启应用进程时保留数据卷。

本地数据库、端口和存储前缀必须区别于其他项目及测试／生产环境。日志、浏览器测试产物、生成的 `.env`、本地数据、上传目录和构建产物默认加入 `.gitignore`，除非负责人另有明确要求。运行时可变业务数据不得写入仓库内 JSON；结构化事实进入 PostgreSQL，图片和文件进入对象存储，数据库只保留受授权控制的对象元数据。

## 4. 配置与密钥的所有权

写清配置契约：必填变量名、允许的环境差异、谁提供取值、部署如何消费配置。检查配置形状时不打印具体值。运行时配置不得进入 Web 构建上下文、镜像层或诊断输出。

默认策略：

| 内容 | 版本控制策略 |
| --- | --- |
| 变量名、说明、无害默认值 | 提交模板／示例。 |
| 真实 API 密钥、密码、签名密钥 | 使用已批准的密钥库或受保护的部署配置。 |
| 生成的运行时 `.env`、日志、本地数据 | 不提交。 |

负责人可明确选择对完整且加密／访问受控的配置文件采用不同策略。此例外必须书面记录且一致遵守：限制仓库访问、避免显示凭据、不让凭据进入浏览器或镜像构建上下文，并在部署时以受限权限安装。不得未经明确授权改变仓库的配置策略或轮换凭据。

## 5. 让文档持续真实

以简短的 `docs/README.md` 作为导航入口。适合维护的聚焦文档包括：

- `development.md`：分支／提交模型、本地命令、验证分层、迁移规则；
- `architecture.md`：当前拓扑、归属边界、依赖和已确认限制；
- `deployment.md`：环境、发布授权、迁移／切流／回退行为、维护归属；
- `software-design.md`：项目特有的模块边界、权威性、失败语义与性能证据规则；
- 有非显而易见决策、发布或验证需要长期证据时，使用带日期的记录。

明确标注事项是已实现、计划、假设还是等待外部验证。链接而非重复事实来源，并将历史报告标记为历史。不要为了看似成熟而额外添加流程文档、图表或决策日志；只有它们能长期影响决策或解释非显而易见约束时才编写。

## 6. 分支与提交模型

主动选择协作模型，并在 `AGENTS.md` 与 `development.md` 中写明。

新项目目录若尚未处于 Git 仓库中，先初始化 Git、建立 `.gitignore`，再做首次提交。若 Git 作者身份缺失，只能使用已有的仓库／组织配置或用户提供的信息，不得编造姓名和邮箱。

- 对单人、上线前的快速迭代，在 `main` 直接进行有完整意义的本地提交，通常比仪式化的功能分支更简单。保护未提交改动；不得暂存、重置或将无关改动并入当前任务。推送和发布仍是显式操作。
- 多人协作、受保护的发布分支、外部评审或并行高风险工作，则使用短生命周期功能分支及明确的集成／测试路径。不能暗示某一种模型永远更安全；正确选择是团队能够持续一致执行的模型。

每项完整且已经执行最小必要验证的改动，默认形成一次原子本地提交；不要把每次保存或半成品状态都提交。提交前审阅暂存文件清单和差异，只暂存本任务文件。不提交二进制资源、用户数据、数据库导出、本地文件、构建产物、测试结果或密钥；迁移 SQL、迁移元数据、依赖锁文件和必要源码必须保留。提交信息简洁地说明有实际意义的行为变化即可。推送和发布仍是独立授权动作。

## 7. 验证分层

以最小且能验证改动风险的证据为准：

| 改动 | 最小有效证据 |
| --- | --- |
| 文案、CSS、局部界面交互 | 查看受影响页面，并试用改变的操作及一个必要边界。 |
| 业务规则或较大模块 | 走通关键端到端路径；对关键不变量按需补充或运行聚焦测试。 |
| 授权、持久化写入、迁移、队列任务 | 按影响验证隔离／权限、持久化结果、重复／重试、冲突／取消和迁移行为。 |
| 广泛共享改动或用户明确要求 | 运行仓库适用的全量检查。 |
| 仅文档改动 | 审阅差异、链接与事实一致性。 |

CI 可以运行更完整的确定性检查，例如类型检查、构建、在幂等性重要时重复应用迁移、集成／E2E 测试和就绪 smoke；但不必让每次本地小改动承担同等成本。真实模型／服务商检查必须显式启用，使用合成输入、说明成本，默认不作为发布门禁。

## 8. 面向生产的发布设计

构建和发布应锁定某个已提交 SHA，不能打包任意工作区改动。测试／预发布与生产须在域名、配置、数据库、私有存储、认证／Cookie 上下文以及公开索引策略上相互隔离。

服务需要低中断切换时，使用发布锁，其临界区同时覆盖配置安装及其后的所有消费者。一个可靠的发布顺序是：

```text
获得授权的已提交 SHA
  -> 校验环境／配置身份
  -> 构建不可变应用产物
  -> 执行前向兼容的数据库与队列迁移
  -> 在健康服务旁启动候选版本
  -> 验证容器／进程、API 就绪和相关 Web 响应
  -> 切换私有反向代理流量
  -> 验证公网 HTTPS／版本
  -> 保留一个已知可用的旧产物；只清理安全的旧产物
```

蓝绿槽适合确有低中断切换需求的应用，简单服务不必强上。应用端口绑定 loopback／私有网络，由反向代理终止 HTTPS 并路由同源 API；不能只为方便就暴露数据库或 Worker 端口。

迁移必须允许旧应用与新应用并存。使用短锁超时，并以多次发布完成“扩展 → 应用切换 → 收缩”。不要做自动 down migration。候选启动或切流验证失败时，保持健康服务继续运行。代码回退不得伪装成已应用数据迁移也被逆转。

发布确认后，只清理可证明属于本项目且不再使用的产物：旧发布目录和无引用镜像版本。保留当前与回退候选版本及容器引用镜像。不得对共享构建缓存做全局清理，也不得将数据库、数据卷、对象存储、用户文件或演示数据作为常规发布清理目标。

## 9. 完成交付记录

新项目或基础工程改动完成时，应简洁、如实地记录：最终拓扑，所选开发／分支／配置策略，本地命令，新增文档，验证及结果，以及刻意延期事项。不要因为存在 Dockerfile、未实际演练的发布脚本或替身通过结果，就认定已经生产验收。
