46 lines
3.4 KiB
Markdown
46 lines
3.4 KiB
Markdown
# Tennis Book 开发约定
|
||
|
||
## 产品边界
|
||
|
||
- 本项目是桌面端网球场聚合预约工具,不在渲染层直接调用第三方微信小程序接口。
|
||
- 每个球场必须通过独立适配器接入;公共层只定义球场、日期、场地和时段等稳定概念。
|
||
- 不在公共模型中硬塞某个球场的专属字段。专属请求参数、签名、Cookie 和流程状态留在对应适配器内。
|
||
|
||
## 目录结构
|
||
|
||
- `src/main/`:Electron 主进程、第三方网络请求、凭证和适配器注册。
|
||
- `src/main/settings/`:按球场保存的本机配置与原子写入逻辑,存储位置使用 Electron `userData` 目录。
|
||
- `src/main/bookings/`:待支付锁场订单摘要与恢复逻辑;不得持久化支付签名。
|
||
- `src/main/adapters/<court-id>/`:单个球场的接口与预约流程实现。
|
||
- `src/preload/`:仅暴露经过白名单审核的类型安全 IPC。
|
||
- `src/renderer/`:React UI,不可使用 Node.js API,不可持有第三方密钥。
|
||
- `src/shared/`:主进程、预加载和渲染层共享的纯类型与消息契约。
|
||
- `docs/`:架构决策和球场接入说明。
|
||
|
||
## 命名与扩展规则
|
||
|
||
- 球场 ID 使用稳定的 `kebab-case`,适配器目录名必须与 ID 一致。
|
||
- IPC channel 使用 `domain:action`,新增 channel 时必须同时更新共享类型和 preload 白名单。
|
||
- 新球场先实现 `CourtAdapter`,再注册到适配器注册表;禁止在 React 组件里按球场 ID 写业务分支。
|
||
- 第三方接口字段 `userId` 在本项目语义中是“场地 ID”;固定场地 ID 属于球场适配器私有常量,不得通过 IPC 或配置界面暴露。
|
||
- 场地 ID 只允许在对应适配器请求边界映射到第三方 `userId` 字段和 `STOREID` 请求头。
|
||
- 下单、取消等写操作必须由对应球场适配器独立实现;公共层只编排确认、状态和恢复,不拼装球场专属请求。
|
||
- 模拟数据只允许存在于 `demo` 适配器或明确命名的 fixture 中,接入真实 API 后不得静默回退到模拟成功。
|
||
|
||
## 安全规则
|
||
|
||
- Electron 必须保持 `contextIsolation: true`、`nodeIntegration: false` 和 `sandbox: true`。
|
||
- 第三方令牌、Cookie、签名密钥不得进入渲染进程、日志或版本库。
|
||
- 第三方请求诊断日志只允许在 dev 模式输出;请求头和响应中的访客凭证、支付签名、预支付标识及个人信息必须递归脱敏。
|
||
- `PSPLVISITORID` 持久化在 Electron 主进程管理的本机配置中;设置弹窗可通过白名单 IPC 读取原值用于回填,但关闭弹窗后必须清除渲染层状态,其他业务接口不得返回原值。
|
||
- 每球场配置以 `courtId` 隔离;标识符在共享模型和持久化文件中使用字符串,实际请求前再按接口契约安全转换。
|
||
- 预约人昵称和手机号仅可按产品明确要求存在于当次时段查询的内存结果中;不得写日志、落盘、缓存或用于预约以外的用途。
|
||
- 外部链接只能通过主进程白名单打开;页面不得任意导航或创建窗口。
|
||
- 写操作前必须在主进程重新验证实时可用性和价格;UI 必须二次确认。不得用真实接口做自动化下单或取消测试。
|
||
|
||
## 完成标准
|
||
|
||
- 每次修改至少通过 `npm run typecheck`、`npm run build` 和 `git diff --check`。
|
||
- 影响交互或布局时必须做一次实际渲染检查。
|
||
- 接入真实球场时需要覆盖:正常数据、无可用时段、登录失效、限流、接口格式变化和网络失败。
|