Files
next-tjwater-server/README.md
T
jiang 6d31f456e6
Generic Container CI/CD / test-build-publish (push) Successful in 2m59s
Server CI/CD v2 / build-test-publish-and-deploy (push) Successful in 2m59s
feat: mount peripheral API in main server
2026-10-23 16:05:56 +08:00

186 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NextTJWater Server
`next-tjwater-server` 是 NextTJWater 供水系统的 FastAPI 后端,提供认证、项目、管网、模拟、爆管、漏损、SCADA、地图服务、工况任务和受控 MCP 能力。业务数据和时序数据按已认证项目路由,后台工作进程也必须使用明确的项目范围。
## 技术栈
- Python 3.12
- FastAPI / Uvicorn
- Pydantic / SQLAlchemy / psycopg
- PostgreSQL、PostGIS、TimescaleDB
- WNTR、EPANET、Cython、科学计算与空间分析依赖
- pytest
## 目录结构
```text
app/main.py FastAPI 入口
app/api/ HTTP API 路由
app/auth/ 认证和权限上下文
app/core/ 配置、日志和基础设施初始化
app/domain/ 领域模型和 Pydantic schema
app/infra/ 数据库、EPANET 和外部集成
app/services/ 业务服务编排
app/algorithms/ 管网算法、模拟、爆管、漏损、清洗和健康分析
app/native/ 本地管网数据读写与转换
tests/ 后端测试
resources/ SQL、模板和示例资源
infra/docker/ Docker Compose 编排
```
## 本地开发
先从样板创建本地配置,再按启用的功能填写:
```bash
cp .env.example .env
```
`.env` 只用于本地或部署主机运行,不得提交。生产配置由部署主机的受控环境文件注入,不将完整应用 `.env` 保存为 Gitea Actions 密钥。
推荐使用已有 conda 环境:
```bash
conda run -n server python -m pytest tests/unit tests/auth -q
conda run -n server uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
```
如需要进入环境:
```bash
conda activate server
```
`GET /health` 是无需鉴权的 HTTP 服务存活检查,返回 `200` 和 `{"status":"ok"}`,不查询数据库。
`GET /ready` 检查应用启动状态、元数据库 `SELECT 1` 及已启用的 MCP 传输生命周期;
全部就绪返回 `200`,否则返回 `503`,元数据库探测预算为 2 秒。MCP 关闭时标记为
`disabled`,不阻止就绪。返回结果不包含数据库地址、凭据或原始异常,禁止缓存。
就绪状态不等同于 OAuth、用户权限或真实工具调用成功;指定项目的业务库和时序库仍通过
带身份与 `X-Project-Id` 的 `GET /api/v1/projects/current/database-health` 检查。
## 环境配置
`.env.example` 是唯一应提交的环境配置样板,主要分为以下几组:
- 元数据库、项目业务库、TimescaleDB 及项目数据库连接池。
- GeoServer 项目供应、Keycloak JWT 校验、CORS 和工作台事件。
- 天地图地理编码和地名搜索。
- 调查任务 worker、外围工单同步、数据与动作适配器。
- 可选的 MCP resource、OAuth issuer、宿主和超时预算。
基础数据库变量用于启动和项目供应。运行时的项目请求仍以元数据库中的 `biz_data` 和 `iot_data` 路由为准,不会因为存在默认数据库变量而回退到固定项目。
## 常用命令
外围接入样板作为 `/peripheral` 子应用随主 API 进程启动,复用 PostgreSQL 且不自动建表;授权边界和契约见 [外围样板说明](docs/peripheral-sample.md)。
外围样板提供 synthetic 测试工单和测试数据的版本化 CRUD;工单经同步器投影为 `workbench.operational_tasks` 中的外围来源任务。固定演示时窗和造数方式见 [合成样本说明](docs/peripheral-generated-data.md),运行态读取边界见 [工作台运行态说明](docs/workbench-runtime.md)。这些数据不代表现场事实,也不会触发设备控制。
```bash
conda run -n server python -m pytest tests -q
conda run -n server python scripts/run_server.py
docker build -t tjwater-server:local .
docker compose -f infra/docker/docker-compose.yml config
```
- `pytest`:运行自动化测试。
- `scripts/run_server.py`:使用项目脚本启动服务。
- `docker build`:构建后端镜像。
- `docker compose config`:检查 compose 配置和变量展开。
## 开发规范
- Python 文件、函数、变量、Pydantic 字段、JSON body 字段和 query 参数使用 `snake_case`。
- Python 类和 Pydantic 模型使用 `PascalCase`。
- 新 HTTP 路径使用 `kebab-case`,例如 `/api/v1/pressure-status/analyze`。
- 优先复用现有 FastAPI/service/repository 边界。
- 不要把临时数据、数据库 dump、日志或本地运行产物纳入提交。
## 项目数据库路由
项目级 REST 请求通过 `X-Project-Id` 解析元数据中的数据库配置:
- `biz_data` DSN 用于管网业务数据。每个物理业务库使用同名 `_template` 数据库,通过逻辑订阅只同步 `network` schema;模拟临时库从该项目模板克隆。`WNDB_SCHEMA_TEMPLATE_DB_NAME`(当前为 `tjwater_v2_schema_template`)仅用于创建空业务库和 INP 导入暂存库。
- `iot_data` DSN 用于 TimescaleDB,始终使用元数据配置的完整 DSN,不再从项目代码推导数据库名。
- 元数据、业务库和 TimescaleDB 可以部署在同一主机,也可以分别部署。
在线重算会原子替换一个时刻的节点、管段基线。历史分块已经压缩时,写入事务使用
`TIMESCALEDB_REALTIME_MAX_DECOMPRESSED_TUPLES` 设置解压预算,默认 100 万条;配置必须
为正整数,不允许 0。该设置仅在实时快照写入事务内生效,不改变数据库全局设置或普通读取。
预算按需根据受影响压缩批次的规模调整,超过预算仍会失败并回滚当前快照;此前完成的其他
时刻不会一起回滚。同步、异步及单表批量快照入口使用同一预算。
压缩写入回归位于 `tests/integration/test_realtime_compression.py`;仅在设置
`REALTIME_COMPRESSION_TEST_DSN` 时执行,并且只接受库名以 `tjw_test_realtime_` 开头的
独立可丢弃数据库。测试会创建和删除该库内的 `realtime` schema,禁止指向项目数据库。
完整新建供水项目使用 `POST /api/v1/admin/project-provisions`,以
`multipart/form-data` 同时提交 `name`、小写 `code`、可选的
`description`、`gs_workspace`、`map_zoom` 和 INP `file`。工作流会按顺序完成:
1. EPANET 校验 INP,并从空结构模板创建业务库、导入模型;
2. 创建同名 `_template`,复制 32 张 `network` 表并建立逻辑订阅;
3. 从 `TIMESCALEDB_SCHEMA_TEMPLATE_DB_NAME` 创建空时序库;
4. 创建 GeoServer 工作空间、PostGIS 数据存储和 7 个 GIS 图层,将客户端缓存设为 `GEOSERVER_CLIENT_CACHE_SECONDS`;
5. 最后在一个元数据事务中写入项目、两条加密数据库路由和创建者成员关系,并将项目设为 `active`。
基础设施任一步失败时按 GeoServer、时序库、管网模板、业务库的逆序清理;元数据提交失败也执行同样清理。旧 `POST /admin/projects` 仅保留给已经由外部流程创建好的资源登记使用,并已标记为 deprecated。
使用模板复制或临时方案库的模拟功能时,`biz_data` 账号必须具备数据库创建和删除权限;只有显式删除项目时才会终止该项目的现有数据库会话,普通复制不会主动中断复制源会话。
奉贤项目的原始 GIS 与水质监测点使用独立脚本维护。导入脚本读取两份交付目录并写入项目 BizDB;水质脚本调用现有灵敏度分析服务生成 50 个监测点;发布脚本创建 10 个项目图层并刷新 GeoServer 缓存:
```bash
conda run -n server python scripts/import_fengxian_gis.py --database tjwater_v2
conda run -n server python scripts/generate_fengxian_water_quality_points.py --project tjwater_v2
conda run -n server python scripts/publish_fengxian_map_layers.py --database tjwater_v2 --workspace tjwater_next
```
发布命令需要配置 `GEOSERVER_URL`、`GEOSERVER_USERNAME` 和 `GEOSERVER_PASSWORD`。其中 7 个基础管网图层仍由项目供应流程创建,奉贤发布脚本追加 9 个原始 GIS 图层和 1 个水质监测点图层。
## 工况任务工作进程
调查任务 worker 和外围工单同步器是独立进程,不随 API 进程自动启动:
```bash
conda run -n server python scripts/run_operational_worker.py
conda run -n server python scripts/sync_peripheral_work_orders.py
```
`OPERATIONAL_WORKER_PROJECT_IDS` 是逗号分隔的显式项目 UUID 列表,非空时优先于单项目兼容变量 `OPERATIONAL_WORKER_PROJECT_ID`。如需覆盖所有已启用项目,应将这些项目的 UUID 全部明确写入列表。进程不会自动枚举项目,配置列表也不会自动授权;服务身份必须是每个目标项目的有效成员。
每个项目保持独立的事件游标、会话、消息游标和 OAuth 缓存。`OPERATIONAL_WORKER_MAX_CONCURRENCY` 是每个项目的上限,而不是全局上限。更改项目列表后,需要同时重启 worker 和外围同步器。完整配置、授权和重试边界见 [工况工作进程说明](docs/operational-task-workers.md)。
## 测试与发布
提交前根据改动范围运行最小有效测试:
```bash
conda run -n server python -m pytest tests/unit tests/auth -q
```
发布镜像前建议运行:
```bash
docker build -t tjwater-server:local .
```
Dockerfile 的 `test` 阶段会执行 Python 编译检查、应用导入、OpenAPI 检查和完整 pytest。
Gitea Actions 工作流位于 `.gitea/workflows/package.yml`,可手动触发,也会在推送 `v*` tag 时运行。工作流构建 `test` 阶段,推送不可变的 `sha-*` 镜像,然后通过受限 SSH 账号对 `next-backend` 执行候选验证。只有 tag 工作流会在验证通过后提升正式版本。仓库需要以下 Actions secrets:
- `REGISTRY_USERNAME`
- `REGISTRY_PASSWORD`
- `DEV_DEPLOY_SSH_KEY`
这些密钥只用于镜像仓库和受限开发机部署,不替代后端应用的运行环境配置。
## 安全规则
不要提交 `.env`、客户数据、数据库 dump、日志、生成缓存、`db_inp/`、`temp/`、`data/` 或本地密钥。CI/CD 凭据应放在 Gitea secrets 和仓库变量中。
## 产品 MCP 查询
Server 可选启用 MCP 2026-07-28,默认关闭。当前目录包含 67 项类型化工具,其中 42 项查询、12 项计算、13 项预览式写入。MCP 使用专用 OAuth resource Bearer、宿主绑定上下文和现有项目或任务权限,不提供自由命令执行。
写入工具默认只执行 `dry_run`。真实写入必须使用同一 `request_id`,带上预览返回的 `expected_digest`,并通过宿主原生许可和项目权限检查。超时或结果不明时先查询操作状态,不盲目重试。实施、启用和授权边界见 [MCP 实施与启用](docs/mcp-query-implementation.md) 和 [协议与旧 CLI 能力对照](docs/mcp-query-design.md)。