feat: 完成分类、worksheet 接口开发,资源迁移到七牛

This commit is contained in:
R524809
2026-10-16 17:32:23 +08:00
parent e6ded00a4c
commit 8827110f2f
107 changed files with 12775 additions and 125 deletions
+17 -7
View File
@@ -1,6 +1,8 @@
# Doodle Store Server 基础设置
> 更新日期:2026-10-13。已实现基础配置、日志、中间件、Swagger 与 JWT 守卫,业务登录和 Prisma 账户查询待接入。
> 更新日期:2026-10-15。已实现基础配置、日志、中间件、Swagger、微信登录、Prisma 账户查询与 JWT 守卫。
后续业务接入见 [用户鉴权与登录设计](./用户鉴权与登录设计.md);服务端登录模式和 reason 已接入,小程序恢复及 Web Cookie 会话仍是目标设计。当前接口与验证说明见 [服务端登录接入说明](./服务端登录接入说明.md)。
参考 `atlas-seller-kit/apps/api` 的应用工厂、结构化日志、requestId、请求体限制、默认鉴权与错误处理。保持本项目 NestJS 11 和 `/api/v1` 契约,不复制卖家工作台的多租户、Redis、对象存储或业务模块。
@@ -8,6 +10,8 @@
从 `doodle-store` 根目录执行 `pnpm dev`。服务只读取 `apps/server/.env`,不向上搜索根目录的 Compose `.env`;部署环境变量优先于 `.env`。应用工厂不自行监听端口,main 负责读取配置和启动,测试使用临时端口。
开发命令通过 `apps/server/scripts/dev.mjs` 启动 Nest watch,在收到实际监听成功的通知后,输出 `Swagger: <完整地址>` 并使用系统默认浏览器打开一次。热更新不重复打开;`SWAGGER_ENABLED=false` 时只提示文档已关闭。链接使用实际监听 IP/端口,通配地址转换为本机地址。通知独立于日志级别;打开浏览器失败只提示手动访问,不终止服务。`pnpm start` 保留服务端启动行为,不自动打开浏览器,`server_started` 结构化日志增加 `swagger_url`。
新环境先复制 `apps/server/.env.example` 为 `apps/server/.env`,设置 JWT_SECRET。生成随机密钥的示例命令:
```bash
@@ -19,7 +23,7 @@ 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 整数 |
| HOST / PORT | 127.0.0.1 / 8800;端口须为 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 |
@@ -28,8 +32,12 @@ node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"
| JWT_SECRET | 必填,至少 32 字节;拒绝空值、过短或 change-me 占位值 |
| JWT_ISSUER / JWT_AUDIENCE | doodle-store / doodle-mini |
| JWT_EXPIRES_IN_SECONDS | 86400,即 24 小时;允许 60~604800 秒 |
| WECHAT_MINI_APP_ID | 小程序 AppID;必填,必须与 AppSecret 成对提供 |
| WECHAT_MINI_APP_SECRET | 必填;无默认密钥,仅服务端持有 |
DATABASE_URL 仍保留供后续 Prisma 接入,当前 HTTP 基础层不连接数据库,也不读取七牛凭证。健康检查成功只证明 HTTP 进程可用。
微信配置写入 `apps/server/.env`,不写根目录 Compose `.env`。服务端通过 `ServerConfig.wechatMiniAppId/wechatMiniAppSecret` 读取;两项去除首尾空白后校验非空且不含内部空白,错误不回显实际值。登录时使用 code2Session 验证身份,启动校验不代表已验证微信凭据真实有效。AppSecret 与 JWT_SECRET 是独立密钥,不得混用、下发或输出到日志。
DATABASE_URL 现在必填,必须为 PostgreSQL URL 且使用 public schema;Prisma 单应用连接池最多 5 条连接,连接超时 2 秒、语句超时 5 秒,应用关闭时释放。GET /health 只证明 HTTP 进程可用,GET /health/ready 检查数据库连通性;七牛待接入。
## 2. 请求处理
@@ -40,11 +48,11 @@ DATABASE_URL 仍保留供后续 Prisma 接入,当前 HTTP 基础层不连接
- 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}`,不重复包装健康检查。
- 错误统一为 `{code: HTTP状态码, message: 安全提示, requestId}`,保留 HTTP 状态;JSON 格式错误 400、超限 413、未登录 401、无权限 403、未预期错误 500。可信业务错误新增有限 reason,限流错误携带 Retry-After;成功响应沿用 `{code:0,message,data}`,不重复包装健康检查。
## 3. Swagger
开发默认地址:`http://127.0.0.1:3000/api-docs`;OpenAPI JSON:`/api-docs-json`。Swagger 反映实际注册路由,不展示计划中尚未实现的业务接口。
开发默认地址:`http://127.0.0.1:8800/api-docs`;OpenAPI JSON:`/api-docs-json`。Swagger 反映实际注册路由,不展示计划中尚未实现的业务接口。
使用 access-token Bearer JWT 安全定义,健康检查声明为公开。Swagger 不持久保存浏览器 token。生产默认关闭;如部署时显式开启,应通过部署入口限制访问。Swagger 是直接注册的文档路由,不由控制器 JWT 守卫保护。
@@ -56,12 +64,14 @@ DATABASE_URL 仍保留供后续 Prisma 接入,当前 HTTP 基础层不连接
验签后通过 ACCOUNT_READER 查询账户,要求用户存在、active、userId 一致且 authVersion 匹配。已注销、禁用或版本失效返回 401;不满足角色返回 403。数据库查询失败不降级为“JWT 有效即可通过”。
**当前 ACCOUNT_READER 是拒绝放行的接入占位实现**:有效 token 请求受保护接口时返回 503。后续 Prisma 用户模块必须替换为真实数据库读取;微信 code2Session、账户登录、注销和业务 API 尚未实现。测试中的账户读取替身和 probe 路由只在测试模块注册,不会进入正式服务。
ACCOUNT_READER 现已接入真实 Prisma 查询;数据库失败返回 503/DATABASE_UNAVAILABLE,不降级放行。POST /auth/wechat/login 接入微信 code2Session、start/resume、唯一冲突处理及行锁;GET /me 返回本人摘要。资料修改、注销及其他业务 API 待实现。测试中的账户读取替身、微信 HTTP 替身和 probe 路由只在测试中使用。
## 5. 验证
使用 `pnpm check` 验证格式、ESLint、类型、构建与测试。集成测试覆盖健康检查、前缀、Swagger 开关与 Bearer 定义、CORS、安全头、requestId、JSON/urlencoded、超限和 DTO 校验、日志脱敏、JWT 伪造/过期/错误签名及 claims、账户禁用/缺失/版本失效、服务端角色校验和未接入账户查询时的拒绝放行。
使用 `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;检查进程已关闭,未修改开发数据库或云服务器。
2026-10-15:接入微信静默登录与真实账户读取后,`pnpm check` 的 20 项常规测试和独立 `pnpm test:db` 的 8 项检查通过;构建产物真实启动/数据库连接通过。详细边界与记录见 [服务端登录接入说明](./服务端登录接入说明.md)。
基于 [NestJS Swagger 文档](https://docs.nestjs.com/openapi/introduction) 的运行时文档生成方式及 [ValidationPipe 文档](https://docs.nestjs.com/techniques/validation) 的 DTO 校验机制实现;依赖锁定兼容当前 NestJS 11 的具体版本。