EHR ligero para consultas médicas privadas en España — documentación clínica, templates de tratamiento y recetas PDF en un solo flujo.
- Registro de pacientes con reutilización de datos demográficos
- Templates de tratamiento por diagnóstico
- Generación de receta PDF con un clic (WeasyPrint)
- Autenticación JWT + bcrypt
- Tipos TypeScript auto-generados desde OpenAPI
- Sidecar HAPI FHIR R5 local para interoperabilidad (read-only)
- CI con lint, type-check y tests en cada push/PR
| Componente | Estado | Nota |
|---|---|---|
| Backend API (FastAPI) | ✅ Completo | Endpoints core operativos |
| Frontend (Next.js 14) | ✅ Completo | UI desktop integrada |
| Autenticación | ✅ Funcional | bcrypt + JWT |
| Flujo clínico MVP | ✅ Funcional | Pacientes, consultas, templates, recetas PDF |
| HAPI FHIR R5 sidecar | ✅ Baseline local | Read-only: CapabilityStatement, read, search, Bundle |
| Tipos API | ✅ Automáticos | OpenAPI → TypeScript |
| Gate local + CI | Deuda heredada de mypy puede mantener el gate rojo |
- Python 3.11+ · Node.js 20+ · Docker (Engine + Compose) · WeasyPrint (
brew install weasyprinten macOS)
./scripts/setup-local-db.shLevanta PostgreSQL 17 en localhost:54329 y aplica de forma idempotente el SQL neutral de database/migrations/.
cd backend
python3.11 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # edita DATABASE_URL si es necesario
uvicorn app.main:app --reload --port 8000.env mínimo:
DATABASE_URL=postgresql+asyncpg://postgres:password@localhost:54329/consultamed
JWT_SECRET_KEY=tu-secreto-super-seguro-cambialo
JWT_ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=480
FRONTEND_URL=http://localhost:3000
ENVIRONMENT=development
DEBUG=trueRuta recomendada: PostgreSQL local en
localhost:54329.backend/.env.supabase.examplese conserva solo como referencia histórica/transitoria y ya no describe un camino operativo recomendado.
cd frontend
npm install
npm run devOpcional — frontend/.env.local:
NEXT_PUBLIC_API_URL=http://localhost:8000./scripts/start-hapi-sidecar.shDetalles del sidecar
- Levanta su propia PostgreSQL dedicada (
consultamed-hapi-db,localhost:54330), separada de la DB operacional. - HAPI crea/actualiza su esquema al arrancar; no apliques
database/migrationssobre esta base. - Superficie publicada: solo
CapabilityStatement,read,searchyBundledel subset aprobado — sin versionado,_history, escrituras públicas ni operaciones$meta. - FastAPI mantiene writes, auth y lógica clínica. HAPI es read-only; las escrituras internas van por ETL con
X-Consultamed-ETL-Key. - Carga del subset clínico:
./scripts/load-hapi-clinical-subset.sh - Reset de persistencia HAPI:
docker compose -f sidecars/hapi-fhir/docker-compose.yml down -v --remove-orphans
| Campo | Valor |
|---|---|
sara@consultamed.es |
|
| Password | piloto2026 |
| Servicio | URL |
|---|---|
| Frontend | http://localhost:3000 |
| API / Docs OpenAPI | http://localhost:8000 · http://localhost:8000/docs |
| HAPI metadata | http://localhost:8090/fhir/metadata |
| HAPI health | http://localhost:8090/actuator/health |
./scripts/smoke_phase1.sh http://localhost:8000Valida conectividad, autenticación, pacientes, consultas y templates.
flowchart LR
FE["Frontend\nNext.js 14 + TypeScript"]
API["Backend\nFastAPI · source of truth"]
DB["PostgreSQL 17\noperacional"]
HAPI["HAPI FHIR R5\nsidecar read-only"]
HDB["PostgreSQL 17\ndedicada HAPI"]
PDF["WeasyPrint\nRecetas PDF"]
FE <--> API
API <--> DB
API --> PDF
API -. ETL interna .-> HAPI
HAPI --> HDB
- FastAPI es la API principal y fuente de verdad para writes, auth y lógica clínica.
- HAPI FHIR es un sidecar local de interoperabilidad read-only con persistencia propia.
├── backend/
│ ├── app/ # API, modelos, schemas, servicios, validators, FHIR mapping
│ ├── tests/ # unit/, contracts/, integration/
│ └── scripts/ # export-openapi, migrations, ETL helpers
├── frontend/
│ ├── src/app/ # Next.js App Router pages
│ ├── src/components/
│ ├── src/lib/ # API client, hooks, utils
│ └── src/types/ # Tipos auto-generados + manuales
├── sidecars/hapi-fhir/ # Dockerfile, overlay, config HAPI
├── database/
│ └── migrations/ # SQL neutral usado por setup-local-db
├── supabase/ # Configuración histórica/transitoria fuera del runtime activo
├── scripts/ # setup-local-db, test_gate, start/stop-hapi, smoke tests
├── docs/ # Arquitectura, specs, playbooks, compliance, release
└── .github/workflows/ # CI (backend + frontend)
| Control | Estado |
|---|---|
| bcrypt password hashing | ✅ Activo |
| JWT autenticación (1h prod / 8h dev) | ✅ Activo |
| Validación DNI/NIE | ✅ Activo |
| Input validation en backend | ✅ Activo |
| HTTPS obligatorio | ⏳ Producción |
| RLS completo | ⏳ V2 |
Entorno canónico backend:
backend/.venv(no uses.venven raíz).
# Gate completo (recomendado antes de commit)
./scripts/test_gate.sh
# Backend
cd backend && source .venv/bin/activate
pytest tests/unit tests/contracts -v --tb=short
ruff check .
# Frontend
cd frontend
npm test && npm run lint && npm run type-checkEl repo conserva deuda heredada de
mypyque puede mantener el gate rojo; trátalo como riesgo residual documentado.
| Recurso | Enlace |
|---|---|
| Índice de docs | docs/README.md |
| Contratos de API | docs/API.md |
| Guía de uso clínico | docs/USER_GUIDE.md |
| Arquitectura implementada | docs/architecture/overview.md |
| Specs activas | docs/specs/README.md |
| Despliegue | docs/release/DEPLOYMENT_GUIDE.md |
| DeepWiki (setup dev) | deepwiki.com/AIOjPINEDA/EHR_Local |
Proyecto privado · ConsultaMed