feat(docs): documentation web des API (Swagger UI) liée depuis le menu
CI / build-and-test (push) Successful in 15m9s
CI / build-and-test (push) Successful in 15m9s
Le lien « API » du menu ouvre /api/docs (et /proxy/api/docs) : Swagger UI
auto-hébergé (swagger-ui-dist, aucun CDN, thème sombre), spécification chargée
depuis `${base}/openapi.json`.
/openapi.json devient exhaustif :
- inventaire généré depuis l'arbre Express (collectApiRoutes) : `:param` →
`{param}`, `*` → `{path}`, miroirs /proxy/* et métadonnées écartés, préfixe
/api retiré (le document porte les serveurs /api et /proxy/api) ;
- `app.all()` réduit à GET — ses 35 méthodes HTTP (acl, propfind, m-search…)
entraient dans le document et figaient Swagger au bout de 2 groupes ;
- authentification marquée automatiquement (middlewares de route ET de préfixe,
ex. `r.use('/download', …)`), route publique laissée publique ;
- tags + descriptions de groupe, résumés FR pour les routes courantes ;
- 3 schémas d'auth : bearerAuth (JWT), apiKeyAuth (X-API-Key), cookieAuth ;
- description : méthodes d'auth avec exemples, codes d'erreur et seuils de
débit, section « Serveur MCP » avec snippet `mcpServers` et la liste des
outils LUE dans mcp/server.mjs au démarrage (aucune liste à maintenir).
Dockerfile : `mcp/` copié dans l'image (cette lecture doit exister en prod).
package.json → 1.0.61 (tag de cette livraison).
Tests : api_coverage +3 cas (page /docs + assets, exhaustivité/méthodes/tags/
sécurité, 3 schémas + outils MCP dans la description) → 51/51 verts.
Vérifs instance locale : lien menu = /proxy/api/docs, 114 opérations rendues
sur 12 groupes, bouton Authorize + section MCP visibles, zéro erreur console.
This commit is contained in:
@@ -275,9 +275,10 @@ Légende : **✅ livré** (câblé de bout en bout) · **🟡 partiellement livr
|
||||
* ✅ **Import/Export playlists (JSON)** — `GET /playlists/export` (dump complet + items, format `newtube-playlists-v1`), `POST /playlists/import` (création des listes manquantes, dédoublonnage par titre au réimport, compteurs détaillés ; bornes 200 listes / 5 000 vidéos par liste) ; boutons **[Exporter] [Importer]** sur `/#/library/playlists`.
|
||||
* ✅ **Page Administration** (`/#/admin`, entrée « Administration » de la section Informations dans la barre latérale) — `/healthz` + `/api/providers/metrics` rendus lisibles : statut API, mode YouTube, version et santé yt-dlp, clés actives / bannies (+ suffixes), anti-ban (cookies / PO token / proxy), cache de recherche par provider, compteurs 1 h par provider, quota YouTube du jour. Au passage : `healthz` servi aussi sous `/proxy/api/healthz` (le chemin que le front utilise en prod). *Journaux et exposition Prometheus livrés — voir Observabilité.*
|
||||
* ✅ **Cache TTL par provider** — `server/env-ttl.mjs` (`<BASE>_<PROVIDER>` → `<BASE>` → défaut, valeurs invalides ignorées, jamais de TTL nul) branché sur les caches **details** (`DETAILS_CACHE_TTL_MS_<P>`) et **transcripts** (`TRANSCRIPT_CACHE_TTL_<P>`) en plus de la recherche (`SEARCH_CACHE_TTL_MS_<P>`). Le cache **suggest** reste global par conception : sa clé agrégée couvre plusieurs providers d'un coup, un TTL par provider demanderait de scinder le cache. Tests : `npm run test:cache`
|
||||
* ✅ **Menu du compte refondu** (bouton avatar, haut à droite du header) — panneau sombre à lignes « icône + titre gras + sous-titre gris » : **Thème** (thème réellement appliqué en sous-titre, pastilles dépliées au clic), **Administration** (`/#/admin`), **API** (`/proxy/api/openapi.json` dans un nouvel onglet), **Préférences** (`/#/account/preferences`), **Guide d'utilisation** (`/#/info/utilisation`), **À propos** (version, tagline, lien code source), **Sessions** (`/#/account/sessions`), **Déconnexion** ; pied de page **Version** = version officielle de l'application (`src/app/version.ts`, alignée sur le tag semver publié par `docker/deploy-img.sh`). Clés i18n déclarées des deux côtés (FR + EN)
|
||||
* ✅ **Menu du compte refondu** (bouton avatar, haut à droite du header) — panneau sombre à lignes « icône + titre gras + sous-titre gris » : **Thème** (thème réellement appliqué en sous-titre, pastilles dépliées au clic), **Administration** (`/#/admin`), **API** (`/proxy/api/docs` : Swagger UI dans un nouvel onglet), **Préférences** (`/#/account/preferences`), **Guide d'utilisation** (`/#/info/utilisation`), **À propos** (version, tagline, lien code source), **Sessions** (`/#/account/sessions`), **Déconnexion** ; pied de page **Version** = version officielle de l'application (`src/app/version.ts`, alignée sur le tag semver publié par `docker/deploy-img.sh`). Clés i18n déclarées des deux côtés (FR + EN)
|
||||
* ✅ **Observabilité** — `GET /healthz` (mode `YT_SEARCH_MODE`, binaire yt-dlp, cache, quota du jour, clés masquées — testé par `test:api`), `GET /api/providers/metrics` et la **page Admin** qui les rend, **journal JSON structuré en prod** (une ligne par requête : `ts`, `reqId`, `method`, `route`, `status`, `ms`, adossé au header `X-Request-Id` renvoyé sur chaque réponse) et **`GET /metrics`** — exposition Prometheus sans dépendance (`http_requests_total` par route et code, somme/nombre de durées, démarrage + mémoire du processus ; `METRICS_TOKEN` verrouille l'accès si défini)
|
||||
* ✅ **API production-ready (P0 + P1)** — **plus aucun secret servi au navigateur** : `/assets/config.local.js` est généré par le serveur **avant** les montages statiques (il l'emporte donc sur le fichier local) et ne contient plus `YOUTUBE_API_KEY(S)`, le fichier local n'est plus copié dans l'image Docker ni embarqué dans `dist`, et les appels YouTube passent par `/api/yt` uniquement (clé, rotation, quota et cache côté serveur — suppression des appels directs à googleapis et des gardes « pas de clé ⇒ écran vide ») ; **CORS piloté par `API_ALLOWED_ORIGINS`** (CSV) + méthode `PATCH` (requis par `/user/preferences`) ; **clés d'API longue durée** : `GET/POST /api/keys` + `DELETE /api/keys/:id`, jeton `ntk_…` affiché une seule fois, stocké en SHA-256 avec préfixe affichable, header `X-API-Key` accepté par les **deux** middlewares d'auth (toutes les routes protégées deviennent scriptables), `last_used_at` renseigné à chaque usage ; **`X-Request-Id`** en réponse sur chaque requête ; **`/api/details` rate-limité** (`DETAILS_RATE_LIMIT`, 60/min, réponse JSON — `/api/transcript` avait déjà le sien) ; **version unique `package.json`** (menu du compte + `info.version` de l'OpenAPI). Tests : `npm run test:api`
|
||||
* ✅ **Documentation des API (Swagger UI)** — lien **API** du menu → `/proxy/api/docs` : Swagger UI auto-hébergé (`swagger-ui-dist`, aucun CDN, thème sombre) branché sur `/openapi.json`, **contrat exhaustif généré depuis l'arbre Express** — 93 chemins / 115 opérations contre 20 chemins avant : les entrées écrites à la main gardent paramètres et réponses, le reste est dérivé du code (`:param` → `{param}`, `*` → `{path}`, miroirs `/proxy/*` et métadonnées écartés, `app.all` réduit à GET — les 35 méthodes HTTP faisaient planter Swagger), tags + descriptions de groupe, **3 schémas d'authentification** (JWT `Authorization: Bearer`, clé `X-API-Key`, cookie httpOnly) avec bouton **Authorize**, et une section **« Serveur MCP »** dans la présentation : outils **lus dans `mcp/server.mjs` au démarrage** (aucune liste à maintenir), snippet `mcpServers`, `NEWTUBE_API_URL` / `NEWTUBE_TOKEN` ; `mcp/` est copié dans l'image pour que cette lecture existe en prod. Tests : `npm run test:api` (+3 cas : page + assets, exhaustivité/méthodes/tags/sécurité, auth + MCP)
|
||||
|
||||
### 🟡 Partiellement livré
|
||||
|
||||
|
||||
Reference in New Issue
Block a user