# LintellO Coach — L'IA qui Apprend de Toi

> Système d'apprentissage continu et d'adaptation personnalisée, inspiré par les mémoires de Claude.

---

## 1. Vision

**LintellO Coach** transforme LintellO d'une IA réactive en **assistant personnel qui apprend vraiment de toi**.

### Différences clés vs UserContext actuel

| Aspect | **UserContext** (existant) | **Coach** (nouveau) |
|--------|---------------------------|---------------------|
| **Nature** | Statique, rempli manuellement | Dynamique, apprentissage automatique |
| **Mise à jour** | Rare, par l'utilisateur | Continue, par observation |
| **Portée** | Profil général | Patterns comportementaux détectés |
| **Proactivité** | Passive | Suggestions automatiques |
| **Évolution** | Figée | Score de confiance qui augmente |

### Inspiration Claude.ai

Claude a un système de "mémoires" qui retient :
- Les préférences de style de réponse
- Les compétences/domaines de l'utilisateur
- Les objectifs en cours
- Les blocages récurrents

**LintellO Coach reprend ce concept mais l'adapte au contexte LintellO** avec :
- Détection automatique des patterns
- Dashboard de visualisation
- Suggestions proactives contextuelles
- Privacy-first (opt-in, désactivable)

---

## 2. Architecture Technique

### 2.1 Nouvelles Tables BDD

#### Table `user_learning`

Stocke les patterns détectés automatiquement.

```sql
CREATE TABLE user_learning (
    id CHAR(36) NOT NULL PRIMARY KEY,
    user_id CHAR(36) NOT NULL,
    learning_type ENUM('preference', 'skill', 'goal', 'blocker', 'pattern', 'tool') NOT NULL,
    learning_key VARCHAR(100) NOT NULL COMMENT 'Ex: prefers_detailed_explanations, skill_react, blocker_sql_joins',
    learning_value JSON NOT NULL COMMENT 'Données structurées selon le type',
    confidence_score SMALLINT NOT NULL DEFAULT 0 COMMENT '0-100, augmente avec usage',
    evidence_count INT NOT NULL DEFAULT 1 COMMENT 'Nombre d\'occurrences détectées',
    last_reinforced_at DATETIME NOT NULL,
    created_at DATETIME NOT NULL,
    FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE,
    UNIQUE KEY unique_learning (user_id, learning_type, learning_key),
    INDEX idx_confidence (user_id, confidence_score),
    INDEX idx_type (user_id, learning_type)
);
```

**Champs clés :**

| Champ | Description |
|-------|-------------|
| `learning_type` | Catégorie de l'apprentissage |
| `learning_key` | Identifiant unique du pattern (ex: `prefers_examples`) |
| `learning_value` | JSON avec détails spécifiques |
| `confidence_score` | 0-100, augmente à chaque renforcement |
| `evidence_count` | Nombre de fois où le pattern a été détecté |
| `last_reinforced_at` | Dernière occurrence du pattern |

**Types de learning :**

- **preference** : Style de réponse préféré
- **skill** : Compétence maîtrisée ou en apprentissage
- **goal** : Objectif en cours
- **blocker** : Point de blocage récurrent
- **pattern** : Comportement d'usage (ex: utilise souvent le mode Code)
- **tool** : Outil/techno fréquemment utilisé

#### Table `coach_suggestion`

Stocke les suggestions proactives générées.

```sql
CREATE TABLE coach_suggestion (
    id CHAR(36) NOT NULL PRIMARY KEY,
    user_id CHAR(36) NOT NULL,
    suggestion_type ENUM('tip', 'resource', 'workflow', 'reminder', 'mode_custom') NOT NULL,
    title VARCHAR(255) NOT NULL COMMENT 'Titre court de la suggestion',
    content TEXT NOT NULL COMMENT 'Contenu détaillé',
    trigger_condition JSON NOT NULL COMMENT 'Condition qui a déclenché la suggestion',
    shown_count SMALLINT NOT NULL DEFAULT 0 COMMENT 'Nombre de fois affichée',
    accepted BOOLEAN DEFAULT NULL COMMENT 'NULL = pas encore réagi, TRUE = acceptée, FALSE = refusée',
    accepted_at DATETIME DEFAULT NULL,
    dismissed_at DATETIME DEFAULT NULL,
    created_at DATETIME NOT NULL,
    FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE,
    INDEX idx_pending (user_id, accepted),
    INDEX idx_type (user_id, suggestion_type)
);
```

