# Ultimail Client mail unifié multi-comptes avec backend de synchronisation, frontend web (Next.js) et desktop (Tauri). --- ## Vision & positionnement Alternative souveraine à Gmail et Google Suite. L'interface s'inspire fortement de Google pour que les utilisateurs ne soient pas dépaysés et conservent leurs habitudes tout en migrant progressivement leur infrastructure vers cette solution. ### Objectifs clés - **Parité fonctionnelle** — supporter un maximum de fonctionnalités utiles des suites mail existantes (Gmail, Outlook) - **Au-delà de Gmail** — fonctionnalités de pointe absentes ou limitées chez les géants : connectivité contrôlée avec agents IA, bots, webhooks avancés avec templates - **Expérience uniforme cross-plateforme** — même UX sur desktop web, desktop app (Tauri) et mobile, avec les détails d'implémentation qui rendent cette uniformité possible - **Migration progressive** — un utilisateur peut rattacher ses comptes existants et migrer à son rythme --- ## Architecture ``` ┌─────────────────────────────────────────────────────────┐ │ Clients (frontend) │ │ ├─ Web — Next.js 16 / React 19 (ce repo) │ │ └─ Desktop — Tauri (wrapper du même frontend) │ ├─────────────────────────────────────────────────────────┤ │ Backend (futur) │ │ ├─ Client IMAP/POP3 + SMTP (collecte & envoi) │ │ ├─ Moteur de règles (tri, forward, réponses auto) │ │ ├─ Scheduler (envoi programmé, actions différées) │ │ ├─ API REST/WS pour sync clients │ │ └─ API tokens fine-grained (agents IA, webhooks) │ ├─────────────────────────────────────────────────────────┤ │ Database — PostgreSQL │ │ ├─ Mails + métadonnées complètes + méta Ultimail │ │ ├─ Identifiants connexion serveurs mail │ │ ├─ Comptes Ultimail, préférences, libellés, dossiers │ │ ├─ Règles de tri, webhooks, tokens API │ │ └─ Auth comptes Ultimail │ └─────────────────────────────────────────────────────────┘ ``` --- ## Modèle de domaine ### Compte Ultimail vs Compte mail | Concept | Description | |---------|-------------| | **Compte Ultimail** | Compte utilisateur sur la plateforme. Possède préférences, libellés unifiés, règles, auth. | | **Compte mail** | Connexion SMTP/IMAP ou POP3 vers un serveur/fournisseur. Un compte Ultimail en gère plusieurs. | | **Identité d'envoi** | Adresse "From" utilisée pour envoyer. Peut différer du compte mail d'envoi (alias, catch-all). | | **Identité de réception** | Adresse de destination. Peut différer du compte mail de réception (catch-all, routing). | ### Relations clés - 1 compte Ultimail → N comptes mail (envoi et/ou réception) - 1 compte mail → N identités d'envoi / réception (catch-all, alias) - Adresse de réception ≠ nécessairement le compte mail de réception (liées mais distinctes) - Adresse d'envoi ≠ nécessairement le compte mail d'envoi (envoi via un autre serveur) - Libellés et dossiers unifiés cross-comptes au niveau du compte Ultimail --- ## Backend — Responsabilités (futur) ### Synchronisation & collecte - Client IMAP/SMTP permanent (toujours en ligne, même clients offline) - Collecte des mails de tous les comptes mail rattachés - Sync bidirectionnelle avec les clients (web/Tauri) - Configuration unique propagée à tous les clients ### Règles de tri & automatisations - Règles de tri à la réception (conditions → actions) - Envoi programmé (schedule pour le lendemain, etc.) - Réponses automatiques - Forward automatique - Webhooks à la réception selon règles ### Intégrations IA & programmatiques - Tri par LLM (fournisseurs OpenAI-compatibles) avec contexte/prompt personnalisé par règle - Tokens API fine-grained : accès partiel pour agents IA (lire certains mails, envoyer, catégoriser) - Comportements programmatiques personnalisés par l'utilisateur ### Stockage (PostgreSQL) - Mails complets + métadonnées originales + métadonnées Ultimail (libellés, dossiers, statuts) - Identifiants de connexion aux serveurs mail (chiffrés) - Réglages comptes Ultimail, préférences d'organisation - Règles de tri, webhooks, tokens API, auth --- ## Frontend — Responsabilités (actuel) ### Web (Next.js 16 — ce repo) - Interface mail complète (liste, lecture, composition, recherche, contacts) - Navigation URL-driven (`/mail/{folder}`, `/mail/search`, `/contacts`) - État persisté côté client (Zustand + localStorage) — sera remplacé par sync backend - Mock data actuellement (`lib/email-data.ts`, `lib/contacts/mock-data.ts`) ### Desktop (Tauri — futur) - Même frontend wrappé dans Tauri - Accès natif (notifications, raccourcis système, stockage local) --- ## Réglages & règles Tous les réglages sont gérables depuis l'interface settings d'Ultimail : ### Niveaux de configuration - **Global** (compte Ultimail) — libellés unifiés, préférences d'affichage, densité, thème - **Par identité mail** — signature, nom affiché, réponse par défaut, règles spécifiques ### Types de règles - Tri automatique (conditions sur expéditeur, sujet, contenu → libellé, dossier, archive) - Forward automatique - Réponse automatique - Envoi programmé - Webhook (POST vers URL externe à la réception) - Tri IA (prompt + contexte personnalisé, fournisseur LLM configurable) - Actions API (tokens fine-grained pour agents externes) ### Webhooks — système de templates Les webhooks supportent un format de payload personnalisable via templates réutilisables. Principe : l'utilisateur définit un template (ex: "Slack", "Discord", "Custom") qui décrit le JSON à envoyer, avec des variables interpolées depuis le mail déclencheur. ``` Variables disponibles (exemples) : $sender.name, $sender.email $subject $body.textContent, $body.htmlContent $date, $timestamp $recipients.to, $recipients.cc $attachments.count, $attachments.names $labels, $folder $account.email (identité de réception) ``` Exemple — template Slack : ```json { "text": "Nouveau mail de $sender.name", "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "*$subject*\nDe: $sender.email\n$body.textContent" } } ] } ``` Cela permet de brancher n'importe quel service (Slack, Discord, n8n, Make, custom) sans code, juste en adaptant le template JSON et l'URL du webhook. --- ## Stack technique (actuel) | Couche | Choix | |--------|-------| | Framework | Next.js 16 (App Router, standalone) | | UI | React 19, TypeScript 5.7 | | Styles | Tailwind CSS 4, shadcn/ui (Radix, style new-york) | | État | Zustand 5 (persist JSON debounced) | | Éditeur riche | TipTap 3 | | Icônes | @iconify/react, lucide-react | | Recherche client | fuse.js | | Package manager | pnpm | | Deploy | Docker multi-stage → Node 22 Alpine, CapRover | --- ## Conventions ### Navigation - URL = source de vérité (dossier, onglet inbox, page, message ouvert) - `useMailRoute` + `lib/mail-url.ts` pour parsing/building - Recherche via query params sur `/mail/search` ### Stores (Zustand) - Persistés : mail-store, mail-settings-store, nav-store, account-store, scheduled-store - Éphémères : mail-search-store, mail-ui-store - Ne pas persister l'UI éphémère sauf besoin produit explicite ### Composants (`components/gmail/`) - Organisation par feature : `compose/`, `email-list/`, `email-view/`, `sidebar/`, `mail-search/`, `contacts/` - Re-exports publics à la racine (`email-list.tsx` → `email-list/`) - Hooks dédiés par domaine dans chaque feature ### Docs internes - `components/gmail/README.md` — arborescence composants - `lib/stores/README.md` — architecture stores ### Environnement local & agents Stack dev typique : **nginx (:80)** → `ultid` (Docker) + frontend Next.js (`pnpm dev`, proxy `/api/v1` via `ULTI_PROXY_ORIGIN`). **Les agents doivent redémarrer les services eux-mêmes** quand un changement l'exige — ne pas demander au développeur de le faire. | Changement | Action (depuis `ulti-backend/`) | |----------|----------------------------------| | Code Go (`internal/`, `cmd/`, migrations embarquées) | `./deploy/compose-up.sh up -d --build ultid` | | Variable `.env` lue au démarrage d'`ultid` | `./deploy/compose-up.sh up -d --build ultid` (régénère `.env.resolved`) | | Module Compose optionnel (OpenWebUI, Nextcloud, …) | `./deploy/compose-up.sh up -d` (overlay activé selon `.env`) | | Redémarrage simple sans rebuild | `./deploy/compose-up.sh restart ultid` | | Frontend Next.js (ce repo) | `pnpm dev` se recharge seul ; rebuild seulement si config Next/env change | Après restart backend, vérifier : `curl -s http://127.0.0.1:80/api/v1/ai/config` (JSON, pas 502). Repo backend : `../ulti-backend` — voir aussi `ulti-backend/CLAUDE.md`.