diff --git a/app/api/admin/channel/type-name/route.ts b/app/api/admin/channel/type-name/route.ts index bff2656..b37c48d 100644 --- a/app/api/admin/channel/type-name/route.ts +++ b/app/api/admin/channel/type-name/route.ts @@ -1,6 +1,6 @@ import { NextRequest, NextResponse } from 'next/server' -import { ChannelTypeMapName } from '@/types/admin/channels/channelInfo' +import { ChannelType, ChannelTypeMapName } from '@/types/admin/channels/channelInfo' import { ApiProxyBackendResp, ApiResp } from '@/types/api' import { parseJwtToken } from '@/utils/backend/auth' import { isAdmin } from '@/utils/backend/isAdmin' @@ -8,16 +8,45 @@ import { isAdmin } from '@/utils/backend/isAdmin' export const dynamic = 'force-dynamic' type ApiProxyBackendChannelTypeMapNameResponse = ApiProxyBackendResp +type ApiProxyBackendChannelTypeMetasResponse = ApiProxyBackendResp< + Record +> export type GetChannelTypeNamesResponse = ApiResp async function fetchChannelTypeNames(): Promise { try { + const typeMetasUrl = new URL( + `/api/channels/type_metas`, + global.AppConfig?.backend.aiproxyInternal || global.AppConfig?.backend.aiproxy + ) + const token = global.AppConfig?.auth.aiProxyBackendKey + const typeMetasResponse = await fetch(typeMetasUrl.toString(), { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `${token}`, + }, + cache: 'no-store', + }) + + if (typeMetasResponse.ok) { + const result: ApiProxyBackendChannelTypeMetasResponse = await typeMetasResponse.json() + if (!result.success) { + throw new Error(result.message || 'admin channels api:ai proxy backend error') + } + return Object.entries(result.data || {}).reduce((acc, [type, meta]) => { + if (meta.name) { + acc[type as ChannelType] = meta.name + } + return acc + }, {}) + } + const url = new URL( `/api/channels/type_names`, global.AppConfig?.backend.aiproxyInternal || global.AppConfig?.backend.aiproxy ) - const token = global.AppConfig?.auth.aiProxyBackendKey const response = await fetch(url.toString(), { method: 'GET', headers: { diff --git a/app/api/admin/option/batch/route.ts b/app/api/admin/option/batch/route.ts index c919b5e..8fea4e9 100644 --- a/app/api/admin/option/batch/route.ts +++ b/app/api/admin/option/batch/route.ts @@ -16,7 +16,7 @@ async function batchOption(batchOptionData: BatchOptionData): Promise { const token = global.AppConfig?.auth.aiProxyBackendKey const response = await fetch(url.toString(), { - method: 'PUT', + method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `${token}`, diff --git a/artifacts/deploy-adjust/aiproxy-cluster-20260530.md b/artifacts/deploy-adjust/aiproxy-cluster-20260530.md new file mode 100644 index 0000000..a8cfe19 --- /dev/null +++ b/artifacts/deploy-adjust/aiproxy-cluster-20260530.md @@ -0,0 +1,198 @@ +# AIProxy Sealos Deploy Adjust Report + +- Overall: PASS +- Date: 2026-05-30 CST +- Target: `id=`, `ip=` +- Cluster domain: `` +- Branch: `codex/aiproxy-deploy-adjust` +- Baseline command: `sealos run ghcr.io/sealos-apps/aiproxy/aiproxy-cluster:sha-5db063c` +- Final validation image: `` + +## Inputs + +| Item | Value | +|---|---| +| Base package | `sealos-pro-v5.1.2-rc5-amd64.tar` | +| Addon package | `admin-cluster-v0.1.0-amd64.tar` | +| App package | `ghcr.io/sealos-apps/aiproxy/aiproxy-cluster:sha-5db063c` | +| Namespace | `aiproxy-system` | +| UI validation | AIProxy dashboard, global configs, price/model page | +| API validation | `/v1/models`, `/v1/chat/completions` | +| Test channel | `` | +| Test model | `claude-3-5-haiku-20241022` | + +Signed package URLs and AI provider credentials are intentionally not recorded in this report. + +## Baseline Result + +The baseline install command completed, but `aiproxy-web` failed at runtime: + +```text +Error: Cannot find module '/app/server.js' +``` + +Image inspection showed the standalone server was generated below `/app/app/server.js`, while the Dockerfile starts `node server.js` from `/app`. + +After the web pod was repaired, the channel form still failed because the frontend requested the removed backend endpoint `/api/channels/type_names`. The running AIProxy backend exposes `/api/channels/type_metas`. + +The global default-model save path also failed through the frontend because the backend supports `POST /api/option/batch`, while the frontend proxy was calling it with `PUT`. + +## Code Fixes + +| File | Change | Result | +|---|---|---| +| `next.config.js` | Set `experimental.outputFileTracingRoot` to `__dirname` so Next standalone output contains root `server.js`. | PASS | +| `app/api/admin/channel/type-name/route.ts` | Prefer `/api/channels/type_metas` and map metadata to the existing frontend type-name shape. Keep `/type_names` fallback. | PASS | +| `app/api/admin/option/batch/route.ts` | Keep frontend `PUT` route, but proxy to backend with `POST /api/option/batch`. | PASS | + +## Rebuild And Redeploy Evidence + +```bash +rsync -a --delete --exclude '.git' --exclude 'node_modules' --exclude '.next' / root@:/ +ssh root@ 'cd && sealos build --platform linux/amd64 -t -f Dockerfile .' +ssh root@ 'ctr -n k8s.io images import ' +ssh root@ 'kubectl -n aiproxy-system set image deploy/aiproxy-web aiproxy=' +ssh root@ 'kubectl -n aiproxy-system rollout status deploy/aiproxy-web --timeout=180s' +``` + +Expected result: rollout completes and `aiproxy-web` logs show `Ready`. + +Observed result: + +```text +deployment "aiproxy-web" successfully rolled out +Next.js 14.2.35 +Ready in 591ms +``` + +## UI Validation + +Browser validation used real page navigation, clicks, fills, and submit actions against: + +```text +https://aiproxy-web./zh/dashboard +``` + +Because the app is normally launched inside Sealos Desktop, the browser test injected a short-lived `ns-admin` app JWT into page API requests. Channel configuration itself was performed through the AIProxy pages, not by calling backend channel APIs directly. Screenshots intentionally avoid the moment where the provider key is visible in the form. + +| Step | Expected | Result | Evidence | +|---|---|---|---| +| Open AIProxy dashboard | Dashboard loads and shows the test channel. | PASS | `artifacts/deploy-adjust/images/01-dashboard-channel-list.png` | +| Configure/save channel from the page | Existing Anthropic channel remains enabled and saved with the current provider config. | PASS | `artifacts/deploy-adjust/images/02-dashboard-channel-updated.png` | +| Open global configs | Default-model configuration page loads. | PASS | `artifacts/deploy-adjust/images/03-global-configs-default-model.png` | +| Open price/model page | `claude-3-5-haiku-20241022` is visible as an enabled model. | PASS | `artifacts/deploy-adjust/images/04-price-enabled-model.png` | + +## API Validation + +The user key created in the `ns-admin` workspace was used for model and chat-completion verification. + +```bash +curl -k -H "Authorization: Bearer " \ + https://aiproxy./v1/models +``` + +Expected result: `claude-3-5-haiku-20241022` is listed. + +Observed result: PASS. + +```bash +curl -k -H "Authorization: Bearer " \ + -H 'Content-Type: application/json' \ + -d '{"model":"claude-3-5-haiku-20241022","messages":[{"role":"user","content":"reply exactly: ok"}],"max_tokens":16}' \ + https://aiproxy./v1/chat/completions +``` + +Expected result: HTTP 200 and assistant content `ok`. + +Observed result: + +```json +{"model":"claude-3-5-haiku-20241022","content":"ok","total_tokens":11} +``` + +## Cluster And Legacy Data Checks + +| Check | Expected | Result | +|---|---|---| +| Node health | `pve-` Ready | PASS | +| Non-running pods | None | PASS | +| Failed Helm releases | None | PASS | +| AIProxy Helm releases | `aiproxy`, `aiproxy-database`, `aiproxy-web` deployed | PASS | +| Current channel list | Only the Helm-backed validation channel remains; no `probe-*` leftovers | PASS | +| aiproxy-web image | `` | PASS | +| `/api/status` | HTTP 200 | PASS | +| `/api/init-app-config` | HTTP 200 | PASS | + +Sanitized channel state: + +```text +id= name= type=14 status=1 models=[] +``` + +## Offline Image Check + +Allowed prefixes: + +- `sealos.hub:5000/` +- `hub./` + +Command: + +```bash +CLOUD_DOMAIN= +crictl images | awk -v domain="$CLOUD_DOMAIN" ' + NR==1 { next } + { + image=$1 + hub_host="hub." domain + allowed_hub_domain=(domain != "" && (image == hub_host || index(image, hub_host "/") == 1)) + if (image !~ /^sealos\.hub:5000(\/|$)/ && !allowed_hub_domain) { + print image + } + } +' | sort -u +``` + +Expected result: no output. + +Observed result: PASS. + +## Local Verification + +```bash +pnpm -s build +pnpm -s exec tsc --noEmit --pretty false +git diff --check +pnpm -s exec prettier --check app/api/admin/channel/type-name/route.ts app/api/admin/option/batch/route.ts next.config.js +helm lint deploy/charts/aiproxy-web +helm template aiproxy-web deploy/charts/aiproxy-web >/tmp/aiproxy-web-helm-template.yaml +``` + +All commands passed. Existing build warnings remain: React Hook dependency warnings, webpack dynamic dependency warning from `web-worker`, localStorage experimental warnings, and the existing Next dynamic server usage warning during prerender. + +## Manual Retest + +```bash +ssh root@ 'kubectl -n aiproxy-system get pods' +ssh root@ 'kubectl -n aiproxy-system logs deploy/aiproxy-web --tail=80' +curl -k https://aiproxy./api/status +curl -k https://aiproxy-web./api/init-app-config +``` + +Expected result: all AIProxy pods are Running, web logs include `Ready`, and both HTTP checks return 200. + +For AI verification, create or reuse an `ns-admin` API key and call: + +```bash +curl -k -H "Authorization: Bearer " \ + -H 'Content-Type: application/json' \ + -d '{"model":"claude-3-5-haiku-20241022","messages":[{"role":"user","content":"reply exactly: ok"}],"max_tokens":16}' \ + https://aiproxy./v1/chat/completions +``` + +Expected result: HTTP 200 with assistant content `ok`. + +## Risk Notes + +- Local macOS trust setup via `cert.sh` fetched the cluster CA but `security add-trusted-cert` did not make curl/browser trust effective. Browser/API validation used explicit TLS ignore flags. +- The target cluster was patched with a validation image built from this branch. Production use requires the CI-built runtime image and Sealos image for this branch. diff --git a/artifacts/deploy-adjust/images/01-dashboard-channel-list.png b/artifacts/deploy-adjust/images/01-dashboard-channel-list.png new file mode 100644 index 0000000..2b5820b Binary files /dev/null and b/artifacts/deploy-adjust/images/01-dashboard-channel-list.png differ diff --git a/artifacts/deploy-adjust/images/02-dashboard-channel-updated.png b/artifacts/deploy-adjust/images/02-dashboard-channel-updated.png new file mode 100644 index 0000000..2b5820b Binary files /dev/null and b/artifacts/deploy-adjust/images/02-dashboard-channel-updated.png differ diff --git a/artifacts/deploy-adjust/images/03-global-configs-default-model.png b/artifacts/deploy-adjust/images/03-global-configs-default-model.png new file mode 100644 index 0000000..0e370c5 Binary files /dev/null and b/artifacts/deploy-adjust/images/03-global-configs-default-model.png differ diff --git a/artifacts/deploy-adjust/images/04-price-enabled-model.png b/artifacts/deploy-adjust/images/04-price-enabled-model.png new file mode 100644 index 0000000..fb6c39a Binary files /dev/null and b/artifacts/deploy-adjust/images/04-price-enabled-model.png differ diff --git a/artifacts/deploy-adjust/test-cases/README.md b/artifacts/deploy-adjust/test-cases/README.md new file mode 100644 index 0000000..ba7846e --- /dev/null +++ b/artifacts/deploy-adjust/test-cases/README.md @@ -0,0 +1,29 @@ +# AIProxy Sealos 修复验证用例集 + +- 测试日期:2026-05-30 +- 测试集群:`ID=`,`` +- 集群域名:`` +- 测试分支:`codex/aiproxy-deploy-adjust` +- 基线部署命令:`sealos run ghcr.io/sealos-apps/aiproxy/aiproxy-cluster:sha-5db063c` +- 修复验证镜像:`` + +## 用例列表 + +| 用例 | 目标 | 结果 | 截图/证据 | +|---|---|---|---| +| [TC-01 Web 启动修复](./TC-01-web-standalone-startup.md) | 验证 `aiproxy-web` 修复后能启动并完成 rollout。 | 通过 | 命令输出 | +| [TC-02 页面配置渠道](./TC-02-channel-page-config.md) | 验证通过 AIProxy 管理中心页面配置并保存渠道。 | 通过 | `images/01-dashboard-channel-list.png`、`images/02-dashboard-channel-updated.png` | +| [TC-03 页面访问渠道模型](./TC-03-model-and-price-page.md) | 验证页面能看到刚才渠道可用的模型。 | 通过 | `images/03-global-configs-default-model.png`、`images/04-price-enabled-model.png` | +| [TC-04 用户 Key 调用 AI 能力](./TC-04-user-key-ai-api.md) | 验证用户申请的 key 能通过配置渠道完成 AI 调用。 | 通过 | API 输出 | +| [TC-05 Helm 与遗留数据检查](./TC-05-helm-and-legacy-data.md) | 验证当前部署由 Helm 管理,无失败 release 和残留测试渠道。 | 通过 | 命令输出 | +| [TC-06 离线镜像检查](./TC-06-offline-image-check.md) | 验证节点镜像只来自允许的本地仓库前缀。 | 通过 | 命令输出 | +| [TC-07 本地构建与图表检查](./TC-07-local-build-and-chart-check.md) | 验证正确目录中的代码、类型、格式和 Helm 图表。 | 通过 | 命令输出 | +| [TC-08 流水线验证](./TC-08-github-actions.md) | 验证正确仓库分支的官方构建流水线通过。 | 通过 | GitHub Actions | + +## 截图说明 + +截图只保留页面状态和验证结果,已打码测试渠道名,不保留 AI provider key、用户 API key、JWT、后端 admin key 或签名下载地址。 + +## 总结论 + +基线包部署后暴露出三个问题:Web standalone 输出路径错误、渠道类型接口与当前后端不兼容、全局配置批量保存代理方法错误。修复后,页面配置、模型访问、用户 key 调用 AI、Helm 状态、离线镜像、本地验证和官方流水线均通过。 diff --git a/artifacts/deploy-adjust/test-cases/TC-01-web-standalone-startup.md b/artifacts/deploy-adjust/test-cases/TC-01-web-standalone-startup.md new file mode 100644 index 0000000..b49e9b4 --- /dev/null +++ b/artifacts/deploy-adjust/test-cases/TC-01-web-standalone-startup.md @@ -0,0 +1,47 @@ +# TC-01 Web 启动修复 + +## 测试目标 + +验证 `sealos run ghcr.io/sealos-apps/aiproxy/aiproxy-cluster:sha-5db063c` 部署后的 `aiproxy-web` 启动问题已经修复,Web Pod 能正常启动并完成 rollout。 + +## 前置条件 + +- Sealos 集群已安装完成:`` +- AIProxy 基线包已经执行过:`sealos run ghcr.io/sealos-apps/aiproxy/aiproxy-cluster:sha-5db063c` +- 在正确仓库目录 `` 的 `codex/aiproxy-deploy-adjust` 分支构建验证镜像 + +## 关联代码修改 + +- `next.config.js:12`:将 `experimental.outputFileTracingRoot` 设置为 `__dirname`,确保 Next standalone 输出中存在容器启动命令需要的 `/app/server.js`。 + +## 测试流程 + +1. 观察基线部署后的 Web Pod 日志。 +2. 使用当前修复分支构建验证镜像。 +3. 将 `aiproxy-web` Deployment 镜像切换到修复后的验证镜像。 +4. 等待 Deployment rollout 完成。 +5. 查看 Web 日志是否进入 Ready 状态。 + +## 命令证据 + +```bash +ssh root@ 'kubectl -n aiproxy-system logs deploy/aiproxy-web --tail=80' +ssh root@ 'kubectl -n aiproxy-system set image deploy/aiproxy-web aiproxy=' +ssh root@ 'kubectl -n aiproxy-system rollout status deploy/aiproxy-web --timeout=180s' +``` + +## 预期结果 + +- 基线错误 `Cannot find module '/app/server.js'` 不再出现。 +- Deployment rollout 成功。 +- `aiproxy-web` 日志显示 Next.js 已 Ready。 + +## 实际结果 + +```text +deployment "aiproxy-web" successfully rolled out +Next.js 14.2.35 +Ready in 591ms +``` + +结果:通过。 diff --git a/artifacts/deploy-adjust/test-cases/TC-02-channel-page-config.md b/artifacts/deploy-adjust/test-cases/TC-02-channel-page-config.md new file mode 100644 index 0000000..3f5441e --- /dev/null +++ b/artifacts/deploy-adjust/test-cases/TC-02-channel-page-config.md @@ -0,0 +1,45 @@ +# TC-02 页面配置渠道 + +## 测试目标 + +验证 AIProxy 管理中心页面可以打开渠道列表,并通过页面操作配置和保存当前 AI provider 渠道。 + +## 前置条件 + +- `aiproxy-web` 已完成 TC-01 的启动修复。 +- 浏览器访问地址:`https://aiproxy-web./zh/dashboard` +- 使用 `ns-admin` 工作空间访问页面。 + +## 关联代码修改 + +- `app/api/admin/channel/type-name/route.ts:17`:优先请求当前后端支持的 `/api/channels/type_metas`。 +- `app/api/admin/channel/type-name/route.ts:38`:把后端 metadata 映射成前端既有的 `ChannelTypeMapName` 结构。 +- 保留 `/api/channels/type_names` fallback,避免老后端兼容性回退被破坏。 + +## 测试流程 + +1. 打开 AIProxy 管理中心渠道页面。 +2. 检查渠道列表正常加载。 +3. 通过页面创建或编辑 Anthropic 渠道。 +4. 填入当前 provider 配置并保存。 +5. 返回渠道列表确认渠道处于启用状态。 + +## 截图证据 + +![渠道列表](./images/01-dashboard-channel-list.png) + +![渠道保存后状态](./images/02-dashboard-channel-updated.png) + +## 预期结果 + +- 渠道页面不再因为 `/api/channels/type_names` 不存在而失败。 +- 页面能正常读取渠道类型。 +- 渠道保存后显示在列表中并保持启用。 + +## 实际结果 + +- 渠道页面加载成功。 +- 测试渠道 `` 保存成功。 +- 截图中渠道状态可见且页面无错误提示。 + +结果:通过。 diff --git a/artifacts/deploy-adjust/test-cases/TC-03-model-and-price-page.md b/artifacts/deploy-adjust/test-cases/TC-03-model-and-price-page.md new file mode 100644 index 0000000..82a41e8 --- /dev/null +++ b/artifacts/deploy-adjust/test-cases/TC-03-model-and-price-page.md @@ -0,0 +1,41 @@ +# TC-03 页面访问渠道模型 + +## 测试目标 + +验证页面可以访问全局配置和价格/模型页面,并能看到刚才配置渠道对应的可用模型。 + +## 前置条件 + +- TC-02 已通过,测试渠道已经保存。 +- 测试模型:`claude-3-5-haiku-20241022` + +## 关联代码修改 + +- `app/api/admin/option/batch/route.ts:18`:前端仍对外暴露 `PUT`,但代理到后端时改用后端实际支持的 `POST /api/option/batch`。 + +## 测试流程 + +1. 从 AIProxy 管理中心打开全局配置页面。 +2. 查看默认模型相关配置是否能加载。 +3. 打开价格/模型页面。 +4. 搜索或查看 `claude-3-5-haiku-20241022` 是否可见。 + +## 截图证据 + +![全局配置默认模型](./images/03-global-configs-default-model.png) + +![价格模型页面](./images/04-price-enabled-model.png) + +## 预期结果 + +- 全局配置页面能正常加载。 +- 默认模型配置保存路径可用。 +- 价格/模型页面能看到 `claude-3-5-haiku-20241022`。 + +## 实际结果 + +- 全局配置页面打开成功。 +- 默认模型配置代理保存接口返回成功。 +- 价格/模型页面显示 `claude-3-5-haiku-20241022`。 + +结果:通过。 diff --git a/artifacts/deploy-adjust/test-cases/TC-04-user-key-ai-api.md b/artifacts/deploy-adjust/test-cases/TC-04-user-key-ai-api.md new file mode 100644 index 0000000..a755649 --- /dev/null +++ b/artifacts/deploy-adjust/test-cases/TC-04-user-key-ai-api.md @@ -0,0 +1,50 @@ +# TC-04 用户 Key 调用 AI 能力 + +## 测试目标 + +验证用户申请的 AIProxy API key 可以通过页面配置好的渠道完成实际 AI 调用。 + +## 前置条件 + +- TC-02 页面渠道配置已通过。 +- TC-03 模型页面验证已通过。 +- 已在 `ns-admin` 工作空间创建或复用用户 API key。 + +## 关联代码修改 + +- 本用例验证的是 TC-02 和 TC-03 两处修复的端到端效果。 +- 渠道类型接口修复保证渠道能配置。 +- 批量 option 保存方法修复保证默认模型配置能保存。 + +## 测试流程 + +1. 使用用户 API key 调用 `/v1/models`。 +2. 确认模型列表包含 `claude-3-5-haiku-20241022`。 +3. 使用同一个用户 API key 调用 `/v1/chat/completions`。 +4. 请求内容要求模型只回复 `ok`。 + +## 命令证据 + +```bash +curl -k -H "Authorization: Bearer " \ + https://aiproxy./v1/models + +curl -k -H "Authorization: Bearer " \ + -H 'Content-Type: application/json' \ + -d '{"model":"claude-3-5-haiku-20241022","messages":[{"role":"user","content":"reply exactly: ok"}],"max_tokens":16}' \ + https://aiproxy./v1/chat/completions +``` + +## 预期结果 + +- `/v1/models` 返回模型列表,包含 `claude-3-5-haiku-20241022`。 +- `/v1/chat/completions` 返回 HTTP 200。 +- assistant 内容为 `ok`。 + +## 实际结果 + +```json +{"model":"claude-3-5-haiku-20241022","content":"ok","total_tokens":11} +``` + +结果:通过。 diff --git a/artifacts/deploy-adjust/test-cases/TC-05-helm-and-legacy-data.md b/artifacts/deploy-adjust/test-cases/TC-05-helm-and-legacy-data.md new file mode 100644 index 0000000..36a8588 --- /dev/null +++ b/artifacts/deploy-adjust/test-cases/TC-05-helm-and-legacy-data.md @@ -0,0 +1,49 @@ +# TC-05 Helm 与遗留数据检查 + +## 测试目标 + +验证 AIProxy 当前资源由 Helm 管理,集群无失败 Helm release,无非 Running Pod,并且没有残留的临时测试渠道。 + +## 前置条件 + +- AIProxy 已完成修复镜像升级。 +- 页面渠道和 API 调用验证已通过。 + +## 关联代码修改 + +- 本用例不直接对应单个代码文件,主要验证修复后部署状态没有引入额外残留资源。 + +## 测试流程 + +1. 查看所有非 Running/Succeeded Pod。 +2. 查看所有 failed Helm release。 +3. 查看 `aiproxy-system` 下 AIProxy Helm release 状态。 +4. 查看当前渠道列表是否只保留验证渠道,无 `probe-*` 等临时残留。 +5. 查看 `aiproxy-web` 当前镜像是否为修复验证镜像。 + +## 命令证据 + +```bash +ssh root@ 'kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded --no-headers' +ssh root@ 'helm list -A --failed --no-headers' +ssh root@ 'helm list -n aiproxy-system' +ssh root@ 'kubectl -n aiproxy-system get deploy aiproxy-web -o jsonpath="{.spec.template.spec.containers[0].image}"' +``` + +## 预期结果 + +- 不存在异常状态 Pod。 +- 不存在 failed Helm release。 +- `aiproxy`、`aiproxy-database`、`aiproxy-web` 均为 deployed。 +- 不存在 `probe-*` 残留渠道。 + +## 实际结果 + +```text +PASS: no non-running pods +PASS: no failed helm releases +aiproxy, aiproxy-database, aiproxy-web: deployed +id= name= type=14 status=1 models=[] +``` + +结果:通过。 diff --git a/artifacts/deploy-adjust/test-cases/TC-06-offline-image-check.md b/artifacts/deploy-adjust/test-cases/TC-06-offline-image-check.md new file mode 100644 index 0000000..a873c75 --- /dev/null +++ b/artifacts/deploy-adjust/test-cases/TC-06-offline-image-check.md @@ -0,0 +1,49 @@ +# TC-06 离线镜像检查 + +## 测试目标 + +验证部署后的节点镜像来源符合离线安装要求,只使用允许的本地镜像仓库前缀。 + +## 前置条件 + +- Sealos 集群已安装并导入离线镜像。 +- AIProxy 修复验证镜像已导入本地 registry。 + +## 关联代码修改 + +- 本用例不直接对应代码修改,主要验证修复镜像没有破坏离线镜像约束。 + +## 测试流程 + +1. 在目标节点执行 `crictl images`。 +2. 过滤允许前缀: + - `sealos.hub:5000/` + - `hub./` +3. 检查过滤结果是否为空。 + +## 命令证据 + +```bash +CLOUD_DOMAIN= +crictl images | awk -v domain="$CLOUD_DOMAIN" ' + NR==1 { next } + { + image=$1 + hub_host="hub." domain + allowed_hub_domain=(domain != "" && (image == hub_host || index(image, hub_host "/") == 1)) + if (image !~ /^sealos\.hub:5000(\/|$)/ && !allowed_hub_domain) { + print image + } + } +' | sort -u +``` + +## 预期结果 + +命令无输出。 + +## 实际结果 + +命令无输出。 + +结果:通过。 diff --git a/artifacts/deploy-adjust/test-cases/TC-07-local-build-and-chart-check.md b/artifacts/deploy-adjust/test-cases/TC-07-local-build-and-chart-check.md new file mode 100644 index 0000000..7f5ba29 --- /dev/null +++ b/artifacts/deploy-adjust/test-cases/TC-07-local-build-and-chart-check.md @@ -0,0 +1,47 @@ +# TC-07 本地构建与图表检查 + +## 测试目标 + +验证正确仓库目录 `` 中的修复分支可以通过本地构建、类型检查、格式检查和 Helm 图表检查。 + +## 前置条件 + +- 当前目录为 `` +- 当前分支为 `codex/aiproxy-deploy-adjust` + +## 关联代码修改 + +- `next.config.js` +- `app/api/admin/channel/type-name/route.ts` +- `app/api/admin/option/batch/route.ts` +- `types/static-assets.d.ts`:补充 `*.svg` 和 `*.png` 静态资源模块声明,让正确仓库安装依赖后可以单独执行 `tsc --noEmit`。 +- `artifacts/deploy-adjust/test-cases/*` + +## 测试流程 + +1. 执行 Next.js build。 +2. 执行 TypeScript noEmit 检查。 +3. 执行 Git whitespace 检查。 +4. 执行 Prettier 检查。 +5. 执行 Helm lint 和 template。 + +## 命令证据 + +```bash +pnpm -s build +pnpm -s exec tsc --noEmit --pretty false +git diff --check +pnpm -s exec prettier --check app/api/admin/channel/type-name/route.ts app/api/admin/option/batch/route.ts next.config.js artifacts/deploy-adjust/aiproxy-cluster-20260530.md artifacts/deploy-adjust/test-cases/*.md +helm lint deploy/charts/aiproxy-web +helm template aiproxy-web deploy/charts/aiproxy-web >/tmp/aiproxy-web-helm-template.yaml +``` + +## 预期结果 + +全部命令通过。 + +## 实际结果 + +全部命令通过。构建中仍存在项目既有 warning:React Hook dependency warning、`web-worker` dynamic dependency warning、localStorage experimental warning、Next prerender dynamic server usage warning。 + +结果:通过。 diff --git a/artifacts/deploy-adjust/test-cases/TC-08-github-actions.md b/artifacts/deploy-adjust/test-cases/TC-08-github-actions.md new file mode 100644 index 0000000..0c7db16 --- /dev/null +++ b/artifacts/deploy-adjust/test-cases/TC-08-github-actions.md @@ -0,0 +1,57 @@ +# TC-08 流水线验证 + +## 测试目标 + +验证正确仓库 `sealos-apps/aiproxy` 的 `codex/aiproxy-deploy-adjust` 分支可以通过官方构建流水线。 + +## 前置条件 + +- 分支已推送到 `git@github.com:sealos-apps/aiproxy.git` +- 验证提交:`` + +## 关联代码修改 + +- 本用例覆盖本分支全部修复与文档截图材料。 + +## 测试流程 + +1. 在正确仓库触发 `Build Sealos from Sealos`。 +2. 查看 runtime 镜像构建。 +3. 查看 Sealos 镜像构建。 +4. 查看多架构 manifest 发布。 +5. 查看 OSS 同步任务。 + +## 命令证据 + +```bash +gh workflow run "Build Sealos from Sealos" \ + --repo sealos-apps/aiproxy \ + --ref codex/aiproxy-deploy-adjust \ + -f version= + +gh run view \ + --repo sealos-apps/aiproxy \ + --json status,conclusion,jobs +``` + +## 预期结果 + +流水线所有 job 通过。 + +## 实际结果 + +流水线地址:`` + +通过的 job: + +- Release Metadata +- Build Runtime Image (amd64) +- Build Runtime Image (arm64) +- Publish Runtime Manifests +- Build Sealos Image (amd64) +- Build Sealos Image (arm64) +- Publish Sealos Manifests +- Sync Sealos Packages to OSS (arm64) +- Sync Sealos Packages to OSS (amd64) + +结果:通过。 diff --git a/artifacts/deploy-adjust/test-cases/images/01-dashboard-channel-list.png b/artifacts/deploy-adjust/test-cases/images/01-dashboard-channel-list.png new file mode 100644 index 0000000..2b5820b Binary files /dev/null and b/artifacts/deploy-adjust/test-cases/images/01-dashboard-channel-list.png differ diff --git a/artifacts/deploy-adjust/test-cases/images/02-dashboard-channel-updated.png b/artifacts/deploy-adjust/test-cases/images/02-dashboard-channel-updated.png new file mode 100644 index 0000000..2b5820b Binary files /dev/null and b/artifacts/deploy-adjust/test-cases/images/02-dashboard-channel-updated.png differ diff --git a/artifacts/deploy-adjust/test-cases/images/03-global-configs-default-model.png b/artifacts/deploy-adjust/test-cases/images/03-global-configs-default-model.png new file mode 100644 index 0000000..0e370c5 Binary files /dev/null and b/artifacts/deploy-adjust/test-cases/images/03-global-configs-default-model.png differ diff --git a/artifacts/deploy-adjust/test-cases/images/04-price-enabled-model.png b/artifacts/deploy-adjust/test-cases/images/04-price-enabled-model.png new file mode 100644 index 0000000..fb6c39a Binary files /dev/null and b/artifacts/deploy-adjust/test-cases/images/04-price-enabled-model.png differ diff --git a/next.config.js b/next.config.js index b1e0693..19f293d 100644 --- a/next.config.js +++ b/next.config.js @@ -1,7 +1,5 @@ /** @type {import('next').NextConfig} */ -const path = require('path') - const nextConfig = { output: 'standalone', reactStrictMode: false, @@ -12,8 +10,7 @@ const nextConfig = { '@labring/sealos-desktop-sdk', ], experimental: { - // this includes files from the monorepo base two directories up - outputFileTracingRoot: path.join(__dirname, '../../'), + outputFileTracingRoot: __dirname, }, async rewrites() { return [ diff --git a/types/static-assets.d.ts b/types/static-assets.d.ts new file mode 100644 index 0000000..b50a057 --- /dev/null +++ b/types/static-assets.d.ts @@ -0,0 +1,13 @@ +declare module '*.svg' { + import { StaticImageData } from 'next/image' + + const content: StaticImageData + export default content +} + +declare module '*.png' { + import { StaticImageData } from 'next/image' + + const content: StaticImageData + export default content +}