## Context `src/services/weather.ts` utilise `findMany` sans `take` ni `orderBy`, chargeant potentiellement des centaines d'entrées pour calculer des tendances qui n'utilisent que les 30-90 derniers points. Les services de sessions utilisent `include: { items: true, shares: true, events: true }` pour construire les listes, alors que l'affichage carte n'a besoin que du titre, de la date, du comptage d'items et du statut de partage. `User.name` est filtré dans les recherches admin mais sans index SQLite. Les pages les plus visitées (`/sessions`, `/users`) recalculent leurs données à chaque requête. ## Goals / Non-Goals **Goals:** - Borner le chargement historique weather à une constante configurable - Réduire la taille des objets retournés par les queries de liste (select vs include) - Ajouter un index SQLite sur `User.name` - Introduire un cache Next.js sur les queries de liste avec invalidation ciblée **Non-Goals:** - Changer la structure des modèles Prisma - Modifier le rendu des pages (les sélections couvrent tous les champs affichés) - Introduire un cache externe (Redis, Memcached) - Optimiser les pages de détail session (hors scope) ## Decisions ### 1. Constante WEATHER_HISTORY_LIMIT dans lib/types.ts **Décision** : Définir `WEATHER_HISTORY_LIMIT = 90` dans `src/lib/types.ts` (cohérent avec les autres constantes de config). La query devient : `findMany({ orderBy: { createdAt: 'desc' }, take: WEATHER_HISTORY_LIMIT })`. **Alternatives** : Paramètre d'URL ou env var → sur-ingénierie pour un seuil rarement modifié. ### 2. Select minimal pour les listes — interface ListItem dédiée **Décision** : Pour chaque service de liste, définir un type `XxxListItem` dans `types.ts` avec uniquement les champs de la carte (id, title, createdAt, _count.items, shares.length). Utiliser `select` Prisma pour matcher exactement ce type. **Alternatives** : Garder `include` et filtrer côté TypeScript → charge DB identique, gain nul. ### 3. Index @@index([name]) sur User **Décision** : Ajouter `@@index([name])` dans le modèle `User` de `schema.prisma`. Créer une migration nommée `add_user_name_index`. Impact : SQLite crée un B-tree index, recherches `LIKE 'x%'` bénéficient de l'index (prefix match). **Note** : `LIKE '%x%'` (contains) n'utilise pas l'index en SQLite — acceptable, le use case principal est la recherche par préfixe. ### 4. unstable_cache avec tags sur requêtes de liste **Décision** : Wrapper les fonctions de service de liste (ex: `getSessionsForUser`, `getUserStats`) avec `unstable_cache(fn, [cacheKey], { tags: ['sessions-list:userId'] })`. Les Server Actions appellent `revalidateTag` correspondant après mutation. Durée de cache : `revalidate: 60` secondes en fallback, mais invalidation explicite prioritaire. **Alternatives** : `React.cache` → par-requête uniquement, pas de persistance entre navigations ; `fetch` avec cache → ne s'applique pas aux queries Prisma. ## Risks / Trade-offs - **select strict** → si un composant accède à un champ non sélectionné, erreur TypeScript au build (bonne chose — détecté tôt). - **unstable_cache** → API Next.js marquée unstable. Mitigation : isoler dans les services, wrapper facilement remplaçable. - **Index User.name** → légère augmentation de la taille du fichier SQLite et du temps d'écriture. Négligeable pour les volumes actuels. - **WEATHER_HISTORY_LIMIT** → les calculs de tendance doivent fonctionner avec N entrées ou moins. Vérifier que l'algorithme est robuste avec un historique partiel. ## Migration Plan 1. Migration Prisma `add_user_name_index` (non-destructif, peut être appliqué à tout moment) 2. Ajout `WEATHER_HISTORY_LIMIT` + update query weather (indépendant) 3. Refactoring select par service (vérifier TypeScript au build à chaque service) 4. Ajout cache layer en dernier (dépend des tags définis en Phase 2 si applicable, sinon définir localement)