156 lines
2.8 KiB
Markdown
156 lines
2.8 KiB
Markdown
# Mobile Integration Spec (Stage 1)
|
|
|
|
## Base URL
|
|
|
|
- Processor endpoints are mounted under `/api/v1/mobile`.
|
|
|
|
## Headers
|
|
|
|
- Optional: `x-flow-id` for end-to-end trace correlation.
|
|
- Required for ping/sync endpoints: `x-device-id` with a previously registered `externalDeviceId`.
|
|
|
|
## Endpoints
|
|
|
|
### Register Device
|
|
|
|
- Method: `POST`
|
|
- Path: `/api/v1/mobile/register`
|
|
- Auth: none (trusted private network assumption)
|
|
|
|
Payload:
|
|
|
|
```json
|
|
{
|
|
"externalDeviceId": "android-1234",
|
|
"name": "Pixel 8 Pro",
|
|
"manufacturer": "Google",
|
|
"model": "Pixel 8 Pro",
|
|
"androidVersion": "15"
|
|
}
|
|
```
|
|
|
|
### Ping Device
|
|
|
|
- Method: `PUT`
|
|
- Path: `/api/v1/mobile/ping`
|
|
- Required header: `x-device-id`
|
|
|
|
Payload:
|
|
|
|
```json
|
|
{
|
|
"pingAt": "2026-03-01T10:15:00.000Z"
|
|
}
|
|
```
|
|
|
|
### Sync SMS
|
|
|
|
- Method: `PUT`
|
|
- Path: `/api/v1/mobile/sms/sync`
|
|
- Required header: `x-device-id`
|
|
|
|
Payload:
|
|
|
|
```json
|
|
{
|
|
"messages": [
|
|
{
|
|
"externalMessageId": "msg-1",
|
|
"sender": "+358401111111",
|
|
"recipient": "+358402222222",
|
|
"body": "Hello from device",
|
|
"sentAt": "2026-03-01T10:10:00.000Z",
|
|
"receivedAt": "2026-03-01T10:10:01.000Z",
|
|
"rawPayload": {
|
|
"threadId": "7"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Sync Media Assets
|
|
|
|
- Method: `PUT`
|
|
- Path: `/api/v1/mobile/media/sync`
|
|
- Required header: `x-device-id`
|
|
|
|
Payload:
|
|
|
|
```json
|
|
{
|
|
"assets": [
|
|
{
|
|
"externalMediaId": "media-1",
|
|
"fileId": "01JNE3Q1S3KQX9Y7G2J8G7R0A8",
|
|
"mimeType": "image/jpeg",
|
|
"filename": "IMG_1234.jpg",
|
|
"capturedAt": "2026-03-01T10:05:00.000Z",
|
|
"sizeBytes": 1350021,
|
|
"hash": "sha256-...",
|
|
"metadata": {
|
|
"width": 3024,
|
|
"height": 4032
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Response Contract
|
|
|
|
Success:
|
|
|
|
```json
|
|
{
|
|
"data": {},
|
|
"error": null
|
|
}
|
|
```
|
|
|
|
Failure:
|
|
|
|
```json
|
|
{
|
|
"data": null,
|
|
"error": {
|
|
"flowId": "uuid",
|
|
"code": "VALIDATION_ERROR",
|
|
"message": "Human message",
|
|
"description": "Actionable description",
|
|
"detail": "Technical detail"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Admin Query Contract
|
|
|
|
- Pagination:
|
|
- `page`: 1-based integer
|
|
- `pageSize`: integer
|
|
- Sorting:
|
|
- `sortBy`: operation-specific
|
|
- `sortOrder`: `asc` or `desc`
|
|
- Paginated response payload:
|
|
- `data`: rows
|
|
- `total`: full row count
|
|
- `page`, `pageSize`, `totalPages`
|
|
|
|
## Dedup Rules
|
|
|
|
- Device:
|
|
- Upsert on unique `externalDeviceId`.
|
|
- SMS:
|
|
- Dedup key #1: `(deviceId, externalMessageId)` when provided.
|
|
- Dedup key #2 fallback: `(deviceId, dedupHash)` where dedup hash is SHA-256 of `(deviceId + sentAt + sender + body)`.
|
|
- Media:
|
|
- Dedup key: `(deviceId, externalMediaId)` when provided.
|
|
- `fileId` in `mobile_media_asset` is unique.
|
|
|
|
## Operator Checklist
|
|
|
|
1. Register a device.
|
|
2. Send ping with `x-device-id` and verify dashboard `lastPingAt` updates.
|
|
3. Sync SMS and verify device detail `SMS` tab updates (polling every 5s).
|
|
4. Sync media and verify device detail `Media Assets` tab displays rows.
|