# 需求文档：Web 管理后台（admin-web-console）

## 简介

将现有 PySide6 桌面 GUI（`gui/`）替换为基于浏览器-服务器（BS）架构的 Web 管理后台。后端 API 在现有 FastAPI 骨架（`apps/backend/`）上扩展，前端部署在 `apps/admin-web/`。功能覆盖现有 GUI 的六大模块：任务配置、任务管理（队列与调度）、环境配置、数据库查看器、ETL 状态监控、日志查看器。

## 术语表

- **Admin_Web**：Web 管理后台前端应用，部署在 `apps/admin-web/`
- **Backend_API**：FastAPI 后端服务，部署在 `apps/backend/`，为 Admin_Web 提供 RESTful API
- **ETL_CLI**：现有 ETL 命令行工具（`apps/etl/pipelines/feiqiu/cli/main.py`），Backend_API 通过子进程调用
- **Connector**：数据源连接器，指对接的上游 SaaS 平台（如飞球），对应目录 `apps/etl/pipelines/{connector_name}/`。后续可扩展更多 Connector（台账类、球房类、财务类管理平台）
- **Flow**：执行流程，指 ETL 任务的处理链路，描述数据从哪一层流到哪一层（如 `api_ods_dwd` 表示 API → ODS → DWD）。对应 CLI 参数 `--pipeline`
- **Task_Registry**：任务注册表，定义所有可用 ETL 任务及其业务域分组
- **Task_Config**：任务执行配置，包含 Flow 类型、时间窗口、任务列表等参数
- **Schedule_Store**：调度任务持久化存储（从本地 JSON 迁移至 PostgreSQL）
- **Operator**：管理后台操作员，即门店运营人员
- **Site**：门店，通过 `site_id` 标识，是多门店数据隔离的基本单位

## 需求

### 需求 1：用户认证与会话管理

**用户故事：** 作为 Operator，我希望通过用户名密码登录管理后台，以确保只有授权人员能操作 ETL 系统。

#### 验收标准

1. WHEN Operator 提交有效的用户名和密码, THE Backend_API SHALL 返回一个 JWT 访问令牌和刷新令牌
2. WHEN Operator 提交无效的凭据, THE Backend_API SHALL 返回 401 状态码和错误描述
3. WHILE Operator 持有有效的 JWT 令牌, THE Backend_API SHALL 允许访问受保护的 API 端点
4. WHEN JWT 访问令牌过期, THE Backend_API SHALL 返回 401 状态码，Admin_Web SHALL 使用刷新令牌自动获取新的访问令牌
5. WHEN 刷新令牌也过期, THE Admin_Web SHALL 将 Operator 重定向到登录页面

### 需求 2：ETL 任务配置

**用户故事：** 作为 Operator，我希望在 Web 界面上选择并配置 ETL 任务的执行参数，以便灵活控制数据处理的运行方式。

#### 验收标准

1. WHEN Operator 打开任务配置页面, THE Admin_Web SHALL 从 Backend_API 获取 Task_Registry 中所有可用任务，并按业务域（会员、结算、助教、商品、台桌、团购、库存等）分组展示
2. WHEN Operator 选择执行流程 Flow（如 api_ods_dwd、dwd_dws 等）, THE Admin_Web SHALL 根据 Flow 包含的层（ODS / DWD / DWS / INDEX），仅显示与所选层兼容的任务
3. WHEN Operator 配置时间窗口参数（开始日期、结束日期、窗口分割策略）, THE Admin_Web SHALL 验证结束日期不早于开始日期
4. WHEN Operator 选择 DWD 装载任务, THE Admin_Web SHALL 展示 DWD 表级选择界面，允许按业务域分组勾选目标表
5. WHEN Operator 切换高级选项（dry-run、force-full、skip-quality 等）, THE Admin_Web SHALL 将这些选项反映到最终的 Task_Config 中
6. WHEN Operator 提交任务配置, THE Backend_API SHALL 验证 Task_Config 的完整性，并将其转换为有效的 ETL_CLI 命令参数

### 需求 3：ETL 任务执行

**用户故事：** 作为 Operator，我希望通过 Web 界面触发 ETL 任务执行，并实时查看执行进度和结果。

#### 验收标准

1. WHEN Operator 提交一个有效的 Task_Config, THE Backend_API SHALL 以子进程方式调用 ETL_CLI 执行任务，并返回一个任务执行 ID
2. WHILE ETL_CLI 子进程正在运行, THE Backend_API SHALL 捕获 stdout 和 stderr 输出，并通过 API 端点提供实时日志流
3. WHEN ETL_CLI 子进程执行完毕, THE Backend_API SHALL 记录退出码、执行时长和输出摘要到任务历史
4. IF ETL_CLI 子进程执行超时或异常退出, THEN THE Backend_API SHALL 记录错误信息并将任务状态标记为失败
5. WHEN Operator 请求取消正在执行的任务, THE Backend_API SHALL 向 ETL_CLI 子进程发送终止信号并将任务状态标记为已取消