**Types de suggestions :**

- **tip** : Conseil d'utilisation ("Tu utilises souvent X, sais-tu que...")
- **resource** : Ressource recommandée ("Vu ton intérêt pour Y, cette doc...")
- **workflow** : Optimisation de workflow ("Tu pourrais automatiser...")
- **reminder** : Rappel contextuel ("Projet Z pas ouvert depuis 3 jours")
- **mode_custom** : Proposition de mode personnalisé ("Créer un mode React Expert ?")

#### Table `coach_interaction`

Log des interactions pour affiner la détection.

```sql
CREATE TABLE coach_interaction (
    id CHAR(36) NOT NULL PRIMARY KEY,
    user_id CHAR(36) NOT NULL,
    message_id CHAR(36) DEFAULT NULL COMMENT 'Message concerné si applicable',
    interaction_type VARCHAR(50) NOT NULL COMMENT 'asks_examples, corrects_sql, uses_mode_code, etc.',
    interaction_data JSON DEFAULT NULL COMMENT 'Métadonnées spécifiques',
    created_at DATETIME NOT NULL,
    FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE,
    FOREIGN KEY (message_id) REFERENCES message(id) ON DELETE SET NULL,
    INDEX idx_user_type (user_id, interaction_type),
    INDEX idx_created (created_at)
);
```

### 2.2 Structure learning_value par Type

#### Type `preference`

```json
{
  "key": "prefers_detailed_explanations",
  "label": "Préfère les explications détaillées",
  "detected_from": [
    "Demande souvent 'explique en détail'",
    "Messages longs appréciés (pouces positifs)",
    "Suit-ups fréquents pour développer"
  ],
  "impact": "Les réponses seront plus développées par défaut"
}
```

**Clés possibles :**
- `prefers_detailed_explanations`
- `prefers_concise_answers`
- `needs_examples`
- `prefers_visual_explanations` (tableaux, listes)
- `prefers_step_by_step`

#### Type `skill`

```json
{
  "key": "skill_react",
  "label": "Développement React",
  "level": "intermediate",
  "detected_from": [
    "Conversations fréquentes sur React",
    "Questions sur hooks, state management",
    "Projets React identifiés"
  ],
  "last_topics": ["useContext", "React Query", "performance optimization"],
  "learning_path": ["advanced hooks", "testing", "SSR"]
}
```

**Niveaux :**
- `beginner` : Découvre
- `intermediate` : Pratique
- `advanced` : Maîtrise
- `expert` : Expert

#### Type `goal`

```json
{
  "key": "goal_learn_fastapi",
  "label": "Apprendre FastAPI",
  "status": "active",
  "detected_from": [
    "Conversation 'Comment apprendre FastAPI'",
    "Projet 'API Python' créé",
    "Recherches fréquentes sur FastAPI"
  ],
  "progress": 30,
  "milestones": [
    {"title": "Installation + Hello World", "done": true},
    {"title": "Routing + Path params", "done": true},
    {"title": "Database + SQLAlchemy", "done": false}
  ],
  "next_steps": ["Tutoriel SQLAlchemy", "Implémenter CRUD"]
}
```

#### Type `blocker`

```json
{
  "key": "blocker_sql_joins",
  "label": "Difficulté avec les JOINs SQL",
  "severity": "medium",
  "detected_from": [
    "Questions répétées sur LEFT JOIN",
    "Erreurs SQL dans les conversations",
    "Demande d'explications multiples"
  ],
  "occurrences": 4,
  "suggested_resources": [
    {"type": "tutorial", "title": "SQL JOINs visuellement", "url": "..."},
    {"type": "practice", "title": "Exercices interactifs SQL"}
  ]
}
```

#### Type `pattern`

```json
{
  "key": "pattern_uses_mode_code_morning",
  "label": "Utilise le mode Code le matin",
  "frequency": "daily",
  "time_pattern": {
    "hours": [8, 9, 10, 11],
    "days": ["monday", "tuesday", "wednesday", "thursday", "friday"]
  },
  "detected_from": [
    "Mode Code activé 90% du temps entre 8h-12h",
    "Conversations techniques le matin"
  ]
}
```

