openapi: 3.0.3
info:
  title: Eli Health Metadata API Specification
  description: |
    Complete specification for metadata structures in the Eli Health platform.

    ## Overview
    This specification documents the metadata structures used across the Eli Health platform,
    with particular focus on the `record` table metadata which contains health measurement data.

    ## Metadata Storage Pattern
    The platform uses a hybrid storage approach:
    - **Columns**: Structural data (id, type, userId, timestamps)
    - **JSON Metadata**: Domain-specific measurement data (values, classifications, interpretations)

    ## Known Issues
    ⚠️ **Dual Storage Pattern**: Some fields like `startDate`, `endDate`, and `value` may exist
    in both column storage and JSON metadata, requiring fallback logic in application code.
  version: 1.0.0
  contact:
    name: Eli Health Engineering
    email: engineering@eli.health
servers:
  - url: https://api.eli.health
    description: Production API
  - url: https://api-dev.eli.health
    description: Development API
tags:
  - name: Records
    description: Health measurement records with metadata
  - name: Readings
    description: Test strip readings and analysis

paths:
  /api/records:
    get:
      tags:
        - Records
      summary: Get health records with metadata
      description: Retrieves health measurement records including full metadata
      operationId: getRecords
      parameters:
        - name: type
          in: query
          description: Filter by record type
          required: false
          schema:
            $ref: '#/components/schemas/RecordType'
        - name: startDate
          in: query
          description: Filter records after this date
          required: false
          schema:
            type: string
            format: date-time
        - name: endDate
          in: query
          description: Filter records before this date
          required: false
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: Successfully retrieved records
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/RecordWithMetadata'
                  total:
                    type: integer
                    example: 150

  /api/records/{id}:
    get:
      tags:
        - Records
      summary: Get single record with metadata
      description: Retrieves a specific health measurement record by ID
      operationId: getRecordById
      parameters:
        - name: id
          in: path
          required: true
          description: Record UUID
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Successfully retrieved record
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RecordWithMetadata'
        '404':
          description: Record not found

  /api/readings/history/v2:
    get:
      tags:
        - Readings
      summary: Get reading history with metadata (v2)
      description: |
        Returns reading history with metadata. Note: This endpoint has a known issue
        where the `value` field appears both outside and inside the metadata object.
      operationId: getHistoryV2
      responses:
        '200':
          description: Successfully retrieved history
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ReadingHistoryV2'

