openapi: 3.0.3 info: title: HoffDesk Family Dashboard API — Sprint 1 description: | Backend API for the HoffDesk family dashboard. Provides aggregated "today" view with calendar, weather, and system health data. version: 1.0.0 contact: name: Socrates servers: - url: http://localhost:8000 description: Local development (Beelink) - url: https://api.hoffdesk.com description: Production (Cloudflare Tunnel) paths: /api/today: get: summary: Aggregate "today" dashboard data description: | Returns all data needed for the dashboard's "Today" view in a single payload. Optimized for mobile-first consumption — minimal nesting, explicit nulls, human-readable strings. operationId: getToday responses: '200': description: Today's dashboard data content: application/json: schema: $ref: '#/components/schemas/TodayResponse' '503': description: Partial data available (some services degraded) content: application/json: schema: $ref: '#/components/schemas/TodayResponse' '500': description: Critical failure (unable to fetch any data) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /api/calendar/upcoming: get: summary: List upcoming calendar events description: | Returns calendar events from Radicale CalDAV. Default window: next 24 hours. Supports custom hours parameter. Events sorted chronologically. operationId: getCalendarUpcoming parameters: - name: hours in: query description: Number of hours to look ahead (default: 24, max: 168) schema: type: integer minimum: 1 maximum: 168 default: 24 responses: '200': description: List of upcoming events content: application/json: schema: $ref: '#/components/schemas/CalendarEventsResponse' '500': description: CalDAV fetch failed content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /api/weather: get: summary: Current weather and forecast description: | Returns current conditions and 24-hour forecast for Green Bay, WI. Source: Open-Meteo (no API key required). operationId: getWeather responses: '200': description: Weather data content: application/json: schema: $ref: '#/components/schemas/WeatherResponse' '503': description: Weather service unavailable content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /api/health: get: summary: System health status description: | Returns health indicators for critical infrastructure components. Used by the dashboard's status card and for uptime monitoring. operationId: getHealth responses: '200': description: System health status content: application/json: schema: $ref: '#/components/schemas/HealthResponse' /healthz: get: summary: Liveness probe description: Lightweight endpoint for load balancer health checks. operationId: healthz responses: '200': description: Service is alive content: text/plain: schema: type: string example: ok components: schemas: TodayResponse: type: object required: - timestamp - calendar - weather - health - meta properties: timestamp: type: string format: date-time description: ISO 8601 timestamp of when this data was assembled example: "2026-04-19T17:30:00-05:00" calendar: $ref: '#/components/schemas/CalendarSummary' weather: $ref: '#/components/schemas/WeatherSummary' health: $ref: '#/components/schemas/HealthSummary' meta: type: object properties: cache_ttl_seconds: type: integer description: Recommended client-side cache duration example: 60 data_freshness: type: object properties: calendar_seconds_ago: type: integer example: 45 weather_seconds_ago: type: integer example: 180 CalendarSummary: type: object required: - status - events_count - events properties: status: type: string enum: [ok, degraded, error] description: Overall calendar service status events_count: type: integer description: Number of events in the next 24h example: 3 events: type: array items: $ref: '#/components/schemas/CalendarEvent' CalendarEvent: type: object required: - uid - summary - start - end - is_all_day properties: uid: type: string description: Unique event identifier from CalDAV example: "event-12345@hoffdesk.com" summary: type: string description: Event title example: "Harper's Soccer Practice" start: type: string format: date-time description: Event start time (ISO 8601, local timezone) example: "2026-04-19T16:00:00-05:00" end: type: string format: date-time description: Event end time (ISO 8601, local timezone) example: "2026-04-19T17:00:00-05:00" is_all_day: type: boolean description: True if this is an all-day event example: false location: type: string nullable: true description: Event location (if provided) example: "Green Bay Community Center" description: type: string nullable: true description: Event description (if provided) attendees: type: array items: type: string nullable: true description: List of attendee names (extracted from description if present) CalendarEventsResponse: type: object required: - status - events properties: status: type: string enum: [ok, error] events: type: array items: $ref: '#/components/schemas/CalendarEvent' error: type: string nullable: true description: Error message if status is error WeatherSummary: type: object required: - status - location - current - forecast properties: status: type: string enum: [ok, degraded, error] description: Weather service status location: type: object required: - name - lat - lon properties: name: type: string example: "Green Bay, WI" lat: type: number example: 44.5133 lon: type: number example: -88.0133 current: $ref: '#/components/schemas/CurrentWeather' forecast: type: array description: Next 24 hours in 1-hour increments items: $ref: '#/components/schemas/HourlyForecast' CurrentWeather: type: object required: - temperature_f - feels_like_f - condition - humidity_pct - wind_mph - updated_at properties: temperature_f: type: number example: 58 feels_like_f: type: number example: 56 condition: type: string description: Human-readable weather condition example: "Partly cloudy" humidity_pct: type: integer example: 72 wind_mph: type: number example: 8 updated_at: type: string format: date-time example: "2026-04-19T17:00:00-05:00" HourlyForecast: type: object required: - hour - temperature_f - condition - precipitation_chance_pct properties: hour: type: string description: Hour in local time (24h format) example: "18:00" temperature_f: type: number example: 55 condition: type: string example: "Cloudy" precipitation_chance_pct: type: integer description: Probability of precipitation (0-100) example: 20 WeatherResponse: type: object required: - status properties: status: type: string enum: [ok, error] data: $ref: '#/components/schemas/WeatherSummary' nullable: true error: type: string nullable: true HealthSummary: type: object required: - overall_status - components - disk_usage properties: overall_status: type: string enum: [healthy, degraded, critical] description: Aggregate health status example: healthy components: type: object properties: openclaw_gateway: $ref: '#/components/schemas/ComponentHealth' radicale_caldav: $ref: '#/components/schemas/ComponentHealth' ollama_local: $ref: '#/components/schemas/ComponentHealth' cloudflare_tunnel: $ref: '#/components/schemas/ComponentHealth' disk_usage: $ref: '#/components/schemas/DiskUsage' ComponentHealth: type: object required: - status - last_check properties: status: type: string enum: [ok, degraded, error] example: ok last_check: type: string format: date-time example: "2026-04-19T17:29:00-05:00" latency_ms: type: integer nullable: true example: 12 error: type: string nullable: true DiskUsage: type: object required: - total_gb - used_gb - free_gb - usage_pct properties: total_gb: type: number example: 476.9 used_gb: type: number example: 142.3 free_gb: type: number example: 334.6 usage_pct: type: number example: 29.8 HealthResponse: type: object required: - status - overall properties: status: type: string enum: [ok, error] overall: $ref: '#/components/schemas/HealthSummary' ErrorResponse: type: object required: - error - code properties: error: type: string description: Human-readable error message code: type: string description: Machine-readable error code example: "CALDAV_UNREACHABLE" details: type: object nullable: true description: Additional context for debugging