跳到正文

功能

Seed 提供的一切,以及还没有的部分

Seed 是一个免费、MIT 许可的 SaaS 启动模板,提供邮箱、Google 和 GitHub 登录、通行密钥、魔法链接、访客账号、双重验证、带角色的群组、按成员计费的 Stripe 订阅、实时更新、离线应用、管理后台、监控,以及可选的每日加密备份。下面每个部分都附有代码链接。

作者 Anton Shubin更新于

Seed 现在就能用,并且在公开开发中。缺少的部分会在受影响的功能旁标注“尚未完成”,如有对应的 issue,也会附上链接。

替你搞定

群组和计费都已接好的 SaaS 启动模板

账号、群组和收款:每个产品在开发第一个功能之前都需要,也是最容易出错的部分。

目前可用已在 CI 中测试。Google 和 GitHub 登录以及 Stripe 需要你自己的密钥,所以在演示中是关闭的。

账号

登录,已搞定

用户用邮箱和密码注册,并通过验证码验证邮箱。忘记密码可以重置,也可以用 Google 或 GitHub 继续、用通行密钥登录,或者通过邮件获取登录链接(没有账号时会顺便完成注册)。也可以先用访客账号试用应用,之后再添加登录方式。身份验证器应用可以开启双重验证(2FA)。用户能看到自己登录过的每台设备,并可以让其他设备退出登录。更改登录方式时需要验证身份,并会发送邮件通知。

  • 密码通过 Web Crypto 用 PBKDF2-SHA-256 哈希,默认 600,000 轮
  • 签名的会话 Cookie,每次登录事件都有审计记录
  • 个人 API 令牌,只以带密钥的哈希形式存储
  • 通行密钥:只存储公钥,每次登录的挑战只能使用一次
  • 魔法链接:一个链接即可登录或注册,只能使用一次,15 分钟内有效,并且只以哈希形式存储
  • 访客账号(匿名登录):访客一键开始,无需任何登录方式,之后可以在同一个账号上添加邮箱和密码、Google、GitHub 或通行密钥
  • 按登录名统计所有网络地址上的密码错误次数,超过后短暂锁定
个人资料的安全页面:密码、“添加通行密钥”按钮、已开启的双重验证,以及已登录设备列表的开头部分。

群组

带角色的群组,从第一分钟就有

每个账号注册时都会获得一个个人群组。用户可以创建共享群组、邀请他人、分配从查看者到所有者的角色,并一步完成所有权转让。已删除的群组可在 30 天内恢复,每个群组都有活动日志。

  • 群组是唯一的租户边界:个人数据和共享数据经过同样的检查
  • 应用、代码和本站都统一称它为群组
  • 没有第二套权限模型需要与第一套保持同步
  • 邀请、角色变更和所有权转让,各有独立的测试
一个群组的活动日志:谁在什么时候添加了哪条笔记或哪个标签,每条笔记都有打开链接。

概览

每个群组的概览

任意日期范围的关键数据和图表。每个人都可以隐藏和重新排列小组件,布局会同步到他们的其他设备。

  • 每个数字都与上一周期对比,但不用红绿色下结论
  • 只统计数量:不涉及笔记内容,也不给人排名
  • 每个小组件独立加载、独立报错、独立重试
  • 新增的聚合会带上自己的小组件,管理后台也会显示

收款

通过 Stripe 按成员计费

用户可以看到价格表、有使用限制的免费版,以及付费套餐的 14 天试用。所有者在邀请新成员之前就能看到多一位成员要多付多少钱;银行卡扣款失败时,会收到一条带日期的清晰提醒。

  • Stripe Checkout 和客户门户;webhook 是套餐状态的唯一来源
  • 订阅数量随成员人数自动调整
  • 付款失败后有宽限期,默认 7 天
  • 套餐限制在服务器端检查,而不只是在应用里
  • 套餐保存在一个目录文件中,价格页直接读取它
尚未完成
  • Stripe 以外的支付服务商
一个示例群组的套餐与账单标签页,按演示用的示例价格显示:Pro 套餐及其续订日期,每月 €36.00,共 4 位成员,每人 €9.00,含所有者,还有更换银行卡、查看发票和取消套餐的按钮。

隐私

用户可以随时离开的账号

用户可以在个人资料中下载自己的数据副本,或删除账号,并有 7 天时间改变主意。已读通知会在 90 天后删除。

  • 下载我的数据:一个包含 JSON 和 CSV 文件的 ZIP,在后台生成,保留 7 天
  • 删除会等待 7 天;期间重新登录即可取消
  • 每晚清理已读通知、失效邀请和旧的审计事件

导出

你的数据,随你带走

可以把任意群组导出为开放的 JSON 文件,之后再作为新群组导入。原来的群组永远不会被覆盖。

  • 所有者负责导出;任何能创建群组的人都可以导入
  • 写入任何数据之前会先检查整个文件,然后一步完成导入
  • 每条笔记和每个标签都会获得新的 ID,因此导入永远不会与现有数据冲突
  • 每个聚合各自注册它在文件中的部分

