提交 eb9c7e99 authored 作者: 王鹏飞's avatar 王鹏飞

docs: map Flutter app to PC learning modules

上级 744a8039
# Flutter APP 到 PC 学习端功能映射
日期:2026-07-17
状态:实施基准
源系统:`/Users/max/code/book/app/book-app`
目标系统:`apps/learning`
## 1. 文档目的
PC 学习端不是一个通用的“首页、图书馆、我的”后台壳,而是现有 Flutter 数字教材 APP 的浏览器版本。本文件把 APP 的真实页面、交互、接口与 PC 信息架构逐项对应,后续模块开发和验收以此为功能基准。
本次迁移遵循三条边界:
1. 业务数据、购买权益、阅读记录、笔记、讨论、错题和订单继续与 APP 共用。
2. Flutter、WebView、原生支付、SQLite 和触摸交互改为适合 PC 浏览器的实现,不追求代码级照搬。
3. APP 中当前不可达、仅残留或明显存在缺陷的能力不会自动视为 PC 首版需求;必须在下表中标为“待确认”。
## 2. 已确认的一级信息架构
APP 底部实际有“课程、图书馆、书架、我的”四个入口,默认停留在图书馆。PC 使用用户已确认的三个一级入口:
| PC 一级入口 | 承接的 APP 能力 | 默认路由 |
| --- | --- | --- |
| 首页 | APP“课程”页:我的课程、继续学习、搜索、最近学习、消息、广告 | `/home` |
| 图书馆 | APP“图书馆”页、搜索、书籍详情、目录、书评、购买/试读入口 | `/library` |
| 我的 | APP“书架”以及 APP“我的”全部功能;采用左侧菜单、右侧内容 | `/my` |
网站根路径 `/` 跳转 `/library`。书籍详情是独立页面 `/book/:bookId`,不是弹窗。阅读器使用独立的沉浸式路由 `/reader/:bookId/:chapterId`,不套普通学习端顶部导航。
## 3. 路由与模块映射
```text
apps/learning/src/modules/
├── auth/ # 登录、验证码、会话、路由保护
├── home/ # APP 课程页
├── library/ # 图书馆筛选与列表
├── search/ # 书籍搜索与搜索记录
├── book/ # 独立书籍详情、目录、书评、购买分支
├── reader/ # PC 阅读器与章节学习闭环
└── my/
├── layout/ # 左侧菜单 + Outlet
├── overview/ # 我的概览与统计
├── books/ # 我的课程/书籍
├── bookshelf/ # 书架
├── history/ # 最近学习
├── favorites/ # 收藏
├── notes/ # 笔记/划线/高亮
├── discussions/ # 讨论与回复
├── wrong-questions/ # 错题
├── reports/ # 学习报告
├── messages/ # 消息中心
├── orders/ # 订单、详情与评价
├── coupons/ # 优惠券
├── wallet/ # 积分与紫荆币
├── profile/ # 个人资料
├── security/ # 手机号、密码、注销
├── feedback/ # 意见反馈
└── help/ # 帮助、关于、协议
```
复杂子域可以继续拥有自己的 `api.ts`、`query.ts`、`query-state.ts`、`types.ts`、`components/` 和 `views/`。仅有一个简单页面的模块保持浅层。不得为了目录整齐创建只有一行转发逻辑的薄封装。
### 3.1 目标路由表
| 路由 | 页面/状态 | APP 来源 |
| --- | --- | --- |
| `/login` | 手机号密码/验证码登录、忘记密码 | `pages/login`, `forget_pwd`, `reset_pwd` |
| `/home` | 我的课程、继续学习、最近学习、消息 | `pages/course` |
| `/library` | 分类、标签、收费、排序、广告、书单 | `pages/library` |
| `/search?q=&page=` | 搜索历史、结果、分页 | `pages/search` |
| `/book/:bookId` | 详情、目录、推荐、简介、书评摘要、学习/购买动作 | `pages/book_detail`, `book_info` |
| `/book/:bookId/reviews` | 全部书评 | `pages/book_score` |
| `/reader/:bookId/:chapterId` | 目录、正文、位置、笔记、讨论、练习 | `pages/read_web`, `assets/html/read.html` |
| `/my` | 用户与学习/账户统计概览 | `pages/mine` |
| `/my/books` | 我的课程/书籍 | `pages/course` |
| `/my/bookshelf` | 书架、选择、删除、购买 | `pages/book_shop` |
| `/my/history` | 最近学习 | `pages/study_history` |
| `/my/favorites` | 收藏 | `pages/user_love` |
| `/my/notes` | 按书聚合的笔记 | `pages/user_notes` |
| `/my/notes/:bookId` | 单书笔记、定位、编辑、删除 | `pages/user_notes_des`, `user_edit_note` |
| `/my/discussions` | 按书聚合的讨论 | `pages/user_discuss` |
| `/my/discussions/:bookId` | 讨论、回复、点赞、删除 | `pages/user_discuss_des` |
| `/my/wrong-questions` | 按书聚合的错题 | `pages/user_wrong` |
| `/my/wrong-questions/:bookId` | 单书错题 | `pages/user_wrong_des` |
| `/my/reports/:bookId` | 学习报告 | `pages/study_report` |
| `/my/messages` | 消息、已读、业务跳转 | `pages/user_msg` |
| `/my/orders` | 状态筛选、搜索、分页 | `pages/user_order` |
| `/my/orders/:orderNo` | 订单详情、取消、续付、评价 | `pages/user_order_*` |
| `/my/coupons` | 优惠券状态与分页 | `pages/user_coupon` |
| `/my/wallet` | 积分、紫荆币流水与充值 | `pages/user_point`, `user_coin*` |
| `/my/profile` | 头像、昵称、性别 | `pages/user_info`, `user_nick`, `user_gender` |
| `/my/security` | 修改手机号/密码、注销 | `pages/user_security`, `change_*` |
| `/my/feedback` | 意见反馈 | `pages/user_feedback` |
| `/my/help` | 帮助中心、关于与协议 | `pages/help_center`, `user_about`, `user_terms` |
订单、钱包与支付模块在功能上归属“我的”,但实现时可在 `modules/my` 内保持独立子域,避免一个 `my/api.ts` 持续膨胀。
## 4. 各模块功能基准
### 4.1 首页
首页承接 APP 的课程页,而不是新增一套无数据来源的营销首页:
- 我的课程分页列表。
- 课程卡片显示封面、书名、作者、未学习/已学完/当前进度。
- 点击书籍进入独立详情;点击“继续学习”进入上次章节。
- 搜索入口、最近学习入口、消息入口和未读数。
- 运营广告轮播与空、加载、错误状态。
主要接口:`myCourse`、`getBookInformation`、`getListAll(type=2)`、`getMessageNums`。
### 4.2 图书馆、搜索与书籍详情
图书馆真实筛选协议为:
```text
category category_id,默认 0
label label_id,默认 0
price all | paid | free,对应 is_free
sortField none | read_num | rating
sortOrder asc | desc
page 正整数
pageSize 默认 20(PC)
view grid | list(仅 UI 状态)
```
这些可恢复状态使用 `nuqs` 写入 URL。APP 当前并不存在 `tab=all|course` 或 `sort=latest|popular` 的图书馆协议,因此早期架构证明中的这两个字段不得继续作为业务契约。
图书馆必须覆盖:分类、标签、免费/收费、阅读人数/评分排序、广告、分页、收藏;搜索必须覆盖服务端搜索记录、清空历史、结果分页和收藏。
书籍详情必须覆盖:
- 封面、作者、价格/VIP 价格、评分、学习人数。
- 目录树、当前章、已读、试读标记。
- 编辑推荐、简介 HTML、本书信息、评分分布和全部书评入口。
- 收藏、加入书架、学习报告、阅读/继续阅读/试读/购买分支。
- 免费、已拥有、有试读、未拥有、未登录五类权限状态。
### 4.3 阅读器
PC 阅读器首个完整闭环包括:
- 树形目录、前后章、全文搜索和指定章节直达。
- 富文本、图片、音频、视频替代内容、公式、代码、图集、扩展阅读和气泡。
- 当前章节、稳定阅读锚点、进度、阅读记录与阅读时长。
- 文本选区、划线、高亮、笔记、公开状态、编辑和删除。
- 章节讨论、回复、点赞和删除。
- 章节练习、答案结果和错题数据。
- 购买/试读锁章处理、会话过期和错误恢复。
- 鼠标、滚轮、键盘、焦点与可访问性。
APP 的历史 `positioning` 是 DOM 节点路径与 offset JSON。PC 必须先做兼容读取和回显;新标注建议同时保存文本引用/上下文锚点,不能直接更换格式而导致历史笔记失效。
以下能力不列入第一版上线阻塞项,但需要保留演进边界:离线 ZIP 下载、SQLite 队列、断网批量同步、原生防截屏和 iOS 内购。APP 当前没有可用的字号/字体/行距/正文主题设置,所以这些属于 PC 增强能力,不应标成“APP 已有功能”。
### 4.4 我的
“我的”采用固定左侧菜单与右侧子路由内容,`/my` 是概览。功能不得堆在一个 `MyView` 中:
- 概览:用户资料、学习资产计数、账户资产计数、最近学习和消息入口。
- 学习资产:我的书籍、书架、收藏、历史、笔记、讨论、错题、报告。
- 账户资产:订单、优惠券、积分、紫荆币和支付/充值状态。
- 个人设置:资料、安全、消息、反馈、帮助、关于、协议和退出。
各列表的搜索、状态、页码、排序和当前 tab 进入 URL;编辑正文、回复正文、验证码、支付二维码和 token 不进入 URL。
## 5. 状态和组件边界
| 状态类型 | 工具 | 示例 |
| --- | --- | --- |
| 服务端事实 | TanStack React Query | 课程、书单、详情、用户、笔记、订单 |
| 刷新后应恢复的页面操作 | nuqs/路径参数 | 筛选、分页、tab、章节、锚点、侧栏面板 |
| 跨组件瞬时 UI | Zustand(确有需要时) | 阅读器工具栏展开、临时选区、全局播放器 |
| 局部瞬时状态 | React | 输入焦点、未提交表单、hover |
路由页面负责组合 query、URL 状态和业务事件;模块组件只接收明确值和语义回调。Ant Design 已有的表单、按钮、菜单、分页、抽屉、提示和反馈直接使用,不自写基础组件,也不为统一 API 再包一层。领域组件按独立业务职责拆分,例如 `BookCard`、`ChapterTree`、`ReaderNotesPanel`,而不是把整个页面写进单一组件,也不是把每个按钮都抽成文件。
## 6. API 与浏览器安全前置条件
开发环境按用户指定使用:
```text
/api/web/* -> https://ebook-app.ezijing.com/api/book/*
```
这只是 Vite 同源代理协议,不等于生产可用的浏览器鉴权。现有 APP API 每次请求要求 `appId`、`appSecret`、`Sign` 和 Bearer token;`appSecret` 与签名密钥不能进入浏览器代码。
生产前必须由 `com-ebook-app-api` 提供 Web 会话/BFF 边界:
- 浏览器只持有 HttpOnly、Secure、SameSite 合理的会话 Cookie。
- Web 服务端完成会员身份、原 APP 业务调用或业务层复用。
- 登录、验证码、刷新、CSRF、频率限制和审计在服务端处理。
- 不允许前端使用 `X-Skip-Sig` 绕过签名。当前 `AppAuth` 对该头直接跳过校验,生产整改时必须限制为不可从公网触发或移除。
前端可以先完成类型、query、页面和代理契约,但真实受保护接口联调以 Web 会话接口就绪为准。
## 7. 会员与后台管理入口
同手机号才视为同一个自然人:会员侧 `members.phone` 与后台 `admin_user.tel` 相同,手机号不同即为两个用户。前端不自行比较本地手机号。
学习端会话上下文由服务端返回 `has_admin_access`。仅为 `true` 时右上角显示“进入后台管理”。点击后由服务端签发一次性、短时、单次消费 ticket;管理端 `/admin/sso` 兑换为独立后台 token,移除 URL ticket 后进入后台。进入过程不再要求输入后台密码,但后台 API 必须再次校验账号启用、有效期、角色和权限。
现有后台 `checkSsoLogin` 已能通过 TGC 按手机号查 `admin_user`,但尚不能证明它满足学习会员到后台的一次性交换;其 SSO 分支的账号状态/有效期校验也需要补齐。
## 8. 验收口径
“完整复刻 APP”按功能与数据闭环验收,不按 Flutter 控件像素照搬:
1. 上述路由对应能力均可从 PC 信息架构到达。
2. 同一会员在 APP 和 PC 看到一致的课程、权益、进度、笔记、讨论、错题与订单。
3. 书籍权限、试读、购买、章节内容和写操作由服务端校验。
4. URL 恢复列表状态、详情、章节、阅读锚点和业务面板。
5. 阅读器历史标注可以兼容显示,新的标注经刷新和跨端打开仍可定位。
6. 有后台账号才显示入口,后台免密进入不共享学习 token。
7. 所有模块具备加载、空、错误、未授权和重试状态,并通过常见 PC 宽度与键盘操作验收。
## 9. 代码证据
- APP 路由与主导航:`book-app/lib/routes/routes.dart`、`lib/pages/main/`。
- 首页/课程:`lib/pages/course/`、`lib/apis/course.dart`。
- 图书馆/搜索/详情:`lib/pages/library/`、`search/`、`book_detail/`、`book_info/`、`book_score/`、`lib/apis/library.dart`。
- 阅读器:`lib/pages/read_web/`、`assets/html/read.html`、`read_unline.html`、`lib/utils/sql.dart`。
- 登录与会话:`lib/pages/login/`、`lib/store/user.dart`、`lib/services/http.dart`、`lib/apis/account.dart`。
- 我的:`lib/pages/mine/`、`lib/pages/user_*`、`study_history/`、`study_report/`、`book_shop/`、`lib/apis/mine.dart`、`shop.dart`。
- APP API 路由与安全:`com-ebook-app-api/route/app.php`、`app/middleware/AppAuth.php`、`LoginTokenAuth.php`。
# PC Learning Migration Implementation Plan
> **For agentic workers:** Use `superpowers:subagent-driven-development` for module implementation and `superpowers:test-driven-development` for each behavior change. Each worker owns one module and must not edit another module without coordinator approval.
**Goal:** Build `apps/learning` as a PC-browser implementation of the existing Flutter `book-app`, first establishing the correct application shell and module boundaries, then completing browsing, reading, personal-center, transaction, and admin-SSO workflows against browser-safe APIs.
**Source of truth:** `docs/architecture/flutter-app-to-pc-feature-map.md` and the actual Flutter/API code paths cited there. The earlier Stage 0 proof UI is not a product specification.
**Architecture:** React 19 + TypeScript + Vite 8 application, Ant Design 6 primitives, TanStack React Query for server state, nuqs for recoverable URL state, Zustand only for truly transient cross-component state. The app remains independent from `apps/admin`; production serves learning at `/` and admin at `/admin/`.
**Execution rule:** Complete Milestone A before sending Home, Library/Book, Reader, and My to separate Terra workers. Those workers may run in parallel only when their file ownership does not overlap. Shared router, HTTP, authentication, layout, theme, and generated API types remain coordinator-owned.
## Global constraints
- Work only in `/Users/max/code/book/admin/center-book` on branch `next`.
- Treat `/Users/max/code/book/app/book-app` and both API repositories as read-only unless a later task explicitly authorizes backend edits.
- Preserve the user-owned `skills-lock.json` change and any unrelated worktree changes.
- Do not copy Flutter widgets mechanically. Preserve business behavior and data, then adapt the interaction to PC.
- Do not put APP `appSecret`, signing secret, member token, admin token, or payment data in URL or browser bundles.
- Do not use `X-Skip-Sig` as a browser integration mechanism.
- Use Ant Design directly for standard controls; create only domain components with meaningful behavior.
- A route view coordinates URL state, Query hooks, semantic handlers, and domain components. It must not become the entire page implementation.
- Each list/detail mutation must have explicit Query invalidation or optimistic-update behavior and tests.
- Every recoverable page operation must have a URL contract before UI implementation.
## Milestone A — Reconcile the shell with the audited APP
This milestone is the next executable unit. It deliberately builds structure and contracts, not fake business responses.
### Task A1: Remove proof-only business assumptions
**Modify:**
- `apps/learning/src/modules/library/query-state.ts`
- `apps/learning/src/modules/library/query-state.test.tsx`
- `apps/learning/src/modules/library/api.ts`
- `apps/learning/src/modules/library/query.ts`
- `apps/learning/src/modules/library/query.test.ts`
- `apps/learning/src/modules/library/views/LibraryView.tsx`
- `docs/superpowers/plans/2026-07-17-stage-0-monorepo-foundation.md`
**Behavior:**
- Replace proof fields `sort=latest|popular` and `tab=all|course` with the actual APP library protocol: `category`, `label`, `price`, `sortField`, `sortOrder`, `page`, `pageSize`, and `view`.
- Map URL values to API fields only in `api.ts`: `category_id`, `label_id`, `is_free`, `sort_field`, `sort`, `page`, `page_size`.
- Keep default values out of the serialized URL.
- Do not call the protected upstream API until browser-safe authentication is available; the shell must show a documented unavailable/loading boundary rather than fabricated books.
- Move standalone book details out of the library implementation into the `book` module.
**Tests first:**
- Parse all valid values and fall back on invalid enum/integer values.
- Reset page to 1 when a filter changes.
- Use `replace` for text/view changes and `push` for explicit filter, sort, and page actions.
- Query key contains only the normalized API inputs and changes for every input that changes the response.
### Task A2: Establish shared HTTP and response contracts
**Create:**
- `apps/learning/src/api/types.ts`
- `apps/learning/src/api/errors.ts`
- `apps/learning/src/api/unwrap.ts`
- `apps/learning/src/api/unwrap.test.ts`
- `apps/learning/src/router/paths.ts`
**Modify:**
- `apps/learning/src/utils/http.ts`
- `apps/learning/src/main.tsx`
**Interfaces:**
```text
ApiEnvelope<T> = { code, message/msg, data }
ApiError = normalized transport/business/auth error
unwrapApiData(response) -> T or throws ApiError
```
**Behavior:**
- Keep browser base URL `/api/web` and `withCredentials: true`.
- Never generate APP signatures or store bearer tokens in this client.
- Normalize APP-style `code !== 200`, HTTP 401/403, cancellation, and transport errors.
- Authentication redirection belongs to the auth/router boundary, not an Axios import cycle.
- Configure Query retry to skip auth and business errors and only retry safe transient failures.
### Task A3: Build the application route/layout skeleton
**Create or modify:**
- `apps/learning/src/layouts/LearningLayout.tsx`
- `apps/learning/src/layouts/LearningLayout.css`
- `apps/learning/src/layouts/LearningLayout.test.tsx`
- `apps/learning/src/router/RootLayout.tsx`
- `apps/learning/src/router/routes.tsx`
- `apps/learning/src/router/routes.test.tsx`
- `apps/learning/src/modules/home/routes.tsx`
- `apps/learning/src/modules/home/views/HomeView.tsx`
- `apps/learning/src/modules/home/views/HomeView.css`
- `apps/learning/src/modules/library/routes.tsx`
- `apps/learning/src/modules/book/routes.tsx`
- `apps/learning/src/modules/book/views/BookDetailView.tsx`
- `apps/learning/src/modules/reader/routes.tsx`
- `apps/learning/src/modules/reader/views/ReaderView.tsx`
**Behavior:**
- `/` and unknown ordinary routes redirect to `/library`.
- Top navigation contains exactly 首页 `/home`、图书馆 `/library`、我的 `/my`.
- The right side has user/session space and a conditional admin-entry slot; it must not infer admin access locally.
- `/book/:bookId` is a standalone content page while the top navigation remains selected on 图书馆.
- `/reader/:bookId/:chapterId` uses a full-screen reader layout outside `LearningLayout`.
- The shell is desktop-first but remains usable at tablet widths; no final module visual design is required in this task.
- Home placeholder visibly describes its audited responsibilities (courses and continue learning), not generic initialization text.
**Tests first:**
- Root redirect, unknown redirect, book route, reader route, and nested My route.
- Top navigation selection for `/home`, `/library`, `/book/100`, and `/my/books`.
- Reader route does not render the normal top navigation.
### Task A4: Build the nested My information architecture
**Create or modify:**
- `apps/learning/src/modules/my/routes.tsx`
- `apps/learning/src/modules/my/routes.test.tsx`
- `apps/learning/src/modules/my/layout/MyLayout.tsx`
- `apps/learning/src/modules/my/layout/MyLayout.css`
- `apps/learning/src/modules/my/layout/menu.ts`
- `apps/learning/src/modules/my/overview/views/MyOverviewView.tsx`
- `apps/learning/src/modules/my/books/views/MyBooksView.tsx`
- `apps/learning/src/modules/my/bookshelf/views/MyBookshelfView.tsx`
**Behavior:**
- `/my` is the overview index.
- `/my/books` and `/my/bookshelf` are real independent child routes.
- Use `Layout.Sider`, `Menu`, `Content`, and `Outlet` directly.
- Menu selection must work for nested detail URLs by longest-prefix matching, not exact pathname equality.
- The three initial pages show layout regions and domain responsibilities only. Do not invent server data.
- `menu.ts` records the future groups from the feature map (learning assets, account assets, settings), but do not expose dead menu links before their route exists.
### Task A5: Record maintenance boundaries
**Create:**
- `apps/learning/AGENTS.md`
**Modify:**
- `AGENTS.md`
**Document:**
- Flutter is the functional source of truth.
- Exact route/module ownership.
- Query/nuqs/Zustand decision tree.
- Ant Design direct-use and no-over-encapsulation rules.
- API signature/session security boundary.
- Reader is an independent layout/domain.
- My submodules must remain nested under `modules/my/<domain>`.
### Task A6: Verify and commit the reconciled shell
Run from repository root:
```bash
pnpm test:learning
pnpm lint:learning
pnpm build:learning
pnpm test
pnpm build
pnpm verify:build-layout
git diff --check
```
Also audit:
```bash
rg -n "latest|popular|tab: 'all'|X-Skip-Sig|appSecret|redux|useSearchParams|new URLSearchParams" apps/learning/src
```
Expected: no proof-only library values, no secret/signature implementation, no Redux, and no scattered search-param parsing. Commit only reviewed project changes; leave `skills-lock.json` untouched unless the user explicitly asks to include it.
## Milestone B — Browser authentication and application context
**Frontend ownership:** `modules/auth`, `api`, `router`, `layouts`.
**Backend dependency:** browser-safe `/api/web/auth/*` or equivalent SSO session endpoints.
Deliver:
- Login/password/SMS/forgot-password flows.
- `GET auth/context` Query containing member session and `has_admin_access`.
- Protected/public route policy matching the final product decision.
- HttpOnly-cookie session initialization, logout, CSRF integration, and safe return URL.
- Conditional top-right admin entry.
- One-time ticket request and `/admin/sso` exchange; no admin password re-entry.
Do not start protected live-data integration until this backend contract is confirmed. Mock Service Worker may be introduced only for tests and local UI scenarios, never as hidden production fallback.
## Milestone C — Home module
**Owner:** `modules/home/**` only, plus tests.
**APP source:** `pages/course/**`.
Deliver Query/API/types and UI for course pagination, progress/status, continue learning, advertisements, recent learning, and message badge. Course filters/pagination use URL state where applicable. Continue-learning navigation resolves the latest book detail and routes to the saved chapter.
Acceptance: empty/loading/error/paginated states, progress semantics, detail/reader navigation, and query-key tests.
## Milestone D — Library, search, and book details
**Owners:** `modules/library/**`, `modules/search/**`, and `modules/book/**`; no shared-file edits without coordinator review.
Deliver:
- Categories, labels, real filter mapping, list/grid mode, pagination, favorite mutation.
- Search history, clear, keyword results, pagination, cancellation of stale search.
- Standalone detail, recursive chapter tree, recommendation, sanitized description HTML, book metadata, rating summary/list.
- Free/owned/preview/purchase/guest action selector, bookshelf mutation, report/read navigation.
Acceptance: refreshable URL state; mutation rollback/invalidation; recursive chapter tests; sanitization tests; permission action matrix.
## Milestone E — My learning assets
Split into independent child tasks under `modules/my`:
1. `overview`, `books`, `bookshelf`, `history`, `favorites`.
2. `notes`, including per-book details and reader positioning.
3. `discussions`, including replies, likes, and deletion.
4. `wrong-questions` and `reports`.
Each child owns its API/query/state/types/components/views. All list state is URL-restorable. Successful mutations invalidate only the affected book, aggregate, and statistic keys.
## Milestone F — Reader and learning loop
Reader work is isolated because it has the highest migration risk.
### F1 Reader document foundation
- Typed section content, recursive directory, previous/next chapter, full-text search.
- Three-column desktop layout: collapsible directory/search, document, notes/discussion panel.
- Safe rich-content rendering and media/formula/code adapters.
- URL contract for chapter, anchor, panel, note/discussion identifiers.
### F2 Progress and historical annotation compatibility
- Stable anchor restoration and debounced progress/read-record writes.
- Visibility lifecycle for read-time open/close.
- Legacy `positioning` parser/renderer with fixture tests from real data.
- New annotation anchor format that preserves a legacy-compatible payload until backend migration is approved.
### F3 Interaction and assessment
- Mouse/keyboard text selection, line/highlight/note create-edit-delete.
- Discussion/reply/like/delete.
- Chapter exercise, answer submit/result, wrong-question linkage.
- Locked chapter, preview, purchase, expired session, and retry states.
Offline ZIP/SQLite synchronization is a separate later plan after the online reader passes cross-device parity tests.
## Milestone G — My account, transactions, and settings
Split by ownership:
- `messages`.
- `orders` and PC QR payment state machine.
- `coupons` and `wallet`.
- `profile` and `security`.
- `feedback` and `help`.
PC payment replaces native SDK/iOS IAP with server-created WeChat/Alipay QR orders, idempotent status polling, timeout, cancel, and entitlement refresh. Amounts and discounts are always calculated on the server.
## Milestone H — Deployment, security, and parity verification
- One Jenkins Pipeline builds both applications and verifies `dist/learning` plus `dist/admin`.
- Nginx serves learning `/`, admin `/admin/`, and proxies `/api/web/` plus `/api/admin/` before SPA fallback.
- Add E2E flows: login → library; course → continue reader; annotate → refresh; APP/PC parity fixture; admin-ticket exchange; QR payment simulation.
- Security review: XSS/CSP, CSRF, session fixation, ticket replay, object authorization, rate limiting, secret scan, and the `X-Skip-Sig` bypass.
- Performance review: code splitting by route, long-document rendering, image/media lazy loading, Query cache bounds, reader memory, and Core Web Vitals.
## Parallel worker ownership after Milestone A
| Worker | Allowed files | Forbidden shared files |
| --- | --- | --- |
| Home | `modules/home/**` | router, layouts, api base, My/Library/Reader |
| Library/Book | `modules/library/**`, `modules/search/**`, `modules/book/**` | router aggregator, auth, reader, My |
| Reader | `modules/reader/**` | root layout, auth, other modules |
| My | `modules/my/**` | root layout, auth, other modules |
The coordinator integrates module route exports, shared API types, theme tokens, authentication, and dependency changes. Workers report any required shared change rather than editing it opportunistically.
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论