#### Type `tool`

```json
{
  "key": "tool_react",
  "label": "React",
  "usage_frequency": "very_high",
  "related_tools": ["TypeScript", "Vite", "Zustand"],
  "detected_from": [
    "Projets React multiples",
    "Questions techniques React",
    "Code React généré/analysé"
  ]
}
```

---

## 3. Services Backend

### 3.1 CoachLearningService

Service principal qui détecte et enregistre les patterns.

```php
class CoachLearningService
{
    public function __construct(
        private UserLearningRepository $learningRepository,
        private CoachInteractionRepository $interactionRepository,
        private EntityManagerInterface $em
    ) {}

    /**
     * Détecte et enregistre un pattern depuis un message
     */
    public function detectFromMessage(Message $message, User $user): void
    {
        // Détection des préférences
        if ($this->detectsNeedsExamples($message)) {
            $this->reinforcePattern($user, 'preference', 'needs_examples', [
                'label' => 'Demande souvent des exemples',
            ]);
        }

        if ($this->detectsLongResponse($message) && $this->hasPositiveFeedback($message)) {
            $this->reinforcePattern($user, 'preference', 'prefers_detailed_explanations');
        }

        // Détection des compétences
        $tools = $this->extractTools($message);
        foreach ($tools as $tool) {
            $this->reinforcePattern($user, 'tool', "tool_{$tool}", [
                'label' => $tool,
                'usage_frequency' => 'high',
            ]);
        }

        // Détection des blocages
        if ($this->detectsRepeatedQuestion($message, $user)) {
            $topic = $this->extractTopic($message);
            $this->reinforcePattern($user, 'blocker', "blocker_{$topic}", [
                'label' => "Difficulté avec {$topic}",
                'severity' => 'medium',
            ]);
        }

        // Log de l'interaction
        $this->logInteraction($user, $message, $this->classifyInteraction($message));
    }

    /**
     * Renforce un pattern existant ou le crée
     */
    private function reinforcePattern(
        User $user,
        string $type,
        string $key,
        array $value = []
    ): void {
        $learning = $this->learningRepository->findOneBy([
            'user' => $user,
            'learningType' => $type,
            'learningKey' => $key,
        ]);

        if ($learning) {
            // Renforcer : augmenter confiance + evidence
            $learning->setConfidenceScore(min(100, $learning->getConfidenceScore() + 5));
            $learning->setEvidenceCount($learning->getEvidenceCount() + 1);
            $learning->setLastReinforcedAt(new \DateTimeImmutable());
        } else {
            // Créer nouveau pattern
            $learning = new UserLearning();
            $learning->setUser($user);
            $learning->setLearningType($type);
            $learning->setLearningKey($key);
            $learning->setLearningValue($value);
            $learning->setConfidenceScore(20); // Score initial
            $learning->setEvidenceCount(1);
            $learning->setLastReinforcedAt(new \DateTimeImmutable());
        }

        $this->em->persist($learning);
        $this->em->flush();
    }

    /**
     * Récupère les patterns actifs (confiance >= 40)
     */
    public function getActivePatterns(User $user, ?string $type = null): array
    {
        $qb = $this->learningRepository->createQueryBuilder('l')
            ->where('l.user = :user')
            ->andWhere('l.confidenceScore >= 40')
            ->setParameter('user', $user)
            ->orderBy('l.confidenceScore', 'DESC');

        if ($type) {
            $qb->andWhere('l.learningType = :type')
               ->setParameter('type', $type);
        }

        return $qb->getQuery()->getResult();
    }

    /**
     * Détecte si le message demande des exemples
     */
    private function detectsNeedsExamples(Message $message): bool
    {
        $patterns = [
            '/donne[- ]moi un exemple/i',
            '/par exemple/i',
            '/peux[- ]tu (me )?montrer/i',
            '/illustre/i',
        ];

        foreach ($patterns as $pattern) {
            if (preg_match($pattern, $message->getContent())) {
                return true;
            }
        }

        return false;
    }

    // ... autres méthodes de détection
}
```

### 3.2 CoachSuggestionService

Génère des suggestions proactives.