components:
  schemas:
    RecordType:
      type: string
      enum:
        - hormone-measurement
        - heart-rate
        - blood-pressure
        - glucose
        - weight
        - sleep
        - activity
      description: Type of health measurement record

    HormoneType:
      type: string
      enum:
        - cortisol
        - testosterone
        - estradiol
        - progesterone
        - dhea
        - vitamin-d
      description: Specific hormone being measured

    HormoneClassification:
      type: string
      enum:
        - low
        - within range
        - above range
        - high
        - medium
      description: Classification of the hormone measurement result

    HormoneUnits:
      type: string
      enum:
        - ng/mL
        - ng/dL
        - pg/mL
        - nmol/L
        - µg/dL
      description: Unit of measurement for hormone values

    RecordWithMetadata:
      type: object
      required:
        - id
        - type
        - startDate
        - metadata
      properties:
        id:
          type: string
          format: uuid
          example: "d077d9fb-6039-4758-bc48-2930c3bdc559"
          description: Unique identifier for the record

        type:
          $ref: '#/components/schemas/RecordType'

        startDate:
          type: string
          format: date-time
          example: "2024-11-03T18:50:29Z"
          description: |
            Start timestamp of the measurement.
            ⚠️ May also exist in metadata.startDate - check both locations

        endDate:
          type: string
          format: date-time
          example: "2024-11-03T18:50:45Z"
          description: |
            End timestamp of the measurement.
            ⚠️ May also exist in metadata.endDate - check both locations

        userId:
          type: string
          format: uuid
          description: ID of the user this record belongs to

        metadata:
          oneOf:
            - $ref: '#/components/schemas/HormoneMetadata'
            - $ref: '#/components/schemas/HeartRateMetadata'
            - $ref: '#/components/schemas/GenericMetadata'
          discriminator:
            propertyName: type
            mapping:
              cortisol: '#/components/schemas/HormoneMetadata'
              testosterone: '#/components/schemas/HormoneMetadata'
              heart-rate: '#/components/schemas/HeartRateMetadata'
          description: |
            JSON metadata containing measurement-specific data.
            Structure varies based on record type.

    HormoneMetadata:
      type: object
      required:
        - type
        - value
        - unit
      properties:
        type:
          $ref: '#/components/schemas/HormoneType'

        value:
          type: number
          format: float
          example: 1.5
          description: The measured hormone value

        unit:
          $ref: '#/components/schemas/HormoneUnits'

        low:
          type: number
          format: float
          example: 1.0
          description: Lower bound of normal range

        high:
          type: number
          format: float
          example: 2.0
          description: Upper bound of normal range

        lowPop:
          type: number
          format: float
          example: 0.44
          description: Population percentile for low range

        highPop:
          type: number
          format: float
          example: 1.93
          description: Population percentile for high range

        classification:
          $ref: '#/components/schemas/HormoneClassification'

        interpretation:
          type: string
          example: "Excellent"
          description: Human-readable interpretation of the result

        recommendations:
          type: string
          example: "Great job! Your daily routine keeps your cortisol levels within range."
          description: Personalized recommendations based on the result

        score:
          type: integer
          minimum: 0
          maximum: 100
          example: 92
          description: Overall health score for this measurement

        probability:
          type: number
          format: float
          minimum: 0
          maximum: 1
          example: 0.49
          description: Statistical probability or confidence level

        batchNumber:
          type: string
          example: "cortisol-1"
          description: Test kit batch identifier

        startDate:
          type: string
          format: date-time
          example: "2024-11-03T19:30:29+01:00"
          description: |
            Measurement start time with timezone.
            ⚠️ Duplicates record.startDate - fallback logic required

        endDate:
          type: string
          format: date-time
          example: "2024-11-03T19:50:45+01:00"
          description: |
            Measurement end time with timezone.
            ⚠️ Duplicates record.endDate - fallback logic required

        wakeUpTime:
          type: string
          format: date-time
          example: "2024-11-03T14:00:00+01:00"
          description: User's wake up time on the day of measurement

        label:
          type: string
          example: "1.0-2.0"
          description: Display label for the measurement range

        tags:
          type: array
          items:
            type: string
            format: uuid
          description: Array of health tag IDs associated with this measurement

        heartRate:
          type: array
          description: Heart rate data collected during measurement
          items:
            type: object
            properties:
              wearable:
                type: string
                description: Device that collected the data
              timestamp:
                type: string
                format: date-time
              heartRate:
                type: number
                description: Heart rate in BPM
              message:
                type: string
                description: Additional context or notes

    HeartRateMetadata:
      type: object
      properties:
        type:
          type: string
          const: heart-rate
        avgHeartRate:
          type: number
          description: Average heart rate in BPM
        minHeartRate:
          type: number
          description: Minimum heart rate in BPM
        maxHeartRate:
          type: number
          description: Maximum heart rate in BPM
        restingHeartRate:
          type: number
          description: Resting heart rate in BPM
        source:
          type: string
          description: Data source (e.g., "Apple Watch", "Fitbit")

    GenericMetadata:
      type: object
      additionalProperties: true
      description: |
        Generic metadata structure for other record types.
        Can contain any key-value pairs specific to the measurement type.

    ReadingHistoryV2:
      type: object
      description: |
        Reading history response format from getHistoryV2 endpoint.
        ⚠️ Known issue: value field appears in two places
      properties:
        id:
          type: string
          format: uuid
        user_id:
          type: string
          format: uuid
        startDate:
          type: string
          format: date-time
          description: Fallback from metadata.startDate or record.startDate
        endDate:
          type: string
          format: date-time
          description: Fallback from metadata.endDate or record.endDate
        value:
          type: number
          description: |
            ⚠️ DEPRECATED: This field is duplicated.
            Use metadata.value instead.
        metadata:
          type: object
          properties:
            value:
              type: number
              description: The actual measurement value (use this one)
            type:
              $ref: '#/components/schemas/HormoneType'
        exerciseTagPresent:
          type: boolean
          description: Whether exercise tags are associated with this reading

    Reading:
      type: object
      required:
        - id
        - status
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for the reading
        status:
          type: string
          enum:
            - pending
            - processing
            - completed
            - error
            - cancelled
          description: Current status of the reading
        code:
          type: string
          enum:
            - success
            - invalid_image
            - processing_error
            - timeout
          description: Completion code indicating result
        imageFilePath:
          type: string
          description: Path to the test strip image in storage bucket
        timeZone:
          type: string
          example: "America/New_York"
          description: Canonical timezone where reading was performed
        processingTime:
          type: integer
          description: Time taken to process the image in milliseconds
        recordId:
          type: string
          format: uuid
          description: Associated record ID containing the measurement data
        userId:
          type: string
          format: uuid
          description: User who created this reading
        message:
          type: string
          description: Error or status message
        suggestions:
          type: string
          description: Suggestions or recommendations
        statusCode:
          type: integer
          description: HTTP-like status code for the reading result
        created:
          type: string
          format: date-time
          description: When the reading was created
        updated:
          type: string
          format: date-time
          description: When the reading was last updated