给新接手者的"地图":目录层级、各模块职责、运行与部署流程。细节散落各专题文档,本文只做总览 + 指路。 关联:产品/IA docs/01、技术架构与契约 docs/02、数据契约 docs/03、设计规范 docs/04、接口 docs/06、迭代与发布 docs/08。
hs-data 是内部一站式数据平台(monorepo)。当前 MVP 端到端做通一个 L3 报表——拼团漏斗(行为分析 > 漏斗分析 > 拼团漏斗),含两个视图:漏斗(固定 5 步快照)与趋势(按日折线)。其余能力域进导航、出"待开发"占位。
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 …),无需全局装。
多模块单页应用:统一外壳(顶栏 + 左侧三级导航 + 内容区),业务模块挂内容区。当前只有漏斗模块是实模块,其余是占位。
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。
只读查询服务。无写入、无 bitmap、无跨天聚合;数据源是预聚合的两张 ADS 表。详见 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。
后端 GET /openapi.json → 生成前端 TS 类型,作为契约同步手段(corepack pnpm@10 gen:api-types)。当前前端实际用手维护的 apps/web/src/api/types.ts(刻意镜像契约,便于后续切换为生成类型)。
| 文件 | 用途 |
|---|---|
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(本地接真库时用) |
线上(单进程同源,见 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。
/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。
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