# 管理后台前端代码修改记录 本文档记录每次对管理后台前端(**qy-lty-admin**,Next.js + React)代码的修改,方便追踪变更历史。 > **范围说明**:本仓库与服务端 [qy_lty](../../qy_lty/) 是独立项目,各自维护独立的修改记录。**仅记录本仓库(管理后台前端)改动**;跨项目联动改动需在 [qy_lty/docs/修改记录.md](../../qy_lty/docs/修改记录.md) 同期写一条相互引用的条目。 --- ## 修改格式说明 每次修改按以下格式记录: ``` ### [日期] 修改简述 - **文件路径**: 相对于项目根目录的文件路径 - **修改类型**: 新增 / 修改 / 删除 / 重构 / 修复Bug - **修改内容**: 具体修改了什么 - **修改原因**: 为什么要做这个修改 ``` --- ## 修改历史 ### [2026-05-08] Phase 1(前端)凭据槽位 API 客户端 配套服务端 Phase:[../qy_lty/.planning/phases/02-admin-rest/](../../qy_lty/.planning/phases/02-admin-rest/)(已落地,commit 46d72b8) 覆盖前端需求:CRED-FE-01 - **文件路径**: - `lib/api/credential-slot.ts`(新增) - `lib/api/index.ts`(修改) - **修改类型**: 新增(API 客户端层;纯逻辑,无 UI 改动) - **修改内容**: - 新建 `lib/api/credential-slot.ts`,封装: - 类型 `CredentialSlot { appId, accessTokenMasked, updatedAt }`(脱敏掩码语义命名) - 类型 `CredentialSlotUpdatePayload { appId, accessToken }`(明文语义命名) - 适配器 `mapBackendCredentialSlot()`(snake_case → camelCase) - API 函数 `getCredentialSlot()` / `updateCredentialSlot(payload)`,分别走 `apiClient.get` / `apiClient.put` 命中 `/v1/admin/credential-slot/`,沿用仓库统一的 `response.data?.data || response.data` 双保险解包;PUT body 仅传 `{ app_id, access_token }`,不携 `updated_at`(与 `updateAiModel` / `updateOutfit` 风格一致) - `lib/api/index.ts` 末尾追加具名 re-export,让组件层可 `import { getCredentialSlot, type CredentialSlot } from '@/lib/api'` - **修改原因**: - 启动 Milestone v1.0「通用凭据槽位前端集成」,本 phase 为后续 Phase 2(RBAC + 入口控件)、Phase 3(编辑对话框 + Sonner 反馈)提供调用层基础 - `accessTokenMasked` vs `accessToken` 故意命名不同,让 TS 编译期捕捉「把脱敏字符串当真值回写 PUT」的 bug - **跨项目联动**: 无 — 后端 commit 46d72b8 已建立互引;Phase 1 是纯 API client 层落地(无 UI 改动),调用的后端接口由 qy_lty 后端 Milestone v1.0 Phase 2 提供(commit `46d72b8` 已建立前后端互引修改记录);本 phase 不引入新跨项目代码契约,无需再次互引。前端 UI 集成(Phase 2 + 3)引入实质用户能力时再评估是否需要新一轮互引 - **服务端联动**: 同上「跨项目联动」字段;后端 commit `46d72b8` 已建立互引闭环,本 phase 无需再次互引 ### [2026-05-07] Phase 2 — 锁定后端通用凭据槽位 REST 接口契约(消费方文档化) 配套服务端 Phase:[../qy_lty/.planning/phases/02-admin-rest/](../../qy_lty/.planning/phases/02-admin-rest/) 覆盖服务端需求:CRED-03 + CRED-04(本仓库消费方) - **文件路径**: `docs/修改记录.md`(仅文档新增条目;本仓库代码未改) - **修改类型**: 新增(文档) - **修改内容**: - 文档化服务端在本日落地的 `/api/v1/admin/credential-slot/` REST 接口契约(GET 脱敏读取 + PUT 全字段覆写 + admin token 鉴权),为后续 Web 管理后台前端(本仓库)的 CRED-FE-* phase 写 API client 与表单 UI 留下契约锚点 - 接口契约要点(消费方视角): - URL:`{NEXT_PUBLIC_API_BASE_URL}/v1/admin/credential-slot/` - 鉴权:`Authorization: Bearer `(来源于 `/api/v1/admin/login/` 的现有 admin 登录返回值) - GET 响应:`{ success: boolean, code: number, message: string, data: { app_id: string, access_token: string /* 末 4 位脱敏掩码,前缀 * */, updated_at: string /* ISO 8601 */ } }` - PUT 请求体:`{ app_id?: string, access_token?: string }`(任一字段缺省时由后端兜底保留原值;写入是全字段覆写语义,建议前端 UI 始终提交两字段全集以避免歧义) - PUT 响应同 GET 形态(access_token 同样脱敏返回,前端**不应**用响应值回填明文输入框) - 错误矩阵:401(无 token / token 失效)、403(持非 admin token,message 含"需要管理员权限")、400(参数无效) - **修改原因**: - 服务端首次为本管理后台暴露受控的凭据读写接口;本仓库即将启动 CRED-FE-01(API client) + CRED-FE-02(表单录入页面)等 phase,先把后端契约固化进本仓库修改记录便于反查 - 文档化"GET 与 PUT 响应均脱敏 access_token"避免前端工程师误以为可以从响应回填明文表单(实际明文仅存于 DB;任何回填只能保留掩码或要求运营重新输入) - **服务端联动**: 后端联动条目 [../qy_lty/docs/修改记录.md](../../qy_lty/docs/修改记录.md) 同期 `[2026-05-07] Phase 2 — 管理端通用凭据槽位 REST 接口(GET 脱敏 / PUT 覆写)`。本仓库代码未改,仅文档侧做契约固化;待本仓库 CRED-FE-01 phase 启动落地 API client + Hook 时再补一条独立条目并互引 ### [2026-05-07] 修复 NEXT_PUBLIC_API_BASE_URL 注入时机错误(线上登录 Network Error) - **文件路径**: - `qy-lty-admin/Dockerfile` - `.gitea/workflows/deploy.yaml`(仓库根目录,与本前端构建/部署链直接相关) - `k8s/admin-deployment-prod.yaml`(仓库根目录,与本前端构建/部署链直接相关) - **修改类型**: 修复Bug - **修改内容**: - `qy-lty-admin/Dockerfile`:在 `COPY . .` 之后、`RUN yarn build` 之前新增 `ARG NEXT_PUBLIC_API_BASE_URL` 与 `ENV NEXT_PUBLIC_API_BASE_URL=${NEXT_PUBLIC_API_BASE_URL}`,让该值在 build 期可被注入 - `.gitea/workflows/deploy.yaml`:在 admin 镜像 `docker build` 命令上加 `--build-arg NEXT_PUBLIC_API_BASE_URL=https://${DOMAIN_API}/api`(test 环境拼成 `https://qy-lty.test.airlabs.art/api`,prod 环境拼成 `https://qy-lty.airlabs.art/api`);同时删除 `Replace domain placeholders by environment` 段中已失效的 `sed -i "s|https://qy-lty.airlabs.art|https://${DOMAIN_API}|g" k8s/admin-deployment-prod.yaml` - `k8s/admin-deployment-prod.yaml`:删除运行时无效的 `env: NEXT_PUBLIC_API_BASE_URL=https://qy-lty.airlabs.art`,改为注释说明该变量必须在 docker build 时通过 `--build-arg` 注入 - **修改原因**: - 线上 https://qy-lty-admin.test.airlabs.art/login 点登录弹 "Network Error"。DevTools 抓到 Request URL 是 `http://localhost:8000/api/v1/admin/login/`,对应 `lib/api/client.ts` 中 `process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000/api"` 的 fallback 值。 - 根因:Next.js 的 `NEXT_PUBLIC_*` 变量在 `next build` 时被静态编译进客户端 JS 包,运行时再设置容器环境变量已经无效。原 Dockerfile 没有 `ARG/ENV`,原 deploy.yaml 没有 `--build-arg`,只有 `k8s/admin-deployment-prod.yaml` 在容器运行时设了变量——所以打包出的镜像里硬编码的是默认 fallback `http://localhost:8000/api`,前端 HTTPS 页面去打本机的 8000 端口,浏览器报 `ERR_CONNECTION_REFUSED`,axios 包装为 "Network Error"。 - 修复后构建期会把正确的 `https://qy-lty.test.airlabs.art/api` / `https://qy-lty.airlabs.art/api` 编译进 JS 包,登录请求会正确打到后端。 - 备注:原 `k8s/admin-deployment-prod.yaml` 写的是 `https://qy-lty.airlabs.art`(**缺少 `/api` 后缀**),即便注入时机正确,路径也会拼错(`/v1/admin/login/` 而非 `/api/v1/admin/login/`),双重 bug。本次修复一并纠正。 - **服务端联动**: 本次修复仅涉及前端构建链与部署配置,未改动 `qy_lty` 后端代码,无需在服务端写联动条目。 --- ### [2026-04-30] 初始化 CLAUDE.md 与 docs/修改记录.md 骨架 - **文件路径**: `CLAUDE.md`、`docs/修改记录.md` - **修改类型**: 新增 - **修改内容**: - 新建 `CLAUDE.md`:写明项目身份(Next.js 15 App Router + React 19 后台)、技术栈、路由分组、鉴权与权限模型、与 `qy_lty` 后端的依赖关系,并嵌入"项目修改记录规则(重要 — 自动执行)"段落 - 新建本文件 `docs/修改记录.md`:以 `qy_lty/docs/修改记录.md` 同名文件为骨架,划清"仅记录管理后台前端改动"的边界 - **修改原因**: - 此前本仓库无 CLAUDE.md 和修改记录文档,新会话进入工作时缺乏上下文锚点;与服务端 `qy_lty` 项目的改动追踪互不可见 - 配套服务端 `qy_lty/CLAUDE.md` 同日新增的"项目修改记录规则"段落,要求两端各自独立维护修改记录、跨项目联动改动相互引用,从源头避免漏记和混记 - 服务端同期条目:[qy_lty/docs/修改记录.md](../../qy_lty/docs/修改记录.md) 2026-04-30 "CLAUDE.md 新增项目修改记录规则段落"