### 需求 4：任务队列管理

**用户故事：** 作为 Operator，我希望管理任务执行队列，以便批量安排和控制任务的执行顺序。

#### 验收标准

1. WHEN Operator 将一个 Task_Config 添加到队列, THE Backend_API SHALL 创建一个状态为"待执行"的队列任务项并返回其 ID
2. WHEN 队列中存在待执行任务且当前无任务正在运行, THE Backend_API SHALL 按队列顺序自动取出下一个任务并开始执行
3. WHEN Operator 调整队列中任务的顺序, THE Backend_API SHALL 更新任务的执行优先级
4. WHEN Operator 从队列中删除一个待执行任务, THE Backend_API SHALL 将该任务从队列中移除
5. WHEN Operator 查看任务历史, THE Backend_API SHALL 返回按时间倒序排列的历史执行记录，包含任务编码、状态、开始时间、执行时长和退出码

### 需求 5：调度任务管理

**用户故事：** 作为 Operator，我希望创建和管理定时调度任务，以便 ETL Connector 能按计划自动运行。

#### 验收标准

1. WHEN Operator 创建调度任务时, THE Backend_API SHALL 接受调度配置（一次性 / 固定间隔 / 每日 / 每周 / Cron 表达式）并持久化到 Schedule_Store
2. WHEN 调度任务到达预定执行时间, THE Backend_API SHALL 自动将对应的 Task_Config 加入执行队列
3. WHEN Operator 启用或禁用一个调度任务, THE Backend_API SHALL 更新该任务的启用状态并重新计算下次执行时间
4. WHEN Operator 编辑调度任务的配置, THE Backend_API SHALL 验证新配置的有效性并更新 Schedule_Store
5. WHEN Operator 删除一个调度任务, THE Backend_API SHALL 从 Schedule_Store 中移除该任务及其执行历史
6. WHEN Operator 查看调度任务列表, THE Backend_API SHALL 返回所有调度任务及其最近执行状态、下次执行时间和执行次数

### 需求 6：环境配置管理

**用户故事：** 作为 Operator，我希望通过 Web 界面查看和编辑 ETL 的 .env 配置文件，以便调整运行参数而无需直接操作服务器文件。

#### 验收标准

1. WHEN Operator 打开环境配置页面, THE Backend_API SHALL 读取当前 .env 文件内容并返回键值对列表（敏感值如密码和令牌以掩码形式展示）
2. WHEN Operator 修改配置项并提交, THE Backend_API SHALL 验证配置格式的正确性，写入 .env 文件，并返回更新结果
3. WHEN Operator 导出配置, THE Backend_API SHALL 生成一份去除敏感值的配置文件供下载
4. IF Operator 提交的配置包含格式错误的键值对, THEN THE Backend_API SHALL 返回具体的错误位置和描述，拒绝写入

### 需求 7：数据库查看器

**用户故事：** 作为 Operator，我希望通过 Web 界面查看数据库表结构和执行查询，以便快速检查 ETL 数据质量。

#### 验收标准

1. WHEN Operator 打开数据库查看器页面, THE Admin_Web SHALL 展示可用的 Schema 列表（meta、ods、dwd、core、dws、app）
2. WHEN Operator 选择一个 Schema, THE Backend_API SHALL 返回该 Schema 下所有表的名称和行数统计
3. WHEN Operator 选择一张表, THE Backend_API SHALL 返回该表的列定义（列名、数据类型、是否可空、默认值）
4. WHEN Operator 提交一条 SQL 查询, THE Backend_API SHALL 在只读事务中执行该查询，限制返回行数上限为 1000 行，并返回结果集
5. IF Operator 提交的 SQL 包含写操作（INSERT / UPDATE / DELETE / DROP / TRUNCATE）, THEN THE Backend_API SHALL 拒绝执行并返回错误提示
6. IF SQL 查询执行超过 30 秒, THEN THE Backend_API SHALL 终止查询并返回超时错误

### 需求 8：ETL 状态监控

**用户故事：** 作为 Operator，我希望在 Web 界面上查看 ETL Connector 的运行状态和数据游标信息，以便及时发现异常。

#### 验收标准

1. WHEN Operator 打开 ETL 状态页面, THE Backend_API SHALL 返回各 ODS 表的最新数据游标（最后抓取时间、记录数）
2. WHEN Operator 查看最近执行记录, THE Backend_API SHALL 返回最近 50 条任务执行记录，包含任务名称、状态、开始时间、执行时长
3. WHEN Operator 刷新状态页面, THE Backend_API SHALL 返回最新的游标和执行状态数据

### 需求 9：实时日志查看

**用户故事：** 作为 Operator，我希望在 Web 界面上实时查看 ETL 任务的执行日志，以便监控任务进度和排查问题。

#### 验收标准

