计划与方法
这门课程带 Java/Spring 开发者用 11 个全天工作日写出一个完整的 NestJS API。每天包含一个知识点、它在 Spring 里的对应物,以及在 TaskFlow 里的实践。TaskFlow 是一个项目与任务管理 API。本页交代整体安排:日期、前置要求、 每日节奏、日程和进度跟踪。
概览
| 项目 | 说明 |
|---|---|
| 开始 | 2026 年 11 月 9 日周一 |
| 结束 | 2026 年 11 月 24 日周二 |
| 时长 | 11 个全天工作日,约 2.5 周(11 月 11 日周三是法定假日,跳过) |
| 前置要求 | 接触过 TypeScript,已安装 Docker |
| 技术栈 | NestJS、TypeScript、PostgreSQL、TypeORM、Docker Compose、Jest |
| 贯穿项目 | TaskFlow,一个项目与任务管理 API |
TaskFlow 使用的版本,也就是网站所有代码片段的版本:NestJS 12.1、TypeScript 6.0、TypeORM 1.1、PostgreSQL 16、 Jest 30,HTTP 平台是 Express 5。Docker 镜像运行在 Node 24 LTS 上:本地请使用同一个大版本,避免出现差异。
贯穿项目 TaskFlow
TaskFlow 一天天长大:第一天一个 /health 接口,第二天内存版增删改查,第四天接入 PostgreSQL,第八天加上认证, 最后一天完成 Docker 镜像和 CI。完整项目在本网站仓库的 examples/ 目录下。它能编译、通过 lint,27 个单元测试和 8 个基于真实 PostgreSQL 的端到端测试全部通过。各章的代码片段都取自这里。
- 领域模型(用户、项目、成员、任务)见领域模型。
- 目录结构和命名约定见仓库结构。
- 如何运行项目:资源,TaskFlow。
跟课有两种方式:自己一天天重建 TaskFlow(这是计划的本意),或者阅读完成版项目,把精力放在讲解上。前一种学到的 更多;完成版可以当作参考答案。
学习方法
每天都按同一个节奏进行:
| 时段 | 时长 | 内容 |
|---|---|---|
| 上午 | 3 小时 | 简短的理论和 Spring ↔ Nest 对照,配合官方文档 |
| 下午 | 3 小时 | 在 TaskFlow 中实现、测试、提交 |
| 一天结束时 | 30 分钟 | 更新 LEARNINGS.md(和 Spring 不同的地方、陷阱),打 git 标签 jour-XX |
上午从当天的章节入手:“Spring → NestJS”表格是切入点,“原理”一节讲清运行机制,“延伸阅读”里的链接通向官方 文档。想到某个 Spring 概念却不知道它在 Nest 里对应什么时,完整对照表就是 你的地图。
下午按章节的“TaskFlow 案例”和“练习”在 TaskFlow 里动手。最后做一次能编译、测试全部通过的提交。
每天(或每个功能)一个提交,回头看提交历史就像读一本学习日志:每个提交记录一个步骤,顺序就是你理解它们的顺序。
学习日志
LEARNINGS.md 是整个课程的日志本。TaskFlow 自带的模板每天分三栏:
# LEARNINGS
Journal à remplir chaque fin de journée (30 min), puis `git tag jour-XX`.
Pour chaque jour : ce qui diffère de Spring, les pièges rencontrés, les questions ouvertes.
## J1 · Fondations Node et Nest
- Différence avec Spring :
- Piège rencontré :
- À creuser :
## J2 · Controllers, DTO, validation
- Différence avec Spring :
- Piège rencontré :
- À creuser :
<!-- Copier le bloc pour J3 à J11. -->重点记下从 Spring 过来让你意外的地方:半年后你要找的正是这些。简短具体的条目(“@Query() 收到的是字符串, 需要 @Type(() => Number)”)比课程总结更有用。
每天结束时,给仓库当前状态打标签:
git add -A
git commit -m "J2:内存版项目增删改查,DTO 带校验"
git tag jour-02之后可以用这些标签回顾整个过程:
git log --oneline --decorate # 提交历史,带 jour-XX 标签
git diff jour-04 jour-05 --stat # 关系与迁移那一天改了什么
git checkout jour-03 # 回到 J3 的状态(用 git switch - 切回来)日程
| 天 | 日期 | 主题 | TaskFlow 交付物 |
|---|---|---|---|
| J1 | 11 月 9 日周一 | Node、事件循环、Nest 项目、模块化架构 | 项目骨架、Docker Compose、第一个接口 |
| J2 | 11 月 10 日周二 | 控制器、路由、DTO、校验 | 内存版项目增删改查 |
| 11 月 11 日周三 | 法定假日 | ||
| J3 | 11 月 12 日周四 | 依赖注入、provider、service | 服务层、模块 |
| J4 | 11 月 13 日周五 | PostgreSQL、TypeORM、实体、repository | 项目数据持久化 |
| J5 | 11 月 16 日周一 | 关系、迁移、事务 | 任务挂到项目下、迁移 |
| J6 | 11 月 17 日周二 | 异常、过滤器、管道、拦截器、中间件 | 全局错误处理、请求日志 |
| J7 | 11 月 18 日周三 | 配置、多环境、日志 | 带校验的 ConfigModule、按环境区分配置 |
| J8 | 11 月 19 日周四 | JWT 认证、guard、角色 | 用户、登录、受保护的接口 |
| J9 | 11 月 20 日周五 | 事件、定时任务、异步、队列 | 状态变化时发通知 |
| J10 | 11 月 23 日周一 | 单元测试、集成测试、端到端测试 | 核心模块的测试覆盖 |
| J11 | 11 月 24 日周二 | Swagger、健康检查、Dockerfile、CI、最终回顾 | Docker 镜像、CI 流水线、OpenAPI 文档 |
按自然周算:第一周 4 天(周三是假日),第二周 5 天,第三周 2 天。
进度跟踪
当天的交付物提交并打好标签后,勾选对应的一行。
- [ ] J1:基础、项目骨架、Compose(章节)
- [ ] J2:控制器、DTO、校验(章节)
- [ ] J3:依赖注入与模块(章节)
- [ ] J4:TypeORM 与 PostgreSQL(章节)
- [ ] J5:关系、迁移、事务(章节)
- [ ] J6:异常、过滤器、拦截器(章节)
- [ ] J7:配置与日志(章节)
- [ ] J8:JWT 认证与角色(章节)
- [ ] J9:事件、定时任务、队列(章节)
- [ ] J10:单元测试与端到端测试(章节)
- [ ] J11:Swagger、健康检查、Docker、CI(章节)
建议
没有缓冲日
日程连排 11 天,没有缓冲。J4 的一次延误(PostgreSQL 连接怎么也建立不起来、实体装饰器写错)会拖累后面所有内容。 一开始就想好进度落后时要舍弃什么,并且每天都停在一个能编译的状态,哪怕功能还不完整。
可选内容
下面这些可以跳过,不影响后续课程:
| 内容 | 天 | TaskFlow 的做法 |
|---|---|---|
| 用 BullMQ 队列发通知(Redis) | J9 | 已实现,但只在设置了 REDIS_URL 时启用;否则监听器只写一条日志 |
| Refresh token | J8 | 未实现:只有一个 15 分钟有效的 JWT access token |
| 端到端测试使用 Testcontainers | J10 | 未使用:端到端测试跑在 Compose 的 db-test 服务上 |
需要时复习 TypeScript
计划假设你“接触过” TypeScript。如果只剩模糊印象,在 J1 之前复习这些:
interface和type(运行时被擦除)与class(运行时存在)的区别:这是理解依赖注入和校验的关键 (差异);- 参数属性(
constructor(private readonly service: ProjectsService) {}),每个 provider 都会用到; - 联合类型和类型收窄(
string | null、if (!task) throw …),以及字符串值的enum; ?.和??,在 Nest 代码里随处可见;async/await和Promise<T>(J1);- 模块的导入和导出,包括
import type; - 装饰器(
tsconfig.json里的experimentalDecorators):它们是函数,不是注解 (差异)。
从 J3 开始写测试
计划把测试集中放在 J10,但不要等到那时:J3 把 ProjectsService 放到抽象层后面之后,用 Test.createTestingModule 加内存 store 写一个单元测试只要几行(J10,测试模块)。 之后每天为每条业务规则补一个测试(仅成员可访问、状态流转、归档)。这样 J10 只需补齐端到端测试、设定覆盖率阈值, 而不是一口气全部写完;后面几天的每次重构(J4 换成 TypeORM、J8 加入用户)也都有测试保护。