diff --git a/README.md b/README.md index a747c47..115d396 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# TJWaterServerBinary 内部后端 +# NextTJWater Server -`TJWaterServerBinary` 是 TJWater 内部版 Python 后端,基于 FastAPI 提供认证、项目、管网、模拟、爆管、漏损、SCADA 和地图服务集成能力。该仓库用于内部开发和完整功能维护。 +`next-tjwater-server` 是 NextTJWater 供水系统的 FastAPI 后端,提供认证、项目、管网、模拟、爆管、漏损、SCADA、地图服务、工况任务和受控 MCP 能力。业务数据和时序数据按已认证项目路由,后台工作进程也必须使用明确的项目范围。 ## 技术栈 @@ -30,6 +30,14 @@ infra/docker/ Docker Compose 编排 ## 本地开发 +先从样板创建本地配置,再按启用的功能填写: + +```bash +cp .env.example .env +``` + +`.env` 只用于本地或部署主机运行,不得提交。生产配置由部署主机的受控环境文件注入,不将完整应用 `.env` 保存为 Gitea Actions 密钥。 + 推荐使用已有 conda 环境: ```bash @@ -45,11 +53,23 @@ conda activate server `GET /health` 是无需鉴权的 HTTP 服务存活检查,返回 `200` 和 `{"status":"ok"}`,不查询数据库。 `GET /ready` 检查应用启动状态、元数据库 `SELECT 1` 及已启用的 MCP 传输生命周期; -全部就绪返回 `200`,否则返回 `503`,元数据库探测预算为2秒。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` 路由为准,不会因为存在默认数据库变量而回退到固定项目。 + ## 常用命令 外围接入样板是独立进程,复用 PostgreSQL,不自动建表;启动、授权边界和契约见 [外围样板说明](docs/peripheral-sample.md)。 @@ -84,8 +104,8 @@ docker compose -f infra/docker/docker-compose.yml config - 元数据、业务库和 TimescaleDB 可以部署在同一主机,也可以分别部署。 在线重算会原子替换一个时刻的节点、管段基线。历史分块已经压缩时,写入事务使用 -`TIMESCALEDB_REALTIME_MAX_DECOMPRESSED_TUPLES` 设置解压预算,默认100万条;配置必须 -为正整数,不允许0。该设置仅在实时快照写入事务内生效,不改变数据库全局设置或普通读取。 +`TIMESCALEDB_REALTIME_MAX_DECOMPRESSED_TUPLES` 设置解压预算,默认 100 万条;配置必须 +为正整数,不允许 0。该设置仅在实时快照写入事务内生效,不改变数据库全局设置或普通读取。 预算按需根据受影响压缩批次的规模调整,超过预算仍会失败并回滚当前快照;此前完成的其他 时刻不会一起回滚。同步、异步及单表批量快照入口使用同一预算。 @@ -117,6 +137,19 @@ conda run -n server python scripts/publish_fengxian_map_layers.py --database tjw 发布命令需要配置 `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)。 + ## 测试与发布 提交前根据改动范围运行最小有效测试: @@ -131,7 +164,15 @@ conda run -n server python -m pytest tests/unit tests/auth -q docker build -t tjwater-server:local . ``` -Gitea 包工作流位于 `.gitea/workflows/package.yml`,通常由 tag 触发构建、推送镜像并通知部署 webhook。 +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` + +这些密钥只用于镜像仓库和受限开发机部署,不替代后端应用的运行环境配置。 ## 安全规则 @@ -139,4 +180,6 @@ Gitea 包工作流位于 `.gitea/workflows/package.yml`,通常由 tag 触发 ## 产品 MCP 查询 -Server 可选启用 MCP 2026-07-28 的25项项目查询及10项受控分析,默认关闭。它使用专用 OAuth resource Bearer、宿主绑定上下文及现有项目/任务权限,调查查询返回前持久化证据。启用需更新依赖、应用项目 SQL 迁移和配置 Keycloak token exchange;这些生产操作尚未执行。详见 [实施与启用](docs/mcp-query-implementation.md) 和 [协议/旧 CLI 能力对照](docs/mcp-query-design.md)。 +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)。