# 云端部署与报销闭环说明

更新时间：2026-06-09 19:49 CST

## 1. 当前线上入口

新一套公司财务报销/走账系统后端已部署到云服务器，并使用独立路径避免覆盖旧线上财务看板。

```text
公网入口：https://wwyl.yipeng.online/finance-reimbursement/
健康检查：https://wwyl.yipeng.online/finance-reimbursement/health
报销审批看板：https://wwyl.yipeng.online/finance-reimbursement/dashboard/
云端服务：company-finance.service
云端路径：/srv/company-finance/current
云端文档：/srv/company-finance/docs
内部监听：127.0.0.1:8102
数据库：PostgreSQL / company_finance
```

> 说明：旧 `/finance/` 线上看板仍保留在 `studio-finance.service`，本次没有直接覆盖。等新报销系统实际使用稳定后，再决定是否把 `/finance/` 切到新系统。

## 2. 已落地的表结构

本次云端已创建并迁移一期报销闭环所需 PostgreSQL 表，共 16 张/视图：

- `subject_type`
- `subject`
- `source_category`
- `expense_category`
- `project`
- `cash_account`
- `attachment`
- `invoice`
- `invoice_link`
- `intake_draft`
- `reimbursement_order`
- `reimbursement_item`
- `fund_transaction`
- `reimbursement_payment`
- `audit_log`
- `reimbursement_order_summary` 视图

核心口径：

```text
报销先进入 intake_draft
人工确认/审批边界后创建 reimbursement_order + reimbursement_item
发票/附件进入 invoice / attachment，并通过 invoice_link 关联明细
实际付款发生后再用 fund_transaction + reimbursement_payment 核销
个人账余额后续从无票报销、个人垫付、注资、公司还个人等事实派生
```

## 3. 当前已支持的报销接口

```text
GET  /health
GET  /api/intake/intents
GET  /api/intake/rules?intent=record_reimbursement
POST /api/intake/validate
POST /api/intake/preview
POST /api/intake/drafts
GET  /api/intake/drafts/:id
POST /api/intake/drafts/:id/commit
GET  /api/reimbursements
GET  /api/reimbursements/:id
POST /api/reimbursements/approval/prepare
POST /api/reimbursements/approval/submit
POST /api/approval/feishu/callback
POST /api/webhooks/feishu/approval
GET  /api/dashboards
GET  /api/dashboards/reimbursements
GET  /api/dashboards/reimbursements/summary
GET  /mcp/tools
POST /mcp/call
```

MCP-like 业务工具中，报销相关优先使用：

```text
finance_get_intake_rules
finance_validate_intake_draft
finance_prepare_reimbursement
finance_preview_intake
finance_archive_source_file
finance_submit_reimbursement_approval
finance_commit_draft
finance_search_records(record_type="reimbursement")
```

## 4. 当前已维护主体

截至 2026-06-08，以下主体已按“公司”性质维护到本地种子、云端种子和云端 PostgreSQL：

```text
sub_dianjiang       点绛
sub_yunhan          云汉寻真
sub_misepojian      秘色破茧
sub_wanwuyouling    万物有灵
```

默认基础经营项目已维护：

```text
proj_yunhan_base_operation        云汉寻真-基础经营
proj_dianjiang_base_operation     点绛-基础经营
proj_misepojian_base_operation    秘色破茧-基础经营
proj_wanwuyouling_base_operation  万物有灵-基础经营
```

## 5. 报销草稿字段边界

`record_reimbursement` 的阻塞字段仍按规则文件执行：

- 申请/经办人：`applicant_subject_id`
- 收款/报销对象：`payee_subject_id`
- 每条明细金额：`items[].amount`
- 费用归属项目或主体基础经营：`items[].project_id` / `items[].owner_subject_id`
- 发票状态：`items[].invoice_status`
- 费用说明：`items[].description`

可选但已支持入库的字段：

- 整单附件：`attachments[]`
- 明细附件：`items[].attachments[]`
- 发票信息：`items[].invoice`
- 发票号：`items[].invoice_no`
- 费用分类：`items[].expense_category_id`
- 来源分类：`items[].source_category_id`
- 发生日期：`occurred_at` 或 `items[].occurred_at`

## 6. 已验证结果

已完成真实工具验证：

