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
|
Accepte requêtes texte (`Inception 2010`), IMDb IDs (`tt0133093`) et URLs
|
||||||
TMDB collées (`themoviedb.org/movie/27205`).
|
TMDB collées (`themoviedb.org/movie/27205`).
|
||||||
|
|
||||||
### `GET /admin`
|
### `GET /admin` — Dashboard admin
|
||||||
Listing protégé des fichiers du projet (mot de passe argon2id).
|
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 :
|
Pour générer un nouveau hash :
|
||||||
```bash
|
```bash
|
||||||
node tools/hashPassword.js 'mon-mot-de-passe'
|
node tools/hashPassword.js 'mon-mot-de-passe'
|
||||||
```
|
```
|
||||||
Puis copier la sortie dans `.env` sous `ADMIN_PASSWORD_HASH=`.
|
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`
|
### `GET /health`
|
||||||
JSON liveness/readiness : status, uptime, mémoire, nombre de notes IMDb
|
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é.
|
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/
|
proxytmdb/
|
||||||
├── server.js # Bootstrap Fastify + rate limit + sessions
|
├── server.js # Bootstrap Fastify + rate limit + sessions + warmup
|
||||||
├── config.js # Constantes, ports, chemins, env vars
|
├── config.js # Env vars, chemins, constantes
|
||||||
├── biome.json # Lint + format
|
├── biome.json # Lint + format
|
||||||
├── public/ # SPA vanilla JS (UI publique)
|
├── public/ # Statique (UI publique + SPA admin)
|
||||||
│ ├── index.html
|
│ ├── index.html # UI publique : recherche + grille posters + modal
|
||||||
│ ├── style.css
|
│ ├── style.css # Theme dark partage
|
||||||
│ └── app.js
|
│ ├── 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/
|
├── lib/
|
||||||
│ ├── paths.js # Layout <type>/<floor(id/1000)>/<id>.json
|
│ ├── paths.js # Layout <type>/<floor(id/1000)>/<id>.json
|
||||||
│ ├── mbLevenshtein.js # Levenshtein UTF-8 par codepoint
|
│ ├── mbLevenshtein.js # Levenshtein UTF-8 par codepoint
|
||||||
│ ├── titleFilter.js # Translit ligatures + filtre Latin/chiffres
|
│ ├── titleFilter.js # Translit ligatures + filtre Latin/chiffres
|
||||||
│ ├── queryParser.js # Extraction annee/episode/titre
|
│ ├── queryParser.js # Extraction annee/episode/titre
|
||||||
│ ├── imdbRatings.js # Index IMDb en memoire (Map)
|
│ ├── imdbRatings.js # Index IMDb en memoire (Map, auto-reload mtime)
|
||||||
│ ├── imdbMapping.js # Mapping IMDb -> TMDb id
|
│ ├── imdbMapping.js # Mapping IMDb -> TMDb id (+ preload au boot)
|
||||||
│ ├── http.js # fetch + retry + concurrence limitee
|
│ ├── http.js # fetch + retry + Limiter de concurrence
|
||||||
│ ├── format.js # Devises et runtime
|
│ ├── format.js # Devises (Intl) + runtime
|
||||||
│ ├── lockFile.js # Lock file PID-based pour le cron
|
│ ├── lockFile.js # Lock PID-based pour le cron (O_EXCL)
|
||||||
│ ├── password.js # Argon2id hash + verify
|
│ ├── password.js # Argon2id hash + verify
|
||||||
│ ├── metrics.js # Counters/Histograms Prometheus
|
│ ├── metrics.js # Counters/Histograms/Gauges Prometheus
|
||||||
│ ├── searchEngine.js # Pool workers + watcher reload chaud
|
│ ├── 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)
|
│ └── searchWorker.js # Worker thread (1 chunk de la base)
|
||||||
├── routes/
|
├── routes/
|
||||||
│ ├── api.js # /api (movie/tv/imdb/providers/search) + cache LRU
|
│ ├── api.js # /api (movie/tv/imdb/providers/search) + cache LRU
|
||||||
│ ├── admin.js # /admin (login argon2 + listing)
|
│ ├── search.js # /search HTML compat ancien PHP
|
||||||
│ └── health.js # /health + /metrics
|
│ ├── admin.js # /admin (login argon2 + dashboard SPA + APIs)
|
||||||
|
│ └── health.js # /health + /metrics (Prometheus)
|
||||||
├── cron/
|
├── cron/
|
||||||
│ ├── runAll.js # Pipeline complet (avec lock file)
|
│ ├── runAll.js # Pipeline complet (avec lock file)
|
||||||
│ ├── run.sh # Wrapper nvm pour crontab
|
│ ├── run.sh # Wrapper nvm pour crontab
|
||||||
│ ├── imdbRatings.js # title.ratings.tsv.gz
|
│ ├── 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
|
│ ├── tmdbSync.js # Sync incrementale via /changes
|
||||||
│ ├── justwatchSync.js # /watch/providers
|
│ ├── justwatchSync.js # /watch/providers
|
||||||
│ ├── tmdb2imdb.js # Mappings bidirectionnels
|
│ ├── tmdb2imdb.js # Mappings bidirectionnels
|
||||||
│ ├── buildSearch.js # Chunks de recherche
|
│ ├── buildSearch.js # Chunks de recherche
|
||||||
│ └── ambiguity.js # Detection des doublons
|
│ └── ambiguity.js # Detection des doublons
|
||||||
├── tools/
|
├── tools/
|
||||||
│ └── hashPassword.js # Outil CLI pour generer un hash argon2
|
│ └── hashPassword.js # CLI : generer un hash argon2id
|
||||||
├── test/
|
├── test/
|
||||||
│ └── helpers.test.js # Tests unitaires
|
│ └── helpers.test.js # Tests unitaires (Levenshtein, query parser, paths)
|
||||||
├── tmdbintegral/ # Donnees (gitignore)
|
├── tmdbintegral/ # Donnees TMDB + JustWatch (gitignore)
|
||||||
└── imdbratings.tsv # Donnees IMDb (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
|
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).
|
démarrage (mémoire résidente, ~120 Mo total).
|
||||||
- L'index IMDb (`imdbratings.tsv`, ~30 Mo, 1.66M lignes) est chargé une fois
|
- 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
|
en `Map` au démarrage. Les mappings IMDb→TMDB (`imdb2movie.json` /
|
||||||
(typiquement après le cron quotidien).
|
`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é à
|
- 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
|
l'identique de l'ancienne version PHP : on peut basculer sans regénérer
|
||||||
les ~1700 dossiers x 1000 fichiers existants.
|
les ~1700 dossiers x 1000 fichiers existants.
|
||||||
- Les 8 workers de recherche sont persistants (vs PHP qui forkait 8
|
- 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.
|
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