{"openapi":"3.1.0","info":{"title":"tooo API","version":"1.0.0","description":"tooo 的后端。原生端的读写走 POST /api/sync(行的列见 packages/sync-spec/sync-schema.json,mutation 参数见 mutations.schema.json),配对、设备、活动上传和统计类读取走这里的 REST。由 services/backend/src/openapi.ts 生成,不要手改。"},"servers":[{"url":"{origin}","description":"tooo 服务器","variables":{"origin":{"default":"http://localhost:6060"}}}],"security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"tags":[{"name":"meta"},{"name":"identity"},{"name":"oauth"},{"name":"sync"},{"name":"mcp"},{"name":"activity"},{"name":"tasks"},{"name":"timing"},{"name":"settings"},{"name":"contexts"},{"name":"review"},{"name":"reminders"},{"name":"server"}],"paths":{"/api/health":{"get":{"operationId":"getHealth","tags":["meta"],"summary":"健康检查","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"const":"ok","type":"string"},"service":{"type":"string"},"version":{"type":"string"},"time":{"type":"string","format":"date-time"}},"required":["status","service","version","time"]}}}}}}},"/api/openapi.json":{"get":{"operationId":"getOpenapiJson","tags":["meta"],"summary":"这份接口描述","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"OpenAPI 3.1 文档"}}}}}}},"/api/auth/login":{"post":{"operationId":"postAuthLogin","tags":["identity"],"summary":"老的共用密码登录(写 cadence_session cookie)","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"password":{"type":"string"}},"required":["password"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"type":"boolean"},"required":{"const":false,"type":"boolean"}},"required":["ok"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"太频繁","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/auth/me":{"get":{"operationId":"getAuthMe","tags":["identity"],"summary":"当前请求认出的空间和设备","description":"signupMode:新建空间的方式(TODAY_SIGNUP),open 直接建、invite 要带邀请码(入口页多一个邀请码输入框)、closed 不能建,只能配对。signup 是老字段,只在 open 时为 true。admin:登录的是管理员空间(能发邀请码)。","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"authed":{"type":"boolean"},"required":{"type":"boolean"},"ownerId":{"type":"string"},"admin":{"type":"boolean"},"device":{"$ref":"#/components/schemas/Device"},"legacyPassword":{"type":"boolean"},"signup":{"type":"boolean"},"signupMode":{"type":"string","enum":["open","invite","closed"]}},"required":["authed","required","legacyPassword","signup","signupMode"]}}}}}}},"/api/auth/logout":{"post":{"operationId":"postAuthLogout","tags":["identity"],"summary":"退出:吊销当前设备并清 cookie","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/space/create":{"post":{"operationId":"postSpaceCreate","tags":["identity"],"summary":"新建空间和第一台设备","description":"client=native 时令牌在响应体 token 里,之后带 Authorization: Bearer;client=web 时写 httpOnly cookie,不给 token。恢复码只显示这一次。只收 application/json。signupMode=invite 时要带 inviteCode(管理员发的邀请码,不分大小写,空格和横线忽略;一张只能用一次):没带回 400(code invite_required),不对、用过、撤销或过期回 403(code invite_invalid),用错太多次 429。signupMode=closed 时 403。timezone 是这台设备的 IANA 时区(如 America/New_York),成为新空间的时区(到点提醒、「今天」按它算);认不出的当作没给。","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client":{"type":"string","enum":["web","native"]},"name":{"type":"string"},"platform":{"type":"string"},"inviteCode":{"type":"string","maxLength":64,"description":"邀请码,10 位"},"timezone":{"type":"string","maxLength":64,"description":"IANA 时区名"}},"required":["client"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"device":{"$ref":"#/components/schemas/Device"},"recoveryCodes":{"type":"array","items":{"type":"string"}},"token":{"type":"string"}},"required":["device","recoveryCodes"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"这个凭据不能做这件事","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"只收 application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"太频繁","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/pair/request":{"post":{"operationId":"postPairRequest","tags":["identity"],"summary":"新设备发起配对:拿到 6 位授权码和轮询口令","description":"timezone 是这台设备的 IANA 时区:配对成功后,如果这个空间的时区还没人定过(老客户端新建的空间),就用它。","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client":{"type":"string","enum":["web","native"]},"name":{"type":"string"},"platform":{"type":"string"},"timezone":{"type":"string","maxLength":64,"description":"IANA 时区名"}},"required":["client"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"requestId":{"type":"string"},"code":{"type":"string"},"pollSecret":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"}},"required":["requestId","code","pollSecret","expiresAt"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"太频繁","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/pair/poll":{"post":{"operationId":"postPairPoll","tags":["identity"],"summary":"新设备轮询配对结果","description":"approved 时 client=native 的请求在 token 里拿到设备令牌(只给这一次)。只收 application/json。","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"requestId":{"type":"string"},"pollSecret":{"type":"string"}},"required":["requestId","pollSecret"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["pending","approved","denied","expired"]},"device":{"$ref":"#/components/schemas/Device"},"token":{"type":"string"}},"required":["status"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"只收 application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"太频繁","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/recover":{"post":{"operationId":"postRecover","tags":["identity"],"summary":"用恢复码在新设备上回到空间","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"client":{"type":"string","enum":["web","native"]},"code":{"type":"string"},"name":{"type":"string"},"platform":{"type":"string"}},"required":["client","code"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"device":{"$ref":"#/components/schemas/Device"},"token":{"type":"string"}},"required":["device"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"只收 application/json","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"太频繁","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/pair/lookup":{"post":{"operationId":"postPairLookup","tags":["identity"],"summary":"已登录设备输入授权码,看是谁在请求","description":"命令行密钥和连接器回 403:只能在网页或 App 上做。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","pattern":"^\\d{6}$"}},"required":["code"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["device","agent"]},"name":{"type":"string"},"platform":{"type":"string"},"clientName":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"}},"required":["kind","name","platform","expiresAt"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"这个凭据不能做这件事","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"太频繁","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/pair/approve":{"post":{"operationId":"postPairApprove","tags":["identity"],"summary":"同意或拒绝一个配对请求","description":"命令行密钥和连接器回 403:只能在网页或 App 上做。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","pattern":"^\\d{6}$"},"approve":{"type":"boolean"}},"required":["code","approve"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"这个凭据不能做这件事","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"太频繁","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/recovery/regenerate":{"post":{"operationId":"postRecoveryRegenerate","tags":["identity"],"summary":"换一批恢复码(旧的作废)","description":"命令行密钥和连接器回 403:只能在网页或 App 上做。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"recoveryCodes":{"type":"array","items":{"type":"string"}}},"required":["recoveryCodes"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"这个凭据不能做这件事","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/devices":{"get":{"operationId":"getDevices","tags":["identity"],"summary":"这个空间的设备、密钥和连接器","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"devices":{"type":"array","items":{"$ref":"#/components/schemas/DeviceListItem"}}},"required":["devices"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/devices/rename":{"post":{"operationId":"postDevicesRename","tags":["identity"],"summary":"改设备名","description":"命令行密钥和连接器回 403:只能在网页或 App 上做。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"这个凭据不能做这件事","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/devices/revoke":{"post":{"operationId":"postDevicesRevoke","tags":["identity"],"summary":"吊销设备(连接器的 OAuth 令牌一起作废)","description":"命令行密钥和连接器回 403:只能在网页或 App 上做。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"这个凭据不能做这件事","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/devices/key":{"post":{"operationId":"postDevicesKey","tags":["identity"],"summary":"新建命令行密钥(只显示这一次)","description":"命令行密钥和连接器回 403:只能在网页或 App 上做。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"}},"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"device":{"$ref":"#/components/schemas/Device"},"token":{"type":"string"}},"required":["device","token"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"这个凭据不能做这件事","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/invites":{"get":{"operationId":"getInvites","tags":["identity"],"summary":"这台服务器发过的邀请码(管理员)","description":"新的在前,最多 200 张;不含邀请码本身。\n\n命令行密钥和连接器回 403:只能在网页或 App 上做。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"invites":{"type":"array","items":{"$ref":"#/components/schemas/Invite"}}},"required":["invites"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"这个凭据不能做这件事","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postInvites","tags":["identity"],"summary":"新建一张邀请码(管理员)","description":"code 只在这次回复里出现。expiresInDays 不给是 30 天,给 null 是不过期。\n\n命令行密钥和连接器回 403:只能在网页或 App 上做。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","maxLength":200},"expiresInDays":{"anyOf":[{"type":"integer","minimum":1,"maximum":365},{"type":"null"}]}},"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Invite"},{"type":"object","properties":{"code":{"type":"string","pattern":"^[A-HJKMNP-Z2-9]{10}$"}},"required":["code"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"这个凭据不能做这件事","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/invites/revoke":{"post":{"operationId":"postInvitesRevoke","tags":["identity"],"summary":"撤销一张还没用过的邀请码(管理员)","description":"已撤销的再撤原样返回;已经用过的回 409。\n\n命令行密钥和连接器回 403:只能在网页或 App 上做。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invite"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"这个凭据不能做这件事","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/.well-known/oauth-protected-resource":{"get":{"operationId":"getWellKnownOauthProtectedResource","tags":["oauth"],"summary":"受保护资源元数据(RFC 9728)","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"resource":{"type":"string"},"authorization_servers":{"type":"array","items":{"type":"string"}},"scopes_supported":{"type":"array","items":{"type":"string"}},"bearer_methods_supported":{"type":"array","items":{"type":"string"}},"resource_name":{"type":"string"}},"required":["resource","authorization_servers","scopes_supported","bearer_methods_supported","resource_name"]}}}}}}},"/.well-known/oauth-protected-resource/mcp":{"get":{"operationId":"getWellKnownOauthProtectedResourceMcp","tags":["oauth"],"summary":"受保护资源元数据(/mcp 后缀的位置)","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"resource":{"type":"string"},"authorization_servers":{"type":"array","items":{"type":"string"}},"scopes_supported":{"type":"array","items":{"type":"string"}},"bearer_methods_supported":{"type":"array","items":{"type":"string"}},"resource_name":{"type":"string"}},"required":["resource","authorization_servers","scopes_supported","bearer_methods_supported","resource_name"]}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"operationId":"getWellKnownOauthAuthorizationServer","tags":["oauth"],"summary":"授权服务器元数据(RFC 8414)","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["issuer","authorization_endpoint","token_endpoint"]}}}}}}},"/oauth/register":{"post":{"operationId":"postOauthRegister","tags":["oauth"],"summary":"动态注册客户端(RFC 7591)","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"redirect_uris":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10},"token_endpoint_auth_method":{"type":"string","enum":["none","client_secret_basic","client_secret_post"]},"grant_types":{"type":"array","items":{"type":"string"}},"response_types":{"type":"array","items":{"type":"string"}},"client_name":{"type":"string"},"client_uri":{"type":"string"},"logo_uri":{"type":"string"},"scope":{"type":"string"},"software_id":{"type":"string"},"software_version":{"type":"string"}},"required":["redirect_uris"]}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"client_id_issued_at":{"type":"integer"},"client_secret":{"type":"string"},"client_secret_expires_at":{"type":"integer"},"client_name":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string"}},"token_endpoint_auth_method":{"type":"string"},"grant_types":{"type":"array","items":{"type":"string"}},"response_types":{"type":"array","items":{"type":"string"}}},"required":["client_id","redirect_uris"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"429":{"description":"太频繁","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/oauth/authorize":{"get":{"operationId":"getOauthAuthorize","tags":["oauth"],"summary":"授权端点:登记请求后跳到网页的同意页","security":[],"parameters":[{"name":"client_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"redirect_uri","in":"query","required":false,"schema":{"type":"string"}},{"name":"response_type","in":"query","required":true,"schema":{"const":"code","type":"string"}},{"name":"code_challenge","in":"query","required":true,"schema":{"type":"string"},"description":"PKCE S256"},{"name":"code_challenge_method","in":"query","required":true,"schema":{"const":"S256","type":"string"}},{"name":"state","in":"query","required":false,"schema":{"type":"string"}},{"name":"resource","in":"query","required":false,"schema":{"type":"string"},"description":"必须是 <origin>/mcp"},{"name":"scope","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"302":{"description":"跳到 /#oauth=<请求 id>;参数错误时回纯文本错误页(400),不跳回客户端"},"400":{"description":"参数不合法","content":{"text/plain":{"schema":{"type":"string"}}}},"429":{"description":"太频繁","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/oauth/request":{"get":{"operationId":"getOauthRequest","tags":["oauth"],"summary":"同意页读这个授权请求","security":[{"oauthBrowser":[]}],"parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"clientName":{"type":"string"},"code":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"},"authed":{"type":"boolean"},"status":{"type":"string","enum":["pending","approved","denied","expired"]},"redirectHost":{"type":"string"}},"required":["clientName","code","expiresAt","authed","status","redirectHost"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/oauth/request/status":{"get":{"operationId":"getOauthRequestStatus","tags":["oauth"],"summary":"同意页轮询:同意后拿跳回地址","security":[{"oauthBrowser":[]}],"parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["pending","approved","denied","expired"]},"redirect":{"type":"string"}},"required":["status"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/oauth/consent":{"post":{"operationId":"postOauthConsent","tags":["oauth"],"summary":"已登录的浏览器直接同意或拒绝","security":[{"oauthBrowser":[],"deviceCookie":[]},{"oauthBrowser":[],"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"approve":{"type":"boolean"}},"required":["id","approve"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"redirect":{"type":"string"}},"required":["redirect"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/oauth/token":{"post":{"operationId":"postOauthToken","tags":["oauth"],"summary":"换令牌:授权码(PKCE)或刷新令牌","description":"客户端认证:公开客户端只带 client_id;机密客户端用 Basic 头或 client_secret。错误按 RFC 6749 §5.2。","security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","enum":["authorization_code","refresh_token"]},"code":{"type":"string"},"redirect_uri":{"type":"string"},"code_verifier":{"type":"string"},"refresh_token":{"type":"string"},"resource":{"type":"string"},"client_id":{"type":"string"},"client_secret":{"type":"string"}},"required":["grant_type"]}},"application/json":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","enum":["authorization_code","refresh_token"]},"code":{"type":"string"},"redirect_uri":{"type":"string"},"code_verifier":{"type":"string"},"refresh_token":{"type":"string"},"resource":{"type":"string"},"client_id":{"type":"string"},"client_secret":{"type":"string"}},"required":["grant_type"]}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenSet"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"429":{"description":"太频繁","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/oauth/revoke":{"post":{"operationId":"postOauthRevoke","tags":["oauth"],"summary":"吊销令牌(RFC 7009)","security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"token":{"type":"string"},"client_id":{"type":"string"},"client_secret":{"type":"string"}},"required":["token"]}},"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"client_id":{"type":"string"},"client_secret":{"type":"string"}},"required":["token"]}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"空响应"},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"429":{"description":"太频繁","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/api/sync":{"post":{"operationId":"postSync","tags":["sync"],"summary":"推 mutation、拉行增量","description":"每批最多 100 条 mutation;mutations[].args 按 name 见 packages/sync-spec/mutations.schema.json。每页最多 2000 条 patch,more=true 时立即再拉。503 时 lastMutationId 之前的已提交,稍后重发其余的。\n\n只认网页和 App 的设备凭据:没有设备(老密码、开发模式)回 400,命令行密钥回 403。","security":[{"bearer":[]},{"deviceCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncRequest"}}},"description":"上限 4194304 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncResponse"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"这个凭据不能做这件事","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"暂时不可用,稍后重试","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncUnavailable"}}}}}}},"/api/sync/events":{"get":{"operationId":"getSyncEvents","tags":["sync"],"summary":"SSE:这个空间有写入就推一个 poke","description":"event: hello / poke,data: {\"v\": <owners.version 或 null>};每 25 秒一行注释 `: ping`。收到 poke 调一次 POST /api/sync。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"text/event-stream":{"schema":{"type":"string"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"暂时不可用,稍后重试","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/mcp":{"post":{"operationId":"postMcp","tags":["mcp"],"summary":"MCP Streamable HTTP(无状态子集)","description":"JSON-RPC 2.0,一条或一批;全是通知时回 202 无正文。工具列表用 tools/list 取(每个工具带 title 和 annotations)。协议版本认 2025-11-25、2025-06-18、2025-03-26、2024-11-05:请求头 MCP-Protocol-Version 没带按 2025-03-26;带了不认的版本,或是 2026-07-28 新一代的请求(server/discover、params._meta 里带新版本号),回 400 和 JSON-RPC -32600,新一代客户端据此退回 initialize。401 时 WWW-Authenticate 指向 /.well-known/oauth-protected-resource/mcp。","security":[{"oauth2":["today"]},{"bearer":[]},{"cadenceKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/JsonRpcRequest"},{"type":"array","items":{"$ref":"#/components/schemas/JsonRpcRequest"}}]}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/JsonRpcResponse"},{"type":"array","items":{"$ref":"#/components/schemas/JsonRpcResponse"}}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"getMcp","tags":["mcp"],"summary":"不提供 SSE 流","security":[{"oauth2":["today"]},{"bearer":[]},{"cadenceKey":[]}],"responses":{"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Method Not Allowed"}}},"delete":{"operationId":"deleteMcp","tags":["mcp"],"summary":"没有会话可删","security":[{"oauth2":["today"]},{"bearer":[]},{"cadenceKey":[]}],"responses":{"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"405":{"description":"Method Not Allowed"}}}},"/api/activity/upload":{"post":{"operationId":"postActivityUpload","tags":["activity"],"summary":"上传这台设备某一天各 App 的用时(整体覆盖)","description":"同一台设备同一天重复上传结果不变;这次没有的 App 会被删掉,不给 intervals 等于这一天没有区间。请求体上限 2097152 字节。要有设备:App 用设备令牌,电脑上的记录脚本用命令行密钥。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityUploadInput"}}},"description":"上限 2097152 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityUploadResult"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/activity":{"get":{"operationId":"getActivity","tags":["activity"],"summary":"某天各设备的用时、合并排行(老的 ManicTime 数据并在里面)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"parameters":[{"name":"date","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"description":"默认今天"},{"name":"intervals","in":"query","required":false,"schema":{"type":"string","enum":["1","true"]},"description":"带上时间线的前台区间"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityDay"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/usage/daily":{"post":{"operationId":"postUsageDaily","tags":["activity"],"summary":"老的 ManicTime 上传:电脑某天各软件用时(覆盖写入)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"day":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"activeSeconds":{"type":"integer","minimum":0},"apps":{"type":"array","items":{"type":"object","properties":{"app":{"type":"string","minLength":1,"maxLength":200},"seconds":{"type":"integer","minimum":0}},"required":["app","seconds"],"additionalProperties":false},"maxItems":500},"source":{"type":"string","maxLength":50,"default":"manictime"}},"required":["day","activeSeconds","apps"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"type":"boolean"},"apps":{"type":"integer"}},"required":["ok","apps"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/capture":{"post":{"operationId":"postCapture","tags":["tasks"],"summary":"记下一条(进收件箱,或带日期直接排进日程)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string","minLength":1,"maxLength":500},"scheduledDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"pomodoros":{"anyOf":[{"type":"integer","minimum":1,"maximum":8},{"type":"null"}]},"contextIds":{"type":"array","items":{"type":"string","maxLength":200},"maxItems":50},"recurrence":{"anyOf":[{"type":"object","properties":{"freq":{"type":"string","enum":["daily","weekly"]},"byday":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}},"mode":{"const":"fixed","type":"string","default":"fixed"}},"required":["freq"],"additionalProperties":false},{"type":"null"}]}},"required":["text"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdResult"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/list":{"get":{"operationId":"getList","tags":["tasks"],"summary":"按视图列任务","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"parameters":[{"name":"horizon","in":"query","required":false,"schema":{"type":"string","enum":["today","week","month","inbox","action","waiting","reference","note","all","undated","overdue"]},"description":"默认 inbox"},{"name":"anchor","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"description":"today/week/month 的锚定日"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"horizon":{"type":"string"},"anchor":{"anyOf":[{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},{"type":"null"}]},"count":{"type":"integer"},"items":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/list.ts"}}},"required":["horizon","anchor","count","items"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/clarify":{"post":{"operationId":"postClarify","tags":["tasks"],"summary":"理清一条收件箱","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"choice":{"type":"string","enum":["action","reference","trash"]},"status":{"type":"string","enum":["pending","in_progress"]},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]},"contextIds":{"type":"array","items":{"type":"string","maxLength":200},"maxItems":50},"pomodoros":{"anyOf":[{"type":"integer","minimum":1,"maximum":8},{"type":"null"}]},"priority":{"anyOf":[{"type":"string","enum":["important_urgent","important_not_urgent","urgent_not_important","not_important_not_urgent"]},{"type":"null"}]},"scheduledDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"intention":{"anyOf":[{"type":"object","properties":{"cueKind":{"type":"string","enum":["after_event","after_task","at_location","time_window"]},"cueText":{"type":"string","maxLength":500},"afterTaskId":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null},"rehearsedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null}},"required":["cueKind","cueText"],"additionalProperties":false},{"type":"null"}]}},"required":["id","choice"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/clarify.ts"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/complete":{"post":{"operationId":"postComplete","tags":["tasks"],"summary":"完成(连同步骤树,结束计时)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Ok"},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks/get":{"get":{"operationId":"getTasksGet","tags":["tasks"],"summary":"一条任务的详情","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/tasks.ts (TaskDetail)"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks/note":{"post":{"operationId":"postTasksNote","tags":["tasks"],"summary":"改备注(HTML)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"note":{"type":"string","maxLength":50000}},"required":["id","note"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/tasks.ts (updateTaskNote)"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks/update":{"post":{"operationId":"postTasksUpdate","tags":["tasks"],"summary":"改任务的任意属性","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string","minLength":1,"maxLength":500},"status":{"type":"string","enum":["inbox","pending","in_progress","done","dropped"]},"clarify":{"anyOf":[{"type":"string","enum":["action","reference","note","trash"]},{"type":"null"}]},"priority":{"anyOf":[{"type":"string","enum":["important_urgent","important_not_urgent","urgent_not_important","not_important_not_urgent"]},{"type":"null"}]},"pomodoros":{"anyOf":[{"type":"integer","minimum":1,"maximum":8},{"type":"null"}]},"projectId":{"anyOf":[{"type":"string"},{"type":"null"}]},"contextIds":{"type":"array","items":{"type":"string","maxLength":200},"maxItems":50},"scheduledDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"dueDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"deferDate":{"anyOf":[{"type":"string"},{"type":"null"}]},"delegatedTo":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"category":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"note":{"type":"string","maxLength":50000},"intention":{"anyOf":[{"type":"object","properties":{"cueKind":{"type":"string","enum":["after_event","after_task","at_location","time_window"]},"cueText":{"type":"string","maxLength":500},"afterTaskId":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"default":null},"rehearsedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null}},"required":["cueKind","cueText"],"additionalProperties":false},{"type":"null"}]},"scheduledTime":{"anyOf":[{"type":"string","pattern":"^\\d{2}:\\d{2}$"},{"type":"null"}]},"flagged":{"type":"boolean"},"rank":{"type":"string","maxLength":40},"remind":{"type":"boolean"},"remindBefore":{"type":"integer","minimum":0,"maximum":1440},"remindAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"remindOffsetMin":{"anyOf":[{"type":"integer","minimum":-10080,"maximum":1440},{"type":"null"}]},"rest":{"type":"boolean"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks/steps/add":{"post":{"operationId":"postTasksStepsAdd","tags":["tasks"],"summary":"加一步(加在最后)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"parentId":{"type":"string"},"title":{"type":"string","minLength":1,"maxLength":500}},"required":["parentId","title"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdResult"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks/delete":{"post":{"operationId":"postTasksDelete","tags":["tasks"],"summary":"删除(软删,连同步骤)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/steps.ts (deleteTask)"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks/restore":{"post":{"operationId":"postTasksRestore","tags":["tasks"],"summary":"撤销删除","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/steps.ts (restoreTask)"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks/repeat":{"post":{"operationId":"postTasksRepeat","tags":["tasks"],"summary":"设重复、改规则或停掉","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"recurrence":{"anyOf":[{"type":"object","properties":{"freq":{"type":"string","enum":["daily","weekly"]},"byday":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}}},"required":["freq"],"additionalProperties":false},{"type":"null"}]},"templateId":{"type":"string","format":"uuid"}},"required":["id","recurrence"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/recurring.ts (setRepeat)"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/order":{"post":{"operationId":"postOrder","tags":["tasks"],"summary":"手动排顺序(一天的列表或某个任务的步骤)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"scope":{"const":"day","type":"string"},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":500}},"required":["scope","date","ids"],"additionalProperties":false},{"type":"object","properties":{"scope":{"const":"steps","type":"string"},"parentId":{"type":"string"},"ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":500}},"required":["scope","parentId","ids"],"additionalProperties":false}]}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/order.ts"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/reschedule":{"post":{"operationId":"postReschedule","tags":["tasks"],"summary":"排到日历上","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"date":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","date"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/extras.ts (reschedule)"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/recurring":{"get":{"operationId":"getRecurring","tags":["tasks"],"summary":"重复规则列表","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/recurring.ts (listRecurring)"}}},"required":["items"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/recurring/delete":{"post":{"operationId":"postRecurringDelete","tags":["tasks"],"summary":"停止重复(删规则)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/recurring.ts (deleteRecurring)"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/recurring/restore":{"post":{"operationId":"postRecurringRestore","tags":["tasks"],"summary":"撤销停止重复","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/recurring.ts (restoreRecurring)"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/focus/start":{"post":{"operationId":"postFocusStart","tags":["timing"],"summary":"开始一个番茄 / 正计时会话","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"taskId":{"type":"string","minLength":1},"mode":{"type":"string","enum":["pomodoro","stopwatch"]},"plannedPomodoros":{"type":"integer","exclusiveMinimum":0},"workSeconds":{"type":"integer","exclusiveMinimum":0},"breakSeconds":{"type":"integer","exclusiveMinimum":0}},"required":["taskId","mode"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FocusSession"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/focus/pause":{"post":{"operationId":"postFocusPause","tags":["timing"],"summary":"暂停会话","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","minLength":1}},"required":["sessionId"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/FocusSession"},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/focus/resume":{"post":{"operationId":"postFocusResume","tags":["timing"],"summary":"继续会话","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","minLength":1}},"required":["sessionId"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/FocusSession"},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/focus/advance":{"post":{"operationId":"postFocusAdvance","tags":["timing"],"summary":"老客户端的番茄推进","description":"只为 0.4 的老客户端保留:到点自动发的不推进;休息阶段早于目标 2 秒以上(跳过休息)或暂停着时只结束休息,不开始下一颗。新客户端用 /api/focus/rest 和 /api/focus/end-break。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","minLength":1},"from":{"type":"object","properties":{"phase":{"type":"string","enum":["work","break"]},"phaseIndex":{"type":"integer"}},"required":["phase","phaseIndex"],"additionalProperties":false}},"required":["sessionId"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/FocusSession"},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/focus/rest":{"post":{"operationId":"postFocusRest","tags":["timing"],"summary":"番茄从工作进入休息","description":"工作在这一刻结束(过了目标的部分照样记在任务上),休息开始。已在这一颗的休息里时不变;番茄已经到了别的阶段、会话不在走时 409。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","minLength":1},"from":{"type":"object","properties":{"phaseIndex":{"type":"integer","minimum":1}},"required":["phaseIndex"],"additionalProperties":false}},"required":["sessionId","from"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/FocusSession"},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/focus/end-break":{"post":{"operationId":"postFocusEndBreak","tags":["timing"],"summary":"结束休息(不开始下一颗)","description":"变成暂停着的下一颗;已经是下一颗的「没开始」时不变;番茄已经到了别的阶段时 409。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","minLength":1},"from":{"type":"object","properties":{"phaseIndex":{"type":"integer","minimum":1}},"required":["phaseIndex"],"additionalProperties":false}},"required":["sessionId","from"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/FocusSession"},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/rest/start":{"post":{"operationId":"postRestStart","tags":["timing"],"summary":"开始休息计时(不挂任务)","description":"番茄完成后的「休息 N 分钟?」〔开始休息〕、正计时和步骤菜单里的「休息」用它;番茄工作阶段的休息仍用 /api/focus/rest。默认切换:前台那件暂停(前台是补位上来的则回到后台接着走)。往上数,到目标(seconds,不给 = 设置里的休息时长)只提醒一次;点结束休息或开始别的事时结束。已经在休息时不变。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"seconds":{"type":"integer","minimum":60,"maximum":7200}},"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"entryId":{"type":"string"},"since":{"type":"string","format":"date-time"},"targetSeconds":{"type":"integer"},"endsAt":{"type":"string","format":"date-time"}},"required":["entryId","since","targetSeconds","endsAt"]},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/rest/end":{"post":{"operationId":"postRestEnd","tags":["timing"],"summary":"结束休息计时","description":"只结束休息,被它暂停的那件不自动接着(前台空出来时后台最近的那件补位)。没在休息时什么都不做(ended=false)。seconds 是这一轮休息了多少秒。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"ended":{"type":"boolean"},"seconds":{"type":"integer"}},"required":["ended","seconds"]},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/rest/cancel":{"post":{"operationId":"postRestCancel","tags":["timing"],"summary":"撤销开始休息","description":"同 /api/tasks/cancel:这段休息不记,被它暂停的那件接着走(中间那段算回给它),被它转到后台的补位那件回到前台。没在休息时 409。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"restored":{"type":"boolean"}},"required":["restored"]},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/focus/switch-mode":{"post":{"operationId":"postFocusSwitchMode","tags":["timing"],"summary":"番茄和正计时互换","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","minLength":1},"mode":{"type":"string","enum":["pomodoro","stopwatch"]}},"required":["sessionId","mode"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FocusSession"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/focus/complete":{"post":{"operationId":"postFocusComplete","tags":["timing"],"summary":"结束会话并完成任务","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"taskId":{"type":"string","minLength":1}},"required":["taskId"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"ok":{"const":true,"type":"boolean"},"taskTotalSeconds":{"type":"integer"}},"required":["ok","taskTotalSeconds"]},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/focus/stop":{"post":{"operationId":"postFocusStop","tags":["timing"],"summary":"结束会话(任务留着)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","minLength":1},"toStatus":{"type":"string","enum":["pending","in_progress","done","dropped"]}},"required":["sessionId"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/FocusSession"},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/focus/current":{"get":{"operationId":"getFocusCurrent","tags":["timing"],"summary":"所有没结束的会话;active 是前台的会话","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"sessions":{"type":"array","items":{"$ref":"#/components/schemas/FocusSession"}},"active":{"anyOf":[{"$ref":"#/components/schemas/FocusSession"},{"type":"null"}]}},"required":["sessions","active"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/focus/active":{"get":{"operationId":"getFocusActive","tags":["timing"],"summary":"桌面用的聚合视图","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/focus-types.ts (ActiveFocus)"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/focus/totals":{"get":{"operationId":"getFocusTotals","tags":["timing"],"summary":"几件事各自的累计秒数","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"parameters":[{"name":"taskIds","in":"query","required":false,"schema":{"type":"string"},"description":"逗号分隔"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"totals":{"type":"object","additionalProperties":{"type":"integer"}}},"required":["totals"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/now":{"get":{"operationId":"getNow","tags":["timing"],"summary":"现在在计什么","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Now"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks/start":{"post":{"operationId":"postTasksStart","tags":["timing"],"summary":"开始一件事(流程、步骤或单件事)","description":"默认切换:前台那件暂停,后台在走的不动;parallel=true 同时进行:前台那件转到后台接着走。例外:前台是服务器补位顶上来的(回复里 now.front.auto 为 true,不是他选的),两种结果相同,它都回到后台接着走、不暂停,客户端不必弹开始菜单。对后台在走的事调用,就是把它拉到前台。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"mode":{"type":"string","enum":["pomodoro","stopwatch"]},"plannedPomodoros":{"type":"integer"},"parallel":{"type":"boolean"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/start.ts (startTask)"},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks/pause":{"post":{"operationId":"postTasksPause","tags":["timing"],"summary":"暂停一件事(前台或后台)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/start.ts (pauseTask)"},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks/cancel":{"post":{"operationId":"postTasksCancel","tags":["timing"],"summary":"撤销开始","description":"删掉这一轮记的时间,把这件事放回开始前的样子;被它暂停的那件在期间没被动过时接着走(restored)。只对正在走的事有效:不在走、这一轮是更新前开始的,回 409。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"restored":{"type":"boolean"}},"required":["restored"]},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/tasks/front":{"post":{"operationId":"postTasksFront","tags":["timing"],"summary":"把后台在走的那件拉到前台","description":"原前台转到后台接着走;已在前台不变;不在走时 409。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Ok"},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/steps/next":{"post":{"operationId":"postStepsNext","tags":["timing"],"summary":"完成这一步(不开始下一步)","description":"不给 leafId 时完成这棵树里正在走的那一步;没有可完成的,finished 为 null。下一步在 now.next 里,点了才开始。current 留给老悬浮条,总是 null。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"parentId":{"type":"string"},"leafId":{"type":"string"}},"required":["parentId"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"current":{"type":"null"},"finished":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"}},"required":["id","title"]},{"type":"null"}]}},"required":["current","finished"]},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/time/start":{"post":{"operationId":"postTimeStart","tags":["timing"],"summary":"开始一条计时(可只写标签)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"taskId":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"default":null},"label":{"type":"string","maxLength":200,"default":""}},"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdResult"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/time/stop":{"post":{"operationId":"postTimeStop","tags":["timing"],"summary":"结束一条计时","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/time.ts (stopTimer)"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/work/last":{"get":{"operationId":"getWorkLast","tags":["timing"],"summary":"最近一次开始工作的时刻(桌面强制工作模式)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"lastStartedAt":{"anyOf":[{"type":"string","description":"Postgres timestamptz 的文本形式,如 \"2026-10-18 09:30:00.123456+08\";不是 RFC 3339"},{"type":"null"}]},"running":{"type":"boolean"}},"required":["lastStartedAt","running"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/farm":{"get":{"operationId":"getFarm","tags":["timing"],"summary":"时间分布:某天的半小时格、工作 / 休息 / 未记录的占比","description":"一天按空间时区的零点切开(一般 48 格,夏令时那天 46 或 50 格);coverage 是这一天的占比、格子、空档和还没分类的导入时段(docs/architecture/time-coverage.md)。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"parameters":[{"name":"date","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"description":"默认今天"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FarmDay"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/time/entries":{"post":{"operationId":"postTimeEntries","tags":["timing"],"summary":"补记一段过去的时间","description":"补记面板、时间分布页里点未记录的格子用。rest = 记成休息;endDate 给了可以跨零点(一段最长 48 小时)。和别的事重叠的部分记成后台段,这件事自己记过的部分不重复记。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"start":{"type":"string","pattern":"^\\d{2}:\\d{2}$"},"end":{"type":"string","pattern":"^(\\d{2}:\\d{2}|24:00)$"},"endDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"taskId":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null},"label":{"type":"string","default":""},"rest":{"type":"boolean"}},"required":["date","start","end"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddEntryResult"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/intervals":{"get":{"operationId":"getIntervals","tags":["timing"],"summary":"导入的时段","description":"和 from 到 to(本地日期,含两头;不给是今天)有重叠的,按开始排;deleted=1 连删掉的一起列。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"}},{"name":"to","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"}},{"name":"source","in":"query","required":false,"schema":{"type":"string"}},{"name":"deleted","in":"query","required":false,"schema":{"type":"string","enum":["1"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"to":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"intervals":{"type":"array","items":{"$ref":"#/components/schemas/ImportedInterval"}}},"required":["from","to","intervals"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/intervals/import":{"post":{"operationId":"postIntervalsImport","tags":["timing"],"summary":"导入时段(手表、日历……)","description":"同一个 source + externalId 再导入是更新那一段。不进计时的总数,不改他的计时记录;改过的、已分类而这次要改短改类的不覆盖(status kept)。一次最多 500 段;source 不能是 tooo。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"intervals":{"type":"array","items":{"type":"object","properties":{"source":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\u0000-\\u001f\\u007f]*$"},"externalId":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[^\\u0000-\\u001f\\u007f]*$"},"start":{"anyOf":[{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$"},{"type":"string","format":"date-time"}]},"end":{"anyOf":[{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$"},{"type":"string","format":"date-time"}]},"label":{"type":"string","maxLength":200,"pattern":"^[^\\u0000-\\u001f\\u007f]*$","default":""},"class":{"anyOf":[{"type":"string","enum":["work","rest"]},{"type":"null"}]},"confidence":{"anyOf":[{"type":"number","minimum":0,"maximum":1},{"type":"null"}]},"details":{"type":"object","additionalProperties":{}}},"required":["source","externalId","start","end"],"additionalProperties":false},"minItems":1,"maxItems":500}},"required":["intervals"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"source":{"type":"string"},"externalId":{"type":"string"},"status":{"type":"string","enum":["created","updated","unchanged","kept"]},"note":{"type":"string"},"interval":{"$ref":"#/components/schemas/ImportedInterval"}},"required":["id","source","externalId","status","interval"]}}},"required":["results"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/intervals/correct":{"post":{"operationId":"postIntervalsCorrect","tags":["timing"],"summary":"改一段导入的时段(分类、起止、说明)或删掉","description":"改过的这一段,来源再导入不再覆盖。removedMinutes 是这次去掉的已记分钟(原来算工作或休息、现在不算的部分)。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":64},"class":{"anyOf":[{"type":"string","enum":["work","rest"]},{"type":"null"}]},"start":{"anyOf":[{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$"},{"type":"string","format":"date-time"}]},"end":{"anyOf":[{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$"},{"type":"string","format":"date-time"}]},"label":{"type":"string","maxLength":200,"pattern":"^[^\\u0000-\\u001f\\u007f]*$"},"delete":{"const":true,"type":"boolean"}},"required":["id"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"interval":{"$ref":"#/components/schemas/ImportedInterval"},"removedMinutes":{"type":"integer"}},"required":["interval","removedMinutes"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/settings/ui":{"get":{"operationId":"getSettingsUi","tags":["settings"],"summary":"界面语言、主题、背景","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UiSettings"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postSettingsUi","tags":["settings"],"summary":"改界面设置(只传要改的,null 清掉)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"lang":{"anyOf":[{"type":"string","enum":["zh","en"]},{"type":"null"}]},"theme":{"anyOf":[{"type":"string","enum":["light","dark"]},{"type":"null"}]},"bg":{"anyOf":[{"type":"string","enum":["plain","dots","grid"]},{"type":"null"}]}},"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UiSettings"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/settings/focus":{"get":{"operationId":"getSettingsFocus","tags":["settings"],"summary":"番茄时长、默认开始方式、没计时的时间算什么","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FocusDefaults"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postSettingsFocus","tags":["settings"],"summary":"改番茄时长 / 默认开始方式 / 没计时的时间算什么","description":"只改传进来的项,至少一项;untimedAs 只改怎么算,不改任何记录,过去的日子也一起按新的算","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"workMinutes":{"type":"integer"},"breakMinutes":{"type":"integer"},"mode":{"type":"string","enum":["pomodoro","stopwatch"]},"untimedAs":{"type":"string","enum":["rest","unrecorded"]}},"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FocusDefaults"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/contexts":{"get":{"operationId":"getContexts","tags":["contexts"],"summary":"场景列表","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/contexts.ts (ContextRow)"}}},"required":["items"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postContexts","tags":["contexts"],"summary":"新建场景","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"kind":{"type":"string","enum":["place","tool","person","energy","custom"],"default":"custom"}},"required":["name"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/contexts.ts (createContext)"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/contexts/available":{"post":{"operationId":"postContextsAvailable","tags":["contexts"],"summary":"场景可用 / 不可用","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"available":{"type":"boolean"}},"required":["id","available"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/contexts.ts (setContextAvailable)"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/review/weekly":{"get":{"operationId":"getReviewWeekly","tags":["review"],"summary":"一周的复盘数据(默认本周)","description":"review:这一周最新存的那一版周报(谁写的、几点存的都在里面),没存过为 null;这一周存过几版,用 GET /api/review/by-week。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"parameters":[{"name":"week","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"description":"那一周里任意一天;不给是本周"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/review.ts (WeekStats)"},{"type":"object","properties":{"coverage":{"$ref":"#/components/schemas/Coverage","description":"这一周的工作、休息、未记录,合计和每天"},"review":{"anyOf":[{"$ref":"#/components/schemas/ReviewVersion"},{"type":"null"}],"description":"这一周最新存的那一版周报;没存过为 null。更新前的服务器没有这个键"}},"required":["coverage"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postReviewWeekly","tags":["review"],"summary":"存一次周复盘(这一周的新一版)","description":"weekStart 是复盘周(那一周里任意一天,归到周一),不给是本周。每次存成这一周的新一版,同一周取最新的那一版(docs/architecture/reminders-weekly.md §4.6)。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"steps":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","maxLength":200},"done":{"type":"boolean"}},"required":["key","done"],"additionalProperties":false},"maxItems":50,"default":[]},"note":{"type":"string","maxLength":50000,"default":""},"plan":{"type":"string","maxLength":50000,"default":""},"weekStart":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdResult"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/review/history":{"get":{"operationId":"getReviewHistory","tags":["review"],"summary":"最近几次复盘(每一版一行,带复盘周 week_start、谁写的 author、saved_at)","description":"最近存的 8 版,新的在前;同一周存过几次就占几行,所以回满 8 行不等于只有 8 周。更早的周、某一周存过几版,用 GET /api/review/by-week。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ReviewVersion"}}},"required":["items"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/review/latest":{"get":{"operationId":"getReviewLatest","tags":["review"],"summary":"最近一次存的反思和计划(带它是哪一周、谁写的)","description":"保存时刻最晚的那一版,不论它写的是哪一周(周一补写上一周,它就是最近一次),week_start 说明是哪一周。一版都没有时 note、plan 是空串,其余为 null。at 是 Postgres 的时刻文本,新客户端读 saved_at。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string"},"plan":{"type":"string"},"at":{"anyOf":[{"type":"string","description":"Postgres timestamptz 的文本形式,如 \"2026-10-18 09:30:00.123456+08\";不是 RFC 3339"},{"type":"null"}]},"week_start":{"anyOf":[{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},{"type":"null"}],"description":"它写的是哪一周(周一);老数据为 null。更新前的服务器没有这个键"},"saved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"保存的时刻,带这个空间时区的偏移。更新前的服务器没有这个键"},"author":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"写入的那台设备(或密钥、连接器)的名字;不知道为 null。更新前的服务器没有这个键"}},"required":["note","plan","at"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/review/by-week":{"get":{"operationId":"getReviewByWeek","tags":["review"],"summary":"某一周最新存的那一版周报,和这一周存过几版","description":"这一周没存过周报时 review 为 null、versions 为 0(不是 404)。history 最多回 8 版,更早的周从这里按周取。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"parameters":[{"name":"week","in":"query","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"description":"那一周里任意一天(归到周一);不给是本周"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"week_start":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"versions":{"type":"integer"},"review":{"anyOf":[{"$ref":"#/components/schemas/ReviewVersion"},{"type":"null"}]}},"required":["week_start","versions","review"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/mirror":{"get":{"operationId":"getMirror","tags":["review"],"summary":"今天的觉察镜像","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/extras.ts (mirror)"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/reminders/pending":{"get":{"operationId":"getRemindersPending","tags":["reminders"],"summary":"某个渠道到点该弹的提醒(桌面轮询)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"parameters":[{"name":"channel","in":"query","required":false,"schema":{"type":"string"},"description":"默认 desktop"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string"},"count":{"type":"integer"},"items":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/reminders.ts"}}},"required":["channel","count","items"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/reminders":{"get":{"operationId":"getReminders","tags":["reminders"],"summary":"提醒列表","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"items":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/reminders.ts"}}},"required":["count","items"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postReminders","tags":["reminders"],"summary":"新建提醒","description":"fireAt 早于此刻一天以上、或不是时刻,回 400;这个空间还没到点的提醒已有 500 条时回 429(code too_many)。anchorTz 不给 = 这个空间的时区。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["due","defer","waiting_followup","daily_plan","evening_review","weekly_review","focus_phase","custom"],"default":"custom"},"taskId":{"type":"string","maxLength":64},"fireAt":{"type":"string","maxLength":64},"channels":{"type":"array","items":{"type":"string","enum":["feishu","desktop","weixin","mobile-push","web-push","email","wecom"]},"minItems":1,"maxItems":7,"default":["feishu"]},"body":{"type":"string","maxLength":1000},"anchorTz":{"type":"string","maxLength":64}},"required":["fireAt"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdResult"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"太频繁","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/presence":{"post":{"operationId":"postPresence","tags":["reminders"],"summary":"设备报在用 / 离开","description":"状态变化时报一次,在用期间最多每分钟一次;要有设备凭据(App、网页、悬浮条)。电脑回来的那一刻(带 anchor,或离开 ≥ 15 分钟)服务器顺带判断要不要出「没在计时」「计时没停 · 离开回来」,要出就在 prompt 里带上,这台设备直接出示,不用再认领。「当天第一次」由服务器判断。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","enum":["active","away"]},"since":{"type":"string","format":"date-time"},"anchor":{"type":"string","enum":["back","unlock"]},"awaySeconds":{"type":"integer","minimum":0,"maximum":2592000},"form":{"type":"string","enum":["computer","phone"]}},"required":["state"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"const":true,"type":"boolean"},"show":{"type":"boolean"},"prompt":{"anyOf":[{"$ref":"#/components/schemas/Prompt"},{"type":"null"}]},"reason":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["ok","show","prompt","reason"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/prompts/claim":{"post":{"operationId":"postPromptsClaim","tags":["reminders"],"summary":"出示之前认领一条提醒","description":"{id}:服务器建的行(到点、过点没开始、计时很久、一天收尾)到了本地闹钟或拉取里;{kind, facts}:设备自己发现的时刻(用了一阵;离开回来)。回 show=true 带提醒的全部字段,或 show=false 带 reason(elsewhere 在别处出了、quiet 勿扰、gap 间隔未到、backoff 已退避、off 关了、answered 已回应……);手机被告知 elsewhere 时按 retryAt 再认领一次,那边没响应就由手机出。认领失败(没网、超时):定时提醒照出,情境提醒不出。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":64}},"required":["id"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","enum":["untimed","stale_timer"]},"facts":{"type":"object","properties":{"moment":{"type":"string","enum":["busy","away"]},"since":{"type":"string","format":"date-time"},"from":{"type":"string","format":"date-time"}},"required":["moment"],"additionalProperties":false}},"required":["kind","facts"],"additionalProperties":false}]}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"show":{"type":"boolean"},"reason":{"type":"string"},"retryAt":{"type":"string","format":"date-time"},"id":{"type":"string"},"kind":{"type":"string","enum":["untimed","stale_timer","due","late_start","day_end","weekly"]},"moment":{"type":"string"},"at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"title":{"type":"string"},"body":{"type":"string"},"actions":{"type":"array","items":{"$ref":"#/components/schemas/PromptAction"}},"taskId":{"anyOf":[{"type":"string"},{"type":"null"}]},"span":{},"place":{"anyOf":[{"type":"string"},{"type":"null"}]},"startsAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"任务的到点提醒:那件事的开始时刻,客户端在提醒到开始这段倒数(倒计时窗口是开始前 2 到 60 分钟);没有开始时刻、不是任务的到点为 null"}},"required":["show"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/prompts/act":{"post":{"operationId":"postPromptsAct","tags":["reminders"],"summary":"按提醒上的一个按钮","description":"一个按钮一个事务(补记加开始同成同败),记下回应,回一行结果和按完的 now。没有这个按钮、要选一件却没给 taskId 时 400;命令行密钥和 AI 连接器按「不算」「停在…」时 403;这条已经处理过 409;那一轮已经不在计时 409(code not_running)。任务的到点提醒多一个 done(完成那件事);周报的 snooze 是 1 小时,open_review 只回 weekStart、不算回应,skip_week 这一周不再提醒。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":64},"action":{"type":"string","enum":["start","pick","not_now","log_as","log_rest","keep","cut","stop_at","stop","snooze","ok","rest","end_break","later","tomorrow","all_tomorrow","fill_gaps","ignore","done","open_review","skip_week"]},"taskId":{"type":"string","minLength":1,"maxLength":64}},"required":["id","action"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"ok":{"const":true,"type":"boolean"},"id":{"type":"string"},"action":{"type":"string","enum":["start","pick","not_now","log_as","log_rest","keep","cut","stop_at","stop","snooze","ok","rest","end_break","later","tomorrow","all_tomorrow","fill_gaps","ignore","done","open_review","skip_week"]},"outcome":{"anyOf":[{"type":"string","enum":["acted","snoozed","dismissed","ignored"]},{"type":"null"}]},"result":{"type":"string"},"moved":{"type":"array","items":{"type":"string"}},"gaps":{"type":"array","items":{"$ref":"#/components/schemas/PromptGap"}},"weekStart":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"周报的「打开复盘」「这周不写」:复盘周的周一(客户端打开那一周的复盘页)"}},"required":["ok","id","action","outcome","result"]},{"type":"object","properties":{"now":{"$ref":"#/components/schemas/Now"}},"required":["now"]}]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"这个凭据不能做这件事","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"找不到(或不在这个空间)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"冲突(客户端给的新建 id 已被别的空间用掉,或状态不允许)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/prompts":{"get":{"operationId":"getPrompts","tags":["reminders"],"summary":"最近 2 小时还没回应的提醒,和此刻的两个数","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"prompts":{"type":"array","items":{"$ref":"#/components/schemas/Prompt"}},"untimedMinutes":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"什么都没在计时已经多少分钟;在计时、今天还没记过为 null"},"gapsToday":{"type":"array","items":{"$ref":"#/components/schemas/PromptGap"}}},"required":["prompts","untimedMinutes","gapsToday"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/settings/prompts":{"get":{"operationId":"getSettingsPrompts","tags":["settings"],"summary":"主动提醒的设置和近 7 天每种的出现、响应次数","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptSettingsState"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"postSettingsPrompts","tags":["settings"],"summary":"改主动提醒的设置(只给要改的;语气 tone、勿扰、间隔、每天上限、退避、每种的开关和参数)","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tone":{"type":"string","enum":["plain","snark"]},"quiet":{"anyOf":[{"type":"object","properties":{"from":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"to":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"required":["from","to"],"additionalProperties":false},{"type":"null"}]},"minGapMinutes":{"type":"integer","minimum":0,"maximum":240},"dailyCap":{"type":"integer","minimum":0,"maximum":50},"backoff":{"type":"object","properties":{"after":{"type":"integer","minimum":1,"maximum":10},"maxMinutes":{"type":"integer","minimum":30,"maximum":1440}},"additionalProperties":false},"untimed":{"type":"object","properties":{"on":{"type":"boolean"},"awayMinutes":{"type":"integer","minimum":5,"maximum":240},"busyMinutes":{"type":"integer","minimum":5,"maximum":240},"phone":{"type":"boolean"}},"additionalProperties":false},"stale_timer":{"type":"object","properties":{"on":{"type":"boolean"},"awayMinutes":{"type":"integer","minimum":5,"maximum":240},"longMinutes":{"anyOf":[{"type":"integer","minimum":15,"maximum":600},{"type":"null"}]}},"additionalProperties":false},"due":{"type":"object","properties":{"on":{"type":"boolean"},"secondPlaceMinutes":{"type":"integer","minimum":1,"maximum":60}},"additionalProperties":false},"late_start":{"type":"object","properties":{"on":{"type":"boolean"},"afterMinutes":{"type":"integer","minimum":1,"maximum":120},"waitMinutes":{"type":"integer","minimum":10,"maximum":240}},"additionalProperties":false},"day_end":{"type":"object","properties":{"on":{"type":"boolean"},"from":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"at":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"latest":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"additionalProperties":false},"weekly":{"type":"object","properties":{"on":{"type":"boolean"},"weekday":{"type":"integer","minimum":0,"maximum":6},"at":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"where":{"type":"string","enum":["weixin","device"]}},"additionalProperties":false}},"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptSettingsState"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/push/register":{"post":{"operationId":"postPushRegister","tags":["reminders"],"summary":"登记 Expo 推送令牌","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":1,"maxLength":500},"platform":{"type":"string","maxLength":50,"default":"expo"}},"required":["token"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/ops/push.ts"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/push/web/key":{"get":{"operationId":"getPushWebKey","tags":["reminders"],"summary":"Web Push 的 applicationServerKey","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"publicKey":{"type":"string"}},"required":["publicKey"]}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/push/web/subscribe":{"post":{"operationId":"postPushWebSubscribe","tags":["reminders"],"summary":"登记 Web Push 订阅","description":"一个空间最多留 20 个订阅,超了删掉最久没更新的。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"endpoint":{"type":"string","maxLength":2048},"keys":{"type":"object","properties":{"p256dh":{"type":"string","minLength":1,"maxLength":200},"auth":{"type":"string","minLength":1,"maxLength":200}},"required":["p256dh","auth"],"additionalProperties":false},"expirationTime":{"anyOf":[{"type":"number","minimum":0,"maximum":8640000000000000},{"type":"null"}]}},"required":["endpoint","keys"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/webpush.ts (saveSubscription)"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/push/web/unsubscribe":{"post":{"operationId":"postPushWebUnsubscribe","tags":["reminders"],"summary":"取消 Web Push 订阅","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"endpoint":{"type":"string","minLength":1,"maxLength":2048}},"required":["endpoint"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"形状见 services/backend/src/webpush.ts (removeSubscription)"}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/push/web/test":{"post":{"operationId":"postPushWebTest","tags":["reminders"],"summary":"发一条试试","description":"每个空间 10 分钟最多 10 次,超了 429。","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"endpoint":{"type":"string","minLength":1,"maxLength":2048},"title":{"type":"string","minLength":1},"body":{"type":"string"}},"required":["title","body"],"additionalProperties":false}}},"description":"上限 262144 字节"},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"sent":{"type":"integer"},"failed":{"type":"integer"}},"required":["sent","failed"]}}}},"400":{"description":"参数不合法","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"请求体太大","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"太频繁","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/scheduler/tick":{"post":{"operationId":"postSchedulerTick","tags":["server"],"summary":"立即跑一轮这个空间的例行任务和到点提醒","security":[{"bearer":[]},{"deviceCookie":[]},{"cadenceKey":[]},{"legacySession":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"没有认出凭据","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"issues":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"zod 的校验问题(只在参数不合法时有)"}},"code":{"type":"string","description":"可以按它分支的错误种类(只有部分错误带):invite_required、invite_invalid(新建空间)、invalid、too_many(提醒)……"}},"required":["error"]},"OAuthError":{"type":"object","properties":{"error":{"type":"string"},"error_description":{"type":"string"}},"required":["error"]},"Ok":{"type":"object","properties":{"ok":{"const":true,"type":"boolean"}},"required":["ok"]},"Device":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["device","cli","agent"]},"platform":{"type":"string"}},"required":["id","name","kind","platform"],"description":"device = 网页或 App;cli = 命令行密钥;agent = OAuth 连接器"},"DeviceListItem":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["device","cli","agent"]},"platform":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"lastSeenAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"current":{"type":"boolean"}},"required":["id","name","kind","platform","createdAt","lastSeenAt","current"]},"FocusSession":{"type":"object","properties":{"id":{"type":"string"},"taskId":{"type":"string"},"taskTitle":{"type":"string"},"mode":{"type":"string","enum":["pomodoro","stopwatch"]},"state":{"type":"string","enum":["running","paused","done"]},"phase":{"type":"string","enum":["work","break"]},"phaseIndex":{"type":"integer","description":"这一段工作开始时是第几颗(休息、结束休息时用它作 from.phaseIndex)。正在做的是第几颗 = phaseIndex + floor(phaseElapsedSeconds ÷ workSeconds)(工作阶段)"},"plannedPomodoros":{"anyOf":[{"type":"integer"},{"type":"null"}]},"completedPomodoros":{"type":"integer","description":"工作阶段结束时记下的做满颗数,不含正在走的这一段工作里已经满了的;一共做满几颗 = completedPomodoros + floor(phaseElapsedSeconds ÷ workSeconds)(工作阶段)"},"workSeconds":{"type":"integer","description":"一颗的工作时长:每满一个就算做满一颗,时钟接着往上数"},"breakSeconds":{"type":"integer"},"phaseElapsedSeconds":{"type":"integer","description":"这一段(工作或休息)已计秒数,含正在走的,按回复时刻算;工作阶段过了 workSeconds 不清零"},"phaseRemainingSeconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"番茄 = max(0, 这一段的时长 − 已计),正计时为 null。只给老悬浮条倒数用;新客户端一律往上数"},"runningSince":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"serverNow":{"type":"string","format":"date-time"},"taskTotalSeconds":{"type":"integer"},"startedAt":{"type":"string","format":"date-time"},"endedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id","taskId","taskTitle","mode","state","phase","phaseIndex","plannedPomodoros","completedPomodoros","workSeconds","breakSeconds","phaseElapsedSeconds","phaseRemainingSeconds","runningSince","serverNow","taskTotalSeconds","startedAt","endedAt"],"description":"番茄 / 正计时会话(focus-types.ts FocusSession)。工作阶段满了几颗 = floor(phaseElapsedSeconds ÷ workSeconds),休息阶段、正计时、已结束为 0(timer.md §18)"},"NowItem":{"type":"object","properties":{"taskId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"被点开始的那件:步骤是树根;只写标签的计时为 null"},"leafId":{"anyOf":[{"type":"string"},{"type":"null"}]},"title":{"type":"string"},"crumb":{"type":"array","items":{"type":"string"}},"mode":{"type":"string","enum":["pomodoro","stopwatch","step","timer"]},"sessionId":{"anyOf":[{"type":"string"},{"type":"null"}]},"session":{"anyOf":[{"$ref":"#/components/schemas/FocusSession"},{"type":"null"}]},"rootId":{"anyOf":[{"type":"string"},{"type":"null"}]},"index":{"type":"integer"},"total":{"type":"integer"},"hasNext":{"type":"boolean"},"since":{"type":"string","format":"date-time","description":"这一段的开始"},"totalSeconds":{"type":"integer","description":"叶子自己的累计(含后台、含正在走的这一段),按回复时刻算"},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"这一轮的开始;null = 不能撤销"},"undo":{"anyOf":[{"type":"object","properties":{"taskId":{"anyOf":[{"type":"string"},{"type":"null"}]},"how":{"type":"string","enum":["paused","background"]},"auto":{"const":true,"type":"boolean"}},"required":["taskId","how"],"description":"撤销时原前台会怎样(只供预测)。auto 只在 how = background 且被顶到后台的那件当时是补位上来的前台时有,撤销会把它原样放回(仍是 auto)"},{"type":"null"}]},"auto":{"type":"boolean","description":"前台是服务器补位顶上来的、不是他选的。为 true 时再开始别的事,切换和同时进行结果一样(它回到后台接着走),客户端不弹开始菜单;后台项恒为 false"},"rest":{"type":"boolean","description":"这一项此刻记的是休息:番茄在休息阶段、休息计时,或这件事(或它任一上层)标了算作休息"},"restTimer":{"anyOf":[{"$ref":"#/components/schemas/RestTimerInfo"},{"type":"null"}],"description":"这一项是休息计时(不挂任务的休息,mode 为 timer、title「休息」):目标和到目标的时刻,卡片主按钮「结束休息」(POST /api/rest/end)。别的项为 null"}},"required":["taskId","leafId","title","crumb","mode","sessionId","session","rootId","index","total","hasNext","since","totalSeconds","startedAt","undo","auto","rest","restTimer"],"description":"一个在走的计时项(ops/now.ts NowItem)"},"RestTimerInfo":{"type":"object","properties":{"targetSeconds":{"type":"integer","description":"目标时长(秒)"},"endsAt":{"type":"string","format":"date-time","description":"到目标的时刻;过了它照样往上数,超出 = 现在 − endsAt"}},"required":["targetSeconds","endsAt"],"description":"休息计时的目标(docs/architecture/timer.md §17.3)"},"NowNext":{"type":"object","properties":{"rootId":{"type":"string"},"leafId":{"type":"string"},"title":{"type":"string"},"crumb":{"type":"array","items":{"type":"string"}},"index":{"type":"integer"},"total":{"type":"integer"}},"required":["rootId","leafId","title","crumb","index","total"],"description":"「接下来」:刚完成一步后,同一棵树里的下一步"},"Now":{"type":"object","properties":{"kind":{"type":"string","enum":["step","focus","paused","idle"]},"step":{"anyOf":[{"type":"object","additionalProperties":true,"description":"NowStep(ops/now.ts);前台的步骤"},{"type":"null"}]},"focus":{"type":"object","additionalProperties":true,"description":"ActiveFocus(focus-types.ts);前台的会话"},"paused":{"anyOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"pausedSession":{"anyOf":[{"$ref":"#/components/schemas/FocusSession"},{"type":"null"}]},"session":{"anyOf":[{"$ref":"#/components/schemas/FocusSession"},{"type":"null"}],"description":"前台的会话"},"front":{"anyOf":[{"$ref":"#/components/schemas/NowItem"},{"type":"null"}]},"background":{"type":"array","items":{"$ref":"#/components/schemas/NowItem"},"description":"同时在走的其余几件,最近放到后台的在前"},"next":{"anyOf":[{"$ref":"#/components/schemas/NowNext"},{"type":"null"}]},"idleSince":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"休息中从几点起(docs/architecture/time-coverage.md §15):设置是没计时算休息(untimedAs = rest)、前台什么都没在走(没在计时,或都暂停着)时,是最后一段工作结束的时刻,从这里往上数「休息中 23:15 · 从 13:02 起」;中间记的休息不算断开。前台有一项在走、设置是 unrecorded、从没记过工作时为 null"}},"required":["kind","step","focus","paused","pausedSession","session","front","background","next","idleSince"],"description":"现在在计什么(ops/now.ts)。kind、step、focus、paused、pausedSession、session 是老字段,都描述前台"},"UiSettings":{"type":"object","properties":{"lang":{"anyOf":[{"type":"string","enum":["zh","en"]},{"type":"null"}]},"theme":{"anyOf":[{"type":"string","enum":["light","dark"]},{"type":"null"}]},"bg":{"anyOf":[{"type":"string","enum":["plain","dots","grid"]},{"type":"null"}]}},"required":["lang","theme","bg"]},"FocusDefaults":{"type":"object","properties":{"workMinutes":{"type":"integer"},"breakMinutes":{"type":"integer"},"mode":{"type":"string","enum":["pomodoro","stopwatch"]},"untimedAs":{"type":"string","enum":["rest","unrecorded"],"description":"没计时的时间算:rest 休息(默认)/ unrecorded 未记录(docs/architecture/time-coverage.md §15)"}},"required":["workMinutes","breakMinutes","mode","untimedAs"]},"IdResult":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]},"Invite":{"type":"object","properties":{"id":{"type":"string"},"note":{"anyOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["active","used","revoked","expired"]},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"null = 不过期"},"usedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"revokedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id","note","status","createdAt","expiresAt","usedAt","revokedAt"],"description":"一张邀请码(identity/invites.ts);不含邀请码本身"},"SyncRequest":{"type":"object","properties":{"cursor":{"type":"integer","minimum":0},"mutations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","minimum":1},"name":{"type":"string","minLength":1,"maxLength":64},"args":{},"at":{"type":"string","maxLength":64},"hlc":{"type":"string","maxLength":64},"baseTimingRev":{"type":"integer","minimum":0}},"required":["id","name","args","at","hlc"],"additionalProperties":false},"maxItems":100,"default":[]}},"required":["cursor"],"additionalProperties":false},"SyncResultItem":{"type":"object","properties":{"id":{"type":"integer"},"status":{"type":"string","enum":["ok","superseded","rejected"]},"code":{"type":"string"},"message":{"type":"string"},"dropped":{"type":"array","items":{"type":"string"}}},"required":["id","status"]},"SyncPatchItem":{"oneOf":[{"type":"object","properties":{"t":{"type":"string"},"op":{"const":"put","type":"string"},"row":{"type":"object","additionalProperties":true,"description":"白名单列 + version,见 sync-schema.json"}},"required":["t","op","row"]},{"type":"object","properties":{"t":{"type":"string"},"op":{"const":"del","type":"string"},"key":{"type":"string","description":"行键:键列用 '|' 连起来"}},"required":["t","op","key"]}]},"SyncResponse":{"type":"object","properties":{"cursor":{"type":"integer"},"more":{"type":"boolean"},"reset":{"type":"boolean"},"serverNow":{"type":"string","format":"date-time"},"serverHlc":{"type":"string"},"lastMutationId":{"type":"integer"},"results":{"type":"array","items":{"$ref":"#/components/schemas/SyncResultItem"}},"patch":{"type":"array","items":{"$ref":"#/components/schemas/SyncPatchItem"},"maxItems":2000}},"required":["cursor","more","reset","serverNow","serverHlc","lastMutationId","results","patch"]},"SyncUnavailable":{"type":"object","properties":{"lastMutationId":{"type":"integer"},"retryAfterMs":{"type":"integer","default":2000}},"required":["lastMutationId","retryAfterMs"]},"ActivityUploadInput":{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"source":{"type":"string","enum":["android","mac","windows","manictime"]},"apps":{"type":"array","items":{"type":"object","properties":{"appId":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[^\\u0000-\\u001f\\u007f]*$"},"appName":{"type":"string","maxLength":200,"pattern":"^[^\\u0000-\\u001f\\u007f]*$"},"seconds":{"type":"integer","minimum":0,"maximum":90000},"opens":{"type":"integer","minimum":0,"maximum":100000},"firstUsed":{"type":"string","format":"date-time"},"lastUsed":{"type":"string","format":"date-time"}},"required":["appId","seconds"],"additionalProperties":false},"maxItems":1000},"intervals":{"type":"array","items":{"type":"object","properties":{"app":{"type":"string","maxLength":255,"pattern":"^[^\\u0000-\\u001f\\u007f]*$"},"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}},"required":["app","start","end"],"additionalProperties":false},"maxItems":10000}},"required":["date","source","apps"],"additionalProperties":false},"ActivityUploadResult":{"type":"object","properties":{"ok":{"const":true,"type":"boolean"},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"apps":{"type":"integer"},"intervals":{"type":"integer"},"changed":{"type":"integer"},"removed":{"type":"integer"}},"required":["ok","date","apps","intervals","changed","removed"]},"ActivityApp":{"type":"object","properties":{"appId":{"type":"string"},"appName":{"type":"string"},"seconds":{"type":"integer"},"opens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"firstUsed":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"lastUsed":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["appId","appName","seconds","opens","firstUsed","lastUsed"]},"ActivityDevice":{"type":"object","properties":{"deviceId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"null = 老的 ManicTime 上传(/api/usage/daily),没有设备行"},"deviceName":{"type":"string"},"platform":{"type":"string"},"source":{"type":"string","enum":["android","mac","windows","manictime"]},"form":{"type":"string","enum":["phone","computer"]},"totalSeconds":{"type":"integer"},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"apps":{"type":"array","items":{"$ref":"#/components/schemas/ActivityApp"}}},"required":["deviceId","deviceName","platform","source","form","totalSeconds","updatedAt","apps"]},"ActivityMergedApp":{"type":"object","properties":{"appId":{"type":"string"},"appName":{"type":"string"},"seconds":{"type":"integer"},"opens":{"anyOf":[{"type":"integer"},{"type":"null"}]},"devices":{"type":"integer"}},"required":["appId","appName","seconds","opens","devices"]},"ActivityInterval":{"type":"object","properties":{"deviceId":{"type":"string"},"appId":{"type":"string"},"appName":{"type":"string"},"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}},"required":["deviceId","appId","appName","start","end"]},"ActivityDay":{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"totals":{"type":"object","properties":{"all":{"type":"integer"},"phone":{"type":"integer"},"computer":{"type":"integer"}},"required":["all","phone","computer"],"description":"秒;各设备相加"},"devices":{"type":"array","items":{"$ref":"#/components/schemas/ActivityDevice"}},"merged":{"type":"array","items":{"$ref":"#/components/schemas/ActivityMergedApp"}},"intervals":{"type":"array","items":{"$ref":"#/components/schemas/ActivityInterval"}}},"required":["date","totals","devices","merged"]},"CoverageCell":{"type":"object","properties":{"kind":{"type":"string","enum":["work","rest","none","future"]},"imported":{"type":"boolean"},"auto":{"type":"boolean"}},"required":["kind","imported"],"description":"半小时一格,按多数:一样多时工作优先,其次休息;没记的部分赢了是 none(未记录),或者(设置是没计时算休息时)kind 为 rest 且 auto 为 true:这段是没计时算成的休息,可以补记成工作;别的格子没有 auto。future = 整格还没到。imported:这一格赢的那一类大半来自导入的时段"},"CoverageSpan":{"type":"object","properties":{"start":{"type":"string","description":"本地 HH:MM;到次日零点写 24:00"},"end":{"type":"string"},"minutes":{"type":"integer"},"startIso":{"type":"string","format":"date-time"},"endIso":{"type":"string","format":"date-time"}},"required":["start","end","minutes","startIso","endIso"],"description":"一段没计时、按设置算作休息的时间(不限长短)"},"CoverageGap":{"type":"object","properties":{"start":{"type":"string","description":"本地 HH:MM;到次日零点写 24:00"},"end":{"type":"string"},"minutes":{"type":"integer"},"startIso":{"type":"string","format":"date-time"},"endIso":{"type":"string","format":"date-time"},"phoneMinutes":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"这段时间手机在用的分钟;这一天手机没有时段数据为 null"},"computerMinutes":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"同上,电脑"},"topApps":{"type":"array","items":{"type":"object","properties":{"app":{"type":"string"},"minutes":{"type":"integer"}},"required":["app","minutes"]}}},"required":["start","end","minutes","startIso","endIso","phoneMinutes","computerMinutes","topApps"],"description":"空档:未记录、不短于 30 分钟的一段(今天从零点算到现在),带设备提示"},"CoverageUnclassified":{"type":"object","properties":{"id":{"type":"string"},"source":{"type":"string"},"label":{"type":"string"},"start":{"type":"string","description":"本地 YYYY-MM-DD HH:MM(整段,可能跨天)"},"end":{"type":"string"},"startIso":{"type":"string","format":"date-time"},"endIso":{"type":"string","format":"date-time"},"minutes":{"type":"integer","description":"落在这一天里的分钟"},"uncoveredMinutes":{"type":"integer","description":"其中没被他的记录和已分类的导入盖住的分钟(按设置是未记录,或没计时算成的休息)"},"confidence":{"anyOf":[{"type":"number"},{"type":"null"}]}},"required":["id","source","label","start","end","startIso","endIso","minutes","uncoveredMinutes","confidence"],"description":"一段还没分类的导入时段(如 tooo 记的「手机和电脑都没在用」)"},"CoverageNumbers":{"type":"object","properties":{"seconds":{"type":"integer","description":"统计时长:过去的日子是零点到次日零点(夏令时那天 23 或 25 小时),今天是零点到现在"},"work":{"type":"integer"},"rest":{"type":"integer","description":"含 restAuto"},"unrecorded":{"type":"integer","description":"work + rest + unrecorded = seconds;设置是没计时算休息时为 0"},"entryWork":{"type":"integer","description":"他自己的记录里的工作(计时的总数只认它)"},"entryRest":{"type":"integer"},"importedWork":{"type":"integer","description":"导入的、已分类的时段补上的工作(只填他没记的时间)"},"importedRest":{"type":"integer"},"restAuto":{"type":"integer","description":"休息里没计时、按设置算成休息的部分(「其中没计时 N」);设置是 unrecorded 时为 0"}},"required":["seconds","work","rest","unrecorded","entryWork","entryRest","importedWork","importedRest","restAuto"],"description":"秒"},"DayCoverage":{"allOf":[{"$ref":"#/components/schemas/CoverageNumbers"},{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"untimedAs":{"type":"string","enum":["rest","unrecorded"],"description":"算这一份数时用的设置「没计时的时间算」"},"start":{"type":"string","format":"date-time","description":"本地零点"},"end":{"type":"string","format":"date-time","description":"次日零点"},"cells":{"type":"array","items":{"$ref":"#/components/schemas/CoverageCell"}},"gaps":{"type":"array","items":{"$ref":"#/components/schemas/CoverageGap"},"description":"设置是没计时算休息时没有未记录,为空"},"autoRest":{"type":"array","items":{"$ref":"#/components/schemas/CoverageSpan"},"description":"没计时、算作休息的各段;设置是 unrecorded 时为空"},"unclassified":{"type":"array","items":{"$ref":"#/components/schemas/CoverageUnclassified"}}},"required":["date","untimedAs","start","end","cells","gaps","autoRest","unclassified"]}]},"Coverage":{"type":"object","properties":{"from":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"to":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"untimedAs":{"type":"string","enum":["rest","unrecorded"]},"days":{"type":"array","items":{"$ref":"#/components/schemas/DayCoverage"}},"total":{"$ref":"#/components/schemas/CoverageNumbers"}},"required":["from","to","untimedAs","days","total"]},"FarmDay":{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},"blocks":{"type":"array","items":{"type":"object","properties":{"slot":{"type":"integer"},"kind":{"type":"string","enum":["red","green","rest"]},"imported":{"type":"boolean"},"taskId":{"anyOf":[{"type":"string"},{"type":"null"}]},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"category":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["slot","kind","imported","taskId","title","category"],"description":"red 工作 / rest 休息 / green 未记录、没计时算成的休息和将来(老客户端照旧能画);新客户端读 coverage.cells"}},"redCount":{"type":"integer"},"restCount":{"type":"integer"},"greenCount":{"type":"integer"},"restSeconds":{"type":"integer","description":"他记下的休息"},"totalSeconds":{"type":"integer","description":"他记下的工作"},"byCategory":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string"},"count":{"type":"integer"}},"required":["category","count"]}},"tasks":{"type":"array","items":{"type":"object","additionalProperties":true,"description":"FarmTask(ops/farm.ts):每件事当天的用时(含后台),逐层小计;只列工作"}},"coverage":{"$ref":"#/components/schemas/DayCoverage"}},"required":["date","blocks","redCount","restCount","greenCount","restSeconds","totalSeconds","byCategory","tasks","coverage"],"description":"时间分布页的一天(ops/farm.ts;这一页原名「番茄农场」,接口和字段名不变)"},"EntrySegment":{"type":"object","properties":{"id":{"type":"string"},"start":{"type":"string"},"end":{"type":"string"},"minutes":{"type":"integer"},"background":{"type":"boolean"},"alongside":{"type":"array","items":{"type":"string"}}},"required":["id","start","end","minutes","background","alongside"]},"AddEntryResult":{"type":"object","properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}]},"minutes":{"type":"integer"},"segments":{"type":"array","items":{"$ref":"#/components/schemas/EntrySegment"}},"skipped":{"type":"array","items":{"type":"object","properties":{"start":{"type":"string"},"end":{"type":"string"}},"required":["start","end"]}},"note":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","minutes","segments","skipped","note"],"description":"实际记下的各段(和别的事重叠的部分是后台段);整段都记过时 segments 为空"},"ImportedInterval":{"type":"object","properties":{"id":{"type":"string"},"source":{"type":"string"},"externalId":{"type":"string"},"label":{"type":"string"},"class":{"anyOf":[{"type":"string","enum":["work","rest"]},{"type":"null"}]},"start":{"type":"string","description":"本地 YYYY-MM-DD HH:MM"},"end":{"type":"string"},"startIso":{"type":"string","format":"date-time"},"endIso":{"type":"string","format":"date-time"},"minutes":{"type":"integer"},"confidence":{"anyOf":[{"type":"number"},{"type":"null"}]},"details":{"type":"object","additionalProperties":true},"corrected":{"type":"boolean","description":"他或他的 Agent 改过:来源再导入不覆盖"},"deleted":{"type":"boolean"},"conflicts":{"type":"array","items":{"type":"object","properties":{"entryId":{"type":"string"},"title":{"type":"string"},"start":{"type":"string"},"end":{"type":"string"},"minutes":{"type":"integer"},"rest":{"type":"boolean"}},"required":["entryId","title","start","end","minutes","rest"],"description":"和他自己的记录重叠的一段"}},"coveredMinutes":{"type":"integer","description":"被他自己的记录盖住的分钟"}},"required":["id","source","externalId","label","class","start","end","startIso","endIso","minutes","confidence","details","corrected","deleted","conflicts","coveredMinutes"],"description":"一段导入的时段(ops/intervals.ts)"},"ReviewVersion":{"type":"object","properties":{"id":{"type":"string"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"保存的时刻(UTC);老字段,新客户端读 saved_at"},"note":{"type":"string","description":"反思,存下的 HTML;复盘页用「## 本周大事 / 本周成就 / 本周反思」三行标题把它拆成三块,没有标题的整段算本周反思"},"plan":{"type":"string","description":"下周三件,存下的 HTML,一行一件"},"week_start":{"anyOf":[{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"},{"type":"null"}],"description":"复盘周的周一;没有记下的老行为 null"},"saved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"保存的时刻,带这个空间时区的偏移,如 2026-10-25T20:14:00+08:00"},"author":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"写入的那台设备(或命令行密钥、AI 连接器)的名字,如「Hermes」「Claude」;老数据、服务器写的为 null。更新前的服务器没有这个键"}},"required":["id","completed_at","note","plan","week_start"],"description":"周报的一版:每存一次是一版(ops/review.ts ReviewVersion)。saved_at、author 是后加的,连着更新前的服务器时没有这两个键"},"PromptAction":{"type":"object","properties":{"id":{"type":"string","enum":["start","pick","not_now","log_as","log_rest","keep","cut","stop_at","stop","snooze","ok","rest","end_break","later","tomorrow","all_tomorrow","fill_gaps","ignore","done","open_review","skip_week"]},"label":{"type":"string"},"needs":{"const":"task_id","type":"string"}},"required":["id","label"],"description":"提醒上的一个按钮;needs = task_id:按之前要他再选一件(POST /api/prompts/act 带 taskId)"},"Prompt":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["untimed","stale_timer","due","late_start","day_end","weekly"]},"moment":{"type":"string","description":"first / back / busy(没在计时)、away / long(计时没停)、task / at / custom / pomo_work / pomo_break / pomo / rest(到点;at = 定点式提醒、任务没有开始时刻;rest = 休息计时到目标)、late、day_end、weekly(周报)"},"at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"出现的时刻(换了一处时是第二处出现的时刻)"},"title":{"type":"string","description":"第一行;语气设置只换这一行"},"body":{"type":"string","description":"第二行(事实);库里是 reminders.detail 列。reminders.body 列是给老客户端和微信的一行字,不在这里"},"actions":{"type":"array","items":{"$ref":"#/components/schemas/PromptAction"}},"taskId":{"anyOf":[{"type":"string"},{"type":"null"}]},"span":{"anyOf":[{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["start","end"],"description":"这条提醒说的那段时间:没在计时是从哪起,离开回来是离开的那段,计时很久是这一轮的开始"},{"type":"null"}]},"place":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"出在哪:设备 id、phone、weixin、agent;null = 老办法,各渠道都发"}},"required":["id","kind","moment","at","title","body","actions","taskId","span","place"],"description":"一条主动提醒(ops/prompt-store.ts PromptOut)"},"PromptGap":{"$ref":"#/components/schemas/CoverageGap"},"PromptSettings":{"type":"object","properties":{"tone":{"type":"string","enum":["plain","snark"]},"quiet":{"anyOf":[{"type":"object","properties":{"from":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"to":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"required":["from","to"],"additionalProperties":false},{"type":"null"}]},"minGapMinutes":{"type":"integer","minimum":0,"maximum":240},"dailyCap":{"type":"integer","minimum":0,"maximum":50},"backoff":{"type":"object","properties":{"after":{"type":"integer","minimum":1,"maximum":10},"maxMinutes":{"type":"integer","minimum":30,"maximum":1440}},"additionalProperties":false},"untimed":{"type":"object","properties":{"on":{"type":"boolean"},"awayMinutes":{"type":"integer","minimum":5,"maximum":240},"busyMinutes":{"type":"integer","minimum":5,"maximum":240},"phone":{"type":"boolean"}},"additionalProperties":false},"stale_timer":{"type":"object","properties":{"on":{"type":"boolean"},"awayMinutes":{"type":"integer","minimum":5,"maximum":240},"longMinutes":{"anyOf":[{"type":"integer","minimum":15,"maximum":600},{"type":"null"}]}},"additionalProperties":false},"due":{"type":"object","properties":{"on":{"type":"boolean"},"secondPlaceMinutes":{"type":"integer","minimum":1,"maximum":60}},"additionalProperties":false},"late_start":{"type":"object","properties":{"on":{"type":"boolean"},"afterMinutes":{"type":"integer","minimum":1,"maximum":120},"waitMinutes":{"type":"integer","minimum":10,"maximum":240}},"additionalProperties":false},"day_end":{"type":"object","properties":{"on":{"type":"boolean"},"from":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"at":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"latest":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"}},"additionalProperties":false},"weekly":{"type":"object","properties":{"on":{"type":"boolean"},"weekday":{"type":"integer","minimum":0,"maximum":6},"at":{"type":"string","pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"where":{"type":"string","enum":["weixin","device"]}},"additionalProperties":false}},"additionalProperties":false,"description":"读出来时每一项都有值(没改过的是默认值);改的时候只给要改的那几项"},"PromptKindStats":{"type":"object","properties":{"shown":{"type":"integer"},"acted":{"type":"integer"}},"required":["shown","acted"],"description":"近 7 天出现几次、响应几次"},"PromptSettingsState":{"type":"object","properties":{"settings":{"$ref":"#/components/schemas/PromptSettings"},"stats":{"type":"object","properties":{"untimed":{"$ref":"#/components/schemas/PromptKindStats"},"stale_timer":{"$ref":"#/components/schemas/PromptKindStats"},"due":{"$ref":"#/components/schemas/PromptKindStats"},"late_start":{"$ref":"#/components/schemas/PromptKindStats"},"day_end":{"$ref":"#/components/schemas/PromptKindStats"},"weekly":{"$ref":"#/components/schemas/PromptKindStats"}},"required":["untimed","stale_timer","due","late_start","day_end","weekly"]},"lang":{"type":"string","enum":["zh","en"]}},"required":["settings","stats","lang"]},"TokenSet":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"const":"Bearer","type":"string"},"expires_in":{"type":"integer"},"refresh_token":{"type":"string"},"scope":{"type":"string"}},"required":["access_token","token_type","expires_in","refresh_token","scope"]},"JsonRpcRequest":{"type":"object","properties":{"jsonrpc":{"const":"2.0","type":"string"},"id":{"anyOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"method":{"type":"string"},"params":{"type":"object","additionalProperties":true}},"required":["jsonrpc","method"]},"JsonRpcResponse":{"type":"object","properties":{"jsonrpc":{"const":"2.0","type":"string"},"id":{"anyOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"result":{},"error":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"}},"required":["code","message"]}},"required":["jsonrpc","id"]}},"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"设备令牌 td_…(App)或命令行密钥 tk_…(脚本、Agent)"},"deviceCookie":{"type":"apiKey","in":"cookie","name":"today_device","description":"网页设备(httpOnly)"},"cadenceKey":{"type":"apiKey","in":"header","name":"x-cadence-key","description":"设备令牌、命令行密钥,或老的共用密码"},"legacySession":{"type":"apiKey","in":"cookie","name":"cadence_session","description":"老的共用密码登录后的 cookie"},"oauthBrowser":{"type":"apiKey","in":"cookie","name":"today_oauth","description":"发起授权的浏览器(GET /oauth/authorize 写入)"},"oauth2":{"type":"oauth2","description":"Claude / ChatGPT 这类 MCP 连接器;访问令牌只在 /mcp 上认","flows":{"authorizationCode":{"authorizationUrl":"/oauth/authorize","tokenUrl":"/oauth/token","refreshUrl":"/oauth/token","scopes":{"today":"读写这个空间","offline_access":"要刷新令牌(本来就总是发)"}}}}}}}