Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

86 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

International Chinese Platform 标志:汉语与地球

International Chinese Platform

面向国际中文教育的公开 Beta 全栈教学协作平台

将教师认证、课程审核、预约课堂和作业反馈连接为同一条可部署、可验证、可审计的教学闭环。

项目概览 · 教学闭环 · 公开体验 · 快速开始 · 系统架构 · 质量证据 · 文档 · English

CI Status: public beta 71 Node tests 4 cross-role browser workflows Vue 3 Fastify 5 PostgreSQL 15 Cloudflare R2 and MinIO Node.js 24 pnpm 11 Docker Compose


项目概览

International Chinese Platform 不是只展示页面的课程原型,而是一套围绕真实教学协作建模的全栈系统:学生、教师和管理员在同一份 PostgreSQL 业务数据上完成身份认证、教师认证、课程审核、预约、课堂、作业、通知与中文对话练习。

这个仓库同时包含 Vue 3 前端、Fastify 领域 API、编号迁移、私有对象存储适配、实时课堂协议、测试、部署配置与运行手册。推荐的公开 Beta 部署拓扑将前端放在 Vercel、版本化 API 放在 Railway,文件放在私有 Cloudflare R2,生产邮件经签名的 Vercel 中继投递。项目不会依赖某个版本不明的外部后端。

Important

完整性契约:在当前公开 Beta 的边界内,任何人都可以从本仓库安装依赖、启动 PostgreSQL 与 MinIO、迁移和导入演示数据、体验三角色流程、运行测试,并沿着文档部署核心服务。完整不等于虚构商业 LMS 能力;支付、正式选课、课堂录制、多节点实时广播和高可用被明确列为后续范围。

为什么值得深入阅读

  • 真正的业务闭环,而不是菜单堆砌:课程、预约、作业和教师认证都有服务端状态转换、权限约束、通知与审计记录。
  • 同一份事实数据:角色页面不是各自模拟;教师、学生和管理员都读写同一套 PostgreSQL 领域数据。
  • 安全边界被写进实现:会话不透明且只通过 HttpOnly Cookie 传递;写操作验证来源、角色与资源归属;文件先进入临时对象再校验并条件晋升。
  • 从本地到公开 Beta 的路径完整:开发环境使用 PostgreSQL + MinIO;生产架构使用 Vercel、Railway、PostgreSQL、R2 与受 HMAC 保护的邮件中继。
  • 诚实地表达限制:实时房间成员状态目前驻留单个 API 进程,因此公开 Beta 只运行一个后端实例;未用“高可用”或“无限扩展”掩盖这一事实。

四条可验证的教学闭环

每条旅程都应说明一次真实操作怎样跨越角色、状态与持久化边界。下图中的四条流程也是浏览器 E2E 实际验证的核心旅程。

flowchart TB
  subgraph Verification["教师认证"]
    V1["教师注册 / 修改资料"] -->|进入待核验队列| V2["管理员人工核验"]
    V2 -->|批准| V3["已认证:公开展示、可被预约"]
    V3 -->|撤销或资料再次变更| V1
  end

  subgraph Course["课程审核"]
    C1["教师创建草稿"] -->|提交审核| C2["待审核"]
    C2 -->|批准| C3["已发布:学生可发现"]
    C2 -->|驳回并附理由| C4["已驳回"]
    C4 -->|修改后重提| C2
  end

  subgraph Lesson["预约与课堂"]
    L1["学生发起预约"] -->|教师接受 + 双方冲突检查| L2["已接受 + 专属课堂"]
    L1 -->|教师拒绝 / 任一方取消| L3["关闭"]
    L2 -->|时间窗内获取一次性票据| L4["聊天、在线状态、WebRTC 信令"]
    L4 -->|参与者完成课堂| L5["课堂完成"]
  end

  subgraph Assignment["作业与反馈"]
    A1["教师编写并发布"] -->|学生保存草稿| A2["学生提交"]
    A2 -->|教师评分与反馈| A3["学生查看结果"]
    A1 -->|关闭作业| A4["禁止新的写入"]
  end
Loading
旅程 用户能看到什么 服务端承担的关键约束
教师认证 教师资料被审核;被撤销后不再被学生发现或预约 管理员决定、状态冲突保护、审计与通知;资料变更自动重新待审
课程审核 草稿可被驳回、修改并再次提交;学生只看到已发布课程 教师所有权、审核状态机、发布可见性
预约与课堂 学生发起预约,教师接受后进入专属课堂 双方时间冲突检查、事务创建课堂、短期单用途 WebSocket 票据、房间隔离
作业与反馈 教师发布,学生提交,教师评分,学生看到结果 截止时间和关闭状态校验、提交所有权、评分结果持久化

三个工作区

学生 教师 管理员
发现已认证教师和已发布课程;预约课堂;提交作业;练习持久化中文对话;查看通知与评分。 维护专业资料;提交课程审核;处理预约;参与课堂;发布、关闭和评分作业。 核验教师;审核课程;查看聚合指标、审计活动与平台级工作状态。

公开发现与学生转化路径

