From 156ac939c478d46ef4e1d0518124fd24aee9cc77 Mon Sep 17 00:00:00 2001 From: Henrythefoodie <13022037121@163.com> Date: Fri, 24 Jul 2026 14:03:50 +0800 Subject: [PATCH] docs: elevate bilingual project README --- README.en.md | 334 +++++++++++++++--- README.md | 331 +++++++++++++---- SECURITY.md | 2 +- .../0001-self-contained-modular-monolith.md | 5 +- docs/adr/0002-server-side-opaque-sessions.md | 5 +- .../0005-vercel-railway-split-deployment.md | 2 +- docs/operations.md | 4 +- ...6-07-24-readme-information-architecture.md | 38 ++ 8 files changed, 588 insertions(+), 133 deletions(-) create mode 100644 docs/plans/2026-07-24-readme-information-architecture.md diff --git a/README.en.md b/README.en.md index de57ffb..1fae69a 100644 --- a/README.en.md +++ b/README.en.md @@ -1,94 +1,312 @@ -# International Chinese Platform + -A public-beta full-stack platform for international Chinese education. Students, teachers, and administrators share persistent workflows for registration, teacher verification, courses, appointments, live classrooms, assignments, notifications, and dialogue practice. +
A public-beta, full-stack collaboration platform for international Chinese education.
+It connects teacher verification, course review, scheduled classrooms, and assignment feedback into one deployable, testable, auditable learning workflow.
-## Architecture ++ Overview + · + Learning journeys + · + Quick start + · + Architecture + · + Quality evidence + · + Documentation + · + 中文 +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
packageManager
+- Docker Desktop or Docker Engine for local PostgreSQL and MinIO
+- Optional: Python 3.12 plus Playwright Chromium for browser E2E
+
+### 1. Clone, install, and create local configuration
```bash
+git clone https://github.com/computersciencefreshmen/International_Chinese_Platform.git
+cd International_Chinese_Platform
+corepack enable
pnpm install --frozen-lockfile
+```
+
+Windows PowerShell:
+
+```powershell
+Copy-Item .env.example .env.local
+```
+
+macOS / Linux:
+
+```bash
+cp .env.example .env.local
+```
+
+.env.local keeps the development API, PostgreSQL, and MinIO connections explicit. SMTP, AI, and TURN are not prerequisites for the core teaching journeys.
+
+### 2. Start dependencies, migrate data, seed the demo, and run the app
+
+On a first image pull, wait until PostgreSQL is healthy and minio-init has completed before migrating and seeding.
+
+```bash
docker compose up -d postgres minio minio-init
pnpm db:migrate
pnpm db:seed
pnpm dev
```
-- Frontend: `http://localhost:5173`
-- API: `http://localhost:7777/api/v1`
-- MinIO console: `http://localhost:9001`
+Then open:
-See [`.env.example`](./.env.example). Local development and CI use PostgreSQL as well, eliminating SQLite/production drift.
+- Web: http://localhost:5173
+- API: http://localhost:7777/api/v1
+- MinIO Console: http://localhost:9001
-## Commands
+### 3. Verify that startup worked
+
+macOS / Linux:
```bash
-pnpm dev
-pnpm build
-pnpm db:migrate
-pnpm db:seed
-pnpm admin:bootstrap
-pnpm test:api
-pnpm check
-pnpm backup:create
-pnpm backup:restore
+curl --fail http://localhost:7777/api/v1/ready
```
-Production configuration rejects `SEED_ON_START=true`; demo users and courses are never imported automatically.
+Windows PowerShell:
+
+```powershell
+Invoke-RestMethod http://localhost:7777/api/v1/ready
+```
+
+When the API is ready, open the web app and use these local-demo-only accounts:
+
+| Role | Email | Password |
+| ------------- | -------------------------------- | --------------------- |
+| Student | student@example.com | Demo123! |
+| Teacher | teacher@example.com | Demo123! |
+| Administrator | admin@example.com | Demo123! |
+
+> Teacher verification is a manual platform-administrator review, not issuer-side credential verification. External certificate OCR and authenticity checking remain out of scope.
-## File security model
+> [!CAUTION]
+> Demo data is for explicit local or test seeding only. Production rejects SEED_ON_START=true; do not run pnpm db:seed or pnpm db:reset against a production database.
-The browser may write only short-lived keys under `tmp/uploads/`; signatures bind Content-Type and Content-Length. Completion streams the object, validates size, magic bytes, and SHA-256, then conditionally copies the source ETag into a new `files/` key. A final key never receives a PUT URL, so reusing the original URL cannot overwrite a verified file.
+### Useful commands
-Deletion is backed by a retryable database outbox. Production R2 should also expire `tmp/` after one day. Private video and material downloads first pass API authorization and then redirect to a five-minute signed URL.
+```bash
+pnpm dev # run Vite and Fastify together
+pnpm build # build the production web client
+pnpm db:migrate # apply pending numbered PostgreSQL migrations
+pnpm db:seed # import idempotent demo data outside production
+pnpm db:reset # rebuild local development data; drops the local public schema
+pnpm admin:bootstrap # create the first production administrator once
+pnpm test:api # Node API, database, and security tests
+pnpm check # ESLint + Prettier + API tests + production build
+pnpm backup:create # after production backup setup, create an encrypted PostgreSQL backup
+pnpm backup:restore # after production restore setup, restore only with explicit CONFIRM_RESTORE
+```
+
+
-## Deployment
+## Architecture: clear responsibilities, explicit trust boundaries
+
+```mermaid
+flowchart LR
+ Browser["Browser · Vue 3"]
+ Vercel["Vercel · SPA"]
+ API["Railway · single Fastify instance"]
+ PG[("Railway PostgreSQL")]
+ R2["Cloudflare R2 · private objects"]
+ Relay["Vercel Function · /api/mail-relay"]
+ Gmail["Gmail SMTP"]
+ Backup["Railway Cron · encrypted backup"]
+ BackupBucket["private R2 backup bucket"]
+
+ Browser -->|"HTTPS page"| Vercel
+ Vercel -->|"/api/v1/* rewrite"| API
+ Browser -->|"WSS classroom connection"| API
+ Browser -->|"10-minute presigned PUT"| R2
+ API --> PG
+ API --> R2
+ API -->|"HMAC-signed HTTPS payload"| Relay
+ Relay -->|"SMTP 465"| Gmail
+ Backup -->|"pg_dump + AES-256-GCM"| BackupBucket
+```
-- Frontend: Vercel project `international-chinese-platform`
-- Backend: one Railway Docker service
-- Database: Railway PostgreSQL
-- Files: private Cloudflare R2 bucket
-- Mail: Gmail SMTP application password
+For local development, Vite, Fastify, PostgreSQL, and MinIO replace Vercel, Railway, and R2. The application keeps the same S3 interface and database-migration discipline so that development behavior does not silently diverge from production. Before a browser receives a presigned PUT, it asks the API for a restricted upload intent; after upload, the API checks size, magic bytes, and SHA-256, then promotes the object only when its ETag still matches.
-See the [operations manual](./docs/operations.md) for exact secrets, R2 CORS/lifecycle, administrator bootstrap, backups, restore drills, and rollback. Architecture decisions are in [`docs/adr`](./docs/adr).
+| Component | Responsibility | Why it is separated this way |
+| --------------------- | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
+| Vue 3 + Vercel | UI, routing, and static assets | Static content stays close to users; only versioned business APIs are rewritten, so the browser still reaches the API with first-party cookies. |
+| Fastify + Railway | Domain API, authorization, state transitions, and WebSocket | Teaching rules remain on the server; the beta keeps one instance instead of pretending cross-instance room coordination is solved. |
+| PostgreSQL | Source of truth for users, courses, appointments, assignments, reviews, notifications, and audit data | Numbered migrations, transactions, and concurrency protection keep cross-role workflows independent of front-end ordering. |
+| Cloudflare R2 / MinIO | Private files and temporary upload objects | Direct browser upload avoids proxying large bodies through the API; MinIO reproduces the S3 contract locally. |
+| Vercel mail relay | Holds Gmail SMTP credentials and delivers verification mail | Railway sends a minimal signed payload; SMTP credentials never live in the browser, API environment, or Git. |
+| Railway backup Cron | Exports and encrypts PostgreSQL backups | Backup work is separate from the API process, and restore still requires explicit confirmation. |
+
+
+
+## Engineering credibility and quality evidence
+
+| Area | Implementation | Evidence |
+| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
+| Identity and authorization | scrypt password hashes, server-side session digests, HttpOnly cookies, origin checks, role and resource-ownership checks | [authentication tests](./server/test/auth.test.js), [security policy](./SECURITY.md) |
+| Teaching state | PostgreSQL transactions, conditional updates, numbered migrations, audit records, and notifications | [domain routes](./server/routes), [migrations](./server/db/migrations) |
+| Private files | upload intents, temporary keys, content type and length binding, magic-byte/SHA-256 validation, ETag-conditional promotion, short-lived downloads | [object-storage ADR](./docs/adr/0004-r2-object-storage.md), [file tests](./server/test/files.test.js) |
+| Live classroom | short-lived single-use classroom tickets; history, membership, and WebRTC signaling isolated by classroom | [classroom tests](./server/test/realtime-classroom.test.js) |
+| Mail boundary | HMAC request from Railway to a Vercel Function with freshness and strict-payload checks | [mail-relay ADR](./docs/adr/0006-vercel-hmac-mail-relay.md) |
+| Delivery and recovery | health/readiness probes, expand-only migrations, encrypted backups, restore confirmation, and rollback guidance | [operations manual](./docs/operations.md) |
+
+### What CI actually proves
+
+pnpm check runs ESLint, Prettier, the complete Node API/database/security suite, and a Vite production build. The repository currently contains 71 Node tests. GitHub Actions also starts isolated PostgreSQL and MinIO services, builds the production app, and exercises four cross-role browser journeys:
+
+1. Course submission → rejection → revision → approval → student catalog visibility.
+2. Student request → teacher acceptance → dedicated classroom → classroom completion.
+3. Teacher publishes → student submits → teacher grades → student sees feedback.
+4. Administrator revokes verification → student cannot discover or book → administrator reapproves → teacher becomes public again.
+
+To reproduce browser E2E locally, install e2e/requirements.txt and Playwright Chromium, start the service with the same PostgreSQL, MinIO, and production environment used by the [CI workflow](./.github/workflows/ci.yml), then run python e2e/test_workflows.py. See the [Node tests](./server/test) and [browser E2E](./e2e/test_workflows.py).
+
+## Deployment, operations, and beta scope
+
+The recommended public-beta topology is Vercel for the Vue SPA and mail-relay function; Railway for one Fastify API instance, PostgreSQL, and an independent backup Cron; and Cloudflare R2 for private files and encrypted backups. Secrets, R2 CORS, migrations, administrator bootstrap, monitoring, restore drills, and rollback are documented in the [operations manual](./docs/operations.md).
+
+| A good fit today | Not in the current scope |
+| --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| Course projects, portfolio demonstrations, small self-hosted teaching collaboration, and public-beta validation | Payments, formal enrollment and seat deduction, recording, external certificate OCR/verification, paid AI, multi-instance real-time fan-out, and high availability |
+| Classrooms that can connect directly or have a configured TURN service | Reliable audio/video behind strict NAT, because TURN is not bundled yet |
+
+Course price and capacity are informational only; they are not a payment or seat-allocation system. Until a formal enrollment model exists, assignments for published courses are visible to and submittable by every signed-in student; there is no roster or enrollment authorization layer yet. Before the system can scale horizontally, classroom presence needs cross-instance broadcast and coordination.
+
+
+
+## Documentation map
+
+- [Public-beta operations manual](./docs/operations.md): production variables, R2, mail relay, backup, restore, and rollback.
+- [ADR 0003: PostgreSQL](./docs/adr/0003-postgresql-production-database.md), [ADR 0004: R2](./docs/adr/0004-r2-object-storage.md), [ADR 0005: Vercel / Railway](./docs/adr/0005-vercel-railway-split-deployment.md), and [ADR 0006: HMAC mail relay](./docs/adr/0006-vercel-hmac-mail-relay.md): the current production architecture decisions.
+- [Historical plans](./docs/plans): the migration story from the earlier SQLite prototype to the PostgreSQL/R2 cloud architecture. These are not the source of truth for the current runtime.
+- [Security policy](./SECURITY.md): private disclosure, supported scope, and deployment security expectations.
+
+## Main directories
+
+```text
+src/ Vue 3 client and role workspaces
+server/routes/ Fastify domain API
+server/db/migrations/ numbered PostgreSQL migrations
+server/services/ mail, dialogue, and object-storage adapters
+server/ops/ backup and restore
+server/test/ API, database, and security integration tests
+e2e/ four cross-role Playwright workflows
+docs/adr/ architecture decision records
+docs/operations.md deployment and operations manual
+```
-## Verification
+## Contributions, security, and license
-CI uses PostgreSQL and isolated MinIO, then runs source checks, API integration tests, the production build, and cross-role Playwright workflows. File tests cover forged extensions, quota races, concurrent completion, presigned URL reuse, ETag-conditional promotion, and unauthorized downloads.
+Issues and pull requests are welcome. For larger behavior changes, describe the user journey, server-side state change, test strategy, and documentation impact first; each pull request should keep implementation, tests, and documentation aligned.
-## Public Beta limits
+Report security issues privately through [SECURITY.md](./SECURITY.md). Do not publish credentials, personal data, or vulnerability details in public issues, screenshots, or demo environments.
-- No TURN server; audio/video may fail behind strict NAT.
-- No multi-instance room broadcasting, HA, payments, formal enrollment, class recording, or paid external AI.
-- Price and capacity are informational course fields, not payment or seat allocation.
+This repository currently has no open-source license. Except where applicable law clearly permits otherwise, obtain the maintainer’s permission before reuse, redistribution, or production use.
-Security issues should be reported privately through [`SECURITY.md`](./SECURITY.md), never through a public issue containing credentials or vulnerability details.
+
diff --git a/README.md b/README.md
index bca21ff..e6ea0af 100644
--- a/README.md
+++ b/README.md
@@ -1,115 +1,312 @@
-# International Chinese Platform
+
-面向国际中文教育的公开 Beta 全栈平台。学生、教师和管理员在同一套持久化数据上完成注册、教师审核、课程、预约、实时课堂、作业、通知和对话流程。
+面向国际中文教育的公开 Beta 全栈教学协作平台
+将教师认证、课程审核、预约课堂和作业反馈连接为同一条可部署、可验证、可审计的教学闭环。
-## 架构 ++ 项目概览 + · + 教学闭环 + · + 快速开始 + · + 系统架构 + · + 质量证据 + · + 文档 + · + English +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
packageManager 固定)
+- Docker Desktop 或 Docker Engine,用于本地 PostgreSQL 与 MinIO
+- 可选:Python 3.12 + Playwright Chromium,用于运行浏览器 E2E
+
+### 1. 克隆、安装并创建本地配置
```bash
+git clone https://github.com/computersciencefreshmen/International_Chinese_Platform.git
+cd International_Chinese_Platform
+corepack enable
pnpm install --frozen-lockfile
+```
+
+Windows PowerShell:
+
+```powershell
+Copy-Item .env.example .env.local
+```
+
+macOS / Linux:
+
+```bash
+cp .env.example .env.local
+```
+
+.env.local 把开发 API、PostgreSQL 和 MinIO 连接放在同一份显式配置中;无需填写 SMTP、AI 或 TURN 才能体验核心教学流程。
+
+### 2. 启动依赖、迁移数据并导入演示内容
+
+首次拉取镜像时,请先等待 PostgreSQL 显示为 healthy,且 minio-init 成功完成,再执行迁移与种子命令。
+
+```bash
docker compose up -d postgres minio minio-init
pnpm db:migrate
pnpm db:seed
pnpm dev
```
-- 前端:`http://localhost:5173`
-- API:`http://localhost:7777/api/v1`
-- MinIO 控制台:`http://localhost:9001`
+打开以下地址:
-配置模板见 [`.env.example`](./.env.example)。本地和 CI 也使用 PostgreSQL,避免 SQLite/生产差异。
+- Web:http://localhost:5173
+- API:http://localhost:7777/api/v1
+- MinIO Console:http://localhost:9001
-## 常用命令
+### 3. 验证启动成功
+
+macOS / Linux:
```bash
-pnpm dev # 前端与 API
-pnpm build # Vite 生产构建
-pnpm db:migrate # 应用未执行的编号迁移
-pnpm db:seed # 仅本地/测试演示数据
-pnpm admin:bootstrap # 创建首个生产管理员
-pnpm test:api # PostgreSQL API 集成测试
-pnpm check # lint + format + API tests + build
-pnpm backup:create # 加密 pg_dump 并上传备份 Bucket
-pnpm backup:restore # 受 CONFIRM_RESTORE 保护的恢复
+curl --fail http://localhost:7777/api/v1/ready
+```
+
+Windows PowerShell:
+
+```powershell
+Invoke-RestMethod http://localhost:7777/api/v1/ready
```
-生产配置会拒绝 `SEED_ON_START=true`,不会导入本地演示账号或课程。
+如果 API 就绪,访问 Web 地址并使用下列仅限本地演示的账号登录:
-## 文件安全模型
+| 角色 | 邮箱 | 密码 |
+| ------ | -------------------------------- | --------------------- |
+| 学生 | student@example.com | Demo123! |
+| 教师 | teacher@example.com | Demo123! |
+| 管理员 | admin@example.com | Demo123! |
-浏览器只能写入 `tmp/uploads/` 的短期 Key,并且签名绑定 Content-Type 与 Content-Length。完成接口流式检查大小、魔数和 SHA-256,并以源 ETag 为条件复制到新的 `files/` Key。正式 Key 从不签发 PUT URL,因此原上传 URL 即使被重复使用也不能覆盖已验证文件。
+> 教师认证是平台管理员的人工审核,不等同于外部证书颁发方的联网真实性核验;后者仍在当前范围之外。
-对象删除使用数据库 Outbox 重试;生产 R2 还应为 `tmp/` 配置 1 天生命周期兜底。私有视频和资料下载先经过 API 权限判断,再 302 到 5 分钟签名 URL。
+> [!CAUTION]
+> 演示数据只能在本地或测试环境显式导入。生产配置拒绝 SEED_ON_START=true,pnpm db:seed 与 pnpm db:reset 也不应对生产数据库执行。
-## 健康检查
+### 常用命令
-- `GET /api/v1/health`:进程存活
-- `GET /api/v1/ready`:数据库不可用返回 503;R2 不可用返回 `degraded`
+```bash
+pnpm dev # 同时启动 Vite 与 Fastify
+pnpm build # 构建生产前端
+pnpm db:migrate # 应用尚未执行的 PostgreSQL 编号迁移
+pnpm db:seed # 导入幂等演示数据(非生产)
+pnpm db:reset # 重建本地开发数据库(会删除本地 public schema)
+pnpm admin:bootstrap # 一次性创建首个生产管理员
+pnpm test:api # Node API / 数据库 / 安全测试
+pnpm check # ESLint + Prettier + API 测试 + 生产构建
+pnpm backup:create # 生产备份配置完成后,创建加密 PostgreSQL 备份
+pnpm backup:restore # 生产恢复配置完成后,受 CONFIRM_RESTORE 保护地恢复
+```
+
+
+
+## 系统架构:职责清晰,信任边界明确
-## 云部署
+```mermaid
+flowchart LR
+ Browser["浏览器 · Vue 3"]
+ Vercel["Vercel · SPA"]
+ API["Railway · 单实例 Fastify"]
+ PG[("Railway PostgreSQL")]
+ R2["Cloudflare R2 · 私有对象"]
+ Relay["Vercel Function · /api/mail-relay"]
+ Gmail["Gmail SMTP"]
+ Backup["Railway Cron · 加密备份"]
+ BackupBucket["私有 R2 备份 Bucket"]
-- 前端:Vercel 项目 `international-chinese-platform`
-- 后端:Railway Docker 单实例
-- 数据库:Railway PostgreSQL
-- 文件:Cloudflare R2 私有 Bucket
-- 邮件:Railway 通过 HMAC HTTPS 调用 Vercel `/api/mail-relay`;Gmail 应用密码只保存在 Vercel
-- 备份:独立 Railway Cron 每日 `18:00 UTC` 运行;公开 Beta 暂时复用私有 staging Bucket
+ Browser -->|"HTTPS 页面"| Vercel
+ Vercel -->|"/api/v1/* rewrite"| API
+ Browser -->|"WSS 课堂连接"| API
+ Browser -->|"10 分钟预签名 PUT"| R2
+ API --> PG
+ API --> R2
+ API -->|"HMAC 签名 HTTPS 请求"| Relay
+ Relay -->|"SMTP 465"| Gmail
+ Backup -->|"pg_dump + AES-256-GCM"| BackupBucket
+```
-完整 Secret、R2 CORS/生命周期、管理员初始化、备份、恢复和回滚步骤见[运维手册](./docs/operations.md)。架构决策见 [`docs/adr`](./docs/adr)。
+本地图中,Vercel / Railway / R2 分别由 Vite、Fastify、PostgreSQL 和 MinIO 替代;应用层使用同一套 S3 接口和数据库迁移,减少“开发环境能跑、生产环境行为不同”的风险。浏览器会先向 API 申请受限上传意图,再获得临时对象的预签名 PUT;API 在完成后校验大小、魔数和 SHA-256,并仅在 ETag 条件满足时晋升到正式私有 Key。
-## 验证
+| 组件 | 职责 | 为什么这样划分 |
+| --------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------- |
+| Vue 3 + Vercel | 用户界面、路由与静态资产 | 静态内容靠近用户;仅把版本化业务 API 重写到后端,浏览器仍以第一方 Cookie 访问 API。 |
+| Fastify + Railway | 领域 API、权限判断、状态转换、WebSocket | 将教学规则留在服务端;公开 Beta 维持单实例,避免假装已解决跨实例房间协调。 |
+| PostgreSQL | 用户、课程、预约、作业、审核、通知与审计的事实来源 | 编号迁移、事务与并发保护使跨角色流程不会依赖前端顺序。 |
+| Cloudflare R2 / MinIO | 私有文件和上传临时对象 | 浏览器直传减少 API 传输压力;MinIO 在本地复现 S3 语义。 |
+| Vercel 邮件中继 | 持有 Gmail SMTP 凭据并投递验证码 | Railway 只传递最小签名载荷;SMTP 密码不进入浏览器、API 环境或 Git。 |
+| Railway Backup Cron | 导出并加密 PostgreSQL 备份 | 备份与 API 进程职责分离;恢复仍需显式确认。 |
-CI 使用 PostgreSQL 服务和独立 MinIO,执行源码检查、API 集成测试、生产构建与学生/教师/管理员 Playwright 工作流。文件测试覆盖伪造扩展名、配额竞争、并发完成、签名 URL 重用、ETag 条件复制和越权下载。
+
-## 公开 Beta 边界
+## 工程可信度与质量证据
-- 暂无 TURN;严格 NAT 环境可能无法建立音视频。
-- 暂无多实例房间广播、高可用、支付、正式入学、课堂录像和外部付费 AI。
-- 价格与容量当前是课程信息,不代表支付或正式席位占用。
+| 领域 | 实现方式 | 可验证证据 |
+| ---------- | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
+| 身份与授权 | scrypt 密码哈希、服务端 Session 摘要、HttpOnly Cookie、来源校验、角色与资源所有权检查 | [认证测试](./server/test/auth.test.js)、[安全策略](./SECURITY.md) |
+| 教学状态 | PostgreSQL 事务、条件更新、编号迁移、审计与通知 | [领域路由](./server/routes)、[迁移](./server/db/migrations) |
+| 私有文件 | 上传意图、临时 Key、签名绑定类型与长度、魔数/SHA-256、ETag 条件晋升、短期签名下载 | [对象存储 ADR](./docs/adr/0004-r2-object-storage.md)、[文件测试](./server/test/files.test.js) |
+| 实时课堂 | 短期、单用途课堂票据;聊天室成员、历史与 WebRTC 信令按课堂隔离 | [课堂测试](./server/test/realtime-classroom.test.js) |
+| 邮件边界 | Railway 对 Vercel Function 的 HMAC 请求、时间窗与严格 payload 校验 | [邮件中继 ADR](./docs/adr/0006-vercel-hmac-mail-relay.md) |
+| 发布与恢复 | 健康/就绪探针、扩展型迁移、加密备份、恢复确认与回滚步骤 | [运维手册](./docs/operations.md) |
+
+### CI 实际验证什么
+
+pnpm check 会运行 ESLint、Prettier、完整 Node API/数据库/安全测试与 Vite 生产构建。本仓库当前包含 71 个 Node 测试;GitHub Actions 还会启动隔离 PostgreSQL 和 MinIO,构建生产应用,并在真实浏览器中验证四条跨角色流程:
+
+1. 课程“提交 → 驳回 → 修改重提 → 批准 → 学生目录可见”。
+2. 预约“学生申请 → 教师接受 → 专属课堂 → 学生完成课堂”。
+3. 作业“教师发布 → 学生提交 → 教师评分 → 学生查看反馈”。
+4. 教师认证“管理员撤销 → 学生无法发现/预约 → 管理员重新批准 → 重新公开”。
+
+若要本地复现浏览器 E2E,请先安装 e2e/requirements.txt 与 Playwright Chromium,以与 [CI 工作流](./.github/workflows/ci.yml) 相同的 PostgreSQL、MinIO 和生产环境变量启动服务,再运行 python e2e/test_workflows.py。查看 [Node 测试](./server/test) 与 [浏览器 E2E](./e2e/test_workflows.py)。
+
+## 部署、运维与适用范围
+
+推荐的公开 Beta 生产拓扑为:Vercel 托管 Vue 单页应用与邮件中继函数;Railway 托管一个 Fastify API 实例、PostgreSQL 与独立备份 Cron;Cloudflare R2 保存私有文件和加密备份。完整的 Secret、R2 CORS、迁移、管理员初始化、监控、恢复演练和回滚步骤在 [运维手册](./docs/operations.md)。
+
+| 现在适合 | 当前未覆盖 |
+| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
+| 课程项目、作品集展示、小规模自部署教学协作、公开 Beta 验证 | 支付结算、正式入学与席位扣减、课堂录制、外部证书 OCR/真实性核验、付费 AI、多实例实时广播、高可用 |
+| 可直连或已配置 TURN 的课堂环境 | 严格 NAT 下的可靠音视频(尚未内置 TURN) |
+
+价格和容量目前是课程信息,并不代表支付或正式席位占用。在正式选课模型上线前,已发布课程的作业对所有登录学生可见并可提交;当前没有 roster 或 enrollment 权限层。扩展为多实例前,需要先为课堂成员状态引入跨实例广播与协调层。
+
+
+
+## 文档地图
+
+- [公开 Beta 运维手册](./docs/operations.md):生产变量、R2、邮件中继、备份、恢复和回滚。
+- [ADR 0003:PostgreSQL](./docs/adr/0003-postgresql-production-database.md)、[ADR 0004:R2](./docs/adr/0004-r2-object-storage.md)、[ADR 0005:Vercel / Railway](./docs/adr/0005-vercel-railway-split-deployment.md)、[ADR 0006:HMAC 邮件中继](./docs/adr/0006-vercel-hmac-mail-relay.md):当前生产架构的关键决策。
+- [历史计划](./docs/plans):保留项目从 SQLite 原型迁移到 PostgreSQL/R2 云架构的演进记录;它们不是当前运行时配置的事实来源。
+- [安全策略](./SECURITY.md):私密披露方式、支持范围和部署安全要求。
## 主要目录
```text
-src/ Vue 3 前端
+src/ Vue 3 前端与角色工作区
server/routes/ Fastify 领域 API
server/db/migrations/ PostgreSQL 编号迁移
server/services/ 邮件、对话与对象存储适配器
server/ops/ 备份与恢复
-server/test/ API/数据库/安全集成测试
-e2e/ 跨角色 Playwright 工作流
+server/test/ API、数据库和安全集成测试
+e2e/ 四条跨角色 Playwright 工作流
docs/adr/ 架构决策记录
-docs/operations.md 云部署与运维手册
+docs/operations.md 部署与运维手册
```
-安全问题请按 [`SECURITY.md`](./SECURITY.md) 私密报告,不要在公开 Issue 中披露凭据或漏洞细节。
+## 贡献、安全与许可证
+
+欢迎以 Issue 或 Pull Request 参与改进。较大的行为变化请先说明用户旅程、服务端状态变化、测试方式与文档影响;每个 PR 应尽量让实现、测试与说明保持同步。
+
+安全问题请按 [SECURITY.md](./SECURITY.md) 私密报告,不要在公开 Issue、截图或演示环境中泄露凭据、个人数据或漏洞细节。
+
+本仓库当前未随附开源许可证。除适用法律明确允许的情形外,请在复用、再发布或用于生产前先取得维护者许可。
+
+
diff --git a/SECURITY.md b/SECURITY.md
index af0c3a7..f07ac23 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -22,7 +22,7 @@ Please allow time for a fix and coordinated disclosure. After remediation, the p
- Never enable demo seeding in production and never bake administrator credentials into an image or Compose file.
- Store `VERIFICATION_CODE_SECRET`, SMTP, AI, and TURN credentials outside version control; grant access only to deployment operators and rotate them after suspected exposure.
- Keep secure, HttpOnly session cookies enabled, disable bearer authentication unless an audited non-browser client requires it, and configure the trusted proxy boundary deliberately.
-- Back up both the SQLite database and uploaded files, encrypt backups, test restores, and restrict backup access.
+- Back up PostgreSQL data, encrypt backup dumps, test restores, and restrict access to both the private object bucket and the backup bucket.
- Rebuild frequently from the lockfile and review dependency/security alerts before deploying.
Deployment hardening, backup, restore, migration, and secret-handling procedures are documented in [docs/operations.md](docs/operations.md).
diff --git a/docs/adr/0001-self-contained-modular-monolith.md b/docs/adr/0001-self-contained-modular-monolith.md
index b2cab6b..bd82f1b 100644
--- a/docs/adr/0001-self-contained-modular-monolith.md
+++ b/docs/adr/0001-self-contained-modular-monolith.md
@@ -1,7 +1,8 @@
# ADR-0001:采用自包含模块化单体
-**状态:** Accepted
-**日期:** 2026-07-19
+**状态:** Superseded by ADR-0003、ADR-0004 和 ADR-0005 · **日期:** 2026-07-19
+
+> **历史说明:** 这是最初的 SQLite、同进程部署决策。当前运行时使用 PostgreSQL、R2 兼容对象存储与 Vercel/Railway 分离部署;请以 ADR-0003 至 ADR-0006 为当前生产架构的事实来源。
## Context
diff --git a/docs/adr/0002-server-side-opaque-sessions.md b/docs/adr/0002-server-side-opaque-sessions.md
index 97f087c..93b8044 100644
--- a/docs/adr/0002-server-side-opaque-sessions.md
+++ b/docs/adr/0002-server-side-opaque-sessions.md
@@ -1,7 +1,8 @@
# ADR-0002:使用服务端 opaque session
-**状态:** Accepted
-**日期:** 2026-07-19
+**状态:** Partially superseded by ADR-0003 · **日期:** 2026-07-19
+
+> **历史说明:** 不透明服务端 Session 的安全模型仍然有效;当前实现把 Session 摘要保存在 PostgreSQL,而不是本文记录的 SQLite。数据存储事实以 ADR-0003 为准。
## Context
diff --git a/docs/adr/0005-vercel-railway-split-deployment.md b/docs/adr/0005-vercel-railway-split-deployment.md
index 787c492..6ef5e76 100644
--- a/docs/adr/0005-vercel-railway-split-deployment.md
+++ b/docs/adr/0005-vercel-railway-split-deployment.md
@@ -5,7 +5,7 @@
## Decision
-Serve the Vue SPA from Vercel and the single-instance Fastify API from Railway. Vercel externally rewrites `/api/:path*` to Railway, while classroom WebSockets connect directly to the Railway WSS origin returned in the one-time ticket response.
+Serve the Vue SPA from Vercel and the single-instance Fastify API from Railway. Vercel externally rewrites `/api/v1/:path*` to Railway, while classroom WebSockets connect directly to the Railway WSS origin returned in the one-time ticket response.
## Consequences
diff --git a/docs/operations.md b/docs/operations.md
index 6425a37..35060e4 100644
--- a/docs/operations.md
+++ b/docs/operations.md
@@ -1,6 +1,6 @@
-# 公开 Beta 部署与运维手册
+# 公开 Beta 参考部署与运维手册
-本文档对应当前线上架构:Vercel 托管 Vue 前端和邮件中继函数,Railway 运行单实例 Fastify 与独立备份 Cron 服务,Railway PostgreSQL 保存业务数据,Cloudflare R2 私有 Bucket 保存文件与加密备份。
+本文档定义推荐的公开 Beta 部署拓扑:Vercel 托管 Vue 前端和邮件中继函数,Railway 运行单实例 Fastify 与独立备份 Cron 服务,Railway PostgreSQL 保存业务数据,Cloudflare R2 私有 Bucket 保存文件与加密备份。部署前应在自己的 Vercel/Railway/R2 账号中完成域名、Secret 与健康检查验收。
```text
Browser ── HTTPS ──> Vercel ── /api/v1/* rewrite ──> Railway Fastify ──> PostgreSQL
diff --git a/docs/plans/2026-07-24-readme-information-architecture.md b/docs/plans/2026-07-24-readme-information-architecture.md
new file mode 100644
index 0000000..3e4ebd6
--- /dev/null
+++ b/docs/plans/2026-07-24-readme-information-architecture.md
@@ -0,0 +1,38 @@
+# README information architecture overhaul
+
+- Date: 2026-07-24
+- Status: Implemented
+
+## Goal
+
+Rebuild the repository README as a first-class product and engineering entry point. A new reader should understand the platform in 30 seconds, run a verified local workflow in five minutes, and trace major architectural and security decisions within fifteen minutes.
+
+## Decision
+
+Use the visual hierarchy from the earlier portfolio-oriented README—brand hero, navigation, concise quality signals, workflow diagrams, and a completeness contract—while treating the current PostgreSQL, R2/MinIO, Vercel/Railway, and HMAC mail-relay implementation as the only runtime source of truth.
+
+The README remains an entry point rather than an operations manual. Detailed secrets, recovery, R2 CORS, and rollout steps stay in docs/operations.md. Historical SQLite-era plans and ADRs remain available as project history but are explicitly distinguished from current production decisions.
+
+## Reader flow
+
+1. Hero: project purpose, public-beta status, CI, and technology signals.
+2. Value: why persistent cross-role teaching workflows matter.
+3. Evidence: four server-enforced journeys and three role workspaces.
+4. Action: reproducible local quick start, readiness probe, and seeded demo accounts.
+5. Understanding: deployment topology, component responsibilities, and trust boundaries.
+6. Verification: Node tests, browser E2E, CI services, documentation, security, scope, and licensing.
+
+## Facts protected by the rewrite
+
+- Production API traffic uses only the /api/v1/* Vercel rewrite to Railway.
+- Railway sends a signed minimal payload to Vercel /api/mail-relay; Gmail credentials stay in Vercel.
+- PostgreSQL is the current database and R2/MinIO is the object-storage contract.
+- The public beta runs one API instance because classroom presence is currently process-local.
+- The test suite contains 71 Node tests and four cross-role browser workflows at the time of this rewrite.
+
+## Acceptance criteria
+
+- Chinese and English README files tell the same architecture story.
+- Every major claim links to code, a test, or a current operations/ADR document.
+- A reader can reach a ready API and seeded role account without hidden setup assumptions.
+- Limitations are explicit rather than disguised as production capability.