# 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 的具体版本。