```php
class CoachSuggestionService
{
    public function __construct(
        private CoachSuggestionRepository $suggestionRepository,
        private CoachLearningService $learningService,
        private EntityManagerInterface $em
    ) {}

    /**
     * Génère des suggestions contextuelles pour l'utilisateur
     */
    public function generateSuggestions(User $user): void
    {
        $patterns = $this->learningService->getActivePatterns($user);

        // Suggestion : Mode personnalisé si outil très utilisé
        $tools = array_filter($patterns, fn($p) => $p->getLearningType() === 'tool');
        foreach ($tools as $tool) {
            if ($tool->getConfidenceScore() >= 80 && !$this->hasModeCustomForTool($user, $tool)) {
                $this->createSuggestion($user, 'mode_custom', [
                    'title' => "Créer un mode {$tool->getLearningValue()['label']} Expert ?",
                    'content' => "Tu utilises beaucoup {$tool->getLearningValue()['label']}. Je peux créer un mode personnalisé optimisé pour tes besoins !",
                    'trigger_condition' => [
                        'tool' => $tool->getLearningKey(),
                        'confidence' => $tool->getConfidenceScore(),
                    ],
                ]);
            }
        }

        // Suggestion : Ressource si blocage détecté
        $blockers = array_filter($patterns, fn($p) => $p->getLearningType() === 'blocker');
        foreach ($blockers as $blocker) {
            if ($blocker->getConfidenceScore() >= 60) {
                $this->createSuggestion($user, 'resource', [
                    'title' => "Ressource pour {$blocker->getLearningValue()['label']}",
                    'content' => "J'ai remarqué que {$blocker->getLearningValue()['label']} te pose problème. Je peux te suggérer des ressources adaptées ?",
                    'trigger_condition' => [
                        'blocker' => $blocker->getLearningKey(),
                    ],
                ]);
            }
        }

        // Suggestion : Rappel projet inactif
        $this->checkInactiveProjects($user);
    }

    /**
     * Récupère les suggestions en attente pour affichage
     */
    public function getPendingSuggestions(User $user, int $limit = 3): array
    {
        return $this->suggestionRepository->createQueryBuilder('s')
            ->where('s.user = :user')
            ->andWhere('s.accepted IS NULL')
            ->andWhere('s.dismissedAt IS NULL')
            ->setParameter('user', $user)
            ->orderBy('s.createdAt', 'DESC')
            ->setMaxResults($limit)
            ->getQuery()
            ->getResult();
    }

    private function createSuggestion(User $user, string $type, array $data): void
    {
        // Vérifier qu'une suggestion similaire n'existe pas déjà
        $existing = $this->suggestionRepository->findOneBy([
            'user' => $user,
            'suggestionType' => $type,
            'title' => $data['title'],
        ]);

        if ($existing) {
            return; // Ne pas dupliquer
        }

        $suggestion = new CoachSuggestion();
        $suggestion->setUser($user);
        $suggestion->setSuggestionType($type);
        $suggestion->setTitle($data['title']);
        $suggestion->setContent($data['content']);
        $suggestion->setTriggerCondition($data['trigger_condition']);

        $this->em->persist($suggestion);
        $this->em->flush();
    }
}
```

### 3.3 Adaptive Prompting

Le système Coach enrichit le system prompt avec les patterns détectés.

```php
// Dans MistralService.php

private function buildCoachContext(User $user): string
{
    if (!$user->isCoachEnabled()) {
        return '';
    }

    $patterns = $this->coachLearningService->getActivePatterns($user);
    $context = [];

    foreach ($patterns as $pattern) {
        switch ($pattern->getLearningType()) {
            case 'preference':
                if ($pattern->getLearningKey() === 'prefers_detailed_explanations') {
                    $context[] = "L'utilisateur préfère les explications détaillées avec exemples.";
                }
                if ($pattern->getLearningKey() === 'needs_examples') {
                    $context[] = "Toujours fournir des exemples concrets.";
                }
                break;

            case 'skill':
                $skill = $pattern->getLearningValue();
                $context[] = "Compétence : {$skill['label']} (niveau {$skill['level']}).";
                break;

            case 'blocker':
                $blocker = $pattern->getLearningValue();
                $context[] = "Point d'attention : {$blocker['label']}. Expliquer clairement si le sujet est abordé.";
                break;

            case 'tool':
                $tool = $pattern->getLearningValue();
                if ($pattern->getConfidenceScore() >= 70) {
                    $context[] = "L'utilisateur utilise fréquemment {$tool['label']}.";
                }
                break;
        }
    }

    if (empty($context)) {
        return '';
    }

    return "\n\n=== CONTEXTE COACH ===\n" . implode("\n", $context) . "\n===================\n";
}

// Appel dans buildSystemPrompt()
$systemPrompt .= $this->buildCoachContext($user);
```