1. WHILE 一个 ETL 任务正在执行, THE Admin_Web SHALL 通过 WebSocket 或 SSE 连接实时展示该任务的日志输出
2. WHEN Operator 在日志查看器中输入过滤关键词, THE Admin_Web SHALL 仅展示包含该关键词的日志行
3. WHEN 任务执行完毕, THE Admin_Web SHALL 保留完整日志内容供 Operator 回顾
4. WHEN Operator 查看历史任务的日志, THE Backend_API SHALL 返回该任务的完整日志记录

### 需求 10：响应式布局与导航

**用户故事：** 作为 Operator，我希望管理后台具有清晰的导航结构和响应式布局，以便在不同设备上高效操作。

#### 验收标准

1. THE Admin_Web SHALL 提供侧边栏导航，包含八个功能模块入口：任务配置、任务管理、环境配置、数据库、ETL 状态、日志、球房编号管理、租户管理员管理
2. WHEN Operator 点击导航项, THE Admin_Web SHALL 切换到对应的功能模块页面，且不触发整页刷新
3. THE Admin_Web SHALL 在状态栏区域展示当前数据库连接状态和任务执行状态
4. WHILE 有任务正在执行, THE Admin_Web SHALL 在导航栏或状态栏显示执行中的视觉指示

### 需求 11：租户管理员账号管理

**用户故事：** 作为系统管理员（Operator），我需要在系统管理后台中创建和管理租户管理员账号，以便租户管理员能登录独立的租户管理后台（`apps/tenant-admin/`）进行用户审核、Excel 上传等操作。

#### 验收标准

1. WHEN Operator 打开租户管理员管理页面, THE Admin_Web SHALL 展示所有租户管理员账号列表，包含用户名、所属租户、管辖球房列表、账号状态（启用/禁用）、创建时间
2. WHEN Operator 创建租户管理员账号, THE Backend_API SHALL 接受用户名、初始密码、所属租户标识、管辖球房 ID 列表（`site_id` 数组），并在 `auth` Schema 中创建对应记录，密码以 bcrypt 哈希存储
3. WHEN Operator 编辑租户管理员账号, THE Backend_API SHALL 允许修改管辖球房列表、账号状态（启用/禁用），以及重置密码
4. WHEN Operator 禁用某租户管理员账号, THE Backend_API SHALL 将该账号状态设为禁用，该管理员后续登录租户管理后台时 SHALL 被拒绝
5. WHEN Operator 为租户管理员分配球房, THE Backend_API SHALL 验证球房 ID（`site_id`）在 `auth.site_code_mapping` 中存在，不存在时返回 422 错误
6. THE Backend_API SHALL 确保同一用户名不可重复创建（唯一约束）
7. WHEN Operator 查看某租户管理员详情, THE Admin_Web SHALL 展示该管理员管辖的球房列表及每个球房的球房代码（`site_code`）和名称

### 需求 12：球房编号管理

**用户故事：** 作为系统管理员（Operator），我需要在系统管理后台中为每个门店（`site_id`）分配球房编号（`site_code`），以便小程序用户申请时通过球房编号定位到对应门店。

#### 验收标准

1. WHEN Operator 打开球房编号管理页面, THE Admin_Web SHALL 展示 `auth.site_code_mapping` 中所有球房编号映射列表，包含球房编号（`site_code`）、门店 ID（`site_id`）、创建时间
2. WHEN Operator 新增球房编号映射, THE Backend_API SHALL 接受 `site_code`（格式：2 字母 + 3 数字，如 `AB123`）和 `site_id`（BIGINT），验证格式正确后写入 `auth.site_code_mapping`
3. IF 提交的 `site_code` 已存在, THEN THE Backend_API SHALL 返回 409 冲突错误
4. IF 提交的 `site_id` 已绑定其他 `site_code`, THEN THE Backend_API SHALL 返回 409 冲突错误（`site_code` 与 `site_id` 一对一）
5. WHEN Operator 编辑球房编号映射, THE Backend_API SHALL 允许修改 `site_code`（需验证新编号不与其他记录冲突）
6. WHEN Operator 删除球房编号映射, THE Backend_API SHALL 检查是否有用户申请引用该 `site_code`，若有则拒绝删除并提示关联数据存在
7. THE Admin_Web SHALL 在球房编号管理页面提供搜索功能，支持按 `site_code` 或 `site_id` 搜索

### 需求 13：Task_Config 序列化与反序列化

**用户故事：** 作为 Operator，我希望任务配置能在前后端之间正确传输和持久化，以确保配置不丢失。

#### 验收标准

1. THE Backend_API SHALL 将 Task_Config 序列化为 JSON 格式进行传输和存储
2. WHEN Backend_API 接收到 JSON 格式的 Task_Config, THE Backend_API SHALL 反序列化为内部 Task_Config 对象并验证所有必填字段
3. FOR ALL 有效的 Task_Config 对象, 序列化后再反序列化 SHALL 产生与原始对象等价的结果（往返一致性）
4. IF 反序列化时遇到缺失或类型错误的字段, THEN THE Backend_API SHALL 返回包含具体字段名和错误原因的验证错误