多语言

从一开始就支持九种语言

应用、管理后台和本网站支持英语、俄语、西班牙语、德语、巴西葡萄牙语、阿拉伯语、法语、日语和简体中文。用户在应用中选择语言,选择会保存到账号中。本网站的每个页面在每种语言下都有独立的地址。

  • 每种语言一个 TypeScript 目录文件,由测试检查并列出所有缺失或过时的文案
  • 复数、数字和日期使用平台自带的 Intl,不依赖任何 i18n 库
  • 网站的每个页面都有 hreflang 链接,站点地图列出每种语言
  • 阿拉伯语页面从右向左排版
  • 邮件以收件人的语言发送

需要时随时可用

实时同步、离线和后台任务

大多数启动模板因为太难而略过的部分:实时更新、没有网络也能用的应用,以及绝不能丢失的任务。

目前可用离线写入支持笔记和标签;其他列表在离线时会显示上次加载的内容。

实时同步

无需刷新,更改即时可见

一位成员的更改会出现在该群组每个打开的标签页中;笔记本从休眠中唤醒后,也会补上错过的内容。

  • 标准 WebSocket,每次更改都带有序号
  • 从休眠中唤醒的标签页会重新连接,并拉取错过的内容
  • 实时同步可以关闭:应用会改为定时轮询,使用体验不变
第一个窗口:笔记编辑器,标题已改为“Q4 路线图:新用户引导、计费和发票”。
窗口 1
第二个窗口,单独登录:点击“保存”后,它的笔记列表顶部立刻显示新标题,无需刷新。
窗口 2

离线

没有网络也能打开的应用

应用可以像原生应用一样安装,没有网络也能打开,网络恢复后会自动发送排队中的更改。过时的更改会显示为需要你处理的冲突,绝不会悄悄覆盖。

  • 每个列表在 IndexedDB 中都有一份副本,写入队列带有幂等键
  • 每个冲突都可以选择“保留我的版本”或“使用服务器版本”
  • 改一项设置即可关闭,或者彻底移除:删除一个文件夹,再按书面清单操作
离线时做的更改遇到了服务器上更新的版本:“有 1 项更改需要你来选择”并排显示笔记的两个版本,并提供“保留我的版本”和“使用服务器版本”。

键盘

应用和管理后台都支持键盘快捷键

按 ? 查看所有快捷键。在任意页面按 N 即可添加笔记,无需离开当前页面;先按 G 再按一个字母即可打开对应栏目。在输入框中打字时,快捷键不会干扰你。

  • 按 Ctrl K(Mac 上为 ⌘K)或 / 打开搜索
  • 每个应用用一份列表绑定按键并生成 ? 对话框的内容,所以它绝不会显示一个按了没反应的键
  • 可以在某台设备上关闭单键快捷键;Ctrl K 和 Esc 仍然有效
  • 在管理后台中,先按 G 再按一个字母即可打开各个模块

通知

应用内、手机、桌面和 Telegram 通知

用户在受到邀请、获得新角色或被转让群组时会收到通知:在应用内、通过手机或桌面上的 Web 推送,以及关联 Telegram 后在 Telegram 中。

  • 使用你自己密钥的 Web 推送,一条任务即可生成:deno task vapid-key:create
  • 应用内的未读数,以及“全部标为已读”
  • 个人资料中列出每台设备的推送订阅
  • Telegram 机器人,设置令牌之前处于关闭状态:通过一次性验证码关联,你的产品自己的命令只需在一个文件中添加
通知页面:三条未读通知,分别关于新的群组所有者、角色变更和一份邀请,点击每一行都会打开相关内容。

后台任务

崩溃也不会丢失的任务

即使服务器中途重启,邮件和通知也照样会发出,因为任务在执行之前就已保存。你自己的任务可以立即运行、稍后运行或定时运行。

  • 每个命令都在与更改相同的数据库事务中写入它的事件
  • Worker 消费这个 outbox,发送邮件、推送和实时更新
  • 一个任务就是一个定义:名称、处理函数,如果需要重复执行,再加上调度计划
  • 失败的尝试会以逐渐延长的间隔重试;运营人员可以在管理后台看到每一次运行
同一事务:要么都保存,要么都不保存更改一条笔记、一位成员它的事件outbox 中的一行Worker消费 outbox邮件验证码、通知推送手机、桌面实时其他标签页

你的产品

复制一个功能,就能添加一个新功能

笔记是一个贯穿所有层的完整功能:数据库、API、界面、离线和测试。新功能照着它逐个文件复制即可,有一份清单按顺序列出了每个文件。

  • 每个功能都是同一种结构,代码始终好找
  • 每一层都有自己的测试,可以一并复制
  • 每个 ID 都是按时间排序的 UUID(第 7 版)
