架构
系统概览
iOS 应用 / 代理客户端 -> api.<domain> -> API Gateway -> Lambda 后端 -> Postgres
网页应用 -> app.<domain> -> CloudFront -> SPA
浏览器与代理认证 -> auth.<domain> -> API Gateway -> 认证 Lambda -> Cognito
顶级域名回退 -> <domain> -> CloudFront 重定向 -> app.<domain>
原则
app、api和auth分别使用独立的公开域名。- Postgres 是唯一的真实数据源。
- iOS 客户端采用离线优先模式,本地使用 SQLite,并通过同步与服务端保持一致。
- 网页应用、iOS 应用和外部代理接口共享同一套工作区数据模型。
- 外部代理从
GET https://api.flashcards-open-source-app.com/v1/开始接入。
支持的客户端
- 运行在
app.flashcards-open-source-app.com的网页应用 - 主仓库中的 iOS 应用,本地使用 SQLite 存储
- 发布在 Google Play 上的 Android 应用
- 通过发现流程、OTP 引导和
Authorization: ApiKey接入的外部代理客户端
数据模型
workspacesworkspace_membersuser_settingsdevicescardsdecksreview_eventsapplied_operationssync_state
数据流
网页应用
- 浏览器通过
auth.<domain>完成登录。 - 网页应用从
api.<domain>加载工作区数据。 - AI 聊天请求通过
/chat/local-turn。 - 复习提交在写入时会更新调度器状态。
iOS
- iOS 应用先把数据写入本地 SQLite。
- 本地变更会进入待发送队列。
- 同步通过
/v1/workspaces/{workspaceId}/sync/push上传变更。 - 同步通过
/v1/workspaces/{workspaceId}/sync/pull拉取远端更新。 - 本地数据库应用这些变更,并推进同步游标。
外部代理
- 代理客户端从
GET /v1/开始。 - OTP 引导流程在
auth.<domain>上进行。 - 代理客户端会获得一个长期有效的 API 密钥。
- 代理客户端会先加载
/v1/agent/me,列出可用工作区,必要时选择其中一个,然后再调用/v1/agent/sql。
调度
Flashcards 使用 FSRS 作为复习调度器。
实现说明:
- 后端和 iOS 分别维护一套相互镜像的 FSRS 实现。
- 网页应用遵循同一份调度数据契约,但不会额外内置第三套调度器实现。
- 工作区级别的调度设置包括期望保留率(
desired retention)、学习步骤(learning steps)、重新学习步骤(relearning steps)、最大间隔(maximum interval)和fuzz。 - 实际的复习时间戳取自
reviewedAtClient。
更详细的契约说明,请参阅主仓库中的 FSRS 调度逻辑。
认证
- 通过 Cognito 提供邮箱 OTP 登录。
- 托管的网页应用使用跨子域共享的浏览器会话 Cookie。
auth.<domain>上的代理客户端 OTP 引导流程会返回长期有效的ApiKey。AUTH_MODE=none用于本地开发。AUTH_MODE=cognito用于接近生产环境的认证方式。
部署形态
app.<domain>-> CloudFront + S3api.<domain>-> API Gateway + Lambda 后端auth.<domain>-> API Gateway + Lambda 认证服务- Postgres 部署在 AWS RDS 上
顶级域名可以继续保留给独立的营销网站使用。如果在初始部署阶段尚未被占用,基础设施也可以临时将其重定向到 app.<domain>。