# mailbox_ai — Webmail + Assistant IA pour Perfex CRM (cible v3.4.1)

> Conçu par MyISI. Webmail multi-comptes IMAP/SMTP **dans l'admin Perfex**, avec une couche IA
> **optionnelle et à la demande**. S'aligne sur les conventions des modules maison `myisi_api`
> et `sm_sharepoint_sync` (mêmes hooks, install idempotent, settings, sécurité).

**This file is the LOCKED CONTRACT.** Tout fichier généré DOIT s'y conformer : signatures,
schéma BDD, contrats partagés (Crypto / Imap_sync / AIService), routes, et règles de sécurité.
Quand une méthode du cœur Perfex est incertaine (app_menu, register_staff_capabilities,
tasks_model, tickets_model, leads_model…), la LIRE dans le source réel avant de l'appeler :
sur le serveur applicatif, sous `<racine_perfex>/application/` — ne PAS inventer.

---

## 0. Identité & principe directeur
- Module system name : **`mailbox_ai`**. Dossier : `modules/mailbox_ai/`.
- Header : `Module Name: Mailbox AI` · `Version: 1.0.0` · `Requires at least: 3.4.*` · `Author: MyISI`. AUCUN code Envato/license/phone-home.
- **Le webmail DOIT fonctionner sans IA.** La couche IA est isolée derrière `AIProviderInterface` ; son indisponibilité (clé absente, quota, provider down) ne casse JAMAIS le webmail. Aucun appel IA automatique : tout est déclenché par un clic explicite (sauf flag « AI automation » off par défaut).
- PHP **8.2 compatible**. UI = Bootstrap natif Perfex + jQuery + DataTables. i18n FR+EN (zéro texte en dur, tout via `_l()`).
- Provider IA par défaut pour cette installation : **Ollama Cloud** (modèle cloud Gemma). OpenRouter = 2e implémentation.
- N'est PAS un serveur mail (consomme IMAP/SMTP existants) ni un remplacement de l'emailing transactionnel Perfex.

## 1. Conventions Perfex 3.4.1 (VÉRIFIÉES sur myisi_api / sm_sharepoint_sync)
- `defined('BASEPATH') or exit('No direct script access allowed');` en tête de CHAQUE fichier.
- `define('MAILBOX_AI_MODULE', 'mailbox_ai');` + `require_once __DIR__.'/helpers/mailbox_ai_helper.php';` au bootstrap (PAS `$CI->load->helper()` à ce stade).
- Cycle de vie : `register_activation_hook(MAILBOX_AI_MODULE, fn)` → `require_once __DIR__.'/install.php'` ; `register_uninstall_hook(...)` → `uninstall.php`. Désactivation = non destructif.
- Langues : `register_language_files(MAILBOX_AI_MODULE, [MAILBOX_AI_MODULE]);`.
- install.php **idempotent** : `if(!$CI->db->table_exists($prefix.'<t>')){ $CI->db->query('CREATE TABLE ...'); }`, InnoDB, `utf8mb4` / `utf8mb4_unicode_ci`, `db_prefix()` (=`tbl`). Options via `if(!option_exists('<o>')){ add_option('<o>',$default,$autoload); }`.
- Menu/permissions/cron enregistrés via `hooks()->add_action('admin_init', fn)` et `hooks()->add_action('app_cron', fn)`.
- Routing module : `config/routes.php` → `$route['mailbox_ai/(:any)...'] = 'controller/method'` (MX préfixe le nom du module).
- Contrôleurs admin : `extends AdminController`, gate `is_admin()` ou capability ; URLs via `admin_url('mailbox_ai/...')`.
- Capabilities : `register_staff_capabilities('mailbox_ai', $caps, _l('mailbox_ai'))` ; contrôle via `staff_can($cap,'mailbox_ai')`. **(Vérifier la signature exacte app_menu/add_sidebar_menu_item dans le cœur avant build.)**
- CSRF natif Perfex sur toute action mutante ; jamais de `xss_clean` global d'un body JSON.

## 2. Schéma BDD (install.php — 11 tables, toutes préfixées db_prefix())
Reprend §3 de la spec (types exacts). Points durs imposés :
- `tblmailbox_ai_accounts` : `imap_password_enc TEXT`, `smtp_password_enc TEXT` (chiffrés AES-256-GCM, jamais en clair) ; `folder_mapping JSON` ; `sync_mode ENUM('cron','light','manual')` ; `visibility ENUM('all','owner','roles')` ; `owner_staffid INT`.
- `tblmailbox_ai_emails` : **`UNIQUE(account_id, message_id)`** (idempotence sync) + **KEY `(account_id, folder, received_at)`** ; `body_html LONGTEXT` (purifié au stockage), `body_text LONGTEXT`.
- `tblmailbox_ai_attachments`, `_categories`, `_templates`, `_drafts`, `_scheduled`, `_autoreplies`, **`_autoreply_log`** (anti-boucle : frequency/cooldown/max_per_day), `_ai_preferences` (`UNIQUE(account_id)`), `_ai_log` (audit + coûts IA).
- Réglages globaux (provider/modèle/clé chiffrée/flags) via `add_option()` : `mailbox_ai_ai_enabled`(0), `mailbox_ai_ai_provider`, `mailbox_ai_ai_model`, `mailbox_ai_ai_api_key_enc`(autoload 0), `mailbox_ai_encryption_ready`, `mailbox_ai_default_language`(fr), `mailbox_ai_default_tone`, `mailbox_ai_default_length`, `mailbox_ai_sync_default_mode`(manual). PAS de table de settings.

