5.8 KiB
Context
当前项目是 Bun + TypeScript 的前后端一体化 demo:开发期由 Vite React 提供前端 HMR,Bun 提供 /api/* 和 /health;生产期先构建 Vite 静态资源,再通过 Bun file import 将资源和后端编译为单 executable。
现有能力已经通过 typecheck、单元测试和 executable smoke test 验证,但真实业务开发尚未开始。此变更聚焦平台基础设施硬化,目标是在业务 API、数据模型和前端业务页面扩展之前,先把开发联调、代码质量、格式一致性、HTTP 契约和生产验证闭环固化下来。
Goals / Non-Goals
Goals:
- 引入 ESLint 审查代码质量、React Hooks 规则和前后端边界。
- 引入 Prettier 统一代码风格,但不格式化
openspec/,避免影响 OpenSpec 文档和 tasks 一行一个任务的规则。 - 提供快速
check和完整verify两层验证命令。 - 让开发期 Vite proxy 目标端口和 Bun server 监听端口保持一致。
- 补齐 HTTP method、JSON 404/405、静态资源缓存和低风险安全头的运行时契约。
- 增强生产 executable smoke test,确保验证的是当前源码构建出的生产产物。
- 同步 README,使文档描述与脚本、构建中间产物和验证流程一致。
Non-Goals:
- 不开发 gateway checker 真实业务能力。
- 不引入数据库、持久化、认证、React Router 或 UI 组件库。
- 不新增 CI 配置;本次仅提供本地
check和verify命令,CI 接入留给后续仓库托管策略。 - 不引入 CSP;本次只加入低风险安全响应头,避免提前约束未来前端资源策略。
- 不做大规模目录重构或业务框架抽象。
Decisions
ESLint 和 Prettier 分工
ESLint 只承担质量审查和边界约束,不承担缩进、换行、引号等格式职责。Prettier 专门负责代码风格,避免 ESLint stylistic 规则和格式化器重复工作。
备选方案是只引入 ESLint 并启用 stylistic 规则,但后续维护成本更高,且容易和编辑器格式化行为冲突。另一个备选方案是只引入 Prettier,但它无法检查 React Hooks、未处理 Promise 或前端误导入后端实现等质量问题。
本次采用的最小依赖集合为 eslint、@eslint/js、typescript-eslint、eslint-plugin-react-hooks、eslint-plugin-react-refresh 和 prettier。暂不引入 eslint-config-prettier,除非实现阶段引入会与 Prettier 冲突的 ESLint preset 或 stylistic 规则。
验证命令分层
新增 check 和 verify 两层命令:
check
├─ typecheck
├─ lint
├─ format:check
└─ test
verify
├─ check
├─ build
└─ test:smoke
check 面向日常开发,反馈快;verify 面向提交前或发布前验证,包含生产构建和 executable smoke test。备选方案是只提供 verify,但每次都构建 executable 会降低日常迭代速度。
Prettier 忽略范围
Prettier SHALL 忽略 openspec/、dist/、.build/、node_modules/、bun.lock 和临时构建产物。openspec/ 排除是显式决策,因为 OpenSpec tasks 要求一行一个任务,Markdown 自动折行可能破坏审阅体验和规则遵循。
开发期端口配置
文档化的全栈开发命令以 PORT 作为后端端口的唯一对外配置。Vite proxy 使用的 BACKEND_PORT 应由开发脚本从 PORT 派生,或者明确作为内部变量,避免用户只改 BACKEND_PORT 导致 proxy 与 server 分叉。直接运行 Bun server 或生产 executable 时仍可继续使用现有 CLI 参数覆盖 host 和 port。
运行配置校验
运行配置继续保持 CLI 参数优先于环境变量,缺省时使用 README 文档化默认值。端口配置必须拒绝非整数、小于 0 或大于 65535 的值,并通过单元测试覆盖默认值、优先级、非法输入和边界值,避免开发期和生产期配置行为分叉。
HTTP method 和错误契约
现有 demo 端点按路径匹配,后续业务扩展前需要先固化 method 语义。/health 和 /api/demo 以 GET 为主,并支持 HEAD 返回相同状态和 headers 但无响应体;不支持的 method 返回 JSON 405,并带 Allow header。未知 /api/* 继续返回 JSON 404,不能落入前端 HTML fallback。
生产响应头策略
生产 HTML 使用 Cache-Control: no-cache,Vite hash 静态资源使用长缓存 public, max-age=31536000, immutable。所有生产 HTTP 响应增加低风险安全头,例如 X-Content-Type-Options: nosniff 和 Referrer-Policy。CSP 暂不纳入本次变更,避免后续业务页面接入外部资源时产生过早约束。
构建确定性
生成 .build/static-assets.ts 时,嵌入资源列表应按稳定顺序输出。这样可以减少重复构建时的无意义差异,也方便 smoke test 和后续审查定位问题。
Smoke test 增强
test:smoke SHALL 针对当前构建出的 executable 验证生产行为,包括 /health、/api/demo、未知 API、根 HTML、SPA fallback、静态资源、未知静态资源、生产 runtime mode、缓存头和低风险安全头。verify 必须先执行 build 再 smoke,避免验证旧产物。
Risks / Trade-offs
- 新增 ESLint 和 Prettier 会增加开发依赖与初次配置成本 → 采用最小依赖集合,只启用与当前项目直接相关的规则。
- 现有代码可能被 Prettier 产生格式化改动 → 本次作为平台硬化变更集中处理,后续业务变更减少格式噪音。
- 405 和 HEAD 行为会让 HTTP handler 稍复杂 → 在业务 API 扩展前处理,避免未来每个端点重复补语义。
- 安全头不包含 CSP,安全强度有限 → 先采用低风险头,CSP 在前端资源来源稳定后单独设计。
verify包含构建和 smoke,运行更慢 → 保留快速check作为日常反馈通道。