docs: 基本完成初版数据库设计

This commit is contained in:
R524809
2026-10-15 10:09:34 +08:00
parent 63a6993276
commit e6ded00a4c
41 changed files with 2597 additions and 180 deletions
+67
View File
@@ -0,0 +1,67 @@
# Doodle Store Server 基础设置
> 更新日期:2026-10-13。已实现基础配置、日志、中间件、Swagger 与 JWT 守卫,业务登录和 Prisma 账户查询待接入。
参考 `atlas-seller-kit/apps/api` 的应用工厂、结构化日志、requestId、请求体限制、默认鉴权与错误处理。保持本项目 NestJS 11 和 `/api/v1` 契约,不复制卖家工作台的多租户、Redis、对象存储或业务模块。
## 1. 启动与环境变量
从 `doodle-store` 根目录执行 `pnpm dev`。服务只读取 `apps/server/.env`,不向上搜索根目录的 Compose `.env`;部署环境变量优先于 `.env`。应用工厂不自行监听端口,main 负责读取配置和启动,测试使用临时端口。
新环境先复制 `apps/server/.env.example` 为 `apps/server/.env`,设置 JWT_SECRET。生成随机密钥的示例命令:
```bash
node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"
```
真实密钥仅写入受控环境配置,不提交仓库。当前本机已生成独立开发密钥;测试使用测试专用密钥,生产必须另行生成。
| 配置 | 默认 / 要求 |
| ------------------------- | ----------------------------------------------------------------- |
| NODE_ENV | development;允许 development/test/production |
| HOST / PORT | 127.0.0.1 / 3000;端口须为 1~65535 整数 |
| LOG_LEVEL | info;允许 error/warn/info/debug |
| API_BODY_LIMIT_BYTES | 1048576,即 1 MiB;允许 1 KiB~10 MiB |
| SWAGGER_ENABLED | 未设置时开发/测试 true,生产 false;生产不要照搬开发示例中的 true |
| CORS_ORIGINS | 空列表;逗号分隔的完整 HTTP(S) origin,不接受 * 或路径 |
| TRUSTED_PROXY_CIDRS | 空列表;按部署显式设置代理 IP/CIDR,不使用 true 或跳数 |
| JWT_SECRET | 必填,至少 32 字节;拒绝空值、过短或 change-me 占位值 |
| JWT_ISSUER / JWT_AUDIENCE | doodle-store / doodle-mini |
| JWT_EXPIRES_IN_SECONDS | 86400,即 24 小时;允许 60~604800 秒 |
DATABASE_URL 仍保留供后续 Prisma 接入,当前 HTTP 基础层不连接数据库,也不读取七牛凭证。健康检查成功只证明 HTTP 进程可用。
## 2. 请求处理
- 全部控制器使用 `/api/v1` 前缀,公开健康检查为 `GET /api/v1/health`。
- 创建 Nest 应用时设置 `bodyParser: false`,再显式安装 JSON 和 urlencoded 解析器;共同使用字节限制,urlencoded 使用 extended=false。
- requestId 在解析请求体之前生成;符合 `[A-Za-z0-9_-]{8,128}` 的 X-Request-Id 可沿用,否则生成 req_UUID。所有响应携带 X-Request-Id。
- 请求完成记录 method、path、状态、耗时及 requestId,不记录 query、请求体、Authorization、Cookie。JSON 日志递归脱敏密码、token、微信身份及其他敏感字段。
- Helmet 安全头与隐藏 X-Powered-By。Swagger 开启时放宽文档所需 CSP;Swagger 关闭时使用默认 CSP。
- CORS 使用精确 origin 白名单,无 Cookie 凭证模式;允许 Bearer Authorization,并向浏览器暴露 X-Request-Id。无 origin 的小程序/服务端请求可用,CORS 不代替身份校验。
- DTO 使用 ValidationPipe:transform、whitelist、forbidNonWhitelisted;不隐式把数字字符串转换成数字,不在错误里返回原始对象或值。
- 错误统一为 `{code: HTTP状态码, message: 安全提示, requestId}`,保留 HTTP 状态;JSON 格式错误 400、超限 413、未登录 401、无权限 403、未预期错误 500。成功响应沿用 `{code:0,message,data}`,不重复包装健康检查。
## 3. Swagger
开发默认地址:`http://127.0.0.1:3000/api-docs`;OpenAPI JSON:`/api-docs-json`。Swagger 反映实际注册路由,不展示计划中尚未实现的业务接口。
使用 access-token Bearer JWT 安全定义,健康检查声明为公开。Swagger 不持久保存浏览器 token。生产默认关闭;如部署时显式开启,应通过部署入口限制访问。Swagger 是直接注册的文档路由,不由控制器 JWT 守卫保护。
## 4. JWT 与账户检查
`JwtTokenService` 仅供可信服务端业务签发 token,没有公开的测试登录或任意用户 token 签发接口。使用 HS256,签发 sub=userId、authVersion、iat、exp,并验证 algorithm、issuer、audience、有效期和身份字段类型。
`AccessTokenGuard` 为全局守卫,路由默认需要登录。公开接口使用 `@Public()`,业务代码用 `@CurrentUser()` 获取已核对的身份;管理接口使用 `@Roles('admin')`,角色从当前账户取得,不读取客户端或 token 自报角色。
验签后通过 ACCOUNT_READER 查询账户,要求用户存在、active、userId 一致且 authVersion 匹配。已注销、禁用或版本失效返回 401;不满足角色返回 403。数据库查询失败不降级为“JWT 有效即可通过”。
**当前 ACCOUNT_READER 是拒绝放行的接入占位实现**:有效 token 请求受保护接口时返回 503。后续 Prisma 用户模块必须替换为真实数据库读取;微信 code2Session、账户登录、注销和业务 API 尚未实现。测试中的账户读取替身和 probe 路由只在测试模块注册,不会进入正式服务。
## 5. 验证
使用 `pnpm check` 验证格式、ESLint、类型、构建与测试。集成测试覆盖健康检查、前缀、Swagger 开关与 Bearer 定义、CORS、安全头、requestId、JSON/urlencoded、超限和 DTO 校验、日志脱敏、JWT 伪造/过期/错误签名及 claims、账户禁用/缺失/版本失效、服务端角色校验和未接入账户查询时的拒绝放行。
2026-10-13:`pnpm check` 全部通过,12 项测试通过。另使用构建后的 `dist/main.js` 启动真实进程,核对服务端 `.env` 加载、健康检查 HTTP 200、OpenAPI JSON HTTP 200 和 X-Request-Id;检查进程已关闭,未修改开发数据库或云服务器。
基于 [NestJS Swagger 文档](https://docs.nestjs.com/openapi/introduction) 的运行时文档生成方式及 [ValidationPipe 文档](https://docs.nestjs.com/techniques/validation) 的 DTO 校验机制实现;依赖锁定兼容当前 NestJS 11 的具体版本。