Skip to content

lucas-1000/health-data-storage

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

27 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Health Data Storage API

A generic, RESTful API for storing and querying health data with PostgreSQL backend. Designed to be consumed by mobile apps, MCP servers, and other health data clients.

🎯 Purpose

This service acts as the single source of truth for all your health data. It provides a clean, generic API that can:

  • Accept health samples from multiple sources (iOS app, wearables, manual entry)
  • Store data in a structured PostgreSQL database
  • Provide query APIs for retrieving and analyzing data
  • Serve multiple consumers (MCP servers, dashboards, analytics tools)

πŸ—οΈ Architecture Position

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Data Sources   β”‚
β”‚  - iOS App      β”‚
β”‚  - Wearables    β”‚
β”‚  - Manual Entry β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚ POST /api/samples
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ health-data-storage  β”‚  ← YOU ARE HERE
β”‚  - REST API          β”‚
β”‚  - PostgreSQL        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚ GET /api/samples/*
         β”‚
    β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β–Ό         β–Ό            β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚MCP     β”‚ β”‚Web   β”‚  β”‚Analytics β”‚
β”‚Servers β”‚ β”‚Dashboardβ”‚  β”‚ Tools    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“Š Database Schema

The system uses 7 PostgreSQL tables to store all health, nutrition, and user data:

1. users - User Authentication & Management

id                    SERIAL PRIMARY KEY
google_id             VARCHAR(255) UNIQUE NOT NULL
email                 VARCHAR(255) UNIQUE NOT NULL
name                  VARCHAR(255)
picture_url           TEXT
api_key               VARCHAR(64) UNIQUE NOT NULL
created_at            TIMESTAMPTZ DEFAULT NOW()
last_login_at         TIMESTAMPTZ
deleted_at            TIMESTAMPTZ                    -- When account deleted
deletion_scheduled_at TIMESTAMPTZ                    -- 30-day grace period

Google OAuth authentication with unique API keys per user.

2. oauth_clients - MCP Server Registration

client_id       VARCHAR(64) PRIMARY KEY
client_secret   VARCHAR(64) NOT NULL
name            VARCHAR(255) NOT NULL
redirect_uris   TEXT[] NOT NULL
allowed_scopes  TEXT[] NOT NULL
created_at      TIMESTAMPTZ DEFAULT NOW()

Registered OAuth clients (MCP servers) that can access user data.

3. oauth_tokens - MCP Authentication Tokens

token           VARCHAR(255) PRIMARY KEY
user_id         INTEGER REFERENCES users(id)
client_id       VARCHAR(64) REFERENCES oauth_clients(client_id)
scopes          TEXT[] NOT NULL
expires_at      TIMESTAMPTZ NOT NULL
refresh_token   VARCHAR(255) UNIQUE
created_at      TIMESTAMPTZ DEFAULT NOW()

Active OAuth access tokens with refresh capability.

4. health_samples - Generic Health Data

id              SERIAL PRIMARY KEY
user_id         VARCHAR(255) NOT NULL
type            VARCHAR(100) NOT NULL           -- e.g., "BloodGlucose", "HeartRate"
value           NUMERIC NOT NULL
unit            VARCHAR(50) NOT NULL            -- e.g., "mg/dL", "bpm"
start_date      TIMESTAMPTZ NOT NULL
end_date        TIMESTAMPTZ NOT NULL
source          VARCHAR(255)                    -- e.g., "Lingo", "Apple Watch"
local_timezone  VARCHAR(50)                     -- e.g., "America/Los_Angeles"
metadata        JSONB                           -- Additional data as JSON
created_at      TIMESTAMPTZ DEFAULT NOW()

UNIQUE(user_id, type, start_date, source)

Supported Data Types:

  • BloodGlucose (mg/dL)
  • HeartRate (bpm)
  • Steps (count)
  • BodyMass (kg)
  • ActiveEnergyBurned (kcal)
  • Any other health metric

5. food_logs - Nutrition/Meal Tracking

id              SERIAL PRIMARY KEY
user_id         VARCHAR(255) NOT NULL
timestamp       TIMESTAMPTZ NOT NULL
local_date      DATE                            -- YYYY-MM-DD in user's timezone
local_time      TIME                            -- HH:MM:SS in user's timezone
local_timezone  VARCHAR(50)                     -- IANA timezone identifier
photo_url       TEXT                            -- URL to photo in GCS bucket
net_carbs       DECIMAL NOT NULL                -- Net carbs (total - fiber)
total_carbs     DECIMAL DEFAULT 0               -- Total carbohydrates
fiber           DECIMAL DEFAULT 0               -- Dietary fiber
protein         DECIMAL NOT NULL
fat             DECIMAL NOT NULL
calories        DECIMAL NOT NULL
sugar           DECIMAL DEFAULT 0               -- Sugar content
sodium          DECIMAL DEFAULT 0               -- Sodium in mg
foods           JSONB NOT NULL                  -- Array of food items
confidence      DECIMAL NOT NULL                -- AI confidence (0.0 - 1.0)
meal_type       VARCHAR(50)                     -- 'breakfast', 'lunch', 'dinner', 'snack'
manual_override BOOLEAN DEFAULT false
notes           TEXT
created_at      TIMESTAMPTZ DEFAULT NOW()

Stores all meal data with AI-analyzed nutrition info and photos.

6. water_logs - Hydration Tracking

id              SERIAL PRIMARY KEY
user_id         INTEGER NOT NULL REFERENCES users(id)
timestamp       TIMESTAMPTZ NOT NULL
local_date      DATE
local_time      TIME
local_timezone  VARCHAR(50)
amount_ml       DECIMAL NOT NULL CHECK (amount_ml > 0)
notes           TEXT
created_at      TIMESTAMPTZ DEFAULT NOW()

Tracks daily water intake in milliliters.

7. user_preferences - User Settings & Goals

user_id                 INTEGER PRIMARY KEY REFERENCES users(id)

-- Body metrics
height_cm               DECIMAL
weight_kg               DECIMAL
age                     INTEGER
gender                  VARCHAR(20)     -- 'male', 'female', 'other'
activity_level          VARCHAR(20)     -- 'sedentary', 'light', 'moderate', 'very_active', 'extra_active'

-- Dietary goals
dietary_goal            VARCHAR(50)     -- 'weight_loss', 'maintenance', 'muscle_gain', 'keto'
target_calories         DECIMAL
target_net_carbs        DECIMAL
target_protein          DECIMAL
target_fat              DECIMAL
target_fiber            DECIMAL

-- Display preferences
show_calories           BOOLEAN DEFAULT true
show_carbs              BOOLEAN DEFAULT true
show_net_carbs          BOOLEAN DEFAULT true
show_fiber              BOOLEAN DEFAULT false
show_fat                BOOLEAN DEFAULT true
show_protein            BOOLEAN DEFAULT true

-- Water tracking
water_tracking_enabled  BOOLEAN DEFAULT false
target_water_ml         DECIMAL DEFAULT 2000

created_at              TIMESTAMPTZ DEFAULT NOW()
updated_at              TIMESTAMPTZ DEFAULT NOW()

User body metrics, dietary goals, and app display preferences.

Key Indexes

idx_health_samples_user_type_date    ON health_samples(user_id, type, start_date DESC)
idx_food_logs_user_local_date        ON food_logs(user_id, local_date DESC)
idx_water_logs_user_date             ON water_logs(user_id, local_date DESC)
idx_oauth_tokens_user                ON oauth_tokens(user_id)

πŸ”Œ API Endpoints

Health Check

GET /health

Response:

{
  "status": "ok",
  "service": "health-data-storage",
  "timestamp": "2025-10-22T12:00:00Z"
}

Store Health Samples (Bulk Insert)

POST /api/samples
Headers: X-API-Secret: your-secret
Body:
{
  "userId": "[email protected]",
  "samples": [
    {
      "type": "BloodGlucose",
      "value": 95,
      "unit": "mg/dL",
      "startDate": "2025-10-22T10:30:00Z",
      "endDate": "2025-10-22T10:30:00Z",
      "source": "Lingo",
      "metadata": {}
    }
  ]
}

Response:

{
  "success": true,
  "inserted": 1,
  "total": 1
}

Query Health Samples

GET /api/[email protected]&type=BloodGlucose&startDate=2025-10-01T00:00:00Z&endDate=2025-10-22T23:59:59Z&limit=100
Headers: X-API-Secret: your-secret

Response:

{
  "count": 10,
  "samples": [...]
}

Get Latest Sample

GET /api/samples/[email protected]&type=BloodGlucose
Headers: X-API-Secret: your-secret

Response:

{
  "id": 123,
  "user_id": "[email protected]",
  "type": "BloodGlucose",
  "value": 95,
  "unit": "mg/dL",
  "start_date": "2025-10-22T10:30:00Z",
  "end_date": "2025-10-22T10:30:00Z",
  "source": "Lingo",
  "metadata": {},
  "created_at": "2025-10-22T10:31:00Z"
}

Get Summary Statistics

GET /api/samples/[email protected]&type=BloodGlucose&startDate=2025-10-01T00:00:00Z&endDate=2025-10-22T23:59:59Z
Headers: X-API-Secret: your-secret

Response:

{
  "count": 100,
  "average": 98.5,
  "min": 75,
  "max": 125,
  "unit": "mg/dL"
}

πŸš€ Setup

Prerequisites

  • PostgreSQL database (Cloud SQL, Supabase, etc.)
  • Node.js 20+
  • Google Cloud Platform account (for deployment)

Environment Variables

DATABASE_URL=postgresql://user:password@host:5432/dbname
API_SECRET=your-secure-random-secret
PORT=8080
NODE_ENV=production

Local Development

# Install dependencies
npm install

# Build TypeScript
npm run build

# Start server
npm start

Deploy to Cloud Run

# Set environment variables
export GOOGLE_CLOUD_PROJECT=your-project-id
export DATABASE_URL=postgresql://...
export API_SECRET=$(openssl rand -base64 32)

# Deploy
chmod +x deploy.sh
./deploy.sh

After deployment, save the service URL and API_SECRET for use in:

  • iOS app configuration
  • MCP server configuration
  • Other clients

πŸ”’ Authentication

API uses a shared secret (X-API-Secret header) for authentication. This is simple but effective for:

  • Mobile apps (secret stored securely on device)
  • MCP servers (secret in environment variables)
  • Trusted clients

For multi-tenant or public-facing deployments, consider implementing OAuth2 or JWT authentication.

πŸ“ˆ Future Extensions

Easy to add:

  • New data types: Just start sending them! Schema is generic.
  • Multi-user support: User management and proper authentication.
  • Webhooks: Notify consumers when new data arrives.
  • Data export: CSV, JSON bulk exports.
  • Aggregations: Daily/weekly/monthly rollups.
  • Data retention: Automatic cleanup of old data.

πŸ”— Related Projects

  • health-tracking-app: iOS app that POSTs data to this API
  • mcp-glucose: MCP server that queries glucose data from this API
  • mcp-activity: (future) MCP server for activity data
  • mcp-nutrition: (future) MCP server for food/nutrition data

πŸ“ License

MIT

About

REST API for storing and querying health data from Apple Health (PostgreSQL + Cloud Run)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •