Files
iAOP/deploy/fba/README.md
bot_dev1 609fda0505 feat(#182): 模型注册表后端化 TemplateRegistry 服务化 HTTP API(E1)
新增 core/model-framework/registry_api.py(标准库 http.server,对齐 auth_api
风格,零依赖),把已交付的 TemplateRegistry 暴露为 HTTP 服务:

- GET  /api/v1/registry/models                 列表(可按 stage 过滤)
- POST /api/v1/registry/models                 注册新版本(服务端校验)
- POST /api/v1/registry/models/{name}/{version}/promote   dev→staging→prod
- POST /api/v1/registry/models/{name}/rollback?version=&stage=  回滚指定 stage

服务端持久化:PersistedRegistry 每次写操作原子落盘到
deploy/data/registry/registry.json(可挂卷),重启不丢;首次启动自动播种
4 条演示模型(对齐 web/admin/admin.js seedModels)。

鉴权双轨:读接 FBA JWT(core/auth/fba_jwt.py),写要求权限码 iaop:admin
或 iaop:studio;未配置 FBA_TOKEN_SECRET_KEY 降级旧 core/auth 会话;
两者均无时为本地/CI 演示模式(读免鉴权、写需 token 占位)。

测试:tests/test_registry_api.py(16 例,含四接口回环联调、401/403 路径、
promote/rollback/持久化/种子)+ _fba_stub.py(FBA 桩)。全 284 例通过。

部署:deploy/fba/README.md 补 nginx 反代 /api/v1/registry/ → :8090 约定。
2026-08-06 15:30:57 +08:00

191 lines
8.6 KiB
Markdown
Raw Permalink 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.
# iAOP · FBA 基础设施部署(Epic #159 · Phase 0)
将 [fastapi-best-architecture](https://github.com/fastapi-practices/fastapi-best-architecture)
(下称 FBA)作为 iAOP 的统一认证 / 用户角色权限基座,以 Docker 方式与现有 iAOP
服务并行部署,由宿主机现有 nginx 以 `/fba/` 前缀统一反代。
## 架构位置
```
浏览器
│ http://39.101.182.167:8090
▼
宿主机 nginx(现有 iAOP 站点)
├── / → iAOP 前端(web/ 静态)
├── /api/v1/ → iAOP 后端(现有 FastAPI,业务接口)
└── /fba/ → 127.0.0.1:8001 → fba_server(FBA 后端,认证/RBAC)
├── fba_postgres(PG16)
└── fba_redis
```
> iAOP 自身也使用 `/api/v1` 前缀,因此 FBA 必须通过 `/fba/` 前缀隔离,
> 两者不能共用路径。
## 前置条件
1. 服务器已安装 Docker 与 Docker Compose 插件(`docker compose version` 可查)。
2. 获取 FBA 源码,放到本仓库同级目录:
```bash
cd /opt/apps # 假设 iAOP 在 /opt/apps/iAOP
git clone https://github.com/fastapi-practices/fastapi-best-architecture fba-backend
```
若放在其他位置,修改 `compose.env` 中的 `FBA_SRC`。
## 部署步骤
```bash
cd /opt/apps/iAOP/deploy/fba
# 1. 修改密钥与密码(生产必做)
# - compose.env: FBA_PG_PASSWORD
# - fba.env: DATABASE_PASSWORD(与上一致)、TOKEN_SECRET_KEY
python3 -c "import secrets; print(secrets.token_urlsafe(32))" # 生成 TOKEN_SECRET_KEY
# 2. 构建并启动
docker compose --env-file compose.env up -d --build
# 3. 初始化数据库表结构 + 内置数据(菜单/角色/管理员)
docker exec -it fba_server fba init
# 若 fba 命令不可用,改用:docker exec -it fba_server python backend/cli.py init
# 4. 验证服务
curl -s http://127.0.0.1:8001/api/v1/auth/captcha | head -c 200
# 5. 合并 nginx 片段(见 nginx-fba.conf 头部说明),然后 reload
nginx -t && nginx -s reload
# 6. 通过外部入口验证
curl -s http://39.101.182.167:8090/fba/api/v1/auth/captcha | head -c 200
```
FBA 默认管理员账号:`admin / 123456`(登录后请立即修改)。
## 常用运维命令
```bash
docker compose --env-file compose.env logs -f fba_server # 看日志
docker compose --env-file compose.env restart fba_server # 重启
docker compose --env-file compose.env down # 停止(数据保留在卷中)
docker exec -it fba_postgres psql -U postgres -d fba # 进数据库
```
## 与 iAOP 代码侧的关系(后续 Phase)
- **Phase 1**:iAOP 前端 `web/shared/session.js` 改为调用
`/fba/api/v1/auth/login`(JSON 登录)与 `/fba/api/v1/auth/codes`
(授权码)做登录与鉴权,现有 `core/auth` 退役。
- **Phase 2**:Sider 菜单由 FBA `sys_menu` 接口驱动(`GET /fba/api/v1/sys/menus/sidebar`,
服务端按角色授权过滤),替代前端硬编码角色过滤。**需先执行菜单播种**:
```bash
python3 deploy/fba/seed_iaop_menus.py \
--base http://127.0.0.1:8001/api/v1 \
--username admin --password '<FBA管理员密码>'
```
脚本幂等:注册 iAOP 6 模块菜单(含子菜单)、创建 `engineer`/`viewer`
角色并按 PRD 8.2 分配菜单。之后在 FBA 后台给用户分配角色即可。
未播种时前端自动降级为本地角色过滤,菜单不会空白。
- **Phase 3**:FBA UI(Vue3 + AntDV)管理界面已预构建,产物在
`deploy/fba/artifacts/fba-ui-dist.tar.gz`(构建参数 `VITE_BASE=/fba-admin/`、
`VITE_GLOB_API_URL=http://39.101.182.167:8090/fba`)。部署:
```bash
cd /opt/apps/iAOP
mkdir -p deploy/fba/fba-ui
tar -xzf deploy/fba/artifacts/fba-ui-dist.tar.gz -C deploy/fba/fba-ui/
# 确认 nginx 已 include 最新 nginx-fba.conf(含 /fba-admin/ 段)后 reload
nginx -t && nginx -s reload
```
入口 `http://39.101.182.167:8090/fba-admin/`,用 FBA 账号登录即可管理
用户/角色/菜单/日志。iAOP 顶栏对 admin 角色提供「系统管理」直达链接。
若需重新构建(如换域名):改 `fba-ui/apps/web-antdv-next/.env.production`
后 `pnpm --filter @vben/web-antdv-next build`(Vben5 monorepo,需 pnpm)。
- **Phase 4**:业务接口按钮级权限。
- 前端:`IAOP_SESSION.perms()` / `hasPerm(code)` 读取 FBA `/auth/codes`
权限码(超管自动拥有全部;菜单播种时已写入 `iaop:<module>`)。
- 后端:`core/auth/fba_jwt.py` 提供零依赖 HS256 校验器 `FbaAuth`
(与 FBA 的 JWT 同构:claims = sub/session_uuid/exp,密钥取环境变量
`FBA_TOKEN_SECRET_KEY`,**必须与 fba.env 的 TOKEN_SECRET_KEY 一致**)。
业务服务内 `FbaAuth.from_env()` 返回 None 时走旧 core/auth 会话(双轨过渡)。
按钮级校验用 `fba.require_perm(authorization, "iaop:xxx")`(回源
`/auth/codes`,带 5 分钟内存缓存)。
- 单元测试:`python -m unittest core.auth.tests.test_fba_jwt -v`(8 例全过)。
- **Phase 5**:收尾。待全部 Phase 部署验收后:旧 core/auth 登录轨与
UserStore 本地账号降级保留为演示模式;生产环境以 FBA 为唯一认证源。
## 注意事项
- `fba_postgres` / `fba_redis` 不映射宿主端口,仅容器网络内可达;
`fba_server` 仅绑定 `127.0.0.1:8001`。
- iAOP 现有数据(SQLite 业务库)与 FBA 的 PG 库完全独立,Phase 0 不迁移任何数据。
- FBA 源码目录(`fba-backend`)不属于本仓库,升级 FBA 时在
`fba-backend` 目录内 `git pull` 后重新 `--build` 即可。
---
## Epic #163 · FBA UI 原生重构(2026-08,issue #164-#177)
### 新架构
```
浏览器
│ http://39.101.182.167:8090
▼
宿主机 nginx(deploy/fba/nginx-fba.conf)
├── / → iAOP 静态外壳(web/,C1 后自动收口到 /fba-admin/)
├── /fba-admin/ → FBA UI 原生版(Vben5 web-antdv-next,构建产物 dist/)
│ · 菜单由 FBA 后端下发(seed_iaop_menus.py v2,type=1 原生菜单)
│ · 6 模块 → views/iaop/*(cockpit/chat/studio/admin)
│ · 推理通道 /v1/ → 127.0.0.1:30800(推理服务,独立于 /fba)
├── /fba/ → 127.0.0.1:8001 fba_server(认证/RBAC/系统管理)
└── /v1/ → 127.0.0.1:30800 推理服务(iAOP LLM 网关)
```
### 组件落点
- 受控源码:`fba-ui-src/`(fastapi-best-architecture-ui 工程,apps/web-antdv-next)
- 构建流水线:`build-ui.sh`(pnpm install → build → artifacts/fba-ui-dist.tar.gz)
- 菜单播种 v2:`seed_iaop_menus.py`(幂等 upsert + admin 角色 + 退役菜单隐藏)
- 部署:解包 dist → 替换 fba_ui 容器站点目录 → nginx reload(见 C2 验证记录)
### 旧架构存档
- `web/` 静态演示外壳保留(FBA 停掉时兜底;/index.html、/auth/login.html 已加 C1 自动收口跳转)
- 旧登录页三轨会话已精简为 FBA 单轨(session.js,FBA 接入版)
---
## 模型注册表 API 反代(issue #182,PRD 5.3 ③)
iAOP 后端的模型模板注册表(`core/model-framework/registry_api.py`)以独立
`http.server` 服务运行(默认 `127.0.0.1:8090`,零依赖标准库实现)。前端模型管理 /
版本发布(E2,issue #183)通过 nginx 把 `/api/v1/registry/` 反代到该端口:
```
location /api/v1/registry/ {
proxy_pass http://127.0.0.1:8090/api/v1/registry/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
```
服务启动:
```bash
cd /opt/apps/iAOP
# 配置 FBA 密钥后(与 fba.env 的 TOKEN_SECRET_KEY 一致)写操作接 FBA JWT 鉴权
export FBA_TOKEN_SECRET_KEY=<同 fba.env>
python -m core.model_framework.registry_api
# → iAOP RegistryAPI on http://127.0.0.1:8090 (data=deploy/data/registry/registry.json, fba=on)
```
数据落盘到 `deploy/data/registry/registry.json`(生产可挂卷),重启不丢。
首次启动自动播种 4 条演示模型(与 `web/admin/admin.js` 的 `seedModels()` 对齐)。
鉴权双轨:读接口接 FBA JWT(`FbaAuth.verify`);写接口要求权限码 `iaop:admin` 或
`iaop:studio`。未配置 `FBA_TOKEN_SECRET_KEY` 时降级旧 `core/auth` 会话(写权限由
角色 admin/engineer 判定);两者均未配置时为本地/CI 演示模式——读免鉴权、写需
带任意 token 占位(避免裸奔写)。