EPPA Developer Setup¶
EPPA is the LABIS posturography tool for clinical/research workflows. This front contains a Next.js frontend, a FastAPI calculation/auth API, Docker deployment assets, Python tests, and Playwright end-to-end tests.
Work from this directory unless a command says otherwise:
cd fronts/eppa
Do not commit real patient data, clinical payloads, secrets, production tokens, database dumps, Vaultwarden exports, PANs, CVVs, PIN blocks, or track data.
Prerequisites¶
- Node.js 20.x. There is no
.nvmrc; use Node 20 because the Docker image isnode:20-alpineand local dependencies are tested against modern Node. - npm 10.x, included with current Node 20 releases.
- Python 3.11 or newer. Python 3.12 also works for the current API/test stack.
- Docker Engine with the Compose plugin (
docker compose ...). - Playwright browsers, installed after
npm ci. - Optional: PostgreSQL and MinIO via
docker composefor auth/clinical-data work. The calculation API and most Playwright coverage do not require real clinical records.
Fresh Checkout Setup¶
cd fronts/eppa
npm ci
npx playwright install --with-deps chromium
python3 -m venv venv
source venv/bin/activate
pip install -r python/requirements.txt
For local infrastructure used by the auth and clinical-data backend:
docker compose up -d postgres minio
docker compose ps
DATABASE_URL="${DATABASE_URL:?Set DATABASE_URL before running migrations}" \
PYTHONPATH=python python3 -m alembic -c python/alembic.ini upgrade head
Compose requires Postgres, MinIO, database URL, and JWT secret inputs from the
environment. Start from .env.example and keep the populated file outside
version control.
Local Development¶
Run the API and frontend in separate terminals.
Terminal 1, FastAPI on host port 8100:
source venv/bin/activate
API_PORT=8100 \
CORS_ALLOW_ORIGINS=http://localhost:9002 \
PYTHONPATH=python \
python3 python/api.py
Terminal 2, Next.js on host port 9002:
NEXT_PUBLIC_API_URL=http://127.0.0.1:8100 npm run dev
Open:
- Frontend:
http://localhost:9002 - API health:
http://localhost:8100/health - API docs:
http://localhost:8100/docs - MinIO console, when running:
http://localhost:9001
./start-api.sh is still available for the legacy default API port 8000, but
new local setup should prefer the explicit API_PORT=8100 command above so it
matches Docker and Playwright.
Playwright¶
The default Playwright config starts its own API and production Next.js server:
npx playwright test
Defaults:
- Frontend:
WEB_PORT=9102, soPLAYWRIGHT_BASE_URLdefaults tohttp://localhost:9102. - API:
API_PORT=8100, soPLAYWRIGHT_API_URLdefaults tohttp://localhost:8100. - Python executable:
PYTHON=python3.
To test against already-running local servers instead of letting Playwright start them:
PLAYWRIGHT_BASE_URL=http://localhost:9002 \
PLAYWRIGHT_API_URL=http://127.0.0.1:8100 \
npx playwright test
Useful variants:
npm run test:e2e:playwright -- playwright/e2e/login.spec.ts
npm run test:e2e:playwright:ui
npm run test:e2e:playwright:report
Other Verification¶
npm run typecheck
npm run test:py:coverage
PYTHONPATH=python pytest tests python/tests/auth
PYTHONPATH=python pytest tests/test_integration.py -v
node tests/js/testAnalysis.js
node tests/js/testMissingDataSemantics.js
python3 scripts/validate_matlab_fixtures.py
npm run test also runs Python tests, JavaScript analysis tests, and an Octave
MATLAB-equivalence test. Use it only when Octave is installed.
npm run test:py:coverage generates coverage.xml and prints missing Python
lines in the terminal. It excludes only tests that depend on real, private, or
binary MATLAB validation fixtures (Base completa- CORREGIDA.xlsx and real
.mat files), so CI remains reproducible without committing private data.
There is currently no enforced minimum coverage threshold.
Environment Variables¶
Use a local .env file only for backend settings that python/auth/config.py
loads, or export values in the shell before starting processes. Do not commit a
populated .env.
| Variable | Example value | Used by | Notes |
|---|---|---|---|
NEXT_PUBLIC_API_URL |
http://127.0.0.1:8100 |
Next.js build/runtime | Public API base URL baked into frontend builds. Use https://eppa.firemandeveloper.com or https://eppa2.firemandeveloper.com for server builds. |
API_PORT |
8100 |
FastAPI, Playwright, Docker entrypoint | FastAPI listens on this port inside the process. Docker maps container port 8000 to host 8100 for the legacy eppa service. |
CORS_ALLOW_ORIGINS |
http://localhost:9002 |
FastAPI | Comma-separated browser origins allowed to call the API. |
PYTHONPATH |
python |
Python commands | Required when running the API/tests from fronts/eppa. |
PYTHON |
python3 |
npm scripts, Playwright | Override when the interpreter is named differently. |
WEB_PORT |
9102 |
Playwright | Port for the Playwright-managed Next.js server. |
PLAYWRIGHT_BASE_URL |
http://localhost:9002 |
Playwright | When set, Playwright assumes the frontend server already exists and skips its webServer startup. |
PLAYWRIGHT_API_URL |
http://127.0.0.1:8100 |
Playwright tests | API URL used by tests and health checks. |
DATABASE_URL |
postgresql+psycopg://eppa:<url-encoded-secret>@postgres:5432/eppa |
FastAPI auth/data backend, Alembic | Required by Compose. Keep the populated value outside version control. |
JWT_ALGO |
HS256 |
FastAPI auth | HS256 for local/dev. RS256 is supported with key paths. |
JWT_SECRET |
<generated-secret> |
FastAPI auth | Required in production for stable HS256 tokens (or use JWT_SECRET_FILE). Never commit a real value. |
JWT_SECRET_FILE |
/run/secrets/eppa2_jwt_secret |
FastAPI auth | Path to a file containing the JWT secret (e.g. a Docker mounted secret). JWT_SECRET takes priority when both are set. |
EPPA_JWT_SECRET_SOURCE |
/absolute/path/to/eppa2-jwt-secret |
Docker Compose | Host path to the external secret file mounted as eppa2_jwt_secret. |
JWT_PRIVATE_KEY_PATH |
/etc/eppa/jwt-private.pem |
FastAPI auth | Required only when JWT_ALGO=RS256. |
JWT_PUBLIC_KEY_PATH |
/etc/eppa/jwt-public.pem |
FastAPI auth | Required only when JWT_ALGO=RS256. |
JWT_ISSUER |
eppa-api |
FastAPI auth | Token issuer claim. |
ACCESS_TOKEN_TTL_SECONDS |
900 |
FastAPI auth | Access-token lifetime. |
REFRESH_TOKEN_TTL_SECONDS |
1209600 |
FastAPI auth | Refresh-token lifetime. |
COOKIE_SECURE |
false locally, true in production |
FastAPI auth | Set true behind HTTPS. |
COOKIE_SAMESITE |
lax |
FastAPI auth | lax, strict, or none. |
COOKIE_DOMAIN |
.firemandeveloper.com |
FastAPI auth | Optional. Leave unset for localhost. |
LOGIN_RATE_LIMIT |
10/minute |
FastAPI auth | SlowAPI limit for login. |
FORGOT_PASSWORD_RATE_LIMIT |
5/hour |
FastAPI auth | SlowAPI limit for forgot-password. |
RESET_PASSWORD_RATE_LIMIT |
10/hour |
FastAPI auth | SlowAPI limit for reset-password. |
PASSWORD_RESET_TTL_SECONDS |
3600 |
FastAPI auth | Password reset token lifetime. |
PASSWORD_MIN_LENGTH |
10 |
FastAPI auth | Minimum practitioner password length. |
FRONTEND_BASE_URL |
http://localhost:9002 |
FastAPI auth email links | Public frontend URL used in reset links. |
EPPA_SMTP_HOST |
smtp.example.test |
FastAPI email | Optional. If unset, password-reset email content is logged by the stub backend. |
EPPA_SMTP_PORT |
587 |
FastAPI email | SMTP port. |
EPPA_SMTP_USER |
eppa-dev@example.test |
FastAPI email | Optional SMTP username. |
EPPA_SMTP_PASSWORD |
<generated-secret> |
FastAPI email | Optional SMTP password. Never commit real credentials. |
EPPA_SMTP_FROM |
no-reply@labis.uca |
FastAPI email | Sender address for reset emails. |
EPPA_ENV |
dev |
FastAPI auth | dev, test, or prod. |
MINIO_ROOT_USER |
eppa_minio_admin |
Docker MinIO | Dev-only value from Compose. |
MINIO_ROOT_PASSWORD |
<generated-secret> |
Docker MinIO | Required by Compose. |
POSTGRES_USER |
eppa |
Docker Postgres | Dev-only value from Compose. |
POSTGRES_PASSWORD |
<generated-secret> |
Docker Postgres | Required by Compose. |
POSTGRES_DB |
eppa |
Docker Postgres | Dev-only value from Compose. |
CYPRESS_apiUrl |
http://localhost:8000 |
legacy Cypress script | Only needed for npm run test:e2e, which wraps Cypress. |
The eppa2 Compose service mounts the file selected by EPPA_JWT_SECRET_SOURCE
at JWT_SECRET_FILE=/run/secrets/eppa2_jwt_secret.
The Python auth backend reads JWT_SECRET_FILE and loads the file contents as the JWT secret when
JWT_SECRET is not set explicitly. EPPA_ENV=prod fails fast if neither an explicit secret nor key
paths are configured, or if COOKIE_SECURE is false.
Docker¶
Build the legacy production image:
docker compose build eppa
Run it locally:
docker compose up -d eppa
docker compose ps
curl -fsS http://127.0.0.1:8100/health
Host port mapping for the legacy eppa service:
127.0.0.1:9002-> container Next.js port3000127.0.0.1:8100-> container FastAPI port8000
Build-time API URL example without Compose:
docker build \
--build-arg NEXT_PUBLIC_API_URL=https://eppa.firemandeveloper.com \
-t eppa:local .
The container starts both processes through entrypoint.sh: FastAPI first,
then next start -H 0.0.0.0 -p 3000.
Production Deployment¶
Production deployment is Docker + Nginx on the server. Run these commands on the server checkout, not on a developer laptop:
cd /home/luis/personal/github-repos/labis-eppa-software/fronts/eppa
git pull --ff-only
docker compose build eppa
docker compose up -d eppa
docker compose ps
curl -fsS http://127.0.0.1:8100/health
curl -sI http://127.0.0.1:9002/ | head -3
For the parallel v2 deployment:
docker compose up -d postgres minio
docker compose build eppa2
docker compose up -d eppa2
docker compose exec eppa2 sh -c 'cd /app && DATABASE_URL=$DATABASE_URL python3 -m alembic upgrade head'
curl -fsS http://127.0.0.1:8101/health
Nginx serves public HTTPS and proxies to loopback ports. The prepared v2 config
lives at deploy/nginx/eppa2.firemandeveloper.com.conf; the full v2 rollout,
TLS, smoke-test, and rollback sequence is in deploy/RUNBOOK-eppa2.md.
Basic-auth credentials for the public Nginx preview must be retrieved from Vaultwarden. Do not print those credentials in this README, PRs, issues, logs, or screenshots.
Project Layout¶
fronts/eppa/
src/ Next.js app, UI components, API client
python/ FastAPI app, calculation engine, auth/data backend
python/migrations/ Alembic migrations
playwright/e2e/ Playwright end-to-end tests
tests/ Python integration and fixture tests
scripts/ Validation and test helpers
deploy/ Deployment runbooks and Nginx config
datos/ Example/research data used by the project
docs/ Product, validation, API, and testing docs
Clinical Data Safety¶
- Use synthetic or explicitly approved fixture data for local tests.
- Do not add new real patient images, clinical records, secrets, or production exports to the repository.
- Keep local databases and MinIO buckets on
127.0.0.1unless a deployment runbook explicitly says otherwise. - Before opening a PR, check
git diff --statandgit difffor accidental data or secret additions.