Fusion #69 (chantier 2) — Alertes unifiées, côté Kanbante.
Audit (vérifié sur main, pas supposé)
Kanbante n'a PAS de table de notifications et n'expose aucun endpoint notifications : sa seule source réelle d'activité est le journal d'événements, déjà exposé par GET /api/events?limit=100 ({ok, events:[{repo_full_name,issue_number,event_type,from_column,to_column,created_at}]}) et rendu par /activity. AUCUN état lu/non lu n'existe dans Kanbante.
Conséquence honnête, codée dans le module : les événements Kanbante sont tous de l'historique et ne sont JAMAIS comptés dans la pastille d'actives.
Les autres sources (même audit que les autres PR du chantier) : Flowdeck GET /api/notifications (non lues = actives), TikTak GET /api/notifications (non lues = actives), ObsiGate : aucune notification entrante consultable (ses /api/notify/* sont des envois sortants admin).
Kanbante n'énonce en CSP que frame-src (console Spark) : aucune ouverture connect-src n'est nécessaire côté Kanbante comme visualiseur. En revanche, sans CORS, la lecture de /api/events depuis un autre hôte est bloquée : cette PR l'ouvre étroitement.
Ce qui change (cette PR Kanbante)
static/js/draco-alertes.js (nouveau, module partagé, pas un fichier ui/barre-apps.*) + static/css/draco-alertes.css : panneau Alertes (actives d'abord, puis historique, par application, origine/titre/date/état/lien profond ; textContent uniquement). Pastille via DRACO_BAR.setCounts({alertes: n}). Bases résolues dans l'ordre barre v0.1.6 : config explicite > hôte -dev dérivé > href rendu > défaut prod. Aucun nouvel endpoint : le module consomme /api/events existant.
app/templates/_draco_bar.html : branche alertes → DRACO_ALERTES.open() (repli : /activity) ; le toast « Alertes unifiées : arrive avec la fédération » DISPARAÎT ; chargement du module.
app/main.py : nouveau DracoAlertesCorsMiddleware (ajouté après AuthMiddleware, donc le plus externe) limité à /api/events pour les seules origines sœurs résolues par resoudre_urls_draco() ; preflight OPTIONS sans données ; le GET reste soumis à AuthMiddleware (session/jeton).
Agrégation À LA DEMANDE, pas une fédération temps réel (relecture à l'ouverture + au chargement pour la pastille).
Vue unifiée complète seulement quand les 4 PR du chantier sont déployées (chaque hôte autorise les sœurs en CSP/CORS) ; sinon la section de l'hôte manquant affiche « Connexion requise » ou « injoignable » avec son lien natif, jamais de faux contenu.
Pastille = Flowdeck non lues + TikTak non lues uniquement.
Aucun bump de version, aucun merge, aucune fermeture d'issue dans cette PR (coordinateur).
Note d'environnement : les tests Kanbante échouent au chargement dans la sandbox si les variables proxy de la sandbox restent définies (httpx lit no_proxy et échoue sur ses entrées IPv6 entre crochets) ; les chiffres ci-dessus sont obtenus avec ces variables neutralisées — préexistant, sans rapport avec cette PR.
Validation déployée (pastille et sections inter-apps en conditions réelles) reste à faire par Bruno après déploiement des 4 PR.
Rebase de la PR #34 sur main post-#70 et post-#68 (conflits _draco_bar.html et app/main.py résolus : suppression du bouton ••• de #70 conservée, palette /recherche de #68 conservée, ajouts #69 appliqués — CSS/JS draco-alertes, handler alertes, middleware CORS /api/events — sans ressusciter le bouton ••• ni la branche menu, et sans retirer le contenu #68). Contenu par ailleurs identique à #34.
Fusion #69 (chantier 2) — Alertes unifiées, côté Kanbante.
## Audit (vérifié sur main, pas supposé)
- Kanbante n'a PAS de table de notifications et n'expose aucun endpoint notifications : sa seule source réelle d'activité est le journal d'événements, déjà exposé par `GET /api/events?limit=100` (`{ok, events:[{repo_full_name,issue_number,event_type,from_column,to_column,created_at}]}`) et rendu par `/activity`. AUCUN état lu/non lu n'existe dans Kanbante.
- Conséquence honnête, codée dans le module : les événements Kanbante sont tous de l'historique et ne sont JAMAIS comptés dans la pastille d'actives.
- Les autres sources (même audit que les autres PR du chantier) : Flowdeck `GET /api/notifications` (non lues = actives), TikTak `GET /api/notifications` (non lues = actives), ObsiGate : aucune notification entrante consultable (ses `/api/notify/*` sont des envois sortants admin).
- Kanbante n'énonce en CSP que `frame-src` (console Spark) : aucune ouverture `connect-src` n'est nécessaire côté Kanbante comme visualiseur. En revanche, sans CORS, la lecture de `/api/events` depuis un autre hôte est bloquée : cette PR l'ouvre étroitement.
## Ce qui change (cette PR Kanbante)
- `static/js/draco-alertes.js` (nouveau, module partagé, pas un fichier `ui/barre-apps.*`) + `static/css/draco-alertes.css` : panneau Alertes (actives d'abord, puis historique, par application, origine/titre/date/état/lien profond ; `textContent` uniquement). Pastille via `DRACO_BAR.setCounts({alertes: n})`. Bases résolues dans l'ordre barre v0.1.6 : config explicite > hôte -dev dérivé > href rendu > défaut prod. Aucun nouvel endpoint : le module consomme `/api/events` existant.
- `app/templates/_draco_bar.html` : branche `alertes` → `DRACO_ALERTES.open()` (repli : `/activity`) ; le toast « Alertes unifiées : arrive avec la fédération » DISPARAÎT ; chargement du module.
- `app/main.py` : nouveau `DracoAlertesCorsMiddleware` (ajouté après `AuthMiddleware`, donc le plus externe) limité à `/api/events` pour les seules origines sœurs résolues par `resoudre_urls_draco()` ; preflight OPTIONS sans données ; le GET reste soumis à `AuthMiddleware` (session/jeton).
- Tests : `tests/test_draco_alertes.py` (3 tests) + `tests/draco-alertes.test.js` (5 tests Node).
## Limites, dites honnêtement
- Agrégation À LA DEMANDE, pas une fédération temps réel (relecture à l'ouverture + au chargement pour la pastille).
- Vue unifiée complète seulement quand les 4 PR du chantier sont déployées (chaque hôte autorise les sœurs en CSP/CORS) ; sinon la section de l'hôte manquant affiche « Connexion requise » ou « injoignable » avec son lien natif, jamais de faux contenu.
- Pastille = Flowdeck non lues + TikTak non lues uniquement.
- Aucun bump de version, aucun merge, aucune fermeture d'issue dans cette PR (coordinateur).
## Tests (chiffres réels, sandbox)
- `pytest tests/test_draco_alertes.py` : 3 passed.
- `pytest tests/test_draco_barre.py` : 21 passed, 0 échec (non-régression).
- `node --test tests/draco-alertes.test.js` : 5 passed.
- Note d'environnement : les tests Kanbante échouent au chargement dans la sandbox si les variables proxy de la sandbox restent définies (httpx lit `no_proxy` et échoue sur ses entrées IPv6 entre crochets) ; les chiffres ci-dessus sont obtenus avec ces variables neutralisées — préexistant, sans rapport avec cette PR.
- Validation déployée (pastille et sections inter-apps en conditions réelles) reste à faire par Bruno après déploiement des 4 PR.
---
Rebase de la PR #34 sur main post-#70 et post-#68 (conflits _draco_bar.html et app/main.py résolus : suppression du bouton ••• de #70 conservée, palette /recherche de #68 conservée, ajouts #69 appliqués — CSS/JS draco-alertes, handler alertes, middleware CORS /api/events — sans ressusciter le bouton ••• ni la branche menu, et sans retirer le contenu #68). Contenu par ailleurs identique à #34.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fusion #69 (chantier 2) — Alertes unifiées, côté Kanbante.
Audit (vérifié sur main, pas supposé)
GET /api/events?limit=100({ok, events:[{repo_full_name,issue_number,event_type,from_column,to_column,created_at}]}) et rendu par/activity. AUCUN état lu/non lu n'existe dans Kanbante.GET /api/notifications(non lues = actives), TikTakGET /api/notifications(non lues = actives), ObsiGate : aucune notification entrante consultable (ses/api/notify/*sont des envois sortants admin).frame-src(console Spark) : aucune ouvertureconnect-srcn'est nécessaire côté Kanbante comme visualiseur. En revanche, sans CORS, la lecture de/api/eventsdepuis un autre hôte est bloquée : cette PR l'ouvre étroitement.Ce qui change (cette PR Kanbante)
static/js/draco-alertes.js(nouveau, module partagé, pas un fichierui/barre-apps.*) +static/css/draco-alertes.css: panneau Alertes (actives d'abord, puis historique, par application, origine/titre/date/état/lien profond ;textContentuniquement). Pastille viaDRACO_BAR.setCounts({alertes: n}). Bases résolues dans l'ordre barre v0.1.6 : config explicite > hôte -dev dérivé > href rendu > défaut prod. Aucun nouvel endpoint : le module consomme/api/eventsexistant.app/templates/_draco_bar.html: branchealertes→DRACO_ALERTES.open()(repli :/activity) ; le toast « Alertes unifiées : arrive avec la fédération » DISPARAÎT ; chargement du module.app/main.py: nouveauDracoAlertesCorsMiddleware(ajouté aprèsAuthMiddleware, donc le plus externe) limité à/api/eventspour les seules origines sœurs résolues parresoudre_urls_draco(); preflight OPTIONS sans données ; le GET reste soumis àAuthMiddleware(session/jeton).tests/test_draco_alertes.py(3 tests) +tests/draco-alertes.test.js(5 tests Node).Limites, dites honnêtement
Tests (chiffres réels, sandbox)
pytest tests/test_draco_alertes.py: 3 passed.pytest tests/test_draco_barre.py: 21 passed, 0 échec (non-régression).node --test tests/draco-alertes.test.js: 5 passed.no_proxyet échoue sur ses entrées IPv6 entre crochets) ; les chiffres ci-dessus sont obtenus avec ces variables neutralisées — préexistant, sans rapport avec cette PR.Rebase de la PR #34 sur main post-#70 et post-#68 (conflits _draco_bar.html et app/main.py résolus : suppression du bouton ••• de #70 conservée, palette /recherche de #68 conservée, ajouts #69 appliqués — CSS/JS draco-alertes, handler alertes, middleware CORS /api/events — sans ressusciter le bouton ••• ni la branche menu, et sans retirer le contenu #68). Contenu par ailleurs identique à #34.