Files
laundry-desk/docs/superpowers/specs/2026-04-23-laundry-desk-design.md
manpengan 426fa54621 docs: add laundry-desk design spec (M0)
洗衣店柜台管理系统的初始设计文档。单店单机 Electron + SQLite,
Apple HIG UI,4 期交付(M1 基础 → M2 收款统计 → M3 拍照打印
→ M4 员工短信)。实现交给 Gemini,Claude 守门禁,Codex 二审。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 09:18:36 +08:00

165 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: laundry-desk 设计文档
date: 2026-04-23
status: approved (M0 — 待 Gemini 实现)
authors: claude (brainstorm), manpengan (decision)
---
# laundry-desk — 洗衣店柜台管理系统
## 1. 目标与场景
单店单机 Windows 桌面系统,覆盖洗衣店柜台全流程:收件登记 / 取件 / 客户 / 收款 / 统计 / 打印 / 短信。
- 运行Windows 10/11NSIS `.exe` 安装器)
- 开发macOS 交叉打包GitHub Actions `windows-latest` 为准)
- 数据:本地 SQLiteWAL + 每日自动备份)
**典型场景:**
- 收件:查回头客 → 录物品明细 → 计价收款 → 生成 4 位取件码 → 打印登记单
- 取件:客户报取件码 / 电话 / 单号 → 查询 → 收尾款 → 标记已取 → 打印取件条
- 管理:店主查看日/月营业额、逾期未取、回头率
## 2. 范围
**In Scopev1.0.0** 收件、取件、订单列表、客户自动去重(按电话)、按件计费、付款方式与欠款、日/月统计、逾期未取、58mm 热敏打印、物品照片、腾讯云 SMS、多员工账号 + 审计日志、Excel 导入导出、自动备份。
**Out of Scope** 多门店 / 云端同步 / 会员积分储值 / 微信小程序 / RFID / 自动称重。
## 3. 技术栈
| 层 | 选型 |
|---|---|
| 应用框架 | Electron 32+ |
| 前端 | React 19 + TypeScript 5 (strict) |
| UI | Tailwind CSS 4 + shadcn/ui |
| 动效 | Framer Motion 11 |
| 字体 | SF Pro Display/Text + PingFang SC |
| 状态 | Zustand |
| 路由 | React Router 7 |
| 数据库 | better-sqlite3 + Drizzle ORM |
| 密码哈希 | @node-rs/argon2 |
| 构建 | Vite + electron-vite |
| 打包 | electron-builderNSIS |
| 图表 | Recharts |
| 打印 | electron-pos-printer58mm ESC/POS |
| 短信 | @tencentcloud/tencentcloud-sdk-nodejs-sms |
| Excel | exceljs |
| 测试 | Vitest单测+ PlaywrightE2E |
| CI | GitHub Actions`windows-latest` 构建 + artifact |
**UI 视觉规范Apple HIG** SF Pro + PingFang SC、圆角 1216px、半透明/毛玻璃卡片、macOS System Colors`systemBlue #007AFF`、Framer Motion 过渡、深色模式跟随系统、窗口 `titleBarStyle: 'hiddenInset'`Mac 开发态)/ Windows 下降级为圆角无边框。
## 4. 数据模型SQLite + Drizzle
金额一律用**整数分**存储(杜绝浮点)。
| 表 | 关键字段 |
|---|---|
| `customers` | id, name, phone (unique), vip_level, total_orders, total_spent, created_at, updated_at |
| `orders` | id, order_no (unique, `YYYYMMDD-NNNN`), pickup_code (char(4)), customer_id (fk), status (pending/ready/picked_up/cancelled), total_amount, paid_amount, payment_method (cash/wechat/alipay/card/unpaid), receive_date, expected_pickup_date, actual_pickup_at, staff_id (fk), picked_up_by (fk nullable), notes, created_at, updated_at |
| `order_items` | id, order_id (fk cascade), item_type, service_type (wash/dry_clean/iron), quantity, unit_price, subtotal, item_notes |
| `order_photos` | id, order_id (fk cascade), file_path (相对 userData), taken_at |
| `staffs` | id, username (unique), password_hash (Argon2), display_name, role (admin/staff), is_active, created_at, last_login_at |
| `sms_log` | id, order_id (fk), phone, content, status (pending/sent/failed), provider_response (json), sent_at |
| `settings` | key (pk), value (json), updated_at |
| `audit_log` | id, staff_id (fk nullable), action (create/update/delete/pickup/cancel/login/export), entity, entity_id, diff (json), created_at |
**索引:** `orders(pickup_code)``orders(customer_id, status, receive_date)``audit_log(created_at)``customers(phone) unique``orders(order_no) unique`
**取件码策略:** 00:00 重置当日池,随机 4 位数字,事务内冲突重试 ≤ 3 次(单店同日 1 万单封顶完全够用)。
**订单号策略:** `YYYYMMDD-NNNN` 顺序号(事务内 `SELECT max(nnnn)+1`,同日 9999 封顶)。
**默认 settings keys** `shop.name``shop.address``printer.enabled``printer.width``sms.enabled``sms.tencent.secret_id``sms.tencent.secret_key`M4 加密存储)、`sms.template_id``price_templates`JSON 数组)。
**备份:** `%APPDATA%/laundry-desk/backups/` 下每日 03:00 zip `.db`,保留最新 30 份滚动删除;设置页提供"立即备份 / 从备份还原"。
## 5. 架构分层
```
src/
main/ # Node 主进程(持有 DB
db/ # Drizzle schema / migrations / backup
services/ # 业务逻辑(无 Electron 依赖,可单测)
ipc/ # IPC handlers按领域分组
window.ts
index.ts
preload/ # 桥接,暴露类型安全 window.api
renderer/ # React UI
routes/ # Home / Receive / Pickup / Orders / OrderDetail / Customers / Stats / Settings / Login
components/ui/ # shadcn/ui 定制
stores/ # Zustand
lib/api.ts # window.api 封装
styles/globals.css
shared/ # main ↔ renderer 共享类型 + Zod schema + 错误码
tests/
```
**硬约束:**
- `contextIsolation: true` / `nodeIntegration: false` / `sandbox: true` / CSP 严格
- Renderer 零 Node/DB 访问,全走 IPC
- IPC 命名 `<domain>:<action>`(如 `orders:create`);入参一律过 Zod返回 `{ ok: true, data } | { ok: false, error: { code, message } }`
- Service 层无 Electron 依赖;接受 db client 注入(测试用 in-memory SQLite
- 单文件 ≤ 400 行、函数 ≤ 50 行、嵌套 ≤ 4 层;金额零浮点;无硬编码密钥
## 6. 核心工作流
### 6.1 收件
电话查回头客 → 明细多行 → 付款方式 + 实收 → 事务生成 `pickup_code` + `order_no` → 写 `orders` + `order_items`+ 可选 `order_photos`)→ 更新 `customers.total_orders/total_spent``audit_log`M3打印登记单。
### 6.2 取件
取件码(优先)/ 电话 / 单号 / 姓名查询 → 多条时列表选 → 有欠款先收 → `status = picked_up``actual_pickup_at``picked_up_by``audit_log`M3打印取件条。
### 6.3 自动备份
`app.ready` 启动 `node-cron` 03:00 → `PRAGMA wal_checkpoint(TRUNCATE)` → 复制 `.db` → zip → 滚动保留 30 份。
### 6.4 短信通知M4
手动/批量触发 → Service 调腾讯云 SMS SDK → 写 `sms_log`pending → sent/failed→ 状态回填订单详情。
## 7. 分期路线图
| 期 | Tag | 交付 |
|---|---|---|
| **M1** | `v0.1.0` | 项目骨架 + Apple HIG 设计系统 + 收件/取件/列表/详情 + 客户自动去重 + 自动备份 + Windows NSIS 打包 |
| **M2** | `v0.2.0` | 价格模板 + 按件计费 + 折扣 + 付款/欠款 + 日/月报表Recharts+ 逾期未取 + Excel 导入导出 |
| **M3** | `v0.3.0` | 收件拍照13 张,存 `userData/photos/YYYY-MM/`+ 58mm 热敏打印登记单 / 取件条 |
| **M4** | `v0.4.0``v1.0.0` | 登录Argon2+ 权限admin/staff+ 审计日志全面绑定 + 腾讯云 SMS 可取件通知(可关闭) |
## 8. 验收门禁(每期必过)
**质量:** TS strict 零错、ESLint/Prettier 零警、文件/函数/嵌套红线、无硬编码密钥、所有 IPC 过 Zod。
**测试:** Service 单测覆盖率 ≥ 70%、Playwright E2E 覆盖本期核心路径、备份可从 zip 还原到新安装。
**交付:** GH Actions `windows-latest` 构建绿灯Windows 10/11 实机冒烟manpengan`.exe` 大小记录基线GitHub Release 附安装器 + SHA256。
**文档:** `README.md` 截图更新;`docs/CHANGELOG.md` 本期条目。
## 9. 分工
| 角色 | 职责 | 工具 |
|---|---|---|
| **Claude (Opus 4.7)** | brainstorm / spec / 门禁验收 / code review | Claude Code |
| **Codex** | 关键节点二次审查(架构 / 安全 / 并发) | Codex CLI |
| **Gemini** | M1~M4 主力实现、测试编写、修 build | Gemini CLI |
| **manpengan** | 决策 / UI 走查 / 发版 | — |
**节奏:** 每期开始 Claude 在 milestone issue 补实施细节 → Gemini 提 PR → Claude 审 → Codex 关键点复审 → Claude 过门禁清单 → manpengan tag release。
## 10. 风险与缓解
| 风险 | 缓解 |
|---|---|
| Mac 交叉打 Windows exebetter-sqlite3 native 模块失败 | GH Actions `windows-latest` 为准;本地 `pnpm rebuild`electron-builder `buildDependenciesFromSource: false` |
| 打印机型号差异 | M3 抽象 `PrinterDriver` 接口,先支持 58mm 通用 ESC/POS型号配置化 |
| 腾讯云 SMS 模板审核周期 | Provider 可替换;模板 id 从 settings 读;无短信时仍可发版 |
| SQLite 单文件损坏 | WAL + 每日 zip + 备份校验任务 |
| Electron XSS → 任意代码 | contextIsolation + sandbox + CSP + 所有 IPC 过 Zod |
| 密钥泄漏(短信 SecretKey | M4 用 OS keychain`keytar`)加密存储,非明文入库 |
## 11. 假设
单店单机;日单量 ≤ 1000员工 ≤ 10打印机 58mm ESC/POS 兼容;柜台机器可联外网(为 SMS / 备份到外部 NAS 留空间v1 不做GitHub 用户名 `manpengan`,仓库 **public**
## 12. Open Questions
无。后续变更走 `docs/adr/YYYY-MM-DD-<topic>.md`