diff --git a/CLAUDE.md b/CLAUDE.md index 64e6fde..3934c94 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -221,6 +221,12 @@ - Système : entité `Notification` (table `notifications`, `recipient`/`actor`/`message`/`category`/`target`/`isRead`), cloche **admin-only** dans `AppTopNav.vue`, providers `/notifications/{unread,today,history}` + `POST /notifications/mark-all-read`. Création historique : `WorkHourSiteValidationProcessor` (1 notif/admin via `UserRepository::findAllAdmins`). - **Fin de contrat (J-1 ouvré)** : commande cron quotidienne `app:contract:end-notifications` (crontab prod, ~6h ; option `--date`). Notifie les admins sur le **dernier jour ouvré avant** `endDate` (inclusif) de la **dernière** période d'un employé (changement de contrat enchaîné exclu). Week-ends + fériés sautés (`WorkingDayCalculator`, via `getHolidaysDayByYears` → applique `EXCLUDED_PUBLIC_HOLIDAYS`, donc **Lundi de Pentecôte traité comme jour ouvré**, cohérent avec le reste de l'app). Fenêtre couverte un jour J = `]J ; prochain_jour_ouvré(J)]`. Message « Fin de {nature} de {Nom} le {date} », catégorie `Contrat`, target `/employees/{id}`, acteur null. Idempotent (`NotificationRepository::existsForRecipientCategoryTargetMessage`). Logique pure testée : `ContractEndNotificationPlanner` + `WorkingDayCalculator`. Front : `AppTopNav.vue` masque le span acteur si `actorName` vide. Doc : `doc/contract-end-notifications.md`. +## Error tracking (GlitchTip) +- Backend Symfony → GlitchTip (SDK Sentry), org `malio`, projet `sirh-api`. **Prod only**, **inerte sans `SENTRY_DSN`**. +- Config : `config/packages/sentry.yaml` (DSN runtime `%env(SENTRY_DSN)%`, release `%app.version%`, 4xx ignorés, `traces_sample_rate: 0`, handler Monolog ERROR+) ; `SentryBundle` enregistré `['prod' => true]` (`config/bundles.php`) ; handler `sentry` en `when@prod` (`config/packages/monolog.yaml`). DSN runtime via l'env_file serveur, jamais committé/baké. +- **Transport réseau** : GlitchTip est interne (bloqué Sophos), SIRH sur VPS OVH → tunnel **Tailscale** sur le host prod. Frontend hors périmètre (ajout futur via proxy nginx `/ingest`). +- Doc : `doc/error-tracking.md`. + ## Backend Conventions - Prefer explicit DTOs over associative arrays - Business rules in backend (providers/processors/services), frontend is display/interaction only diff --git a/doc/error-tracking.md b/doc/error-tracking.md new file mode 100644 index 0000000..16d077b --- /dev/null +++ b/doc/error-tracking.md @@ -0,0 +1,56 @@ +# Error tracking (GlitchTip) + +Les erreurs **backend** (Symfony) sont remontées vers **GlitchTip** (instance interne MALIO, +compatible SDK Sentry), org `malio`, projet `sirh-api`. **Prod uniquement**, **inerte sans DSN**. + +> Frontend hors périmètre (les erreurs front partent du navigateur RH ; ajout futur possible via +> un proxy nginx `/ingest`). + +## Contrainte réseau & transport + +GlitchTip est sur le réseau interne (bloqué par Sophos). SIRH tourne sur un VPS OVH public. Le +container PHP joint GlitchTip via un **tunnel Tailscale** monté sur le host de prod. + +## Fichiers concernés + +| Fichier | Rôle | +|---|---| +| `config/packages/sentry.yaml` | conf backend (prod-only, DSN runtime, 4xx ignorés, release = `app.version`, handler Monolog ERROR+) | +| `config/bundles.php` | `SentryBundle` enregistré `['prod' => true]` | +| `config/packages/monolog.yaml` | handler `sentry` (service) en `when@prod` | +| `.env` | bloc documenté `SENTRY_DSN` (vide → inerte) | + +## Activation (runbook) + +1. **Tailscale sur le host prod OVH** : + ```bash + curl -fsSL https://tailscale.com/install.sh | sh + sudo tailscale up # ou --authkey tskey-auth-XXXX (headless) + tailscale status && tailscale ip -4 + ``` +2. **Vérifier l'accès à GlitchTip** depuis le host : + ```bash + tailscale ping + curl -sS -o /dev/null -w "%{http_code}\n" http://:/_health/ + ``` +3. **Routage container → tailnet** : pointer `SENTRY_DSN` sur l'**IP tailnet** de GlitchTip + (le container ne résout pas MagicDNS). Repli si non routé : sidecar `tailscale/tailscale` + + `network_mode: service:tailscale`. +4. **Créer le projet GlitchTip** `sirh-api` (plateforme `php-symfony`) dans l'org `malio`, + récupérer le DSN (Settings → Client Keys). +5. **Injecter le DSN** dans l'env_file serveur (pas dans l'image), puis redéployer : + ```env + SENTRY_DSN=http://@100.x.y.z:/ + ``` + ```bash + docker compose up -d + docker compose exec php php bin/console cache:clear --env=prod + ``` + +## CA HTTPS (conditionnel) + +Uniquement si le DSN cible l'HTTPS interne `logs.malio-dev.fr` (cert auto-signé) : baker la CA +racine MALIO dans `deploy/docker/Dockerfile.prod` (stage production). Recommandé : préférer +l'endpoint **HTTP** via le tailnet (déjà chiffré par WireGuard) → pas de CA. + +Design détaillé : `docs/superpowers/specs/2026-06-28-glitchtip-backend-error-tracking-design.md`.