# 项目结构与模块 > 给新接手者的"地图":目录层级、各模块职责、运行与部署流程。细节散落各专题文档,本文只做总览 + 指路。 > 关联:产品/IA [docs/01](01-产品需求-MVP.md)、技术架构与契约 [docs/02](02-技术架构.md)、数据契约 [docs/03](03-数据契约.md)、设计规范 [docs/04](04-设计规范.md)、接口 [docs/06](06-接口文档.md)、迭代与发布 [docs/08](08-迭代与发布.md)。 ## 1. 这是什么 hs-data 是**内部一站式数据平台**(monorepo)。当前 MVP 端到端做通**一个** L3 报表——**拼团漏斗**(`行为分析 > 漏斗分析 > 拼团漏斗`),含两个视图:**漏斗**(固定 5 步快照)与**趋势**(按日折线)。其余能力域进导航、出"待开发"占位。 ## 2. 顶层目录 ``` hs-data/ ├── apps/ │ ├── web/ # 前端 SPA(React 19 + Vite + Tailwind v4 + shadcn/ui + ECharts) │ └── api/ # 后端只读查询服务(FastAPI + SQLAlchemy async + asyncpg) ├── packages/ │ └── api-types/ # 由后端 OpenAPI 生成的 TS 类型(契约同步用) ├── docs/ # 平台级 PRD / 技术 / 数据契约 / 设计 / 协作 / 接口 / 结构 / 发布 │ └── prd/ # 模块级 PRD(每个端到端模块一份详规,如 拼团漏斗.md) ├── infra/ # 部署与本地基础设施脚本(look.sh / serve*.sh / serve.py / docker-compose) ├── CLAUDE.md # 开发硬约束(给 AI 与人) └── CHANGELOG.md # 改动留痕(按日期,顶部最新) ``` pnpm workspace(`pnpm-workspace.yaml`)管 `apps/*` + `packages/*`;`pnpm` 用 corepack 调用(`corepack pnpm@10 …`),无需全局装。 ## 3. apps/web —— 前端 多模块单页应用:统一外壳(顶栏 + 左侧三级导航 + 内容区),业务模块挂内容区。当前只有漏斗模块是实模块,其余是占位。 ``` apps/web/src/ ├── main.tsx / App.tsx # 入口 + 路由装配 ├── routes/domains.ts # L1/L2/L3 导航与路由数据(5 能力域,见 docs/01 §2) ├── layout/ # 外壳:AppLayout / NavTree(可折叠导航)/ Breadcrumb / ThemeToggle ├── api/ │ ├── funnel.ts # 查询客户端 + mock(queryFunnel / queryFunnelTrend);USE_MOCK 开关 │ ├── types.ts # 前端契约类型(手维护,镜像后端;见 packages/api-types) │ └── queryClient.ts # TanStack Query 客户端 ├── modules/ │ ├── funnel/ # ★ 拼团漏斗(唯一实模块) │ │ ├── FunnelPage.tsx # L3 页:漏斗 / 趋势 两视图 Tab(React 状态驱动) │ │ ├── FunnelView.tsx # 漏斗视图:单日(默认昨日)/ 近7 / 近30 快照 │ │ ├── TrendView.tsx # 趋势视图:UV 折线 + 转换率折线,范围 近30天/自定义 │ │ ├── period.ts # 固定 5 步定义、日期工具、范围/区间助手 │ │ ├── format.ts # UV / 比率格式化(null → "—",不补零) │ │ └── components/ # TimePeriodSelect / TrendRangeSelect / FunnelChart / TrendChart / FunnelResult / ResultTable │ └── placeholder/ # "待开发"占位页(非可用模块统一复用) └── components/ui/ # shadcn/ui 原语(button/card/calendar/tabs/popover/…) ``` 要点:ECharts 图(`FunnelChart`/`TrendChart`)**懒加载**拆独立 chunk;数据状态三态显式渲染——`ready` 出图、`missing` 出「暂无数据」(不补零)、传输错误出 Alert。 ## 4. apps/api —— 后端 只读查询服务。无写入、无 bitmap、无跨天聚合;数据源是预聚合的两张 ADS 表。详见 [apps/api/README.md](../apps/api/README.md)。 ``` apps/api/app/ ├── main.py # FastAPI 入口;按 STATIC_DIR 可选同源托管 SPA(线上单进程) ├── config.py # 设置(DATABASE_URL / DB_SCHEMA=ads / USE_FAKE_DATA) ├── schemas.py # Pydantic 契约(FunnelQuery* / FunnelTrend*) ├── api/funnels.py # 路由:POST /api/funnels/query、/api/funnels/trend ├── services/ │ ├── funnel.py # 编排 + 转化口径 + 校验 + 趋势裁前导0;FunnelRepository 协议 │ └── repository.py # SqlAlchemy 仓库(连真表)+ Fake 仓库(USE_FAKE_DATA) └── db/ ├── models.py # ORM:ads_trd_group_funnel_daily / _rolling(无 schema,靠 search_path=ads) └── session.py # async engine;真实连接挂 search_path=ads ``` `scripts/`:`export_openapi.py`(导 OpenAPI,无需 DB)、`seed.py`(本地假 PG 灌样例);`alembic/`(本地建表迁移)。**线上真实数据由上游 ETL 写入,不经 seed/alembic。** ## 5. packages/api-types 后端 `GET /openapi.json` → 生成前端 TS 类型,作为契约同步手段(`corepack pnpm@10 gen:api-types`)。当前前端实际用手维护的 `apps/web/src/api/types.ts`(刻意镜像契约,便于后续切换为生成类型)。 ## 6. infra | 文件 | 用途 | |---|---| | `look.sh` | **一键部署**:web 测试+构建 → 推 `feature`(源码)+`deploy`(产物)→ 服务器拉取 → 上线(仅 `/look` 显式触发) | | `serve-hs-api.sh` | 服务器单进程启动器(uvicorn 同源托管 SPA+API,端口 8080,脱离会话存活) | | `serve.py` | 旧纯静态 SPA 服(已被 uvicorn 同源托管取代,保留备用) | | `serve-start.sh` | 静态服守护启动器(历史,未启用) | | `setup.sh` | 服务器装依赖(历史脚手架) | | `docker-compose.yml` | 本地起 PostgreSQL(本地接真库时用) | ## 7. 运行流程 **线上**(单进程同源,见 docs/02 §10): ``` 浏览器 ──HTTP──▶ 服务器 100.64.0.62:8080 (uvicorn, ~/miniconda3 的 Python 3.11) ├── GET /、/assets/* → 托管 ~/hs-data 的 SPA 产物(STATIC_DIR,实时读盘) └── POST /api/funnels/* → 查 PostgreSQL 100.64.0.10:25432 (schema=ads) ``` 前端相对 `/api` 同源调用 → 免 CORS、免反代;只有一个常驻进程。 **本地开发**:Vite dev(:5173)跑前端,默认 `USE_MOCK` 直接出假数据,无需后端;需要时另起 uvicorn(:8000),Vite 代理 `/api` 过去。 **数据**:T+1,最大可查日为昨日。单日可回溯历史;近7/30天为滚动窗口(rolling 表唯一行,只有最新 as-of)。口径见 docs/02 §5–6。 ## 8. 构建与部署流程(`/look`) ``` 本地(Windows) pnpm test + build(VITE_USE_MOCK=false) │ 产物 apps/web/dist ▼ git push: feature(源码) + deploy(纯产物分支) ──▶ GitLab(git.hobbystocks.cn) │ 服务器(CentOS 7) git pull ▼ ~/hs-data ← deploy 分支(SPA 产物,uvicorn 实时读盘,前端改动免重启) ~/hs-api ← feature 分支(后端源码;仅当 apps/api 变更才重启 uvicorn) ``` CentOS 7 glibc 2.17 跑不了现代前端构建,故**本地构建、git 送达、服务器只托管+跑后端**;Python 3.11 用隔离 Miniconda,不动系统环境。细节见 docs/02 §10。 ## 9. 本地怎么跑 ```bash corepack pnpm@10 install corepack pnpm@10 --filter @hs-data/web dev # 前端(mock)→ http://localhost:5173 # 后端(可选,默认假数据) cd apps/api && python -m venv .venv && .venv/Scripts/python -m pip install -e ".[dev]" .venv/Scripts/uvicorn app.main:app --reload --port 8000 # http://localhost:8000/docs # 测试 corepack pnpm@10 --filter @hs-data/web test # 前端 Vitest cd apps/api && .venv/Scripts/pytest -q # 后端 pytest ```