---

## 4. Frontend React

### 4.1 Composant CoachDashboard

Dashboard dédié pour visualiser les patterns détectés.

```tsx
// frontend/src/components/Coach/CoachDashboard.tsx

interface CoachDashboardProps {
  user: User;
}

export const CoachDashboard: React.FC<CoachDashboardProps> = ({ user }) => {
  const [patterns, setPatterns] = useState<UserLearning[]>([]);
  const [suggestions, setSuggestions] = useState<CoachSuggestion[]>([]);

  useEffect(() => {
    loadCoachData();
  }, []);

  const loadCoachData = async () => {
    const patternsRes = await api.get('/api/coach/patterns');
    const suggestionsRes = await api.get('/api/coach/suggestions');
    setPatterns(patternsRes.data);
    setSuggestions(suggestionsRes.data);
  };

  return (
    <div className="coach-dashboard">
      <h1>🎓 Coach LintellO</h1>
      <p>Ce que j'ai appris de toi</p>

      {/* Suggestions en attente */}
      {suggestions.length > 0 && (
        <section className="suggestions">
          <h2>💡 Suggestions pour toi</h2>
          {suggestions.map(s => (
            <SuggestionCard key={s.id} suggestion={s} onAccept={...} onDismiss={...} />
          ))}
        </section>
      )}

      {/* Tes préférences */}
      <section className="preferences">
        <h2>📝 Tes préférences</h2>
        {patterns.filter(p => p.learningType === 'preference').map(p => (
          <PatternCard key={p.id} pattern={p} />
        ))}
      </section>

      {/* Tes compétences */}
      <section className="skills">
        <h2>🚀 Tes compétences</h2>
        {patterns.filter(p => p.learningType === 'skill').map(p => (
          <SkillCard key={p.id} skill={p} />
        ))}
      </section>

      {/* Tes objectifs */}
      <section className="goals">
        <h2>🎯 Tes objectifs</h2>
        {patterns.filter(p => p.learningType === 'goal').map(p => (
          <GoalCard key={p.id} goal={p} />
        ))}
      </section>

      {/* Points d'attention */}
      <section className="blockers">
        <h2>⚠️ Points d'attention</h2>
        {patterns.filter(p => p.learningType === 'blocker').map(p => (
          <BlockerCard key={p.id} blocker={p} />
        ))}
      </section>

      {/* Paramètres Coach */}
      <section className="settings">
        <button onClick={handleDisableCoach}>Désactiver Coach</button>
        <button onClick={handleClearData}>Effacer les données apprises</button>
      </section>
    </div>
  );
};
```

### 4.2 Opt-in Transparent

Message après 10 conversations pour proposer d'activer Coach.

```tsx
// Dans ChatWindow.tsx

useEffect(() => {
  if (conversationsCount === 10 && !user.coachEnabled && !user.coachAsked) {
    showCoachOptIn();
  }
}, [conversationsCount]);

const showCoachOptIn = () => {
  setShowModal({
    title: "🎓 Activer LintellO Coach ?",
    content: (
      <>
        <p>J'ai remarqué des patterns dans tes questions. Veux-tu que j'active le mode Coach pour m'adapter mieux à toi ?</p>
        <h4>Avec Coach activé :</h4>
        <ul>
          <li>Je retiens tes préférences (style de réponse, exemples...)</li>
          <li>Je m'adapte à tes compétences</li>
          <li>Je te suggère des ressources selon tes blocages</li>
          <li>Je te rappelle tes objectifs</li>
        </ul>
        <h4>Privacy :</h4>
        <ul>
          <li>Désactivable à tout moment</li>
          <li>Données effaçables en 1 clic</li>
          <li>Tout reste chiffré comme le reste de LintellO</li>
        </ul>
      </>
    ),
    actions: [
      { label: "Activer Coach", onClick: () => enableCoach(), primary: true },
      { label: "Non merci", onClick: () => dismissCoach() },
    ],
  });
};
```

