From b9bcbf7e6b865f33036256e45bd2e3b68d3b81eb Mon Sep 17 00:00:00 2001 From: ila Date: Sun, 21 Jun 2026 19:30:14 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=A1=A5=E5=85=A8=20AI=20=E5=85=A5?= =?UTF-8?q?=E5=8F=A3/API/=E8=B7=AF=E7=94=B1/=E7=8E=B0=E7=8A=B6=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E5=B9=B6=E5=AF=B9=E9=BD=90=E4=B8=80=E8=87=B4=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增(Codex 起草,本次纳入并校对): - AGENTS.md:仓库级 AI 强约束入口 - docs/00-ai-start-here.md:AI 开发入口与导航 - docs/api.md:账号/生词本/进度 API 合约草案 - docs/routes.md:go-app 页面路由与组件归属 - docs/current-state.md:当前实现状态 补充与对齐: - 验证命令补 bash(WSL/Linux 为主,PowerShell 为备):00-ai-start-here、AGENTS - 04-architecture:新增第六节"项目结构(包布局)"+ 3.2 建表 SQL 草案 - docs/README 导航补 06-tasks;CLAUDE 目录树补 AGENTS/scripts/design_mockups - 00-ai-start-here 去除已过时的"需要补齐"段 - 06-tasks:Phase 2/3/4/5 交叉引用 api.md / routes.md / 包布局 Co-Authored-By: Claude Opus 4.8 --- AGENTS.md | 86 ++++++++++++++++ CLAUDE.md | 20 ++-- docs/00-ai-start-here.md | 155 +++++++++++++++++++++++++++++ docs/03-tech-stack.md | 13 ++- docs/04-architecture.md | 67 ++++++++++++- docs/05-coding-rules.md | 13 ++- docs/06-tasks.md | 10 +- docs/README.md | 9 ++ docs/api.md | 209 +++++++++++++++++++++++++++++++++++++++ docs/current-state.md | 63 ++++++++++++ docs/routes.md | 78 +++++++++++++++ 11 files changed, 710 insertions(+), 13 deletions(-) create mode 100644 AGENTS.md create mode 100644 docs/00-ai-start-here.md create mode 100644 docs/api.md create mode 100644 docs/current-state.md create mode 100644 docs/routes.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..dc727c2 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,86 @@ +# AGENTS.md + +> Repository-level rules for AI coding agents. Read this before changing files. + +## Mission + +Build a mobile-first, installable, offline-capable English intensive-listening PWA for "Family Album, U.S.A." using audio plus sentence-synced English subtitles. The MVP is not a video site, social product, generic course platform, or AI speaking scorer. + +## Required Reading Order + +Before writing code, read these files in order: + +1. `docs/00-ai-start-here.md` +2. `docs/01-vision.md` +3. `docs/02-requirements.md` +4. `docs/03-tech-stack.md` +5. `docs/04-architecture.md` +6. `docs/05-coding-rules.md` +7. `docs/06-tasks.md` +8. `CLAUDE.md` + +Use `docs/00-ai-start-here.md` for navigation. Use `docs/05-coding-rules.md` as the hard implementation rulebook. + +## Task Discipline + +- Work from `docs/06-tasks.md`. +- Pick only the first `TODO` task whose dependencies are all `DONE`. +- Do exactly one task per development turn. +- Mark it `DOING` before implementation, then `DONE` only after its acceptance checks pass. +- Do not jump ahead, batch multiple tasks, or add V2/V3 scope while doing MVP work. + +## MVP Scope + +MVP scope is ep1-17 plus these P0 capabilities: + +- Course list +- Audio playback +- Sentence-synced subtitles +- Vocabulary notebook +- Account and cross-device sync +- PWA install/offline use + +Do not implement video playback, line-level Chinese translation, social features, AI speaking scoring, SRS, tests/quizzes, AB repeat, or multi-course logic unless a task explicitly asks for it. + +## Technical Constraints + +- Frontend: go-app, Go to WebAssembly. +- Styling: plain CSS files, mobile-first, loaded via go-app handler styles. +- State: go-app native state and observers. +- Backend: Go `net/http`. +- Database: SQLite for user data only. +- Auth: httpOnly Session Cookie. +- Deployment target: single self-hosted Go binary serving wasm, static assets, audio, and APIs. +- Do not add new frameworks, heavy libraries, or third-party dependencies without explicit approval. + +## Data Rules + +- Content truth source: `family-album-usa/episodes.json`. +- Do not invent fields. `line` has only `{ "t", "en" }`; there is no `zh`. +- JSON audio paths such as `/family-album/audio/u0101.mp3` are service paths. Map them to disk under `family-album-usa/audio/`. +- Do not fabricate audio for ep18-26. +- `notion_docs/` and `*.bak` are read-only archives. Do not edit, delete, or treat them as source of truth. + +## Verification + +Before claiming a task is done, run the relevant checks from `docs/05-coding-rules.md` and report exactly what passed or failed. + +This project is primarily developed under WSL / Linux (bash). Use bash commands first: + +```bash +GOOS=js GOARCH=wasm go build -o app.wasm # frontend wasm +go build # backend +go vet ./... +python3 scripts/validate_episodes.py +``` + +Windows PowerShell equivalents: + +```powershell +$env:GOOS='js'; $env:GOARCH='wasm'; go build -o app.wasm +go build +go vet ./... +python scripts/validate_episodes.py +``` + +Only run the content validator when content data or its schema is touched. diff --git a/CLAUDE.md b/CLAUDE.md index 48f9503..b01c8c0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,15 +12,19 @@ ## 文档地图(`docs/`) -三份文档职责分层,按需读对应那份;**不要把技术细节往 vision/requirements 里塞**: +文档职责分层,按需读对应那份;**不要把技术细节往 vision/requirements 里塞**: | 文档 | 职责(回答什么) | 该查它当… | | --- | --- | --- | +| [`docs/00-ai-start-here.md`](docs/00-ai-start-here.md) | **AI 开发入口**:阅读顺序、任务领取、验证命令 | AI coding agent 进入项目的第一站 | | [`docs/README.md`](docs/README.md) | 项目概览与导航 | 想先有个整体印象 | | [`docs/01-vision.md`](docs/01-vision.md) | **为什么 / 为谁 / 产品原则 / 不做什么** | 拿不准取舍方向、判断某需求该不该做 | | [`docs/02-requirements.md`](docs/02-requirements.md) | **要什么 + 怎么算达成**(产品语言,无技术词、含验收标准) | 确认功能范围、优先级、验收判据 | -| [`docs/03-tech-stack.md`](docs/03-tech-stack.md) | **用什么**:框架 / 数据库 / UI / 状态管理 / 部署(速查,含待定项) | 想知道某层用哪个技术 | +| [`docs/03-tech-stack.md`](docs/03-tech-stack.md) | **用什么**:框架 / 数据库 / UI / 状态管理 / 部署(速查) | 想知道某层用哪个技术 | | [`docs/04-architecture.md`](docs/04-architecture.md) | **怎么搭**:系统结构、职责划分、**数据模型**、技术难点 | 实际写代码、查数据结构与字段 | +| [`docs/api.md`](docs/api.md) | **API 合约草案**:账号 / 生词本 / 进度接口 | 写后端 API 或前端 API client 前 | +| [`docs/routes.md`](docs/routes.md) | **路由与页面结构**:页面路由、职责、组件归属 | 写 go-app 页面与导航前 | +| [`docs/current-state.md`](docs/current-state.md) | **当前实现状态**:仓库现实、当前可做任务 | 判断代码现状和下一步任务 | | [`docs/05-coding-rules.md`](docs/05-coding-rules.md) | **编码规则**:写代码的硬约束与"完成"的定义 | ⚠️ 动手写代码**之前**必读 | | [`docs/06-tasks.md`](docs/06-tasks.md) | **任务看板**(AI 的 Jira):MVP 拆解、依赖、状态 | 决定"这次做什么"时 | @@ -47,10 +51,14 @@ ``` lingo/ +├── AGENTS.md # 仓库级 AI 强约束入口(英文) ├── CLAUDE.md # 本文件 ├── docs/ # 规范化项目文档(事实来源) -├── notion_docs/ # Notion 原始导出(只读存档) -└── family-album-usa/ # 内容素材 +├── scripts/ # episodes.json 校验/修正脚本 +├── design_mockups/ # UI 效果稿(HTML/CSS,可迁移参考) +├── notion_docs/ # Notion 原始导出(只读存档,git 忽略) +├── design_images/ # 第三方设计参考图(git 忽略) +└── family-album-usa/ # 内容素材(git 忽略,含大音频) ├── episodes.json # 全部课程内容(约 700KB) └── audio/ # 50 个 mp3,命名 u{集}{幕}.mp3,如 u0101.mp3 ``` @@ -63,7 +71,7 @@ lingo/ ```json { - "meta": { "totalEpisodes": 26, "totalActs": 50 }, + "meta": { "totalEpisodes": 26, "totalActs": 78, "audioActs": 49 }, "episodes": [ { "id": 1, "title": "46 Linden Street", "titleCn": "林登大街46号", "acts": [ @@ -93,7 +101,7 @@ lingo/ 1. **「音频 + 时间戳字幕同步」最小原型**(最难一环,先跑通) 2. 课程列表 + 播放页骨架(读 `episodes.json` 渲染) -3. 后端账号体系 + 鉴权(JWT 或 session) +3. 后端账号体系 + 鉴权(httpOnly Session Cookie) 4. 生词本(前端 UI + 后端 API) 5. 进度同步 6. PWA manifest + Service Worker 离线化 diff --git a/docs/00-ai-start-here.md b/docs/00-ai-start-here.md new file mode 100644 index 0000000..bcf132e --- /dev/null +++ b/docs/00-ai-start-here.md @@ -0,0 +1,155 @@ +# AI 开发入口 + +> 给 AI coding agent 的项目入口。这里负责导航和流程,硬性编码规则见 [`05-coding-rules.md`](05-coding-rules.md)。 + +## 一句话定位 + +这是一个大屏手机 / 平板优先的英语精听 PWA:基于「走遍美国 (Family Album, U.S.A.)」音频和逐句英文字幕,提供课程列表、音频播放、逐句同步、生词积累、账号同步和离线学习。 + +MVP 先做「走遍美国」ep1-17。ep18-26 暂缺音频,不进入 MVP 精听闭环。 + +## 必读顺序 + +每次开始写代码前,按这个顺序建立上下文: + +1. [`01-vision.md`](01-vision.md):为什么做、为谁做、什么不做。 +2. [`02-requirements.md`](02-requirements.md):MVP 要什么、怎么算达成。 +3. [`03-tech-stack.md`](03-tech-stack.md):既定技术选型。 +4. [`04-architecture.md`](04-architecture.md):系统结构、职责划分、数据模型和关键难点。 +5. [`05-coding-rules.md`](05-coding-rules.md):写代码前必须遵守的规则。 +6. [`06-tasks.md`](06-tasks.md):领取本轮唯一任务。 +7. [`../CLAUDE.md`](../CLAUDE.md):仓库根部的 AI 上下文和关键数据事实。 + +如果根目录有 [`../AGENTS.md`](../AGENTS.md),也必须先读。它是仓库级强约束入口。 + +## 当前阶段 + +当前项目处于 MVP 起步阶段。任务看板的优先路径是: + +1. Phase 0:最小可运行地基。 +2. Phase 1:先验证字幕同步原型,这是最高风险。 +3. Phase 2:课程列表和播放页。 +4. Phase 3-5:账号、生词本、进度同步。 +5. Phase 6:PWA 安装和离线。 + +设计 spike `T-200` 已完成,后续课程列表和播放页实现时参考: + +- `design_mockups/list.html` +- `design_mockups/play.html` + +这些是视觉参考和可迁移 CSS 来源,不是生产代码本身。 + +## 领取任务规则 + +从 [`06-tasks.md`](06-tasks.md) 领取任务时: + +- 只领取第一个状态为 `TODO` 且依赖均为 `DONE` 的任务。 +- 开始前把该任务状态改为 `DOING`。 +- 本轮只完成这一个任务。 +- 验收通过后把状态改为 `DONE`。 +- 做完即停,汇报验证结果,等待下一步指令。 + +如果代码实际状态和任务看板冲突,先说明冲突,不要擅自跳步或重排。 + +## MVP 边界 + +MVP 只做: + +- 课程列表 +- 音频播放 +- 逐句同步和点句跳转 +- 生词本 +- 账号与跨设备同步 +- PWA 安装和已缓存课程离线可用 + +MVP 不做: + +- 视频播放 +- 行级中英对照 +- 社区、分享、社交 +- AI 口语评分 +- 生词 SRS +- 测验、打卡、激励模块 +- 真正的多教材接入逻辑 + +`course_id` 可以按架构作为用户数据预留列存在,但 MVP 不实现多教材筛选、课程管理或多教材 UI。 + +## 事实来源 + +内容数据只信: + +- `family-album-usa/episodes.json` +- `family-album-usa/audio/` +- `scripts/` 中的数据校验脚本 + +关键事实: + +- 数据结构是 `episode -> act -> line`。 +- `line` 只有 `t` 和 `en`,没有 `zh`。 +- JSON 中 `/family-album/audio/...` 是服务路径,不是磁盘路径。 +- 磁盘音频目录是 `family-album-usa/audio/`。 +- ep18-26 暂缺音频,不要补造假数据。 +- `notion_docs/` 和 `*.bak` 是只读存档,不作为事实来源。 + +## 常见任务该看哪里 + +做课程列表: + +- 先看 `02-requirements.md` 的课程列表验收。 +- 再看 `04-architecture.md` 的内容数据结构。 +- 视觉参考 `design_mockups/list.html`。 + +做播放页或字幕同步: + +- 先看 `02-requirements.md` 的音频播放和逐句同步验收。 +- 再看 `04-architecture.md` 的关键技术难点。 +- 必须遵守 `05-coding-rules.md` 的字幕同步专项:定位当前句用二分查找,对乱序 / 相等时间戳容错。 +- 视觉参考 `design_mockups/play.html`。 + +做账号、生词本、进度: + +- 先看 `02-requirements.md` 的 P0 用户故事和验收。 +- 再看 `04-architecture.md` 的 SQLite 用户数据模型。 +- API 形状如果尚未写入文档,先提出并补充合约,不要在多个任务里各自发明。 + +做 PWA / 离线: + +- 先看 `02-requirements.md` 的离线验收。 +- 再看 `03-tech-stack.md` 的 PWA / Service Worker 选型。 +- 只要求已缓存课程离线可用,不要求首次离线访问全部音频。 + +## 验证命令 + +本项目主要在 **WSL / Linux(bash)** 下开发,命令以 bash 为准: + +```bash +GOOS=js GOARCH=wasm go build -o app.wasm # 前端 wasm +go build # 后端 +go vet ./... +python3 scripts/validate_episodes.py +``` + +Windows PowerShell 等价命令: + +```powershell +$env:GOOS='js'; $env:GOARCH='wasm'; go build -o app.wasm +go build +go vet ./... +python scripts/validate_episodes.py +``` + +说明: + +- 前端 wasm 改动后跑 wasm 构建。 +- 后端 Go 改动后跑 `go build` 和 `go vet ./...`。 +- 改动 `episodes.json` 或内容 schema 后跑 `python scripts/validate_episodes.py`。 +- 没有触碰内容数据时,不需要跑内容校验。 + +## 相关补充文档(已具备) + +以下文档已建好,开发到对应阶段时优先参考: + +- [`api.md`](api.md):账号、生词本、进度 API 合约草案(写后端/前端 client 前看)。 +- [`routes.md`](routes.md):go-app 页面路由与组件归属(写页面/导航前看)。 +- [`current-state.md`](current-state.md):当前实现状态、入口文件、可运行命令、下一步可做任务。 +- 项目包布局见 [`04-architecture.md`](04-architecture.md) 第六节。 diff --git a/docs/03-tech-stack.md b/docs/03-tech-stack.md index c7f086c..4df506c 100644 --- a/docs/03-tech-stack.md +++ b/docs/03-tech-stack.md @@ -1,7 +1,7 @@ # 技术栈(Tech Stack) > "用什么"的统一速查表。选型与理由在此集中维护;"怎么把它们搭起来"见 [架构设计](04-architecture.md)。 -> ⚠️ 标 **待定** 的项目尚未决策,**不要在代码里擅自选定**——先在此文档定下来再用。 +> 当前 MVP 技术栈已全部定稿。若未来新增待定项,先在本文决策,再进入代码。 ## 一、技术栈一览 @@ -27,7 +27,7 @@ MVP 的技术栈已全部敲定(上表均为 ✅)。以下是几条"现在 - **音频分发**:MVP 由单二进制直接提供;带宽吃紧后把 `audio/` 外挂到对象存储 / CDN,仅改静态资源路由。 - **鉴权**:Session Cookie 起步;若将来要做第三方客户端 / 开放 API,再考虑补 JWT 通道。 -> 选型不臆造、未定先标待定的纪律见 [编码规则](05-coding-rules.md);取舍方向见 [项目愿景](01-vision.md) 的"产品原则"。 +> 选型不臆造、未定先写入文档决策的纪律见 [编码规则](05-coding-rules.md);取舍方向见 [项目愿景](01-vision.md) 的"产品原则"。 ## 三、构建与运行命令 @@ -38,4 +38,13 @@ MVP 的技术栈已全部敲定(上表均为 ✅)。以下是几条"现在 | 格式化 / 静态检查 | `gofmt -w .` · `go vet ./...` | | 校验内容数据 | `python3 scripts/validate_episodes.py` | +Windows PowerShell 等价命令: + +```powershell +$env:GOOS='js'; $env:GOARCH='wasm'; go build -o app.wasm +go build +go vet ./... +python scripts/validate_episodes.py +``` + > 实际目录布局、模块划分、数据模型见 [架构设计](04-architecture.md);真实数据 schema 另见 `CLAUDE.md`。 diff --git a/docs/04-architecture.md b/docs/04-architecture.md index c69a466..6bdf084 100644 --- a/docs/04-architecture.md +++ b/docs/04-architecture.md @@ -34,7 +34,7 @@ **后端(net/http)** -- 用户注册 / 登录 / 鉴权(方式见技术栈,待定) +- 用户注册 / 登录 / 鉴权(httpOnly Session Cookie) - 生词本增删查 - 学习进度读写 - (静态音频与文稿可由 go-app Handler 或 CDN 提供) @@ -95,6 +95,39 @@ > 目的是避免将来接入新概念英语等时,对**已产生的用户进度/生词数据**做痛苦的 schema 迁移(用户数据不可重生,内容数据可重生)。 > ⚠️ MVP 阶段**仅留列、填默认值,不写任何多教材逻辑**(不建 courses 表、不改内容 JSON、不做按教材过滤)——多教材接入是 V2+,见 [任务看板](06-tasks.md) 待办池。 +建表草案(SQLite,T-301 实现时以此为基准,可按需微调约束): + +```sql +CREATE TABLE users ( + id INTEGER PRIMARY KEY, + email TEXT UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + created_at TEXT NOT NULL +); + +CREATE TABLE progress ( + user_id INTEGER NOT NULL, + course_id TEXT NOT NULL DEFAULT 'family-album', + episode_id INTEGER NOT NULL, + act INTEGER NOT NULL, + last_position REAL NOT NULL DEFAULT 0, -- 秒 + completed INTEGER NOT NULL DEFAULT 0, -- 0/1 + updated_at TEXT NOT NULL, + PRIMARY KEY (user_id, course_id, episode_id, act) +); + +CREATE TABLE vocab ( + id INTEGER PRIMARY KEY, + user_id INTEGER NOT NULL, + course_id TEXT NOT NULL DEFAULT 'family-album', + word TEXT NOT NULL, + episode_id INTEGER NOT NULL, + act INTEGER NOT NULL, + context_sentence TEXT, + created_at TEXT NOT NULL +); +``` + **功能模块化**:字幕同步、生词本、播放器做成可复用组件,不同教材按需启用(走遍美国用字幕同步;新概念可能更重单词表与语法)。 ## 四、关键技术难点 @@ -117,3 +150,35 @@ 7. (V2)复读 / 测验 / 打卡 > 原则:先验证最难的字幕同步,跑通再往上搭架子,避免先搭一堆架构最后卡在核心功能。 + +## 六、项目结构(建议包布局) + +go-app 同一份代码两处运行:编译成 **wasm 在浏览器**跑(`app.RunWhenOnBrowser()`),编译成**普通二进制在服务器**跑(起 `http.Server` + `app.Handler`)。因此前端组件包必须能进 wasm,而后端包(`net/http`、SQLite、文件 IO)**不能进 wasm**——用构建标签 `//go:build !wasm`(或单独的非 js 包,只被 server 入口引用)隔离。 + +建议布局(T-001 起逐步建立,不必一次建全): + +``` +lingo/ +├── go.mod +├── main.go # 装配入口:注册页面组件 + RunWhenOnBrowser;server 侧起 http + app.Handler +├── pages/ # go-app 前端组件(进 wasm) +│ ├── list.go # 课程列表页(EpisodeList) +│ ├── play.go # 播放页(TranscriptView) +│ ├── player.go # AudioPlayer:syscall/js 封装浏览器 Audio API +│ ├── vocab.go # 生词本页 +│ └── auth.go # 登录/注册(AuthForm) +├── content/ # episodes.json 加载与类型定义(T-003,前后端共用,纯数据可进 wasm) +│ └── content.go +├── server/ # 仅服务器端,//go:build !wasm 隔离,不进 wasm +│ ├── api.go # /api/*(账号 / 生词 / 进度),合约见 docs/api.md +│ ├── auth.go # httpOnly Session Cookie +│ ├── db.go # SQLite 建表与读写(见 3.2 建表草案) +│ └── static.go # /family-album/* → 磁盘 family-album-usa/ 的路径映射 +└── web/ # 静态资源 + ├── app.css # 纯 CSS(可迁移自 design_mockups/ 的 :root + 组件样式) + ├── manifest.webmanifest + └── sw.js # Service Worker(Phase 6) +``` + +- 页面路由与组件归属详见 [`routes.md`](routes.md);后端接口形状详见 [`api.md`](api.md)。 +- `content/` 只放数据结构与加载,保持可进 wasm(前端列表/播放页要用),**不要**在其中引入 server-only 依赖。 diff --git a/docs/05-coding-rules.md b/docs/05-coding-rules.md index 8e66672..1c4cfb4 100644 --- a/docs/05-coding-rules.md +++ b/docs/05-coding-rules.md @@ -38,7 +38,7 @@ ## 4. 架构纪律 - **技术栈固定**:以 [技术栈](03-tech-stack.md) 为准(前端 go-app、后端 `net/http`、数据库 SQLite)。要加任何第三方依赖,**先说明理由并征求同意**。 -- **标"待定"的栈项不要擅自选定**(UI 样式 / 状态管理 / 鉴权方式 / 部署)——先在 tech-stack 文档定下来再用,别在代码里替项目拍板。 +- **技术栈以 [技术栈](03-tech-stack.md) 为准**。若未来新增标"待定"的栈项,不要在代码里擅自选定;先在文档中决策,再实现。 - **内容数据 vs 用户数据分清**:教材内容(episodes.json)前端直接读、**不入库**;SQLite **只存**用户态(users / progress / vocab)。别把课程内容写进数据库。 - 把浏览器互操作(`syscall/js`、Audio API)**封装成可复用组件**,不要散落在各处业务代码里。 - 进度 / 生词本的字段以 [架构设计](04-architecture.md) 第 3.2 节为准(按 `episode_id + act` 定位,不是抽象 lesson_id)。 @@ -75,6 +75,17 @@ - [ ] 涉及数据结构变化的,文档(tech-stack / architecture / CLAUDE.md)已同步 - [ ] 如实汇报:跑了什么、结果如何;测试失败就说失败,别粉饰 +Windows PowerShell 常用验证命令: + +```powershell +$env:GOOS='js'; $env:GOARCH='wasm'; go build -o app.wasm +go build +go vet ./... +python scripts/validate_episodes.py +``` + +`validate_episodes.py` 仅在改动内容数据或 schema 时必跑。 + ## 9. 绝不 - 绝不把密钥 / token 写进代码或提交(用环境变量 / 配置)。 diff --git a/docs/06-tasks.md b/docs/06-tasks.md index 59dfedb..d5dc8e7 100644 --- a/docs/06-tasks.md +++ b/docs/06-tasks.md @@ -49,7 +49,7 @@ | --- | --- | --- | --- | --- | | T-200 | UI 效果稿:播放页 + 课程列表(HTML/CSS) | — | 中保真稿覆盖逐句高亮/点句跳转/进度/无音频降级;用真实数据;CSS 可迁移 go-app。见 `design_mockups/` | DONE | -> 设计 spike,不是生产代码。产出在 `design_mockups/play.html`、`list.html`,作为 T-201/T-203 的视觉依据。 +> 设计 spike,不是生产代码。产出在 `design_mockups/play.html`、`design_mockups/list.html`,作为 T-201/T-203 的视觉依据;CSS 可迁移,但不要直接把 spike 当生产代码整体搬入。 ## Phase 2 · 课程列表 + 播放页 @@ -59,6 +59,8 @@ | T-202 | 路由:列表 → 选集选幕 → 播放页 | T-201 | 点列表项进入对应播放页,可返回 | TODO | | T-203 | 播放页接入 Phase 1 同步组件 | T-202, T-104 | 任选有音频的幕,播放 + 逐句同步 + 点句跳转全部可用 | TODO | +> 页面路由与组件归属见 [路由](routes.md);视觉参考 `design_mockups/`;包布局见 [架构设计](04-architecture.md) 第六节。 + ## Phase 3 · 后端账号体系(Session Cookie) | ID | 任务 | 依赖 | 验收要点 | 状态 | @@ -67,6 +69,8 @@ | T-302 | 注册 / 登录 API + httpOnly Session Cookie | T-301 | 注册、登录成功后下发 httpOnly cookie;带 cookie 的请求能识别用户;登出失效 | TODO | | T-303 | 前端登录 / 注册界面 + 登录态 | T-302 | 能注册登录;刷新后保持登录;未登录访问需登录的页面会被引导登录 | TODO | +> 接口合约见 [API](api.md);建表 SQL 见 [架构设计](04-architecture.md) 第 3.2 节。 + ## Phase 4 · 生词本 | ID | 任务 | 依赖 | 验收要点 | 状态 | @@ -75,7 +79,7 @@ | T-402 | 点词加入生词本(播放页交互) | T-401, T-203 | 在字幕里点单词即可加入;有反馈 | TODO | | T-403 | 生词本列表页 | T-401 | 查看自己的生词列表;刷新/重进仍在 | TODO | -> 对应需求验收:02-requirements 第五节"生词本"。MVP 只存单词,不接词典释义。 +> 对应需求验收:02-requirements 第五节"生词本"。MVP 只存单词,不接词典释义。接口合约见 [API](api.md) 生词本一节。 ## Phase 5 · 进度同步 @@ -85,7 +89,7 @@ | T-502 | 播放时上报进度 + 列表显示进度 | T-501, T-203, T-201 | 播放中断点被记录;课程列表显示学习进度(如"2/3 幕") | TODO | | T-503 | 跨设备验证 | T-502 | A 设备学习后,B 设备登录同账号看到相同进度与生词本 | TODO | -> 对应需求验收:02-requirements 第五节"账号与同步"。 +> 对应需求验收:02-requirements 第五节"账号与同步"。接口合约见 [API](api.md) 学习进度一节。 ## Phase 6 · PWA 离线化 diff --git a/docs/README.md b/docs/README.md index 5285482..5403b01 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,11 +10,16 @@ ## 🗂 文档导航 +- [AI 开发入口](00-ai-start-here.md) — AI coding agent 的阅读顺序、任务领取规则、验证命令 - [项目愿景](01-vision.md) — 为什么 / 为谁 / 产品原则 / 不做什么 - [需求](02-requirements.md) — 要什么 + 验收标准(产品语言,无技术词) - [技术栈](03-tech-stack.md) — 用什么:框架 / 数据库 / UI / 状态管理 / 部署(速查) - [架构设计](04-architecture.md) — 怎么搭:系统结构、职责划分、数据模型、技术难点 +- [API 合约草案](api.md) — 账号、生词本、进度 API 的目标形状 +- [路由与页面结构](routes.md) — go-app 页面路由、页面职责、组件归属 +- [当前实现状态](current-state.md) — 仓库现实状态、当前可做任务、维护规则 - [编码规则](05-coding-rules.md) — 怎么写:AI 写代码前必读的硬约束 +- [任务看板](06-tasks.md) — 做哪一步:MVP 任务拆解、依赖、状态(AI 的 Jira) ## ⚡ 当前阶段 @@ -25,3 +30,7 @@ - 前端:go-app (Go → WebAssembly),PWA 可安装 / 离线 - 后端:Go `net/http` + SQLite - 素材:26 集英文文稿 + 逐句时间戳(音频覆盖 ep1–17,ep18–26 待补) + +## 🤖 AI coding 入口 + +仓库级 AI 规则见根目录 [`../AGENTS.md`](../AGENTS.md);更详细的项目开发导航见 [AI 开发入口](00-ai-start-here.md)。 diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..ca85f0e --- /dev/null +++ b/docs/api.md @@ -0,0 +1,209 @@ +# API 合约草案 + +> 本文定义 MVP 后端 API 的目标形状。实现前可按任务细化,但不要在代码里另起一套不兼容的接口。 + +## 通用约定 + +- 传输:JSON over HTTPS。 +- 鉴权:httpOnly Session Cookie。 +- 未登录访问需要登录的接口时返回 `401`。 +- 请求体和响应体均使用 UTF-8 JSON。 +- 内容数据不通过数据库 API 管理;课程内容来自静态 `episodes.json`。 + +通用错误响应: + +```json +{ + "error": { + "code": "unauthorized", + "message": "需要登录" + } +} +``` + +## 账号 + +### `POST /api/auth/register` + +注册账号并建立登录会话。 + +请求: + +```json +{ + "email": "learner@example.com", + "password": "password" +} +``` + +成功响应: + +```json +{ + "user": { + "id": 1, + "email": "learner@example.com" + } +} +``` + +### `POST /api/auth/login` + +登录并设置 httpOnly Session Cookie。 + +请求: + +```json +{ + "email": "learner@example.com", + "password": "password" +} +``` + +成功响应同注册。 + +### `POST /api/auth/logout` + +清除当前会话。 + +成功响应: + +```json +{ + "ok": true +} +``` + +### `GET /api/me` + +返回当前登录用户。 + +成功响应: + +```json +{ + "user": { + "id": 1, + "email": "learner@example.com" + } +} +``` + +## 生词本 + +### `GET /api/vocab` + +返回当前用户的生词列表。 + +成功响应: + +```json +{ + "items": [ + { + "id": 1, + "course_id": "family-album", + "word": "excuse", + "episode_id": 1, + "act": 1, + "context_sentence": "Excuse me. My name is Richard Stewart.", + "created_at": "2026-06-21T10:00:00Z" + } + ] +} +``` + +### `POST /api/vocab` + +添加一个生词。 + +请求: + +```json +{ + "word": "excuse", + "episode_id": 1, + "act": 1, + "context_sentence": "Excuse me. My name is Richard Stewart." +} +``` + +说明: + +- `course_id` 由服务端固定写入 `"family-album"`。 +- MVP 不接词典,不要求释义字段。 + +成功响应返回新增项。 + +### `DELETE /api/vocab/{id}` + +删除当前用户自己的一个生词。 + +成功响应: + +```json +{ + "ok": true +} +``` + +## 学习进度 + +### `GET /api/progress` + +返回当前用户全部学习进度。 + +成功响应: + +```json +{ + "items": [ + { + "course_id": "family-album", + "episode_id": 1, + "act": 1, + "last_position": 42.5, + "completed": false, + "updated_at": "2026-06-21T10:00:00Z" + } + ] +} +``` + +### `PUT /api/progress` + +写入或更新某一幕的学习进度。 + +请求: + +```json +{ + "episode_id": 1, + "act": 1, + "last_position": 42.5, + "completed": false +} +``` + +说明: + +- `course_id` 由服务端固定写入 `"family-album"`。 +- 定位维度是 `episode_id + act`,不是 `lesson_id`。 + +成功响应返回更新后的进度项。 + +## 静态内容 + +课程内容和音频由静态路由提供: + +- `GET /family-album/episodes.json` +- `GET /family-album/audio/u0101.mp3` + +服务端需要把 `/family-album/audio/...` 映射到磁盘 `family-album-usa/audio/...`。 + +## 待实现时确认 + +- 密码强度和错误文案。 +- Session 存储方式和过期时间。 +- 生词重复添加时返回已有项还是幂等更新。 +- 进度上报频率由前端任务决定,API 保持幂等写入。 diff --git a/docs/current-state.md b/docs/current-state.md new file mode 100644 index 0000000..eb06d5c --- /dev/null +++ b/docs/current-state.md @@ -0,0 +1,63 @@ +# 当前实现状态 + +> 本文记录代码与任务看板的现实状态,帮助 AI coding agent 避免只看计划而忽略仓库现状。 + +## 当前快照 + +- 日期:2026-06-21 +- 阶段:MVP 起步前 / 文档与素材已就位 +- Go 模块:尚未初始化,当前无 `go.mod` +- 生产代码:尚未开始 +- 设计稿:已完成 `design_mockups/list.html` 和 `design_mockups/play.html` +- 内容素材:`family-album-usa/episodes.json` 和 `family-album-usa/audio/` 已存在 + +## 当前目录要点 + +| 路径 | 状态 | 说明 | +| --- | --- | --- | +| `docs/` | 已有 | 项目规范化文档,当前事实来源 | +| `family-album-usa/episodes.json` | 已有 | 课程内容数据 | +| `family-album-usa/audio/` | 已有 | mp3 音频目录 | +| `design_mockups/` | 已有 | UI spike,作为视觉参考 | +| `scripts/` | 已有 | 内容数据校验等脚本 | +| `notion_docs/` | 只读 | Notion 原始导出,不作为事实来源 | +| `go.mod` | 不存在 | T-001 需要创建 | + +## 任务看板状态 + +以 [`06-tasks.md`](06-tasks.md) 为准。 + +当前应领取的第一个开发任务: + +- `T-001`:初始化 go 模块 + go-app 最小可运行页面 + +不要跳到课程列表、账号、生词本或 PWA 离线任务。 + +## 当前可运行内容 + +目前没有生产 App 可运行。 + +可以直接打开这些 HTML spike 查看设计参考: + +- `design_mockups/list.html` +- `design_mockups/play.html` + +## 开始编码前检查 + +开始 T-001 前: + +1. 读根目录 `AGENTS.md`。 +2. 读 `CLAUDE.md`。 +3. 读 `docs/05-coding-rules.md`。 +4. 确认 `docs/06-tasks.md` 中 T-001 仍是第一个可做任务。 +5. 将 T-001 状态改为 `DOING`。 + +## 维护规则 + +当实际代码状态发生变化时,同步更新本文件: + +- 新增或移动入口文件。 +- 初始化 Go 模块。 +- 任务从 `TODO` 进入 `DOING` 或 `DONE`。 +- 新增可运行命令。 +- 发现文档和代码现实不一致。 diff --git a/docs/routes.md b/docs/routes.md new file mode 100644 index 0000000..8e1d4fc --- /dev/null +++ b/docs/routes.md @@ -0,0 +1,78 @@ +# 路由与页面结构 + +> 本文约定 MVP 的前端页面路由和组件归属。具体 go-app 写法以实现时的代码结构为准。 + +## 页面路由 + +| 路由 | 页面 | MVP 说明 | +| --- | --- | --- | +| `/` | 课程列表页 | 默认首页,展示 26 集和各幕状态 | +| `/episode/{episode_id}/act/{act}` | 播放页 | 播放某一集某一幕,支持字幕同步和点句跳转 | +| `/vocab` | 生词本页 | 登录后查看个人生词 | +| `/login` | 登录页 | 登录入口 | +| `/register` | 注册页 | 注册入口 | + +后续如果 go-app 路由实现需要 hash 路由,语义仍保持一致。 + +## 页面职责 + +### 课程列表页 + +读取 `episodes.json` 渲染: + +- 26 集课程。 +- 每集下的 act。 +- 是否有音频。 +- 后续接入进度后显示学习进度。 + +视觉参考:`design_mockups/list.html`。 + +### 播放页 + +根据 URL 参数定位 `episode_id + act`: + +- 有音频时显示播放器、字幕列表、当前句高亮。 +- 点击字幕句子时 seek 到该句 `t`。 +- 无音频时优雅降级,只显示文本和无音频提示。 +- 后续接入生词本后支持点词加入。 +- 后续接入进度后读写 `last_position`。 + +视觉参考:`design_mockups/play.html`。 + +### 生词本页 + +通过 `GET /api/vocab` 获取当前登录用户生词: + +- 展示单词。 +- 展示来源:episode、act、上下文句子。 +- 支持删除。 + +MVP 不展示词典释义。 + +### 登录 / 注册页 + +通过账号 API 建立 httpOnly Session Cookie: + +- 登录成功后返回原目标页或首页。 +- 未登录访问需要账号的页面时,引导登录。 + +## 组件建议 + +| 组件 | 归属 | 说明 | +| --- | --- | --- | +| `EpisodeList` | 课程列表页 | 渲染 episode 和 act 列表 | +| `AudioPlayer` | 播放页 | 封装浏览器 Audio API 互操作 | +| `TranscriptView` | 播放页 | 渲染字幕、当前句高亮、点句跳转 | +| `VocabList` | 生词本页 | 渲染当前用户生词 | +| `AuthForm` | 登录 / 注册页 | 复用账号表单 | + +`AudioPlayer` 和 `TranscriptView` 是后续多教材可复用的核心组件,但 MVP 不提前实现多教材逻辑。 + +## 导航规则 + +- 首页进入播放页:点击某一幕。 +- 播放页返回首页:保留简单返回入口。 +- 生词本入口:可以放在全局导航或列表页顶部。 +- 未登录时:课程内容可否浏览仍待产品确认;需要账号数据的生词本和进度接口必须登录。 + +如果游客浏览策略未确认,实现账号相关任务前先回到 [`02-requirements.md`](02-requirements.md) 的待确认项做决策。