Files
lingo/docs/04-architecture.md
T
ilaandClaude Opus 4.8 060daf02a1 docs: 用户表预留 course_id,记录多教材扩展点
- 04-architecture 3.2:progress/vocab 加预留列 course_id(默认 family-album),
  避免将来接入新概念英语等时迁移用户数据;MVP 仅留列不写多教材逻辑
- 06-tasks:T-301 验收注明该预留列;待办池补"多教材接入"扩展点备忘

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 15:16:59 +08:00

120 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 架构设计
> 本文讲"怎么把技术栈搭起来":系统结构、前后端职责、数据模型、技术难点、开发顺序。
> 具体用了哪些框架 / 库 / 数据库 / 部署方式,见 [技术栈](03-tech-stack.md)。
## 一、系统结构
```
┐
│ 用户浏览器 (大屏手机 / 平板)
│ │
│ ▼ 安装为 PWA,离线缓存
│ 前端 go-app (app.wasm)
│ - 课程列表 / 播放器 / 字幕同步 / 生词本 UI
│ - Service Worker 缓存音频与文稿
│ │
│ ▼ REST API (JSON over HTTPS)
│ 后端 Go net/http
│ - 账号鉴权 / 进度 / 生词本
│ │
│ ▼
│ SQLite 数据库
┘
```
## 二、前后端职责划分
**前端(go-app / wasm)**
- 课程列表、音频播放器
- 字幕同步高亮 + 点击跳转(核心,自写)
- 生词本界面
- PWA manifest + Service Worker
**后端(net/http)**
- 用户注册 / 登录 / 鉴权(方式见技术栈,待定)
- 生词本增删查
- 学习进度读写
- (静态音频与文稿可由 go-app Handler 或 CDN 提供)
## 三、数据模型
数据分两类:**内容数据(静态、只读)** 与 **用户数据(动态、需后端)**。
### 3.1 内容数据 — 静态 `episodes.json`(前端直接读,不入库)
实际素材已存在:`family-album-usa/episodes.json`(约 700KB)+ `family-album-usa/audio/*.mp3`。
结构为 **episode(集)→ act(幕)→ line(句)** 三级(以下为真实结构):
```json
{
"meta": { "version": "1.0.0", "title": "走遍美国 Family Album U.S.A.",
"totalEpisodes": 26, "totalActs": 78, "audioActs": 49, "lastUpdated": "2026-05-29" },
"episodes": [
{
"id": 1, "title": "46 Linden Street", "titleCn": "林登大街46号",
"acts": [
{
"act": 1, "label": "Act I",
"audio": "/family-album/audio/u0101.mp3",
"hasAudio": true, "lineCount": 86,
"lines": [
{ "t": 34.18, "en": "Excuse me. My name is Richard Stewart." }
]
}
]
}
]
}
```
要点(**以实际数据为准,勿臆测字段**):
- **集 episode**:`id` / `title` / `titleCn`(26 集**全部**有中文标题)/ `acts[]`
- **幕 act**:`act` 序号 / `label` / `audio`(服务路径 `/family-album/audio/u{集}{幕}.mp3`)/ `hasAudio` / `lineCount` / `lines[]`
- **句 line**:**只有 `{ t, en }` 两个字段**。`t` 为音频时间戳(秒),`en` 为英文原句。**无 `zh` 字段**——行级中文翻译目前不存在,未来要补需扩展 schema
- 规模:26 集 / 78 个 act 条目,其中 49 个 `hasAudio=true`;`audio/` 目录共 50 个 mp3,合计 6335 句
- ⚠️ **路径映射**:JSON 里的 `/family-album/audio/...` 是**对外服务路径**,对应磁盘目录 `family-album-usa/audio/`,后端路由需做这层映射
- ⚠️ `audio/episode12_act2.mp3` 命名不符合 `u####.mp3` 规则且未被 JSON 引用,属游离文件,接入时需核对
> 多教材扩展:未来接入新概念英语等,可沿用「教材 → 单元 → 句子」三级抽象——「走遍美国」即一个教材。新教材未必每句有时间戳,line 的 `t` 允许缺省。第一版无需为此提前建库,前端按 JSON 渲染即可。
### 3.2 用户数据 — SQLite(需账号,后端读写)
仅存「用户态」,**内容数据不入库**:
**users** — id, email, password_hash, created_at
**progress** — user_id, **course_id**, episode_id, act, last_position(秒), completed, updated_at
**vocab** — id, user_id, **course_id**, word, episode_id, act, context_sentence, created_at
> **`course_id` 是前向兼容的预留列**:MVP 只有「走遍美国」一个教材,建表时即带上此列、固定默认 `"family-album"`。
> 目的是避免将来接入新概念英语等时,对**已产生的用户进度/生词数据**做痛苦的 schema 迁移(用户数据不可重生,内容数据可重生)。
> ⚠️ MVP 阶段**仅留列、填默认值,不写任何多教材逻辑**(不建 courses 表、不改内容 JSON、不做按教材过滤)——多教材接入是 V2+,见 [任务看板](06-tasks.md) 待办池。
**功能模块化**:字幕同步、生词本、播放器做成可复用组件,不同教材按需启用(走遍美国用字幕同步;新概念可能更重单词表与语法)。
## 四、关键技术难点
| 难点 | 说明 | 应对 |
| --- | --- | --- |
| 字幕同步 | 音频 currentTime 匹配 `t`,逐句高亮 + 点句跳转 | 先出最小原型验证 |
| Audio API 互操 | go-app 需通过 syscall/js 调浏览器 | 封装成可复用组件 |
| wasm 首屏体积 | Go wasm 最小约 2MB,首屏较慢 | 离线缓存后续访问快 |
| 离线音频 | 大体积音频缓存策略 | Service Worker 按需缓存 |
## 五、推荐开发顺序
1. **先写「音频 + 时间戳字幕同步」最小原型**(验证最难一环)
2. 搭课程列表 + 播放页骨架
3. 后端账号体系 + 鉴权
4. 生词本(前端 UI + 后端 API)
5. 进度同步
6. PWA manifest + Service Worker 离线化
7. (V2)复读 / 测验 / 打卡
> 原则:先验证最难的字幕同步,跑通再往上搭架子,避免先搭一堆架构最后卡在核心功能。