ultisuite-client/CLAUDE.md
R3D347HR4Y d6d18f911b
Some checks failed
E2E / Playwright e2e (push) Has been cancelled
Lots of stuff and mobile app
2026-06-17 00:13:28 +02:00

11 KiB

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 :

{
  "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.tsxemail-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.

Mobile (Tauri 2 — Android + iOS)

Workspace : mobile/ — voir mobile/README.md (build, Phase 0, scaffolds natifs).

Toolchain Rust : utiliser rustup, pas Homebrew. Sur macOS, Rust peut coexister via brew install rust (/opt/homebrew/bin) et rustup (~/.cargo/bin). Pour Tauri mobile, toujours la toolchain rustup :

  • Vérifier avant tout cargo / pnpm tauri :
    which rustc cargo   # attendu : ~/.cargo/bin/rustc et ~/.cargo/bin/cargo
    rustc --version
    
  • Si which rustc pointe vers /opt/homebrew/bin/rustc, recharger le shell (source "$HOME/.cargo/env") ou placer ~/.cargo/bin avant /opt/homebrew/bin dans le PATH.
  • Cibles mobiles (une fois) :
    rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
    rustup target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios
    

Build frontend mobile (prérequis à chaque app Tauri) : pnpm build:mobile./out.
Compile Rust : cd mobile && cargo check.

Commandes Tauri (layout imbriqué mobile/apps/<id>/src-tauri) :

pnpm tauri:ultimail android init   # pas pnpm tauri --config depuis la racine
pnpm tauri:ultimail android dev

Les agents ne doivent pas supposer que le Rust Homebrew suffit pour les builds Android/iOS.