Files
ftb-project-management/docs/superpowers/specs/2026-07-02-local-cloud-single-source-data-design.md
2026-07-02 14:58:30 +08:00

6.1 KiB
Raw Blame History

外网与本地访问地址共享同一数据设计

背景

用户澄清后的真实问题不是“两台服务器之间同步数据”,而是:同一套项目系统通过外网地址访问、通过本地/内网地址访问时,应该看到同一份业务数据。

当前仓库同时提供:

  • docker-compose.prod.yml:云服务器生产栈,使用 postgres_dataredis_dataserver_data
  • docker-compose.local.yml:本地服务器/LAN 栈,使用 local_postgres_datalocal_redis_datalocal_server_data

如果为了同一套业务同时启动这两套栈,外网地址和本地地址很可能分别打到不同的 Compose project、不同的 PostgreSQL volume因此会看到两套数据。

目标

  • 外网访问地址和本地/内网访问地址进入同一套运行中的服务栈。
  • 同一套服务栈只使用一个 PostgreSQL 主数据 volume。
  • 用户从任意入口创建或修改产品、项目、版本、任务、测试用例、Bug 后,从另一个入口刷新能看到相同数据。
  • 文档明确区分“同一套系统的多个访问入口”和“独立本地演示环境”。
  • 避免把这个需求误实现为双向同步或跨服务器数据库复制。

非目标

  • 不做本地数据库和云端数据库的双向同步。
  • 不要求本地服务器连接云服务器数据库。
  • 不迁移 AI Provider 配置文件到数据库。
  • 不引入后台同步任务、冲突合并队列或数据库复制方案。

推荐方案

采用“单部署栈,多访问入口”的模式。

无论用户从外网域名、服务器公网 IP、局域网 IP还是本机地址访问都应该进入同一个 Nginx然后由该 Nginx 转发到同一个 webserver,最终读写同一个 PostgreSQL。

外网地址 / 域名
  -> 同一个 Nginx
  -> 同一个 NestJS server
  -> 同一个 PostgreSQL volume

本地 / 内网地址
  -> 同一个 Nginx
  -> 同一个 NestJS server
  -> 同一个 PostgreSQL volume

前端继续使用同域 API

NEXT_PUBLIC_API_URL=/api/v1

这样浏览器从哪个地址打开页面,就向该地址下的 /api/v1 发请求。只要这些地址最终落到同一套 Nginx/server数据天然一致。

部署模式

1. 生产/正式业务栈

正式业务只运行一套 Compose例如云服务器上运行 docker-compose.prod.yml

该栈可以同时支持:

  • 外网域名:https://pm.example.com
  • 公网 IPhttp://x.x.x.x
  • 内网 IPhttp://192.168.1.50
  • 本机访问:http://localhost

这些访问方式只要都进入同一个 Nginx就会共享同一份数据。

2. 本地/LAN 演示栈

docker-compose.local.yml 只能用于一套独立的本地/LAN 演示环境。它默认使用 local_* volumes不会和生产栈共享数据。

文档必须明确:如果用户希望外网地址和本地地址看到同一份正式业务数据,不要同时运行 local 栈和 prod 栈来承载同一套业务。

配置设计

Nginx

当前 deploy/nginx/default.conf.template 只有一个 server block并使用

server_name ${SERVER_NAME};

因为同一个 Nginx 容器只有这一套 80 端口 server block即使 Host 不匹配Nginx 也会把请求落到该默认 server block。因此外网域名和内网 IP 在多数单站点部署中已经可以进入同一套服务。

文档需要补充:

  • SERVER_NAME 可以保留主域名。
  • 如果服务器上存在外层 Nginx、多站点配置或严格 host 路由,需要把外网域名和内网访问名都转发到同一套 Compose Nginx。
  • 不要为外网和本地访问分别启动两套 Compose。

前端 API

NEXT_PUBLIC_API_URL 应保持:

NEXT_PUBLIC_API_URL=/api/v1

不要为外网和本地访问分别写成不同绝对 API 地址。绝对地址可能让不同入口打到不同后端,重新制造数据分叉。

NextAuth URL

NEXTAUTH_URL 继续使用主要正式访问地址。当前系统的业务数据读写不依赖浏览器 localStorage 作为主存储;数据一致性的关键是 /api/v1 是否落到同一个后端和数据库。

如果后续接入 OAuth 回调,需要再评估多 Host 登录体验,但这不影响本次业务数据一致性设计。

文档与脚本调整

需要更新:

  • docs/deployment.md:新增“同一部署多入口访问”说明;强调外网/内网要进入同一套 Compose。
  • docs/architecture.md:生产部署边界改为“一个正式业务栈可以有多个访问入口”。
  • docs/decisions.md:增加决策,外网/本地地址一致性通过同一部署栈保证,不做数据同步。
  • docs/workflow.md:部署流程提示不要为同一业务同时启动 prod 和 local 两套栈。
  • .env.production.example:注释说明 SERVER_NAME 是主要域名,内网 IP 通常也会命中同一 Nginx多站点环境需显式路由。
  • .env.local-server.example:注释说明该文件用于独立本地/LAN 演示库,不会与生产数据一致。
  • scripts/verify-production-deploy.mjs:增加部署文档关键语句校验,避免后续文档丢失这个约束。

验证方式

实现后需要验证:

  1. pnpm deploy:verify 通过。
  2. pnpm --filter web type-check 通过。
  3. pnpm --filter server type-check 通过。
  4. 正式栈启动后,外网地址访问 /api/v1/config/ai 返回 200。
  5. 同一台服务器的本地/内网地址访问 /api/v1/config/ai 返回 200。
  6. 从外网地址创建一条业务数据后,从本地/内网地址刷新能看到。
  7. 从本地/内网地址修改同一条业务数据后,从外网地址刷新能看到。

风险与处理

  • 如果外网地址和本地地址分别指向不同 Compose project数据仍会分叉。处理方式是停止其中一套业务栈只保留一个正式业务栈。
  • 如果 NEXT_PUBLIC_API_URL 被配置成绝对 URL不同入口可能绕到不同后端。处理方式是正式同域部署保持 /api/v1
  • 如果机器上还有外层 Nginx 或宝塔面板,多 Host 需要全部反代到同一套 Compose Nginx。
  • 本地/LAN 演示栈仍然有价值,但它是独立演示环境,不承诺与正式业务数据一致。