## 3. Contrats partagés (TOUS les fichiers utilisent exactement ceux-là)

### 3.1 Crypto (libraries/Crypto.php) — [SEC]
- `mailbox_ai_encrypt(string $plain): string` / `mailbox_ai_decrypt(string $cipher): string` (façade helper).
- AES-256-GCM via `openssl_encrypt`, **IV aléatoire 12o par enregistrement**, tag d'auth ; format stocké : `base64(iv|tag|cipher)`. Clé dérivée d'un secret d'app dédié (option `mailbox_ai_secret` 64 hex créé à l'activation) + `ENCRYPTION_KEY` Perfex (HKDF). Déchiffrement uniquement en mémoire au moment de la connexion IMAP/SMTP.

### 3.2 Imap_sync (libraries/Imap_sync.php) — [SYNC]
- Basé sur `webklex/php-imap` (Composer, vendor/ committé). `sync(int $account_id, array $opts=[]): array{fetched,new,errors}`.
- Idempotence : **upsert sur (account_id, message_id)**. Light = en-têtes+snippet (corps lazy à l'ouverture). Cron/manual = complet. Purifie `body_html` (HTMLPurifier) AVANT insert. Anti-SSRF sur l'hôte AVANT connexion (cf §5). Creds déchiffrés en mémoire, effacés après.

### 3.3 Smtp_sender (libraries/Smtp_sender.php) — [SYNC]
- PHPMailer (bundlé Perfex). `send(array $msg): array{ok,error}`. Applique la signature du compte. « Delete » = local uniquement (jamais IMAP) — documenté.

### 3.4 Couche IA (libraries/ai/) — [AI] (strictement isolée, zéro dépendance Perfex/IMAP)
- `interface AIProviderInterface { complete(array $messages, array $opts): AIResult; completeJson(array $messages, array $schema, array $opts): array; name(): string; isConfigured(): bool; }`.
- `abstract AbstractAIProvider` mutualise le HTTP (Guzzle déjà présent), API **compatible OpenAI** `/v1/chat/completions`.
- `OllamaCloudProvider` (base `https://ollama.com`, natif `/api/chat` avec `format`=schéma JSON pour la classification ; modèle défaut cloud Gemma ; thinking OFF pour résumé/reformulation) ET `OpenRouterProvider` (base `https://openrouter.ai/api/v1`, en-têtes `HTTP-Referer`/`X-Title`).
- `AIService` (façade métier) : `summarizeUnread`, `suggestReplies`, `improveMessage`, `summarizeEmail`, `classifyEmail` (JSON structuré → catégorie existante ou `none`). Prompts versionnés dans `libraries/ai/prompts/`. Préférences (tone/language/length/reply_notes) injectées par compte. **Clé jamais exposée au front** ; tout appel IA via le controller serveur `Ai.php`. Garde-fous : rate-limit/staff, plafond tokens, audit `tblmailbox_ai_ai_log`, dégradation gracieuse (quota Ollama atteint → message clair, jamais de 500).

## 4. Layout fichiers (et l'agent build PROPRIÉTAIRE de chaque fichier)
```
mailbox_ai/
  mailbox_ai.php                         [CORE] init: header, consts, hooks, menu sidebar, capabilities, activation/uninstall
  install.php / uninstall.php            [CORE] schéma idempotent (11 tables) / drop guardé
  composer.json                          [CORE] webklex/php-imap, ezyang/htmlpurifier (vendor/ committé)
  config/routes.php                      [CORE] mailbox_ai/* -> controllers
  helpers/mailbox_ai_helper.php          [CORE] utilitaires + façade crypto + bridge Perfex
  libraries/Crypto.php                   [SEC]  AES-256-GCM creds
  libraries/Imap_sync.php                [SYNC] sync IMAP idempotente + purify
  libraries/Smtp_sender.php              [SYNC] envoi PHPMailer
  libraries/Html_sanitizer.php           [SEC]  wrapper HTMLPurifier (cache hors vendor/)
  libraries/Perfex_bridge.php            [BRIDGE] adaptateur leads/tickets/tasks_model (isole la surface de rupture)
  libraries/ai/AIProviderInterface.php   [AI]
  libraries/ai/AbstractAIProvider.php    [AI]
  libraries/ai/OllamaCloudProvider.php   [AI]
  libraries/ai/OpenRouterProvider.php    [AI]
  libraries/ai/AIService.php             [AI]
  libraries/ai/prompts/*.php             [AI]   prompts système versionnés
  models/*_model.php                     [DATA] Accounts, Emails, Templates, Autoreplies, Categories, Drafts, Scheduled, Ai_preferences
  controllers/Mailbox.php                [UI]   inbox, liste, actions, vue thread
  controllers/Accounts.php               [UI]   CRUD comptes + test connexion
  controllers/Compose.php                [UI]   compose/reply/forward/send/draft/schedule
  controllers/Templates.php Autoreplies.php Categories.php Drafts.php Scheduled.php Settings.php  [UI]
  controllers/Ai.php                     [AI]   endpoints AJAX IA (serveur uniquement)
  controllers/Cron.php (ou hook app_cron) [SYNC] sync cron + envoi programmé
  views/*                                [UI]   inbox, modales (email/compose/reply), settings, accounts, ...
  assets/css/mailbox_ai.css assets/js/mailbox_ai.js  [UI]
  language/english|french/mailbox_ai_lang.php        [LANG]
```

## 5. Sécurité (NON négociable — §7 de la spec)
1. **Creds IMAP/SMTP chiffrés** AES-256-GCM (cf 3.1). 2. **XSS stocké** : HTMLPurifier au stockage ET au rendu + rendu du corps dans une **iframe sandboxée** + CSP stricte. 3. **Clés IA** jamais au front, jamais loggées, appels via serveur. 4. **Anti-SSRF** : allowlist/validation d'hôte, blocage IP privées/loopback/link-local avant toute connexion IMAP/SMTP. 5. **Cross-compte** : filtrage `visibility`/`owner_staffid` côté serveur sur CHAQUE requête. 6. **Capabilities** Perfex (view/create/edit/delete). 7. **CSRF** natif sur tout mutant. 8. **Anti-boucle auto-reply** : `tblmailbox_ai_autoreply_log` + cooldown/max_per_day/once_per_sender, jamais répondre à no-reply/mailer-daemon/auto-replies. 9. **PJ** hors webroot (ou controller à accès contrôlé), `Content-Disposition: attachment`, MIME vérifié, jamais exécutées. 10. **Injection** : Query Builder paramétré partout. 11. **Abus IA** : rate-limit/staff + plafond tokens + audit.

## 6. Phases (livrables testables; ne pas passer à N+1 sans les critères d'acceptation §10 de la spec)
0 Scaffold (activable, menu, capabilities, 11 tables) · 1 Comptes+Crypto+anti-SSRF+test connexion · 2 Sync+Inbox (idempotente) · 3 Actions + rendu sécurisé (HTMLPurifier+iframe, testé payload XSS) · 4 Compose/Reply (SMTP, autocomplete staff/contacts/leads, templates, signatures, drafts, scheduled+cron) · 5 Catégories+filtres+bulk · 6 Conversion CRM (Task/Ticket/Lead via Perfex_bridge + rattachement email source) · 7 Couche IA (2 providers, settings, 5 fonctions, rate-limit, audit ; bascule sans changer l'UI ; webmail intact si IA down) · 8 Auto-replies (+ log anti-boucle) · 9 Durcissement + i18n complète.

## 7. Tests E2E (critères de recette — exécutés sur le STAGING)
- Sync rejouée 3× → 0 doublon (UNIQUE respecté).
- Email HTML avec `<script>/onerror/javascript:` → **aucune exécution** au rendu (iframe sandbox).
- Mot de passe compte en base → illisible (chiffré).
- Staff A ne charge pas un email/compte de staff B via ID forgé → 403.
- Bascule provider IA Ollama↔OpenRouter dans settings → mêmes 5 fonctions, UI inchangée.
- Clé IA absente → boutons IA désactivés, webmail 100% OK. Quota Ollama atteint → message clair, pas de 500.
- `classifyEmail` → toujours une catégorie existante ou `none` (JSON valide).
- Auto-reply once_per_sender : 2 mails même expéditeur → 1 seule réponse.
- Hôte IMAP `127.0.0.1`/IP privée → refus (anti-SSRF).
- i18n : aucun texte en dur (tout via `_l()`).

## 8. Déploiement (sans régression — méthode maison deploy2_crm.ps1)
zip du module → **lint `php -n -l` de CHAQUE .php (abort si erreur)** → robocopy /MIR **dans le seul dossier `modules/mailbox_ai/`** (ou `admin/modules/upload`). Activation via Setup → Modules. Rollback = restaurer le dossier précédent. Aucune écriture hors `modules/mailbox_ai/`.
