Branche recherche-partout-68 → main. Ne pas merger sans le go du coordinateur ; aucune version bumpée, aucune issue fermée par cette PR.
Audit des endpoints de recherche réels (vérifié sur main, 2026-10-28)
App
Endpoint JSON
Auth acceptée
Lien profond vérifié
ObsiGate
GET /api/search?q=&vault=all&limit= (SearchResponse.results[] : vault, path, title, snippet)
Bearer access_token, cookie access_token, ou repli cookie SSO draco_session
{og}/#file={vault}:{path}
Flowdeck
GET /api/search?q=
cookie flowdeck_session seulement (sa PR corrige cela)
{fd}/pages/<id>, {fd}/db/<id>
TikTak
GET /api/search?q= (et /api/v1/search)
session native, cookie SSO draco_session, ou Bearer tck_…
{tk}/search?q=<q>&task=<id>
Kanbante
aucun endpoint JSON — page SSR GET /search uniquement (recherche Gitea search_issues via le token serveur, groupée par dépôt, lien /board/<full_name>)
—
{kb}/board/<owner>/<repo> (la carte n'a pas d'URL propre adressable — même limite que la page /search native)
Console agent-commun
aucun endpoint de recherche des discussions ; l'agent n'est pas un hôte de la barre
—
—
Conséquence honnête : pas de section Console (rien à agréger sans inventer une API), et c'est cette PR qui fournit l'endpoint JSON Kanbante manquant.
Architecture choisie : page par hôte + agrégation côté client
Identique aux autres PR du chantier (voir PR TikTak #220 pour l'argumentaire complet) : pas de hub central (SPOF, dépendance runtime entre apps), pas de proxy fan-out serveur (l'hôte ne possède pas de credential sœur sans créer un relais d'identité générique). La page appelle les 4 API en parallèle depuis le navigateur (credentials: "include" : cookies de chaque origine, dont le SSO partagé draco_session, Domain=.dracodev.net), avec debounce 250 ms, timeout 8 s par section, et états chargement/vide/erreur par application (une sœur en panne ne casse pas les autres). Résolution des bases : data-base-* rendus par l'hôte > DRACO_BAR.urls (barre v0.1.6) > dérivation -dev > href des onglets > défauts prod. Aucun fichier ui/barre-apps.* touché. Clavier : / ou Ctrl+K focalise la recherche, ↑/↓ navigue, Entrée ouvre, Échap efface.
Ce qui change (Kanbante)
app/templates/recherche.html (nouveau) + static/js/recherche.js (nouveau, logique partagée du chantier) + static/css/recherche.css (nouveau) : page GET /recherche avec 4 sections (ObsiGate, Flowdeck, TikTak, Kanbante), titre/extrait/contexte par résultat, liens profonds.
app/main.py : route GET /recherche (même render() que /search, qui injecte déjà draco_urls) ; nouvelle route GET /api/search qui réutilise exactement la source de /search (search_issues(q, state="all") sur les connexions du workspace + _group_issue_results) et ne l'expose qu'en JSON filtré (voir ci-dessous). La page /search native est inchangée.
app/recherche.py (nouveau) : conversion groupes_vers_json (seuls numéro, titre, état, corps tronqué à 160 caractères, labels, colonne — aucun autre champ de l'issue Gitea ne sort), CORS bornée (voir ci-dessous) sous forme de middleware ASGI pur, et fonctions pures testables.
app/main.py (AuthMiddleware) : exception étroite — pour le seul chemin /api/search, un jeton SSO draco_session valide (draco.claims_for) autorise la requête, comme les API de recherche des sœurs. Les sessions, Basic et jetons API gardent leurs règles ; les autres chemins sont inchangés. Sans session ni draco, /api/search répond 401 comme les autres /api/* (la section affiche alors « Connexion requise » + le lien vers /search).
app/main.py (middleware) : RechercheCorsMiddleware ajouté après AuthMiddleware (donc exécuté avant lui) — il répond lui-même aux preflights OPTIONS (qui ne portent jamais de cookies) et ajoute les en-têtes CORS aux réponses de /api/searchuniquement pour les origines sœurs résolues (explicite > hôte > dérivation > défaut), jamais *. Les autres routes traversent sans modification.
app/templates/_draco_bar.html : 1 ligne — l'action palette de la barre va désormais sur /recherche au lieu d'ouvrir la palette locale. La palette locale (.palette-trigger, Ctrl+K dans les pages) reste inchangée ; le reste du fragment est inchangé (attention au chantier parallèle sur la barre : conflit possible sur ce fichier, à résoudre au merge).
Tests : tests/test_recherche.py (pytest, 7 tests) + tests/recherche.test.js (Node, 25 assertions : résolution d'URL, liens profonds, normalisation des 4 formats).
CSP : Kanbante n'émet pas de connect-src restrictif (render() ne pose que frame-src) — aucune modification CSP nécessaire ici.
Limites connues (à valider après déploiement)
Les sections ObsiGate, Flowdeck et TikTak restent en erreur tant que leurs PR respectives (CORS bornée, repli draco + auth requise, CORS bornée) ne sont pas déployées — comportement prévu, pas une régression.
Lien profond Kanbante = tableau (/board/<owner>/<repo>), pas la carte elle-même : aucune URL adressable de carte n'existe dans Kanbante (la carte s'ouvre par JS dans le tableau). Le numéro et la colonne sont affichés pour retrouver la carte.
Validation en direct (clic réel sur chaque lien profond, depuis kanbante-dev et kanbante) à faire par Bruno après redéploiement — non vérifiable depuis la sandbox (pas d'accès aux instances).
Tests (chiffres réels, exécutés le 2026-10-28)
node tests/recherche.test.js : 25 assertions OK.
Vérification Python de app/recherche.py (chargé par chemin, pytest absent de la sandbox) : assertions OK — origines sœurs dev, refus tiers, preflight, conversion JSON (plafond, troncature corps à 160, champ parasite exclu), middleware ASGI (preflight sœur → 204 + Access-Control-Allow-Origin exact, preflight tiers → transmis, GET sœur → en-têtes ajoutés).
python3 -m py_compile sur app/main.py, app/recherche.py, tests/test_recherche.py : OK.
Non exécutés ici (dépendances applicatives absentes de la sandbox) : pytest tests/test_recherche.py et le serveur — à valider en CI / après déploiement. Zéro régression revendiquée au-delà de ce qui est mesuré ci-dessus.
## Rechercher partout — page de résultats unifiée + endpoint JSON (fusion #68, chantier 1)
Branche `recherche-partout-68` → `main`. Ne pas merger sans le go du coordinateur ; aucune version bumpée, aucune issue fermée par cette PR.
### Audit des endpoints de recherche réels (vérifié sur `main`, 2026-10-28)
| App | Endpoint JSON | Auth acceptée | Lien profond vérifié |
|---|---|---|---|
| ObsiGate | `GET /api/search?q=&vault=all&limit=` (`SearchResponse.results[] : vault, path, title, snippet`) | Bearer `access_token`, cookie `access_token`, ou repli cookie SSO `draco_session` | `{og}/#file={vault}:{path}` |
| Flowdeck | `GET /api/search?q=` | cookie `flowdeck_session` seulement (sa PR corrige cela) | `{fd}/pages/<id>`, `{fd}/db/<id>` |
| TikTak | `GET /api/search?q=` (et `/api/v1/search`) | session native, cookie SSO `draco_session`, ou Bearer `tck_…` | `{tk}/search?q=<q>&task=<id>` |
| Kanbante | **aucun endpoint JSON** — page SSR `GET /search` uniquement (recherche Gitea `search_issues` via le token serveur, groupée par dépôt, lien `/board/<full_name>`) | — | `{kb}/board/<owner>/<repo>` (la carte n'a pas d'URL propre adressable — même limite que la page `/search` native) |
| Console agent-commun | **aucun endpoint de recherche** des discussions ; l'agent n'est pas un hôte de la barre | — | — |
Conséquence honnête : **pas de section Console** (rien à agréger sans inventer une API), et c'est cette PR qui fournit l'endpoint JSON Kanbante manquant.
### Architecture choisie : page par hôte + agrégation côté client
Identique aux autres PR du chantier (voir PR TikTak #220 pour l'argumentaire complet) : pas de hub central (SPOF, dépendance runtime entre apps), pas de proxy fan-out serveur (l'hôte ne possède pas de credential sœur sans créer un relais d'identité générique). La page appelle les 4 API en parallèle depuis le navigateur (`credentials: "include"` : cookies de chaque origine, dont le SSO partagé `draco_session`, `Domain=.dracodev.net`), avec debounce 250 ms, timeout 8 s par section, et états chargement/vide/erreur **par application** (une sœur en panne ne casse pas les autres). Résolution des bases : `data-base-*` rendus par l'hôte > `DRACO_BAR.urls` (barre v0.1.6) > dérivation `-dev` > href des onglets > défauts prod. Aucun fichier `ui/barre-apps.*` touché. Clavier : `/` ou Ctrl+K focalise la recherche, ↑/↓ navigue, Entrée ouvre, Échap efface.
### Ce qui change (Kanbante)
- `app/templates/recherche.html` (nouveau) + `static/js/recherche.js` (nouveau, logique partagée du chantier) + `static/css/recherche.css` (nouveau) : page `GET /recherche` avec 4 sections (ObsiGate, Flowdeck, TikTak, Kanbante), titre/extrait/contexte par résultat, liens profonds.
- `app/main.py` : route `GET /recherche` (même `render()` que `/search`, qui injecte déjà `draco_urls`) ; **nouvelle route `GET /api/search`** qui réutilise exactement la source de `/search` (`search_issues(q, state="all")` sur les connexions du workspace + `_group_issue_results`) et ne l'expose qu'en JSON filtré (voir ci-dessous). La page `/search` native est **inchangée**.
- `app/recherche.py` (nouveau) : conversion `groupes_vers_json` (seuls numéro, titre, état, corps tronqué à 160 caractères, labels, colonne — aucun autre champ de l'issue Gitea ne sort), CORS bornée (voir ci-dessous) sous forme de middleware ASGI pur, et fonctions pures testables.
- `app/main.py` (`AuthMiddleware`) : **exception étroite** — pour le seul chemin `/api/search`, un jeton SSO `draco_session` valide (`draco.claims_for`) autorise la requête, comme les API de recherche des sœurs. Les sessions, Basic et jetons API gardent leurs règles ; les autres chemins sont inchangés. Sans session ni draco, `/api/search` répond 401 comme les autres `/api/*` (la section affiche alors « Connexion requise » + le lien vers `/search`).
- `app/main.py` (middleware) : `RechercheCorsMiddleware` ajouté après `AuthMiddleware` (donc exécuté avant lui) — il répond lui-même aux preflights OPTIONS (qui ne portent jamais de cookies) et ajoute les en-têtes CORS aux réponses de `/api/search` **uniquement pour les origines sœurs résolues** (explicite > hôte > dérivation > défaut), jamais `*`. Les autres routes traversent sans modification.
- `app/templates/_draco_bar.html` : **1 ligne** — l'action `palette` de la barre va désormais sur `/recherche` au lieu d'ouvrir la palette locale. La palette locale (`.palette-trigger`, Ctrl+K dans les pages) reste inchangée ; le reste du fragment est inchangé (attention au chantier parallèle sur la barre : conflit possible sur ce fichier, à résoudre au merge).
- Tests : `tests/test_recherche.py` (pytest, 7 tests) + `tests/recherche.test.js` (Node, 25 assertions : résolution d'URL, liens profonds, normalisation des 4 formats).
- CSP : Kanbante n'émet pas de `connect-src` restrictif (`render()` ne pose que `frame-src`) — aucune modification CSP nécessaire ici.
### Limites connues (à valider après déploiement)
- Les sections ObsiGate, Flowdeck et TikTak restent en erreur tant que leurs PR respectives (CORS bornée, repli draco + auth requise, CORS bornée) ne sont pas déployées — comportement prévu, pas une régression.
- Lien profond Kanbante = tableau (`/board/<owner>/<repo>`), pas la carte elle-même : aucune URL adressable de carte n'existe dans Kanbante (la carte s'ouvre par JS dans le tableau). Le numéro et la colonne sont affichés pour retrouver la carte.
- Validation en direct (clic réel sur chaque lien profond, depuis `kanbante-dev` et `kanbante`) à faire par Bruno après redéploiement — non vérifiable depuis la sandbox (pas d'accès aux instances).
### Tests (chiffres réels, exécutés le 2026-10-28)
- `node tests/recherche.test.js` : **25 assertions OK**.
- Vérification Python de `app/recherche.py` (chargé par chemin, pytest absent de la sandbox) : **assertions OK** — origines sœurs dev, refus tiers, preflight, conversion JSON (plafond, troncature corps à 160, champ parasite exclu), middleware ASGI (preflight sœur → 204 + `Access-Control-Allow-Origin` exact, preflight tiers → transmis, GET sœur → en-têtes ajoutés).
- `python3 -m py_compile` sur `app/main.py`, `app/recherche.py`, `tests/test_recherche.py` : **OK**.
- Non exécutés ici (dépendances applicatives absentes de la sandbox) : `pytest tests/test_recherche.py` et le serveur — à valider en CI / après déploiement. Zéro régression revendiquée au-delà de ce qui est mesuré ci-dessus.
Complément poussé sur cette branche après création de la PR : sister_origins() accepte désormais l'hôte de la requête (resoudre_urls_draco(hote_requete=...)), et le middleware CORS le lui transmet depuis l'en-tête Host — sinon la résolution retombait sur la configuration seule et ratait l'environnement -dev (le middleware s'exécute avant tout poseur de contexte). Le JS partagé a aussi été mis à jour (compatibilité ESM, globalThis) pour le test ObsiGate. PR toujours mergeable, vérifiée après ces commits.
Complément poussé sur cette branche après création de la PR : sister_origins() accepte désormais l'hôte de la requête (resoudre_urls_draco(hote_requete=...)), et le middleware CORS le lui transmet depuis l'en-tête Host — sinon la résolution retombait sur la configuration seule et ratait l'environnement -dev (le middleware s'exécute avant tout poseur de contexte). Le JS partagé a aussi été mis à jour (compatibilité ESM, globalThis) pour le test ObsiGate. PR toujours mergeable, vérifiée après ces commits.
bruno
merged commit cf98880fc8 into main2026-10-28 12:40:47 -04:00
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.
Rechercher partout — page de résultats unifiée + endpoint JSON (fusion #68, chantier 1)
Branche
recherche-partout-68→main. Ne pas merger sans le go du coordinateur ; aucune version bumpée, aucune issue fermée par cette PR.Audit des endpoints de recherche réels (vérifié sur
main, 2026-10-28)GET /api/search?q=&vault=all&limit=(SearchResponse.results[] : vault, path, title, snippet)access_token, cookieaccess_token, ou repli cookie SSOdraco_session{og}/#file={vault}:{path}GET /api/search?q=flowdeck_sessionseulement (sa PR corrige cela){fd}/pages/<id>,{fd}/db/<id>GET /api/search?q=(et/api/v1/search)draco_session, ou Bearertck_…{tk}/search?q=<q>&task=<id>GET /searchuniquement (recherche Giteasearch_issuesvia le token serveur, groupée par dépôt, lien/board/<full_name>){kb}/board/<owner>/<repo>(la carte n'a pas d'URL propre adressable — même limite que la page/searchnative)Conséquence honnête : pas de section Console (rien à agréger sans inventer une API), et c'est cette PR qui fournit l'endpoint JSON Kanbante manquant.
Architecture choisie : page par hôte + agrégation côté client
Identique aux autres PR du chantier (voir PR TikTak #220 pour l'argumentaire complet) : pas de hub central (SPOF, dépendance runtime entre apps), pas de proxy fan-out serveur (l'hôte ne possède pas de credential sœur sans créer un relais d'identité générique). La page appelle les 4 API en parallèle depuis le navigateur (
credentials: "include": cookies de chaque origine, dont le SSO partagédraco_session,Domain=.dracodev.net), avec debounce 250 ms, timeout 8 s par section, et états chargement/vide/erreur par application (une sœur en panne ne casse pas les autres). Résolution des bases :data-base-*rendus par l'hôte >DRACO_BAR.urls(barre v0.1.6) > dérivation-dev> href des onglets > défauts prod. Aucun fichierui/barre-apps.*touché. Clavier :/ou Ctrl+K focalise la recherche, ↑/↓ navigue, Entrée ouvre, Échap efface.Ce qui change (Kanbante)
app/templates/recherche.html(nouveau) +static/js/recherche.js(nouveau, logique partagée du chantier) +static/css/recherche.css(nouveau) : pageGET /rechercheavec 4 sections (ObsiGate, Flowdeck, TikTak, Kanbante), titre/extrait/contexte par résultat, liens profonds.app/main.py: routeGET /recherche(mêmerender()que/search, qui injecte déjàdraco_urls) ; nouvelle routeGET /api/searchqui réutilise exactement la source de/search(search_issues(q, state="all")sur les connexions du workspace +_group_issue_results) et ne l'expose qu'en JSON filtré (voir ci-dessous). La page/searchnative est inchangée.app/recherche.py(nouveau) : conversiongroupes_vers_json(seuls numéro, titre, état, corps tronqué à 160 caractères, labels, colonne — aucun autre champ de l'issue Gitea ne sort), CORS bornée (voir ci-dessous) sous forme de middleware ASGI pur, et fonctions pures testables.app/main.py(AuthMiddleware) : exception étroite — pour le seul chemin/api/search, un jeton SSOdraco_sessionvalide (draco.claims_for) autorise la requête, comme les API de recherche des sœurs. Les sessions, Basic et jetons API gardent leurs règles ; les autres chemins sont inchangés. Sans session ni draco,/api/searchrépond 401 comme les autres/api/*(la section affiche alors « Connexion requise » + le lien vers/search).app/main.py(middleware) :RechercheCorsMiddlewareajouté aprèsAuthMiddleware(donc exécuté avant lui) — il répond lui-même aux preflights OPTIONS (qui ne portent jamais de cookies) et ajoute les en-têtes CORS aux réponses de/api/searchuniquement pour les origines sœurs résolues (explicite > hôte > dérivation > défaut), jamais*. Les autres routes traversent sans modification.app/templates/_draco_bar.html: 1 ligne — l'actionpalettede la barre va désormais sur/rechercheau lieu d'ouvrir la palette locale. La palette locale (.palette-trigger, Ctrl+K dans les pages) reste inchangée ; le reste du fragment est inchangé (attention au chantier parallèle sur la barre : conflit possible sur ce fichier, à résoudre au merge).tests/test_recherche.py(pytest, 7 tests) +tests/recherche.test.js(Node, 25 assertions : résolution d'URL, liens profonds, normalisation des 4 formats).connect-srcrestrictif (render()ne pose queframe-src) — aucune modification CSP nécessaire ici.Limites connues (à valider après déploiement)
/board/<owner>/<repo>), pas la carte elle-même : aucune URL adressable de carte n'existe dans Kanbante (la carte s'ouvre par JS dans le tableau). Le numéro et la colonne sont affichés pour retrouver la carte.kanbante-devetkanbante) à faire par Bruno après redéploiement — non vérifiable depuis la sandbox (pas d'accès aux instances).Tests (chiffres réels, exécutés le 2026-10-28)
node tests/recherche.test.js: 25 assertions OK.app/recherche.py(chargé par chemin, pytest absent de la sandbox) : assertions OK — origines sœurs dev, refus tiers, preflight, conversion JSON (plafond, troncature corps à 160, champ parasite exclu), middleware ASGI (preflight sœur → 204 +Access-Control-Allow-Originexact, preflight tiers → transmis, GET sœur → en-têtes ajoutés).python3 -m py_compilesurapp/main.py,app/recherche.py,tests/test_recherche.py: OK.pytest tests/test_recherche.pyet le serveur — à valider en CI / après déploiement. Zéro régression revendiquée au-delà de ce qui est mesuré ci-dessus.Complément poussé sur cette branche après création de la PR : sister_origins() accepte désormais l'hôte de la requête (resoudre_urls_draco(hote_requete=...)), et le middleware CORS le lui transmet depuis l'en-tête Host — sinon la résolution retombait sur la configuration seule et ratait l'environnement -dev (le middleware s'exécute avant tout poseur de contexte). Le JS partagé a aussi été mis à jour (compatibilité ESM, globalThis) pour le test ObsiGate. PR toujours mergeable, vérifiée après ces commits.