# CLAUDE.md

本文件为 Claude Code (claude.ai/code) 在本仓库工作时的指导规范。

## 语言（强制）

始终使用中文，覆盖所有场景：

- 对话回复、解释、提问、状态更新 → 中文
- 代码注释 → 中文
- Git commit message → 中文描述 + 英文 Co-Authored-By 签名行
- PR 标题与正文 → 中文
- 审计记录、文档、变更说明 → 中文
- 错误提示、日志说明 → 中文
- 变量名/函数名/类名 → 保持英文（编程惯例）
- 第三方 API 字段名、CLI 命令 → 保持原文

禁止在回复中使用英文段落或英文标题（技术术语、代码片段、专有名词内嵌除外）。

## 项目概览

NeoZQYY Monorepo — 面向台球门店业务的全栈数据平台。多门店隔离（`site_id` + RLS），领域语言中文，货币 CNY，金额 `numeric(2)`。

### 子系统

| 目录 | 说明 |
|------|------|
| `apps/etl/connectors/feiqiu/` | 飞球 Connector：API → ODS → DWD → DWS |
| `apps/backend/` | FastAPI 后端（JWT 双认证、WebSocket、AI 集成） |
| `apps/miniprogram/` | 微信小程序（C 端，Donut + TDesign） |
| `apps/admin-web/` | 系统管理后台（React+Vite+AntD）— 开发/运维视角，操作 ETL 库 |
| `apps/tenant-admin/` | 租户管理后台（React+Vite+AntD）— 门店管理员视角，操作业务库 |
| `apps/mcp-server/` | MCP Server（PostgreSQL 只读，AI 工具集成） |
| `packages/shared/` | 跨项目共享包（enums, money, datetime_utils） |
| `apps/demo-miniprogram/` | MOCK 小程序（假数据驱动，页面样式/展示格式标杆校对） |
| `db/` | 权威 DDL（`schemas/`）/ 迁移归档 / FDW 配置 |
| `tools/` | 通用工具（db/reporting/health/h5-to-mp-checker） |
| `scripts/ops/` | 日常运维脚本（ETL 监控、数据回填、导出等） |

### 两个管理后台的区别

- `admin-web`：开发/运维用，ETL 配置、数据质量、系统监控，全局视角
- `tenant-admin`：门店管理员用（`site_admin`/`tenant_admin`），用户审核/管理、Excel 上传、维客线索，门店隔离视角

## 技术栈

- Python 3.10+，uv workspace（4 成员：etl/connectors/feiqiu、backend、mcp-server、shared）
- 前端：React + Vite + Ant Design，各应用独立 pnpm
- PostgreSQL 四库：`etl_feiqiu` / `test_etl_feiqiu`（ETL，六层 Schema）、`zqyy_app` / `test_zqyy_app`（业务）
- DSN：`PG_DSN`（ETL）、`APP_DB_DSN`（业务），根 `.env` 定义
- 配置分层：`.env` < `.env.local` < 环境变量 < CLI 参数

## 常用命令

```bash
# 依赖安装
uv sync                              # Python 全量安装
cd apps/admin-web && pnpm install    # 前端（admin-web / tenant-admin 各自独立）

# 开发服务器
cd apps/backend && uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload
cd apps/admin-web && pnpm dev        # port 5173
cd apps/tenant-admin && pnpm dev

# ETL
cd apps/etl/connectors/feiqiu
python -m cli.main --dry-run --tasks DWD_LOAD_FROM_ODS
python -m cli.main --pg-dsn "$PG_DSN" --store-id "$STORE_ID" --api-token "$API_TOKEN"

# 测试
cd apps/etl/connectors/feiqiu && pytest tests/unit         # ETL 单元测试
cd apps/etl/connectors/feiqiu && pytest tests/integration --with-db  # ETL 集成测试
cd apps/backend && pytest tests/                           # 后端测试
cd /c/NeoZQYY && pytest tests/ -v                          # Monorepo 属性测试（hypothesis）
cd apps/admin-web && pnpm test                             # 前端 Vitest
cd apps/admin-web && pnpm e2e                              # Playwright e2e
cd apps/admin-web && pnpm lint                             # TypeScript 检查
cd apps/miniprogram && npm test                            # 小程序 Jest
```

