|
|
@@ -0,0 +1,1026 @@
|
|
|
+openapi: 3.1.0
|
|
|
+info:
|
|
|
+ title: Celestia Trace iOS Remote API
|
|
|
+ version: 2026-07-24
|
|
|
+ description: |
|
|
|
+ iOS 客户端实际调用的远程接口契约。
|
|
|
+
|
|
|
+ 维护规则:
|
|
|
+ 1. backend 路由、请求字段或响应字段变化时,先更新本文件,再更新 Swift 模型。
|
|
|
+ 2. 所有 JSON 接口使用统一响应 `{code, message, data}`。
|
|
|
+ 3. 除登录、注册和刷新令牌外,接口均使用 Bearer access token。
|
|
|
+ 4. 公网网关保留 `/celestia-trace/v1`;后端 Gin 路由本身使用 `/v1`。
|
|
|
+ 5. 服务端时间使用 RFC 3339 / ISO 8601,客户端同时兼容带或不带小数秒。
|
|
|
+ x-client-sources:
|
|
|
+ - CelestiaTrace/Services/Network/APIClient.swift
|
|
|
+ - CelestiaTrace/Services/Network/RemoteNetworkService.swift
|
|
|
+ - CelestiaTrace/Services/Auth/RemoteAuthService.swift
|
|
|
+servers:
|
|
|
+ - url: https://api.ccdw.life/celestia-trace/v1
|
|
|
+ description: Production
|
|
|
+tags:
|
|
|
+ - name: Health
|
|
|
+ - name: Auth
|
|
|
+ - name: User
|
|
|
+ - name: Devices
|
|
|
+ - name: Sessions
|
|
|
+ - name: Assets
|
|
|
+ - name: Sync
|
|
|
+paths:
|
|
|
+ /health:
|
|
|
+ get:
|
|
|
+ tags: [Health]
|
|
|
+ operationId: getHealth
|
|
|
+ security: []
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: API and database are healthy
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/HealthEnvelope"
|
|
|
+ "503":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+ /auth/register:
|
|
|
+ post:
|
|
|
+ tags: [Auth]
|
|
|
+ operationId: register
|
|
|
+ security: []
|
|
|
+ requestBody:
|
|
|
+ required: true
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/RegisterRequest"
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Account and login session created
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/AuthEnvelope"
|
|
|
+ "400":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "409":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+ /auth/login:
|
|
|
+ post:
|
|
|
+ tags: [Auth]
|
|
|
+ operationId: login
|
|
|
+ security: []
|
|
|
+ requestBody:
|
|
|
+ required: true
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/LoginRequest"
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Login session created
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/AuthEnvelope"
|
|
|
+ "400":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+ /auth/refresh:
|
|
|
+ post:
|
|
|
+ tags: [Auth]
|
|
|
+ operationId: refreshAccessToken
|
|
|
+ security: []
|
|
|
+ requestBody:
|
|
|
+ required: true
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ type: object
|
|
|
+ required: [refreshToken]
|
|
|
+ properties:
|
|
|
+ refreshToken:
|
|
|
+ type: string
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Tokens rotated; the old refresh token is no longer valid
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/AuthEnvelope"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+ /auth/logout:
|
|
|
+ post:
|
|
|
+ tags: [Auth]
|
|
|
+ operationId: logout
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ $ref: "#/components/responses/EmptySuccess"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+ /user/profile:
|
|
|
+ get:
|
|
|
+ tags: [User]
|
|
|
+ operationId: getProfile
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Current user
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/UserEnvelope"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ put:
|
|
|
+ tags: [User]
|
|
|
+ operationId: updateProfile
|
|
|
+ requestBody:
|
|
|
+ required: true
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/UpdateProfileRequest"
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Updated user
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/UserEnvelope"
|
|
|
+ "400":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "409":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+ /user/change-password:
|
|
|
+ post:
|
|
|
+ tags: [User]
|
|
|
+ operationId: changePassword
|
|
|
+ requestBody:
|
|
|
+ required: true
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ type: object
|
|
|
+ required: [oldPassword, newPassword]
|
|
|
+ properties:
|
|
|
+ oldPassword:
|
|
|
+ type: string
|
|
|
+ newPassword:
|
|
|
+ type: string
|
|
|
+ minLength: 6
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ $ref: "#/components/responses/EmptySuccess"
|
|
|
+ "400":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+ /devices:
|
|
|
+ post:
|
|
|
+ tags: [Devices]
|
|
|
+ operationId: bindDevice
|
|
|
+ requestBody:
|
|
|
+ required: true
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/BindDeviceRequest"
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Bound or updated cloud device
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/DeviceEnvelope"
|
|
|
+ "400":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+ /devices/{deviceId}:
|
|
|
+ parameters:
|
|
|
+ - $ref: "#/components/parameters/DeviceId"
|
|
|
+ put:
|
|
|
+ tags: [Devices]
|
|
|
+ operationId: updateDevice
|
|
|
+ requestBody:
|
|
|
+ required: true
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/UpdateDeviceRequest"
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Updated cloud device
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/DeviceEnvelope"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "404":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ delete:
|
|
|
+ tags: [Devices]
|
|
|
+ operationId: unbindDevice
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Device unbound
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/DeleteEnvelope"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "404":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+ /sessions:
|
|
|
+ get:
|
|
|
+ tags: [Sessions]
|
|
|
+ operationId: listSessions
|
|
|
+ parameters:
|
|
|
+ - name: includeDeleted
|
|
|
+ in: query
|
|
|
+ schema:
|
|
|
+ type: boolean
|
|
|
+ default: true
|
|
|
+ description: iOS uses true to receive deletion tombstones.
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: All sessions visible to the current user
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/SessionListEnvelope"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ post:
|
|
|
+ tags: [Sessions]
|
|
|
+ operationId: upsertSession
|
|
|
+ description: |
|
|
|
+ Idempotent upsert by `(userId, clientId)`.
|
|
|
+ Existing sessions must send `baseRevision`; a mismatch returns HTTP/code 409.
|
|
|
+ `deletedEventClientIds` removes events deleted locally since the last pull.
|
|
|
+ requestBody:
|
|
|
+ required: true
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/SessionUpsertRequest"
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Created or updated session
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/SessionEnvelope"
|
|
|
+ "400":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "409":
|
|
|
+ description: Optimistic-lock conflict
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/ConflictEnvelope"
|
|
|
+
|
|
|
+ /sessions/{sessionId}/assets:
|
|
|
+ parameters:
|
|
|
+ - $ref: "#/components/parameters/SessionId"
|
|
|
+ post:
|
|
|
+ tags: [Assets]
|
|
|
+ operationId: uploadAsset
|
|
|
+ description: |
|
|
|
+ Used for files smaller than 16 MiB. `clientId` makes retries idempotent.
|
|
|
+ A new upload returns `{asset, sessionRevision}`. An idempotent replay may
|
|
|
+ return the asset directly; the iOS decoder intentionally accepts both.
|
|
|
+ requestBody:
|
|
|
+ required: true
|
|
|
+ content:
|
|
|
+ multipart/form-data:
|
|
|
+ schema:
|
|
|
+ type: object
|
|
|
+ required: [clientId, kind, file]
|
|
|
+ properties:
|
|
|
+ clientId:
|
|
|
+ type: string
|
|
|
+ kind:
|
|
|
+ $ref: "#/components/schemas/AssetKind"
|
|
|
+ file:
|
|
|
+ type: string
|
|
|
+ format: binary
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Uploaded asset or idempotent existing asset
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/AssetUploadEnvelope"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "404":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "413":
|
|
|
+ $ref: "#/components/responses/QuotaError"
|
|
|
+
|
|
|
+ /sessions/{sessionId}/assets/init:
|
|
|
+ parameters:
|
|
|
+ - $ref: "#/components/parameters/SessionId"
|
|
|
+ post:
|
|
|
+ tags: [Assets]
|
|
|
+ operationId: initializeChunkedUpload
|
|
|
+ description: iOS uses this flow for files at least 16 MiB, with 8 MiB chunks.
|
|
|
+ requestBody:
|
|
|
+ required: true
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/ChunkUploadInitRequest"
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Chunked upload initialized
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/ChunkUploadInitEnvelope"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "404":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "413":
|
|
|
+ $ref: "#/components/responses/QuotaError"
|
|
|
+
|
|
|
+ /sessions/{sessionId}/assets/chunk:
|
|
|
+ parameters:
|
|
|
+ - $ref: "#/components/parameters/SessionId"
|
|
|
+ post:
|
|
|
+ tags: [Assets]
|
|
|
+ operationId: uploadChunk
|
|
|
+ requestBody:
|
|
|
+ required: true
|
|
|
+ content:
|
|
|
+ multipart/form-data:
|
|
|
+ schema:
|
|
|
+ type: object
|
|
|
+ required: [uploadId, chunkIndex, file]
|
|
|
+ properties:
|
|
|
+ uploadId:
|
|
|
+ type: string
|
|
|
+ format: uuid
|
|
|
+ chunkIndex:
|
|
|
+ type: integer
|
|
|
+ minimum: 0
|
|
|
+ file:
|
|
|
+ type: string
|
|
|
+ format: binary
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Chunk accepted
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/ChunkProgressEnvelope"
|
|
|
+ "400":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "404":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "410":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+ /sessions/{sessionId}/assets/complete:
|
|
|
+ parameters:
|
|
|
+ - $ref: "#/components/parameters/SessionId"
|
|
|
+ post:
|
|
|
+ tags: [Assets]
|
|
|
+ operationId: completeChunkedUpload
|
|
|
+ requestBody:
|
|
|
+ required: true
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ type: object
|
|
|
+ required: [uploadId, totalChunks]
|
|
|
+ properties:
|
|
|
+ uploadId:
|
|
|
+ type: string
|
|
|
+ format: uuid
|
|
|
+ totalChunks:
|
|
|
+ type: integer
|
|
|
+ minimum: 1
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Chunks merged and asset created
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/AssetUploadEnvelope"
|
|
|
+ "400":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "404":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "410":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+ /sessions/{sessionId}/assets/{assetId}:
|
|
|
+ parameters:
|
|
|
+ - $ref: "#/components/parameters/SessionId"
|
|
|
+ - $ref: "#/components/parameters/AssetId"
|
|
|
+ get:
|
|
|
+ tags: [Assets]
|
|
|
+ operationId: downloadAsset
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Attachment bytes; Content-Disposition contains the original filename
|
|
|
+ content:
|
|
|
+ application/octet-stream:
|
|
|
+ schema:
|
|
|
+ type: string
|
|
|
+ format: binary
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+ "404":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+ /storage/quota:
|
|
|
+ get:
|
|
|
+ tags: [Sync]
|
|
|
+ operationId: getStorageQuota
|
|
|
+ description: Called before uploading the pending assets for a session.
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Current storage quota in bytes
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/StorageQuotaEnvelope"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+ /sync/trigger:
|
|
|
+ post:
|
|
|
+ tags: [Sync]
|
|
|
+ operationId: recordSyncCheckpoint
|
|
|
+ description: Called only after all session metadata and assets finish syncing.
|
|
|
+ responses:
|
|
|
+ "200":
|
|
|
+ description: Client sync checkpoint recorded
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/SyncCheckpointEnvelope"
|
|
|
+ "401":
|
|
|
+ $ref: "#/components/responses/Error"
|
|
|
+
|
|
|
+components:
|
|
|
+ securitySchemes:
|
|
|
+ bearerAuth:
|
|
|
+ type: http
|
|
|
+ scheme: bearer
|
|
|
+ bearerFormat: JWT
|
|
|
+ parameters:
|
|
|
+ DeviceId:
|
|
|
+ name: deviceId
|
|
|
+ in: path
|
|
|
+ required: true
|
|
|
+ schema:
|
|
|
+ type: string
|
|
|
+ format: uuid
|
|
|
+ SessionId:
|
|
|
+ name: sessionId
|
|
|
+ in: path
|
|
|
+ required: true
|
|
|
+ schema:
|
|
|
+ type: string
|
|
|
+ format: uuid
|
|
|
+ AssetId:
|
|
|
+ name: assetId
|
|
|
+ in: path
|
|
|
+ required: true
|
|
|
+ schema:
|
|
|
+ type: string
|
|
|
+ format: uuid
|
|
|
+ responses:
|
|
|
+ EmptySuccess:
|
|
|
+ description: Success without a data payload
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/EmptyEnvelope"
|
|
|
+ Error:
|
|
|
+ description: Request failed
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/ErrorEnvelope"
|
|
|
+ QuotaError:
|
|
|
+ description: Storage quota exceeded
|
|
|
+ content:
|
|
|
+ application/json:
|
|
|
+ schema:
|
|
|
+ $ref: "#/components/schemas/QuotaErrorEnvelope"
|
|
|
+ schemas:
|
|
|
+ EnvelopeBase:
|
|
|
+ type: object
|
|
|
+ required: [code, message]
|
|
|
+ properties:
|
|
|
+ code:
|
|
|
+ type: integer
|
|
|
+ message:
|
|
|
+ type: string
|
|
|
+ EmptyEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ type: "null"
|
|
|
+ ErrorEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ properties:
|
|
|
+ data: {}
|
|
|
+ HealthEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ type: string
|
|
|
+ const: healthy
|
|
|
+ RegisterRequest:
|
|
|
+ type: object
|
|
|
+ required: [username, identifier, password]
|
|
|
+ properties:
|
|
|
+ username:
|
|
|
+ type: string
|
|
|
+ minLength: 2
|
|
|
+ identifier:
|
|
|
+ type: string
|
|
|
+ description: Email address or phone number.
|
|
|
+ password:
|
|
|
+ type: string
|
|
|
+ minLength: 6
|
|
|
+ LoginRequest:
|
|
|
+ type: object
|
|
|
+ required: [identifier, password]
|
|
|
+ properties:
|
|
|
+ identifier:
|
|
|
+ type: string
|
|
|
+ description: Username, email address, or phone number.
|
|
|
+ password:
|
|
|
+ type: string
|
|
|
+ UpdateProfileRequest:
|
|
|
+ type: object
|
|
|
+ properties:
|
|
|
+ username:
|
|
|
+ type: [string, "null"]
|
|
|
+ email:
|
|
|
+ type: [string, "null"]
|
|
|
+ phoneNumber:
|
|
|
+ type: [string, "null"]
|
|
|
+ avatarURL:
|
|
|
+ type: [string, "null"]
|
|
|
+ User:
|
|
|
+ type: object
|
|
|
+ required: [id, username, registeredAt]
|
|
|
+ properties:
|
|
|
+ id:
|
|
|
+ type: string
|
|
|
+ format: uuid
|
|
|
+ username:
|
|
|
+ type: string
|
|
|
+ email:
|
|
|
+ type: string
|
|
|
+ phoneNumber:
|
|
|
+ type: string
|
|
|
+ avatarURL:
|
|
|
+ type: string
|
|
|
+ format: uri
|
|
|
+ registeredAt:
|
|
|
+ type: string
|
|
|
+ format: date-time
|
|
|
+ updatedAt:
|
|
|
+ type: string
|
|
|
+ format: date-time
|
|
|
+ AuthData:
|
|
|
+ type: object
|
|
|
+ required: [user, token, refreshToken, expiresAt]
|
|
|
+ properties:
|
|
|
+ user:
|
|
|
+ $ref: "#/components/schemas/User"
|
|
|
+ token:
|
|
|
+ type: string
|
|
|
+ description: Short-lived access JWT.
|
|
|
+ refreshToken:
|
|
|
+ type: string
|
|
|
+ description: Rotated on every refresh.
|
|
|
+ expiresAt:
|
|
|
+ type: string
|
|
|
+ format: date-time
|
|
|
+ AuthEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ $ref: "#/components/schemas/AuthData"
|
|
|
+ UserEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ $ref: "#/components/schemas/User"
|
|
|
+ BindDeviceRequest:
|
|
|
+ type: object
|
|
|
+ required: [name]
|
|
|
+ properties:
|
|
|
+ name:
|
|
|
+ type: string
|
|
|
+ peripheralUUID:
|
|
|
+ type: string
|
|
|
+ hardwareMAC:
|
|
|
+ type: [string, "null"]
|
|
|
+ firmwareVersion:
|
|
|
+ type: [string, "null"]
|
|
|
+ batteryLevel:
|
|
|
+ type: [integer, "null"]
|
|
|
+ minimum: 0
|
|
|
+ maximum: 100
|
|
|
+ freeStorageMB:
|
|
|
+ type: [integer, "null"]
|
|
|
+ totalStorageMB:
|
|
|
+ type: [integer, "null"]
|
|
|
+ UpdateDeviceRequest:
|
|
|
+ type: object
|
|
|
+ properties:
|
|
|
+ name:
|
|
|
+ type: [string, "null"]
|
|
|
+ batteryLevel:
|
|
|
+ type: [integer, "null"]
|
|
|
+ minimum: 0
|
|
|
+ maximum: 100
|
|
|
+ isConnected:
|
|
|
+ type: [boolean, "null"]
|
|
|
+ firmwareVersion:
|
|
|
+ type: [string, "null"]
|
|
|
+ freeStorageMB:
|
|
|
+ type: [integer, "null"]
|
|
|
+ totalStorageMB:
|
|
|
+ type: [integer, "null"]
|
|
|
+ Device:
|
|
|
+ type: object
|
|
|
+ required: [id, name, peripheralUUID]
|
|
|
+ properties:
|
|
|
+ id:
|
|
|
+ type: string
|
|
|
+ format: uuid
|
|
|
+ userId:
|
|
|
+ type: string
|
|
|
+ format: uuid
|
|
|
+ name:
|
|
|
+ type: string
|
|
|
+ peripheralUUID:
|
|
|
+ type: string
|
|
|
+ hardwareMAC:
|
|
|
+ type: string
|
|
|
+ batteryLevel:
|
|
|
+ type: integer
|
|
|
+ firmwareVersion:
|
|
|
+ type: string
|
|
|
+ freeStorageMB:
|
|
|
+ type: integer
|
|
|
+ totalStorageMB:
|
|
|
+ type: integer
|
|
|
+ isConnected:
|
|
|
+ type: boolean
|
|
|
+ boundAt:
|
|
|
+ type: string
|
|
|
+ format: date-time
|
|
|
+ updatedAt:
|
|
|
+ type: string
|
|
|
+ format: date-time
|
|
|
+ DeviceEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ $ref: "#/components/schemas/Device"
|
|
|
+ EventUpsert:
|
|
|
+ type: object
|
|
|
+ required: [clientId, relativeTimeMs, eventType]
|
|
|
+ properties:
|
|
|
+ clientId:
|
|
|
+ type: string
|
|
|
+ relativeTimeMs:
|
|
|
+ type: integer
|
|
|
+ format: int64
|
|
|
+ eventType:
|
|
|
+ type: string
|
|
|
+ enum: [PHOTO, NOTE, MARKER, VOICE, CONTINUATION]
|
|
|
+ textContent:
|
|
|
+ type: [string, "null"]
|
|
|
+ voiceStartOffsetMs:
|
|
|
+ type: [integer, "null"]
|
|
|
+ format: int64
|
|
|
+ voiceEndOffsetMs:
|
|
|
+ type: [integer, "null"]
|
|
|
+ format: int64
|
|
|
+ SessionUpsertRequest:
|
|
|
+ type: object
|
|
|
+ required: [clientId, title, startTime, durationMs, events, deletedEventClientIds]
|
|
|
+ properties:
|
|
|
+ clientId:
|
|
|
+ type: string
|
|
|
+ title:
|
|
|
+ type: string
|
|
|
+ startTime:
|
|
|
+ type: string
|
|
|
+ format: date-time
|
|
|
+ endTime:
|
|
|
+ type: [string, "null"]
|
|
|
+ format: date-time
|
|
|
+ durationMs:
|
|
|
+ type: integer
|
|
|
+ format: int64
|
|
|
+ events:
|
|
|
+ type: array
|
|
|
+ items:
|
|
|
+ $ref: "#/components/schemas/EventUpsert"
|
|
|
+ baseRevision:
|
|
|
+ type: [integer, "null"]
|
|
|
+ format: int64
|
|
|
+ deletedEventClientIds:
|
|
|
+ type: array
|
|
|
+ items:
|
|
|
+ type: string
|
|
|
+ RemoteEvent:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EventUpsert"
|
|
|
+ - type: object
|
|
|
+ required: [id]
|
|
|
+ properties:
|
|
|
+ id:
|
|
|
+ type: string
|
|
|
+ format: uuid
|
|
|
+ clientId:
|
|
|
+ type: [string, "null"]
|
|
|
+ createdAt:
|
|
|
+ type: string
|
|
|
+ format: date-time
|
|
|
+ RemoteSession:
|
|
|
+ type: object
|
|
|
+ required: [id, title, startTime, durationMs, revision]
|
|
|
+ properties:
|
|
|
+ id:
|
|
|
+ type: string
|
|
|
+ format: uuid
|
|
|
+ clientId:
|
|
|
+ type: [string, "null"]
|
|
|
+ title:
|
|
|
+ type: string
|
|
|
+ startTime:
|
|
|
+ type: string
|
|
|
+ format: date-time
|
|
|
+ endTime:
|
|
|
+ type: [string, "null"]
|
|
|
+ format: date-time
|
|
|
+ durationMs:
|
|
|
+ type: integer
|
|
|
+ format: int64
|
|
|
+ revision:
|
|
|
+ type: integer
|
|
|
+ format: int64
|
|
|
+ deletedAt:
|
|
|
+ type: [string, "null"]
|
|
|
+ format: date-time
|
|
|
+ events:
|
|
|
+ type: array
|
|
|
+ items:
|
|
|
+ $ref: "#/components/schemas/RemoteEvent"
|
|
|
+ assets:
|
|
|
+ type: array
|
|
|
+ items:
|
|
|
+ $ref: "#/components/schemas/Asset"
|
|
|
+ SessionEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ $ref: "#/components/schemas/RemoteSession"
|
|
|
+ SessionListEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ type: array
|
|
|
+ items:
|
|
|
+ $ref: "#/components/schemas/RemoteSession"
|
|
|
+ ConflictEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ type: object
|
|
|
+ required: [serverRevision]
|
|
|
+ properties:
|
|
|
+ serverRevision:
|
|
|
+ type: integer
|
|
|
+ format: int64
|
|
|
+ AssetKind:
|
|
|
+ type: string
|
|
|
+ enum: [AUDIO, PHOTO]
|
|
|
+ Asset:
|
|
|
+ type: object
|
|
|
+ required: [id, clientId, kind, fileName, mimeType, sizeBytes, sha256]
|
|
|
+ properties:
|
|
|
+ id:
|
|
|
+ type: string
|
|
|
+ format: uuid
|
|
|
+ clientId:
|
|
|
+ type: string
|
|
|
+ kind:
|
|
|
+ $ref: "#/components/schemas/AssetKind"
|
|
|
+ fileName:
|
|
|
+ type: string
|
|
|
+ mimeType:
|
|
|
+ type: string
|
|
|
+ sizeBytes:
|
|
|
+ type: integer
|
|
|
+ format: int64
|
|
|
+ sha256:
|
|
|
+ type: string
|
|
|
+ pattern: "^[a-fA-F0-9]{64}$"
|
|
|
+ createdAt:
|
|
|
+ type: string
|
|
|
+ format: date-time
|
|
|
+ AssetUploadData:
|
|
|
+ type: object
|
|
|
+ required: [asset, sessionRevision]
|
|
|
+ properties:
|
|
|
+ asset:
|
|
|
+ $ref: "#/components/schemas/Asset"
|
|
|
+ sessionRevision:
|
|
|
+ type: integer
|
|
|
+ format: int64
|
|
|
+ AssetUploadEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ oneOf:
|
|
|
+ - $ref: "#/components/schemas/AssetUploadData"
|
|
|
+ - $ref: "#/components/schemas/Asset"
|
|
|
+ ChunkUploadInitRequest:
|
|
|
+ type: object
|
|
|
+ required: [clientId, kind, fileName, mimeType, fileSize, chunkSize]
|
|
|
+ properties:
|
|
|
+ clientId:
|
|
|
+ type: string
|
|
|
+ kind:
|
|
|
+ $ref: "#/components/schemas/AssetKind"
|
|
|
+ fileName:
|
|
|
+ type: string
|
|
|
+ mimeType:
|
|
|
+ type: string
|
|
|
+ fileSize:
|
|
|
+ type: integer
|
|
|
+ format: int64
|
|
|
+ minimum: 1
|
|
|
+ chunkSize:
|
|
|
+ type: integer
|
|
|
+ minimum: 1
|
|
|
+ ChunkUploadInitEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ type: object
|
|
|
+ required: [uploadId, totalChunks, chunkSize, expiresAt]
|
|
|
+ properties:
|
|
|
+ uploadId:
|
|
|
+ type: string
|
|
|
+ format: uuid
|
|
|
+ totalChunks:
|
|
|
+ type: integer
|
|
|
+ chunkSize:
|
|
|
+ type: integer
|
|
|
+ expiresAt:
|
|
|
+ type: string
|
|
|
+ format: date-time
|
|
|
+ ChunkProgressEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ type: object
|
|
|
+ required: [uploadId, chunkIndex, uploadedChunks, totalChunks]
|
|
|
+ properties:
|
|
|
+ uploadId:
|
|
|
+ type: string
|
|
|
+ format: uuid
|
|
|
+ chunkIndex:
|
|
|
+ type: integer
|
|
|
+ uploadedChunks:
|
|
|
+ type: integer
|
|
|
+ totalChunks:
|
|
|
+ type: integer
|
|
|
+ StorageQuota:
|
|
|
+ type: object
|
|
|
+ required: [totalBytes, usedBytes, remainingBytes]
|
|
|
+ properties:
|
|
|
+ totalBytes:
|
|
|
+ type: integer
|
|
|
+ format: int64
|
|
|
+ usedBytes:
|
|
|
+ type: integer
|
|
|
+ format: int64
|
|
|
+ remainingBytes:
|
|
|
+ type: integer
|
|
|
+ format: int64
|
|
|
+ StorageQuotaEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ $ref: "#/components/schemas/StorageQuota"
|
|
|
+ QuotaErrorEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/StorageQuota"
|
|
|
+ - type: object
|
|
|
+ required: [requiredBytes]
|
|
|
+ properties:
|
|
|
+ requiredBytes:
|
|
|
+ type: integer
|
|
|
+ format: int64
|
|
|
+ SyncCheckpointEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ type: object
|
|
|
+ required: [syncedAt, message]
|
|
|
+ properties:
|
|
|
+ syncedAt:
|
|
|
+ type: string
|
|
|
+ format: date-time
|
|
|
+ message:
|
|
|
+ type: string
|
|
|
+ DeleteEnvelope:
|
|
|
+ allOf:
|
|
|
+ - $ref: "#/components/schemas/EnvelopeBase"
|
|
|
+ - type: object
|
|
|
+ required: [data]
|
|
|
+ properties:
|
|
|
+ data:
|
|
|
+ type: object
|
|
|
+ required: [deletedId]
|
|
|
+ properties:
|
|
|
+ deletedId:
|
|
|
+ type: string
|
|
|
+
|
|
|
+security:
|
|
|
+ - bearerAuth: []
|