📄 today-api-spec.yaml 12,046 bytes Apr 19, 2026 📋 Raw

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