## 架构模式

### 数据库

- 六层 Schema：`meta` → `ods`（原始）→ `dwd`（规范化）→ `core`（聚合）→ `dws`（业务汇总）→ `app`（RLS 视图）
- 跨库访问：`zqyy_app` 通过 FDW 只读映射 `etl_feiqiu.app` schema
- 多门店隔离：`site_id` + RLS，`app` schema 视图层通过 `app.current_site_id` 会话变量过滤

### RLS 视图双 Schema 规则（踩坑 2026-03-29）

新建 DWS/DWD 表的 RLS 视图必须同时在原 schema（如 `dws`）和 `app` schema 创建。后端通过 `app.v_*` 访问。只在 `dws` 创建会导致后端查询失败。迁移模板：先 `CREATE VIEW dws.v_xxx`，再 `CREATE VIEW app.v_xxx`，WHERE 条件相同。回滚需逆序 DROP。

### ETL

> 完整规则见 `apps/etl/connectors/feiqiu/CLAUDE.md`

- 任务模式：继承 `BaseTask`（Extract → Transform → Load），在 `orchestration/task_registry.py` 注册
- 加载器模式：每张目标表一个 Loader，`upsert()` + 冲突处理
- SCD2 处理：`scd/` 模块
- Flow：`--pipeline` 参数指定（如 `api_full`）

### 后端

> 完整规则见 `apps/backend/CLAUDE.md`

- 全局响应包装：`ResponseWrapperMiddleware` → `{ "code": 0, "data": <payload> }`
- JWT 双认证：admin（用户名密码）+ miniapp（微信 code）+ tenant-admin（用户名密码）
- AI 集成：8 个千问应用（DashScope SDK），带熔断、限流、预算追踪
- 后台服务：TaskQueue + Scheduler + 4 个触发器

## 文件归属规则

| 判断标准 | 放置位置 |
|----------|----------|
| 只有本模块开发者需要看的文档 | 模块内 `docs/` |
| 跨模块对照或全局视角的文档 | 根 `docs/` |
| 只验证本模块逻辑的测试 | 模块内 `tests/` |
| 守护 monorepo 结构/约定的测试 | 根 `tests/` |
| 只操作本模块数据的脚本 | 模块内 `scripts/` |
| 日常运维脚本（回填/导出/种子/初始化） | `scripts/ops/` |
| 可复用通用工具（健康检查/数据库/报表/分析） | `tools/`（按类型分子目录） |
| 审计记录（任何模块的变更） | 根 `docs/audit/` — 禁止写入子模块 |
| 数据库文档（全局 schema 视角） | 根 `docs/database/` |
| 归档/待删除内容 | `_DEL/`（保持原路径结构，用户定期手动清理） |

审计产物路径：
- 变更记录：`docs/audit/changes/<YYYY-MM-DD>__<slug>.md`
- 审计一览表：`docs/audit/audit_dashboard.md`（`scripts/audit/gen_audit_dashboard.py` 自动生成，勿手动编辑）

## 飞球数据规范

> 完整规则见 `apps/etl/connectors/feiqiu/CLAUDE.md`（进入 ETL 目录时自动加载）。

**核心速查**：
- `consume_money` 禁止直接计算 → 用 `items_sum` 拆分字段
- 取数优先级：DWS > DWD > 禁止 ODS
- 参考优先级：DWD-DOC > DWS 权威规范 > BD 手册 > ETL 任务文档 > DDL 注释
- 所有 `_archived/` 目录禁止读取或参考

## 编码前需求审问（强制）

新建功能/模块/页面/接口、重构、多模块联动、需求存在模糊或隐含假设时：
1. 不立即动手，先提问循环（每轮 3-5 个问题）
2. 必问维度：用户角色、核心操作、完成后果、数据写入/展示/来源、错误/成功反馈、认证权限、存储（哪个库/新表？）、终端适配、边界条件（并发/幂等/超时）
3. 输出「需求确认摘要」，用户确认后才进入实施

