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