Files
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
..

iAOP · FBA 基础设施部署(Epic #159 · Phase 0)

将 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 源码,放到本仓库同级目录:

    cd /opt/apps                       # 假设 iAOP 在 /opt/apps/iAOP
    git clone https://github.com/fastapi-practices/fastapi-best-architecture fba-backend
    

    若放在其他位置,修改 compose.env 中的 FBA_SRC。

部署步骤

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(登录后请立即修改)。

常用运维命令

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, 服务端按角色授权过滤),替代前端硬编码角色过滤。需先执行菜单播种:
    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)。部署:
    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 "";
}

服务启动:

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 占位(避免裸奔写)。