Appearance
Heriade Contacts — User stories & MVP
Document de référence pour le développement de la v1. Compagnon du
README.md(architecture) et de la maquette HTML (UX).
Statut : v1 cadrée, prête à entrer en sprint. Auteur de la v1 : 1 développeur, ~12 jours dev focus. Utilisateur cible v1 : François D., administrateur de l'enterprise Heriade.
1. Personas
🎯 Persona principal — François (v1)
Rôle : commercial / business developer chez Heriade Quotidien : prospecte sur LinkedIn, échange par Gmail, lance des campagnes Lemlist Frustration : le contexte de chaque conversation est éparpillé sur trois plateformes, impossible de répondre à "où en suis-je avec Sophie ?" sans 5 minutes de recherche Niveau technique : utilisateur avancé d'outils SaaS, attend rapidité et fiabilité Comportement clé : copie-colle ses derniers messages dans un outil tiers pour s'en souvenir
🔮 Personas secondaires (v2+, à anticiper mais pas implémenter)
- Marie — membre de l'équipe Heriade, doit voir ses propres contacts sans déranger ceux de François
- Admin d'un client Heriade — gère ses propres contacts dans son tenant isolé
- Super-admin Heriade — supervise tous les tenants depuis la console admin
2. MVP — ce qui doit absolument fonctionner
2.1 Le test du MVP
Si François utilise l'app pendant une semaine comme remplacement de son carnet de prospection éclaté, et qu'il ne revient pas à l'ancien fonctionnement, le MVP est validé.
2.2 Capacités minimales
Un MVP qui passe ce test doit permettre à François de :
- Se connecter via son compte Heriade existant — pas d'inscription séparée
- Créer un contact avec une entreprise rattachée, en moins de 30 secondes
- Coller un message LinkedIn/Gmail/Lemlist dans la fiche en moins de 10 secondes, taggé par canal
- Retrouver un contact par recherche texte sur n'importe quel champ
- Poser un rappel sur un contact, et le voir apparaître quand il arrive à échéance
- Filtrer sa liste pour répondre à "qui dois-je relancer cette semaine ?"
- Installer l'app sur son ordi/téléphone pour y accéder sans ouvrir un navigateur
2.3 Ce qui N'EST PAS dans le MVP
- Connecteurs réels (LinkedIn, Gmail, Lemlist) → tout est manuel
- Partage avec d'autres utilisateurs
- Notifications email automatiques
- Enrichissement via Pappers
- Intégration avec Bloc Note ou autres apps Heriade
- Import CSV
- Vue calendrier
- Application mobile native
Voir le README.md §9 pour le détail des évolutions prévues.
2.4 Métriques de succès du MVP
| Métrique | Cible v1 | Comment la mesurer |
|---|---|---|
| Adoption | François utilise l'app au moins 4 jours/semaine | Logs de connexion |
| Volume | ≥ 30 contacts saisis dans le premier mois | Compte BDD |
| Vélocité de saisie | ≤ 15 secondes pour ajouter un échange | Mesure UX en interview |
| Bugs bloquants | 0 bug critique en 30 jours | Suivi tickets |
| Performance | Time-to-interactive < 2s au login | Lighthouse |
3. Découpage en Epics
Les user stories sont organisées en 7 épics. Chaque epic correspond à un groupe fonctionnel cohérent et livrable.
| Epic | Nom | Stories | Priorité MVP |
|---|---|---|---|
| E1 | Authentification & accès | 4 | 🔴 Critique |
| E2 | Gestion des contacts | 6 | 🔴 Critique |
| E3 | Gestion des entreprises | 4 | 🔴 Critique |
| E4 | Échanges & historique | 5 | 🔴 Critique |
| E5 | Rappels & tâches | 4 | 🟠 Important |
| E6 | Recherche & filtres | 5 | 🟠 Important |
| E7 | PWA & polish | 4 | 🟡 Confort |
32 user stories au total, dont 22 critiques MVP (E1 à E4 + 3 de E5/E6).
4. User stories
🔐 Epic E1 — Authentification & accès
US-1.1 — Connexion via SSO Heriade
🔴 Critique MVP
En tant que François Je veux me connecter à Heriade Contacts en utilisant mon compte Heriade existant Afin de ne pas gérer un mot de passe supplémentaire
Critères d'acceptation
- Au premier accès à
contacts.heriade.fr, je suis redirigé vers le portail SSO Heriade (/auth-app/portalde la console admin) - Après authentification réussie, je suis renvoyé sur l'app avec un token JWT Supabase valide
- Le token est stocké en cookie httpOnly (pas accessible au JS)
- Si le token est invalide ou expiré, je suis redirigé automatiquement vers le login
- Le bouton "Se déconnecter" dans le menu utilisateur révoque ma session et me ramène au login
Notes techniques
- Bloquant : contrat exact du flow
/auth-app/portalà clarifier avec l'équipe console admin - Fallback de dev : token mocké via
NUXT_DEV_FAKE_TOKENpour ne pas bloquer le sprint
US-1.2 — Identification de l'enterprise active
🔴 Critique MVP
En tant que François Je veux que l'app sache automatiquement à quelle enterprise j'appartiens Afin de ne voir que les contacts de mon organisation
Critères d'acceptation
- Au login, le back appelle
GET /auth/mesur la console admin et récupèreprofile.enterprise_id - Si je n'ai pas d'enterprise rattachée, j'obtiens un message clair "Aucune organisation rattachée à votre compte. Contactez votre administrateur."
- Si mon enterprise est de type
personal, l'accès est refusé avec message "Heriade Contacts est réservé aux comptes professionnels." - Le nom de mon enterprise s'affiche dans la sidebar (sous mon nom)
US-1.3 — Rôle et permissions appliqués
🔴 Critique MVP
En tant que François (administrateur Heriade) Je veux voir mes propres contacts par défaut, et tous ceux de mon enterprise si je suis admin Afin de garder une visibilité utile sans polluer mon espace
Critères d'acceptation
- Le rôle est récupéré depuis
permissions.isAdmin/permissions.isSuperAdmin - Un user
membervoit uniquement les contacts dont il estownerUserId - Un user
administrateurvoit tous les contacts de sonenterpriseId - Un user
super-adminpeut traverser plusieurs enterprises (mais l'UI v1 ne propose pas de switcher — accès via console admin) - Aucune fuite de données entre enterprises : test multi-enterprise validé
US-1.4 — Session persistante et sécurisée
🟠 Important
En tant que François Je veux rester connecté entre deux visites sans avoir à me relogger Afin de ne pas perdre de temps quotidiennement
Critères d'acceptation
- La session dure tant que le token Supabase est valide (durée standard Supabase, ~1h par défaut avec refresh)
- Le refresh token est utilisé en transparence pour prolonger la session
- Une révocation côté console admin prend effet en moins de 60 secondes (TTL du cache de permissions)
- Si la session expire pendant que je travaille, je suis prévenu via toast et redirigé vers le login
👥 Epic E2 — Gestion des contacts
US-2.1 — Créer un contact rapidement
🔴 Critique MVP
En tant que François Je veux créer un nouveau contact en moins de 30 secondes Afin de capturer une rencontre ou une mise en relation sans friction
Critères d'acceptation
- Un bouton "Nouveau contact" est accessible depuis n'importe quelle page
- Le formulaire ne requiert que
firstName+lastName(le reste est optionnel) - Je peux remplir : nom, prénom, email, LinkedIn, téléphone, rôle, entreprise rattachée, tags, notes
- Si je tape un nom d'entreprise inexistant, je peux la créer à la volée depuis le même formulaire
- À la validation, je suis redirigé vers la fiche du contact créé
- Toutes les validations échouées affichent un message clair sous le champ concerné
US-2.2 — Voir une fiche contact complète
🔴 Critique MVP
En tant que François Je veux ouvrir la fiche d'un contact et voir d'un coup d'œil tout son contexte Afin de reprendre la conversation sans chercher
Critères d'acceptation
- La fiche affiche : en-tête (avatar, nom, fonction, entreprise, statut, tags), métadonnées (email, LinkedIn, téléphone, date de premier contact), timeline d'échanges, rappels liés, mini-fiche entreprise
- La fiche se charge en moins de 500ms
- Les liens email/LinkedIn sont cliquables
- Un lien "Voir l'entreprise" mène à la fiche entreprise miroir
US-2.3 — Modifier un contact
🔴 Critique MVP
En tant que François Je veux corriger ou enrichir les informations d'un contact existant Afin de garder mes données à jour
Critères d'acceptation
- Un bouton "Modifier" ouvre le formulaire pré-rempli
- Je peux modifier tous les champs y compris l'entreprise rattachée
- À la sauvegarde, la fiche se rafraîchit sans recharger la page
- Un toast confirme "Contact mis à jour"
- L'historique des échanges et les rappels ne sont pas affectés
US-2.4 — Supprimer un contact
🟠 Important
En tant que François Je veux supprimer un contact qui n'a plus d'intérêt Afin de garder ma base propre
Critères d'acceptation
- Un bouton "Supprimer" dans le menu kebab de la fiche
- Une confirmation obligatoire avant suppression ("Supprimer définitivement ?")
- À la suppression : les échanges liés sont supprimés en cascade, les rappels deviennent autonomes (
contactId = null) — à confirmer - Je suis redirigé vers la liste des contacts
- Toast "Contact supprimé"
US-2.5 — Voir la liste de mes contacts
🔴 Critique MVP
En tant que François Je veux voir tous mes contacts dans un tableau scannable Afin de avoir une vue d'ensemble de ma prospection
Critères d'acceptation
- Tableau avec colonnes : Contact (avatar + nom + fonction), Entreprise, Dernier échange (canal + date), Statut, Tags, Rappels
- Tri par n'importe quelle colonne en cliquant sur l'en-tête
- Tri par défaut : dernier échange descendant (les plus récents en premier)
- Pagination ou virtualisation à partir de 50 contacts
- Cliquer sur une ligne ouvre la fiche du contact
- Le compteur "X contacts" s'affiche en haut du tableau
US-2.6 — Gérer les tags d'un contact
🟠 Important
En tant que François Je veux taguer mes contacts (RH, Tech, VIP, Q2 2026…) Afin de les classer selon mes propres critères
Critères d'acceptation
- Un champ "Tags" dans le formulaire de création/édition, format multi-select avec création à la volée
- Les tags existants sont suggérés en autocomplete au fur et à mesure de la saisie
- Les tags s'affichent comme pastilles sur la fiche et dans la liste
- Pas de limite de nombre de tags par contact
- Les tags sont scopés à l'enterprise (Marie ne voit pas les tags de François s'ils ne sont pas admin du même tenant)
🏢 Epic E3 — Gestion des entreprises
US-3.1 — Créer une entreprise
🔴 Critique MVP
En tant que François Je veux ajouter une entreprise à laquelle rattacher mes contacts Afin de structurer ma vision par compte
Critères d'acceptation
- Bouton "Nouvelle entreprise" depuis la page Entreprises ou depuis le formulaire de création de contact
- Seul
nameest requis ;domain,industry,size,notesoptionnels - Pas d'enrichissement Pappers en v1 — saisie 100% manuelle
- À la création, redirection vers la fiche entreprise
US-3.2 — Voir une fiche entreprise
🔴 Critique MVP
En tant que François Je veux voir une entreprise et tous ses contacts d'un coup Afin de comprendre mon niveau de pénétration d'un compte
Critères d'acceptation
- En-tête entreprise avec logo (initiale), nom, secteur, taille
- Liste des contacts rattachés (mini-table)
- Métadonnées agrégées : nombre total d'échanges, dernière activité, statut global
- Bouton "Nouveau contact dans cette entreprise" pré-remplit le champ
companyId
US-3.3 — Lister les entreprises
🔴 Critique MVP
En tant que François Je veux voir toutes mes entreprises dans un tableau Afin de retrouver une entreprise rapidement
Critères d'acceptation
- Tableau avec : Entreprise (logo + nom + domaine), Secteur, Taille, Nb contacts, Nb échanges, Dernière activité
- Recherche texte sur nom et domaine
- Filtres : secteur, taille
- Cliquer sur une ligne ouvre la fiche entreprise
US-3.4 — Modifier / supprimer une entreprise
🟠 Important
En tant que François Je veux mettre à jour ou supprimer une entreprise Afin de garder une base cohérente
Critères d'acceptation
- Modification via formulaire identique à la création
- Suppression bloquée si l'entreprise a encore des contacts rattachés ("Détachez d'abord les X contacts")
- Confirmation obligatoire avant suppression
💬 Epic E4 — Échanges & historique
US-4.1 — Coller un message dans la fiche contact
🔴 Critique MVP
En tant que François Je veux coller le dernier message LinkedIn/Gmail/Lemlist reçu ou envoyé dans la fiche d'un contact Afin de garder une trace centralisée du contexte de chaque échange
Critères d'acceptation
- Une zone "Coller un message" est visible en permanence en haut de la timeline (pas planquée dans une modale)
- La zone réagit à Cmd+V même si elle n'a pas le focus (focus auto si la fiche est ouverte)
- Dès que du contenu est collé, des contrôles apparaissent : sélecteur de canal (LinkedIn/Gmail/Lemlist/Autre), direction (sortant/entrant), bouton Enregistrer
- Le canal LinkedIn est sélectionné par défaut (canal le plus fréquent pour François)
- La direction "sortant" est sélectionnée par défaut
- La date de l'échange est automatiquement remplie à
now(), modifiable par l'utilisateur - Le bouton Enregistrer est désactivé si le contenu est vide
US-4.2 — Voir la timeline d'un contact
🔴 Critique MVP
En tant que François Je veux voir tous les échanges avec un contact dans l'ordre chronologique Afin de comprendre où on en est sans rouvrir LinkedIn / Gmail / Lemlist
Critères d'acceptation
- Timeline verticale, échanges les plus récents en haut
- Chaque entrée affiche : direction (qui → qui), canal (pastille colorée), date relative ("il y a 3 jours"), contenu intégral
- Pastilles de canal avec codes couleur : LinkedIn (bleu), Gmail (magenta), Lemlist (ambre)
- Possibilité de filtrer la timeline par canal (onglets en haut)
- Les échanges sortants et entrants ont des marqueurs visuels distincts (point violet vs point vert)
US-4.3 — Modifier un échange
🟡 Confort
En tant que François Je veux corriger une faute de frappe ou changer le canal d'un échange existant Afin de garder un historique propre
Critères d'acceptation
- Clic sur un échange ouvre une modale d'édition
- Champs modifiables : contenu, canal, direction, date
- Pas de soft delete : la modification écrase l'ancienne version (pas d'historique de version en v1)
US-4.4 — Supprimer un échange
🟡 Confort
En tant que François Je veux supprimer un échange ajouté par erreur Afin de ne pas polluer la timeline
Critères d'acceptation
- Menu kebab sur chaque entrée → "Supprimer"
- Confirmation obligatoire
- Suppression définitive (pas de poubelle)
US-4.5 — Vue agrégée des échanges au niveau entreprise
🟠 Important
En tant que François Je veux voir tous les échanges avec une entreprise (tous ses contacts confondus) Afin de mesurer mon niveau d'activité sur un compte
Critères d'acceptation
- Sur la fiche entreprise, un onglet "Échanges" affiche la timeline consolidée
- Chaque entrée indique le contact concerné (lien cliquable)
- Filtrage par canal et par contact
- Pas de saisie d'échange à ce niveau : on doit passer par la fiche contact
🔔 Epic E5 — Rappels & tâches
US-5.1 — Créer un rappel sur un contact
🔴 Critique MVP
En tant que François Je veux poser un rappel sur un contact ("Relancer Sophie pour démo T3") Afin de ne pas oublier mes prochaines actions
Critères d'acceptation
- Bouton "Rappel" sur la fiche contact ouvre une modale
- Champs : titre (requis), date d'échéance (requise), description (optionnelle)
- À la création, le rappel apparaît dans le bloc Rappels de la fiche et dans la vue Rappels globale
- Toast "Rappel créé pour le [date]"
US-5.2 — Créer un rappel sur une entreprise ou autonome
🟠 Important
En tant que François Je veux poser un rappel lié à une entreprise sans contact précis, ou un rappel totalement autonome ("Préparer le pitch RH") Afin de gérer toutes mes tâches dans un seul outil
Critères d'acceptation
- Depuis la fiche entreprise : bouton "Rappel" attache le rappel à
companyId - Depuis la page Rappels globale : bouton "Nouveau rappel" permet de choisir contact OU entreprise OU rien
- Un rappel autonome (
contactId = nulletcompanyId = null) est valide
US-5.3 — Vue globale des rappels
🔴 Critique MVP
En tant que François Je veux voir tous mes rappels groupés par échéance Afin de prioriser ma journée
Critères d'acceptation
- Page "Rappels" accessible depuis la sidebar
- Trois groupes : "En retard" (rouge), "Aujourd'hui" (neutre), "À venir" (neutre)
- Chaque rappel affiche : titre, date relative, contact ou entreprise liée (lien cliquable)
- Compteurs par groupe
- Si je n'ai aucun rappel : état vide avec "Tout est sous contrôle 🎉"
US-5.4 — Marquer un rappel comme fait
🔴 Critique MVP
En tant que François Je veux cocher un rappel comme terminé Afin de le faire disparaître de mes alertes
Critères d'acceptation
- Une checkbox sur chaque rappel
- En cochant : le rappel passe en barré,
doneAt = now() - Les rappels faits ne s'affichent pas par défaut dans la vue globale (toggle "Afficher les rappels terminés")
- Décocher annule (
doneAt = null)
🔍 Epic E6 — Recherche & filtres
US-6.1 — Recherche texte dans la liste contacts
🔴 Critique MVP
En tant que François Je veux taper le nom d'un contact, son email ou son entreprise et voir la liste se filtrer en direct Afin de retrouver quelqu'un en moins de 5 secondes
Critères d'acceptation
- Champ de recherche en haut de la liste, focus automatique au chargement
- Recherche fuzzy sur : prénom, nom, email, entreprise, tags
- Résultats filtrés en temps réel (pas de bouton "Rechercher" à cliquer)
- Compteur "X contacts trouvés" mis à jour
- État vide si aucun résultat avec bouton "Effacer la recherche"
US-6.2 — Filtres inline sur la liste contacts
🔴 Critique MVP
En tant que François Je veux filtrer ma liste par statut, tags, canal, entreprise Afin de zoomer sur un sous-ensemble
Critères d'acceptation
- Filtres en barre horizontale au-dessus du tableau
- Chaque filtre est un dropdown multi-select
- Les filtres se cumulent (logique ET entre filtres, OU dans un filtre)
- Chip actif affiché au-dessus du tableau pour chaque filtre posé, avec croix pour retirer
- Bouton "Tout effacer" si au moins un filtre est actif
US-6.3 — Panneau "Plus de filtres"
🟠 Important
En tant que François Je veux accéder à des filtres avancés (période, présence de rappel, direction…) sans les avoir tout le temps à l'écran Afin de garder l'interface respirable au quotidien
Critères d'acceptation
- Bouton "Plus de filtres" (icône réglages) à droite de la barre de filtres
- Clic ouvre un panneau latéral droit (380px)
- Filtres disponibles : Période d'activité, Rappels (en retard / à venir / aucun), Propriétaire, Avec/sans email, Direction du dernier échange
- Boutons "Réinitialiser" et "Appliquer" en bas du panneau
- Esc ou clic sur le backdrop ferme le panneau sans appliquer
US-6.4 — Vues sauvegardées
🟠 Important
En tant que François Je veux sauvegarder une combinaison de filtres ("Prospects chauds + LinkedIn + en retard") sous un nom Afin de y revenir en un clic
Critères d'acceptation
- Bouton "Enregistrer cette vue" apparaît dès qu'au moins un filtre est actif
- Modale demande : nom de la vue, icône (optionnelle)
- Les vues sauvegardées apparaissent dans la sidebar sous "Vues sauvegardées"
- Cliquer sur une vue applique tous ses filtres et navigue vers la liste contacts
- Menu kebab par vue : Renommer, Supprimer
- 3 vues pré-configurées par défaut : Prospects chauds, En attente de réponse, À relancer cette semaine
US-6.5 — Recherche globale Cmd+K
🟠 Important
En tant que François Je veux une recherche universelle accessible depuis n'importe où Afin de sauter directement à un contact ou une entreprise sans naviguer
Critères d'acceptation
- Raccourci Cmd+K (Mac) / Ctrl+K (Windows) ouvre une palette de commande au centre de l'écran
- Champ de recherche avec focus auto
- Résultats groupés : Contacts, Entreprises, Actions rapides (Nouveau contact, Nouveau rappel…)
- Navigation au clavier (flèches haut/bas, Entrée pour ouvrir)
- Esc ferme la palette
- Bouton d'icône
⌘dans la barre de filtres pour utilisateurs sans raccourci clavier
📱 Epic E7 — PWA & polish
US-7.1 — Installer l'app comme PWA
🔴 Critique MVP
En tant que François Je veux installer Heriade Contacts sur mon Mac et mon téléphone Afin de y accéder sans passer par mon navigateur
Critères d'acceptation
- Manifest PWA valide avec icônes 192, 512, maskable
- Service worker enregistré, app installable depuis Chrome desktop / Safari iOS / Chrome Android
- Icône d'install dans la barre d'URL Chrome
- Au premier lancement après install, prompt "Bienvenue dans Heriade Contacts"
- Mode standalone (sans barre de navigation du navigateur)
US-7.2 — Lecture offline des fiches visitées
🟡 Confort
En tant que François Je veux consulter une fiche contact que j'ai déjà ouverte même sans internet Afin de ne pas être bloqué dans le train ou en clientèle
Critères d'acceptation
- Service worker met en cache les fiches contact et entreprise visitées
- En mode offline : les fiches en cache restent accessibles
- Un indicateur visuel "Mode hors-ligne — lecture seule" s'affiche dans la barre du haut
- Les actions de modification sont désactivées en offline (boutons grisés avec tooltip)
- Au retour online, l'indicateur disparaît automatiquement
US-7.3 — États vides et loading
🟠 Important
En tant que François Je veux comprendre ce qui se passe quand l'app charge ou quand je n'ai rien à voir Afin de ne pas penser que l'app est cassée
Critères d'acceptation
- Skeleton loaders sur la liste contacts pendant le chargement initial
- État vide à la première utilisation : "Bienvenue ! Créez votre premier contact" avec CTA
- État vide sur recherche/filtre sans résultat : "Aucun contact ne correspond" + bouton "Effacer les filtres"
- État vide sur fiche contact sans échange : "Aucun échange pour l'instant. Collez votre premier message ci-dessus"
- État vide sur Rappels : "Tout est sous contrôle 🎉"
US-7.4 — Toasts et feedbacks d'action
🟠 Important
En tant que François Je veux un retour visuel quand je crée, modifie ou supprime quelque chose Afin de savoir que mon action a été prise en compte
Critères d'acceptation
- Toast en bas de l'écran pour : création, modification, suppression, erreur
- Toast vert pour succès, rouge pour erreur, gris neutre pour info
- Disparition automatique après 2.5s
- Possibilité de cliquer sur le toast pour le fermer immédiatement
- Action "Annuler" sur le toast pour les suppressions (5s pour annuler)
5. Tickets techniques transverses
Ces tickets ne correspondent pas directement à des user stories utilisateur mais sont indispensables au projet. Ils sont à intercaler dans le sprint.
🛠 Setup & fondations
| Ticket | Description | Estimé | Jalon |
|---|---|---|---|
| T-0.1 | Init monorepo Yarn workspaces (apps/web, apps/api, packages/shared) | 0.5 j | J1 |
| T-0.2 | Configuration ESLint, Prettier, EditorConfig | 0.25 j | J1 |
| T-0.3 | Setup Docker Compose pour PostgreSQL local | 0.25 j | J1 |
| T-0.4 | Configuration .env.example + lecture par Nest et Nuxt | 0.25 j | J1 |
| T-0.5 | Pipeline CI minimal (lint + typecheck + tests) | 0.5 j | J1 |
🔐 Auth backend
| Ticket | Description | Estimé | Jalon |
|---|---|---|---|
| T-1.1 | ConsoleAdminClient : wrapper HTTP avec GET /auth/me | 0.5 j | J1 |
| T-1.2 | Cache LRU des contextes utilisateur (TTL 60s) | 0.25 j | J1 |
| T-1.3 | AuthGuard Nest qui valide le token et peuple req.ctx | 0.5 j | J1 |
| T-1.4 | EnterpriseContextMiddleware + PrismaService scopé enterpriseId | 0.5 j | J1 |
| T-1.5 | RolesGuard + décorateurs @RequireAdmin / @RequireSuperAdmin | 0.25 j | J1 |
| T-1.6 | Décorateur @Ctx() pour injecter le contexte dans les controllers | 0.25 j | J1 |
🗄 Modèle de données
| Ticket | Description | Estimé | Jalon |
|---|---|---|---|
| T-2.1 | Schéma Prisma complet (Company, Contact, Exchange, Reminder) | 0.5 j | J1 |
| T-2.2 | Migration initiale + seed minimal (1 contact, 1 entreprise) | 0.25 j | J1 |
| T-2.3 | Schémas Zod partagés dans packages/shared | 0.5 j | J1 |
🎨 Front fondations
| Ticket | Description | Estimé | Jalon |
|---|---|---|---|
| T-3.1 | Setup Nuxt 3 SPA + @vite-pwa/nuxt + Tailwind | 0.5 j | J1 |
| T-3.2 | Tokens Heriade en variables CSS dans tokens.css | 0.25 j | J1 |
| T-3.3 | Composants UI primitifs (Button, Input, Badge, Card, Dropdown) | 1 j | J1-J2 |
| T-3.4 | Layout principal (sidebar + main) | 0.5 j | J1 |
| T-3.5 | Store auth Pinia + interceptor ofetch injectant le Bearer | 0.5 j | J1 |
| T-3.6 | Middleware route auth.global.ts pour redirections SSO | 0.25 j | J1 |
| T-3.7 | Setup TanStack Vue Query avec configuration globale | 0.25 j | J1 |
🔍 Modules backend
| Ticket | Description | Estimé | Jalon |
|---|---|---|---|
| T-4.1 | Module Contacts (controller + service + DTOs + tests unitaires) | 1 j | J2 |
| T-4.2 | Module Companies (idem) | 0.75 j | J2 |
| T-4.3 | Module Exchanges (idem) | 0.5 j | J3 |
| T-4.4 | Module Reminders (idem) | 0.5 j | J3 |
| T-4.5 | Endpoint Health /health pour monitoring | 0.1 j | J1 |
📦 Polish & QA
| Ticket | Description | Estimé | Jalon |
|---|---|---|---|
| T-5.1 | Génération manifest PWA + icônes (192, 512, maskable) | 0.5 j | J4 |
| T-5.2 | Service worker (vite-pwa) avec stratégie cache pour fiches | 0.5 j | J4 |
| T-5.3 | Skeleton loaders + états vides + toasts | 0.5 j | J4 |
| T-5.4 | Suite de tests E2E (Playwright) couvrant le happy path | 1 j | J4 |
| T-5.5 | Documentation utilisateur courte (page "Aide" dans l'app) | 0.5 j | J4 |
6. Roadmap synthétique
┌────── J1 (3.5j) ───────┐ ┌──── J2 (4j) ────┐ ┌─── J3 (3j) ────┐ ┌── J4 (2j) ───┐
│ Fondations │ │ Contacts & │ │ Échanges & │ │ Polish PWA │
│ │ │ Entreprises │ │ Rappels │ │ │
│ • Monorepo + setup │ │ │ │ │ │ • Manifest │
│ • Schéma Prisma │ │ • US-2.1, 2.2, │ │ • US-4.1, 4.2 │ │ • SW offline │
│ • AuthGuard + Console │ │ 2.3, 2.5 │ │ • US-5.1, 5.3, │ │ • Skeletons │
│ • Tenant scoping │ │ • US-3.1, 3.2, │ │ 5.4 │ │ • US-6.5 │
│ • Nuxt PWA setup │ │ 3.3 │ │ • US-6.1, 6.2 │ │ (Cmd+K) │
│ • US-1.1, 1.2, 1.3 │ │ │ │ │ │ • Tests E2E │
└────────────────────────┘ └─────────────────┘ └────────────────┘ └──────────────┘
▲ ▲ ▲ ▲
Auth marche François saisit App utilisable PWA installable
ses contacts au quotidien v1 livrableTotal estimé : 12.5 jours de dev focus
7. Définition de "Done" v1
Une story est "Done" quand toutes ces conditions sont remplies :
Code
- [ ] Le code passe lint + typecheck + tests unitaires
- [ ] Aucune régression sur les tests E2E existants
- [ ] PR reviewée et mergée
- [ ] Les variables sensibles sont en
.env, jamais commitées
Fonctionnel
- [ ] Tous les critères d'acceptation de la story sont validés
- [ ] La story marche en local sur Chrome, Firefox, Safari
- [ ] Aucune fuite de données cross-tenant (testée avec deux comptes)
- [ ] Les états d'erreur sont gérés (401, 403, 500, network down)
UX
- [ ] Conforme au design system Heriade (couleurs, typo, spacing)
- [ ] Responsive desktop + mobile (≥ 375px)
- [ ] Skeleton ou loader sur les chargements > 200ms
- [ ] Toast de feedback sur les actions
Critères techniques globaux v1
- [ ] PWA installable sur Chrome, Safari iOS, Chrome Android
- [ ] Time-to-interactive < 2s en login (cold start)
- [ ] Score Lighthouse ≥ 90 sur Performance et Accessibilité
- [ ] Aucune erreur console en navigation normale
8. Hors scope explicite v1 — pour mémoire
Ces points reviennent souvent dans les discussions, autant les figer :
- ❌ Pas de chat ou messagerie temps réel — l'app n'envoie pas de messages
- ❌ Pas de notifications push — natives ni email
- ❌ Pas d'export PDF d'une fiche — copy-paste suffit en v1
- ❌ Pas de duplication ou import en masse de contacts — saisie manuelle
- ❌ Pas d'API publique — accès uniquement via le front pour les utilisateurs
- ❌ Pas de mode invité ou de partage public d'une fiche — tout est authentifié
- ❌ Pas d'audit log — qui a modifié quoi quand, pas en v1
Pour le détail des évolutions prévues post-v1, voir README.md §9.
9. Risques et points d'attention
| Risque | Probabilité | Impact | Mitigation |
|---|---|---|---|
Spec /auth-app/portal floue | Élevée | Bloquant J1 | Stub d'auth en dev, branche réelle quand spec dispo |
| Surcharge cognitive avec trop de filtres | Moyenne | Adoption | Test utilisateur avec François à J3 |
| Saisie manuelle des échanges trop lourde | Moyenne | Adoption | Mesurer le temps de saisie en interview semaine 1 |
| Performance dégradée avec 500+ contacts | Faible | Scaling | Virtualisation de la table + indices BDD |
| François n'utilise pas l'app | Moyenne | Échec MVP | Implication tôt en design, démos régulières |
Document v1 · mai 2026 · à mettre à jour à chaque sprint review
