Self-hosting Guide
LOSPOR can be self-hosted by any institution on their own infrastructure. The application is a standard Next.js app backed by a PostgreSQL database.
Requirements
- Node.js 18 or later
- PostgreSQL database (Supabase recommended — free tier is sufficient)
- A Vercel account (free Hobby tier is sufficient) or any server running Node.js
1 — Get the code
git clone https://github.com/kaloyandjunow-prog/lospor-app.git
cd lospor-app
npm install
2 — Set up the database
Create a free project at supabase.com. After creating the project:
- Go to Project Settings → Database → Connection String
- Copy the Transaction pooler URI (port 6543) — this is your
DATABASE_URL
3 — Configure environment variables
Copy .env.example to .env and fill in your values:
cp .env.example .env
# Transaction pooler — used by the app at runtime (port 6543)
DATABASE_URL="postgresql://postgres.<ref>:<pass>@aws-<region>.pooler.supabase.com:6543/postgres"
# Session mode pooler — used by Prisma migrations (port 5432, same hostname as DATABASE_URL)
DIRECT_URL="postgresql://postgres.<ref>:<pass>@aws-<region>.pooler.supabase.com:5432/postgres"
NEXTAUTH_SECRET="your-random-secret" # openssl rand -base64 32
NEXTAUTH_URL="https://your-domain.com"
# Optional — AI pre-operative advisor and lab scan (Mistral La Plateforme; free tier available)
MISTRAL_API_KEY="your-mistral-api-key"
MISTRAL_API_BASE="https://api.mistral.ai/v1" # optional — regional overrides fall back to the global base if inference is not allowed
MISTRAL_MODEL="open-mistral-7b" # optional — override model
Generate NEXTAUTH_SECRET
openssl rand -base64 32
4 — Apply the database schema
npx prisma migrate deploy
This creates all the required tables in your database.
5 — Seed institutions (optional)
The Bulgarian NHIF institution list is already included. To seed it:
npx tsx prisma/seed.ts
6 — Seed ICD-10 vocabulary (required for diagnosis search)
Diagnosis and comorbidity search requires the ICD-10 vocabulary to be seeded. Download the vocabulary bundle from athena.ohdsi.org (select at minimum: ICD10, ICD10CM, ATC) and place the CSV files in a local folder. Then run:
npx tsx scripts/seed-vocabularies.ts --vocab-dir /path/to/athena-csvs
npx tsx scripts/seed-athena-vocabularies.ts --vocab-dir /path/to/athena-csvs --filtered-lospor
npx tsx scripts/seed-lab-loinc.ts
These scripts are idempotent and safe to re-run. Bulgarian ICD-10 labels are loaded
from an Excel file matching ICD10_*.xlsx in the same folder (official MZ export).
Run Athena import locally or from a trusted maintenance machine. Do not run it from Vercel build hooks, serverless API routes, app startup, or deployed runtime. The deployed app only reads already-seeded Supabase tables. Filtered import is recommended for Supabase because full Athena can consume many GB of database storage once indexes are included.
7 — Seed the option library (required)
Every intraop/preop/postop picker and clinical number-control catalogue is served from a database table that starts out empty after step 4: position, technique, vascular access, airway management, monitoring, premedication drugs, intraop drugs, infusions, inhalational agents, fluids, clinical events, sex, blood group, airway grades, disposition, handover items, and numeric range specifications. Without this step the app loads, but clinical pickers will fall back to cached/bundled data or appear blank depending on the client state.
npx tsx scripts/seed-option-library.ts
Idempotent and safe to re-run.
Concept maps, backfill, and quality report
LOSPOR also needs the local concept map and relational research rows to be prepared after the option library is seeded:
npx tsx scripts/seed-concept-maps.ts
npx tsx scripts/backfill-relational.ts
npx tsx scripts/data-quality-report.ts
seed-concept-maps preserves ICD-10 English/Bulgarian labels, LOINC, ATC, INN, app-local option values, mapping method/confidence, review state, and known OMOP concept IDs where the filtered local Athena import provides confident standard mappings. backfill-relational rebuilds normalized research rows from existing cases. data-quality-report is read-only and reports Athena import coverage, relational drift, unmapped/source-only concepts, invalid ranges, future timestamps, export linkage warnings, and missing key research fields.
If seeding fails with a LibraryCategory enum error, do not edit an already
applied migration file. Apply the tracked additive enum migration with
npx prisma migrate deploy, then re-run the seed. Prisma validates migration
checksums, so historical migration files must stay unchanged once applied.
8 — Run in development
npm run dev
The app will be available at http://localhost:3000.
9 — Deploy to Vercel
- Push your code to a GitHub repository (private is fine)
- Import the project at vercel.com
- Set the following environment variables in the Vercel dashboard. You need both
DATABASE_URLandDIRECT_URL:DATABASE_URL— transaction pooler, port 6543 (used by the app at runtime)DIRECT_URL— session mode pooler, port 5432 at the same pooler hostname (used by Prisma's migration engine, which requires persistent prepared statements). Useaws-<region>.pooler.supabase.com:5432— notdb.<ref>.supabase.co:5432, which is the direct connection and is unreachable from Vercel.NEXTAUTH_SECRET,NEXTAUTH_URL, and optionally the Mistral keys.
- Deploy
Vercel automatically handles SSL, CDN, and zero-downtime deployments.
10 — Custom domain
In Vercel, go to Settings → Domains and add your domain. Configure the DNS records as directed by Vercel.
Update NEXTAUTH_URL to your production domain and redeploy.
Updating
To update to a newer version of LOSPOR:
git pull origin main
npm install
npx prisma migrate deploy # apply tracked migrations (production-safe)
npx tsx scripts/seed-option-library.ts
npx tsx scripts/seed-concept-maps.ts
npx tsx scripts/backfill-relational.ts
npx tsx scripts/data-quality-report.ts
Commit and push to trigger a Vercel redeployment.
Creating the first admin
After registering your first account, promote it to admin directly in the Supabase table editor:
- Supabase → Table Editor →
Usertable - Find your user row → set
roletoADMIN - Refresh the app — the Admin panel appears in the navigation bar
Licence
LOSPOR is licensed under AGPL-3.0. Self-hosted installations must make their source code available to users if modified. The unmodified code is already open source at GitHub.