横切关注点地图:从 MVP 到可扩展 SaaS 的 12 道生死线
专栏目录(共 12 篇 + 引言 + 总结)
引言:为什么你的 SaaS 死在了第 2 个客户?
- 讲述一个真实创业团队因“权限+租户”设计失误导致项目崩盘的故事
- 提出“横切关注点 = 系统可扩展性的隐形骨架”
- 介绍“最小正确抽象”原则
第 1 篇:多租户上下文 —— 你的数据真的隔离了吗?
- 错误示范:用部门 ID 冒充租户 ID
- 正确姿势:
tenant_id字段 + 上下文透传(ThreadLocal / AsyncLocalStorage) - 如何在 Web、RPC、MQ、定时任务中统一传递?
- 示例:NestJS 的轻量多租户方案
第 2 篇:认证(AuthN)—— 别让登录逻辑散落在 50 个文件里
- JWT 解析、刷新、黑名单
- 子域名/Path/ Header 如何识别租户?
- 统一认证中间件设计
- 警惕:前端传 userId 后端直接信任!
第 3 篇:授权(AuthZ)—— 从 if(user.id) 到策略引擎的演进路径
- 为什么 RBAC 不够?何时需要 ABAC/ReBAC?
- 权限检查函数的抽象:
can(user, action, resource) - 开源方案对比:Casbin vs SpiceDB vs 自研 ACL 表
- 创业初期建议:先做“资源归属字段 + 简单策略”,预留接口
第 4 篇:日志与审计 —— 合规不是负担,而是信任资产
- 操作日志 vs 系统日志
- 如何自动记录“谁在租户 X 下修改了订单 Y”?
- 结构化日志 + ELK / Loki 实践
- GDPR/等保要求下的最小审计字段清单
第 5 篇:异常处理 —— 别让用户看到你的 stack trace
- 统一错误码体系(业务码 vs HTTP 状态码)
- 敏感信息过滤(数据库密码、用户 token)
- 全局异常中间件 + Sentry 集成
- 异常分类:可恢复 vs 致命
第 6 篇:输入校验 —— 安全的第一道防线
- DTO 校验(Zod / Joi / class-validator)
- 防止 overposting(用户提交 extra 字段篡改数据)
- 校验失败的友好提示(国际化支持)
- 自动化:Swagger/OpenAPI 与校验规则联动
第 7 篇:事务管理 —— 数据一致性的底线
- 本地事务:@Transactional 的正确用法
- 分布式事务:Saga 模式实战(订单 → 扣库存 → 发券)
- 警惕:异步回调中的事务丢失
- 创业建议:尽量避免分布式事务,用最终一致性兜底
第 8 篇:缓存策略 —— 快,但别错
- 缓存穿透/雪崩/击穿防护
- 多租户下的缓存 key 设计:
order:{tenantId}:{id} - 缓存与数据库一致性(Cache-Aside vs Write-Through)
- Redis 命名空间隔离(防测试污染生产)
第 9 篇:可观测性 —— 当系统出问题时,你能看懂它吗?
- Metrics:Prometheus + Grafana 监控 QPS/延迟
- Tracing:Jaeger / Zipkin 跟踪请求链路
- Logging:结构化日志 + trace_id 串联
- 创业最小配置:一行日志包含 tenantId + userId + traceId
第 10 篇:配置管理 —— 别把密码写在代码里
- 多环境配置(dev/staging/prod)
- 敏感信息加密(Vault / KMS / 配置中心)
- 动态配置热更新(无需重启)
- .env 文件的正确使用姿势
第 11 篇:API 版本与兼容性 —— 别让你的客户因为升级而流失
- URL 版本 vs Header 版本
- 字段废弃策略(deprecated + 替代字段)
- 向后兼容的黄金法则
- 自动化:OpenAPI diff 工具检测破坏性变更
第 12 篇:测试支持 —— 如果难测,那一定是架构错了
- 如何 mock 租户上下文和权限?
- 集成测试中的数据隔离(每个测试用独立 tenant)
- 契约测试保障微服务兼容性
- 创业团队的测试金字塔:重单元,轻 E2E
专栏特色
- 每篇结尾有 “创业团队行动清单”
- 提供 可复制的代码模板
- 对比 “错误做法 vs 正确做法”
- 引用 真实事故案例(如某 SaaS 因租户隔离失效被罚)
以 NestJS 为主要框架讲解