Intelligent therapeutic monitoring platform for polymedicated patients. Centralizes treatments, detects drug interactions in real time using official ANSM data, and orchestrates clinical alerts.
A polymedicated patient sees 3 specialists. Each prescribes without knowing the full treatment picture. MediGuard automatically cross-checks all of a patient's medications against the official ANSM Interaction Thesaurus and raises clinical alerts when a contraindication or inadvisable combination is detected.
The system resolves the complete chain: brand name → BDPM → active substance → salt form → normalized INN → therapeutic classes → interactions. Without this resolution, most interactions remain invisible.
Event Sourcing is not a gratuitous technical choice — it's a domain requirement.
In pharmacovigilance, every mutation must be traceable: who added this treatment, when, who stopped it, why, which interactions were detected at that point, who acknowledged the alert, with what justification. A simple CRUD with updated_at columns loses this information.
With Event Sourcing, the patient's event stream tells the complete story:
TherapeuticRecordCreated → 2026-04-06 10:00
TreatmentAdded (Warfarin) → 2026-04-06 10:01
InteractionAnalysisCompleted (0) → 2026-04-06 10:01
TreatmentAdded (Fluconazole) → 2026-04-06 10:05
InteractionAnalysisUpdated (1 PE) → 2026-04-06 10:05
TreatmentAdded (Domperidone) → 2026-04-06 10:10
InteractionAnalysisUpdated (2) → 2026-04-06 10:10
NewCriticalInteractionFound (CI) → 2026-04-06 10:10
AlertRaised (PENDING) → 2026-04-06 10:10
AlertAcknowledged → 2026-04-06 10:15
AlertOverridden (justification) → 2026-04-06 10:20
Every event is immutable, timestamped, and replayable. The patient's state can be reconstructed at any point in time.
┌─────────────────────────────────────────────────────────────────┐
│ Frontend React 18 + MUI 7 │
└──────────────────────────────┬──────────────────────────────────┘
│ REST API (10 endpoints)
┌──────────────────────────────▼──────────────────────────────────┐
│ Symfony 7.4 — PHP 8.5 │
│ command.bus (sync) / query.bus (sync) │
│ event.bus (async — RabbitMQ) │
├────────────┬────────────┬────────────┬──────────────────────────┤
│ Therapeutic│ Interaction│ Alert & │ Drug Catalog │
│ Record │ Analysis │ Decision │ (supporting ctx) │
│ (ES) │ (ES) │ (ES) │ batch import │
├────────────┴────────────┴────────────┴──────────────────────────┤
│ PostgreSQL 16 — Event Store │
│ append-only, optimistic concurrency │
└─────────────────────────────────────────────────────────────────┘
Therapeutic Record — Patient's therapeutic assessment. ES aggregate with addTreatment, stopTreatment (reason + author required), modifyPosology. Every mutation carries a UserId for traceability.
Interaction Analysis — Core domain. InteractionEngine (Domain Service) with multi-level detection algorithm: direct lookup → via class A → via class B → via both classes, with deduplication by symmetric key. PatientInteractionReport (ES aggregate) persists the analysis history.
Alert & Decision — State machine: PENDING → ACKNOWLEDGED → OVERRIDDEN → RESOLVED. An override requires a justification of at least 50 characters. Alerts are raised automatically via EventSubscriber on critical interactions.
Drug Catalog — Supporting context. Batch import of BDPM (15,033 drugs) and ANSM Thesaurus (3,220 interactions). Isolated from the core by an Anti-Corruption Layer.
- command.bus (sync) — mutations: AddTreatmentCommand, StopTreatmentCommand, AcknowledgeAlertCommand...
- query.bus (sync) — reads: GetActiveTreatmentsQuery, GetPatientInteractionsQuery...
- event.bus (async, RabbitMQ) — cross-BC propagation: TreatmentAdded triggers analysis, NewCriticalInteractionFound raises an alert
Adding a medication
→ TreatmentAdded (async)
→ AnalyzePatientInteractions (sync)
→ InteractionEngine detects CI
→ NewCriticalInteractionFound (async)
→ RaiseAlert (sync)
→ ClinicalAlert PENDING
| Source | Content | Volume |
|---|---|---|
| BDPM | Drugs, compositions, substances | 15,033 specialties |
| ANSM Thesaurus | Drug interactions (parsed PDF) | 3,220 interactions |
| ANSM Thesaurus | Therapeutic classes ↔ substances | 168 classes, 1,924 members |
Hybrid substance normalization: official ANSM FT (priority) → regex fallback for salts → ICU transliterator for diacritics (2,234 substances affected).
| Layer | Technologies |
|---|---|
| Backend | PHP 8.5, Symfony 7.4 LTS |
| Frontend | React 18, TypeScript, MUI 7, TanStack Query v5, Vite |
| Database | PostgreSQL 16 |
| Message broker | RabbitMQ 3.13 |
| Architecture | DDD, Clean Architecture, CQRS, Event Sourcing, TDD |
| CI | GitHub Actions (PHPUnit + PHPStan level 8) |
- Docker & Docker Compose
- Node.js 18+ and npm
git clone https://github.com/Drkilla/mediguard.git
cd mediguard
docker compose up -ddocker compose exec php php bin/console doctrine:migrations:migrate --no-interaction
docker compose exec php php bin/console drug-catalog:import-bdpm
docker compose exec php php bin/console drug-catalog:import-thesaurus# Async worker (terminal 1)
docker compose exec -e APP_DEBUG=0 php php bin/console messenger:consume async -vv --env=prod
# Frontend (terminal 2)
cd frontend && npm install && npm run dev- Frontend: http://localhost:5173
- Swagger UI: http://localhost:8080/api/doc
docker compose exec php vendor/bin/phpunit # 243 tests, 630 assertions
docker compose exec php vendor/bin/phpstan analyse # level 8, 0 errors| Method | Route | Description |
|---|---|---|
| GET | /api/drugs/search?q= |
Search drugs |
| POST | /api/patients/{id}/treatments |
Add a treatment |
| GET | /api/patients/{id}/treatments |
Active treatments |
| POST | /api/patients/{id}/treatments/{tid}/stop |
Stop a treatment |
| POST | /api/patients/{id}/treatments/{tid}/modify-posology |
Modify posology |
| GET | /api/patients/{id}/interactions |
Detected interactions |
| GET | /api/patients/{id}/alerts |
Clinical alerts |
| POST | /api/alerts/{id}/acknowledge |
Acknowledge an alert |
| POST | /api/alerts/{id}/override |
Override an alert |
| POST | /api/alerts/{id}/resolve |
Resolve an alert |
src/
├── SharedKernel/ # Event Sourcing, shared Value Objects
├── TherapeuticRecord/ # BC — Therapeutic assessment (ES)
├── InteractionAnalysis/ # BC — Interaction engine (ES)
├── AlertDecision/ # BC — Clinical alerts (ES)
├── DrugCatalog/ # BC — Drug reference catalog
└── UI/Http/Controller/ # REST API
frontend/ # React 18 + TypeScript + MUI 7
docs/ # Detailed project documentation
This project is a technical demonstrator. It is not a medical device and must not be used to make therapeutic decisions.