chore: update various components and services for improved functionality and consistency, including formatting adjustments and minor refactors

This commit is contained in:
Julien Froidefond
2025-12-07 09:54:05 +01:00
parent 4f5724c0ff
commit 39e3328123
141 changed files with 5292 additions and 3243 deletions

View File

@@ -15,12 +15,14 @@ CACHE_DEBUG=true
### Configuration
#### Développement (docker-compose.dev.yml)
```yaml
environment:
- CACHE_DEBUG=true
```
#### Production (.env)
```env
CACHE_DEBUG=true
```
@@ -30,49 +32,61 @@ CACHE_DEBUG=true
Les logs de cache apparaissent dans la console serveur avec le format suivant :
### Cache HIT (donnée valide)
```
[CACHE HIT] home-ongoing | HOME | 0.45ms
```
- ✅ Donnée trouvée en cache
- ✅ Donnée encore valide (pas expirée)
- ⚡ Retour immédiat (très rapide)
### Cache STALE (donnée expirée)
```
[CACHE STALE] home-ongoing | HOME | 0.52ms
```
- ✅ Donnée trouvée en cache
- ⚠️ Donnée expirée mais toujours retournée
- 🔄 Revalidation lancée en background
### Cache MISS (pas de donnée)
```
[CACHE MISS] home-ongoing | HOME
```
- ❌ Aucune donnée en cache
- 🌐 Fetch normal depuis Komga
- 💾 Mise en cache automatique
### Cache SET (mise en cache)
```
[CACHE SET] home-ongoing | HOME | 324.18ms
```
- 💾 Donnée mise en cache après fetch
- 📊 Temps total incluant le fetch Komga
- ✅ Prochaines requêtes seront rapides
### Cache REVALIDATE (revalidation background)
```
[CACHE REVALIDATE] home-ongoing | HOME | 287.45ms
```
- 🔄 Revalidation en background (après STALE)
- 🌐 Nouvelle donnée fetched depuis Komga
- 💾 Cache mis à jour pour les prochaines requêtes
### Erreur de revalidation
```
[CACHE REVALIDATE ERROR] home-ongoing: Error: ...
```
- ❌ Échec de la revalidation background
- ⚠️ Cache ancien conservé
- 🔄 Retry au prochain STALE
@@ -81,14 +95,14 @@ Les logs de cache apparaissent dans la console serveur avec le format suivant :
Les logs affichent le type de TTL utilisé :
| Type | TTL | Usage |
|------|-----|-------|
| `DEFAULT` | 5 min | Données génériques |
| `HOME` | 10 min | Page d'accueil |
| `LIBRARIES` | 24h | Bibliothèques |
| `SERIES` | 5 min | Séries |
| `BOOKS` | 5 min | Livres |
| `IMAGES` | 7 jours | Images |
| Type | TTL | Usage |
| ----------- | ------- | ------------------ |
| `DEFAULT` | 5 min | Données génériques |
| `HOME` | 10 min | Page d'accueil |
| `LIBRARIES` | 24h | Bibliothèques |
| `SERIES` | 5 min | Séries |
| `BOOKS` | 5 min | Livres |
| `IMAGES` | 7 jours | Images |
## Exemple de session complète
@@ -113,22 +127,27 @@ Les logs affichent le type de TTL utilisé :
### 1. DevTools du navigateur
#### Network Tab
- Temps de réponse < 50ms = probablement du cache serveur
- Headers `X-Cache` si configurés
- Onglet "Timing" pour détails
#### Application → Cache Storage
Inspectez le cache du Service Worker :
- `stripstream-cache-v1` : Ressources statiques
- `stripstream-images-v1` : Images (covers + pages)
Actions disponibles :
- ✅ Voir le contenu de chaque cache
- 🔍 Chercher une URL spécifique
- 🗑️ Supprimer des entrées
- 🧹 Vider complètement un cache
#### Application → Service Workers
- État du Service Worker
- "Unregister" pour le désactiver
- "Update" pour forcer une mise à jour
@@ -137,10 +156,13 @@ Actions disponibles :
### 2. API de monitoring
#### Taille du cache
```bash
curl http://localhost:3000/api/komga/cache/size
```
Response :
```json
{
"sizeInBytes": 15728640,
@@ -149,10 +171,13 @@ Response :
```
#### Mode actuel
```bash
curl http://localhost:3000/api/komga/cache/mode
```
Response :
```json
{
"mode": "memory"
@@ -160,11 +185,13 @@ Response :
```
#### Vider le cache
```bash
curl -X POST http://localhost:3000/api/komga/cache/clear
```
#### Changer de mode
```bash
curl -X POST http://localhost:3000/api/komga/cache/mode \
-H "Content-Type: application/json" \
@@ -190,6 +217,7 @@ cat .cache/user-id/home-ongoing.json | jq
```
Exemple de contenu :
```json
{
"data": {
@@ -206,6 +234,7 @@ Exemple de contenu :
### Identifier un problème de cache
**Symptôme** : Les données ne se rafraîchissent pas
```bash
# 1. Vérifier si STALE + REVALIDATE se produisent
CACHE_DEBUG=true
@@ -222,6 +251,7 @@ CACHE_DEBUG=true
### Optimiser les performances
**Objectif** : Identifier les requêtes lentes
```bash
# Activer les logs
CACHE_DEBUG=true
@@ -231,7 +261,8 @@ CACHE_DEBUG=true
[CACHE SET] library-456-all-series | SERIES | 2847.32ms # ⚠️ Très lent !
```
**Solution** :
**Solution** :
- Vérifier la taille des bibliothèques
- Augmenter le TTL pour ces données
- Considérer la pagination
@@ -251,29 +282,33 @@ En mode `file` : les caches survivent au redémarrage
### Temps de réponse normaux
| Scénario | Temps attendu | Log |
|----------|---------------|-----|
| Cache HIT | < 1ms | `[CACHE HIT] ... \| 0.45ms` |
| Cache STALE | < 1ms | `[CACHE STALE] ... \| 0.52ms` |
| Cache MISS (petit) | 50-200ms | `[CACHE SET] ... \| 124.18ms` |
| Cache MISS (gros) | 200-1000ms | `[CACHE SET] ... \| 847.32ms` |
| Revalidate (background) | Variable | `[CACHE REVALIDATE] ... \| 287.45ms` |
| Scénario | Temps attendu | Log |
| ----------------------- | ------------- | ------------------------------------ |
| Cache HIT | < 1ms | `[CACHE HIT] ... \| 0.45ms` |
| Cache STALE | < 1ms | `[CACHE STALE] ... \| 0.52ms` |
| Cache MISS (petit) | 50-200ms | `[CACHE SET] ... \| 124.18ms` |
| Cache MISS (gros) | 200-1000ms | `[CACHE SET] ... \| 847.32ms` |
| Revalidate (background) | Variable | `[CACHE REVALIDATE] ... \| 287.45ms` |
### Signaux d'alerte
⚠️ **Cache HIT > 10ms**
- Problème : Disque lent (mode file)
- Solution : Vérifier les I/O, passer en mode memory
⚠️ **Cache MISS > 2000ms**
- Problème : Komga très lent ou données énormes
- Solution : Vérifier Komga, optimiser la requête
⚠️ **REVALIDATE ERROR fréquents**
- Problème : Komga instable ou réseau
- Solution : Augmenter les timeouts, vérifier la connectivité
⚠️ **Trop de MISS successifs**
- Problème : Cache pas conservé ou TTL trop court
- Solution : Vérifier le mode, augmenter les TTL
@@ -294,12 +329,14 @@ Les logs sont **automatiquement désactivés** si la variable n'est pas définie
## Logs et performance
**Impact sur les performances** :
- Overhead : < 0.1ms par opération
- Pas d'écriture disque (juste console)
- Pas d'accumulation en mémoire
- Safe pour la production
**Recommandations** :
- ✅ Activé en développement
- ✅ Activé temporairement en production pour diagnostics
- ❌ Pas nécessaire en production normale
@@ -307,6 +344,7 @@ Les logs sont **automatiquement désactivés** si la variable n'est pas définie
## Conclusion
Le système de logs de cache est conçu pour être :
- 🎯 **Simple** : Format clair et concis
-**Rapide** : Impact négligeable sur les performances
- 🔧 **Utile** : Informations essentielles pour le debug
@@ -314,4 +352,3 @@ Le système de logs de cache est conçu pour être :
Pour la plupart des besoins de debug, les DevTools du navigateur suffisent.
Les logs serveur sont utiles pour comprendre le comportement du cache côté backend.

