# API de Résolution d'École - Documentation

## Vue d'ensemble

L'API de résolution d'école permet à l'application mobile Corossol de récupérer les informations de base d'une école spécifique et sa configuration d'application, tout en maintenant un niveau de sécurité élevé.

## Endpoints

### 1. Résolution d'École

**GET** `/api/schools/resolve?identifier={CODE_ECOLE}`

Récupère les informations de base d'une école spécifique.

#### Paramètres
- `identifier` (string, obligatoire) : Code de l'école au format E00000

#### Réponses

**200 - Succès**
```json
{
  "data": {
    "identifier": "E00015",
    "name": "Complexe Scolaire Edgar Laurent",
    "apiBaseUrl": "https://back-stemireille.perlenedg.com",
    "logoUrl": "https://cdn.corossol.app/logos/E00015.png",
    "whatsapp": "+22991000000"
  }
}
```

**400 - Identifiant invalide**
```json
{
  "error": "INVALID_FORMAT",
  "message": "Le code école doit être au format E00000 (E suivi de 5 chiffres)"
}
```

**404 - École non trouvée**
```json
{
  "error": "SCHOOL_NOT_FOUND",
  "message": "École non trouvée avec ce code"
}
```

**429 - Rate limit dépassé**
```json
{
  "error": "RATE_LIMIT_EXCEEDED",
  "message": "Trop de requêtes. Veuillez réessayer dans 1 minute.",
  "retryAfter": 60
}
```

### 2. Configuration de l'Application

**GET** `/api/app/config?schoolIdentifier={CODE_ECOLE}`

Récupère la configuration de l'application avec les overrides spécifiques à l'école.

#### Paramètres
- `schoolIdentifier` (string, obligatoire) : Code de l'école au format E00000

#### Headers
- `Accept-Language` (optionnel) : Langue préférée (fr, en)
- `If-None-Match` (optionnel) : ETag pour la validation de cache

#### Réponses

**200 - Succès**
```json
{
  "data": {
    "sliders": [...],
    "support": { ... },
    "profile": { ... },
    "payment": { ... },
    "i18nOverrides": { ... },
    "school": {
      "identifier": "E00015",
      "name": "Complexe Scolaire Edgar Laurent",
      "logoUrl": "https://cdn.corossol.app/logos/E00015.png",
      "whatsapp": "+22991000000"
    }
  },
  "metadata": {
    "schoolIdentifier": "E00015",
    "lastUpdated": "2024-12-01T10:00:00Z",
    "ttlSeconds": 21600,
    "version": "a1b2c3d4"
  }
}
```

**304 - Non modifié**
- Aucun contenu, utilisez l'ETag pour la validation de cache

**400 - Identifiant invalide**
```json
{
  "error": "INVALID_SCHOOL_IDENTIFIER",
  "message": "Le code école est requis et doit être une chaîne de caractères"
}
```

**404 - École non trouvée**
```json
{
  "error": "SCHOOL_NOT_FOUND",
  "message": "École non trouvée avec ce code"
}
```

## Sécurité

### Validation des Entrées
- Format strict du code école : `E` suivi de 5 chiffres
- Validation des types et longueurs
- Rejet des caractères spéciaux dangereux

### Rate Limiting
- `/api/schools/resolve` : 10 requêtes par minute par IP
- `/api/app/config` : 20 requêtes par minute par IP
- Utilisation de Redis pour le stockage des compteurs

### Protection des Données
- Aucune information sensible exposée
- Sanitisation HTML pour prévenir les attaques XSS
- Validation des URLs et schémas autorisés

### Logs et Audit
- Log de toutes les tentatives de résolution
- Log des violations de rate limiting
- Traçabilité des accès par IP

## Utilisation

### Flux Typique

1. **Sélection d'École** : L'utilisateur saisit un code école
2. **Validation** : L'app valide le format E00000
3. **Résolution** : Appel à `/api/schools/resolve` pour vérifier l'existence
4. **Configuration** : Appel à `/api/app/config` pour récupérer la config
5. **Cache** : Stockage local avec ETag pour les mises à jour

### Gestion des Erreurs

```javascript
try {
  const schoolResponse = await fetch(`/api/schools/resolve?identifier=${schoolCode}`);
  
  if (schoolResponse.status === 429) {
    // Rate limit dépassé, attendre et réessayer
    const retryAfter = schoolResponse.headers.get('Retry-After');
    await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
    return retrySchoolResolution(schoolCode);
  }
  
  if (schoolResponse.status === 404) {
    // École non trouvée, afficher message d'erreur
    showError('Code école invalide');
    return;
  }
  
  const schoolData = await schoolResponse.json();
  // Continuer avec la configuration...
  
} catch (error) {
  console.error('Erreur de résolution d\'école:', error);
}
```

### Cache et ETag

```javascript
const getAppConfig = async (schoolIdentifier, etag = null) => {
  const headers = {};
  if (etag) {
    headers['If-None-Match'] = etag;
  }
  
  const response = await fetch(`/api/app/config?schoolIdentifier=${schoolIdentifier}`, {
    headers
  });
  
  if (response.status === 304) {
    // Configuration non modifiée, utiliser le cache local
    return getCachedConfig(schoolIdentifier);
  }
  
  const config = await response.json();
  const newEtag = response.headers.get('ETag');
  
  // Mettre en cache avec le nouvel ETag
  cacheConfig(schoolIdentifier, config, newEtag);
  
  return config;
};
```

## Tests

Exécuter les tests de sécurité :

```bash
npm test test/schools-resolve.test.js
```

## Monitoring

### Métriques à Surveiller
- Nombre de résolutions d'écoles par heure
- Taux d'erreur 404 (écoles non trouvées)
- Violations de rate limiting
- Temps de réponse moyen

### Alertes
- Taux d'erreur > 5%
- Temps de réponse > 2 secondes
- Nombre de tentatives de rate limiting > 100/heure

## Maintenance

### Mise à Jour des Configurations
- Modifier `config/app-content.js`
- Redémarrer l'application ou utiliser le hot reload
- Vérifier la validité des URLs et contenus HTML

### Ajout d'une Nouvelle École
1. Ajouter l'école dans `config/app-content.js`
2. Vérifier le format du code (E00000)
3. Tester la résolution
4. Mettre à jour la documentation si nécessaire
