# BD_Manual：FDW 财务区域查询映射（fdw_finance_area）

> 目标库：后端通过 `get_etl_readonly_connection(site_id)` 直连 ETL 库
> 关联 SPEC：board-finance-dws-area-refactor
> 日期：2026-03-28

---

## 1. 变更说明

### 新增 RLS 视图（ETL 库 app Schema 自动导出）

本次新增的两张 DWS 表各有一个 RLS 视图，后端通过直连 ETL 库的 `app.v_*` 视图访问（与 RNS1.2 以来的模式一致，不使用 `fdw_etl.*` 外部表）。

| 视图 | 源表 | 用途 |
|------|------|------|
| `dws.v_dws_finance_area_daily` | `dws.dws_finance_area_daily` | 区域日粒度财务数据（overview/revenue 板块） |
| `dws.v_dws_finance_board_cache` | `dws.dws_finance_board_cache` | 已完成周期缓存（overview 8 项指标） |

### 后端查询函数

| 函数 | 视图 | 用途 |
|------|------|------|
| `get_finance_overview_area()` | `v_dws_finance_area_daily` | 按 area_code 聚合 overview 8 项指标 |
| `get_finance_revenue_area()` | `v_dws_finance_area_daily` | 按 area_code 聚合 revenue 板块数据 |
| `get_finance_board_cache()` | `v_dws_finance_board_cache` | 查询缓存 |
| `set_finance_board_cache()` | `dws.dws_finance_board_cache` | 写入/更新缓存 |

### RLS 隔离

所有查询通过 `SET LOCAL app.current_site_id = :site_id` 设置门店隔离参数，RLS 视图的 `WHERE site_id = current_setting('app.current_site_id')::bigint` 自动过滤。

---

## 2. 兼容性影响

| 组件 | 影响 |
|------|------|
| ETL 任务 | 无影响。FDW 配置不修改 ETL 库 |
| 后端 API | `fdw_queries.py` 新增 4 个函数，`board_service.py` 改为调用新函数 |
| 小程序 | 无直接影响（API 签名不变） |
| 现有 FDW 外部表 | 无影响。新视图通过直连 ETL 库访问，不经过 `fdw_etl` Schema |

---

## 3. 回滚策略

后端回滚：
1. 恢复 `board_service.py` 到旧逻辑（从 `dws_finance_daily_summary` 取数）
2. 移除 `fdw_queries.py` 中的 4 个新函数

数据库回滚：
```sql
DROP VIEW IF EXISTS dws.v_dws_finance_board_cache;
DROP TABLE IF EXISTS dws.dws_finance_board_cache;
DROP VIEW IF EXISTS dws.v_dws_finance_area_daily;
DROP TABLE IF EXISTS dws.dws_finance_area_daily;
```

---

## 4. 验证 SQL

```sql
-- 1. 验证 RLS 视图可访问（需先设置 site_id）
SET LOCAL app.current_site_id = '1';
SELECT COUNT(*) FROM dws.v_dws_finance_area_daily;

-- 2. 验证缓存视图可访问
SET LOCAL app.current_site_id = '1';
SELECT COUNT(*) FROM dws.v_dws_finance_board_cache;

-- 3. 验证 app_reader 角色有 SELECT 权限
SELECT has_table_privilege('app_reader', 'dws.v_dws_finance_area_daily', 'SELECT') AS daily_ok,
       has_table_privilege('app_reader', 'dws.v_dws_finance_board_cache', 'SELECT') AS cache_ok;

-- 4. 验证区域日粒度数据完整性（每天 9 行）
SET LOCAL app.current_site_id = '1';
SELECT stat_date, COUNT(*) AS cnt
FROM dws.v_dws_finance_area_daily
GROUP BY stat_date
HAVING COUNT(*) != 9;
```
