MePRAM OMOP API is a Django REST Framework service that exposes aggregated clinical dashboard data generated from an OMOP database. It provides cohort summaries, OMOP domains and concepts, fact and measurement aggregations, and stored report payloads. It intentionally does not expose patient-level records or genomic/isolate workflows such as sequence typing, carbapenemases, genomic alerts, or Microreact projects.
flowchart LR
Browser[Browser / API client]
Apache["Apache reverse proxy<br/>application DNS + Keycloak DNS"]
App["Django / Gunicorn<br/>MePRAM OMOP API"]
KC[Keycloak]
OMOP[("External MySQL<br/>mepram_omop")]
KCDB[("Keycloak MySQL<br/>named volume")]
SMTP[SMTP relay]
Browser -->|HTTPS| Apache
Apache -->|application vhost| App
Apache -->|identity vhost| KC
App -->|aggregated queries| OMOP
App -->|JWKS via Compose DNS| KC
App -->|notifications| SMTP
KC --> KCDB
Apache is the public entry point. Tokens use Keycloak's public issuer URL,
while Django retrieves signing keys through the internal mepram-omop-api-keycloak:8080
service address. Production application data lives in the external
mepram_omop database; Keycloak identity state lives in its own persistent
MySQL volume. See LEAME.md for the production runbook.
- Get the code (required)
- Choose your path
- Minimum requirements
- Docker deployment
- Bare-metal deployment (Ubuntu/CentOS)
- Common operations (Docker + bare-metal)
- Final configuration steps
- Developer notes
- Application documentation
git clone https://github.com/BU-ISCIII/mepram-omop-api.git mepram-omop-api
cd mepram-omop-apiFor an orchestrated deployment, every external build context in the service table must exist at the declared path relative to this checkout.
| Capability | Supported | Owner or command |
|---|---|---|
| Docker local test | Yes | container_install.sh --test --engine docker |
| Podman local test | Yes | container_install.sh --test --engine podman |
| Docker production | Yes | container_install.sh --engine docker |
| Podman production | Yes | container_install.sh --engine podman |
| Bare metal | Profile-specific | See Bare-metal deployment |
| Upgrade | Yes | --action upgrade |
| Permission repair | Yes | --action fix-permissions |
| Backup and restore | Yes | Operator-owned; follow LEAME.md |
Services:
| Service | Profile | Build context | Internal port |
|---|---|---|---|
mepram-omop-api |
django |
. |
settings: APP_PORT |
- Django services build with an ephemeral settings secret, render protected host settings, and run controlled migration/bootstrap steps.
Selected add-ons:
- Apache source configuration lives under
conf/apache/; customize its virtual hosts and routes there. The installer renders final bind sources underAPACHE_CONF_PATH(ordeployment/apache/when empty). - Keycloak provides centralized identity with a health-checked MySQL service, realm import, and persistent database state.
- Git and access to every declared build context.
- Docker Engine with Compose v2, or Podman with a Compose provider.
- Enough disk and memory for image builds and persistent application data.
- A protected production settings file for every application and selected add-on.
- Production DNS, TLS termination, database, storage, email, identity, backup, and monitoring services required by the selected profiles.
Copy each application's settings and each conf/<addon>/*_production_settings.txt
to protected ignored files, set mode 0600, and replace every CHANGE_ME. The exact
meaning and security classification of settings is in
conf/INSTALL_SETTINGS.md.
Create the ignored deployment settings directory and copy every production template that this topology consumes:
install -d -m 0700 deployment/settings
install -m 0600 conf/docker_production_settings.txt deployment/settings/mepram-omop-api_production_settings.txt
install -m 0600 conf/apache/apache_production_settings.txt deployment/settings/apache_production_settings.txt
install -m 0600 conf/keycloak/keycloak_production_settings.txt deployment/settings/keycloak_production_settings.txtEdit only the copies under deployment/settings/, replace every CHANGE_ME,
and keep their mode at 0600. Both installation workflows below point to
these protected copies.
Both engines use the same lifecycle and Compose files. Do not invoke Compose directly for the first install or an upgrade: the installer also renders configuration, prepares permissions, waits for readiness, and runs bootstrap.
Docker:
bash container_install.sh --test --action install --engine docker \
--git_revision currentPodman:
bash container_install.sh --test --action install --engine podman \
--git_revision currentTest settings and test services are disposable. Verify either deployment with:
bash scripts/smoke_test.sh --test --engine docker
# or: bash scripts/smoke_test.sh --test --engine podmanDjango test installation creates the disposable database declared by the test Compose profile, waits for it, applies committed migrations, optionally loads fixtures, runs selected data scripts, collects static files, and performs the generated health checks.
Migration/data scripts are repeatable django-extensions runscript names. Use
--script_before for preparation before migrations and --script (an alias of
--script_after) for a transformation after migrations:
bash container_install.sh --test --action install --engine docker \
--script_before prepare_test_data \
--script migrate_optional_valuesFresh installs automatically load conf/first_install_tables.json when the
application provides it. Use --skip_tables for an exceptional fresh install
without that fixture, or --tables to load it explicitly during an upgrade.
--demo_data_map <service,path>, --skip_demo_data, --skip_test_data, and
--skip_test_data_service <service> are part of the standard interface.
--demo_data <path> remains a single-service compatibility option. A project
that supplies fixtures or demo files must set
application_supports_test_data=true and implement load_test_deployment_data
in its wrapper; otherwise explicit demo data is rejected. Production never
selects or loads demo data by default, and upgrades never reload it.
For an automatic first administrator, set CREATE_INITIAL_SUPERUSER=true and
the DJANGO_SUPERUSER_* values in the selected test settings before install.
An existing account is never reset. Open the loopback URL using APP_PORT from
the rendered test environment, or APACHE_PORT when the Apache add-on is used.
Prepare the protected settings files and deploy a reviewed tag or commit.
Docker:
bash container_install.sh --action install --engine docker \
--git_revision <reviewed-tag-or-commit> \
--install_conf_map mepram-omop-api,deployment/settings/mepram-omop-api_production_settings.txt --install_conf_map apache,deployment/settings/apache_production_settings.txt --install_conf_map keycloak,deployment/settings/keycloak_production_settings.txtPodman:
bash container_install.sh --action install --engine podman \
--git_revision <reviewed-tag-or-commit> \
--install_conf_map mepram-omop-api,deployment/settings/mepram-omop-api_production_settings.txt --install_conf_map apache,deployment/settings/apache_production_settings.txt --install_conf_map keycloak,deployment/settings/keycloak_production_settings.txtThe installer creates .env.production.file for later direct Compose
operations. It contains generated runtime values, including secrets copied
from the protected settings sources, so keep it mode 0600, excluded from Git,
and inside the protected configuration backup. Neither the protected settings
nor this generated environment file is copied into image layers.
| Asset | Production location | Backup/rebuild policy |
|---|---|---|
mepram-omop-api database |
mepram-omop-api_db_data named volume, mounted by mepram-omop-api-db |
Logical dump before migration; persistent volume recovery |
mepram-omop-api documents |
mepram-omop-api_documents named volume |
Volume backup |
mepram-omop-api static |
mepram-omop-api_static named volume |
Replaceable through collectstatic |
mepram-omop-api logs |
Host bind configured by HOST_LOG_PATH in mepram-omop-api_production_settings.txt |
Retain/rotate per institutional log policy |
mepram-omop-api rendered settings |
Host bind configured by DJANGO_SETTINGS_PATH in mepram-omop-api_production_settings.txt |
Protected configuration backup |
| Apache logs | /var/log/local/mepram-omop-api/apache host bind |
Retain/rotate per institutional log policy |
| Rendered Apache configuration | APACHE_CONF_PATH (or deployment/apache/ when empty) |
Rebuildable; preserve reviewed source configuration |
| Keycloak database | keycloak_db_data MySQL named volume |
Database and identity backup |
| Keycloak staged realm | /srv/containers/bind/mepram-omop-api/keycloak/realm-import/ read-only host bind |
Back up with deployment configuration; reproducible bootstrap input, not authoritative identity state |
The standard fixes application binds below /srv/containers/bind/mepram-omop-api
and logs below /var/log/local/mepram-omop-api. The operator must still record the
backup owner, retention, actual engine volume names, and restore-test evidence
for every non-rebuildable asset. Never treat a container writable layer as
persistent storage.
The selected profiles and add-ons define the internal application server and proxy topology. Review public hostnames, TLS ownership, forwarded headers, request limits, timeouts, health paths, and static/media routing together.
The application developer must list every scheduler/worker, whether a failed job blocks a workflow, and how operators inspect and retry it. Do not add an untracked host cron job when the application profile owns scheduling.
Use the engine that performed the installation:
docker compose --env-file .env.production.file -f docker-compose.prod.yml ps
docker compose --env-file .env.production.file -f docker-compose.prod.yml logs --tail 200
docker compose --env-file .env.production.file -f docker-compose.prod.yml restartpodman compose --env-file .env.production.file -f docker-compose.prod.yml ps
podman compose --env-file .env.production.file -f docker-compose.prod.yml logs --tail 200
podman compose --env-file .env.production.file -f docker-compose.prod.yml restartDjango upgrades automatically preserve SECRET_KEY from the existing host
settings file at DJANGO_SETTINGS_PATH. No manual key configuration is needed.
If that file does not exist, the installer generates a new key. When restoring
or moving the deployment to a different settings path, restore the old settings
file there before installation if the original signing key must be preserved.
After taking a consistent backup and reading the version-specific upgrade notes:
bash container_install.sh --action upgrade --engine podman \
--git_revision <new-reviewed-tag-or-commit> \
--install_conf_map mepram-omop-api,deployment/settings/mepram-omop-api_production_settings.txt --install_conf_map apache,deployment/settings/apache_production_settings.txt --install_conf_map keycloak,deployment/settings/keycloak_production_settings.txtReplace podman with docker for a Docker-managed deployment. Stop on build,
readiness, bootstrap, migration, or smoke-test failure. See LEAME.md
for the ordered production checklist and rollback decision.
Use Get the code (required) and check out the reviewed revision.
Provision the application database and least-privilege account outside the installer. Confirm that the host can reach it before bootstrap.
Start from conf/docker_production_settings.txt, but review all paths and
container-oriented defaults for the target host. Keep the resulting file
ignored and mode 0600.
The Django profile includes install.sh for application staging and bootstrap,
but system package, database, web-server, service-manager, TLS, and backup
provisioning remain host-specific. Bare-metal installation is supported only
after the application developer documents and tests those integrations.
# Stage application files and dependencies.
bash install.sh --stage install --git_revision current \
--conf deployment/settings/mepram-omop-api_production_settings.txt
# Bootstrap the prepared runtime (settings, migrations and static files).
bash install.sh --bootstrap install \
--conf deployment/settings/mepram-omop-api_production_settings.txtFor upgrades, take a backup and replace both install actions with upgrade.
Do not use container-oriented paths or defaults on a bare-metal host without an
application-specific review.
For a host-managed Apache 2.4 deployment, adapt the reviewed virtual host from
conf/apache/ to the distribution path. The generated add-on files target the
container image, so do not copy them blindly without checking module names,
paths, runtime user, TLS ownership, and log locations.
Ubuntu/Debian baseline:
sudo cp <reviewed-apache-vhost.conf> /etc/apache2/sites-available/mepram-omop-api.conf
sudo a2enmod proxy proxy_http headers
sudo a2ensite mepram-omop-api.conf
sudo apache2ctl configtest
sudo systemctl reload apache2CentOS/RHEL baseline:
sudo cp <reviewed-apache-vhost.conf> /etc/httpd/conf.d/mepram-omop-api.conf
sudo httpd -t
sudo systemctl reload httpdThe reviewed virtual host must define the public ServerName, proxy to the
Django APP_PORT, serve the correct static/media paths, preserve forwarded
scheme/host headers, and use institutionally managed TLS and logs.
Follow the same staged lifecycle with upgrade only after a consistent backup
and review of the version-specific guide.
Each Django service declares DATABASE as external or compose. A Compose-managed
database is initialized from that service's protected DB_NAME, DB_USER, and
DB_PASSWORD values and persists in its <service>_db_data volume. For an
external database, create a dedicated schema and least-privilege account, verify
connectivity from the application container, and keep DBA credentials outside
this repository.
Connect as an authorized database administrator without putting the password on the command line:
DB_HOST='CHANGE_ME'
DB_PORT='3306'
DB_ADMIN='CHANGE_ME'
DB_NAME='CHANGE_ME'
DB_USER='CHANGE_ME'
mysql --host="$DB_HOST" --port="$DB_PORT" --user="$DB_ADMIN" --passwordCreate the application database and account. Replace every angle-bracket value;
restrict the account host further than % when the network topology permits.
CREATE DATABASE `<db-name>`
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER '<db-user>'@'%' IDENTIFIED BY '<strong-generated-password>';
GRANT ALL PRIVILEGES ON `<db-name>`.* TO '<db-user>'@'%';
FLUSH PRIVILEGES;Verify the same endpoint and least-privilege credentials configured for the application:
mysql --host="$DB_HOST" --port="$DB_PORT" --user="$DB_USER" --password \
--database="$DB_NAME" --execute='SELECT 1;'Back up every non-rebuildable row in the persistence table from one consistent recovery point before installation or upgrade. Record the revision, image IDs, settings files, and backup identifiers.
BACKUP_DIR="/srv/containers/backup/mepram-omop-api/$(date +%Y%m%d_%H%M%S)"
DOCUMENTS_VOLUME='CHANGE_ME'
DB_HOST='CHANGE_ME'
DB_PORT='3306'
DB_NAME='CHANGE_ME'
DB_USER='CHANGE_ME'
mkdir -p "$BACKUP_DIR"
git rev-parse HEAD > "$BACKUP_DIR/git-revision.txt"
cp .env.production.file "$BACKUP_DIR/"
cp deployment/settings/mepram-omop-api_production_settings.txt "$BACKUP_DIR/"
cp deployment/settings/apache_production_settings.txt "$BACKUP_DIR/"
cp deployment/settings/keycloak_production_settings.txt "$BACKUP_DIR/"
chmod -R go-rwx "$BACKUP_DIR"
# For each Compose-managed application database:
podman compose --env-file .env.production.file -f docker-compose.prod.yml \
exec -T <service>-db sh -c 'exec mysqldump --single-transaction --routines --triggers -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' \
> "$BACKUP_DIR/<service>-database.sql"
# For each external application database:
mysqldump --single-transaction --routines --triggers \
--host="$DB_HOST" --port="$DB_PORT" --user="$DB_USER" --password \
"$DB_NAME" > "$BACKUP_DIR/database.sql"
podman volume ls | grep 'mepram-omop-api'
podman volume export "$DOCUMENTS_VOLUME" > "$BACKUP_DIR/documents.tar"
# Dump logico obligatorio del estado autoritativo de Keycloak.
podman compose --env-file .env.production.file -f docker-compose.prod.yml \
exec -T mepram-omop-api-keycloak-db sh -c \
'exec mysqldump --single-transaction --routines --triggers -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' \
> "$BACKUP_DIR/keycloak-database.sql"
tar -C /srv/containers/bind -czf "$BACKUP_DIR/bind-mounts.tar.gz" mepram-omop-api
sha256sum "$BACKUP_DIR"/* > "$BACKUP_DIR/SHA256SUMS"For Docker, archive a named volume through a temporary container after ensuring the application is not writing to it:
docker run --rm \
--volume "$DOCUMENTS_VOLUME":/data:ro \
--volume "$BACKUP_DIR":/backup \
alpine tar -C /data -cf /backup/documents.tar .The full ordered backup checklist, including logs and image metadata, is in LEAME.md.
An image-only rollback is safe only when the previous application version supports the current schema and persistent-file format. Otherwise stop writes, restore the database and files from the same recovery point, deploy the recorded compatible revision, and rerun all smoke tests.
Compatible application-only rollback:
bash container_install.sh --action upgrade --engine podman \
--git_revision <previous-reviewed-revision> \
--install_conf_map mepram-omop-api,deployment/settings/mepram-omop-api_production_settings.txt --install_conf_map apache,deployment/settings/apache_production_settings.txt --install_conf_map keycloak,deployment/settings/keycloak_production_settings.txtFull restore when schema or persistent-file formats are incompatible:
BACKUP_DIR='/srv/containers/backup/mepram-omop-api/CHANGE_ME'
DOCUMENTS_VOLUME='CHANGE_ME'
DB_HOST='CHANGE_ME'
DB_PORT='3306'
DB_NAME='CHANGE_ME'
DB_USER='CHANGE_ME'
podman compose --env-file .env.production.file -f docker-compose.prod.yml down
# Restore external databases directly. For Compose-managed databases, start
# <service>-db, wait for its healthcheck, and import through that service.
mysql --host="$DB_HOST" --port="$DB_PORT" --user="$DB_USER" --password \
"$DB_NAME" < "$BACKUP_DIR/database.sql"
podman volume import "$DOCUMENTS_VOLUME" "$BACKUP_DIR/documents.tar"
tar -C /srv/containers/bind -xzf "$BACKUP_DIR/bind-mounts.tar.gz"
install -d -m 0700 deployment/settings
install -m 0600 "$BACKUP_DIR/mepram-omop-api_production_settings.txt" deployment/settings/mepram-omop-api_production_settings.txt
install -m 0600 "$BACKUP_DIR/apache_production_settings.txt" deployment/settings/apache_production_settings.txt
install -m 0600 "$BACKUP_DIR/keycloak_production_settings.txt" deployment/settings/keycloak_production_settings.txt
bash container_install.sh --action fix-permissions --engine podman \
--install_conf_map mepram-omop-api,deployment/settings/mepram-omop-api_production_settings.txt --install_conf_map apache,deployment/settings/apache_production_settings.txt --install_conf_map keycloak,deployment/settings/keycloak_production_settings.txt
# Arrancar solo la base de datos, esperar readiness y restaurar su dump logico.
podman compose --env-file .env.production.file -f docker-compose.prod.yml up -d mepram-omop-api-keycloak-db
until podman compose --env-file .env.production.file -f docker-compose.prod.yml \
exec -T mepram-omop-api-keycloak-db sh -c \
'mysqladmin ping -h 127.0.0.1 -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" --silent'; do sleep 2; done
podman compose --env-file .env.production.file -f docker-compose.prod.yml \
exec -T mepram-omop-api-keycloak-db sh -c \
'exec mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' \
< "$BACKUP_DIR/keycloak-database.sql"Then deploy the revision recorded in git-revision.txt, start the deployment,
and run the smoke test before reopening service. For Docker volume restoration,
reverse the temporary-container archive command by mounting the empty target
volume at /data and extracting /backup/documents.tar there.
-
Preserve installer output,
compose ps, image IDs, and service logs. -
Test the direct application health endpoint and dependencies.
-
Test proxy routing, public DNS, and TLS after direct health succeeds.
-
Run permission repair for reviewed ownership or SELinux drift:
bash container_install.sh --action fix-permissions --engine podman \ --install_conf_map mepram-omop-api,deployment/settings/mepram-omop-api_production_settings.txt --install_conf_map apache,deployment/settings/apache_production_settings.txt --install_conf_map keycloak,deployment/settings/keycloak_production_settings.txt
-
Do not fake migrations, delete volumes, or rebuild from an unrecorded revision as a first response.
# Logs and an interactive shell (replace podman with docker when applicable).
podman compose --env-file .env.production.file -f docker-compose.prod.yml \
logs --tail 200 mepram-omop-api
podman compose --env-file .env.production.file -f docker-compose.prod.yml \
exec mepram-omop-api bash
# Rebuild static assets without running migrations.
podman compose --env-file .env.production.file -f docker-compose.prod.yml \
exec mepram-omop-api bash -lc \
'cd "$INSTALL_PATH" && source virtualenv/bin/activate && python manage.py collectstatic --noinput'
# Inspect Django and migration state before deciding whether to recover.
podman compose --env-file .env.production.file -f docker-compose.prod.yml \
exec mepram-omop-api bash -lc \
'cd "$INSTALL_PATH" && source virtualenv/bin/activate && python manage.py check --deploy && python manage.py showmigrations --plan'For bootstrap recovery, fix the cause and rerun container_install.sh with the
same revision, protected configuration, and --action install or upgrade.
This safely recreates the temporary runtime configuration and repeats the
controlled migration/fixture/static lifecycle. Direct manage.py migrate is a
diagnostic last resort and must use the same backup and release procedure.
podman compose --env-file .env.production.file -f docker-compose.prod.yml \
logs --tail 200 mepram-omop-api-apache
podman compose --env-file .env.production.file -f docker-compose.prod.yml \
exec mepram-omop-api-apache httpd -t
APACHE_PORT='CHANGE_ME'
SERVER_STATUS_SERVER_NAME='localhost'
curl --fail --show-error \
--header "Host: $SERVER_STATUS_SERVER_NAME" \
"http://127.0.0.1:$APACHE_PORT/server-status?auto"Keep SERVER_STATUS_ALLOW_FROM limited to trusted diagnostic hosts. If SELinux
is enabled, inspect the persistent log bind and confirm a container-compatible
label before restarting:
ls -ldZ /var/log/local/mepram-omop-api/apacheAn Apache failure containing ModSecurity: Failed to open debug log file often
means the existing modsec_debug.log inode has stale ownership or labeling.
Preserve it for diagnosis, run fix-permissions, and restart Apache. If it must
be replaced, move it to a timestamped backup instead of deleting evidence:
sudo mv /var/log/local/mepram-omop-api/apache/modsec_debug.log \
/var/log/local/mepram-omop-api/apache/modsec_debug.log.blocked
bash container_install.sh --action fix-permissions --engine podman \
--install_conf_map mepram-omop-api,deployment/settings/mepram-omop-api_production_settings.txt --install_conf_map apache,deployment/settings/apache_production_settings.txt --install_conf_map keycloak,deployment/settings/keycloak_production_settings.txt
podman compose --env-file .env.production.file -f docker-compose.prod.yml restart mepram-omop-api-apacheThe installer renders the repository-owned JSON selected by
KEYCLOAK_REALM_TEMPLATE_PATH into the deployment-owned
KEYCLOAK_IMPORT_PATH before Compose starts. With the generated production
default, the read-only bind source is:
/srv/containers/bind/mepram-omop-api/keycloak/realm-import/
Do not change permissions on the repository source. The installer creates the
staging directory when /srv/containers/bind/mepram-omop-api is writable by the
deployment user and assigns staged files to Keycloak as 1000:0 with mode
0640. Back up this directory with the other protected deployment binds, but
use keycloak_db_data as the authoritative identity backup.
The application developer must document real post-install workflows here: initial administrator ownership, email delivery, identity-provider clients, storage credentials, scheduled jobs, and one representative user workflow. The generated baseline creates the initial Django administrator only when its profile settings explicitly request it.
Add application-specific development, test, and release workflows here.
container_install.sh sources the vendored files under
deployment/lib/container/. Do not edit those copies. Check or update them
from the standards repository with scaffold.py check-lib or sync-lib.
Django migrations MUST be generated, reviewed, tested, and committed with the
release. Installation and upgrade use container_install.sh; deployment MUST
NOT run makemigrations or silently manufacture schema history.
--test selects the test topology but does not guarantee an empty database:
its named database volume survives container recreation. Use --action install
only with an empty database and --action upgrade only with a recognized,
committed migration history.
See the Django schema migration workflow for legacy adoption, development-only migrations, release consolidation, container commands, production-like testing, and migration squashing.
Keep source checkouts, protected configuration, bind mounts, engine-managed
volumes, logs, and backups separate. For rootless Podman, run the installer as
the same unprivileged account every time and use fix-permissions instead of
manually changing engine storage.
bash scripts/smoke_test.sh --engine podmanApplication developers must extend the baseline smoke test with authenticated and domain-specific read workflows without removing the generated checks.
All application endpoints are under /v1 and operate on Django-managed
dashboard tables populated from the approved aggregate SQL import. The main
routes are:
| Route | Purpose |
|---|---|
/health/ |
Deployment-level application health |
/v1/health |
Database and dashboard-table health with row counts |
/v1/metadata |
Domains, event types, demographic filters and capabilities |
/v1/capabilities |
Supported and intentionally unsupported API features |
/v1/cohort/report |
Retrieve reports; superusers may store validated reports |
/v1/cohort/summary |
Cohort totals and age/sex distributions |
/v1/domains |
OMOP domain aggregates |
/v1/concepts |
Search and paginate concepts |
/v1/facts/concepts |
Fact/concept aggregates and stratifications |
/v1/measurements/numeric |
Numeric measurement aggregates |
/v1/measurements/categorical |
Categorical measurement aggregates |
/v1/openapi/ |
OpenAPI schema |
/v1/swagger/ |
Interactive API documentation |
Common list parameters include q, limit, offset, event_type, and
stratification (none, age, sex, or age_sex) where supported. The
OpenAPI schema is the authoritative field-level reference. Report payloads are
validated against
core/api/services/report_payload_schema.json.
Operational procedures and rollback are documented in LEAME.md. Project issues and support requests should be routed through the repository's maintainer-approved support channel; do not include clinical data or secrets.