Build Pigway Frame Flow with bilingual UI, complete KoKonna driver and safe automation
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
# Optional external integration contract
|
||||
|
||||
Ticktar integration is optional. Frame Flow has no runtime dependency on Ticktar.
|
||||
No external client receives a KoKonna API key, accesses the SQLite database, or
|
||||
imports a vendor SDK. Web UI and external clients use the same application services.
|
||||
|
||||
## Architecture
|
||||
|
||||
External client → /api/v1 → Application / DisplayService → FrameDeviceDriver → KoKonna.
|
||||
Configure the caller with FRAME_FLOW_URL and FRAME_FLOW_TOKEN only. No caller-specific
|
||||
branch exists in core. Frame Flow starts and works with no integration configuration.
|
||||
|
||||
## Authentication and permissions
|
||||
|
||||
Authorization: Bearer FRAME_FLOW_TOKEN. The bootstrap token is provided through
|
||||
.env or a secret file; database stores SHA-256 hash only. The client model supports
|
||||
client_id, name, permissions, enabled, created_at, last_used_at. Permissions:
|
||||
devices:read, images:read, images:delete, display:write, templates:read, render:write,
|
||||
jobs:read, jobs:write, history:read, settings:write, admin.
|
||||
0.1.0 seeds one admin token; provisioning scoped client rows is supported by middleware
|
||||
but multi-token management UI is not implemented. Use a trusted server-to-server
|
||||
connection; CORS is opt-in by exact origins, never wildcard by default.
|
||||
|
||||
## Discovery and capabilities
|
||||
|
||||
GET /api/v1/devices; GET /api/v1/devices/{id}; GET /api/v1/templates.
|
||||
Device provides id/name/status, display geometry, power, current_content, firmware,
|
||||
model/model_code, timezone, last_seen_at, capabilities. Model fallback is flagged
|
||||
model_verified=false when the cloud omits model fields. Do not branch on driver:
|
||||
check capabilities upload/gallery/delete/switch/battery/color/remote_refresh.
|
||||
Native slideshow members/editing are unavailable in KoKonna's documented API.
|
||||
|
||||
## Display
|
||||
|
||||
POST /api/v1/display, Idempotency-Key: a-unique-client-request-key
|
||||
|
||||
```json
|
||||
{
|
||||
"device_id": "living-room",
|
||||
"content": {
|
||||
"type": "template",
|
||||
"template": "daily-dashboard",
|
||||
"data": {"title": "Good Morning", "events": []},
|
||||
"profile": "color"
|
||||
},
|
||||
"options": {"duration": 1800, "restore_previous": true, "priority": 50},
|
||||
"source": {"client": "external-app", "request_id": "caller-trace"}
|
||||
}
|
||||
```
|
||||
|
||||
Content supports image (exactly one image_id/image_name/asset_id/base64), image_url
|
||||
(HTTPS/public DNS/exact allowlist), template. html/markdown explicitly return
|
||||
UNSUPPORTED_CAPABILITY. For upload-only use device /upload with display_now=false;
|
||||
this is safe local staging because KoKonna cloud upload always activates an image.
|
||||
|
||||
Returns HTTP 202: {operation_id, job_id, status:"accepted"}. job_id is a legacy
|
||||
acceptance alias for operation_id, not a scheduler job ID.
|
||||
|
||||
## Render and operations
|
||||
|
||||
POST /api/v1/render with template content returns 202 and a local rendered asset
|
||||
when completed; no device write. GET /api/v1/operations/{operation_id}:
|
||||
QUEUED → RENDERING → UPLOADING → SYNCING → COMPLETED / FAILED / UNKNOWN.
|
||||
Result includes image_id or asset_id/url. SYNCING confirms imageId plus synced
|
||||
through read-only device status; there is no documented physical-screen telemetry.
|
||||
Token must own the operation or be admin. Never interpret HTTP 202 as refreshed.
|
||||
|
||||
## Idempotency
|
||||
|
||||
Key is scoped to authenticated client, retained seven days. Same key and same
|
||||
normalized action/body returns the same operation, even across restart. A different
|
||||
body with the same key returns CONFLICT (409). Do not retry UNKNOWN with a new key.
|
||||
Cloud writes have no automatic retries. UNKNOWN blocks further device writes;
|
||||
admin /operations/{id}/reconcile reads device/gallery and may acknowledge a manually
|
||||
verified outcome without reissuing a write.
|
||||
|
||||
## Errors and tracing
|
||||
|
||||
All API errors: {error:{code,message,request_id,details:{}}}. Stable codes include
|
||||
INVALID_REQUEST, UNAUTHORIZED, FORBIDDEN, DEVICE_NOT_FOUND, DEVICE_OFFLINE,
|
||||
UNSUPPORTED_CAPABILITY, RENDER_FAILED, UPLOAD_FAILED, WRITE_RESULT_UNKNOWN,
|
||||
RATE_LIMITED, INTERNAL_ERROR, CONFIG_REQUIRED, WRITE_DISABLED, CONFLICT, NOT_FOUND,
|
||||
CLOUD_UNAVAILABLE. Use code, not message text. Validation does not echo inputs.
|
||||
X-Request-ID accepts a bounded safe identifier; it is returned on the response.
|
||||
The authenticated client is authoritative; source.client is optional metadata.
|
||||
History stores client_id/request_id/operation_id/device_id/action/result/timestamp.
|
||||
No internal endpoints, headers, stacks, paths or secrets are returned.
|
||||
|
||||
## Future webhook
|
||||
|
||||
SQLite events and webhook_subscriptions reserve operation.completed/failed,
|
||||
display.changed, device.online/offline/low_battery events. 0.1.0 emits operation/display
|
||||
events only; no callback delivery, retry worker or registration API is implemented.
|
||||
Future deliveries should use signed payloads and bounded retries.
|
||||
OAuth, tenancy, RBAC management and generated SDKs are future work.
|
||||
|
||||
## Compatibility
|
||||
|
||||
/openapi.json and /docs are the contract. Snapshot tests cover paths, response
|
||||
codes, standard device fields, security and operation enums. Static snapshot is
|
||||
also supplied in docs/openapi.json. Breaking changes require /api/v2.
|
||||
Reference in New Issue
Block a user