View File

@@ -34,9 +34,11 @@ Le système de caching est organisé en **3 couches indépendantes** avec des re
## Couche 1 : Service Worker (Client)
### Fichier
`public/sw.js`
### Responsabilité
- Support offline de l'application
- Cache persistant des images (couvertures et pages de livres)
- Cache des ressources statiques Next.js
@@ -44,20 +46,22 @@ Le système de caching est organisé en **3 couches indépendantes** avec des re
### Stratégies
#### Images : Cache-First
```javascript
// Pour toutes les images (covers + pages)
const isImageResource = (url) => {
return (
(url.includes("/api/v1/books/") &&
(url.includes("/api/v1/books/") &&
(url.includes("/pages") || url.includes("/thumbnail") || url.includes("/cover"))) ||
(url.includes("/api/komga/images/") &&
(url.includes("/series/") || url.includes("/books/")) &&
(url.includes("/api/komga/images/") &&
(url.includes("/series/") || url.includes("/books/")) &&
url.includes("/thumbnail"))
);
};
```
**Comportement** :
1. Vérifier si l'image est dans le cache
2. Si oui → retourner depuis le cache
3. Si non → fetch depuis le réseau
@@ -65,11 +69,13 @@ const isImageResource = (url) => {
5. Si échec → retourner 404
**Avantages** :
- Performance maximale (lecture instantanée depuis le cache)
- Fonctionne offline une fois les images chargées
- Économise la bande passante
#### Navigation et ressources statiques : Network-First
```javascript
// Pour les pages et ressources _next/static
event.respondWith(
@@ -85,7 +91,7 @@ event.respondWith(
// Fallback sur le cache si offline
const cachedResponse = await cache.match(request);
if (cachedResponse) return cachedResponse;
// Page offline si navigation
if (request.mode === "navigate") {
return cache.match("/offline.html");
@@ -95,18 +101,20 @@ event.respondWith(
```
**Avantages** :
- Toujours la dernière version quand online
- Fallback offline si nécessaire
- Navigation fluide même sans connexion
### Caches
| Cache | Usage | Stratégie | Taille |
|-------|-------|-----------|--------|
| `stripstream-cache-v1` | Ressources statiques + pages | Network-First | ~5 MB |
| `stripstream-images-v1` | Images (covers + pages) | Cache-First | Illimité |
| Cache | Usage | Stratégie | Taille |
| ----------------------- | ---------------------------- | ------------- | -------- |
| `stripstream-cache-v1` | Ressources statiques + pages | Network-First | ~5 MB |
| `stripstream-images-v1` | Images (covers + pages) | Cache-First | Illimité |
### Nettoyage
- Automatique lors de l'activation du Service Worker
- Suppression des anciennes versions de cache
- Pas d'expiration (contrôlé par l'utilisateur via les paramètres du navigateur)
@@ -114,9 +122,11 @@ event.respondWith(
## Couche 2 : ServerCacheService (Serveur)
### Fichier
`src/lib/services/server-cache.service.ts`
### Responsabilité
- Cache des réponses API Komga côté serveur
- Optimisation des temps de réponse
- Réduction de la charge sur Komga
@@ -126,6 +136,7 @@ event.respondWith(
Cette stratégie est **la clé de la performance** de l'application.
#### Principe
```
Requête → Cache existe ?
├─ Non → Fetch normal + mise en cache
@@ -136,6 +147,7 @@ Requête → Cache existe ?
```
#### Implémentation
```typescript
async getOrSet<T>(
key: string,
@@ -144,7 +156,7 @@ async getOrSet<T>(
): Promise<T> {
const cacheKey = `${user.id}-${key}`;
const cachedResult = this.getStale(cacheKey);
if (cachedResult !== null) {
const { data, isStale } = cachedResult;
@@ -164,12 +176,14 @@ async getOrSet<T>(
```
#### Avantages
**Temps de réponse constant** : Le cache expiré est retourné instantanément
**Données fraîches** : Revalidation en background pour la prochaine requête
**Pas de délai** : L'utilisateur ne subit jamais l'attente de revalidation
**Résilience** : Même si Komga est lent, l'app reste rapide
#### Inconvénients
⚠️ Les données peuvent être légèrement obsolètes (jusqu'au prochain refresh)
⚠️ Nécessite un cache initialisé (première requête toujours lente)
@@ -178,9 +192,11 @@ async getOrSet<T>(
L'utilisateur peut choisir entre deux modes :
#### Mode Mémoire (par défaut)
```typescript
cacheMode: "memory"
cacheMode: "memory";
```
- Cache stocké en RAM
- **Performances** : Très rapide (lecture < 1ms)
- **Persistance** : Perdu au redémarrage du serveur
@@ -188,9 +204,11 @@ cacheMode: "memory"
- **Idéal pour** : Développement, faible charge
#### Mode Fichier
```typescript
cacheMode: "file"
cacheMode: "file";
```
- Cache stocké sur disque (`.cache/`)
- **Performances** : Rapide (lecture 5-10ms)
- **Persistance** : Survit aux redémarrages
@@ -201,14 +219,14 @@ cacheMode: "file"
Chaque type de données a un TTL configuré :
| Type | TTL par défaut | Justification |
|------|----------------|---------------|
| `DEFAULT` | 5 minutes | Données génériques |
| `HOME` | 10 minutes | Page d'accueil (données agrégées) |
| `LIBRARIES` | 24 heures | Bibliothèques (rarement modifiées) |
| `SERIES` | 5 minutes | Séries (métadonnées + progression) |
| `BOOKS` | 5 minutes | Livres (métadonnées + progression) |
| `IMAGES` | 7 jours | Images (immuables) |
| Type | TTL par défaut | Justification |
| ----------- | -------------- | ---------------------------------- |
| `DEFAULT` | 5 minutes | Données génériques |
| `HOME` | 10 minutes | Page d'accueil (données agrégées) |
| `LIBRARIES` | 24 heures | Bibliothèques (rarement modifiées) |
| `SERIES` | 5 minutes | Séries (métadonnées + progression) |
| `BOOKS` | 5 minutes | Livres (métadonnées + progression) |
| `IMAGES` | 7 jours | Images (immuables) |
#### Configuration personnalisée
@@ -235,6 +253,7 @@ const cacheKey = `${user.id}-${key}`;
```
**Avantages** :
- Pas de collision entre utilisateurs
- Progression de lecture individuelle
- Préférences personnalisées
@@ -244,18 +263,21 @@ const cacheKey = `${user.id}-${key}`;
Le cache peut être invalidé :
#### Manuellement
```typescript
await cacheService.delete(key); // Une clé
await cacheService.deleteAll(prefix); // Toutes les clés avec préfixe
await cacheService.clear(); // Tout le cache
await cacheService.delete(key); // Une clé
await cacheService.deleteAll(prefix); // Toutes les clés avec préfixe
await cacheService.clear(); // Tout le cache
```
#### Automatiquement
- Lors d'une mise à jour de progression
- Lors d'un changement de favoris
- Lors de la suppression d'une série
#### API
```
DELETE /api/komga/cache/clear // Vider tout le cache
DELETE /api/komga/home // Invalider le cache home
@@ -264,12 +286,14 @@ DELETE /api/komga/home // Invalider le cache home
## Couche 3 : Cache HTTP (Navigateur)
### Responsabilité
- Cache basique géré par le navigateur
- Headers HTTP standard
### Configuration
#### Next.js ISR (Incremental Static Regeneration)
```typescript
export const revalidate = 60; // Revalidation toutes les 60 secondes
```
@@ -279,20 +303,23 @@ Utilisé uniquement pour les routes avec rendu statique.
#### Headers explicites (désactivé)
Les headers HTTP explicites ont été **supprimés** car :
- Le ServerCacheService gère déjà le caching efficacement
- Évite la confusion entre plusieurs couches de cache
- Simplifie le debugging
Avant (supprimé) :
```typescript
NextResponse.json(data, {
headers: {
'Cache-Control': 'public, s-maxage=60, stale-while-revalidate=120'
}
"Cache-Control": "public, s-maxage=60, stale-while-revalidate=120",
},
});
```
Maintenant :
```typescript
NextResponse.json(data); // Pas de headers
```
@@ -322,29 +349,32 @@ Exemple : Chargement de la page d'accueil
### Temps de réponse typiques
| Scénario | Temps | Détails |
|----------|-------|---------|
| Cache ServerCache valide + SW | ~50ms | Optimal |
| Cache ServerCache expiré + SW | ~50ms | Revalidation en background |
| Pas de cache ServerCache + SW | ~200-500ms | Première requête |
| Cache SW uniquement | ~10ms | Images seulement |
| Tout à froid | ~500-1000ms | Pire cas |
| Scénario | Temps | Détails |
| ----------------------------- | ----------- | -------------------------- |
| Cache ServerCache valide + SW | ~50ms | Optimal |
| Cache ServerCache expiré + SW | ~50ms | Revalidation en background |
| Pas de cache ServerCache + SW | ~200-500ms | Première requête |
| Cache SW uniquement | ~10ms | Images seulement |
| Tout à froid | ~500-1000ms | Pire cas |
## Cas d'usage
### 1. Première visite
```
User → App → Komga (tous les caches vides)
Temps : ~500-1000ms
```
### 2. Visite suivante (online)
```
User → ServerCache (valide) → Images SW
Temps : ~50ms
```
### 3. Cache expiré (online)
```
User → ServerCache (stale) → Retour immédiat
@@ -353,6 +383,7 @@ Temps ressenti : ~50ms (aucun délai)
```
### 4. Mode offline
```
User → Service Worker cache uniquement
Fonctionnalités :
@@ -373,6 +404,7 @@ CACHE_DEBUG=true
```
**Format des logs** :
```
[CACHE HIT] home-ongoing | HOME | 0.45ms # Cache valide
[CACHE STALE] home-ongoing | HOME | 0.52ms # Cache expiré (retourné + revalidation)
@@ -386,24 +418,28 @@ CACHE_DEBUG=true
### API de monitoring
#### Taille du cache serveur
```bash
GET /api/komga/cache/size
Response: { sizeInBytes: 15728640, itemCount: 234 }
```
#### Mode de cache actuel
```bash
GET /api/komga/cache/mode
Response: { mode: "memory" }
```
#### Changer le mode
```bash
POST /api/komga/cache/mode
Body: { mode: "file" }
```
#### Vider le cache
```bash
POST /api/komga/cache/clear
```
@@ -411,21 +447,26 @@ POST /api/komga/cache/clear
### DevTools du navigateur
#### Network Tab
- Temps de réponse < 50ms = cache serveur
- Headers `X-Cache` si configurés
- Onglet "Timing" pour détails
#### Application → Cache Storage
Inspecter le Service Worker :
- `stripstream-cache-v1` : Ressources statiques
- `stripstream-images-v1` : Images
Actions disponibles :
- Voir le contenu
- Supprimer des entrées
- Vider complètement
#### Application → Service Workers
- État du Service Worker
- "Unregister" pour le désactiver
- "Update" pour forcer une mise à jour
@@ -433,21 +474,25 @@ Actions disponibles :
## Optimisations futures possibles
### 1. Cache Redis (optionnel)
- Pour un déploiement multi-instances
- Cache partagé entre plusieurs serveurs
- TTL natif Redis
### 2. Compression
- Compresser les données en cache (Brotli/Gzip)
- Économie d'espace disque/mémoire
- Trade-off CPU vs espace
### 3. Prefetching intelligent
- Précharger les séries en cours de lecture
- Précharger les pages suivantes dans le reader
- Basé sur l'historique utilisateur
### 4. Cache Analytics
- Ratio hit/miss
- Temps de réponse moyens
- Identification des données les plus consultées
@@ -456,7 +501,8 @@ Actions disponibles :
### Pour les développeurs
**Utiliser BaseApiService.fetchWithCache()**
**Utiliser BaseApiService.fetchWithCache()**
```typescript
await this.fetchWithCache<T>(
"cache-key",
@@ -465,12 +511,14 @@ await this.fetchWithCache<T>(
);
```
**Invalider le cache après modification**
**Invalider le cache après modification**
```typescript
await HomeService.invalidateHomeCache();
```
**Choisir le bon TTL**
**Choisir le bon TTL**
- Court (1-5 min) : Données qui changent souvent
- Moyen (10-30 min) : Données agrégées
- Long (24h+) : Données quasi-statiques
@@ -499,4 +547,3 @@ Le système de caching de StripStream est conçu pour :
🧹 **Simplicité** : 3 couches bien définies, pas de redondance
Le système est maintenu simple avec des responsabilités claires pour chaque couche, facilitant la maintenance et l'évolution future.

View File

@@ -7,12 +7,10 @@ Service de gestion de l'authentification
### Méthodes
- `loginUser(email: string, password: string): Promise<UserData>`
- Authentifie un utilisateur
- Retourne les données utilisateur
- `createUser(email: string, password: string): Promise<UserData>`
- Crée un nouvel utilisateur
- Retourne les données utilisateur
@@ -26,12 +24,10 @@ Service de gestion des bibliothèques
### Méthodes
- `getLibraries(): Promise<Library[]>`
- Récupère la liste des bibliothèques
- Met en cache les résultats
- `getLibrary(libraryId: string): Promise<Library>`
- Récupère une bibliothèque spécifique
- Lance une erreur si non trouvée
@@ -51,11 +47,9 @@ Service de gestion des séries
### Méthodes
- `getSeries(seriesId: string): Promise<Series>`
- Récupère les détails d'une série
- `getSeriesBooks(seriesId: string, page: number = 0, size: number = 24, unreadOnly: boolean = false): Promise<LibraryResponse<KomgaBook>>`
- Récupère les livres d'une série
- Supporte la pagination et le filtrage
@@ -69,19 +63,15 @@ Service de gestion des livres
### Méthodes
- `getBook(bookId: string): Promise<{ book: KomgaBook; pages: number[] }>`
- Récupère les détails d'un livre et ses pages
- `updateReadProgress(bookId: string, page: number, completed: boolean = false): Promise<void>`
- Met à jour la progression de lecture
- `getPage(bookId: string, pageNumber: number): Promise<Response>`
- Récupère une page spécifique d'un livre
- `getCover(bookId: string): Promise<Response>`
- Récupère la couverture d'un livre
- `getPageThumbnail(bookId: string, pageNumber: number): Promise<Response>`
@@ -94,16 +84,13 @@ Service de gestion des images
### Méthodes
- `getImage(path: string): Promise<ImageResponse>`
- Récupère une image depuis le serveur
- Gère le cache des images
- `getSeriesThumbnailUrl(seriesId: string): string`
- Génère l'URL de la miniature d'une série
- `getBookThumbnailUrl(bookId: string): string`
- Génère l'URL de la miniature d'un livre
- `getBookPageUrl(bookId: string, pageNumber: number): string`
@@ -116,15 +103,12 @@ Service de gestion de la configuration
### Méthodes
- `getConfig(): Promise<Config>`
- Récupère la configuration Komga
- `saveConfig(config: Config): Promise<Config>`
- Sauvegarde la configuration Komga
- `getTTLConfig(): Promise<TTLConfig>`
- Récupère la configuration TTL
- `saveTTLConfig(config: TTLConfig): Promise<TTLConfig>`
@@ -137,7 +121,6 @@ Service de gestion du cache serveur
### Méthodes
- `getCacheMode(): string`
- Récupère le mode de cache actuel
- `clearCache(): void`
@@ -159,7 +142,6 @@ Service de gestion des préférences
### Méthodes
- `getPreferences(): Promise<Preferences>`
- Récupère les préférences utilisateur
- `savePreferences(preferences: Preferences): Promise<void>`
@@ -182,15 +164,12 @@ Service de base pour les appels API
### Méthodes
- `buildUrl(config: Config, path: string, params?: Record<string, string>): string`
- Construit une URL d'API
- `getAuthHeaders(config: Config): Headers`
- Génère les en-têtes d'authentification
- `fetchFromApi<T>(url: string, headers: Headers, raw?: boolean): Promise<T>`
- Effectue un appel API avec gestion d'erreurs
- `fetchWithCache<T>(key: string, fetcher: () => Promise<T>, type: CacheType): Promise<T>`