---

## 5. API Endpoints

```php
// src/Controller/Api/CoachController.php

#[Route('/api/coach', name: 'api_coach_')]
class CoachController extends AbstractController
{
    #[Route('/enable', name: 'enable', methods: ['POST'])]
    public function enable(): JsonResponse
    {
        $user = $this->getUser();
        $user->setCoachEnabled(true);
        $user->setCoachAsked(true);
        $this->em->flush();

        return $this->json(['message' => 'Coach activé']);
    }

    #[Route('/disable', name: 'disable', methods: ['POST'])]
    public function disable(): JsonResponse
    {
        $user = $this->getUser();
        $user->setCoachEnabled(false);
        $this->em->flush();

        return $this->json(['message' => 'Coach désactivé']);
    }

    #[Route('/patterns', name: 'patterns', methods: ['GET'])]
    public function getPatterns(): JsonResponse
    {
        $user = $this->getUser();
        $patterns = $this->learningService->getActivePatterns($user);

        return $this->json($patterns);
    }

    #[Route('/suggestions', name: 'suggestions', methods: ['GET'])]
    public function getSuggestions(): JsonResponse
    {
        $user = $this->getUser();
        $suggestions = $this->suggestionService->getPendingSuggestions($user);

        return $this->json($suggestions);
    }

    #[Route('/suggestions/{id}/accept', name: 'suggestion_accept', methods: ['POST'])]
    public function acceptSuggestion(CoachSuggestion $suggestion): JsonResponse
    {
        $suggestion->setAccepted(true);
        $suggestion->setAcceptedAt(new \DateTimeImmutable());
        $this->em->flush();

        // Déclencher l'action associée (ex: créer mode custom)
        $this->handleSuggestionAction($suggestion);

        return $this->json(['message' => 'Suggestion acceptée']);
    }

    #[Route('/suggestions/{id}/dismiss', name: 'suggestion_dismiss', methods: ['POST'])]
    public function dismissSuggestion(CoachSuggestion $suggestion): JsonResponse
    {
        $suggestion->setAccepted(false);
        $suggestion->setDismissedAt(new \DateTimeImmutable());
        $this->em->flush();

        return $this->json(['message' => 'Suggestion ignorée']);
    }

    #[Route('/clear', name: 'clear', methods: ['DELETE'])]
    public function clearData(): JsonResponse
    {
        $user = $this->getUser();

        // Supprimer toutes les données apprises
        $this->learningRepository->deleteAllForUser($user);
        $this->suggestionRepository->deleteAllForUser($user);
        $this->interactionRepository->deleteAllForUser($user);

        $this->em->flush();

        return $this->json(['message' => 'Données Coach effacées']);
    }
}
```

---

## 6. Roadmap d'Implémentation

### Sprint 1 (semaines 1-2) : Foundation

| Tâche | Détail |
|-------|--------|
| Tables BDD | user_learning, coach_suggestion, coach_interaction + migrations |
| Entités Doctrine | UserLearning, CoachSuggestion, CoachInteraction |
| CoachLearningService | Détection basique (prefers_examples, needs_detailed) |
| User.coachEnabled | Champ boolean pour opt-in |
| API enable/disable | Endpoints activation Coach |

### Sprint 2 (semaines 3-4) : Détection & Adaptation

| Tâche | Détail |
|-------|--------|
| Détection skills | Extraction outils/technos depuis messages |
| Détection blockers | Questions répétées sur même sujet |
| Adaptive Prompting | buildCoachContext() dans MistralService |
| CoachSuggestionService | Génération suggestions basiques |

### Sprint 3 (semaines 5-6) : Frontend Dashboard

| Tâche | Détail |
|-------|--------|
| CoachDashboard | Vue patterns/suggestions/skills/goals |
| Opt-in modal | Message après 10 conversations |
| PatternCard | Composants pour afficher patterns |
| SuggestionCard | Composants suggestions avec accept/dismiss |

### Sprint 4 (semaines 7-8) : Advanced Features

