--- name: ticket13-f0-frontend-transport-inventory description: Résultat de l'inventaire B0/F0 frontend du chantier client/serveur #13 — la frontière gateways transport-neutres existe déjà, F1 = ajout d'adapters HTTP+WS. metadata: type: reference --- Inventaire B0/F0 (ticket #13 server/client mode), côté frontend TS/React. Doc : `docs/ticket13-f0-frontend-transport-inventory.md`. **Constat clé** : la frontière « gateways TS transport-neutres » du plan est DÉJÀ réalisée et testée. - `src/ports/index.ts` = 21 gateways sans Tauri ; toute la couche `features/`+`app/` en dépend via DI (`useGateways()`). - `src/adapters/*` = seul lieu important `@tauri-apps/api`. - Garde L1 `src/app/no-direct-invoke.test.ts` casse la CI si un fichier hors `adapters` importe Tauri / appelle `invoke(`. - `src/app/di.tsx` `resolveGateways()` bifurque déjà Tauri vs mock → F1 = ajouter `createHttpWsGateways()` (3ᵉ impl). **Donc F1 = écrire un 2ᵉ jeu d'adapters derrière des ports inchangés, aucun composant métier à réécrire.** **Flux Channel (→ WebSocket)** : (1) `terminal.ts` PTY, (2) `agent.ts` PTY agent (réutilise `makeTerminalHandle`), (3) `ticket.ts` `sendTicketChat` `Channel`. Tous modélisés côté port par callback `onData`/`onChunk`. Le contrat PTY WS du carnet mappe 1-pour-1 sur `TerminalHandle` (write/resize/detach/close, detach≠close, scrollback au reattach) → port inchangé pour F3. `TerminalView.tsx` ne connaît que le port. **Event portable** : `system.onDomainEvent("domain://event")` (bus domaine) → WS serveur→client. **Desktop-only à cadrer** : `system.pickFolder` (dossier = machine serveur ≠ client web → file-picker serveur), `window.ts` (WebviewWindow OS) et `focusedProject.ts` (multi-fenêtres OS) probablement hors V1 web. `uiPreferences` (localStorage) marche tel quel. Convention DTO à préserver côté adapter HTTP : commandes snake_case, payloads camelCase souvent enveloppés `{ request: {...} }`.