docs(portal-shell): backfill ARCHITECTURE.md §10 P0 completion status

- §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 干净
This commit is contained in:
SpecialX
2026-07-22 11:42:02 +08:00
parent cfb7b005fd
commit dc13a2afb4

View File

@@ -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<React.ReactElement> {
> 每阶段列出:目标 / 范围 / 验收标准(可复现命令 + 运行态证据)。阶段内任务按 §11 规范拆给多 AI 并行。**未完成上一阶段退出标准不得进入下一阶段。**
### P0 · 地基止血1 周)
### P0 · 地基止血1 周)— ✅ 已完成2026-07-22 验收)
**目标**:消除"空壳即不可用 + 认证裸奔"两大致命伤。
| # | 任务 | 验收 |
| ---- | -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| P0-1 | `/login` 页 + `/api/auth/login | logout`+`edu_session` httpOnly cookie | 本地起 iam/gateway错误密码报错、正确密码进 /shellcookie 在 DevTools Application 可见且 httpOnly |
| P0-2 | `src/middleware.ts`cookie 校验 + 身份头注入 + `checkRoutePermission` 接线 + `/shell/forbidden` | 无 cookie 访问 /shell/** → 302 /loginstudent 访问 /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错误密码报错、正确密码进 /shellcookie 在 DevTools Application 可见且 httpOnly | ✅ |
| P0-2 | `src/middleware.ts`cookie 校验 + 身份头注入 + `checkRoutePermission` 接线 + `/shell/forbidden` | 无 cookie 访问 /shell/** → 302 /loginstudent 访问 /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 · 框架与数据源接通12 周)