QP Fleet Current Project State Snapshot
Last updated: 2026-05-26T22:11:02.065Z
# QP_CURRENT_STATE.md
> 生成时间:2026-05 | 面向读者:ChatGPT / Codex / Cursor / 新接手开发者
> 这是一份**真实工程现状快照**,不是理想架构文档。
---
## 1. 项目定位
QP Fleet System 是 QuickPath 内部车队运营与财务管理系统。
- 不是单一应用,是"多层协作"的运营+财务体系。
- 当前主线:**V3 财务系统收口 + V3.2 Internal Ops 只读页面**。
- Internal Ops 新增清洁记录查看:`/ops/cleaning-submissions`(只读,读取 `Cleaning_Submissions`,不写 Google Sheet)。
- 2026-05-25 支线最小收尾:A-guide 已接入 ECS 表格控制中心只读展示(含 control/show、缓存、刷新、同步、默认来源与数据来源类型),不新增写入;下一步主线回归 V3 财务收口。
- 部署地址:`http://47.77.231.107:4020`
- 服务器路径:`/opt/qp-fleet-system`
- PM2 进程名:`qp-fleet-system`(唯一允许操作的进程)
- 端口:`4020`(同机另有 Etsy Image Tool,端口 4030,**禁止误碰**)
---
## 2. 项目文件结构(真实现状)
```
/opt/qp-fleet-system/
├── server.js # 唯一入口,所有路由和页面都在这里
├── package.json # express / googleapis / xlsx / axios
├── service-account.json # Google API 鉴权(不提交)
├── cache/
│ └── finance/ # Finance cache-first 本地缓存
│ ├── A_overview.json
│ ├── A_Records.json
│ ├── A_Turo_Payouts.json
│ ├── A_management_fee_rules.json
│ ├── Guide-Owner.json
│ ├── Guide-OP-detail.json
│ ├── Finance_Summary_Master.json
│ ├── Finance_Cars_Master.json
│ ├── Finance_Reimbursement_Master.json
│ └── Finance_Batch_Overview.json
├── data/
│ └── datahub/
│ └── DataHub.xlsx # 本地中间数据文件(xlsx)
├── data/
│ └── settlements/ # 结算草稿文件(owner__month.json)
└── docs/ # 项目规则 MD 文档
├── CLAUDE.md # AI 工具入口说明(必须先读)
├── QP_CURRENT_STATUS.md
├── QP_PROJECT_OVERVIEW.md
├── QP_VERSION_TREE.md
├── QP_FINANCE_RULES.md
├── QP_DATAHUB_STRUCTURE.md
├── QP_ECS_MASTER_MIGRATION.md
├── QP_INTERNAL_OPS_PLAN.md
└── QP_SCRAPER_ARCHITECTURE.md
```
> ⚠️ `server.js` 是单体文件,所有路由、HTML 页面渲染、API、中间件都在其中。没有 React/Vue 框架,前端是 server-side rendered HTML + inline JS。
---
## 3. 技术栈
| 层级 | 技术 |
|------|------|
| 后端框架 | Express 5 (Node.js) |
| 认证 | Google Service Account (googleapis) |
| 主数据源(当前) | Google Sheet(两个 Sheet ID) |
| 中间层 | DataHub.xlsx(本地) |
| 缓存层 | `/cache/finance/*.json`(本地 JSON) |
| 前端渲染 | Server-side HTML,inline JS,无构建工具 |
| 包管理 | npm(无 lock file 限制)|
| 进程管理 | PM2 |
---
## 4. 数据源结构与三层关系
### 4.1 数据来源层级(当前真实状态)
```
[Google Sheet - 主数据源]
├── DATA_HUB_SHEET_ID = "1_e5chw2tstso6P7AFQwgHpmLtuR9HQBQXCfnPSAx0a8"
│ ├── A_overview ← 车辆/车主/平台/位置/归属关系
│ ├── A_Records ← 行程分类、费用拆解(辅助,非收入主口径)
│ ├── A_Turo_Payouts ← 正式收入口径 ✅
│ ├── A_management_fee_rules
│ ├── Guide-Owner ← 车主 PayOption / OP 规则
│ ├── Guide-OP-detail ← 各费用类型 OP1/OP2/OP3 处理规则
│ └── Guide-A ← ECS Table UI registry(ECS-Ctrl=yes 才进入)
│
└── DEFAULT_FINANCE_OUTPUT_SHEET_ID = "1eUESU1D6oj8PoXNxRgplITKZrY9xPZ-5adf2Z4kRICE"
├── Finance_Summary_Master
├── Finance_Cars_Master
├── Finance_Reimbursement_Master
└── Finance_Batch_Overview
[DataHub.xlsx - 本地中间层]
路径:/opt/qp-fleet-system/data/datahub/DataHub.xlsx
作用:接住抓取结果、缓存结果、财务中间结果,降低直接读 Sheet 耦合
读取函数:readDataHubTab(tabName)
[cache/finance/*.json - 本地 JSON 缓存]
作用:Finance API cache-first 读取,减少 Google Sheet 调用频率
刷新入口:GET /api/finance-cache-refresh
状态查询:GET /api/finance-cache-status
```
### 4.2 读取优先级(当前已确认)
```
Finance Master API:
local cache (JSON) → [fallback] Google Sheet
ECS Table UI (/ops/tables):
Google Sheet first → [fallback] DataHub.xlsx
ECS Table UI (/ops/table?tab=...):
DataHub.xlsx → [fallback] Google Sheet
原则:本地没有再 fallback;不确定来源时看 dataSourceDiagnostics 字段
```
### 4.3 Google Sheet / DataHub / ECS 三者关系
```
当前阶段:Sheet-Master + ECS Co-Pilot(副驾驶验证期)
Google Sheet ──→ [抓取/同步] ──→ DataHub.xlsx
↓
cache/finance/*.json
↓
Finance API (cache-first)
↓
/finance/* 页面(只读展示)
ECS(当前)= 读取、展示、验证
ECS(未来)= 主数据源(ECS-Master,尚未切换)
```
---
## 5. 当前主线模块(已完成 - Finance V1)
### 5.1 Finance Shell 入口
- 路由:`GET /finance`
- 左侧菜单分组(Finance / Owner / Operations / Tools)+ 可折叠
- iframe 框架,月份/车主选择器,语言切换(en/zh)
### 5.2 已完成页面(Finance V1 收口状态)
| 页面 | 路由 | 状态 |
|------|------|------|
| Dashboard | `/finance` → `dashboard` view | ✅ READY |
| Finance V1 Acceptance | `financeV1Acceptance` view | ✅ READY |
| Owner Detail | `/finance-owner-detail` | ✅ READY |
| Monthly Settlement Report | `/finance-owner-report` | ✅ READY |
| Owner Print | `/finance-owner-print` | ✅ READY |
| Expense Detail Report | `/finance-expense-report-v1` | ✅ READY |
| Payment Tracking | 内嵌 view | ✅ READY |
| Vehicle Anomalies | view | ✅ READY |
| Cache Refresh | `/finance-cache-refresh` | ✅ READY |
| Payout Debug | `/finance-payout-debug` | ✅ DEBUG工具 |
| Trip Income Debug | `/finance-trip-income-debug` | ✅ DEBUG工具 |
| Car Rule Preview | `/finance-car-trip-rule-preview` | ✅ DEBUG工具 |
### 5.3 Finance V1 线上验收状态(2026-05)
```
Owners = 5
Pay To Owners = $17,818.35
Paid/Remaining = $17,455.01 / $363.34
Henry = NEEDS_REVIEW(人工复核,不是系统错误)
Tan/Roy/Quenna/Ning W = READY
monthly-run-status: readyCount=5, missingCount=0, errorCount=0
```
---
## 6. 当前进行中模块(V3.2 Internal Ops)
### 6.1 /ops 入口
- 路由:`GET /ops`
- 内部运营后台,**不对车主开放**
- 当前全部只读,不写回 Google Sheet
### 6.2 V3.2 已落地步骤
| Step | 内容 | 状态 |
|------|------|------|
| Step2 | `/ops` 首页,模块卡片(Overview/Anomalies/Maintenance等)| ✅ |
| Step3 | Ops Overview Snapshot(复用 `/api/finance-dashboard-month`)| ✅ |
| Step4 | Vehicle Anomalies Snapshot(复用 `/api/finance-vehicles-month`)| ✅ |
| Step4 | ECS Table UI:`/ops/tables` + `/ops/table?tab=...` | ✅ |
| Step4.1 | Guide-A TabType 语义(Ctrl/Show)+ Sheet-first 策略 | ✅ |
| Step5 | 单表字段 checkbox 选择 + 搜索框 | ✅ |
| Step6 | Select All/Clear/Default10 + row limit(50/100/200/500) + sticky header | ✅ |
| Step7 | 分页 + 行顺序(Original/Reverse)+ localStorage 视图偏好 | ✅ |
| Step7.1 | 全量数据分页顺序修复(limit 语义改为 page size)| ✅ |
| Step7.2 | localStorage columns 对齐校验 + 越界修正 + Reset Saved View | ✅ |
| Step8.1 | Cleaning Upload Prototype(`/ops/cleaning-upload` + `/api/ops/cleaning-upload` 受控写入) | ✅ |
---
## 7. 核心 API 清单
### Finance 核心 API(cache-first)
```
GET /api/finance-dashboard-month?month=YYYY-MM
GET /api/finance-owner-detail?owner=...&month=...
GET /api/finance-dashboard-master?month=...
GET /api/finance-owner-master?owner=...&month=...
GET /api/finance-monthly-run-status?month=...
GET /api/finance-owner-report-v1-calc?owner=...&month=...
GET /api/finance-owner-cards?month=...
GET /api/finance-vehicles-month?month=...
GET /api/finance-home-dashboard?month=...
```
### Cache 管理 API
```
GET /api/finance-cache-refresh ← 触发缓存刷新(写 JSON 文件)
GET /api/finance-cache-status ← 查询各 tab 缓存状态
POST /api/datahub-xlsx-upload ← 上传新版 DataHub.xlsx
GET /api/datahub-xlsx-status ← 查询 DataHub.xlsx 状态
```
### Debug API
```
GET /api/finance-payout-debug?...
GET /api/finance-trip-income-debug?tripId=...
GET /api/finance-op-compare-debug?owner=...&from=OP1&to=OP3
GET /api/finance-owner-op?owner=...
GET /api/finance-car-trip-rule-preview-note?...
```
### Settlement 草稿 API
```
GET /api/finance-owner-car-settlement-preview?owner=...&month=...
POST /api/finance-settlement-draft-save
GET /api/finance-settlement-draft-load
```
---
## 8. Cache 体系
### 8.1 cache-first 读取函数(server.js 内)
```javascript
loadFinanceCache(tabName) // 读 JSON cache
readDataHubTab(tabName) // 读 DataHub.xlsx(含 fallback Google Sheet)
readSheet(sheetId, tabName) // 直接读 Google Sheet
```
### 8.2 缓存覆盖 Tab 列表
**FINANCE_CACHE_TABS**(来源:DATA_HUB_SHEET_ID)
- A_overview, A_Records, A_Turo_Payouts, A_management_fee_rules
- Guide-Owner, Guide-OP-detail(+ 其他 Guide 表)
**FINANCE_MASTER_CACHE_TABS**(来源:DEFAULT_FINANCE_OUTPUT_SHEET_ID)
- Finance_Summary_Master, Finance_Cars_Master
- Finance_Reimbursement_Master, Finance_Batch_Overview
### 8.3 兼容性注意(已知坑)
```
- cached rows 可能是二维数组或对象数组,读取层必须兼容两种格式
- ownerMonthKey 可能是 owner__month 或 owner_month,两种都要支持
- rowsToObjectList() 负责标准化处理
```
---
## 9. 财务核心规则(禁止搞错)
```
✅ A_Turo_Payouts = 正式收入口径
❌ A_Records ≠ 正式收入(只做分类/参考)
✅ 收入以 Turo payout 入账月份为准
❌ 不按 trip start/end 做入账
✅ Paid By = 谁垫付(不代表费用归属)
✅ 费用归属 = Plate / Belongs To
✅ PaytoCost = 不参与利润分成(直接返还)
✅ reimbursement = 按类型拆分(toll/EV/ticket/gas/cleaning/smoking/damage)
✅ OP1/OP2/OP3 = PayOption 计算路径
PBP-100%:管理公司拿100%,车主拿0%
PBP-30%: 管理公司拿30%,车主拿70%
✅ Payment Batch = 判断同批 payout 多条记录归属关系(不能随便改逻辑)
✅ 车主打印版 = Owner Standard(不展示内部 debug 字段)
```
---
## 10. ECS 迁移路线(当前阶段)
```
当前:Sheet-Master + ECS Co-Pilot(只读验证)
迁移路线(已确认,不可跳步):
Google Sheet → ECS Table UI → ECS-Master → 后期数据库化
当前说明:Google Sheet 当前仍是主数据源;ECS 当前是副驾驶(展示、读取、测试、验证、逐步承接);ECS-Master 是未来单独大版本,不是当前 V3.2 目标;当前只预留 record_id、updated_at、sync_version、操作日志、冲突检测等未来能力;当前不新增写 Google Sheet,除非用户明确确认。
当前已完成:ECS Table UI(/ops/tables + /ops/table)只读展示
当前下一步:继续完善 ECS Table UI / Internal Ops 只读与验证能力。当前仍是 Sheet-Master + ECS Co-Pilot 副驾驶验证期,不进入 ECS-Master 正式切换。
强制规则:
- 每次只迁移一个模块
- 每个模块:先只读 → 再编辑 → 再主数据源切换
- 不允许直接废掉 Google Sheet 逻辑
```
---
## 11. 当前风险点
| 风险 | 说明 | 严重度 |
|------|------|--------|
| server.js 单体过大 | 所有逻辑在一个文件,维护难度高 | 中(已知,暂不重构)|
| cache 时效性 | cache 未自动定时刷新,依赖手动触发 | 中 |
| 二维数组兼容 | cached rows 格式不一致,需要 rowsToObjectList 适配 | 中 |
| ownerMonthKey 双格式 | owner__month vs owner_month 需要双向兼容 | 低-中 |
| Henry NEEDS_REVIEW | 人工复核状态,非系统错误,但需定期清理 | 低 |
| ECS-Master 未切换 | Google Sheet 仍是主数据源,Sheet 故障会影响数据刷新 | 中 |
| PM2 同机多进程 | 同机运行 Etsy Image Tool,误操作 restart all 会影响生产 | 高 |
| A_Records 误用风险 | 如果不熟悉规则,容易把 A_Records 当收入主口径 | 高 |
---
## 12. 当前下一步重点
### 近期(当前进行)
- V3.2 继续推进:`/ops` 模块从只读展示向 Maintenance/Repair/Clean/Task 扩展
- Finance V1 收口稳定观察期
### 中期(计划中)
- 当前下一步:继续完善 ECS Table UI / Internal Ops 只读与验证能力。当前仍是 Sheet-Master + ECS Co-Pilot 副驾驶验证期,不进入 ECS-Master 正式切换。
- Scraper 统一框架(当前 Turo 优先稳定)
- Owner Portal 正式化
- Checkout 后续完善
### 暂停中(不做)
- 大型重构
- 数据库化重写
- 新增写 Google Sheet 行为(需明确确认才能做)
---
## 13. 开发规则速查(AI 工具必读)
```
禁止事项:
❌ 直接修改 main 分支
❌ 直接操作 ECS 生产数据
❌ pm2 restart all / pm2 delete all
❌ 影响 BookCars / Etsy Image Tool(端口 4030)
❌ 新增写 Google Sheet(未经确认)
❌ 修改 OP1/OP2/OP3/PayOption/Payment Batch 计算逻辑
❌ 用 A_Records 替代 A_Turo_Payouts 做收入来源
❌ 把 Paid By 当费用归属
❌ 把 PaytoCost 纳入利润分成
每次改动必须说明:
✅ 改哪些文件
✅ 改哪些函数或路由
✅ 是否影响 API
✅ 是否影响 OP 财务规则
✅ 是否写 Google Sheet
✅ 是否影响 BookCars / Etsy Tool
```
---
## 14. 上下文缺失说明
以下内容从项目知识库中**无法完整确认**,需要人工补充:
1. **server.js 完整路由列表**:文件过大,只能读到片段,无法枚举所有路由
2. **FINANCE_CACHE_TABS 完整列表**:仅确认了部分 tab 名称,完整列表未完全可见
3. **Guide-A 当前收录的 Tab 列表**:ECS-Ctrl=yes 的表有哪些,未完全确认
4. **Settlement 草稿的完整状态机**:draft save/load/confirm 流程边界未完全可见
5. **Scraper 当前实际运行状态**:本地 Data Collector Machine 的实际抓取频率未知
6. **OP 公式具体数值**:管理费比例、停车费规则的具体数值未在文档中完整列出
7. **Owner 列表**:文档提到 Henry/Tan/Roy/Quenna/Ning W,是否有其他 owner 未确认
8. **BookCars 系统**:提到"不影响 BookCars"但无 BookCars 相关文档,边界不清楚
---
*本文档由 Claude 根据 QP Fleet 项目知识库自动生成。如有出入,以实际代码和 docs/ 目录下 MD 文档为准。*
# QP_CURRENT_STATE.md
> 生成时间:2026-05 | 面向读者:ChatGPT / Codex / Cursor / 新接手开发者
> 这是一份**真实工程现状快照**,不是理想架构文档。
---
## 1. 项目定位
QP Fleet System 是 QuickPath 内部车队运营与财务管理系统。
- 不是单一应用,是"多层协作"的运营+财务体系。
- 当前主线:**V3 财务系统收口 + V3.2 Internal Ops 只读页面**。
- 部署地址:`http://47.77.231.107:4020`
- 服务器路径:`/opt/qp-fleet-system`
- PM2 进程名:`qp-fleet-system`(唯一允许操作的进程)
- 端口:`4020`(同机另有 Etsy Image Tool,端口 4030,**禁止误碰**)
---
## 2. 项目文件结构(真实现状)
```
/opt/qp-fleet-system/
├── server.js # 唯一入口,所有路由和页面都在这里
├── package.json # express / googleapis / xlsx / axios
├── service-account.json # Google API 鉴权(不提交)
├── cache/
│ └── finance/ # Finance cache-first 本地缓存
│ ├── A_overview.json
│ ├── A_Records.json
│ ├── A_Turo_Payouts.json
│ ├── A_management_fee_rules.json
│ ├── Guide-Owner.json
│ ├── Guide-OP-detail.json
│ ├── Finance_Summary_Master.json
│ ├── Finance_Cars_Master.json
│ ├── Finance_Reimbursement_Master.json
│ └── Finance_Batch_Overview.json
├── data/
│ └── datahub/
│ └── DataHub.xlsx # 本地中间数据文件(xlsx)
├── data/
│ └── settlements/ # 结算草稿文件(owner__month.json)
└── docs/ # 项目规则 MD 文档
├── CLAUDE.md # AI 工具入口说明(必须先读)
├── QP_CURRENT_STATUS.md
├── QP_PROJECT_OVERVIEW.md
├── QP_VERSION_TREE.md
├── QP_FINANCE_RULES.md
├── QP_DATAHUB_STRUCTURE.md
├── QP_ECS_MASTER_MIGRATION.md
├── QP_INTERNAL_OPS_PLAN.md
└── QP_SCRAPER_ARCHITECTURE.md
```
> ⚠️ `server.js` 是单体文件,所有路由、HTML 页面渲染、API、中间件都在其中。没有 React/Vue 框架,前端是 server-side rendered HTML + inline JS。
---
## 3. 技术栈
| 层级 | 技术 |
|------|------|
| 后端框架 | Express 5 (Node.js) |
| 认证 | Google Service Account (googleapis) |
| 主数据源(当前) | Google Sheet(两个 Sheet ID) |
| 中间层 | DataHub.xlsx(本地) |
| 缓存层 | `/cache/finance/*.json`(本地 JSON) |
| 前端渲染 | Server-side HTML,inline JS,无构建工具 |
| 包管理 | npm(无 lock file 限制)|
| 进程管理 | PM2 |
---
## 4. 数据源结构与三层关系
### 4.1 数据来源层级(当前真实状态)
```
[Google Sheet - 主数据源]
├── DATA_HUB_SHEET_ID = "1_e5chw2tstso6P7AFQwgHpmLtuR9HQBQXCfnPSAx0a8"
│ ├── A_overview ← 车辆/车主/平台/位置/归属关系
│ ├── A_Records ← 行程分类、费用拆解(辅助,非收入主口径)
│ ├── A_Turo_Payouts ← 正式收入口径 ✅
│ ├── A_management_fee_rules
│ ├── Guide-Owner ← 车主 PayOption / OP 规则
│ ├── Guide-OP-detail ← 各费用类型 OP1/OP2/OP3 处理规则
│ └── Guide-A ← ECS Table UI registry(ECS-Ctrl=yes 才进入)
│
└── DEFAULT_FINANCE_OUTPUT_SHEET_ID = "1eUESU1D6oj8PoXNxRgplITKZrY9xPZ-5adf2Z4kRICE"
├── Finance_Summary_Master
├── Finance_Cars_Master
├── Finance_Reimbursement_Master
└── Finance_Batch_Overview
[DataHub.xlsx - 本地中间层]
路径:/opt/qp-fleet-system/data/datahub/DataHub.xlsx
作用:接住抓取结果、缓存结果、财务中间结果,降低直接读 Sheet 耦合
读取函数:readDataHubTab(tabName)
[cache/finance/*.json - 本地 JSON 缓存]
作用:Finance API cache-first 读取,减少 Google Sheet 调用频率
刷新入口:GET /api/finance-cache-refresh
状态查询:GET /api/finance-cache-status
```
### 4.2 读取优先级(当前已确认)
```
Finance Master API:
local cache (JSON) → [fallback] Google Sheet
ECS Table UI (/ops/tables):
Google Sheet first → [fallback] DataHub.xlsx
ECS Table UI (/ops/table?tab=...):
DataHub.xlsx → [fallback] Google Sheet
原则:本地没有再 fallback;不确定来源时看 dataSourceDiagnostics 字段
```
### 4.3 Google Sheet / DataHub / ECS 三者关系
```
当前阶段:Sheet-Master + ECS Co-Pilot(副驾驶验证期)
Google Sheet ──→ [抓取/同步] ──→ DataHub.xlsx
↓
cache/finance/*.json
↓
Finance API (cache-first)
↓
/finance/* 页面(只读展示)
ECS(当前)= 读取、展示、验证
ECS(未来)= 主数据源(ECS-Master,尚未切换)
```
---
## 5. 当前主线模块(已完成 - Finance V1)
### 5.1 Finance Shell 入口
- 路由:`GET /finance`
- 左侧菜单分组(Finance / Owner / Operations / Tools)+ 可折叠
- iframe 框架,月份/车主选择器,语言切换(en/zh)
### 5.2 已完成页面(Finance V1 收口状态)
| 页面 | 路由 | 状态 |
|------|------|------|
| Dashboard | `/finance` → `dashboard` view | ✅ READY |
| Finance V1 Acceptance | `financeV1Acceptance` view | ✅ READY |
| Owner Detail | `/finance-owner-detail` | ✅ READY |
| Monthly Settlement Report | `/finance-owner-report` | ✅ READY |
| Owner Print | `/finance-owner-print` | ✅ READY |
| Expense Detail Report | `/finance-expense-report-v1` | ✅ READY |
| Payment Tracking | 内嵌 view | ✅ READY |
| Vehicle Anomalies | view | ✅ READY |
| Cache Refresh | `/finance-cache-refresh` | ✅ READY |
| Payout Debug | `/finance-payout-debug` | ✅ DEBUG工具 |
| Trip Income Debug | `/finance-trip-income-debug` | ✅ DEBUG工具 |
| Car Rule Preview | `/finance-car-trip-rule-preview` | ✅ DEBUG工具 |
### 5.3 Finance V1 线上验收状态(2026-05)
```
Owners = 5
Pay To Owners = $17,818.35
Paid/Remaining = $17,455.01 / $363.34
Henry = NEEDS_REVIEW(人工复核,不是系统错误)
Tan/Roy/Quenna/Ning W = READY
monthly-run-status: readyCount=5, missingCount=0, errorCount=0
```
---
## 6. 当前进行中模块(V3.2 Internal Ops)
### 6.1 /ops 入口
- 路由:`GET /ops`
- 内部运营后台,**不对车主开放**
- 当前全部只读,不写回 Google Sheet
### 6.2 V3.2 已落地步骤
| Step | 内容 | 状态 |
|------|------|------|
| Step2 | `/ops` 首页,模块卡片(Overview/Anomalies/Maintenance等)| ✅ |
| Step3 | Ops Overview Snapshot(复用 `/api/finance-dashboard-month`)| ✅ |
| Step4 | Vehicle Anomalies Snapshot(复用 `/api/finance-vehicles-month`)| ✅ |
| Step4 | ECS Table UI:`/ops/tables` + `/ops/table?tab=...` | ✅ |
| Step4.1 | Guide-A TabType 语义(Ctrl/Show)+ Sheet-first 策略 | ✅ |
| Step5 | 单表字段 checkbox 选择 + 搜索框 | ✅ |
| Step6 | Select All/Clear/Default10 + row limit(50/100/200/500) + sticky header | ✅ |
| Step7 | 分页 + 行顺序(Original/Reverse)+ localStorage 视图偏好 | ✅ |
| Step7.1 | 全量数据分页顺序修复(limit 语义改为 page size)| ✅ |
| Step7.2 | localStorage columns 对齐校验 + 越界修正 + Reset Saved View | ✅ |
---
## 7. 核心 API 清单
### Finance 核心 API(cache-first)
```
GET /api/finance-dashboard-month?month=YYYY-MM
GET /api/finance-owner-detail?owner=...&month=...
GET /api/finance-dashboard-master?month=...
GET /api/finance-owner-master?owner=...&month=...
GET /api/finance-monthly-run-status?month=...
GET /api/finance-owner-report-v1-calc?owner=...&month=...
GET /api/finance-owner-cards?month=...
GET /api/finance-vehicles-month?month=...
GET /api/finance-home-dashboard?month=...
```
### Cache 管理 API
```
GET /api/finance-cache-refresh ← 触发缓存刷新(写 JSON 文件)
GET /api/finance-cache-status ← 查询各 tab 缓存状态
POST /api/datahub-xlsx-upload ← 上传新版 DataHub.xlsx
GET /api/datahub-xlsx-status ← 查询 DataHub.xlsx 状态
```
### Debug API
```
GET /api/finance-payout-debug?...
GET /api/finance-trip-income-debug?tripId=...
GET /api/finance-op-compare-debug?owner=...&from=OP1&to=OP3
GET /api/finance-owner-op?owner=...
GET /api/finance-car-trip-rule-preview-note?...
```
### Settlement 草稿 API
```
GET /api/finance-owner-car-settlement-preview?owner=...&month=...
POST /api/finance-settlement-draft-save
GET /api/finance-settlement-draft-load
```
---
## 8. Cache 体系
### 8.1 cache-first 读取函数(server.js 内)
```javascript
loadFinanceCache(tabName) // 读 JSON cache
readDataHubTab(tabName) // 读 DataHub.xlsx(含 fallback Google Sheet)
readSheet(sheetId, tabName) // 直接读 Google Sheet
```
### 8.2 缓存覆盖 Tab 列表
**FINANCE_CACHE_TABS**(来源:DATA_HUB_SHEET_ID)
- A_overview, A_Records, A_Turo_Payouts, A_management_fee_rules
- Guide-Owner, Guide-OP-detail(+ 其他 Guide 表)
**FINANCE_MASTER_CACHE_TABS**(来源:DEFAULT_FINANCE_OUTPUT_SHEET_ID)
- Finance_Summary_Master, Finance_Cars_Master
- Finance_Reimbursement_Master, Finance_Batch_Overview
### 8.3 兼容性注意(已知坑)
```
- cached rows 可能是二维数组或对象数组,读取层必须兼容两种格式
- ownerMonthKey 可能是 owner__month 或 owner_month,两种都要支持
- rowsToObjectList() 负责标准化处理
```
---
## 9. 财务核心规则(禁止搞错)
```
✅ A_Turo_Payouts = 正式收入口径
❌ A_Records ≠ 正式收入(只做分类/参考)
✅ 收入以 Turo payout 入账月份为准
❌ 不按 trip start/end 做入账
✅ Paid By = 谁垫付(不代表费用归属)
✅ 费用归属 = Plate / Belongs To
✅ PaytoCost = 不参与利润分成(直接返还)
✅ reimbursement = 按类型拆分(toll/EV/ticket/gas/cleaning/smoking/damage)
✅ OP1/OP2/OP3 = PayOption 计算路径
PBP-100%:管理公司拿100%,车主拿0%
PBP-30%: 管理公司拿30%,车主拿70%
✅ Payment Batch = 判断同批 payout 多条记录归属关系(不能随便改逻辑)
✅ 车主打印版 = Owner Standard(不展示内部 debug 字段)
```
---
## 10. ECS 迁移路线(当前阶段)
```
当前:Sheet-Master + ECS Co-Pilot(只读验证)
迁移路线(已确认,不可跳步):
Google Sheet → ECS Table UI → ECS-Master → 后期数据库化
当前说明:Google Sheet 当前仍是主数据源;ECS 当前是副驾驶(展示、读取、测试、验证、逐步承接);ECS-Master 是未来单独大版本,不是当前 V3.2 目标;当前只预留 record_id、updated_at、sync_version、操作日志、冲突检测等未来能力;当前不新增写 Google Sheet,除非用户明确确认。
当前已完成:ECS Table UI(/ops/tables + /ops/table)只读展示
当前下一步:继续完善 ECS Table UI / Internal Ops 只读与验证能力。当前仍是 Sheet-Master + ECS Co-Pilot 副驾驶验证期,不进入 ECS-Master 正式切换。
强制规则:
- 每次只迁移一个模块
- 每个模块:先只读 → 再编辑 → 再主数据源切换
- 不允许直接废掉 Google Sheet 逻辑
```
---
## 11. 当前风险点
| 风险 | 说明 | 严重度 |
|------|------|--------|
| server.js 单体过大 | 所有逻辑在一个文件,维护难度高 | 中(已知,暂不重构)|
| cache 时效性 | cache 未自动定时刷新,依赖手动触发 | 中 |
| 二维数组兼容 | cached rows 格式不一致,需要 rowsToObjectList 适配 | 中 |
| ownerMonthKey 双格式 | owner__month vs owner_month 需要双向兼容 | 低-中 |
| Henry NEEDS_REVIEW | 人工复核状态,非系统错误,但需定期清理 | 低 |
| ECS-Master 未切换 | Google Sheet 仍是主数据源,Sheet 故障会影响数据刷新 | 中 |
| PM2 同机多进程 | 同机运行 Etsy Image Tool,误操作 restart all 会影响生产 | 高 |
| A_Records 误用风险 | 如果不熟悉规则,容易把 A_Records 当收入主口径 | 高 |
---
## 12. 当前下一步重点
### 近期(当前进行)
- V3.2 继续推进:`/ops` 模块从只读展示向 Maintenance/Repair/Clean/Task 扩展
- Finance V1 收口稳定观察期
### 中期(计划中)
- 当前下一步:继续完善 ECS Table UI / Internal Ops 只读与验证能力。当前仍是 Sheet-Master + ECS Co-Pilot 副驾驶验证期,不进入 ECS-Master 正式切换。
- Scraper 统一框架(当前 Turo 优先稳定)
- Owner Portal 正式化
- Checkout 后续完善
### 暂停中(不做)
- 大型重构
- 数据库化重写
- 新增写 Google Sheet 行为(需明确确认才能做)
---
## 13. 开发规则速查(AI 工具必读)
```
禁止事项:
❌ 直接修改 main 分支
❌ 直接操作 ECS 生产数据
❌ pm2 restart all / pm2 delete all
❌ 影响 BookCars / Etsy Image Tool(端口 4030)
❌ 新增写 Google Sheet(未经确认)
❌ 修改 OP1/OP2/OP3/PayOption/Payment Batch 计算逻辑
❌ 用 A_Records 替代 A_Turo_Payouts 做收入来源
❌ 把 Paid By 当费用归属
❌ 把 PaytoCost 纳入利润分成
每次改动必须说明:
✅ 改哪些文件
✅ 改哪些函数或路由
✅ 是否影响 API
✅ 是否影响 OP 财务规则
✅ 是否写 Google Sheet
✅ 是否影响 BookCars / Etsy Tool
```
---
## 14. 上下文缺失说明
以下内容从项目知识库中**无法完整确认**,需要人工补充:
1. **server.js 完整路由列表**:文件过大,只能读到片段,无法枚举所有路由
2. **FINANCE_CACHE_TABS 完整列表**:仅确认了部分 tab 名称,完整列表未完全可见
3. **Guide-A 当前收录的 Tab 列表**:ECS-Ctrl=yes 的表有哪些,未完全确认
4. **Settlement 草稿的完整状态机**:draft save/load/confirm 流程边界未完全可见
5. **Scraper 当前实际运行状态**:本地 Data Collector Machine 的实际抓取频率未知
6. **OP 公式具体数值**:管理费比例、停车费规则的具体数值未在文档中完整列出
7. **Owner 列表**:文档提到 Henry/Tan/Roy/Quenna/Ning W,是否有其他 owner 未确认
8. **BookCars 系统**:提到"不影响 BookCars"但无 BookCars 相关文档,边界不清楚
---
*本文档由 Claude 根据 QP Fleet 项目知识库自动生成。如有出入,以实际代码和 docs/ 目录下 MD 文档为准。*
- V3.2 Step8.3: Upgraded `/ops/cleaning-upload` to Fleet Ops Quick Entry Cleaning flow with plate search, lock/unlock, upload overlay, front-end compression, wake lock, and resumable upload prompts (overwrite/append).
- Added cleaning APIs: search-plates, init, upload-photo, finalize, log-error; writes to Cleaning_Submissions, VIN8 tab, clean tab (YES only), System_Log/System_Error.
- 2026-05-24:完成 V3.2 Step8.5,仅增强 `/ops/cleaning-today` 只读看板入口与筛选:新增顶部 Back/ViewAll/Refresh、新增 `plate/ctxLot/canDispatch/ctxWho` 筛选、保留 `?date=YYYY-MM-DD`,并增加空状态与只读声明;未改上传链路、Drive 层级、Finance/OP、Etsy/4030。
- 2026-05-24:A档快速PR完成 `/ops/cleaning-upload` 中文文案优化与员工可读性提升:页面标题、字段名、按钮文案改为中文优先;`Checkout` 调整为 `还车检查(暂未开放)`;`状态更新` 调整为 `车辆状态更新(暂未开放)`;保留既有三个入口与 Cleaning 上传主流程;未改任何 API、上传逻辑、Drive 层级及 Finance/OP/Etsy/BookCars。
- 2026-05-24:A档快速PR收口验收增强:`/ops/cleaning-upload` 顶部新增“当前仅开放:清洁完成上传;还车检查和车辆状态更新暂未开放。”提示,上传成功卡片按钮优化为“继续上传下一辆 / 查看今日清洁看板 / 查看该车记录”;`/ops/cleaning-today` 与 `/ops/cleaning-submissions` 改为中文优先文案(标题、筛选项、按钮、状态与空状态),未改筛选逻辑、读取逻辑、软删除逻辑,Cleaning 主流程进入收口验收阶段。
- 2026-05-24:A档快速PR修复 Cleaning 记录页批量隐藏交互:`/ops/cleaning-submissions` 与 `/ops/cleaning-today` 的“一键隐藏当前无效记录”改为收集当前页全部可标记删除项并逐条调用 `POST /api/ops/cleaning-submissions/mark-deleted`;无候选时提示“当前没有可隐藏的无效记录。”;批量完成提示成功/失败数量,并在完成后自动刷新当前筛选结果;未改上传逻辑、Drive删除、Sheet物理删除、Finance/OP/Etsy/BookCars。
- 2026-05-24:A档快速PR(验收收口文案与默认显示优化)完成:`/ops/cleaning-upload` 上传成功卡片新增验收提示“上传成功后,请到“今日清洁看板”确认记录是否有效。测试记录可在“清洁记录列表”中隐藏。”;`/ops/cleaning-today` 与 `/ops/cleaning-submissions` 按钮文案统一为“一键隐藏测试/失效记录”,并将状态说明改为“有效 = 文件夹还在;文件夹不存在/无链接 = 测试或失效记录;已删除 = 已隐藏记录。”;默认仍只显示有效记录(不显示 Deleted=YES 与无效记录);未改上传逻辑、Drive 层级、Google Sheet 写入逻辑及 Finance/OP/Etsy/BookCars。
- 2026-05-24:B档功能PR新增 `/ops/status-update` 草稿页与配套 API:新增 `GET /ops/status-update`、`GET /api/ops/status-update/search-plates`、`POST /api/ops/status-update/submit-draft`;页面支持车牌尾号搜索与锁车(数据源优先 `A_overview` / 本地 DataHub overview),提交只写入 `Status_Update_Drafts`(字段:submittedAt/plate/vinLast8/owner/oldStatus/newStatus/submittedBy/note/sourcePage/rawPayload),明确提示“当前为状态更新草稿,不会改变真实车辆状态”;未改 Finance API/OP公式、Cleaning上传逻辑、Drive层级、Etsy/4030/BookCars。
- 2026-05-25:V3.1 Step5F-0 开始,新增 `GET /finance-owner-legacy-report-v1` 旧报表数据结构复刻页(四模块:结算汇总 / 收益明细 / 报销费用明细 / 花销费用明细),参数支持 `month` + `owner`,优先复用 `finance-owner-detail`、`finance-owner-report-v1-calc`、`finance-expense-flow-debug` 现有读取结果;缺失字段统一前端显示“暂无数据 / 缺少字段”,不报错。未改 Finance 公式、未写 Google Sheet、未影响 OP / Cleaning / Etsy / BookCars。
- 2026-05-25:C档前置最小修复仅针对 Dashboard UI/状态读取层:修复 `/finance-dashboard` 月份默认来源(优先 URL `?month=YYYY-MM`,无则当前月/既有默认),并确保页面 `monthInput` 与实际请求 `/api/finance-dashboard-month` 的 month 一致;顶部新增只读口径提示(当前加载月份、Finance Master cache-first + Google Sheet fallback、Owner 搜索仅列表筛选不触发重算);`/finance` 外壳在 dashboard 视图下禁用 Owner 输入并提示“Dashboard 为全车主汇总,Owner 只用于 Owner 页面”;“Recalculate This Month”降权为“管理员重算(会写入 Sheet,耗时较久)”并新增明确确认弹窗。未改财务公式、未改 OP 规则、未改 `/api/finance-step6`、未改 `/api/finance-batch-monthly` 计算逻辑、未新增 Google Sheet 写入、未改 Cleaning/Etsy/BookCars。
- 2026-05-25:C档核心工程前置诊断新增只读页面与只读 API:新增 `GET /finance-dashboard-debug` 与 `GET /api/finance-dashboard-debug`,用于定位 Dashboard 在 `month=2026-03` 时 Owners/PayToOwners 为 0 的缺失层级(cache、Google Sheet fallback、OwnerMonthKey、月份格式)。诊断输出覆盖 `Finance_Summary_Master` / `Finance_Cars_Master` / `Finance_Reimbursement_Master` / `Finance_Batch_Overview` 四表的来源、总行数、月匹配行、样例 key、列名、cache 状态与 sheet fallback 状态,并给出下一步建议。明确只读:不写 Google Sheet、不触发重算、不改公式。未改 `/api/finance-step6`、未改 `/api/finance-batch-monthly`、未改 OP 规则、未改 Cleaning/Etsy/BookCars。
- 2026-05-25:V3.1 Step5F-1 最小修复完成,目标为 2026-03 Finance Master 结果层与 cache 链路(不改财务公式/OP 规则)。`/api/finance-batch-monthly` 新增批量完成后自动刷新 Finance Master 本地缓存(默认开启,可用 `refreshCache=0` 关闭),并在响应返回 `cacheRefreshed/cacheRefreshResults`;同时 `/api/finance-cache-refresh` 支持 `outputSheetId` 参数,刷新 Master cache 时按目标输出表读取,不再固定默认表。本次修复涉及 2026-03 月份生成链路与缓存一致性:Google Sheet 写入保持原有四张 Master 表写入逻辑;cache 刷新改为明确执行;未改 OP 公式、未改 Guide-OP-detail 规则、未改 A_Records/A_Turo_Payouts 口径、未改 Cleaning/Etsy/BookCars。
- 2026-05-25:V3.1 Step5F-2 完成,旧版车主月报复刻页 `/finance-owner-legacy-report-v1` 四模块切换为真实数据口径:结算汇总与收益明细优先读取 `Finance_Summary_Master`/`Finance_Cars_Master`(通过 `/api/finance-owner-detail` cache-first 链路);报销费用明细优先读取 `Finance_Reimbursement_Master`(按 PaidBy 归集展示);花销费用明细读取 `A_Flow` 调试口径(按 owner/BelongsTo/Plate 归集展示),并明确与报销分离。缺字段统一显示“缺少字段/暂无数据”且页面不报错。未改 Finance 公式、未写 Google Sheet、未影响 OP / Dashboard / Cleaning / Etsy / BookCars。
- 2026-05-25:V3.1 Step5F-3 最小字段对齐修复:`/finance-owner-legacy-report-v1` 修正 month 提示逻辑(仅非法 `YYYY-MM` 才提示)、花销费用日期展示统一为 `YYYY-MM-DD`(仅前端显示格式化,不改原数据)、花销“费用类型/备注”增加多字段兼容(`feeType/Fee Type/费用类型/category/Type/备注说明/Note`),收益明细增加车辆字段别名兼容读取(出租率/出租天数/出租次数/均价尝试 `UtilizationRate/RentalDays|RentalDayCount/TripCount|RentalCount/AvgDailyRate|AveragePrice` 及中文别名)。未改 Finance 公式、未改 OP 规则、未改 `/api/finance-step6`、未改 `/api/finance-batch-monthly`、未新增 Google Sheet 写入。
- 2026-05-25:V3.1 Step5F-4 A档快速 PR 完成:`/finance-owner-legacy-report-v1` 仅展示层优化,新增顶部数据来源轻提示;结算汇总按“收入类/扣费类/返还报销类/最终结果”分组并高亮“最终应付车主”;收益明细为出租率/出租天数/出租次数/均价缺失值改为“待接月度统计”,并新增“运营字段待接 A_Records 月度统计”说明;报销费用明细与花销费用明细各自补充口径说明文案。未改 Finance 公式、未改 OP 规则、未改 `/api/finance-step6`、未改 `/api/finance-batch-monthly`、未涉及 Google Sheet 写入。
- 2026-05-25:V3.1 Step5F-5 A档快速 PR 完成:修复 `/finance-owner-legacy-report-v1` 结算汇总中“最终应付车主 Final Net To Owner”标签被当作 `<span ...>` 文本显示的问题,改为正常中英文字段名展示并保留最终金额绿色高亮;同时在 Finance 入口页新增“旧版车主月报预览”快捷入口(`/finance-owner-legacy-report-v1`),方便日常验收进入旧版预览。未改 Finance 公式、未写 Google Sheet、未影响 OP/Cleaning/Etsy/BookCars,未改 `/api/finance-step6` 与 `/api/finance-batch-monthly`。
- 2026-05-25:V3.1 Step5F-6 完成,旧版车主月报 `/finance-owner-legacy-report-v1` 收益明细补齐运营统计字段(出租率/出租天数/出租次数/均价):优先读取 `Finance_Cars_Master` 既有字段,缺失时通过新增只读接口 `GET /api/finance-owner-legacy-monthly-stats` 按 `owner+month+plate` 从 `A_Records` 当月行程补算(tripCount、rentalDays、utilizationRate、avgDailyRate,均价基于 `Finance_Cars_Master.rentalBaseIncome / rentalDays`);无行程显示“0/暂无行程”,不再大面积显示“待接月度统计”。本次仅展示层与只读读取增强,未改 Finance 公式、未改 OP、未改 `/api/finance-step6`、未改 `/api/finance-batch-monthly`、未写 Google Sheet。
- 2026-05-25:V3.1 Step5F-7 完成,旧版车主月报 `/finance-owner-legacy-report-v1` 修正口径:报销费用明细由“汇总”改为“A_Flow 明细行”并按 `PaidBy=owner` 过滤(不再按 Belongs To 判定报销);花销费用明细继续按 Belongs To 归属口径展示并保留说明;收益明细“车型”改为读取 overview/Finance Master 车型字段,不再固定平台字样;出租率/出租天数/出租次数/均价继续走 `A_Records` 只读补算链路并按跨月重叠天数计算。未改公式、未写 Sheet、未影响 OP/Dashboard/Cleaning/Etsy/BookCars,未改 `/api/finance-step6` 与 `/api/finance-batch-monthly`。
- 2026-05-25:V3.1 Step5F-8 完成,`/finance-owner-legacy-report-v1` 报销费用明细改为专用 PaidBy 口径读取:扩展 `/api/finance-expense-flow-debug` 只读参数 `mode`(`paidBy` / `belongsTo` / `ownerAny`)与 `paidByOwner`,页面改为双通道读取(报销明细仅 `mode=paidBy&paidByOwner=owner`;花销明细继续 `mode=belongsTo`)。报销列表保留展示 Belongs To 字段但不参与筛选。未改 Finance 公式、未改 OP、未改 `/api/finance-step6`、未改 `/api/finance-batch-monthly`、未写 Google Sheet、未影响 Dashboard/Cleaning/Etsy/BookCars。
- 2026-05-25:V3.1 Step5F-10 完成,新增 `GET /finance-owner-legacy-report-v2` 纯后端渲染版本,保留旧页 `/finance-owner-legacy-report-v1` 不改动;V2 支持 `month=YYYY-MM&owner=车主名`,四模块(结算汇总/收益明细/报销费用明细/花销费用明细)均由服务端渲染输出,避免 inline JS 拼接语法风险。数据口径保持现有规则:结算汇总与收益明细读取 `finance-owner-detail`(`Finance Master / owner detail`)并继续只读接入 `A_Records` 运营补算;报销费用明细读取 `A_Flow` 且仅按 `PaidBy=owner` 过滤(不按 `Belongs To` 限制);花销费用明细读取 `A_Flow` 且按 `Belongs To=owner`。同时在 Finance 入口新增“旧版车主月报 V2”按钮。未改 Finance 公式、未改 OP 规则、未改 `/api/finance-step6`、未改 `/api/finance-batch-monthly`、未写 Google Sheet、未影响 Dashboard/Cleaning/Etsy/BookCars。
- 2026-05-25:V3.1 Step5F-7 补丁修复完成(仅 A_Records 车牌匹配):`/api/finance-owner-legacy-monthly-stats` 与 `/api/finance-owner-legacy-monthly-stats-debug` 的 Vehicle 车牌提取由旧的 `CA ` 固定截断逻辑改为 `extractPlateFromVehicleText` + 统一 normalize(转大写、去 `#`、去空格、仅保留字母数字);修复 `Henry (CA #9NLY246)` 等文本被提取成 `#9NLY24` 的问题,匹配前对 `ownerPlates` 与 `extractedPlate` 同口径标准化,确保 `ownerPlateMatched` 与 `statsByPlate` 有效统计恢复。未改 Finance 公式、未改 OP 规则、未写 Google Sheet、未改 Dashboard/Cleaning/Etsy/BookCars。
- 2026-05-26:V3.1 Step5F-9 完成,`/finance-owner-legacy-report-v2` 新增展示层展开/收起交互:收益明细、报销费用明细、花销费用明细支持模块级折叠(默认:收益/报销展开,花销收起);收益明细每车新增“查看行程/收起行程”(数据来自 `/api/finance-owner-legacy-monthly-stats` 已参与本月统计的 overlap 行程);每车新增“查看费用/收起费用”(数据来自 `A_Flow` 只读链路 `/api/finance-expense-flow-debug`,按 `month+plate` 过滤,不按 PaidBy/owner 筛选)。本次仅改 V2 展示与必要只读读取,未改公式、未改 OP、未改 `/api/finance-step6`、未改 `/api/finance-batch-monthly`、未写 Google Sheet,未影响 V1 与 Dashboard/Cleaning/Etsy/BookCars。
- 2026-05-26:A档文档任务完成,新增 `docs/QP_FINANCE_DATA_MAP.md`(Claude 审计结果正式化):补齐财务系统总数据流、数据源总表、`A_Turo_Payouts / A_Records / A_Flow / A_overview` 关系、字段字典、收入口径、费用归属 vs 报销归属、API 数据地图、页面数据地图、cache-first 策略、出租天数/出租率/报销费用/车辆花销推导例子、已知坑点。仅文档更新;未改代码、未改 `server.js`、未写 Google Sheet、未改 Finance 公式、未改 OP、未触碰 Dashboard/Cleaning/Etsy/BookCars。
- 2026-05-26:V3.1 Step5F-10(V2 打印与车主可读版优化)完成,`/finance-owner-legacy-report-v2` 仅展示层优化:页面标题改为“车主月度报表 Owner Monthly Report”并在顶部展示车主与月份;四模块保留且默认状态为收益明细展开、报销费用明细展开、花销费用明细收起、每车行程/每车费用明细收起;结算汇总“最终应付车主 Final Net To Owner”按正负金额高亮(正数绿色、负数红色并提示车主需向公司补付);表格统一金额右对齐、长备注自动换行、费用明细收据链接统一显示“查看收据”;新增打印样式,打印时隐藏返回链接/加载按钮/技术说明与调试弱文案,仅保留标题、月份、车主、四模块及当前展开内容;内部版本提示移至页底弱化展示。未改财务公式、未改 OP、未改 `/api/finance-step6`、未改 `/api/finance-batch-monthly`、未写 Google Sheet、未改 V1 与 Dashboard/Cleaning/Etsy/BookCars。
- 2026-05-26:V3.1 Step5F-11(旧版车主月报 V2 最终验收收口记录)完成:`/finance-owner-legacy-report-v2` 最小可用版已收口;已完成项包括结算汇总展示、收益明细报告、出租率/出租天数/出租次数显示、每车行程展开、每车费用展开、报销费用明细按 `PaidBy=owner`、花销费用明细按 `Belongs To=owner`、展开/收起、打印样式与车主可读版基础美化。本次仅文档更新,不改 `server.js`、不改 API、不改公式、不改 OP、不写 Google Sheet,且未触碰 Dashboard/Cleaning/Etsy/BookCars。
- 2026-05-26:V3.3 Step1(Finance Monthly Snapshot 基础层)完成最小可用底座:新增 `POST /api/finance-snapshots/system-auto`(生成 System Auto Version,默认不覆盖,已存在返回 alreadyExists)与 `GET /api/finance-snapshots`(按 owner/month 查询 snapshot 列表);新增 `/finance-snapshots` 内部管理页(查询 + 生成 + 列表)。Snapshot 存储采用本地 JSON 目录 `data/finance-snapshots/`,文件名 `<month>__<ownerNormalized>__system-auto.json`。本次仅新增 snapshot 新层,不改 Finance 公式、不改 OP 规则、不改 `/api/finance-step6`、不改 `/api/finance-batch-monthly`、不写 Google Sheet、不做 Manual Adjustment。
- 2026-05-26:V3.3 Step1.1(Snapshot 详情查看与基础预览)完成:新增只读 API `GET /api/finance-snapshots/:snapshotId`,可返回 snapshot `raw`(完整 JSON)与 `detail`(基础信息、数据摘要、关键金额、车辆明细预览);`/finance-snapshots` 列表页新增“查看详情”按钮与页面内只读详情预览区域。仅查看不编辑;未改 Finance 公式、未改 OP、未改 `/api/finance-step6`、未改 `/api/finance-batch-monthly`、未写 Google Sheet、未做 Manual Adjustment/Display Version 切换/Lock。
- 2026-05-26:V3.3 Step1.4(Snapshot 管理页基础收口优化)完成:仅优化 `/finance-snapshots` 只读管理页展示体验(未改 Snapshot 保存逻辑、未改 Snapshot API 业务逻辑)。新增 completeness 颜色标识:`Complete` 绿色、`Missing Cars/Missing Expenses/Missing Stats/Missing Summary` 橙色、`Need Review` 红色;新增解释文案(`Complete = 可作为人工调整底稿`、`Need Review = 数据不完整,不建议进入人工调整`);增强筛选提示(默认提示输入 month/owner,owner 为空表示查看该月份全部 owner,month 为空表示查看全部 snapshot);对 `Missing/Need Review` 旧测试快照增加“不完整(保留旧测试快照,不删除)”标记;页面底部新增下一步提示(Step1 完成后进入 Step2 Manual Adjustment,且 Manual Adjustment 只基于 Complete snapshot)。未改 Finance 公式、未改 OP、未改 `/api/finance-step6`、未改 `/api/finance-batch-monthly`、未写 Google Sheet、未做 Manual Adjustment。
---
## 12. V3.3 Step2-0(Manual Adjustment 设计)
- 2026-05-26:已新增 `docs/QP_FINANCE_MANUAL_ADJUSTMENT_PLAN.md`。
- 本次仅完成 Manual Adjustment 设计文档(业务规则、数据结构、处理流程、边界、Step2 拆分)。
- 当前仍处于“文档先行”阶段,**尚未进入代码实现**。
- 明确未改:`server.js`、API、Finance 公式、OP、step6、batch monthly、Google Sheet 写入链路。
- 2026-05-26:V3.3 Step2.1(Manual v1 创建最小版)完成:新增 `POST /api/finance-snapshots/manual-v1`,仅允许基于 `Complete + SYSTEM_AUTO` 快照创建 `Manual v1` 本地 JSON(文件名 `<month>__<ownerNormalized>__manual-v1.json`),写入最小 adjustment 字段(`adjustmentType/plate/amount/reason`)并复制 base snapshot `data`,默认不覆盖已存在 manual-v1(返回 `alreadyExists:true`)。`/finance-snapshots` 页面新增“创建 Manual v1”按钮(仅 Complete + SYSTEM_AUTO 显示)和最小表单提交流程。未做重算、未改公式、未改 OP、未改 `/api/finance-step6`、未改 `/api/finance-batch-monthly`、未写 Google Sheet。
---
## 13. Staging 测试环境规划(2026-05-26 新增)
为避免未充分验证代码直接影响正式环境,新增 staging 规划:
- Production 保持不变:`/opt/qp-fleet-system` + `qp-fleet-system` + `4020`
- Staging 新增环境:`/opt/qp-fleet-system-staging` + `qp-fleet-staging` + `4021`
- 发布流程更新:PR 合并后先部署 staging,staging 验收通过后再部署正式 4020。
- 运维禁令继续生效:禁止 `pm2 restart all` / `pm2 delete all`;禁止误碰 Etsy Image Tool(4030)。
- 2026-05-26:V3.3 Step2.2(Manual v1 PAYOUT_ADJUSTMENT 最小重算版)完成:Manual v1 从 System Auto 派生后执行最小重算,仅处理 `PAYOUT_ADJUSTMENT`。在 `data.cars` 按 plate 查找目标车并更新收入字段(兼容 `Income_Payout/incomePayout/income/totalIncome/ownerIncome`),同步更新车辆最终结算字段(兼容 `FinalSettlement/finalSettlement/Final Net To Owner/finalNetToOwner/netToOwner`),并同步更新 `data.summary` 的 `Total Income` 与 `Final Net To Owner`(字段存在时)。新增 `adjustmentsApplied`、`adjustmentSummary`。不覆盖 System Auto、不写 Google Sheet、不改 finance-step6/batch monthly。
- 2026-05-26:V3.3 Step2.3(Manual v1 Difference Preview 最小版)完成:`GET /api/finance-snapshots/:snapshotId` 新增 `detail.diffPreview` 只读差异预览,`/finance-snapshots` 详情区新增 “Manual差异预览” 展示。仅用于查看 base vs manual 的最小差异,不修改 Manual v1 创建逻辑、不改 System Auto、不写 Google Sheet、不改 Finance 公式/OP/step6/batch monthly。