问题:infer.ts BASE_URL=/v1,fetchModels/chatCompletion 再拼 /v1/* 导致 /v1/v1 双前缀,当前仅靠 nginx 对 /v1/ rewrite 去前缀巧合耦合才通。 修复(前后端+部署一起改): 1. nginx-fba.conf:新增 location /v1/,proxy_pass http://127.0.0.1:30800/ (带末尾 /,不去前缀直接透传),消除对 rewrite 的隐式依赖。 2. infer.ts:BASE_URL 改为空串,调用方统一写 /v1/models、 /v1/chat/completions、/v1/health(fetchHealth 原误用 /health 已修正)。 3. cockpit/index.vue:健康检查改走 infer.ts 的 fetchHealth 封装, 不再裸 fetch('/v1/health'),路径口径统一。 4. ask() latencyMs 由硬编码 0 改为 performance.now() 实测耗时。 5. README 补充推理通道路径约定说明。 验收:浏览器 Network 确认 /v1/models、/v1/chat/completions、 /v1/health 均 200 且无 /v1/v1 请求。(本环境无 pnpm,构建验证转 bot_qa)
173 lines
8.5 KiB
Markdown
173 lines
8.5 KiB
Markdown
# 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 网关,**不去前缀直接透传**)
|
||
```
|
||
|
||
### 推理通道路径约定(issue #188)
|
||
- 推理服务真实路径即 `:30800/v1/*`(`/v1/models`、`/v1/chat/completions`、`/v1/health`)。
|
||
- nginx 反代 `/v1/` 用 `proxy_pass http://127.0.0.1:30800/`(带末尾 `/`,**不去前缀**,直接透传到后端的 `/v1/...`)。
|
||
- 前端 `api/iaop/infer.ts` 的 `BASE_URL` 为空串,调用方统一写 `/v1/models`、`/v1/chat/completions`、`/v1/health`,**不再出现 `/v1/v1` 双前缀**,也不依赖 nginx rewrite 去前缀的巧合耦合。
|
||
- nginx location 片段见 `deploy/fba/nginx-fba.conf`。
|
||
|
||
### 组件落点
|
||
- 受控源码:`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 接入版)
|
||
|
||
### 模型注册表服务(issue #182 [E1],PRD 5.3 服务化)
|
||
- 代码:`core/model-framework/registry_api.py`(标准库 http.server,零依赖)
|
||
- 运行:`REGISTRY_DATA_DIR=<可挂卷目录> python3 core/model-framework/registry_api.py`(默认 :8002,绑定 127.0.0.1)
|
||
- 数据:`REGISTRY_DATA_DIR/registry.json`(JSON 持久化;首次启动种子 4 条演示模型)
|
||
- 鉴权双轨:FBA JWT(`FBA_TOKEN_SECRET_KEY` 配置时启用,写操作要求 `iaop:admin`/`iaop:studio` 权限码);未配置时降级 core/auth 会话(engineer/admin 角色可写)
|
||
- **nginx 反代约定**(加到宿主机 nginx server):
|
||
```nginx
|
||
location /api/v1/registry/ {
|
||
proxy_pass http://127.0.0.1:8002;
|
||
proxy_set_header Host $host;
|
||
}
|
||
```
|
||
- 单测:`python core/model-framework/tests/test_registry_api.py`(11 用例:promote/rollback/403 权限拒绝/401/持久化)
|