🍋 Cyime —— 青柠写 轻快写作,随云流动,支持多方案图片上传的云文档
当前推荐的部署方式是前后端分离:
packages/web 单独部署到 Cloudflare Pages 或 EdgeOne Pages,保留 SvelteKit SSR。packages/server 与 packages/realtime 独立部署,适合后续统一放进 Docker Compose。当前已支持以下前端 SSR 目标:
前端部署时只需要导入当前仓库,并将项目根目录设置为 packages/web。
最小必填环境变量:
PUBLIC_API_BASE_URL=https://你的后端域名这是前端访问 Go API 的基础地址,前端所有 /api/v1/... 请求都会拼接到这个 origin。生产部署时必须填写浏览器可访问的后端公网地址,不要填容器内网地址或仅服务器本机可访问的地址。
可选公开环境变量:
PUBLIC_AVATAR_MAX_BYTES=2097152PUBLIC_AVATAR_OUTPUT_SIZE=512服务端媒体相关环境变量里,文档图片上传上限可通过 MEDIA_DOCUMENT_IMAGE_MAX_BYTES 配置;当前默认值为 5242880(5MB)。
常用构建命令:
pnpm install --frozen-lockfile && pnpm run buildpnpm install --frozen-lockfile --config.node-linker=hoistedpnpm run build:edgeoneCloudflare Pages 构建如果涉及 Node 内建模块兼容,仓库内已经提供 packages/web/wrangler.toml,默认启用 nodejs_compat,并且 pnpm run build 会自动识别 CF_PAGES=1 切到 Cloudflare 构建。
这些 PUBLIC_* 变量统一按运行时公开变量处理,适合在 Pages / EdgeOne 的项目环境变量里配置。
更完整的平台配置说明请参阅 Web 部署说明。
前后端分离部署时,需要同时配置浏览器访问链路、后端跨域白名单和登录回调地址:
packages/web:PUBLIC_API_BASE_URL=https://你的后端域名packages/server:CORS_ALLOWED_ORIGINS=https://你的前端域名packages/server:FRONTEND_CALLBACK_URL=https://你的前端域名/auth/callbackpackages/server:PUBLIC_BASE_URL=https://你的前端域名packages/server:API_BASE_URL=https://你的后端域名这些地址分别解决“前端请求后端”“后端允许前端跨域请求”“登录后回到前端”“Skill OAuth 未登录时跳到前端登录页”“后端生成自己的公网 URL”。如果使用 AI 融合能力里的 Markdown 转换服务,还需要额外配置后端到前端的内部调用:
MARKDOWN_CONVERTER_URL=https://你的前端域名MARKDOWN_CONVERTER_TOKEN=同一把内部共享密钥MARKDOWN_CONVERTER_TOKEN 需要同时配置到 packages/server 与 packages/web 的运行环境,用于保护 /markdown/convert 内部路由。它不是用户中心创建的 API Token,也不应提供给 AI 客户端。
packages/server 是 Go API 服务。packages/realtime 是独立的实时协作服务。packages/realtime。实时协作总开关:
COLLABORATION_ENABLED=true|falsepackages/server 会把该值作为 collaborationEnabled 通过 /api/v1/config 下发给前端packages/realtime 会用同名变量决定是否接受 websocket、presence 和强制持久化请求packages/server/.env 和 packages/realtime/.env 中设置为 falsepackages/web/.env 中的 PUBLIC_COLLABORATION_ENABLED=falsePUBLIC_COLLABORATION_ENABLED && 后端下发的 collaborationEnabled.env.examplepackages/realtimepackages/server/.env 设 COLLABORATION_ENABLED=falsepackages/web/.env 设 PUBLIC_COLLABORATION_ENABLED=falseCyime 提供面向 AI 客户端和外部工具的工作区集成能力:
https://你的前端域名/skill.mdhttps://你的前端域名/manifest.jsonhttps://你的前端域名/openapi.jsonhttps://你的后端域名/api/v1/mcphttps://你的后端域名/api/v1/open推荐优先使用 MCP;当客户端不支持 MCP 时,再使用 REST Open API。MCP 当前通过 HTTP JSON-RPC 暴露,客户端应以 POST /api/v1/mcp 调用。
用户中心可以创建 Cyime API Token,用于支持 HTTP MCP 的客户端、脚本或其他外部工具访问 MCP/Open API。这个 token 与站点登录会话无关,应按需要授予最小权限。
支持浏览器 OAuth 的 Skill 客户端可以先打开授权地址完成 Cyime 登录,再用授权码换取 scoped API Token:
https://你的后端域名/api/v1/auth/skill/oauth/authorizehttps://你的后端域名/api/v1/auth/skill/oauth/token用户登录后会先看到 Cyime 前端渲染的授权确认页,页面会列出请求客户端、回调地址、权限范围和 token 有效期。只有用户点击授权后,后端才会生成 authorization code。Token 响应中的 access_token 就是后续请求使用的 Cyime API Token,应只保存在客户端 secret store 中。
启用 Skill OAuth 时请确认服务端配置:
PUBLIC_BASE_URL=https://你的前端域名:未登录用户会先跳到 ${PUBLIC_BASE_URL}/login。API_BASE_URL=https://你的后端域名:后端生成 OAuth 授权 URL、OIDC 回调和 return_to 时使用。CYIME_SKILL_OAUTH_REDIRECT_URIS=...:生产 HTTPS 回调地址 allowlist。多个地址用英文逗号分隔;本地 loopback(localhost / 127.0.0.1)和 custom scheme 默认允许。常用权限范围:
workspace:read:读取文件/文件夹列表和搜索结果。workspace:write:创建文件夹、重命名、创建文档所需的工作区写权限。document:read:读取文档 Markdown 内容。document:write:创建或更新文档 Markdown 内容。file:move:移动文件或文件夹。file:copy:复制文件或文件夹。file:delete:移动文件或文件夹到回收站。该权限具有破坏性,应仅在明确需要时开启。不同 MCP 客户端会用不同配置形态包裹同一个 Cyime MCP endpoint。常见的两类是:
mcpServers 按名称管理多个 MCP server。streamable_http MCP transport。两者使用同一个 URL 和 bearer token。
{
"mcpServers": {
"cyime-workspace": {
"type": "http",
"url": "https://你的后端域名/api/v1/mcp",
"headers": {
"Authorization": "Bearer <CYIME_API_TOKEN>"
}
}
}
}
{
"transport": "streamable_http",
"url": "https://你的后端域名/api/v1/mcp",
"headers": {
"Authorization": "Bearer <CYIME_API_TOKEN>"
},
"timeout": 5,
"sse_read_timeout": 300
}
不要把真实 API Token 写进仓库、README、issue、日志或公开提示词。前端用户中心会在本地剪贴板生成配置模板;测试完成后可以吊销 token。
支持 Skill 的客户端可以导入前端暴露的 skill.md:
https://你的前端域名/skill.md
Skill 会声明 MCP 优先、REST Open API 兜底,并优先通过浏览器 OAuth 获取 API Token;不支持 OAuth 的客户端仍可把 API Token 配置为 CYIME_API_TOKEN 这类 secret 变量。不要把 token 明文写入 skill.md、manifest.json、openapi.json 或聊天消息。
MCP 当前包含 cyime_search_files、cyime_list_files、创建/读取/更新/增量更新 Markdown 文档、重命名、移动、复制和软删除工具。tools/list 会返回 readOnlyHint、destructiveHint 等 MCP annotations,方便客户端区分只读工具和需要确认的破坏性工具。
MCP/Open API 读写文档时对外使用 Markdown,内部存储使用 Tiptap JSON。为了让 AI 写入 Markdown 和前端编辑器粘贴 Markdown 的行为一致,推荐让 Go 后端调用 packages/web 提供的内部转换服务:
POST /markdown/convertMARKDOWN_CONVERTER_TOKEN 做内部共享密钥后端可以只配置 web origin,服务端会自动补 /markdown/convert:
MARKDOWN_CONVERTER_URL=https://你的前端域名
MARKDOWN_CONVERTER_TOKEN=
MARKDOWN_CONVERTER_TIMEOUT=5s
MARKDOWN_CONVERTER_FALLBACK=false
MARKDOWN_CONVERTER_TOKEN 由部署者自行生成并分别配置到 packages/server 和 packages/web 的运行环境中。它不是用户中心创建的 cyime_sk_... API Token,也不能给 AI 客户端使用。
默认情况下,Go 后端必须通过 Web 前端转换器完成 Markdown 与编辑器 JSON 的互转。即使未配置 MARKDOWN_CONVERTER_URL 或 MARKDOWN_CONVERTER_TOKEN,也不会自动回退到 Go 内置简化转换器;MCP/Open API Markdown 读写会失败,写入失败时会明确提示文档未更改。只有显式设置 MARKDOWN_CONVERTER_FALLBACK=true 时,才允许绕过前端转换器并使用 Go legacy fallback。
本地生成内部转换 token 的示例:
openssl rand -hex 32
本地验证转换服务时,先在前端进程和测试 shell 中配置同一个 MARKDOWN_CONVERTER_TOKEN,然后请求:
curl -sS http://127.0.0.1:5173/markdown/convert \
-H "Authorization: Bearer ${MARKDOWN_CONVERTER_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"direction":"markdown-to-json","markdown":"# Hello\n\n- one\n- two"}'
如果转换服务不可用、未配置或返回无效结果,且 MARKDOWN_CONVERTER_FALLBACK=false,MCP/Open API Markdown 读写会失败,写入失败时会明确提示文档未更改;只有显式设置 MARKDOWN_CONVERTER_FALLBACK=true 时才会回退到 Go 内置的简化 Markdown 转换器。
关于仓库迁移、提交历史整理以及部署仓库说明,请参阅:
以下是本项目核心功能(特别是认证系统)相关的主要文件架构。
/packages/server)cmd/server/main.go: 应用入口。负责注册所有 API 路由并应用中间件。internal/auth/handler.go: 认证处理器。处理 /login, /callback, /refresh 等路由的主逻辑。internal/auth/token.go: 令牌服务核心。封装了所有关于令牌的创建、持久化和刷新逻辑。internal/middleware/auth.go: JWT 认证中间件。提供 Protected() 中间件来保护需要认证的接口。internal/user/handler.go: 用户处理器。处理与用户数据相关的请求 (/user/me)。internal/database/database.go: 数据库。初始化 GORM 连接并执行自动迁移。internal/models/*.go: 数据库模型。定义了 users, auth_providers 等数据表结构。/packages/web)src/lib/stores/auth.ts: 前端认证的大脑。通过 Svelte Store 集中管理认证状态和所有刷新逻辑。src/lib/api.ts: API 请求工具。导出的 apiFetch 函数封装了原生 fetch,自动处理认证头和 401 错误重试。src/routes/auth/callback/+page.svelte: 登录回调页。处理从第三方登录成功后的跳转。src/routes/workspace/+layout.svelte: 工作区路由守卫。保护 /workspace 目录下的所有页面。环境准备:
pnpm,建议使用 22+。启动后端服务:
# 进入后端目录
cd packages/server
# 对数据服务进行初始化操作,并注入 Oauth 服务以便接下来的操作
ENV=DEVELOPMENT go run ./cmd/init/main.go
# 运行后端
ENV=DEVELOPMENT go run ./cmd/server/main.go
后端服务将运行在 http://localhost:8080。
说明:后端启动会自动读取 packages/server/.env。
启动前端服务:
# 进入前端目录
cd packages/web
# 安装依赖
pnpm install
# 运行前端开发服务器
pnpm run dev
前端服务将运行在 http://localhost:5173。
完整示例见根目录 .env.example。下面只列当前最常用的配置项。
认证与会话
JWT_SECRET_KEY:JWT 与部分签名逻辑依赖的密钥,生产环境必须配置。ACCESS_TOKEN_LIFETIME_MINUTES:Access Token 生命周期,默认 15。ACCESS_TOKEN_LIFETIME_SECONDS:Access Token 秒级生命周期覆盖项,优先级高于分钟配置,主要用于本地刷新链路测试。REFRESH_TOKEN_LIFETIME_HOURS:Refresh Token 生命周期,默认 720(30 天)。FRONTEND_CALLBACK_URL:登录成功后回跳到前端的地址。PUBLIC_BASE_URL:对外可访问的前端基础地址。Skill OAuth 未登录时会跳到 ${PUBLIC_BASE_URL}/login。API_BASE_URL / PUBLIC_API_BASE_URL:对外可访问的后端基础地址。用于生成登录入口、OIDC 回调和 Skill OAuth return_to。CYIME_SKILL_OAUTH_REDIRECT_URIS:Skill OAuth 生产 HTTPS 回调地址 allowlist,多个地址用英文逗号分隔。本地 loopback 与 custom scheme 默认允许。文档数量限制
DEFAULT_DOCUMENT_QUOTA:全局默认文档上限。document_quota,会优先使用用户自己的值。实时协作开关
COLLABORATION_ENABLED:是否启用实时协作,默认 truepackages/server/.env 与 packages/realtime/.env 保持一致/api/v1/config 下发的 collaborationEnabledPUBLIC_COLLABORATION_ENABLED,默认 true.env.exampleSkill / MCP Markdown 转换
MARKDOWN_CONVERTER_URL:内部 Markdown 转换服务地址。默认必需;可填写前端 origin,例如 https://你的前端域名,Go 后端会自动补 /markdown/convert。MARKDOWN_CONVERTER_TOKEN:Go 后端与 Web 内部转换服务之间的共享密钥。默认必需,需要同时配置到 packages/server 与 packages/web 的运行环境,不要写入仓库。MARKDOWN_CONVERTER_TIMEOUT:Go 后端调用转换服务的超时时间,默认 5s。MARKDOWN_CONVERTER_FALLBACK:转换服务未配置或失败时是否回退到 Go 内置简化转换器,默认 false。保持 false 时,写入失败会明确提示文档未更改。MARKDOWN_CONVERTER_MAX_BYTES:Web 内部转换路由接受的最大请求体字节数,默认 2097152。媒体与图床
MEDIA_STORAGE_PROVIDER:可选 local | r2 | s3 | cos,默认 local。MEDIA_TOKEN_SECRET:私有媒体短期签名密钥;留空时回退到 JWT_SECRET_KEY。MEDIA_SIGN_TTL_SECONDS:私有媒体签名有效期,默认 120 秒。MEDIA_AVATAR_SIGN_TTL_SECONDS:私有头像签名有效期,默认 300 秒。MEDIA_AVATAR_MAX_BYTES:头像上传大小限制,默认 2MB。本地媒体存储
MEDIA_LOCAL_ROOT_DIR:本地文件落盘目录。MEDIA_LOCAL_BASE_URL:本地媒体对外访问前缀。S3 / R2 / COS 兼容存储
MEDIA_S3_ENDPOINTMEDIA_S3_BUCKETMEDIA_S3_REGIONMEDIA_S3_ACCESS_KEY_IDMEDIA_S3_SECRET_ACCESS_KEYMEDIA_S3_PUBLIC_BASE_URLR2_ENDPOINT、R2_BUCKET、R2_REGION、R2_ACCESS_KEY_ID、R2_SECRET_ACCESS_KEY、R2_PUBLIC_BASE_URL媒体 GC / 引用回收
MEDIA_ASSET_GC_ENABLEDMEDIA_ASSET_GC_INTERVALMEDIA_ASSET_GC_BATCH_SIZEMEDIA_ASSET_GC_MAX_ATTEMPTSMEDIA_ASSET_GC_RETRY_GAPMEDIA_ASSET_RECONCILE_ENABLEDMEDIA_ASSET_RECONCILE_BATCH_SIZE其他
CORS_ALLOWED_ORIGINS:允许的前端来源,多个值用英文逗号分隔。RESET_WORKSPACE_TABLES_ON_BOOT:启动时重置业务表,仅调试时使用。