MediBot / docs /DEPLOYMENT_DB.md
github-actions[bot]
Deploy MedOS Global from 956ae78f
e3e3e14
|
Raw
History Blame Contribute Delete
6.61 kB

Database deployment

MedOS supports two database drivers chosen at runtime by a single env var.

DATABASE_URL set? Driver Use case
Yes, starts with postgres:// or postgresql:// Postgres (production) Vercel, Hugging Face Spaces, CI smoke tests
Unset or invalid SQLite (fallback) Local development, ephemeral previews, offline self-hosting

The schema is the same on both drivers. Migrations apply driver-specific SQL automatically.

Refusing the fallback in production. When NODE_ENV=production and DATABASE_URL is missing or invalid, the server refuses to start instead of silently coming up on SQLite. There is no separate flag — NODE_ENV already tells us this is production. Set NODE_ENV=development locally to opt into the SQLite fallback.

Choosing a Postgres host

The project is tested against Neon but works with any Postgres ≥ 13 — Supabase, Railway, RDS, Cloud SQL, plain postgres:16. Neon's pooler endpoint (...-pooler....neon.tech) is what the code expects for serverless deployments.

The one new env var

For the database migration itself you only have to add one variable:

Var Type Example
DATABASE_URL secret postgresql://USER:PASS@ep-xxx-pooler.region.aws.neon.tech/neondb?sslmode=require

Everything else (SSL mode, pool size, statement timeout, fallback path) has a sensible default baked into the code. Defaults are listed at the bottom of this doc — you only override them if a deployment proves you need to.

The pre-existing MedOS env vars stay the same; they were already required before this migration:

  • ADMIN_EMAIL, ADMIN_PASSWORD — first-run admin seed.
  • ENCRYPTION_KEY — at-rest encryption for BYO HF tokens.
  • SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, FROM_EMAIL — email transport.
  • APP_URL — used in outbound email links.
  • NODE_ENV — standard Node.js env tag. Set to production on Vercel + HF.

See .env.example for the consolidated list.

Setting env vars per platform

GitHub Actions

Settings → Secrets and variables → Actions.

  • Repository secrets for everything tagged "secret" above.
  • Repository variables for everything tagged "variable".

Per-environment scoping: if you have a production and a staging Action environment, set them separately so previews can target Neon's preview branches.

Reference in a workflow:

jobs:
  smoke:
    runs-on: ubuntu-latest
    env:
      NODE_ENV: production
      DATABASE_URL: ${{ secrets.DATABASE_URL }}
      ADMIN_EMAIL: ${{ vars.ADMIN_EMAIL }}
      ADMIN_PASSWORD: ${{ secrets.ADMIN_PASSWORD }}
      ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: cd 9-HuggingFace-Global && npm ci && npm run db:migrate

Hugging Face Spaces

Space → Settings → Variables and secrets.

  • Secrets for the sensitive set.
  • Variables for the non-sensitive set.

Hugging Face Spaces persists /data between restarts on most Space hardware tiers, so the SQLite fallback works there if you choose not to use Postgres. With DATABASE_URL set, the Space writes to Postgres and the on-disk SQLite at /data/medos.db is unused.

Sample space.yml extract:

emoji: 🩺
sdk: docker
app_port: 7860
secrets:
  - DATABASE_URL
  - ADMIN_PASSWORD
  - ENCRYPTION_KEY
  - SMTP_PASS
variables:
  NODE_ENV: "production"
  ADMIN_EMAIL: "admin@medos.health"
  SMTP_HOST: "smtp.sendgrid.net"
  SMTP_PORT: "587"
  SMTP_USER: "apikey"
  FROM_EMAIL: "MedOS <noreply@your-domain>"
  APP_URL: "https://your-space.hf.space"

Vercel

Project → Settings → Environment Variables.

  • Tag every var for Production and Preview (you'll typically want a separate Neon database branch for Preview).
  • The Neon connection string already includes sslmode=require; do not modify it.

You can also use Vercel's Neon integration to inject DATABASE_URL automatically per branch.

Migration command

After setting env vars, run migrations once before the first request:

# Production (Postgres)
DATABASE_URL=postgresql://... npm run db:migrate

# Development (SQLite)
npm run db:migrate

The same npm run db:migrate works for both drivers. Migrations are version-gated and idempotent — running twice is safe.

Connection-failure behavior

Driver Boot First request Mid-request
Postgres + NODE_ENV=production Process exits 1 if connect fails (no silent fallback) Same as boot 503 response, structured log line
Postgres + NODE_ENV=development Logs warning, falls back to SQLite Reads from SQLite at $DB_PATH Same
SQLite (dev only) Always succeeds locally; fails only if path is unwritable Reads from local file n/a

Production is always Postgres-required: when NODE_ENV=production and DATABASE_URL is missing or invalid, the server refuses to start. Silent fallback is convenient in development; it is a foot-gun in production, so we never enable it there.

Rotating the database password

If a credential is ever exposed (e.g., pasted into a chat, a screenshot, or a logged URL), rotate immediately:

  1. Neon → Branches → production → Roles → Reset password on the user.
  2. Update DATABASE_URL in GitHub Actions secrets, HF Spaces secrets, and Vercel env vars.
  3. Redeploy each platform so the new connection string takes effect.
  4. Audit recent logins for the rotated role (Neon → Operations).

Plan for a quarterly rotation regardless of incident.

Local development

cd 9-HuggingFace-Global
npm install
npm run dev

Without DATABASE_URL set, the app uses SQLite at ./medos.db. The first request triggers the migration runner; verification codes show up on stdout because SMTP is unconfigured.

If you want to develop against Postgres locally, run a container:

docker run --name medos-pg -e POSTGRES_PASSWORD=devpass -p 5432:5432 -d postgres:16
export DATABASE_URL="postgresql://postgres:devpass@localhost:5432/postgres"
npm run db:migrate
npm run dev

Cross-references

  • 9-HuggingFace-Global/lib/db-adapter/ — implementation.
  • 9-HuggingFace-Global/lib/db-adapter/migrations/ — schema definitions.
  • SECURITY.md (repo root) — credential reporting and rotation policy.
  • THREAT_MODEL.md (repo root) — assets, including DB credentials.
  • PRIVACY.md (repo root) — what data lives in the DB and how it is retained / deleted.