1 libs/domain/notes/+lib.ts 2 libs/server/db/migrations/…_notes.sql 3 libs/server/notes/ 4 apps/api/features/notes/handlers.ts 5 apps/api/features/notes/operations.ts 6 libs/ui/notes-screen.tsx 7 apps/spa/src/state/notes.ts 8 e2e/notes.e2e.ts

运维

运行它、监控它、支持它的用户

一台你租用的服务器,看清它在做什么的工具,以及一个让运营人员帮助产品用户的后台。

目前可用下面每个模块现在都已上线。尚未完成的部分都列在对应模块下方。

支持

给运营人员用的管理后台

运营人员可以按姓名或邮箱查找用户,查看其登录方式、会话、群组和历史记录。在同一个地方,他们还能管理群组、退款、维护邮件简报的订阅者、查看所有后台任务、重新运行失败的任务,以及检查系统健康状况。 59 秒看完演示.

  • 独立的应用,运行在独立的域名上,使用独立的会话 Cookie
  • 13 个模块,从仪表盘到 API 令牌
  • 有风险的操作会先确认,每个操作都会写入审计日志
尚未完成
  • 以用户身份登录,看到对方所看到的内容

部署

一台服务器,一条命令

Seed 可以运行在你租用的任何 Linux 服务器上,开发和生产环境都使用 Docker Compose。多个产品可以共用一台服务器。

  • Traefik 作为入口,自动签发证书
  • Postgres 和 Valkey 与应用一起运行
  • Garage(一个 S3 文件存储)用于存放笔记中的图片和 PDF 以及头像。上传通过签名链接进行,并按文件内容检查。照片(包括 HEIC)会被转换为体积小巧的 AVIF 和 WebP 版本,并移除位置等元数据
  • VictoriaMetrics、VictoriaLogs 和 Grafana,带告警
  • 可选的每日 restic 加密数据库备份,以及书面的恢复步骤
  • 推送版本标签时,由 CI 发布正式版镜像
$ deno task deploy Copying files... Copying infra/envs/.env.prod to infra/envs/.env... Creating web push keys if missing... Starting the app... Deploy completed.
已精简:省略了各步骤之间 rsync 和 Compose 的输出。
  • Traefik
  • Postgres
  • Valkey
  • VictoriaMetrics
  • VictoriaLogs
  • Grafana
  • Alertmanager
  • Garage file store
  • restic backups

网站

可直接改造的公开网站

就是本站:快速、服务端渲染,关闭 JavaScript 也能使用,包含价格页、法律页面、博客和邮件简报。

  • 服务端使用 Fresh;每个操作都是真实的链接或表单
  • 价格读取自应用的套餐目录
  • 双重确认订阅的邮件简报,一键退订,邮件以收件人的语言发送
  • 在管理后台撰写的博客,支持每种语言的文章及其译文、主题、RSS 订阅源和文章结构化数据
  • 在管理后台设置的联系方式,显示在页脚和结构化数据中
  • 可选的商品目录,适合网店,在管理后台编辑:商品照片、颜色、尺码、尺码表和售罄尺码,覆盖你销售的每种语言,并为每个商品和每个分享渠道生成一个短追踪链接
  • sitemap.xml、robots.txt、规范链接和 Open Graph 图片
  • 可选的无 Cookie 统计,使用你自己的 Umami,每个行动号召都有事件记录,管理后台有统计页面:按来源和商品查看访问量和下单点击
  • 每个页面都支持九种语言,各有独立地址和 hreflang 链接;法律页面保留英文版

质量

该测的地方都测了

统计于2026年10月16日:应用有 34 个浏览器测试套件,另有单元测试和界面测试,全部在 CI 中运行。每项更改在合并之前都要经过 pull request 和代码审查。

  • 使用 Playwright 的浏览器测试,直接针对真实的 API 和数据库
  • 单元测试和界面测试就放在被测代码旁边
  • 针对 Postgres 的集成测试
Seed 与其他方案的对比

常见问题

Seed 能做到吗?

Seed 能在 Vercel 或 Serverless 函数上运行吗?

不能。Seed 以常驻容器的形式,用 Docker Compose 运行在你租用的一台 Linux 服务器上,因为 API 需要保持 WebSocket 连接,Worker 需要持续消费队列。

Seed 能在 Node.js 或 Bun 上运行吗?

目前还不能。Seed 的服务器在 Docker 中的 Deno 2 上运行,任务和测试也使用 Deno。代码基于 fetch、Request 和 Web Crypto 等 Web 标准编写。

Seed 能使用 Postgres 以外的数据库吗?

不能。Seed 基于 Postgres 构建:它的迁移、查询和集成测试都以 Postgres 为前提。

Seed 能发布为移动或桌面应用吗?

暂时还不能作为应用商店里的应用发布。目前,Web 应用可以在手机和电脑上通过浏览器安装,没有网络也能打开;Android 和桌面应用已在计划中。

一分钟看它跑起来

演示就是你第一天就能拿到的应用。无需注册即可打开:你的访客账号自带示例数据。