diff --git a/docs/architecture/004_architecture_impact_map.md b/docs/architecture/004_architecture_impact_map.md
index f03a39a..741f059 100644
--- a/docs/architecture/004_architecture_impact_map.md
+++ b/docs/architecture/004_architecture_impact_map.md
@@ -1622,6 +1622,146 @@ GraphQL 响应中,错误通过 `errors[].extensions` 携带 ActionState 字段
}
```
+### 11.7 portal-shell 前端数据访问层 + GraphQL 安全栈(v2.1 M3 新增)
+
+> 来源:[portal-shell 数据抽象与 GraphQL 加固 spec](../superpowers/specs/2026-07-17-portal-shell-data-abstraction-and-graphql-hardening-design.md) v1.0 / [实施 plan](../superpowers/plans/2026-07-17-portal-shell-data-abstraction-and-graphql-hardening.md)
+> 关联 ADR:ADR-023(Apollo Federation 替代 BFF)、ADR-036(Router-Authorization)、ADR-042(前端数据访问四层分层)、ADR-043(PQ Manifest + APQ 安全加固)
+> 实施阶段:v2.1 M1(数据抽象层)+ M3(GraphQL 安全加固)+ M4(resolver 守卫补齐)
+
+#### 11.7.1 四层数据访问分层(Widget → API → Operations → Hook)
+
+> v2.1 变更:废弃 widget 内联 `gql\`...\``字面量模式,统一抽取到`lib/api/` 四层架构。原 31 个 widget 全部迁移,0 处内联 gql 残留。
+
+```mermaid
+graph TD
+ subgraph Widget["Widget 层(UI)"]
+ W[widgets/*.tsx
只关心渲染]
+ end
+ subgraph API["API 层(语义化函数)"]
+ A1[lib/api/parent.ts]
+ A2[lib/api/teacher.ts]
+ A3[lib/api/admin.ts]
+ A4[lib/api/student.ts]
+ A5[lib/api/universal.ts]
+ A6[lib/api/sidebar.ts]
+ A7[lib/api/topbar.ts]
+ end
+ subgraph Ops["Operations 层(gql 文档集中)"]
+ O[lib/api/operations/*.graphql.ts
51 个 DocumentNode 常量]
+ end
+ subgraph Hook["Hook 层(Apollo 封装)"]
+ H1[useWidgetQuery]
+ H2[useWidgetMutation]
+ end
+ subgraph Codegen["类型生成"]
+ C[graphql-codegen
7 子图 schema.graphql → types.ts]
+ end
+ W --> A1 & A2 & A3 & A4 & A5 & A6 & A7
+ A1 & A2 & A3 & A4 & A5 & A6 & A7 --> O
+ A1 & A2 & A3 & A4 & A5 & A6 & A7 --> H1 & H2
+ O --> C
+```
+
+**层职责矩阵**:
+
+| 层 | 位置 | 职责 | 禁止 |
+| ---------- | --------------------------------------------- | ------------------------------------------------------- | ----------------------------------------- |
+| Widget | `src/widgets/*.tsx` | UI 渲染、用户交互 | 内联 gql 字面量、直接 import Apollo hooks |
+| API | `src/lib/api/.ts` | 语义化函数(`useMyChildren()` / `saveLessonPlan()` 等) | 写 gql 字符串、直接操作 Apollo cache |
+| Operations | `src/lib/api/operations/*.graphql.ts` | gql DocumentNode 常量集中存放(51 个 query/mutation) | 包含业务逻辑 |
+| Hook | `src/lib/useWidgetQuery/useWidgetMutation.ts` | Apollo useQuery/useMutation 封装 + ApiError 归一化 | 引用具体 domain |
+| Types | `src/lib/api/types.ts` + codegen 生成 | TS 类型(Widget 友好形) | 手写 |
+
+**7 个 domain API 文件**:
+
+| 文件 | Widget 数 | 主要场景 |
+| -------------- | --------- | ---------------------------------------------------------------------------------- |
+| `universal.ts` | 7 | 公告 / 通知 / 课表 / 作业 / 考试 / 成绩 / 考勤(多角色复用) |
+| `sidebar.ts` | 3 | 当前用户 / 我的班级 / 学期列表(侧边栏) |
+| `topbar.ts` | 2 | 搜索 / 通知铃铛(顶栏,`useNotificationBell` 限 N 条) |
+| `teacher.ts` | 5 | 教材 / 教案 / 题目 / 课表规则 / 教案保存 / 课表更新 |
+| `student.ts` | 5 | AI Tutor / 选修课 / 错题本 / 学习路径 / 错题掌握标记 |
+| `parent.ts` | 3 | 我的子女 / 请假审批 / 请假驳回 |
+| `admin.ts` | 11 | 用户 / 角色 / 权限 / 学校 / 插件注册 / 角色插件映射 / 布局模板 / 邀请码 / 审计日志 |
+
+**类型生成(graphql-codegen)**:
+
+- 配置:`apps/portal-shell/codegen.yml`
+- schema 来源:7 个子图的 `services//src/graphql/generated/schema.graphql`
+- 生成产物:`src/lib/api/operations/types.ts`(仅类型,无运行时代码)
+- 关键配置:`skipDocumentsValidation: true`(避免子图未启动时 codegen 失败)
+- schema 归一化:`scripts/normalize-schema.ts` 移除 federation 指令(`@key` / `@requires` / `@extends`)防止 codegen 误解析
+
+#### 11.7.2 GraphQL 安全栈(APQ + PQ Manifest + 深度/成本限制)
+
+> v2.1 M3 安全加固:解决"前端 gql 字面量暴露 schema,攻击者可构造任意查询探测"风险。
+
+```mermaid
+graph LR
+ subgraph FE["portal-shell(前端)"]
+ APQ[createPersistedQueryLink
sha256 query → hash]
+ end
+ subgraph Router["apollo-router :3000"]
+ Manifest[pq-manifest.json
hash → query 白名单]
+ Limits[limits.max_depth=10
max_cost=1000
max_batch_size=5]
+ Intro[introspection
环境变量控制]
+ end
+ subgraph Sub["子图 /graphql"]
+ Guard[RouterAuthGuard
+ @RequirePermission]
+ end
+ APQ -->|只发 hash| Manifest
+ Manifest -->|未知 hash 拒绝| APQ
+ Manifest --> Limits
+ Limits --> Intro
+ Intro --> Guard
+```
+
+**安全机制矩阵**:
+
+| 机制 | 位置 | 防御目标 | 配置 |
+| ---------------------------------- | -------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------- |
+| APQ(Automatic Persisted Queries) | `apps/portal-shell/src/lib/apollo-client.ts` | 前端只发 query hash,不发明文 query | `createPersistedQueryLink({ sha256 })`,env `NEXT_PUBLIC_APOLLO_APQ=false` 关闭 |
+| PQ Manifest | `apps/portal-shell/public/pq-manifest.json` | Router 仅解析白名单 hash,拒绝未知 hash 任意查询 | 51 个 query 的 `sha256 → query` 映射,由 `scripts/generate-pq-manifest.ts` 生成 |
+| Router 强制 manifest | `infra/apollo-router/router.yaml` | 生产模式(`require_manifest: true`)拒绝未注册查询 | env `APOLLO_REQUIRE_PQ_MANIFEST=true`,entrypoint.sh 启动前检查文件存在性 |
+| 深度限制 | `router.yaml` `limits.max_depth=10` | 防止深度嵌套查询 DoS | 11 层嵌套被 router 拒绝(`QUERY_DEPTH_EXCEEDED`) |
+| 成本限制 | `router.yaml` `limits.max_cost=1000` | 防止高成本查询 DoS | 按字段复杂度评分累加 |
+| 批量限制 | `router.yaml` `limits.max_batch_size=5` | 防止批量查询 DoS | 单次请求最多 5 个 query |
+| Introspection 控制 | `router.yaml` `supergraph.introspection` | 生产关闭 introspection 防止 schema 泄露 | env `APOLLO_ROUTER_INTROSPECTION=false`(开发默认 true) |
+| Router-Authorization 信任 | 子图 `RouterAuthGuard`(见 §5.5) | 防止绕过 Router 直接访问子图 | 子图校验 `Router-Authorization` header,拒绝非 Router 请求(ADR-036) |
+| Resolver 字段级权限 | 子图 `@RequirePermission()` 装饰器 | 防止越权访问字段 | 每个 Resolver 必须声明权限点(见 §3.8) |
+
+**PQ Manifest 生成流程**:
+
+1. `pnpm --filter @edu/portal-shell run codegen` → 从 7 子图 schema 生成 TS 类型
+2. `pnpm --filter @edu/portal-shell run generate-pq-manifest` → 遍历 `lib/api/operations/index.ts` 中所有 DocumentNode,`print(doc)` 后 `sha256(query)` 生成映射,写入 `public/pq-manifest.json`
+3. `prebuild` 钩子自动串联 codegen + generate-pq-manifest
+4. Docker compose 挂载 `pq-manifest.json` 到 apollo-router `/etc/apollo-router/pq-manifest.json:ro`
+5. apollo-router entrypoint.sh 启动前校验 manifest 存在性(`require_manifest=true` 时缺失即 exit 1)
+
+**安全栈测试覆盖**(`apps/portal-shell/src/lib/api/__tests__/security.test.ts`):
+
+- PQ Manifest 完整性(6 cases):DocumentNode 校验 / sha256 稳定性 / 确定性 / 唯一性 / manifest 文件有效性 / hash 一致性
+- Query depth limit(2 cases):11 层嵌套构造 / 合法查询构造(实际拒绝由 router 执行)
+- APQ behavior(2 cases):默认启用 / `NEXT_PUBLIC_APOLLO_APQ=false` 关闭
+
+#### 11.7.3 Resolver 权限守卫(@RequirePermission 字段级)
+
+> v2.1 M4:补齐 19 个 TS resolver 文件的 `@RequirePermission()` 装饰器。Python 子图(data-ana/ai)权限基础设施待补,见 [审计报告](../security/graphql-auth-audit-2026-07.md) follow-up。
+
+**已审计范围**:50 个 resolver(35 TS + 15 Python)
+
+| 状态 | 数量 | 说明 |
+| ------------------------- | ---- | -------------------------------------------------------------------------------------- |
+| 已有 `@RequirePermission` | 37 | 18 原有 + 19 M4 补齐 |
+| 缺失守卫 | 13 | 4 个 TS(`/graphql` 路径未覆盖,由 RouterAuthGuard 兜底)+ 9 个 Python(待补基础设施) |
+
+**TS 审计 follow-up**(不阻断 M3 验收):
+
+- 4 个 TS 子图(iam / core-edu / content / msg)的 `AuthMiddleware` 仅覆盖 REST 路径,未覆盖 `/graphql`(由 `RouterAuthGuard` 兜底,仍建议补齐字段级守卫)
+- Python 子图(data-ana / ai)缺 `@RequirePermission` 基础设施,需补 Strawberry / Ariadne 中间件
+
+详见:`docs/security/graphql-auth-audit-2026-07.md`
+
---
## 12. 架构约束
@@ -1728,6 +1868,8 @@ GraphQL 响应中,错误通过 `errors[].extensions` 携带 ActionState 字段
| ADR-039 | 乐观锁版本号回传 | CQRS 读后一致性:写返回 version,读携带 expectedVersion,ES 落后则穿透读 MySQL | ✅ 已采纳(v2.1) |
| ADR-040 | Redis Pub/Sub 推送背板 | 边缘网关不挂 Kafka,msg worker → Redis Pub/Sub → realtime-gateway 订阅,轻量 + 按需订阅 | ✅ 已采纳(v2.1) |
| ADR-041 | ScopeToken 优化大规模 ID 列表 | 不传全量数组,传极短 token,子图从 Redis SMEMBERS 获取,降低 HTTP payload 开销 | ✅ 已采纳(v2.1) |
+| ADR-042 | portal-shell 前端数据访问四层分层(2026-07-17) | Widget → API → Operations → Hook,废弃 widget 内联 gql 字面量,集中管理 GraphQL 文档 | ✅ 已采纳(v2.1,lib/api/ 7 domain + 51 operations) |
+| ADR-043 | PQ Manifest + APQ 安全加固(2026-07-17) | 前端只发 query hash,Router 仅解析白名单 manifest,叠加深度/成本/introspection 限制 | ✅ 已采纳(v2.1,pq-manifest.json + router.yaml limits) |
---
@@ -1994,12 +2136,33 @@ graph LR
### 16.4 v2.1 关联 spec 文档
-| 文档 | 用途 |
-| --------------------------------------------------------------------------- | ---------------------------------------------------------- |
-| `docs/superpowers/specs/2026-07-14-architecture-v2-redesign-design.md` | v2.1 架构重设计主 spec(ADR-023~041 决策源) |
-| `docs/superpowers/specs/2026-07-14-portal-shell-widget-dashboard-design.md` | portal-shell 插件化仪表盘设计 spec |
-| `infra/port-allocation.md` | 端口分配唯一源(含 apollo-router/config-service/Temporal) |
+| 文档 | 用途 |
+| ------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
+| `docs/superpowers/specs/2026-07-14-architecture-v2-redesign-design.md` | v2.1 架构重设计主 spec(ADR-023~041 决策源) |
+| `docs/superpowers/specs/2026-07-14-portal-shell-widget-dashboard-design.md` | portal-shell 插件化仪表盘设计 spec |
+| `docs/superpowers/specs/2026-07-17-portal-shell-data-abstraction-and-graphql-hardening-design.md` | portal-shell 前端数据访问层 + GraphQL 安全栈加固 spec(ADR-042/043) |
+| `docs/superpowers/plans/2026-07-17-portal-shell-data-abstraction-and-graphql-hardening.md` | portal-shell 数据抽象与 GraphQL 加固 20-task 实施 plan |
+| `docs/security/graphql-auth-audit-2026-07.md` | 50 resolver @auth 审计报告(35 TS + 15 Python) |
+| `infra/port-allocation.md` | 端口分配唯一源(含 apollo-router/config-service/Temporal) |
+
+### 16.5 portal-shell 数据抽象与 GraphQL 加固子阶段(2026-07-17 新增)
+
+> 来源:[spec v1.0](../superpowers/specs/2026-07-17-portal-shell-data-abstraction-and-graphql-hardening-design.md) + [plan](../superpowers/plans/2026-07-17-portal-shell-data-abstraction-and-graphql-hardening.md)
+> 关联 ADR:ADR-042(前端数据访问四层分层)、ADR-043(PQ Manifest + APQ 安全加固)
+
+| 子阶段 | 内容 | 退出标准 | 状态 |
+| ------ | ------------------------------------------------------------ | --------------------------------------------------------- | ------- |
+| M1 | lib/api 四层架构 + 7 domain 迁移 + 31 widget 全量切换 | 0 处内联 gql 字面量、95/95 测试通过 | ✅ 完成 |
+| M2 | 迁移完整性验证(typecheck + lint + test 全绿) | 0 error / 0 warning / 85 测试通过(M1 收尾) | ✅ 完成 |
+| M3 | GraphQL 安全加固(APQ + PQ Manifest + router limits + 测试) | apollo-router 启用 manifest + 深度/成本限制 + 10 安全测试 | ✅ 完成 |
+| M4 | Resolver @RequirePermission 审计 + 补齐 | 50 resolver 审计完成、19 TS resolver 补齐守卫 | ✅ 完成 |
+
+**Follow-up(不阻断 M3 验收)**:
+
+- 4 个 TS 子图 `AuthMiddleware` 覆盖 `/graphql` 路径(当前由 `RouterAuthGuard` 兜底)
+- Python 子图(data-ana / ai)补 `@RequirePermission` 基础设施(Strawberry / Ariadne 中间件)
+- 生产环境部署前将 `APOLLO_REQUIRE_PQ_MANIFEST=true` + `APOLLO_ROUTER_INTROSPECTION=false` 写入部署 env
---
-> **本文件 v2.1 已基于代码现状(2026-07-15)全面校准,反映 Apollo Federation + portal-shell 架构重设计(M0-M11 全部完成)。后续代码变更须按 [项目规则 §1](../../.trae/rules/project_rules.md) 同步更新本文件 + 运行 `pnpm run arch:scan`。**
+> **本文件 v2.1 已基于代码现状(2026-07-15)全面校准,反映 Apollo Federation + portal-shell 架构重设计(M0-M11 全部完成)+ 2026-07-17 portal-shell 数据抽象与 GraphQL 加固(M1-M4 完成)。后续代码变更须按 [项目规则 §1](../../.trae/rules/project_rules.md) 同步更新本文件 + 运行 `pnpm run arch:scan`。**