内容
# Calnode
**一款简洁、可自行托管的日程安排引擎,可与您的 AI 堆栈集成。**
Calnode 是一款类似 Calendly 的预约应用,以单个 Go 二进制文件发布,带有嵌入式 SQLite 数据库 - 无需 Redis,无需 Postgres,无需单独的 API 服务器,无需多 GB 镜像。它是 API-first、原生支持 Webhook 的,适用于代理执行预约的场景。您可以自行托管整个系统在一台 5 美元的服务器上;没有任何功能被付费墙限制。
> 我们的生产实例每月仅需 **~0.09 美元** 的计算费用。它是一个单一的静态二进制文件,服务于一个 SQLite 文件 - 运行成本几乎为零。
`Apache-2.0` · `Go 1.26` · `single static binary` · `SQLite + Litestream`
---
## 为什么选择 Calnode
- **一个二进制文件,一个文件。** 纯 Go SQLite(无 CGO)编译为一个完全静态的二进制文件。您可以通过 `docker run` 运行它,或直接部署到 VPS 服务器上。无需额外的服务来协调。
- **API-first,适用于代理。** 具有 88 个端点的完整 REST API,支持 API 密钥和 **HMAC 签名的 Webhook,可通过 API 配置** - 您可以使用 Claude、ChatGPT、n8n 或 curl 脚本化每个预约操作。同时,内置 **MCP 服务器**(官方 Go SDK;stdio + Streamable HTTP),为代理提供一流的预约工具。
- **现代化,无冗余。** Go 后端 + SvelteKit 5 管理应用;公共预约页面是服务器渲染的 Go 模板,实现即时加载和轻量级页面。
- **正确性至上。** DST 安全的时间处理(UTC 时间 + IANA 时区名称),事务性的重复预约保护,以及原生的 API 日历空闲/忙碌检查(不会出现过时的 `.ics` 源)。
- **属于您。** 按租户隔离的设计 - 一个部署对应一个隔离的工作空间,您的数据,您的日历凭证。没有共享的多租户数据库。
- **易于扩展。** 清洁的 Go 代码库,带有 `sqlc` 生成的查询 - 不是一个 100 包的 monorepo。您可以轻松添加一个新端点。
---
## Calnode vs cal.com
默认的开源调度器是一个 SaaS 巨型应用。Calnode 则完全相反。
| | cal.com | Calnode |
|---|---|---|
| **代码库** | 500k+ LOC TS across ~100 packages | 精简的 Go + 一个 SvelteKit 应用 |
| **运行时依赖** | 4 GB+ 镜像;需要 Redis **+** Postgres **+** API 服务器 | 一个静态二进制文件 + 一个 SQLite 文件 |
| **数据库** | Postgres (+ Redis) | SQLite (WAL) + Litestream 实时备份 |
| **Webhook** | 仅限 UI | **API-first**,HMAC 签名,每个 Webhook 的有效载荷 |
| **AI / 代理** | 无 | REST API + Webhook **+ 原生 MCP 服务器** (stdio + HTTP) |
| **部署** | 协调多个服务 | `docker run` 一个容器 |
| **隔离性** | 共享多租户 DB(到处都有 `org_id`) | 按租户隔离 - 默认隔离 |
| **许可证** | AGPL-3.0 | **Apache-2.0**,无付费墙限制 |
*(cal.com 数据反映其公开范围;请参阅设计文档以获取完整原理。)*
如果您正在权衡自托管调度器,并希望 **小巧、快速、可脚本化且支持 AI**,而非功能最大化,Calnode 就是为您而建。
---
## AI 原生
通过 API,任何人类可以做的事情,代理也可以做到:
```bash
# 查找时间段并预约,附带 API 密钥
curl -s "$BASE/v1/event-types/intro-call/slots?from=2026-06-16&to=2026-06-20&tz=Pacific/Auckland" \
-H "Authorization: Bearer $API_KEY"
curl -s -X POST "$BASE/v1/bookings" -H "Authorization: Bearer $API_KEY" \
-H 'Idempotency-Key: 9f3c…' -H 'Content-Type: application/json' \
-d '{"event_type_slug":"intro-call","start_at":"2026-06-17T21:00:00Z","name":"Alex","email":"alex@example.com","timezone":"Pacific/Auckland"}'
```
通过 API 配置 Webhook,将预约生命周期事件(`booking.created` / `.rescheduled` / `.cancelled`)发送到 n8n / Make / 您自己的服务。
**原生 MCP 服务器。** 一个 Model Context Protocol 服务器被编译 **到二进制文件中**(官方 Go SDK),暴露八种一流工具 - `list_event_types`,`get_event_type`,`get_available_slots`,`create_booking`,`get_booking`,`reschedule_booking`,`cancel_booking`,`list_bookings`。MCP 工具调用与 REST API 相同的内部服务(无并行代码路径),因此预约的副作用 - 日历事件,确认邮件,Webhook,提醒 - 都会完全相同。
两种传输方式:
- **stdio** 用于本地代理 - 运行 `calnode mcp`(日志输出到 stderr,JSON-RPC 输出到 stdout)。
- **Streamable HTTP** 在 `POST /mcp` 用于远程代理。Calnode 自身就是一个 **OAuth 2.1 授权服务器**(动态客户端注册 + PKCE),因此代理通过 URL 添加服务器并点击 **连接** → 使用工作区的 Google/Microsoft 登录 → 批准一个同意屏幕 - 无需预共享密钥。`cno_` API 密钥也适用于脚本。(Connect UX 需要 HTTPS - 它在部署的实例上很出色。)
```
用户: "下周在奥克兰与 Wynne 预约 30 分钟通话。"
代理: get_available_slots("intro-call", "2026-06-16", "2026-06-20", "Pacific/Auckland")
→ 呈现选项 → create_booking(…) → 返回确认 + 会议链接
```
**对话式预约 - 在预约页面本身。** 除了代理外,预约页面(和嵌入式小部件)提供一个可选的 **"通过聊天预约"** 助手:访客输入"免费的周二下午或下周"并解析实际可用性并预约 - 确定性引擎仍然计算时间段(模型从不发明时间),而助手仅查看空闲/忙碌窗口,从不查看您的日历内容。 **自带模型** - 任何 OpenAI 兼容的端点(托管模型或您自己运行的模型);默认为关闭,标准日历始终作为备用。
**连接 Claude(远程 / HTTP)。** 在 Claude(claude.ai 或 Desktop)→ **设置 → 连接器 → 添加自定义连接器** → 输入 `https://<your-instance>/mcp` → **连接** → 登录 → **允许**。自定义连接器需要付费的 Claude 计划;服务器必须在 HTTPS 上。 *本地 stdio 替代方案(任何计划):* 将 MCP 客户端指向 `calnode mcp` 子命令通过其配置文件 - 无需 OAuth,直接访问本地 DB。
**权限。** MCP 工具 **按角色范围划分**,镜像应用的其他部分:**所有者/管理员** 在整个工作区范围内操作,**成员** 仅查看和管理他们主办的预约。(stdio 子命令是本地操作员 → 完全访问。)预约 **创建** 和可用性是公共预约界面,对所有人开放。角色固定(所有者 / 管理员 / 成员);可配置的 RBAC 有意在精简的核心之外。
---
## 快速开始
```bash
docker run -d -p 3000:3000 \
-e BASE_URL=https://booking.example.com \
-e CALNODE_ENCRYPTION_KEY="$(openssl rand -hex 32)" \
-e CALNODE_RECOVERY_SECRET="$(openssl rand -hex 32)" \
-e DATABASE_URL=sqlite:///data/calnode.db \
-v calnode-data:/data \
<your-image>
```
打开 `/` → 它重定向到 `/admin/` 并引导您完成首次设置(创建所有者帐户,连接日历,添加事件类型)。在前面添加一个 TLS 终止代理,转发原始 `Host` 头。
**完整指南 → [DEPLOY.md](DEPLOY.md)** (环境变量, Railway 逐步指南,自定义域名,Resend 电子邮件,Google & Microsoft OAuth,Litestream 备份,故障排除)。
---
## 功能
**已发布**
- 事件类型,具有每种类型的时长,位置,自定义问题,自定义电子邮件副本
- DST 正确的可用性(工作时间,按周计算的规则,日期覆盖)
- 团队路由: **固定 · 循环 · 集体 · 优先级**
- **Google 日历和 Microsoft 365 / Outlook** - 原生空闲/忙碌冲突检查,背后有一个提供程序抽象;自动 **Google Meet / Teams** 链接,仅当主持人的连接日历与平台匹配时才会生成(否则使用手动链接)
- **使用 Google 或 Microsoft** (OAuth)或电子邮件 + 密码登录
- 公共预约 + 自助 **重新安排/取消**,通过签名的管理链接
- HTML 品牌电子邮件(徽标,商业名称,大小/不透明度)与添加到日历的链接
- REST API(88 个端点)+ API 密钥; **HMAC Webhook**,每个 Webhook 的有效载荷 + 交付日志
- **原生 MCP 服务器**(8 种工具;通过 `calnode mcp` 进行 stdio + Streamable HTTP 在 `/mcp`)
- **对话式预约**(预约页面 + 嵌入式小部件上的“通过聊天预约”;自带 LLM,默认为关闭)
- **付费预约** - Stripe Checkout(支付后预约:时间段被保留,确认付款 Webhook,自动退款取消)
- **Zoom** - 按主机 OAuth;预订位置的 Zoom 会议在分配的主机帐户下创建
- **内置视频会议(LiveKit)** - 浏览器中的会议室作为预订位置(无需应用或帐户即可供访客使用);主机控制(静音,结束所有人,移交 **和重新获得** 主持人, attendee 屏幕共享切换)和 **会议录制** 直接到您自己的备份存储桶中,可在应用内下载。 自带 LiveKit 端点(云或自托管);在设置 → 视频中配置。
- 可嵌入的预约小部件(Shadow-DOM Web 组件;内联 + 弹出)
- 成员,角色(所有者/管理员/成员),电子令牌邀请
- 预订创建时的 `Idempotency-Key`;事务性重复预订防护
- 静止时信封加密(密钥与 KEK 密封;恢复转储)
- 可选分析:`<head>` 代码注入 + `window.dataLayer` 事件(GTM/GA4)
**路线图上**
- Apple / CalDAV 日历 · 神奇链接身份验证 · OpenAPI 规范 · 多域名(一个实例,多个主机名)
---
## 技术栈
- **后端:** Go 1.26 · 纯 Go SQLite (`modernc.org/sqlite`,CGO-free → 静态二进制文件) · `goose` 迁移
- **管理 UI:** SvelteKit 2 / Svelte 5 · Vite 8 · Tailwind 4 · shadcn-svelte(通过 `go:embed` 嵌入编译时)
- **公共页面:** 服务器渲染的 Go `html/template` + 普通 JS(无框架运行时)
- **持久性:** SQLite WAL + 可选的 Litestream 复制(S3/R2)用于备份和恢复到某一时间点
- **后台工作:** 进程内作业队列在同一 DB 上 - 提醒,Webhook 交付,日历协调。 无代理。
---
## 设计原则
几个承载负载的设计决策(完整细节请参阅设计文档):
- **数据库是真相的来源;外部日历是投影。** 预约一旦本地提交就存在;同步到 Google 是一个可重试的副作用。
- **时间 = UTC 瞬间 + IANA 时区名称**,而非固定偏移量 - 可用性解析为每日 UTC,因此 DST 转换永远不会破坏时间段。
- **单个进程,无外部服务。** 耐用性来自 Litestream,而非第二个数据存储。
- **按租户隔离。** 每个安装是一个工作区;隔离是一项功能,自托管和云路径相同。
---
## 商业支持
自托管永久免费 - `docker run` 它,您拥有整个系统。 如果您不想自己运行, **[Orchestratr](https://calnode.com/services)** - Calnode 背后的团队 - 将为您部署和操作:
- **在您的基础设施上进行生产部署** - VPC,私有云或裸金属
- **SSO** (SAML / OIDC)与 Okta,Entra ID 或 Google Workspace 集成
- **日历,Zoom 和 CRM 集成**,连接到您的现有堆栈
- **从 Calendly / cal.com 迁移**,以及批量用户和团队配置
- **培训和持续支持**,适用于您的运维和 IT 团队
为受监管和中大型组织而建,需要 Calnode 在其自己的基础设施上,完全集成。 → **[calnode.com/services](https://calnode.com/services)**
---
## 许可证
[Apache-2.0](LICENSE)。 完整的调度器可自行托管,之前免费的功能永远不会被付费墙限制。
**代码** 是 Apache-2.0; **"Calnode" 名称和徽标** 不是 - 请参阅 [TRADEMARK.md](TRADEMARK.md)(免费使用代码;请为您的 fork 取一个不同的名称)。 在 [CLA](CLA.md) 下接受贡献,以便项目可以支持每一行并保持其未来的许可选项 - 请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。