Application web d'administration pour un registre québécois de maladies rares. Permet la gestion des participants (patients), de leurs contacts, des consentements, du suivi de l'historique des modifications, des rapports et de la sélection en lot (panier).
Le backend (API + base de données) est partagé avec le futur portail participant (rareqc-portal-participant) : un seul serveur API, une seule base, un seul Keycloak — voir rareqc-infra/docs/integration-portail.md.
| Couche | Technologies |
|---|---|
| Backend | Go 1.25, Gin, GORM, PostgreSQL 16, Swagger (swaggo) |
| Auth | Keycloak (OIDC, patron BFF — cookies httpOnly, aucun jeton côté navigateur) |
| Frontend | React 19, TypeScript, Vite, Tailwind CSS v4, shadcn/ui, i18next, recharts, ExcelJS |
| Infra | Docker Compose (Go API, Nginx) + plateforme partagée rareqc-infra (PostgreSQL, Keycloak) |
| Qualité | ESLint, Prettier, Husky + lint-staged, tests Go (go test ./...) |
- Plateforme partagée
rareqc-infradémarrée (PostgreSQL + Keycloak — crée le réseau Dockerrareqc-net) :docker compose up -ddans le reporareqc-infra - Docker et Docker Compose
- Go 1.25+ (développement backend local)
- Node.js 22+ via nvm (développement frontend local)
Toujours en premier :
docker compose up -ddans~/src/rareqc-infra(PostgreSQL sur 5440, Keycloak sur 8081).
# Démarrer API + Frontend (rejoignent le réseau rareqc-net)
docker compose up --build
# Charger les données de test (dans un autre terminal)
docker compose --profile dev run --rm seed| Service | URL |
|---|---|
| Frontend | http://localhost:3001 |
| API | http://localhost:8082/api |
| Swagger | http://localhost:8082/swagger/index.html |
| PostgreSQL | localhost:5440 (rareqc-infra) |
| Keycloak | http://localhost:8081 (rareqc-infra) |
# 1. L'API en dev (les défauts pointent vers la plateforme rareqc-infra — aucun .env requis)
cd backend && go run ./cmd/api/
# 2. Charger les données de test
docker compose --profile dev run --rm seed
# 3. Le frontend en mode dev
cd frontend
npm install
npm run dev| Service | URL |
|---|---|
| Frontend | http://localhost:5173 |
| API (dev) | http://localhost:8080/api |
| Swagger | http://localhost:8080/swagger/index.html |
Le serveur Vite proxy /api vers l'API en dev local (8080). Si l'API tourne en docker plutôt qu'avec go run : VITE_API_PROXY_TARGET=http://localhost:8082 npm run dev.
La page d'accueil redirige vers Keycloak (thème RareQC). Utilisateurs de test (mot de passe test1234) :
| Utilisateur | Rôle | Résultat |
|---|---|---|
vincent-test, marie-test |
registre_admin |
accès complet |
sansrole-test |
aucun | page « accès refusé » |
participant-test |
participant |
page « accès refusé » (réservé au futur portail participant) |
docker compose up --build utilise le cache Docker. Si vous modifiez le code Go, les changements ne seront pas pris en compte à moins de forcer un rebuild :
# Rebuild sans cache + redémarrer
docker compose build --no-cache api && docker compose up -d api
# Puis re-seed si le schéma a changé
docker compose --profile dev run --rm seedPourquoi ? Docker met en cache chaque layer du Dockerfile. Si seul le code source change mais que les layers
COPY go.modetgo mod downloadsont identiques, Docker réutilise le binaire compilé précédemment. Le flag--no-cacheforce la recompilation complète.
La base vit dans la composition rareqc-infra (volume pgdata, partagé avec Keycloak). Pour repartir d'un jeu de données propre, le re-seed suffit dans la plupart des cas :
docker compose --profile dev run --rm seedPour une réinitialisation complète (schéma compris), voir « Base applicative : sauvegarde / restauration » dans le README de rareqc-infra — pgdata détruit aussi la base Keycloak (realm réimporté au prochain démarrage).
Le seed génère 200 participants réalistes répartis sur 7 trimestres (Q3 2024 → Q1 2026) avec une croissance progressive :
| Trimestre | Participants |
|---|---|
| Q3 2024 | 10 |
| Q4 2024 | 15 |
| Q1 2025 | 20 |
| Q2 2025 | 25 |
| Q3 2025 | 35 |
| Q4 2025 | 45 |
| Q1 2026 | 50 |
- 170 enfants (0-17 ans) avec contact mère (primaire) et optionnellement père
- 30 adultes (18-65 ans) avec contact « soi-même » (primaire)
- Noms québécois et anglophones, numéros RAMQ, codes postaux et indicatifs régionaux réalistes
- 2 formulaires de consentement (RareQc et RQDM) avec clauses et PDFs templates
- 200 documents signés (un par participant)
- ~400 consentements avec statuts variés (valide, expiré, retiré) et cascade appliquée
- 2 systèmes externes (CQDG ~60%, CQGC ~40%) avec IDs aléatoires
- 300+ entrées d'activité réparties sur les 7 trimestres
- 4 auteurs : John Smith, Marie Tremblay, Pierre Gagnon, Sophie Lavoie
docker compose --profile dev run --rm seedLe seed est dans un profil Docker dev séparé et n'est jamais inclus dans l'image de production.
PGPASSWORD=rareqc psql -h localhost -p 5440 -U rareqc -d rareqc_registre# Tests backend
cd backend && go test ./...
# Lint frontend
cd frontend && npm run lint
# Formater le code frontend
cd frontend && npm run format
# Régénérer la spec Swagger + client TypeScript (tout-en-un)
make generate
# Ou séparément :
make doc # Swagger seulement (backend/docs/)
make generate-client-typescript # Client TypeScript seulement (frontend/api/)Le frontend utilise un client TypeScript auto-généré depuis la spec Swagger (même pipeline que radiant-portal) :
Annotations Go (swag) → swagger.yaml → openapi-generator (typescript-axios) → frontend/api/
Après tout changement à l'API backend (nouveaux endpoints, types modifiés), exécuter make generate pour mettre à jour le client frontend. Les types manuels dans src/types/ sont des barrels de ré-export depuis le client généré.
Patron BFF (backend-for-frontend) : le backend Go est le client OIDC confidentiel de Keycloak. Les jetons vivent dans trois cookies httpOnly signés et n'atteignent jamais le JavaScript du navigateur. Double mode : cookies de session (navigateur) ou Authorization: Bearer vérifié contre le JWKS (scripts — voir rareqc-infra/scripts/api-token.sh).
- Le rôle realm est exigé par groupe de routes : les routes admin exigent
registre_admin; les futures routes/me/...du portail participant exigerontparticipant. - Le client OIDC est choisi selon l'origine de la requête : les origines listées dans
PARTICIPANT_PORTAL_HOSTSutilisentportail-participant-bff, tout le resteregistre-admin-bff. - Un utilisateur authentifié sans le bon rôle voit une page « accès refusé » (pas d'écrans vides).
Tout est documenté dans backend/.env.example — les défauts pointent vers la plateforme de dev rareqc-infra, donc aucun .env n'est requis en dev.
| Variable | Défaut | Description |
|---|---|---|
GIN_MODE |
(vide) | release = mode production : refuse de démarrer si un secret/réglage est resté à sa valeur de dev ; logs JSON |
PORT |
8080 |
Port d'écoute HTTP |
CORS_ALLOWED_ORIGINS |
* |
Origines CORS (séparées par des virgules) — * interdit en release |
POSTGRES_HOST / POSTGRES_PORT |
localhost / 5440 |
PostgreSQL (plateforme rareqc-infra) |
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB |
rareqc / rareqc / rareqc_registre |
Accès BD |
POSTGRES_SSLMODE |
disable |
sslmode du driver — valeur explicite exigée en release |
KEYCLOAK_HOST / KEYCLOAK_INTERNAL_HOST |
http://localhost:8081 / (=HOST) |
Keycloak public / interne (conteneurs) |
KEYCLOAK_REALM / KEYCLOAK_CLIENT / KEYCLOAK_CLIENT_SECRET |
rareqc / registre-admin-bff / (dev) |
Client OIDC du portail admin |
KEYCLOAK_PARTICIPANT_CLIENT / KEYCLOAK_PARTICIPANT_CLIENT_SECRET |
portail-participant-bff / (dev) |
Client OIDC du portail participant |
PARTICIPANT_PORTAL_HOSTS |
http://localhost:5174,http://localhost:3002 |
Origines du portail participant |
SESSION_SECRET |
(dev) | Signature des cookies de session |
PORTAL_HOST |
http://localhost:5173 |
Origine de secours du flux OIDC |
COOKIE_SECURE |
false |
true hors dev (exige HTTPS) |
STORAGE_TYPE |
database |
Stockage des documents (database ou s3) |
Les documents supportent deux backends de stockage :
| Mode | STORAGE_TYPE |
Stockage | Téléchargement |
|---|---|---|---|
| Base de données | database (défaut) |
Table document_file (bytea) |
Servi par l'API |
| Object store | s3 |
Bucket S3-compatible | Redirection 307 |
En développement, le mode database est utilisé par défaut. En production, configurer STORAGE_TYPE=s3 avec les variables S3 appropriées.
Note : L'upload vers S3 n'est pas encore implémenté. Seul le redirect au téléchargement est en place.
Projet interne — usage restreint.