From d1649ddfce019f7b86497befb72c401598595cf4 Mon Sep 17 00:00:00 2001 From: "Christoph K." Date: Tue, 7 Apr 2026 19:03:03 +0200 Subject: [PATCH] Add OpenAPI 3.1 spec for REST API Covers all endpoints: health, trackpoint ingest (single + batch), query (days, trackpoints, stops, suggestions), journal entry creation. Co-Authored-By: Claude Sonnet 4.6 --- openapi.yaml | 465 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100644 openapi.yaml diff --git a/openapi.yaml b/openapi.yaml new file mode 100644 index 0000000..f2c5cbf --- /dev/null +++ b/openapi.yaml @@ -0,0 +1,465 @@ +openapi: 3.1.0 + +info: + title: Pamietnik API + version: 0.1.0 + description: Life & travel journal — REST API for trackpoint ingest and data query. + +servers: + - url: http://192.168.1.4:9050 + description: NAS (local) + - url: http://localhost:9050 + description: Local dev + +security: + - cookieAuth: [] + +paths: + + /healthz: + get: + summary: Health check + security: [] + responses: + '200': + description: Server is up + content: + text/plain: + example: ok + + /readyz: + get: + summary: Readiness check + security: [] + responses: + '200': + description: Server is ready + + # --- Ingest --- + + /v1/trackpoints: + post: + summary: Ingest single trackpoint + tags: [Ingest] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TrackpointInput' + responses: + '200': + description: Accepted (or duplicate — idempotent) + content: + application/json: + schema: + $ref: '#/components/schemas/BatchResponse' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + + /v1/trackpoints:batch: + post: + summary: Ingest batch of trackpoints (max 500) + tags: [Ingest] + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/TrackpointInput' + maxItems: 500 + responses: + '200': + description: Processed — check accepted_ids and rejected for details + content: + application/json: + schema: + $ref: '#/components/schemas/BatchResponse' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + + # --- Query --- + + /v1/days: + get: + summary: List days with trackpoint activity + tags: [Query] + parameters: + - name: from + in: query + required: true + schema: + type: string + format: date + example: '2026-01-01' + - name: to + in: query + required: true + schema: + type: string + format: date + example: '2026-12-31' + responses: + '200': + description: List of days + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/DaySummary' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + + /v1/trackpoints: + get: + summary: List trackpoints for a date + tags: [Query] + parameters: + - name: date + in: query + required: true + schema: + type: string + format: date + example: '2026-04-07' + responses: + '200': + description: List of trackpoints + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Trackpoint' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + + /v1/stops: + get: + summary: List stops for a date + tags: [Query] + parameters: + - name: date + in: query + required: true + schema: + type: string + format: date + example: '2026-04-07' + responses: + '200': + description: List of stops + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Stop' + '401': + $ref: '#/components/responses/Unauthorized' + + /v1/suggestions: + get: + summary: List suggestions for a date + tags: [Query] + parameters: + - name: date + in: query + required: true + schema: + type: string + format: date + example: '2026-04-07' + responses: + '200': + description: List of suggestions + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Suggestion' + '401': + $ref: '#/components/responses/Unauthorized' + + # --- Journal --- + + /entries: + post: + summary: Create journal entry with optional images + tags: [Journal] + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + required: [date, time] + properties: + date: + type: string + format: date + example: '2026-04-07' + time: + type: string + example: '14:30' + title: + type: string + description: + type: string + lat: + type: number + format: double + lon: + type: number + format: double + images: + type: array + items: + type: string + format: binary + description: JPEG, PNG, WebP or HEIC — max 10 MB each, 32 MB total + responses: + '201': + description: Entry created + content: + application/json: + schema: + $ref: '#/components/schemas/JournalEntry' + '400': + $ref: '#/components/responses/BadRequest' + '401': + $ref: '#/components/responses/Unauthorized' + +components: + + securitySchemes: + cookieAuth: + type: apiKey + in: cookie + name: session + + responses: + BadRequest: + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + Unauthorized: + description: Not authenticated + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + + schemas: + + TrackpointInput: + type: object + required: [event_id, device_id, trip_id, timestamp, lat, lon] + properties: + event_id: + type: string + format: uuid + description: Client-generated UUID — used for idempotency + device_id: + type: string + trip_id: + type: string + timestamp: + type: string + format: date-time + example: '2026-04-07T12:00:00Z' + lat: + type: number + format: double + minimum: -90 + maximum: 90 + lon: + type: number + format: double + minimum: -180 + maximum: 180 + source: + type: string + enum: [gps, manual] + default: gps + note: + type: string + accuracy_m: + type: number + format: double + speed_mps: + type: number + format: double + bearing_deg: + type: number + format: double + altitude_m: + type: number + format: double + + Trackpoint: + allOf: + - $ref: '#/components/schemas/TrackpointInput' + + BatchResponse: + type: object + properties: + server_time: + type: string + format: date-time + accepted_ids: + type: array + items: + type: string + rejected: + type: array + items: + $ref: '#/components/schemas/RejectedItem' + + RejectedItem: + type: object + properties: + event_id: + type: string + code: + type: string + enum: [VALIDATION_ERROR, DB_ERROR, INVALID_TIMESTAMP] + message: + type: string + + DaySummary: + type: object + properties: + date: + type: string + format: date + count: + type: integer + first_ts: + type: string + format: date-time + last_ts: + type: string + format: date-time + + Stop: + type: object + properties: + stop_id: + type: string + device_id: + type: string + trip_id: + type: string + start_ts: + type: string + format: date-time + end_ts: + type: string + format: date-time + center_lat: + type: number + format: double + center_lon: + type: number + format: double + duration_s: + type: integer + place_label: + type: string + place_details: + type: object + + Suggestion: + type: object + properties: + suggestion_id: + type: string + stop_id: + type: string + type: + type: string + enum: [highlight, name_place, add_note] + title: + type: string + text: + type: string + created_at: + type: string + format: date-time + dismissed_at: + type: string + format: date-time + + JournalEntry: + type: object + properties: + entry_id: + type: string + user_id: + type: string + entry_date: + type: string + format: date + entry_time: + type: string + example: '14:30' + title: + type: string + description: + type: string + lat: + type: number + format: double + lon: + type: number + format: double + created_at: + type: string + format: date-time + images: + type: array + items: + $ref: '#/components/schemas/JournalImage' + + JournalImage: + type: object + properties: + image_id: + type: string + entry_id: + type: string + filename: + type: string + original_name: + type: string + mime_type: + type: string + size_bytes: + type: integer + format: int64 + created_at: + type: string + format: date-time + + Error: + type: object + properties: + code: + type: string + message: + type: string