公开 Beta 不再把登录页当作陌生访客的第一站。首页先解释平台价值,访客无需账户即可查看真实 API 返回的已认证教师与已发布课程;当访客准备预约时,平台才要求登录或注册,并在学生身份验证成功后恢复原来的教师详情与预约意图。

flowchart LR
  Home["公开首页 / "] --> Teachers["教师目录 /teachers"]
  Home --> Courses["课程目录 /courses"]
  Teachers --> Teacher["教师详情 /teachers/:teacherId"]
  Courses --> Course["课程详情 /courses/:courseId"]
  Teacher -->|"发起预约"| Auth["登录或注册 /login"]
  Auth -->|"学生 + 已校验同源 redirect"| Booking["返回教师详情并继续预约"]
  Auth -->|"教师或管理员"| Workspace["进入对应角色工作区"]
Loading
路由 是否需要登录 用途
/ 双语价值主张、认证教师与精选课程;教师和课程资源独立加载,单个 API 失败不会拖垮整个首页。
/teachers/teachers/:teacherId 浏览已启用、已认证教师;搜索、专长、最低评分和分页条件保存在 URL 中。
/courses/courses/:courseId 浏览已发布且教师已认证的课程;搜索、分类和分页条件保存在 URL 中。
/login?mode=login|register&redirect=... 登录或三步注册;学生登录后恢复经过校验的预约路径。
/legal/terms/legal/privacy 版本化 Beta 条款与隐私说明。
/account-recovery/403/404 真实支持入口,以及明确的权限不足和资源未找到状态。

语言、跳转与预约语义

  • 语言选择:优先使用保存在 localStorage 的用户选择;没有历史选择时读取浏览器首选语言,中文环境使用中文,其余环境默认英文。切换语言会同步更新 html lang 与页面元数据。
  • 安全返回redirect 只接受以单个 / 开头的同源站内路径,拒绝协议相对地址、反斜杠、跨域目标和再次跳回登录页,避免开放重定向。只有学生身份会恢复预约目标;教师和管理员进入各自工作区并收到角色说明。
  • 预约不是购买:参考价格仅供沟通,当前不会收取费用;预约必须由教师确认后才成立。发生时段冲突时,表单保留用户输入并允许重新选择,而不是产生重复请求或虚构可用时段。

快速本地启动

前置条件

  • 推荐 Node.js 24;项目支持 Node.js 22 及以上版本
  • pnpm 11.9.0(由 packageManager 固定)
  • Docker Desktop 或 Docker Engine,用于本地 PostgreSQL 与 MinIO
  • 可选:Python 3.12 + Playwright Chromium,用于运行浏览器 E2E

1. 克隆、安装并创建本地配置

git clone https://github.com/computersciencefreshmen/International_Chinese_Platform.git
cd International_Chinese_Platform
corepack enable
pnpm install --frozen-lockfile

Windows PowerShell:

Copy-Item .env.example .env.local

macOS / Linux:

cp .env.example .env.local

.env.local 把开发 API、PostgreSQL 和 MinIO 连接放在同一份显式配置中;无需填写 SMTP、AI 或 TURN 才能体验核心教学流程。

2. 启动依赖、迁移数据并导入演示内容

首次拉取镜像时,请先等待 PostgreSQL 显示为 healthy,且 minio-init 成功完成,再执行迁移与种子命令。

docker compose up -d postgres minio minio-init
pnpm db:migrate
pnpm db:seed
pnpm dev

打开以下地址:

3. 验证启动成功

macOS / Linux:

curl --fail http://localhost:7777/api/v1/ready

Windows PowerShell:

Invoke-RestMethod http://localhost:7777/api/v1/ready

如果 API 就绪,访问 Web 地址并使用下列仅限本地演示的账号登录:

角色 邮箱 密码
学生 student@example.com Demo123!
教师 teacher@example.com Demo123!
管理员 admin@example.com Demo123!

教师认证是平台管理员的人工审核,不等同于外部证书颁发方的联网真实性核验;后者仍在当前范围之外。

Caution

演示数据只能在本地或测试环境显式导入。生产配置拒绝 SEED_ON_START=truepnpm db:seedpnpm db:reset 也不应对生产数据库执行。

常用命令

pnpm dev                 # 同时启动 Vite 与 Fastify
pnpm build               # 构建生产前端
pnpm db:migrate          # 应用尚未执行的 PostgreSQL 编号迁移
pnpm db:seed             # 导入幂等演示数据(非生产)
pnpm db:reset            # 重建本地开发数据库(会删除本地 public schema)
pnpm admin:bootstrap     # 一次性创建首个生产管理员
pnpm test:unit           # Vitest:语言选择、文案目录与前端单元测试
pnpm test:api            # Node:API / PostgreSQL / 安全集成测试
pnpm test:e2e            # Playwright:公开发现、Auth、预约、可访问性与响应式验收
python e2e/test_workflows.py # Python Playwright:四条跨角色生产构建工作流
pnpm check               # ESLint + Prettier + unit/API 测试 + 生产构建
pnpm backup:create       # 生产备份配置完成后,创建加密 PostgreSQL 备份
pnpm backup:restore      # 生产恢复配置完成后,受 CONFIRM_RESTORE 保护地恢复

