# #223 — Dev/prod sans noms publics en dur : URLs de l'écosystème par configuration > Ouvert le 2026-10-25 (chantier dev/prod de Bruno). Contexte : l'installation > actuelle (`deepin.lab.home`) devient l'environnement **dev** (noms en `-dev`), > la future installation (`jump.point.mint.home`) sera la **prod** (noms > officiels sans suffixe), identique sauf noms et clés. Règle : aucun nom > public de l'écosystème codé en dur dans le code vivant ; défauts = noms > officiels ; le dev déclare ses `-dev` dans son seul `.env`. ## Configuration (nouveau module `backend/draco_config.py`) Lecture à l'appel, jamais à l'import. Défauts officiels : | Variable | Défaut officiel | Rôle | |---|---|---| | `DRACO_AGENT_URL` | `https://agent.dracodev.net` | Base du service d'agents. À défaut : origine dérivée d'`AGENT_EVENEMENTS_URL`, puis défaut. | | `DRACO_OBSIGATE_URL` | `https://og.dracodev.net` | Liens profonds ObsiGate | | `DRACO_FLOWDECK_URL` | `https://flowdeck.dracodev.net` | Liens profonds Flowdeck | | `DRACO_TIKTAK_URL` | `https://tiktak.dracodev.net` | Liens profonds TikTak | | `DRACO_KANBANTE_URL` | `https://kanbante.dracodev.net` | Onglet Kanbante de la barre | | `DRACO_GITEA_URL` | `https://git.dracodev.net` | Cartes Kanbante (= issues Gitea). Distincte d'`OBSIGATE_GITEA_URL` (source connectée de l'assistant). | `AGENT_EVENEMENTS_URL` (existant, #220) reste la configuration première du journal d'événements ; `agent_journal._url()` retombe sur `DRACO_AGENT_URL + /api/v1/evenements` quand elle est absente. ## Backend - **CSP** (`backend/main.py`, `SecurityHeadersMiddleware`) : `connect-src` et `frame-src` utilisent `draco_config.agent_origine()` — dérivée de la config à chaque réponse, plus aucun littéral. Tests dans `tests/test_security_headers.py` **via la config** (défaut officiel neutralisé, dérivation depuis `AGENT_EVENEMENTS_URL`, priorité `DRACO_AGENT_URL`). - **Références croisées** (`backend/external_refs.py`) : - `parse_deep_link` reconnaît les hôtes officiels **et** configurés (`draco_config.hotes_reconnus()`) — un lien collé depuis le dev comme depuis la prod est reconnu. - `build_deep_link(app, type, id)` construit l'URL d'affichage depuis la config ; `list_refs` / `get_ref` / `delete_ref` servent des copies dont `target_url` est **reconstruite à la lecture**. ⚠️ Les références **stockées** (`data/external_refs/*.json`) gardent l'URL absolue collée par l'utilisateur : aucune migration, la valeur stockée n'est simplement plus jamais servie telle quelle. - **WebAuthn — confirmé, aucun changement** : `resolve_relying_party()` (`backend/auth/webauthn_mfa.py`, BUG-070) dérive `rp_id`/origines de la requête (hôte exact, `X-Forwarded-Host`/`X-Forwarded-Proto` honorés si `OBSIGATE_TRUST_PROXY=true`), et `OBSIGATE_WEBAUTHN_RP_ID` / `OBSIGATE_WEBAUTHN_ORIGINS` priment quand ils sont posés. Aucun nom figé. ## Frontend (contrat d'injection de dracodev-commons) L'hôte fournit les URL : `backend/main.py::_index_html()` injecte `window.DRACO_URLS = {…}` (JSON issu de `draco_config.urls_publiques()`, nonce CSP par le mécanisme existant) dans `index.html` au service. - `frontend/draco-panneau.js` : `API = window.DRACO_URLS.agent || défaut officiel` ; `appHote()` retire un suffixe `-dev` éventuel du premier label d'hôte (`og-dev` → `obsigate` pour le lien profond `?app=`). - `frontend/draco-liens.js` : « Ouvrir dans TikTak » = `window.DRACO_URLS.tiktak || défaut officiel`. - `frontend/index.html` : les `href` des onglets portent les défauts officiels ; le script de configuration de la barre les réécrit depuis `DRACO_URLS`. Le menu des apps (`draco-barre.js`) est construit depuis ces onglets : il suit donc sans changement. - Chemin réellement servi : `/static/draco-*.js` via le montage `StaticFiles`, `Cache-Control: no-cache` posé par `SecurityHeadersMiddleware` sur `/static/*`, et service worker **network-first** pour le code — aucun cache-busting par empreinte n'existe (revalidation systématique). ## Restes assumés - Suffixe SSO `dracodev.net` (`draco_session.validate_return_to`, `frontend/js/auth.js`) : ce n'est pas un nom d'hôte mais le domaine parent commun aux deux environnements (les noms `-dev` restent des sous-domaines) ; le domaine du cookie est déjà configurable (`DRACO_SESSION_COOKIE_DOMAIN`). - Mentions textuelles (titres/messages du panneau, contact OpenAPI et lien « À propos » vers le dépôt Git) : infra Git hors périmètre, ou libellés. - `OBSIGATE_SEARXNG_URL` : déjà configurable, défaut officiel conservé. - Le panneau reste un asset partagé : la même ligne d'injection doit être recopiée dans les 3 autres apps par leurs chantiers respectifs pour retrouver l'octet-identique.