# ReinLoop Server 功能与接口 ## 通用约定 业务接口为 `POST /api`。请求与响应均为 JSON,响应包含 `success`。 标注为 Admin 的接口需要附加: ```json {"adminToken":""} ``` `deviceId` 统一为两段格式:`/`。 ## 服务入口 | 方法 | 路径 | 用途 | | --- | --- | --- | | `POST` | `/api` | 主业务 API | | `POST` | `/upload/:token` | 根据上传凭证接收 multipart 文件 | | `GET` | `/files/:fileID` | 下载已存储文件 | | `GET` | `/health` | 服务存活检查 | ## 设备心跳与组织 | type | 鉴权 | 请求字段 | 功能与响应要点 | | --- | --- | --- | --- | | `deviceHeartbeat` | 无 | `deviceId` | 已登记设备每 10 秒上报。返回 `deviceId`、服务器记录的 `lastSeenAt`;未登记设备失败。 | | `listOrganizations` | Admin | 无 | 返回 `companies`,每家公司包含 `productionLines`。产线包含 `id`、`companyId`、`name`、`code`、`deviceId`、`lastSeenAt`、`online`。最近 30 秒有心跳时 `online` 为 `true`。 | | `createCompany` | Admin | `name`、`code` | 创建公司。`code` 全局唯一,只允许 2-64 位小写字母、数字、`_`、`-`。 | | `createProductionLine` | Admin | `companyId`、`name`、`code` | 创建产线。产线编码在公司内唯一;服务端固定生成 `/`。 | Panel 应每 10 秒调用 `listOrganizations` 刷新在线状态,不应自行推测设备状态。 ## 许可证 | type | 鉴权 | 请求字段 | 功能与响应要点 | | --- | --- | --- | --- | | `createLicense` | Admin | `licenseId`、`companyId`、`productionLineId`、`customer`、`issued`、`expiry`、`features`、`license` | 创建已签名许可证。服务端以 RSA-PSS 公钥验签,校验签名载荷、组织关系和设备 ID。`issued`/`expiry` 使用 `YYYY-MM-DD HH:MM`,按 `Asia/Shanghai` 解析并存为 UTC。相同 ID 和内容幂等成功,不同内容冲突。 | | `listLicenses` | Admin | 无 | 返回许可证摘要列表,不返回原始 `license`。 | | `getLicense` | Admin | `licenseId` | 返回完整许可证详情,可包含原始 `license`。 | | `revokeLicense` | Admin | `licenseId`、`reason` | 撤销许可证,保留历史、撤销时间和原因。`licenseId` 会去除首尾空白。失败时返回 `errCode`:`ADMIN_TOKEN_INVALID`、`ADMIN_TOKEN_NOT_CONFIGURED`、`LICENSE_ID_REQUIRED` 或 `LICENSE_NOT_FOUND`。兼容旧类型 `revoke_license`、`licenseRevoke`、`revoke`,以及旧字段 `license_id`、`admin_token`。每次撤销会记录不含令牌的结构化审计日志。 | | `validateLicense` | 无 | `licenseId`、`deviceId` | 返回 `valid`、`status`、`licenseId`。状态为 `active`、`revoked`、`expired`、`not_found` 或 `device_mismatch`;不泄露客户信息和许可证原文。 | 许可证格式为 `payloadBase64|signatureBase64`。服务端只读取 `LICENSE_PUBLIC_KEY_PATH` 的公钥,绝不接收或保存 RSA 私钥。 ## 文件与模型 | type | 鉴权 | 请求字段 | 功能与响应要点 | | --- | --- | --- | --- | | `uploadDataFile` | 视目录而定 | `fileName`、`folder` | 签发通用两步上传凭证。目录为 `*/model_config` 时必须 Admin;其他既有 ReinLoop 数据上传保持兼容。 | | `issueModelUpload` | Admin | `deviceId`、`fileName`、可选 `modelName`、`overwrite` | `fileName` 是本地原始文件名;传入 `modelName` 时以该名称存储和识别模型,并保留 `originalFileName`。同名模型已存在时返回 `conflict: true`;仅 `overwrite: true` 可签发覆盖凭证。 | | `listModels` | 无 | `folder` | 返回 `files` 当前模型名数组和 `fileList` 元数据数组,最多 100 条;每条同时包含 `fileName` 和 `originalFileName`。 | | `downloadModel` | 视文件而定 | `fileID` | 模型保持兼容;非模型文件要求 Admin 并返回短期签名下载 URL。 | | `deleteFile` | Admin | `fileID`,或 `folder` 与 `fileName` | 删除文件及元数据;同名文件不唯一时必须使用 `fileID`。 | | `deleteModel` | Admin | 同 `deleteFile` | 模型删除的明确管理端别名。 | 上传分两步:先调用 `uploadDataFile` 或 `issueModelUpload`,再将文件作为 `multipart/form-data` 的 `file` 字段提交到响应中的 `uploadMetadata.url`。上传成功返回 HTTP `204`;响应中的 `fileID` 可用于下载和删除。 模型重命名不会修改文件格式,因此 `modelName` 与原始 `fileName` 的扩展名必须一致。未传 `modelName` 时两者相同,旧客户端行为不变。 上传到 `/ind_data` 的 `.csv`、`.json` 会自动进入 Panel inbox。 ## 配置发布与读取 | type | 鉴权 | 请求字段 | 功能与响应要点 | | --- | --- | --- | --- | | `publishIdentificationConfig` | Admin | `deviceId`、`parameters` | 校验辨识参数并为 `/identification_config/identification_config.csv` 签发上传凭证。 | | `getIdentificationConfig` | 无 | `deviceId` | 返回该设备辨识 CSV 的 `fileID` 和 `url`。 | | `publishVolumeConfig` | Admin | `parameters` | 校验容积参数并签发 `volume_config.json` 上传凭证。上传完成后更新功能参数记录。 | | `getVolumeConfigFile` | 无 | 无 | 返回已发布容积 JSON 的 `fileID`、`cloudPath`、`url`。 | | `getFunctionConfig` | 无 | `configType: "volume"` | 返回已发布容积参数的 `parameters`、`version`、`updateTime`。 | 发布接口仅签发上传凭证;客户端完成二步上传后,读取接口才会返回新文件或参数。 ## 辨识结果与 Panel 收件箱 | type | 鉴权 | 请求字段 | 功能与响应要点 | | --- | --- | --- | --- | | `registerIdentificationResult` | 无 | `deviceId`、`runId`、可选 `fileName` | ReinLoop 登记待审核辨识结果。 | | `getIdentificationFeedback` | 无 | `deviceId`、`runId` | 未就绪时 `ready: false`;就绪时返回 `ready: true` 和 `result`(`0` 或 `1`)。 | | `setIdentificationFeedback` | Admin | `deviceId`、可选 `runId`、`result` | Panel 提交辨识审核结果,`result` 必须为数字 `0` 或 `1`。 | | `ackIdentificationFeedback` | 无 | `deviceId`、`runId` | ReinLoop 消费后清理反馈。 | | `getPendingPanelFile` | Admin | `deviceId` | 获取指定设备下一条待处理 CSV/JSON;无数据时 `pending: false`,有数据时返回文件信息和 `url`。 | | `ackPanelFile` | Admin | `deviceId`、`fileID` | Panel 处理完成后确认,移除 inbox 项并标记历史记录为 `processed`,不立即删除文件。 | | `listIdentificationFiles` | Admin | `deviceId`、可选 `mediaType`、`status`、`page`、`pageSize` | 分页返回设备的辨识 CSV/JSON 暂存历史。 | | `getIdentificationFileDownload` | Admin | `fileID` | 返回原始辨识文件的短期签名下载 URL。 | | `deleteIdentificationFile` | Admin | `fileID` | 显式删除辨识文件、历史记录及待处理消息。 | CSV 辨识文件须先以同名 `runId` 调用 `registerIdentificationResult`,才会出现在 `getPendingPanelFile`;初始行程 JSON 可直接获取。 已处理文件默认保留 30 天,从 `processedAt` 开始计算;待处理文件不会被 TTL 清理。 保留时长和清理周期分别由 `IDENTIFICATION_RETENTION_MS`、`IDENTIFICATION_PURGE_INTERVAL_MS` 配置。 ## 容积配置请求 | type | 鉴权 | 请求字段 | 功能与响应要点 | | --- | --- | --- | --- | | `createVolumeConfigRequest` | 无 | `deviceId` | ReinLoop 创建一次性上传请求,返回 `requestId`、`createdAtMs`、`expiresAtMs`。同设备旧请求会被替换。 | | `getPendingVolumeConfigRequest` | 无 | `deviceId` | 查询是否存在待上传请求,返回 `pending` 和请求时间信息。 | | `submitVolumeConfigFile` | 无 | `deviceId`、`requestId`、`fileID`、可选 `fileName` | 将已上传到 `/volume_config_requests//` 的文件绑定至请求。 | | `getVolumeConfigRequest` | 无 | `deviceId`、`requestId` | 轮询配置是否就绪,返回 `ready`、`expired`;就绪时包含下载 `url`。 | | `ackVolumeConfigRequest` | 无 | `deviceId`、`requestId` | ReinLoop 下载完成后确认,清理请求及关联文件。 | 请求有效期由 `VOLUME_REQUEST_TTL_MS` 控制,默认 300000 毫秒(5 分钟)。