```text
npm run check
BASE_URL=http://127.0.0.1:8791 npm test
npm run db:migrate
BASE_URL=https://wwyl.yipeng.online/finance-reimbursement npm run test:db
```

云端 DB smoke test 曾创建 1 条测试报销单、1 条明细、1 条发票、1 条附件并读取成功；早期 smoke 测试记录已删除。后续真实审批联调产生的测试报销单保留为回归证据。

2026-06-08 已补充验证：

```text
finance_resolve_subject 点绛 / 云汉寻真 / 秘色破茧 / 万物有灵 均可解析为 company 主体
finance_resolve_project 点绛基础经营 / 秘色破茧基础经营 均可解析到默认基础经营项目
云端 PostgreSQL subject/project 表已可查询到上述新增主体与基础经营项目
```

2026-06-09 已完成真实飞书审批闭环验证：统一报销模板、当前飞书会话用户发起、飞书自动 webhook 回调、系统状态回写均已跑通。三张测试单 `RB20260609-97CB911E`、`RB20260609-F392C5DA`、`RB20260609-CC5EAD97` 最终状态均为 `APPROVED`。

> 当前可以描述为“飞书审批链路已通过真实测试”；但 `APPROVED` 仍表示审批通过/待打款，不等于已付款。付款核销到 `PAID` 仍需后续资金流水流程。

2026-06-08 看板登录部署验证：

```text
未登录访问 /dashboard/ 返回 302，自动跳转到 /login?next=/finance-reimbursement/dashboard/
/login 登录页返回 200，包含“登录财务系统”
登录成功后服务端写入 HttpOnly Cookie：finance_dashboard_session
登录后访问 /dashboard/ 返回 HTML 且包含“财务系统 · 看板”
登录后页面中“数据授权 Token”与 apiToken 均为 0，不再在看板页显示 token 输入区
登录后 GET /api/dashboards 返回 reimbursements 看板注册信息
登录后 GET /api/dashboards/reimbursements/summary?granularity=month 返回 PostgreSQL 汇总数据
POST /api/auth/logout 返回 200，并清除登录 cookie
```

> 报销明细和汇总属于财务数据。现在由登录页验证现有 `FINANCE_API_TOKEN`，验证通过后用服务端 HttpOnly Cookie 保持登录态；看板页不再显示或保存授权 token。

## 7. 2026-06-09 飞书审批自动回调验证结论

已验证链路：

```text
报销草稿/报销单入库 → 上传/绑定审批附件 → 发起飞书审批 → 飞书自动 POST callback → 系统按实例 ID 回写状态 → 看板/API 显示 APPROVED
```

关键证据：

```text
测试单：RB20260609-97CB911E / RB20260609-F392C5DA / RB20260609-CC5EAD97
最终状态：APPROVED
回调事件统计：2026-06-09 17:30 后 callback_events=18，approved_events=9，unknown_events=3
每个关键实例事件分布：APPROVAL_PENDING=2，APPROVED=3，UNKNOWN=1
```

状态守卫口径：飞书通过后可能继续推送无状态 `approval` 事件；系统只记录 `UNKNOWN` 审计事件，不允许其覆盖 `APPROVED`、`REJECTED`、`PAID` 等终态。

有票测试口径：合成 PDF 已验证 COS 审计附件和飞书审批附件两层链路；真实发票 OCR/结构化入库仍需用真实发票另做验证。

详细记录：`docs/2026-06-09_报销审批自动回调闭环验证.md`

## 8. 使用建议

接下来可以直接拿用户已有发票，从“报销草稿”开始边用边优化：

1. 机器人先调用规则，判断缺哪些字段；
2. 对用户发票/凭证整理出结构化 `record_reimbursement` 草稿；
3. 先预览给用户确认；
4. 用户确认后调用 commit，正式写入 PostgreSQL；
5. 后续付款发生时，再新增 `fund_transaction` 并用 `reimbursement_payment` 核销。

## 9. 安全边界

- 本文不记录数据库密码、token、AppSecret 或连接串。
- 本次新增路径 `/finance-reimbursement/`，没有覆盖旧 `/finance/`。
- `03_用户资料` 仍然只读；发票文件如来自用户资料区，应复制/登记附件引用，不在原始资料区写改删。
