feat(parent-portal): 完整实现 P4+P5+P6 家长端微前端
实现内容(仲裁裁决驱动,首次即最终方案): P4 核心功能 - 认证:localStorage token 存储(F12)+ REST 登录(ISSUE-004)+ refreshAccessToken 竞态防护 - 子女切换:ChildSwitcher(Tab ≤3 / 下拉 ≥4)+ Zustand store(ISSUE-009 纯前端切换) - 数据查询:urql GraphQL 消费 parent-bff(F9)+ TanStack Query 缓存 - 通知中心:NotificationFeed + 已读/全部已读 mutations - 通知偏好:三维矩阵 + ISSUE-033 localStorage 降级 - 5 层状态管理:URL/Server/Client/Global UI/Form - 跨标签同步:BroadcastChannel + storage 事件 P5 实时推送 - WebSocket 连接 push-gateway + 指数退避重连 - HTTP 轮询降级(60s)+ 实时通知 Hook P6 硬化 - Web Vitals 上报 + OTel trace - i18n 5 语言(zh-CN/en-US/zh-TW/ja-JP/ar-SA 含 RTL) - PWA manifest + Service Worker - CSP 安全头 + 权限点 F7 命名 + 设计令牌三层 测试与构建 - Vitest 92 测试全通过(utils/auth/child-store/ChildSwitcher/NotificationFeed/login) - MSW mock 未就绪上游(parent-bff GraphQL + iam REST + iam GetChildrenByParent P0 阻塞用 fixtures) - Dockerfile 多阶段构建(G1,端口 4002,HEALTHCHECK /api/health) - typecheck + lint 零错误 经验沉淀 - known-issues.md §2.13 追加 12 条实现期经验(无 AI 身份标注) - arch.db 已更新(15 TS 模块 / 482 符号 / 138 proto) 依据:02-architecture-design.md(回写总裁裁决)、coord-final-decisions.md、 president-final-rulings.md、parent-portal_workline.md、parent-portal_contract.md
This commit is contained in:
@@ -434,24 +434,36 @@
|
||||
|
||||
> parent-portal 复用 teacher-portal Shell 暴露的 AppShell / usePermission / ApiClient / ErrorBoundary / 设计令牌 / A11y 工具集,本节仅记录 parent-portal **特有**的"场景→技术"映射,通用前端映射见 §2.12。
|
||||
|
||||
| 场景 | 技术/规则 |
|
||||
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| P4 端口分配 | parent-portal = **4002**(004 §1.2 强制 4 端 4000-4003;ai07 初稿误用 3002 与 iam 冲突,ai15 修订) |
|
||||
| P4 MF Remote 角色 | next.config.js 配 `@module-federation/nextjs-mf` 暴露 `./ChildSwitcher` 等家长端特有组件,复用 Shell 提供的 `AppShell`/`usePermission`/`ApiClient`/`RequirePermission` |
|
||||
| P4 DataScope CHILDREN | 家长仅能查看自己绑定子女的数据(004 §5.4 L0 SELF 变体),前端通过 ApiClient 透传 userId + childId,下游服务按 DataScope 过滤 |
|
||||
| P4 多子女切换 ChildSwitcher | Zustand slice(`selectedChildId`)+ 切换后 `queryClient.invalidateQueries({ queryKey: ['child', prevId] })`;多子女 Tab(≤3)或下拉(≥4);空态/单子女/多子女三态分支 |
|
||||
| P4 多子女数量边界 | 0 子女(EmptyChildState 引导绑定)→ 1 子女(隐藏切换器)→ 2-3(Tab Bar)→ 4-10(下拉)→ >10(搜索 + 列表);超出 10 触发性能预警 |
|
||||
| P4 通知偏好三维矩阵 | `Record<childId, Record<eventType, Record<channel, boolean>>>`;react-hook-form + Zod 校验;默认值矩阵(成绩发布=邮件+短信、作业批改=邮件、教师沟通=短信、学校通知=邮件);渠道可用性校验 |
|
||||
| P4 跨标签同步 | BroadcastChannel API(`parent-portal-sync`)+ localStorage 持久化 + LWW(Last-Write-Wins)冲突解决;同步 selectedChildId / 通知偏好 / 已读状态 |
|
||||
| P4 隐私合规(COPPA/FERPA/PIPL) | 未成年人数据最小化采集;通知偏好默认 opt-in;数据保留 7 年后自动归档;前端不缓存敏感字段到 localStorage(仅 childId + 已读位图) |
|
||||
| P4 i18n 5 语言含 RTL | next-intl 支持 zh-CN / en-US / zh-TW / ja-JP / ar-SA;ar-SA 用 `dir="rtl"` + Tailwind `rtl:` 变体;翻译文件按域分 namespace(parent/grades/notifications/preferences) |
|
||||
| P4 PWA + Service Worker | manifest.json(name/short_name/icons/theme_color)+ Service Worker 缓存策略(App Shell precache + API stale-while-revalidate + 离线兜底页);P5+ 支持离线查看子女成绩缓存 |
|
||||
| P4 API 契约版本管理 | 主版本 URL `/api/v1/*` → `/api/v2/*` + 子版本响应头 `X-API-Version` + Deprecation/Sunset 头埋点 + 低带宽场景 `X-Fields` 字段裁剪(GraphQL 风格,BFF REST 透传) |
|
||||
| P4 性能预算 | Bundle ≤ 80KB JS / 20KB CSS / 200KB 总;recharts 懒加载;MF shared 单例避免 React 重复打包;dynamic import 非首屏组件;预加载子女数据 |
|
||||
| P4 监控与降级 | 10 项前端指标(MF 加载失败率/ApiClient 错误率/Web Vitals/切换延迟等)+ 9 项降级策略(MF 失败回退独立页/BFF 5xx 降级缓存/WS 重试指数退避等) |
|
||||
| P4 模块演化与解耦 | 拆分触发条件(Bundle > 120KB / 团队 > 3 人 / 独立部署需求);拆分后 MF 配置从 Shell 暴露;状态管理迁移路径(Zustand → Server Component + Server Actions);MF 升级路径(MF 2.0 → 3.0) |
|
||||
| P4 iam 家长-学生关联 P0 阻塞 | iam 缺 `GetChildrenByParent` proto RPC + `GET /iam/children` REST + `iam_student_guardians` 表;ai02 补全前 parent-portal 仅能假设单子女硬编码 childId 开发调试 |
|
||||
| P4 BFF 错误码前缀 | **BFF_PARENT\_=parent-bff**(coord final §B5,统一 `BFF_XXX_` 风格);前端按 `BFF_PARENT_*` 前缀路由 i18n key,与 BFF_TEACHER_/BFF_STUDENT_ 对齐 |
|
||||
| 场景 | 技术/规则 |
|
||||
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| P4 端口分配 | parent-portal = **4002**(004 §1.2 强制 4 端 4000-4003;ai07 初稿误用 3002 与 iam 冲突,ai15 修订) |
|
||||
| P4 MF Remote 角色 | next.config.js 配 `@module-federation/nextjs-mf` 暴露 `./ChildSwitcher` 等家长端特有组件,复用 Shell 提供的 `AppShell`/`usePermission`/`ApiClient`/`RequirePermission` |
|
||||
| P4 DataScope CHILDREN | 家长仅能查看自己绑定子女的数据(004 §5.4 L0 SELF 变体),前端通过 ApiClient 透传 userId + childId,下游服务按 DataScope 过滤 |
|
||||
| P4 多子女切换 ChildSwitcher | Zustand slice(`selectedChildId`)+ 切换后 `queryClient.invalidateQueries({ queryKey: ['child', prevId] })`;多子女 Tab(≤3)或下拉(≥4);空态/单子女/多子女三态分支 |
|
||||
| P4 多子女数量边界 | 0 子女(EmptyChildState 引导绑定)→ 1 子女(隐藏切换器)→ 2-3(Tab Bar)→ 4-10(下拉)→ >10(搜索 + 列表);超出 10 触发性能预警 |
|
||||
| P4 通知偏好三维矩阵 | `Record<childId, Record<eventType, Record<channel, boolean>>>`;react-hook-form + Zod 校验;默认值矩阵(成绩发布=邮件+短信、作业批改=邮件、教师沟通=短信、学校通知=邮件);渠道可用性校验 |
|
||||
| P4 跨标签同步 | BroadcastChannel API(`parent-portal-sync`)+ localStorage 持久化 + LWW(Last-Write-Wins)冲突解决;同步 selectedChildId / 通知偏好 / 已读状态 |
|
||||
| P4 隐私合规(COPPA/FERPA/PIPL) | 未成年人数据最小化采集;通知偏好默认 opt-in;数据保留 7 年后自动归档;前端不缓存敏感字段到 localStorage(仅 childId + 已读位图) |
|
||||
| P4 i18n 5 语言含 RTL | next-intl 支持 zh-CN / en-US / zh-TW / ja-JP / ar-SA;ar-SA 用 `dir="rtl"` + Tailwind `rtl:` 变体;翻译文件按域分 namespace(parent/grades/notifications/preferences) |
|
||||
| P4 PWA + Service Worker | manifest.json(name/short_name/icons/theme_color)+ Service Worker 缓存策略(App Shell precache + API stale-while-revalidate + 离线兜底页);P5+ 支持离线查看子女成绩缓存 |
|
||||
| P4 API 契约版本管理 | 主版本 URL `/api/v1/*` → `/api/v2/*` + 子版本响应头 `X-API-Version` + Deprecation/Sunset 头埋点 + 低带宽场景 `X-Fields` 字段裁剪(GraphQL 风格,BFF REST 透传) |
|
||||
| P4 性能预算 | Bundle ≤ 80KB JS / 20KB CSS / 200KB 总;recharts 懒加载;MF shared 单例避免 React 重复打包;dynamic import 非首屏组件;预加载子女数据 |
|
||||
| P4 监控与降级 | 10 项前端指标(MF 加载失败率/ApiClient 错误率/Web Vitals/切换延迟等)+ 9 项降级策略(MF 失败回退独立页/BFF 5xx 降级缓存/WS 重试指数退避等) |
|
||||
| P4 模块演化与解耦 | 拆分触发条件(Bundle > 120KB / 团队 > 3 人 / 独立部署需求);拆分后 MF 配置从 Shell 暴露;状态管理迁移路径(Zustand → Server Component + Server Actions);MF 升级路径(MF 2.0 → 3.0) |
|
||||
| P4 iam 家长-学生关联 P0 阻塞 | iam 缺 `GetChildrenByParent` proto RPC + `GET /iam/children` REST + `iam_student_guardians` 表;ai02 补全前 parent-portal 仅能假设单子女硬编码 childId 开发调试 |
|
||||
| P4 BFF 错误码前缀 | **BFF_PARENT\_=parent-bff**(coord final §B5,统一 `BFF_XXX_` 风格);前端按 `BFF_PARENT_*` 前缀路由 i18n key,与 BFF_TEACHER_/BFF_STUDENT_ 对齐 |
|
||||
| P4 认证 token 存储 | localStorage(F12 裁决,P4 用 localStorage,非 cookie);refreshAccessToken 竞态防护用 inflight Promise 复用,并发请求只触发一次 refresh fetch |
|
||||
| P4 switchChild 纯前端 | ISSUE-009 裁决:切换子女不调后端,仅 Zustand slice + localStorage 持久化 selectedChildId;切换后由前端 invalidateQueries 触发数据刷新 |
|
||||
| P4 通知偏好 localStorage 降级 | ISSUE-033 裁决:P4 localStorage 为准,更新先写本地再尝试 GraphQL mutation(失败不阻塞);P5+ 切换到后端为主存储 |
|
||||
| P4 上游 mock 策略 | MSW 拦截 parent-bff GraphQL + iam REST;iam GetChildrenByParent P0 阻塞用 mock fixtures(student-001 + student-002 双子女);MSW server 在 providers 启动 |
|
||||
| TS noUncheckedIndexedAccess | Record 索引访问返回 `T \| undefined`;内层 Record 改 `Partial<Record<...>>` 或空对象回退(`?? {}`)避免 undefined 传播 |
|
||||
| urql fetchOptions headers 类型 | 返回类型须用 `Record<string, string>` 累积再展开,不可用条件对象(`{...(token?{Authorization}:{})}`)否则 TS 推断不兼容 |
|
||||
| Vitest Promise 身份比较 | `expect(p1).toBe(p2)` 对 Promise 不可靠(async 包装产生新 Promise);改为验证行为副作用(如 fetch 调用次数 === 1 证明竞态防护生效) |
|
||||
| jsdom window.location.href | 设置触发 "Not implemented: navigation" stderr 警告(非错误,测试仍通过);mock 用 `Object.defineProperty(window, "location", {...})` 替代 `vi.spyOn` |
|
||||
| MSW 响应过快观察加载态 | MSW 默认同步响应,加载态测试看不到 "加载中";用 `server.use()` + `delay(ms)` 延迟响应再断言按钮文本 |
|
||||
| Testing Library getByRole 误匹配 | `getByRole("button", { name: /未读/ })` 会匹配通知项 aria-label="未读";改用 `getAllByRole("button")` + find 文本内容过滤精确选中筛选按钮 |
|
||||
| ESLint flat config 测试文件 | 放宽规则需含 `*.test.tsx`/`*.spec.tsx`/`__tests__/**` 模式,否则 tsx 测试文件按严格规则报错 |
|
||||
| Dockerfile 多阶段构建 | G1 裁决首次即多阶段:builder(node:20-alpine 跑 build)+ runner(node:20-alpine 跑 server),端口 4002,HEALTHCHECK 指向 `/api/health`,非 root 用户 nextjs |
|
||||
|
||||
### 2.14 parent-bff(TS/NestJS,P4)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user