# 历史提案:月报渠道顺序清单 ## 状态 本文件仅保留原始分析。正式实现已编号为 `database/006_report_channel_manifest.sql`;是否应用以及执行 SHA 只以 `database/APPLIED_MIGRATIONS.md` 为准。不要把本 proposal 本身当作迁移执行。 ## 已证实的缺口 analytics 1.2 要求 `channels[]` 严格等于月报实际工作表名称和顺序,并保留实际存在的空工作表。当前: - `finance.daily_channel_metrics` 只有 `daily_version_id / worksheet / row_count`; - `finance.v_channel_booking_enriched` 没有渠道顺序; - finance schema 中没有 `worksheet_order / ordinal / channel_order` 候选列; - 物理行顺序、字母排序和硬编码都不能成为业务契约。 因此当前数据库可以重建数值聚合,但不能 DB-only 生成完整 analytics 1.2。 ## 最小结构建议 建议新增 report-level 表 `finance.report_channel_manifest`,每个正式月报版本、每个实际工作表一行: | 字段 | 建议类型 | 约束/含义 | |---|---|---| | `report_version_id` | `bigint` | 非空,外键指向 `finance.report_versions(id)` | | `worksheet` | `text` | 非空且去除首尾空白后不为空;保存原工作表名称 | | `worksheet_order` | `integer` | 非空,从 1 连续编号;保存工作簿 sheet 顺序 | | `row_count` | `integer` | 非空且不小于 0;空工作表必须保存 0 | 建议约束: - 主键:`(report_version_id, worksheet)`; - 唯一键:`(report_version_id, worksheet_order)`; - 同一 report version 的顺序必须完整连续为 `1..N`; - active/current report 在激活前必须有完整 manifest; - manifest 必须绑定 `report_versions.artifact_file_id` 对应的同一月报工件,不能从事实行排序推断。 ## 写入与回填边界 - 新月报:由已验收的月报生成/采用流程读取工作簿 `sheetnames` 后,在同一版本发布事务中写入;不得在看板查询时补写。 - 既有 2026-07:必须由另行授权的受控回填读取月报工件本身并记录原 sheet 顺序。不能用数据库物理顺序、渠道字母顺序、当前 XLSX 7.22 快照或硬编码 6 个渠道代替 7.26 工件。 - 该表只保存工作表名称、顺序和聚合行数,不保存客人级字段。 ## 切换验收 迁移与回填完成后,仍需同时满足: 1. report artifact SHA-256、month 和 `as_of_date` 与 XLSX baseline 相同; 2. 渠道名称、顺序、空渠道和 row_count 完全一致; 3. KPI、公司销售、房型明细、渠道明细和渠道×房型矩阵逐项一致; 4. repository 只查询 `finance.v_channel_booking_enriched`、版本表和本 manifest; 5. 所有测试通过后,才把本地 `OPERA_DASHBOARD_SOURCE` 切到 `database`。 现有服务端 repository 已按上述表名与字段进行能力探测;表不存在或清单不完整时会以 `DB_CHANNEL_ORDER_UNAVAILABLE` 明确回退 XLSX。