例外：用户说"直接改/跳过审问/不用问了"、Bug 修复（有明确复现步骤）、纯格式/文档调整、已有完整 spec

## 逻辑改动前置调研（强制）

任何逻辑改动（ETL/业务规则/API/数据模型/前端交互），写代码前必须完成调研：
1. 用 Explore 子代理调研：目标模块文件、`docs/audit/changes/` 历史审计、相关 README/PRD/BD 手册、要修改的文件及其调用方/被调用方、数据流向（上游→当前→下游）、影响范围
2. 输出「改动前上下文摘要」（模块职责、历史变更、影响范围、风险点），用户确认后开始实施

流程：需求审问 → 用户确认 → 前置调研 → 用户确认 → 编码实施

例外：纯格式调整、注释/文档纯文字修改、用户说"直接改/跳过调研"、新建文件且不涉及已有逻辑

## 改动后验证（强制）

逻辑改动完成后，必须执行以下验证步骤：
1. 运行相关测试（单元/集成/lint），如无法运行需说明原因
2. 输出 diff 摘要（改了哪些文件、每个文件改动要点）
3. 列出未覆盖的风险点（未测试的路径、可能的副作用、需要人工验证的场景）

例外：纯格式/文档/注释调整、用户说"跳过验证"

## 数据库 Schema 变更规则

修改任何影响 PostgreSQL schema 的内容（迁移/DDL/表定义/ORM 模型）时，必须同步更新 `docs/database/`：
- 变更说明：新增/修改/删除的表、字段、约束、索引
- 兼容性：对 ETL、后端 API、小程序字段映射的影响
- 回滚策略：如何撤销
- 验证步骤：至少 3 条校验 SQL

## 测试与验证环境规范

1. 必须 `load_dotenv` 加载根 `.env`；必需变量缺失时立即报错，禁止静默回退空字符串
2. cwd 与正式一致：ETL → `apps/etl/connectors/feiqiu/`；后端 → `apps/backend/`
3. 配置走 `AppConfig.load()` 正常流程，不得为测试单独构造简化配置
4. 数据库使用测试库（`TEST_DB_DSN`），禁止连正式库
5. 属性测试分组执行：每次单个测试函数或 `-k` 筛选，禁止一次性跑全部；hypothesis 默认 `max_examples=100`

例外：用户指定简化环境、纯单元测试用 FakeDB/FakeAPI、`--dry-run` CLI 验证

## 脚本规范

- 复杂操作优先写 Python 脚本，避免复杂 shell 逻辑
- 一次性运维脚本 → `scripts/ops/`；模块专属 → 模块内 `scripts/`
- `scripts/ops/` 中的脚本不在 uv workspace 内，导入 ETL 纯函数需用 `importlib.util` + stub 方式（参考 `scripts/ops/backfill_finance_area_daily.py`、`tests/conftest.py`）

## 子代理使用原则

- 委托子代理：批量文件读取（≥3 个）、大范围搜索、不熟悉的模块探索、多步骤 shell 操作
- 主流程直接处理：单个已知文件、简单单条命令、小范围精确搜索

## 审计

任何逻辑改动必须可追溯、可验证、可回滚。

完成一轮改动后，使用 `/audit` 命令执行审计。流程：
1. 运行 `python scripts/audit/prescan.py` 预扫描（自动识别变更文件、分类风险、合规检查，零 token）
2. 补充语义上下文（从对话记忆中提取每个变更的原因和思路）
3. 委托子代理写审计记录到 `docs/audit/changes/`
4. 补齐缺失的文档同步
5. 运行 `python scripts/audit/gen_audit_dashboard.py` 刷新审计一览表

预扫描脚本支持 `--files` 参数：当 git status 包含大量历史未提交变更时，可只传入本次会话涉及的文件列表。

已废弃（不再使用）：
- Prompt-ID 溯源、`docs/audit/prompt_logs/` — Claude Code 原生 session 日志已覆盖
- AI_CHANGELOG 文件内标记 — git blame 替代
- CHANGE 块级代码标记 — git blame 替代
- Session 日志 (`docs/audit/session_logs/`) — Claude Code 原生 session 存储已覆盖
