MAJ README : architecture, dashboard admin, hot reload, lock cron
This commit is contained in:
75
README.md
75
README.md
@@ -146,14 +146,27 @@ posters, modal de détail avec tagline/overview/budget/revenue/providers FR.
|
||||
Accepte requêtes texte (`Inception 2010`), IMDb IDs (`tt0133093`) et URLs
|
||||
TMDB collées (`themoviedb.org/movie/27205`).
|
||||
|
||||
### `GET /admin`
|
||||
Listing protégé des fichiers du projet (mot de passe argon2id).
|
||||
### `GET /admin` — Dashboard admin
|
||||
SPA protégée par mot de passe (argon2id), 3 onglets, refresh automatique 10 s :
|
||||
|
||||
- **Tableau de bord** — cartes de statut (dernier cron, films/séries TMDB,
|
||||
notes IMDb, cache hit-rate, process), barres d'utilisation disque par
|
||||
catégorie, résumé du cron (compteurs + log tail).
|
||||
- **Métriques** — `/metrics` Prometheus parsé en HTML : table HTTP par route,
|
||||
table latences p50/p95, compteurs internes, process Node.
|
||||
- **Fichiers** — listing du projet, fichiers servis sous `/admin/files/`.
|
||||
|
||||
Pour générer un nouveau hash :
|
||||
```bash
|
||||
node tools/hashPassword.js 'mon-mot-de-passe'
|
||||
```
|
||||
Puis copier la sortie dans `.env` sous `ADMIN_PASSWORD_HASH=`.
|
||||
|
||||
### Endpoints internes admin (auth requise)
|
||||
- `GET /admin/api/stats` — JSON agrégé (cron, fichiers, disque, cache, process)
|
||||
- `GET /admin/api/metrics` — métriques Prometheus parsées en JSON structuré
|
||||
- `GET /admin/api/files` — listing des fichiers du projet en JSON
|
||||
|
||||
### `GET /health`
|
||||
JSON liveness/readiness : status, uptime, mémoire, nombre de notes IMDb
|
||||
chargées. Renvoie 503 si l'index IMDb n'a pas pu être chargé.
|
||||
@@ -171,46 +184,52 @@ Format Prometheus standard : `http_requests_total`, `http_request_duration_secon
|
||||
|
||||
```
|
||||
proxytmdb/
|
||||
├── server.js # Bootstrap Fastify + rate limit + sessions
|
||||
├── config.js # Constantes, ports, chemins, env vars
|
||||
├── server.js # Bootstrap Fastify + rate limit + sessions + warmup
|
||||
├── config.js # Env vars, chemins, constantes
|
||||
├── biome.json # Lint + format
|
||||
├── public/ # SPA vanilla JS (UI publique)
|
||||
│ ├── index.html
|
||||
│ ├── style.css
|
||||
│ └── app.js
|
||||
├── public/ # Statique (UI publique + SPA admin)
|
||||
│ ├── index.html # UI publique : recherche + grille posters + modal
|
||||
│ ├── style.css # Theme dark partage
|
||||
│ ├── app.js # Logique UI publique
|
||||
│ ├── admin.html # SPA admin : 3 onglets
|
||||
│ ├── admin.css # Styles dashboard (cartes, barres, tableaux)
|
||||
│ └── admin.js # Logique dashboard + parsing metriques
|
||||
├── lib/
|
||||
│ ├── paths.js # Layout <type>/<floor(id/1000)>/<id>.json
|
||||
│ ├── mbLevenshtein.js # Levenshtein UTF-8 par codepoint
|
||||
│ ├── titleFilter.js # Translit ligatures + filtre Latin/chiffres
|
||||
│ ├── queryParser.js # Extraction annee/episode/titre
|
||||
│ ├── imdbRatings.js # Index IMDb en memoire (Map)
|
||||
│ ├── imdbMapping.js # Mapping IMDb -> TMDb id
|
||||
│ ├── http.js # fetch + retry + concurrence limitee
|
||||
│ ├── format.js # Devises et runtime
|
||||
│ ├── lockFile.js # Lock file PID-based pour le cron
|
||||
│ ├── imdbRatings.js # Index IMDb en memoire (Map, auto-reload mtime)
|
||||
│ ├── imdbMapping.js # Mapping IMDb -> TMDb id (+ preload au boot)
|
||||
│ ├── http.js # fetch + retry + Limiter de concurrence
|
||||
│ ├── format.js # Devises (Intl) + runtime
|
||||
│ ├── lockFile.js # Lock PID-based pour le cron (O_EXCL)
|
||||
│ ├── password.js # Argon2id hash + verify
|
||||
│ ├── metrics.js # Counters/Histograms Prometheus
|
||||
│ ├── searchEngine.js # Pool workers + watcher reload chaud
|
||||
│ ├── metrics.js # Counters/Histograms/Gauges Prometheus
|
||||
│ ├── stats.js # Agregateur stats admin (TTL cache)
|
||||
│ ├── dataReload.js # Hot reload post-cron (chunks/mappings/ratings)
|
||||
│ ├── searchEngine.js # Pool workers persistants + reloadAllPools()
|
||||
│ └── searchWorker.js # Worker thread (1 chunk de la base)
|
||||
├── routes/
|
||||
│ ├── api.js # /api (movie/tv/imdb/providers/search) + cache LRU
|
||||
│ ├── admin.js # /admin (login argon2 + listing)
|
||||
│ └── health.js # /health + /metrics
|
||||
│ ├── search.js # /search HTML compat ancien PHP
|
||||
│ ├── admin.js # /admin (login argon2 + dashboard SPA + APIs)
|
||||
│ └── health.js # /health + /metrics (Prometheus)
|
||||
├── cron/
|
||||
│ ├── runAll.js # Pipeline complet (avec lock file)
|
||||
│ ├── run.sh # Wrapper nvm pour crontab
|
||||
│ ├── imdbRatings.js # title.ratings.tsv.gz
|
||||
│ ├── tmdbExports.js # Exports quotidiens TMDB
|
||||
│ ├── tmdbExports.js # Exports quotidiens TMDB (avec fallback veille)
|
||||
│ ├── tmdbSync.js # Sync incrementale via /changes
|
||||
│ ├── justwatchSync.js # /watch/providers
|
||||
│ ├── tmdb2imdb.js # Mappings bidirectionnels
|
||||
│ ├── buildSearch.js # Chunks de recherche
|
||||
│ └── ambiguity.js # Detection des doublons
|
||||
├── tools/
|
||||
│ └── hashPassword.js # Outil CLI pour generer un hash argon2
|
||||
│ └── hashPassword.js # CLI : generer un hash argon2id
|
||||
├── test/
|
||||
│ └── helpers.test.js # Tests unitaires
|
||||
├── tmdbintegral/ # Donnees (gitignore)
|
||||
│ └── helpers.test.js # Tests unitaires (Levenshtein, query parser, paths)
|
||||
├── tmdbintegral/ # Donnees TMDB + JustWatch (gitignore)
|
||||
└── imdbratings.tsv # Donnees IMDb (gitignore)
|
||||
```
|
||||
|
||||
@@ -241,10 +260,20 @@ sans année) — top-N IDs identiques dans le même ordre.
|
||||
de recherche** générés par le cron. Le serveur en charge un par worker au
|
||||
démarrage (mémoire résidente, ~120 Mo total).
|
||||
- L'index IMDb (`imdbratings.tsv`, ~30 Mo, 1.66M lignes) est chargé une fois
|
||||
en `Map` au démarrage et rechargé automatiquement quand son `mtime` change
|
||||
(typiquement après le cron quotidien).
|
||||
en `Map` au démarrage. Les mappings IMDb→TMDB (`imdb2movie.json` /
|
||||
`imdb2tv.json`, ~16 Mo combinés) sont préchargés au warmup.
|
||||
- **Hot reload post-cron** : un watcher unifié ([lib/dataReload.js](lib/dataReload.js))
|
||||
déclenche en arrière-plan le rechargement des 3 sources de données dès que
|
||||
les fichiers changent — `fs.watch` (inotify) pour les chunks et mappings,
|
||||
`fs.watchFile` (poll 10s) pour `imdbratings.tsv`. **Aucun redémarrage du
|
||||
serveur n'est nécessaire après le cron quotidien.**
|
||||
- Le layout disque `<type>/<floor(id/1000)>/<id>.json` est conservé à
|
||||
l'identique de l'ancienne version PHP : on peut basculer sans regénérer
|
||||
les ~1700 dossiers x 1000 fichiers existants.
|
||||
- Les 8 workers de recherche sont persistants (vs PHP qui forkait 8
|
||||
processus à chaque requête). Gain mesuré : ~30% sur le temps de réponse.
|
||||
- Le cron utilise un **lock file PID** (`.cron.lock`) — si le précédent run
|
||||
n'est pas terminé (ou tourne toujours), le suivant échoue proprement.
|
||||
- Logs cron : `cron.txt` (start/finish dates) + `lastcron.txt` (sortie
|
||||
complète stdout, redirigée par crontab). Les deux sont gitignored et
|
||||
régénérés à chaque run.
|
||||
|
||||
Reference in New Issue
Block a user