# 文件编辑锁契约 v1 ## 公共接口 ```text POST /api/v1/files/{storage_object_id}/lock POST /api/v1/file-locks/{edit_session_id}/heartbeat DELETE /api/v1/file-locks/{edit_session_id} ``` 三个接口均要求 `X-User-ID` 和 `X-Workspace-ID`。加锁成功返回一次性原始 `lock_token`;心跳和释放请求体均为: ```json {"lock_token": "raw-token-returned-by-acquire"} ``` 原始 token 只由客户端持有,数据库只保存 SHA-256 摘要。 ## MySQL 租约 `edit_sessions` 是实时锁权威: - `session_status=active` 且 `expires_at > now()` 表示锁有效; - 同一 `storage_object_id` 同时只能存在一个有效编辑会话; - 心跳更新 `last_heartbeat_at` 与 `expires_at`; - 主动释放将状态改为 `closed`; - 后台清理将超时租约改为 `expired`。 加锁、心跳和释放都在数据库事务中校验 `edit_session_id + lock_token_hash`。 部署时 Runtime 保持单副本;若扩展到多副本,应为加锁查询增加数据库行锁或唯一 租约表约束。 ## 状态与错误 - 冲突返回 HTTP 409、错误码 `FILE_LOCK_CONFLICT`,并包含当前编辑者和租约到期时间; - 错误 token 返回 HTTP 403,且不得续期或释放现有锁; - 浏览器建议每 15 秒心跳,默认租约为 45 秒。