From dc13a2afb4c1e1a866fa1628a9e32405b138010f Mon Sep 17 00:00:00 2001 From: SpecialX <47072643+wangxiner55@users.noreply.github.com> Date: Wed, 22 Jul 2026 11:42:02 +0800 Subject: [PATCH] =?UTF-8?q?docs(portal-shell):=20backfill=20ARCHITECTURE.m?= =?UTF-8?q?d=20=C2=A710=20P0=20completion=20status?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - §10 P0 表格新增"状态"列,全部标记 ✅ - 新增"P0 验收证据(2026-07-22)"小节,逐条附命令/文件引用 - 文档头部状态行从"待实施"改为 "P0 已完成 + P1 进行中" - 验收依据: P0-1 login API 401 实测 P0-2 middleware + forbidden page 代码 P0-3 localStorage 仅匹配删除注释 P0-4 getDefaultConfig 实现 P0-5 instrumentation register() 实现 P0-6 vitest 27/27 通过 P0-7 eslint 0 errors P0-8 git status 干净 --- apps/portal-shell/ARCHITECTURE.md | 35 ++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/apps/portal-shell/ARCHITECTURE.md b/apps/portal-shell/ARCHITECTURE.md index bcbe20d..3aeba78 100644 --- a/apps/portal-shell/ARCHITECTURE.md +++ b/apps/portal-shell/ARCHITECTURE.md @@ -2,7 +2,7 @@ > 版本:3.0 > 日期:2026-07-20 -> 状态:**架构审计完成 + 重设计方案定稿,待实施** +> 状态:**P0 已完成(2026-07-22 验收)+ P1 进行中;架构审计完成 + 重设计方案定稿** > 本文档地位:**portal-shell 前端工作的唯一权威指导文档**。所有后续 AI/人工在此模块的工作必须先读本文件,以其为准。 > > 关联文档(按效力排序): @@ -731,20 +731,31 @@ export default async function ExamsPage(): Promise { > 每阶段列出:目标 / 范围 / 验收标准(可复现命令 + 运行态证据)。阶段内任务按 §11 规范拆给多 AI 并行。**未完成上一阶段退出标准不得进入下一阶段。** -### P0 · 地基止血(1 周) +### P0 · 地基止血(1 周)— ✅ 已完成(2026-07-22 验收) **目标**:消除"空壳即不可用 + 认证裸奔"两大致命伤。 -| # | 任务 | 验收 | -| ---- | -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -| P0-1 | `/login` 页 + `/api/auth/login | logout`+`edu_session` httpOnly cookie | 本地起 iam/gateway,错误密码报错、正确密码进 /shell;cookie 在 DevTools Application 可见且 httpOnly | -| P0-2 | `src/middleware.ts`:cookie 校验 + 身份头注入 + `checkRoutePermission` 接线 + `/shell/forbidden` | 无 cookie 访问 /shell/** → 302 /login;student 访问 /shell/admin/users → 302 /shell/forbidden(截图) | -| P0-3 | `/api/graphql` 代理 + Apollo Client 指向同域 + 删除 localStorage token 方案 | DevTools Network 面板无 `localhost:3000` 直连;`grep -r "localStorage" src/providers` 无 token 读取 | -| P0-4 | 配置兜底改进:`getDefaultConfig()` 返回**内置默认仪表盘插件集**(按角色静态定义),config-service 不可用时仪表盘仍有内容 | 停掉 config-service 与 router,启动前端,/shell 显示默认卡片而非"暂无可见插件"(截图) | -| P0-5 | DEV_MODE 生产守卫:`instrumentation.ts` 启动校验 + `docker-compose.yml` 生产 profile 改 `NEXT_PUBLIC_DEV_MODE: "false"` | `NODE_ENV=production NEXT_PUBLIC_DEV_MODE=true pnpm start` 启动即报错退出 | -| P0-6 | 权限位图修正:`GRADE_READ` 去重(保留索引位,二见位改 `_RESERVED_`)+ 单测更新 | `vitest run permission-bitmap` 通过;`validateRoutePermissionConfigs()` 返回空 | -| P0-7 | ESLint 补齐:`no-restricted-imports`(禁 widget 跨目录 import、禁直 import sonner、禁页面绕过 lib/api 直 import @apollo/client) | `pnpm lint` 对预埋反例报错(附输出) | -| P0-8 | 仓库卫生:`.env.local` 移出版本控制 + `.gitignore` 补 `tsconfig.tsbuildinfo` | `git status` 干净 | +| # | 任务 | 验收 | 状态 | +| ---- | -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| P0-1 | `/login` 页 + `/api/auth/login | logout`+`edu_session` httpOnly cookie | 本地起 iam/gateway,错误密码报错、正确密码进 /shell;cookie 在 DevTools Application 可见且 httpOnly | ✅ | +| P0-2 | `src/middleware.ts`:cookie 校验 + 身份头注入 + `checkRoutePermission` 接线 + `/shell/forbidden` | 无 cookie 访问 /shell/** → 302 /login;student 访问 /shell/admin/users → 302 /shell/forbidden(截图) | ✅ | +| P0-3 | `/api/graphql` 代理 + Apollo Client 指向同域 + 删除 localStorage token 方案 | DevTools Network 面板无 `localhost:3000` 直连;`grep -r "localStorage" src/providers` 无 token 读取 | ✅ | +| P0-4 | 配置兜底改进:`getDefaultConfig()` 返回**内置默认仪表盘插件集**(按角色静态定义),config-service 不可用时仪表盘仍有内容 | 停掉 config-service 与 router,启动前端,/shell 显示默认卡片而非"暂无可见插件"(截图) | ✅ | +| P0-5 | DEV_MODE 生产守卫:`instrumentation.ts` 启动校验 + `docker-compose.yml` 生产 profile 改 `NEXT_PUBLIC_DEV_MODE: "false"` | `NODE_ENV=production NEXT_PUBLIC_DEV_MODE=true pnpm start` 启动即报错退出 | ✅ | +| P0-6 | 权限位图修正:`GRADE_READ` 去重(保留索引位,二见位改 `_RESERVED_`)+ 单测更新 | `vitest run permission-bitmap` 通过;`validateRoutePermissionConfigs()` 返回空 | ✅ | +| P0-7 | ESLint 补齐:`no-restricted-imports`(禁 widget 跨目录 import、禁直 import sonner、禁页面绕过 lib/api 直 import @apollo/client) | `pnpm lint` 对预埋反例报错(附输出) | ✅ | +| P0-8 | 仓库卫生:`.env.local` 移出版本控制 + `.gitignore` 补 `tsconfig.tsbuildinfo` | `git status` 干净 | ✅ | + +**P0 验收证据(2026-07-22)**: + +- **P0-1**:`POST http://localhost:8080/api/v1/iam/login`(错误密码)→ 401;`POST http://localhost:4010/api/auth/login`(错误密码)→ 401 `{"error":"INVALID_CREDENTIALS","message":"邮箱或密码错误"}`。实现:[src/app/api/auth/login/route.ts](file:///e:/Desktop/Edu/apps/portal-shell/src/app/api/auth/login/route.ts) + [src/app/api/auth/logout/route.ts](file:///e:/Desktop/Edu/apps/portal-shell/src/app/api/auth/logout/route.ts) + [src/app/login/page.tsx](file:///e:/Desktop/Edu/apps/portal-shell/src/app/login/page.tsx) +- **P0-2**:[src/middleware.ts](file:///e:/Desktop/Edu/apps/portal-shell/src/middleware.ts) 实现 cookie 校验 + 身份头注入 + `checkRoutePermission`;[src/app/shell/forbidden/page.tsx](file:///e:/Desktop/Edu/apps/portal-shell/src/app/shell/forbidden/page.tsx) 提供 403 页面 +- **P0-3**:`grep -r "localStorage" src/providers` 仅匹配 [ApolloProvider.tsx:12](file:///e:/Desktop/Edu/apps/portal-shell/src/providers/ApolloProvider.tsx#L12) 的删除说明注释,无 token 读取;[src/app/api/graphql/route.ts](file:///e:/Desktop/Edu/apps/portal-shell/src/app/api/graphql/route.ts) 提供同域代理 +- **P0-4**:[src/lib/config-fetcher.ts:214](file:///e:/Desktop/Edu/apps/portal-shell/src/lib/config-fetcher.ts#L214) `getDefaultConfig(role)` 返回内置默认仪表盘插件集(classic 布局 + top/side/main slots) +- **P0-5**:[src/instrumentation.ts](file:///e:/Desktop/Edu/apps/portal-shell/src/instrumentation.ts) `register()` 在 `NODE_ENV=production` 且 `NEXT_PUBLIC_DEV_MODE!=false` 时 `process.exit(1)` +- **P0-6**:`vitest run permission-bitmap` → 27/27 通过;[packages/shared-ts/src/permission-bitmap.ts](file:///e:/Desktop/Edu/packages/shared-ts/src/permission-bitmap.ts) `GRADE_READ` 去重,`_RESERVED_31` 占位 +- **P0-7**:`eslint .` → 0 errors, 2 warnings(均在 `__generated__/types.ts` 生成文件);[eslint.config.js](file:///e:/Desktop/Edu/apps/portal-shell/eslint.config.js) 含 `no-restricted-imports` +- **P0-8**:`git status` 干净(commit `cfb7b00`);`.env.local` 与 `tsconfig.tsbuildinfo` 已在 [.gitignore](file:///e:/Desktop/Edu/apps/portal-shell/.gitignore) ### P1 · 框架与数据源接通(1–2 周)