系统架构:职责清晰,信任边界明确

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"]

  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
Loading

本地图中,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 进程职责分离;恢复仍需显式确认。

工程可信度与质量证据

领域 实现方式 可验证证据
身份与授权 scrypt 密码哈希、服务端 Session 摘要、HttpOnly Cookie、来源校验、角色与资源所有权检查 认证测试安全策略
教学状态 PostgreSQL 事务、条件更新、编号迁移、审计与通知 领域路由迁移
私有文件 上传意图、临时 Key、签名绑定类型与长度、魔数/SHA-256、ETag 条件晋升、短期签名下载 对象存储 ADR文件测试
实时课堂 短期、单用途课堂票据;聊天室成员、历史与 WebRTC 信令按课堂隔离 课堂测试
邮件边界 Railway 对 Vercel Function 的 HMAC 请求、时间窗与严格 payload 校验 邮件中继 ADR
发布与恢复 健康/就绪探针、扩展型迁移、加密备份、恢复确认与回滚步骤 运维手册

CI 实际验证什么

pnpm check 会运行 ESLint、Prettier、Vitest 单元测试、完整 Node API/数据库/安全测试与 Vite 生产构建。本仓库当前包含 71 个 Node API 测试;GitHub Actions 另设两套互补的浏览器门禁:

  • pnpm test:e2e -- e2e/playwright/public-conversion.spec.js --grep-invert @visual 验证公开首页、匿名教师/课程发现、登录后预约意图恢复、409 冲突恢复、注册草稿不保存密码或验证码、键盘/触控目标、axe 与多断点无横向滚动。
  • python e2e/test_workflows.py 在 PostgreSQL、MinIO 和生产构建上验证以下四条跨角色业务流程:
  1. 课程“提交 → 驳回 → 修改重提 → 批准 → 学生目录可见”。
  2. 预约“学生申请 → 教师接受 → 专属课堂 → 学生完成课堂”。
  3. 作业“教师发布 → 学生提交 → 教师评分 → 学生查看反馈”。
  4. 教师认证“管理员撤销 → 学生无法发现/预约 → 管理员重新批准 → 重新公开”。

公开转化测试会由 Playwright 配置自动启动 Vite;第一次运行前执行 pnpm test:e2e:install 安装 Chromium。跨角色测试需要先安装 e2e/requirements.txt 与 Python Playwright Chromium,并以与 CI 工作流 相同的 PostgreSQL、MinIO 和生产环境变量启动服务。查看 Node 测试公开转化 E2E跨角色 E2E

前端性能与体验预算

公开 Beta 将以下指标作为发布门槛,而不是事后优化建议:初始 JavaScript gzip 小于 200 KiB,关键首屏资源小于 800 KiB;移动端 Lighthouse 目标为 LCP 小于 2.5 秒、CLS 小于 0.1、INP 小于 200 毫秒。支持 360、390、768、1024、1280 与 1440 px 宽度,页面不应出现整体横向滚动;核心交互触控目标至少为 44 × 44 px,并尊重 prefers-reduced-motion

部署、运维与适用范围

推荐的公开 Beta 生产拓扑为:Vercel 托管 Vue 单页应用与邮件中继函数;Railway 托管一个 Fastify API 实例、PostgreSQL 与独立备份 Cron;Cloudflare R2 保存私有文件和加密备份。完整的 Secret、R2 CORS、迁移、管理员初始化、监控、恢复演练和回滚步骤在 运维手册

现在适合 当前未覆盖
课程项目、作品集展示、小规模自部署教学协作、公开 Beta 验证 支付结算、正式入学与席位扣减、课堂录制、教师证书真实文件上传与外部真实性核验、付费 AI、多实例实时广播、高可用
可直连或已配置 TURN 的课堂环境 严格 NAT 下的可靠音视频(尚未内置 TURN)

价格和容量目前是课程信息,并不代表支付或正式席位占用。在正式选课模型上线前,已发布课程的作业对所有登录学生可见并可提交;当前没有 roster 或 enrollment 权限层。扩展为多实例前,需要先为课堂成员状态引入跨实例广播与协调层。

文档地图

主要目录

src/                    Vue 3 前端与角色工作区
server/routes/          Fastify 领域 API
server/db/migrations/   PostgreSQL 编号迁移
server/services/        邮件、对话与对象存储适配器
server/ops/             备份与恢复
server/test/            API、数据库和安全集成测试
e2e/                    四条跨角色 Playwright 工作流
docs/adr/               架构决策记录
docs/operations.md      部署与运维手册

贡献、安全与许可证

欢迎以 Issue 或 Pull Request 参与改进。较大的行为变化请先说明用户旅程、服务端状态变化、测试方式与文档影响;每个 PR 应尽量让实现、测试与说明保持同步。

安全问题请按 SECURITY.md 私密报告,不要在公开 Issue、截图或演示环境中泄露凭据、个人数据或漏洞细节。

本仓库当前未随附开源许可证。除适用法律明确允许的情形外,请在复用、再发布或用于生产前先取得维护者许可。

回到顶部 ↑