| Tâche | Détail |
|-------|--------|
| Détection goals | Parser objectifs depuis conversations |
| Goal tracking | Milestones, progression |
| Modes custom auto | Générer mode personnalisé via suggestion |
| Notifications proactives | Badge "Coach a une suggestion pour toi" |

### Sprint 5 (semaines 9-10) : Polish & Analytics

| Tâche | Détail |
|-------|--------|
| EasyAdmin CRUD | Visualiser patterns users en admin |
| Métriques Coach | Taux adoption, suggestions acceptées |
| Export Coach data | Pour l'utilisateur (RGPD) |
| Onboarding Coach | Guide première utilisation |

---

## 7. Exemples Concrets

### Exemple 1 : Détection "needs_examples"

**Conversation :**
```
User: Comment utiliser useContext en React ?
LintellO: [Explication générale]
User: Peux-tu me donner un exemple concret ?
LintellO: [Exemple]

→ Détecté : prefers_examples (confidence +20)
```

**Conversations suivantes :**
```
User: C'est quoi un reducer ?
LintellO: [Explication + EXEMPLE directement, sans attendre la demande]
```

### Exemple 2 : Détection skill React

**Après 5 conversations sur React :**
```
→ Créé : skill_react (confidence 60)
→ Adaptive prompt : "L'utilisateur utilise React"
```

**Impact sur réponses :**
- Privilégie exemples React vs Vue/Angular
- Terminologie React par défaut
- Suggestions hooks modernes

### Exemple 3 : Suggestion mode custom

**Après 10 conversations sur FastAPI :**
```
→ Créé : tool_fastapi (confidence 80)
→ Génère suggestion : "Créer un mode FastAPI Expert ?"

User clique "Accepter"
→ Crée nouveau mode avec :
   - system_prompt optimisé FastAPI
   - keywords : fastapi, pydantic, uvicorn
   - thinking_schema : chain (pour structuration API)
```

### Exemple 4 : Rappel projet inactif

**Projet "API Python" pas ouvert depuis 7 jours :**
```
→ Génère suggestion :
   "Ton projet API Python n'a pas été ouvert depuis 7 jours.
    Veux-tu un rappel de où tu en étais ?"

User clique "Accepter"
→ Ouvre le projet
→ Charge dernière conversation liée au projet
→ Résume : "Tu travaillais sur l'authentification JWT"
```

---

## 8. Privacy & RGPD

### Conformité RGPD

- **Opt-in explicite** : Coach désactivé par défaut
- **Transparence** : Dashboard montre TOUTES les données apprises
- **Effacement** : Bouton "Effacer données Coach" en 1 clic
- **Désactivation** : Désactivable à tout moment
- **Export** : Données Coach incluses dans export RGPD

### Sécurité

- Tables `user_learning`, `coach_suggestion`, `coach_interaction` liées à `user` avec `ON DELETE CASCADE`
- Champ `learning_value` (JSON) **NON chiffré** car pas de données sensibles (juste des patterns comportementaux)
- Les messages réels restent chiffrés dans `message.content`
- Coach analyse les patterns, pas les contenus bruts

---

## 9. Métriques de Succès

| Métrique | Objectif |
|----------|----------|
| Taux d'activation Coach | > 60% des users après 10 conversations |
| Taux d'acceptation suggestions | > 40% |
| Augmentation engagement | +20% sessions après activation Coach |
| Satisfaction Coach | > 4/5 (sondage) |

---

## 10. Différenciation Concurrente

| Feature | ChatGPT | Claude | Notion AI | **LintellO Coach** |
|---------|---------|--------|-----------|-------------------|
| Mémorisation préférences | ❌ | ✅ Limited | ❌ | ✅ Détaillé |
| Détection compétences | ❌ | ✅ Basic | ❌ | ✅ Avec niveau |
| Suggestions proactives | ❌ | ❌ | ❌ | ✅ |
| Dashboard transparent | ❌ | ❌ | ❌ | ✅ |
| Modes custom auto | ❌ | ❌ | ❌ | ✅ |
| Privacy-first | ❌ | ✅ | ❌ | ✅ + Chiffré |

**Argument marketing :** *"Une IA qui apprend VRAIMENT de toi, et te montre ce qu'elle a compris"*

---

## Historique du Document

| Date | Modification |
|------|--------------|
| 2026-02-16 | Création — Specs LintellO Coach inspiré de Claude memories |
