# Story 4.4: Implémenter la gestion des limites de prédictions

Status: review

## Acceptance Criteria

**Given** un utilisateur gratuit consulte une prédiction
**When** il accède à une prédiction
**Then** le système vérifie son quota quotidien (1-2 prédictions/jour)
**And** si le quota n'est pas dépassé, la prédiction est affichée
**And** le compteur de prédictions consultées est incrémenté

**Given** un utilisateur gratuit a atteint sa limite
**When** il tente de consulter une prédiction supplémentaire
**Then** un message indique qu'il a atteint sa limite
**And** une option pour passer à Premium est proposée
**And** la prédiction n'est pas affichée

**Given** un utilisateur premium consulte des prédictions
**When** il accède à des prédictions
**Then** aucune limite n'est appliquée
**And** toutes les prédictions sont accessibles

## Tasks / Subtasks

- [x] Mettre à jour le schéma utilisateur pour le tracking des limites (AC: #1)
  - [x] Ajouter la colonne `daily_predictions_count` à `users`
  - [x] Ajouter la colonne `last_prediction_date` à `users`
  - [x] Générer et appliquer les migrations
  - [x] Mettre à jour les types TypeScript

- [x] Créer le service de vérification des limites (AC: #1)
  - [x] Créer `src/services/limitService.ts`
  - [x] Implémenter `checkFreeUserLimit(userId)`
  - [x] Implémenter `incrementDailyCount(userId)`
  - [x] Implémenter `resetDailyCount()` (cron ou à minuit)
  - [x] Retourner `allowed`, `remaining`, `limit`

- [x] Créer le middleware de limitation (AC: #1, #2)
  - [x] Créer `src/middleware/rateLimit.ts`
  - [x] Vérifier le statut premium
  - [x] Vérifier le quota quotidien pour les utilisateurs gratuits
  - [x] Bloquer l'accès si limite atteinte
  - [x] Retourner 429 si limite atteinte

- [x] Créer un composant de limite atteinte (AC: #2)
  - [x] Créer `src/components/limits/LimitReached.tsx`
  - [x] Afficher le message: "Limite de prédictions atteinte"
  - [x] Afficher le compteur (ex: "1/2 prédictions utilisées")
  - [x] Ajouter bouton "Passer à Premium"
  - [x] Utiliser shadcn/ui components

- [x] Créer le composant de compteur de prédictions (AC: #1)
  - [x] Créer `src/components/limits/PredictionCounter.tsx`
  - [x] Afficher les prédictions restantes
  - [x] Afficher le quota (ex: "1/2")
  - [x] Mettre à jour en temps réel
  - [x] Ne pas afficher pour les utilisateurs premium

- [x] Configurer le reset quotidien des limites (AC: #1)
  - [x] Créer un cron job ou endpoint `/api/limits/reset`
  - [x] Réinitialiser `daily_predictions_count` à 0
  - [x] Mettre à jour `last_prediction_date`
  - [x] Logger les resets
  - [x] Tester le reset à minuit

- [x] Tester la gestion des limites (AC: #1, #2, #3)
  - [x] Tester avec utilisateur gratuit (1-2 prédictions)
  - [x] Tester quand la limite est atteinte
  - [x] Tester avec utilisateur premium (illimité)
  - [x] Vérifier que le reset quotidien fonctionne
  - [x] Vérifier que le compteur est mis à jour

## Dev Notes

### Stack Technique
- **Limites:** 1-2 prédictions/jour (free), illimité (premium)
- **Cron:** Vercel Cron ou node-cron
- **State:** Zustand + React Query

### File Structure
```
src/
├── services/
│   └── limitService.ts
├── middleware/
│   └── rateLimit.ts
├── components/
│   └── limits/
│       ├── LimitReached.tsx
│       └── PredictionCounter.tsx
└── app/
    └── api/
        └── limits/
            └── reset/route.ts
```

### References
- [Source: _bmad-output/planning-artifacts/epics.md#Story-4.4]

## Dev Agent Record

### Agent Model Used
GLM-4.7

### Completion Notes List
- Schéma utilisateur mis à jour avec colonnes daily_predictions_count et last_prediction_date
- Migration générée (0003_cheerful_true_believers.sql) et appliquée à la base de données
- Types TypeScript automatiquement mis à jour par Drizzle ORM
- Service de vérification des limites créé avec checkFreeUserLimit(), incrementDailyCount(), resetDailyCount()
- Middleware de limitation implémenté avec vérification du statut premium et du quota quotidien
- Composant LimitReached créé avec design shadcn/ui, affichage du compteur et bouton "Passer à Premium"
- Composant PredictionCounter créé, affiche les prédictions restantes, ne s'affiche pas pour les utilisateurs premium
- API endpoint /api/limits/reset créé pour réinitialiser les limites quotidiennes
- Tests complets: 50 tests passants pour la gestion des limites (schéma, service, middleware, composants, API, intégration)

### File List
- `src/db/schema.ts` - Schéma utilisateur mis à jour avec daily_predictions_count et last_prediction_date
- `drizzle/migrations/0003_cheerful_true_believers.sql` - Migration générée
- `src/services/limitService.ts` - Service de vérification des limites
- `src/middleware/rateLimit.ts` - Middleware de limitation des prédictions
- `src/components/limits/LimitReached.tsx` - Composant de limite atteinte
- `src/components/limits/PredictionCounter.tsx` - Composant de compteur de prédictions
- `src/app/api/limits/reset/route.ts` - API endpoint pour reset quotidien
- `src/tests/limits-schema.test.ts` - Tests du schéma (8 tests)
- `src/tests/limit-service-real.test.ts` - Tests du service (8 tests)
- `src/tests/rate-limit-middleware.test.ts` - Tests du middleware (6 tests)
- `src/tests/limit-reached.test.tsx` - Tests du composant LimitReached (6 tests)
- `src/tests/prediction-counter.test.tsx` - Tests du composant PredictionCounter (6 tests)
- `src/tests/limits-reset-api.test.ts` - Tests de l'API reset (5 tests)
- `src/tests/limits-integration.test.ts` - Tests d'intégration (11 tests)

## Change Log
- 2026-01-17: Implémentation complète de la gestion des limites de prédictions
  - Ajouté les colonnes daily_predictions_count et last_prediction_date au schéma utilisateur
  - Créé le service limitService.ts avec les fonctions checkFreeUserLimit, incrementDailyCount, resetDailyCount
  - Créé le middleware rateLimit.ts pour vérifier et bloquer les utilisateurs gratuits
  - Créé les composants LimitReached.tsx et PredictionCounter.tsx
  - Créé l'endpoint /api/limits/reset pour le reset quotidien
  - 50 tests d'unité et d'intégration écrits et passants
  - Tous les critères d'acceptation satisfaits
  - Aucune régression détectée
