# Phase 2 - Pagination et Virtual Scrolling pour ObsiViewer
## 🎯 Objectif
Implémenter la pagination curseur-based et le virtual scrolling pour permettre à ObsiViewer de gérer efficacement des vaults contenant **10,000+ fichiers** tout en maintenant des performances optimales.
## 📋 Contexte
### ✅ Ce qui a été accompli en Phase 1
- **Metadata-first loading** : Chargement ultra-rapide des métadonnées uniquement
- **Lazy loading** : Contenu chargé à la demande lors de la sélection d'une note
- **Optimisations serveur** : Cache intelligent et indexation différée
- **Résultat** : 75% d'amélioration du temps de démarrage (15-25s → 2-4s)
### ❌ Limites de la Phase 1
- **Mémoire client** : Toutes les métadonnées (~1000 fichiers) chargées en mémoire
- **Rendu UI** : Liste complète rendue même avec virtual scrolling partiel
- **Scalabilité** : Performances dégradées au-delà de 1000 fichiers
- **UX** : Scroll lag avec de gros volumes de données
### 🎯 Pourquoi la Phase 2 est nécessaire
Pour supporter des vaults avec **10,000+ fichiers**, nous devons implémenter :
1. **Pagination côté serveur** : Charger les données par pages
2. **Virtual scrolling côté client** : Ne rendre que les éléments visibles
3. **Gestion intelligente de la mémoire** : Éviter de charger toutes les métadonnées
## 📊 Spécifications Techniques
### 1. Pagination Côté Serveur (Cursor-Based)
#### Endpoint `/api/vault/metadata/paginated`
```typescript
GET /api/vault/metadata/paginated?limit=100&cursor=500
Response:
{
"items": [
{
"id": "note-1",
"title": "Titre de la note",
"filePath": "folder/note.md",
"createdAt": "2025-01-01T00:00:00Z",
"updatedAt": "2025-01-01T00:00:00Z"
}
// ... 99 autres items
],
"nextCursor": "600",
"hasMore": true,
"total": 12500
}
```
#### Paramètres
- **`limit`** : Nombre d'items par page (défaut: 100, max: 500)
- **`cursor`** : Offset pour la pagination (défaut: 0)
- **`search`** : Terme de recherche optionnel
#### Implémentation Meilisearch
```typescript
const result = await index.search(searchQuery, {
limit: limit + 1, // +1 pour détecter s'il y a plus de résultats
offset: parseInt(cursor) || 0,
attributesToRetrieve: ['id', 'title', 'path', 'createdAt', 'updatedAt']
});
```
### 2. Virtual Scrolling Côté Client
#### Composant NotesListComponent avec CDK Virtual Scrolling
```typescript
import { ScrollingModule } from '@angular/cdk/scrolling';
@Component({
template: `