Corrige deux régressions de /local-workspace :
- le chemin du header restait bloqué sur « Home / <workspace> » quel que
soit le dossier affiché : la route rend désormais breadcrumb_items
(Home / <workspace> / <dossier> / <sous-dossier>, niveaux cliquables,
collapse « … » au-delà de 4) et la navigation sans rechargement recalcule
le chemin via l'event flowdeck:breadcrumb-changed ;
- le clic sur un dossier du sidebar affichait TOUS les composants à la
fois : Alpine.data('wsInitData') retournait le même objet singleton, le
2e montage (navigation partielle) levait « Cannot redefine property:
\ » et initTree abandonnait, laissant tout le contenu au state
brut. La factory retourne désormais une enveloppe fraîche par montage
qui délègue à l'état réactif partagé. #lw-config est aussi relu à chaque
exécution (le 2e montage gardait le folder_id du 1er chargement).
Inclus également le travail en cours de l'arbre : Library (colonnes Last
visited/Source, ordre d'en-tête, favoris à icônes Workspace), Meeting
Notes (bloc, CSS, routes, docs), coloration de code hljs, badges
favori/publié dans l'arbre local-workspace, docs (DATA_MODEL,
architectures) et tests associés.
1806 lines
144 KiB
Markdown
1806 lines
144 KiB
Markdown
# Architecture — Fonctionnalité « Meetings » (modèle Notion) pour Flowdeck
|
||
|
||
| Champ | Valeur |
|
||
|---|---|
|
||
| Version | 1.2 |
|
||
| Date | 8 octobre 2026 — mise à jour du 9 octobre 2026 |
|
||
| Auteur | Spark, pour Bruno |
|
||
| Statut | Proposition d'architecture — à valider avec la stack réelle de Flowdeck |
|
||
| Produit cible | Flowdeck (application web) |
|
||
| Référence fonctionnelle | Meetings dans Notion : onglet *Meetings*, *Notion Calendar* et bloc *AI Meeting Notes* |
|
||
|
||
> **Historique des versions**
|
||
>
|
||
> - **1.0 — 8 octobre 2026** : analyse fonctionnelle d'après la documentation publique de Notion et proposition d'architecture pour Flowdeck.
|
||
> - **1.2 — 9 octobre 2026** : ajout de la section 3B — **maquettes ASCII du panneau** de prise de réunion : les 6 états des captures redessinés en wireframes texte, à disposition exacte (zones, alignements, ordre des contrôles), avec panneau annoté en 8 zones et règles de disposition (§3B.9).
|
||
> - **1.1 — 9 octobre 2026** : ajout du **parcours visuel complet** de la prise de réunion (§3A), établi à partir de 6 captures d'écran d'une session réelle fournies par Bruno, dans l'ordre chronologique. Ajout des composants de traitement que ces captures révèlent et qui manquaient en 1.0 : machine à états du bloc, visualisation de forme d'onde en direct, étapes de traitement exposées à l'utilisateur (*Thinking*), résolution des références aux locuteurs, classification de complétude, titre généré par l'IA, barre de diffusion du résumé et bandeau d'essai / d'entitlement. Les sections 6, 8, 9, 10, 12, 16, 18, 19 et l'annexe A ont été mises à jour en conséquence.
|
||
>
|
||
> **Avertissement méthodologique — à lire avant tout**
|
||
>
|
||
> L'architecture interne de Notion est propriétaire et n'est pas publique. Ce document ne prétend donc pas décrire « comment Notion est construit en interne ».
|
||
>
|
||
> Il contient deux choses distinctes, clairement séparées :
|
||
>
|
||
> 1. **Une analyse fonctionnelle** (section 3) de ce que fait la fonctionnalité Meetings de Notion, établie à partir de sa documentation publique officielle, consultée le 8 octobre 2026. C'est le *comportement observable* du produit.
|
||
> 2. **Une architecture cible originale** (sections 4 à 21) pour implémenter un équivalent dans Flowdeck. Les choix techniques, le modèle de données, les API et les diagrammes sont des propositions de conception, pas une reproduction de l'existant Notion.
|
||
|
||
---
|
||
|
||
## Table des matières
|
||
|
||
1. [Résumé exécutif](#1-résumé-exécutif)
|
||
2. [Périmètre, personas et cas d'usage](#2-périmètre-personas-et-cas-dusage)
|
||
3. [Analyse fonctionnelle : les Meetings dans Notion](#3-analyse-fonctionnelle--les-meetings-dans-notion)
|
||
3A. [Parcours visuel de la prise de réunion — les 6 états du bloc (captures de référence)](#3a-parcours-visuel-de-la-prise-de-réunion--les-6-états-du-bloc-captures-de-référence)
|
||
3B. [Maquettes ASCII du panneau de prise de réunion — disposition exacte des composants](#3b-maquettes-ascii-du-panneau-de-prise-de-réunion--disposition-exacte-des-composants)
|
||
4. [Principes directeurs pour Flowdeck](#4-principes-directeurs-pour-flowdeck)
|
||
5. [Vue d'ensemble du système (C4)](#5-vue-densemble-du-système-c4)
|
||
6. [Architecture front-end web](#6-architecture-front-end-web)
|
||
7. [Architecture back-end](#7-architecture-back-end)
|
||
8. [Flux et séquences clés](#8-flux-et-séquences-clés)
|
||
9. [Modèle de données](#9-modèle-de-données)
|
||
10. [API et événements temps réel](#10-api-et-événements-temps-réel)
|
||
11. [Collaboration temps réel et transcription en direct](#11-collaboration-temps-réel-et-transcription-en-direct)
|
||
12. [Pipeline IA : transcription, diarisation, résumé](#12-pipeline-ia--transcription-diarisation-résumé)
|
||
13. [Intégrations calendrier et visioconférence](#13-intégrations-calendrier-et-visioconférence)
|
||
14. [Sécurité, consentement et conformité](#14-sécurité-consentement-et-conformité)
|
||
15. [Exigences non fonctionnelles](#15-exigences-non-fonctionnelles)
|
||
16. [Résilience et gestion des échecs](#16-résilience-et-gestion-des-échecs)
|
||
17. [Déploiement et exploitation](#17-déploiement-et-exploitation)
|
||
18. [Plan d'implémentation par phases](#18-plan-dimplémentation-par-phases)
|
||
19. [Décisions d'architecture (ADR — résumé)](#19-décisions-darchitecture-adr--résumé)
|
||
20. [Risques et mitigations](#20-risques-et-mitigations)
|
||
21. [Questions ouvertes pour Flowdeck](#21-questions-ouvertes-pour-flowdeck)
|
||
- [Annexe A — Correspondance Notion → Flowdeck](#annexe-a--correspondance-notion--flowdeck)
|
||
- [Annexe B — Glossaire](#annexe-b--glossaire)
|
||
- [Sources](#sources)
|
||
|
||
---
|
||
|
||
## 1. Résumé exécutif
|
||
|
||
La fonctionnalité « meeting » de Notion n'est pas un outil de visioconférence. Notion ne remplace ni Zoom, ni Google Meet, ni Teams. C'est une **couche de capture, de structuration et de mémoire** qui s'adosse à des réunions qui ont lieu ailleurs (ou en personne) et qui transforme une conversation éphémère en actif durable du workspace :
|
||
|
||
```text
|
||
Événement calendrier
|
||
→ note de réunion créée (ou liée) avant l'appel
|
||
→ capture audio sans bot + transcription pendant l'appel
|
||
→ résumé IA structuré, décisions et actions après l'appel
|
||
→ note recherchable, partageable, reliée aux projets et aux tâches
|
||
```
|
||
|
||
Les quatre piliers à reproduire dans Flowdeck sont donc :
|
||
|
||
| Pilier | Rôle | Difficulté |
|
||
|---|---|---|
|
||
| **1. Hub Meetings + calendrier** | Savoir quelles réunions arrivent, préparer les notes, retrouver les anciennes | Moyenne |
|
||
| **2. Document de réunion collaboratif** | Une note unique par réunion : agenda, notes libres, transcript, résumé | Moyenne à élevée (temps réel) |
|
||
| **3. Capture + transcription** | Enregistrer l'audio, transcrire, identifier les locuteurs | **Élevée sur le Web** (voir §6.2) |
|
||
| **4. Pipeline IA post-réunion** | Résumé ancré dans le transcript, décisions, actions assignées | Moyenne (fort enjeu qualité) |
|
||
|
||
**Recommandation principale.** Commencer par un **monolithe modulaire** côté serveur (un seul déployable, des modules aux frontières nettes), un **éditeur collaboratif CRDT** côté client, une **capture Web en deux modes** (micro, puis capture d'onglet), et des **fournisseurs IA abstraits derrière des interfaces** (STT et LLM remplaçables). Ne pas commencer par des microservices : le domaine est encore mouvant, et les frontières deviendront évidentes après le MVP.
|
||
|
||
**Le point d'architecture le plus important du document** se trouve au §6.2 : dans un navigateur, on ne peut pas capturer l'audio système comme le fait l'application desktop de Notion. Toute l'architecture de capture de Flowdeck découle de cette contrainte physique, pas d'un choix de goût.
|
||
|
||
---
|
||
|
||
## 2. Périmètre, personas et cas d'usage
|
||
|
||
### 2.1 Dans le périmètre
|
||
|
||
- Hub « Réunions » : réunions à venir, historique, recherche, filtres.
|
||
- Création / liaison d'une note de réunion depuis un événement calendrier.
|
||
- Synchronisation de calendriers externes (Google Calendar, Microsoft 365 au minimum).
|
||
- Préparation de réunion : ordre du jour, contexte, documents liés, modèle par type de réunion.
|
||
- Capture audio depuis le navigateur, transcription en direct et après coup.
|
||
- Téléversement d'un enregistrement audio existant pour transcription différée.
|
||
- Consentement des participants : demande, journalisation, politique de workspace.
|
||
- Notes libres prises par un humain **pendant** la transcription (les deux coexistent).
|
||
- Résumé IA structuré, décisions, actions avec responsable et échéance.
|
||
- Citations vérifiables : chaque affirmation du résumé pointe vers le passage du transcript.
|
||
- Partage et permissions : privé par défaut, partage automatique optionnel aux participants internes.
|
||
- Recherche plein texte et questions-réponses sur l'historique des réunions.
|
||
- Notifications et récapitulatifs post-réunion (courriel, Slack ou équivalent).
|
||
- Rétention configurable, suppression du transcript et/ou de l'audio, journal d'audit.
|
||
- Création de tâches dans Flowdeck à partir des actions extraites.
|
||
|
||
### 2.2 Hors périmètre (au moins au MVP)
|
||
|
||
- Héberger la visioconférence elle-même (audio/vidéo multi-participants). Flowdeck **rejoint** ou **accompagne** l'appel, il ne le transporte pas.
|
||
- Application desktop native de capture système (c'est un chantier séparé, voir Phase 4).
|
||
- Bot qui rejoint les appels à la place de l'utilisateur (option Phase 3, voir ADR-02).
|
||
- Coaching commercial en temps réel, analyse de sentiment, CRM avancé.
|
||
- Traduction simultanée des réunions.
|
||
|
||
### 2.3 Personas
|
||
|
||
| Persona | Besoin dominant | Fonction critique |
|
||
|---|---|---|
|
||
| **Organisateur** | Préparer, capturer, partager le compte rendu sans travail manuel | Création auto de la note, partage auto, actions |
|
||
| **Participant interne** | Retrouver ce qui a été décidé, ses actions | Recherche, vue « mes actions », citations |
|
||
| **Participant externe (invité)** | Être informé du recueil, recevoir le récapitulatif | Consentement, récapitulatif sans compte Flowdeck |
|
||
| **Absent / remplaçant** | Rattraper une réunion sans l'écouter en entier | Résumé fiable + transcript horodaté |
|
||
| **Admin de workspace** | Contrôler rétention, consentement, accès, coûts | Politiques, audit, opt-out de la fonction |
|
||
| **Développeur / intégrateur** | Brancher calendrier, tâches, webhooks | API stable, événements sortants |
|
||
|
||
### 2.4 Cas d'usage structurants
|
||
|
||
- **UC-01 — Préparer** : à partir du calendrier, créer la note d'une réunion à venir et y écrire l'ordre du jour.
|
||
- **UC-02 — Capturer en visio** : démarrer la transcription pendant un appel Zoom/Meet/Teams ouvert dans le navigateur ou à côté.
|
||
- **UC-03 — Capturer en personne** : enregistrer via le micro de l'ordinateur ou du téléphone, sans événement calendrier.
|
||
- **UC-04 — Réunion spontanée** : démarrer une note ad hoc en moins de 10 secondes.
|
||
- **UC-05 — Importer** : téléverser un fichier audio existant et obtenir transcript + résumé.
|
||
- **UC-06 — Clore** : à l'arrêt, générer le résumé, valider les actions, les convertir en tâches, partager.
|
||
- **UC-07 — Retrouver** : chercher « qu'est-ce qu'on a décidé sur le prix en septembre ? » et obtenir une réponse sourcée.
|
||
- **UC-08 — Gouverner** : un admin impose le message de consentement, une rétention de 30 jours du transcript et désactive l'audio stocké.
|
||
|
||
---
|
||
|
||
## 3. Analyse fonctionnelle : les Meetings dans Notion
|
||
|
||
*Cette section résume, avec mes mots, le comportement documenté publiquement par Notion (centre d'aide et page produit, consultés le 8 octobre 2026). Elle sert de cahier des charges fonctionnel de référence pour Flowdeck.*
|
||
|
||
### 3.1 Les trois surfaces du produit
|
||
|
||
La fonctionnalité est répartie sur trois surfaces qui partagent **le même objet central : la note de réunion**.
|
||
|
||
1. **L'onglet *Meetings*** (barre latérale de Notion) — le hub. Il liste les réunions à venir issues du calendrier connecté et l'ensemble des notes de réunion, avec recherche, tri et filtres. L'utilisateur peut y préparer une note à l'avance, rejoindre la réunion et démarrer la transcription.
|
||
2. **Notion Calendar** — l'application calendrier. Chaque événement peut porter une note : créer une note, en lier une existante, ouvrir la note, ou — à partir de 15 minutes avant le début — « rejoindre et transcrire ». Après la réunion, l'événement donne accès au résumé.
|
||
3. **Le bloc *AI Meeting Notes*** — le composant inséré dans une page (commande `/meet`). C'est le bloc qui contient l'ordre du jour / les notes libres, les contrôles de transcription, le transcript et le résumé généré. Il peut être intégré aux **modèles** d'une base de données de réunions, ce qui est le mécanisme de standardisation des comptes rendus.
|
||
|
||
**Leçon d'architecture n° 1 — une seule note par réunion.** Notion a unifié en 2026 les notes issues de Calendar et celles du workspace en un document unique par réunion, stocké dans le workspace. Pour Flowdeck, c'est une règle de modélisation à adopter dès le jour 1 (voir §9.2, contrainte d'unicité) : les doublons de notes pour un même événement sont la source classique de confusion, de problèmes de permissions et de déduplication pour les intégrations.
|
||
|
||
### 3.2 Points d'entrée
|
||
|
||
| Point d'entrée | Déclencheur |
|
||
|---|---|
|
||
| Commande `/meet` dans une page | Manuel, ad hoc |
|
||
| Onglet *Meetings* → réunion à venir | Événement calendrier |
|
||
| Événement dans Notion Calendar | Créer / lier / ouvrir / rejoindre et transcrire |
|
||
| Tuile « Événements à venir » de l'accueil | Raccourci vers la note |
|
||
| Notification / détection d'une réunion qui commence | Suggestion de démarrer une note |
|
||
| Mobile | Réunion en personne, micro du téléphone |
|
||
| Téléversement d'un fichier audio dans le bloc | Transcription différée |
|
||
|
||
### 3.3 Avant la réunion
|
||
|
||
- La note peut être créée **avant** l'appel et recevoir ordre du jour et contexte. Point important : ces notes humaines sont **prises en compte par l'IA** lors de la génération du résumé — le résumé n'est pas produit à partir du seul transcript.
|
||
- L'utilisateur peut définir une **base de données de réunions par défaut** : les notes créées depuis le calendrier ou une notification y sont rangées automatiquement.
|
||
- La note est **privée par défaut**. Un réglage personnel permet de la partager automatiquement avec les participants internes (membres du workspace) d'un événement calendrier, avec accès en lecture/édition.
|
||
- Les modèles par type de réunion (standup, appel commercial, réunion d'équipe, 1:1, etc.) déterminent la structure attendue du compte rendu.
|
||
|
||
### 3.4 Pendant la réunion
|
||
|
||
**Capture sans bot.** Aucun participant robot ne rejoint l'appel. La capture est locale, côté machine de l'utilisateur :
|
||
|
||
| Client | Ce qui est capturé | Conséquence pratique |
|
||
|---|---|---|
|
||
| Application desktop | Audio système **et** micro | Toutes les voix d'un appel visio sont captées, même au casque |
|
||
| Navigateur | **Micro uniquement** | L'audio de la visio n'est capté que s'il sort par les haut-parleurs ; au casque, les autres participants ne sont pas entendus |
|
||
| Mobile | Micro du téléphone | Adapté au présentiel, pas à un appel mené sur le même téléphone |
|
||
|
||
Le desktop requiert les permissions système d'enregistrement audio/écran. En environnement de bureau virtuel (VDI), la capture distante ne reçoit que le micro, sauf plugin local dédié.
|
||
|
||
**Consentement, intégré au produit.** Avant de transcrire, l'utilisateur doit obtenir le consentement de tous les participants. Notion fournit trois mécanismes : un message texte à coller dans le clavardage de la visio, un **message vocal** lu par une voix de synthèse (langue et voix configurables), ou la demande verbale simple. Options structurantes :
|
||
|
||
- lecture automatique du message à chaque démarrage (préférence personnelle) ;
|
||
- **imposition par le propriétaire du workspace** à tous les membres ;
|
||
- dans Google Meet, une extension dédiée publie et épingle un avis dans le clavardage et affiche un indicateur d'enregistrement.
|
||
|
||
Démarrer la transcription vaut confirmation que le consentement a été obtenu. C'est un acte tracé, pas une simple case cochée.
|
||
|
||
**Contrôles de session.** Démarrer / **mettre en pause** / reprendre / **arrêter** la transcription — les boutons *Pause* et *Stop* sont visibles côte à côte pendant l'enregistrement (capture 2, §3A.3). Pendant ce temps, l'utilisateur écrit ses propres notes dans le même bloc, la transcription continue en arrière-plan.
|
||
|
||
**Ce que les captures ajoutent à la documentation (9 octobre 2026, §3A).** Le panneau initial (capture 1) montre trois éléments qui ne sont pas de simples détails d'habillage : un **sélecteur d'instructions de résumé** (*Instructions: Auto*) présent **avant** le démarrage, une **attestation de consentement implicite par l'action** (« *By starting, you confirm everyone being transcribed has given consent* ») affichée en pied de bloc — en plus des mécanismes actifs du §3.4 — et un bouton de démarrage **à menu déroulant** (*Start transcribing* + chevron), qui laisse choisir une variante de démarrage (source, langue ou mode). Pendant l'enregistrement (capture 2), une **forme d'onde en direct** occupe le centre de la barre d'outils et un **bandeau d'essai** (« *You're on the free trial of AI Meeting Notes* ») apparaît dans le bloc. Enfin, la session d'essai observée était très courte (un seul segment à 0:00) et a **quand même** produit un résumé, classé « bref ou incomplet » (captures 4 et 6, §3A.5) : en pratique, un contenu insuffisant débouche sur un résumé dégradé et étiqueté, pas sur un refus sec — le design Flowdeck retient cette règle au §12.8, qui prime sur l'ancien seuil « environ une minute » compris comme condition bloquante.
|
||
|
||
**Transcription.** Le texte apparaît au fil de l'eau ; un changement de locuteur crée une nouvelle ligne. Sur desktop, les locuteurs peuvent être étiquetés — le cas le plus fiable étant la visio en 1:1, où micro et audio système sont deux canaux distincts ; si la note est liée à un événement calendrier, l'autre participant peut être nommé. Les limites documentées sont explicites : étiquetage moins fiable en groupe, en présentiel à micro partagé, sur navigateur et sur mobile. Une extension pour Google Meet améliore l'attribution, y compris en groupe, sur desktop.
|
||
|
||
### 3.5 Après la réunion
|
||
|
||
- À l'arrêt, le **résumé est généré automatiquement** : points clés, décisions et actions, dans la même page.
|
||
- Le format du résumé dépend d'**instructions** : mode automatique, formats prédéfinis par type de réunion, ou **instructions personnalisées** rédigées par l'utilisateur (privées par défaut, partageables, définissables comme défaut). Changer d'instructions après coup exige de régénérer le résumé (« réessayer »).
|
||
- Le résumé contient des **citations vers le transcript** : survoler montre le passage, cliquer y amène. C'est le mécanisme de vérifiabilité — et, pour Flowdeck, une exigence de conception non négociable (§12.4).
|
||
- Le traitement post-réunion est **visible, étape par étape**, dans l'onglet *Summary* (capture 3, §3A.4) : *Reading transcript…* → *Analyzing the transcript* → *Thinking about how to refer to people* → *Understanding the content*, avec une coche par étape terminée et un état global *Thinking*. L'étape « comment désigner les personnes » est un traitement à part entière — résolution des références aux locuteurs — ajouté au pipeline au §12.7.
|
||
- L'IA **retitre** la réunion d'après son contenu : l'en-tête du bloc passe de « Meeting @Today » à « *Brief or Incomplete Meeting Recording* » dans la session observée (captures 4 à 6). Le titre de page, lui, ne change pas : titre de page et titre de bloc sont deux champs distincts (§9.3, §12.8).
|
||
- Le résumé signale explicitement ses **manques** : enregistrement fragmentaire, aucun sujet ni ordre du jour discernable, notes de l'utilisateur vides. Les marqueurs de citation du résumé sont rendus comme des **notes numérotées** (¹) qui pointent vers un segment du transcript (captures 4 et 6).
|
||
- Une **barre de diffusion** apparaît au-dessus du résumé terminé — « *Share this summary* » : *Copy link*, *Email*, *Slack* (capture 4, §3A.5). Chaque canal est une action traçable, pas un simple copier-coller.
|
||
- Le récapitulatif peut être diffusé là où l'équipe travaille (par exemple Slack ou courriel), et les actions peuvent alimenter les tâches/projets.
|
||
- La note vit **à côté** des projets et documents liés ; elle est indexée par la recherche du workspace et interrogeable en questions-réponses, ce qui transforme l'historique des réunions en mémoire d'équipe.
|
||
|
||
### 3.6 Import d'audio existant
|
||
|
||
Un fichier audio peut être téléversé dans un bloc de notes pour être transcrit et résumé comme une session en direct. Formats documentés : AAC, M4A, MP3, WAV (les fichiers vidéo comme MOV/MP4 ne sont pas pris en charge par ce chemin). Différence de rétention importante : un fichier téléversé est **conservé sur les serveurs** jusqu'à suppression explicite, alors que l'audio d'une session en direct suit le régime temporaire décrit au §3.8.
|
||
|
||
### 3.7 Administration et gouvernance
|
||
|
||
- Activation/désactivation de la fonction au niveau du workspace par le propriétaire.
|
||
- Imposition du message de consentement à tous les membres.
|
||
- Base de réunions par défaut, réglages de partage automatique (personnels).
|
||
- Masquage possible de l'onglet *Meetings*.
|
||
- Côté entreprise, selon la documentation produit : rétention configurable du transcript (avec suppression automatique programmée en gardant le résumé), journaux d'audit, permissions granulaires, SSO, et garanties contractuelles de non-entraînement des modèles sur les données client.
|
||
|
||
### 3.8 Traitement et rétention des données (documentation publique)
|
||
|
||
Notion déclare recourir à des sous-traitants IA pour transcrire et analyser. Le régime documenté pour le direct est, en substance :
|
||
|
||
- l'audio est transmis pour une transcription en temps réel ; les sous-traitants ne le conservent pas ;
|
||
- une copie temporaire reste **localement** pendant la session ;
|
||
- si le traitement temps réel échoue, cette copie est téléversée pour une nouvelle tentative et conservée au plus quelques jours, puis supprimée ; la copie locale est supprimée après succès ou sous un jour environ ;
|
||
- sur mobile, l'audio transite par les serveurs puis est supprimé après succès, avec des fenêtres de conservation plus longues en cas d'échec.
|
||
|
||
**Leçon d'architecture n° 2 — ne pas stocker l'audio par défaut.** Le design « audio éphémère, transcript durable, résumé permanent » réduit à la fois le risque juridique, le coût de stockage et la surface d'attaque. Flowdeck doit l'adopter comme défaut, le stockage d'audio devenant une option explicite (§14.4).
|
||
|
||
### 3.9 Limites connues à ne pas reproduire aveuglément
|
||
|
||
| Limite documentée | Réponse recommandée pour Flowdeck |
|
||
|---|---|
|
||
| Navigateur : micro seul, visio au casque non captée | Ajouter la capture d'onglet (`getDisplayMedia`) dès la Phase 2 (§6.2) |
|
||
| Attribution des locuteurs faible en groupe | Séparer diarisation et identification ; permettre la correction manuelle des locuteurs (§12.3) |
|
||
| Démarrage manuel facile à oublier | Rappels calendrier T-15 / T-0 et détection d'événement en cours (§8.2) |
|
||
| Résumé dépendant de la qualité audio | Indicateur de niveau/qualité en direct et avertissements (§11.3) |
|
||
| Fonction réservée aux plans payants supérieurs | Décider tôt du modèle d'entitlement et du compteur de minutes (§7.10) |
|
||
|
||
---
|
||
|
||
## 3A. Parcours visuel de la prise de réunion — les 6 états du bloc (captures de référence)
|
||
|
||
*Section ajoutée en version 1.1 (9 octobre 2026). Source primaire : 6 captures d'écran d'une même session réelle dans Notion, fournies par Bruno et présentées ici dans l'ordre chronologique où elles ont été prises. La session d'essai est volontairement minuscule — un seul segment de quelques secondes, des notes quasi vides — et c'est précisément ce qui la rend utile : elle montre le comportement du produit dans le cas dégradé (contenu insuffisant), pas seulement dans le cas nominal.*
|
||
|
||
*Numérotation : cette section s'insère entre les sections 3 et 4 sans renuméroter la suite du document, afin de préserver tous les renvois internes de la version 1.0.*
|
||
|
||
### 3A.1 Vue d'ensemble : un seul bloc, six états
|
||
|
||
Le point le plus important que montrent les captures : **il n'y a pas six écrans, il y a un seul bloc qui change d'état**. Le titre de page (« Meeting @Today 8:14 AM »), l'en-tête du bloc et la position dans la page ne bougent jamais ; seuls l'en-tête interne, la rangée d'onglets, les contrôles de droite et le corps changent, au fil d'une machine à états unique.
|
||
|
||
```mermaid
|
||
stateDiagram-v2
|
||
[*] --> Initial: bloc créé (/meet, calendrier, modèle)
|
||
Initial --> Enregistrement: Start transcribing<br/>(attestation de consentement incluse)
|
||
Enregistrement --> Pause: Pause
|
||
Pause --> Enregistrement: Reprendre
|
||
Enregistrement --> Analyse: Stop
|
||
Pause --> Analyse: Stop
|
||
Analyse --> Resultat: résumé généré + titre généré
|
||
Resultat --> Resultat: navigation Summary / Notes / Transcript
|
||
Analyse --> ErreurTraitement: échec STT ou LLM
|
||
ErreurTraitement --> Analyse: Réessayer (à partir des segments conservés)
|
||
Resultat --> [*]
|
||
```
|
||
|
||
| # | État | Capture | Onglets visibles | Contrôle principal à droite |
|
||
|---|---|---|---|---|
|
||
| 1 | Initial (prêt) | `01-panneau-initial.png` | *Notes* seul | *Start transcribing* (bleu, à menu) |
|
||
| 2 | Enregistrement | `02-enregistrement-en-cours.png` | *Notes*, *Transcript* | *Pause* + *Stop* ; forme d'onde en direct |
|
||
| 3 | Analyse | `03-analyse-en-cours.png` | *Summary*, *Notes*, *Transcript* | Pastille *Thinking* ; étapes cochées une à une |
|
||
| 4 | Résultat — *Summary* | `04-resultat-summary.png` | Les trois ; *Summary* actif | Barre « Share this summary » |
|
||
| 5 | Résultat — *Notes* | `05-resultat-notes.png` | Les trois ; *Notes* actif | (réglages seulement) |
|
||
| 6 | Résultat — *Transcript* | `06-resultat-transcript.png` | Les trois ; *Transcript* actif | (réglages seulement) |
|
||
|
||
**Règle de révélation progressive des onglets** (à reproduire telle quelle dans Flowdeck) :
|
||
|
||
```text
|
||
État initial : [ Notes ]
|
||
Enregistrement : [ Notes ] [ Transcript ] ← Transcript naît au démarrage
|
||
Analyse / résultat : [ Summary ] [ Notes ] [ Transcript ] ← Summary naît à l'arrêt,
|
||
et devient l'onglet actif par défaut
|
||
```
|
||
|
||
Un onglet n'existe pas avant que son contenu puisse exister. C'est ce qui rend le bloc lisible pour un nouvel utilisateur : pas d'onglets vides à expliquer.
|
||
|
||
### 3A.2 État 1 — Panneau initial (avant démarrage)
|
||
|
||

|
||
|
||
**Ce que montre la capture**
|
||
|
||
- **Double titre.** Le titre de la page, « Meeting **@Today** 8:14 AM », est un titre généré automatiquement à la création, où `@Today` est une mention de date — pas du texte libre. Le même libellé est repris dans l'en-tête du bloc, précédé d'une icône calendrier avec chevron : le bloc sait qu'il est rattaché à un moment, et ce rattachement est modifiable.
|
||
- **Un seul onglet**, *Notes*, en pastille active à gauche. À droite de la même rangée : une icône « ampoule » (suggestions / aide IA), une icône « curseurs » (réglages du bloc et de la transcription), puis le bouton primaire bleu.
|
||
- **Bouton primaire à menu** : *Start transcribing* + chevron dans un compartiment séparé. Le clic principal démarre avec les réglages courants ; le chevron ouvre les variantes. Flowdeck doit y placer : source audio (micro / onglet + micro), langue de la réunion, et modèle d'instructions si distinct du sélecteur du pied.
|
||
- **Texte d'attente dans le corps** : « *Notion AI will summarize the notes and transcript* ». Ce n'est pas un placeholder d'éditeur, c'est la promesse du bloc, affichée là où le résumé apparaîtra.
|
||
- **Pied de bloc, en trois zones** : à gauche, « *Instructions: Auto* » avec chevron — le sélecteur d'instructions de résumé, donc **choisi et figé au démarrage**, pas après coup ; au centre, séparée par un trait vertical, la mention « *By starting, you confirm everyone being transcribed has given consent.* » ; à droite, deux icônes (sortie audio / haut-parleur et copie).
|
||
|
||
**Composants à implémenter pour Flowdeck**
|
||
|
||
| Composant | Rôle | Section |
|
||
|---|---|---|
|
||
| `meeting-block-header` | Icône calendrier + chevron, titre du bloc éditable, distinct du titre de page | §6.5 |
|
||
| `start-transcribe-split-button` | Démarrage immédiat + menu des variantes (source, langue) ; déclenche la porte de consentement | §6.1, §8.2 |
|
||
| `instructions-selector` | *Auto* / modèle par type / instruction personnalisée ; la valeur choisie est **photographiée** (`instruction_snapshot`) dans la session au démarrage | §9.3, §12.4 |
|
||
| `consent-attestation-inline` | Mention d'attestation par l'action, toujours visible avant démarrage ; le clic sur *Start* écrit le `consent_record` avec `method = start_attestation` | §14.1 |
|
||
| `summary-promise-placeholder` | Texte d'attente du corps, remplacé par les étapes d'analyse (§3A.4) puis par le résumé | §6.5 |
|
||
|
||
### 3A.3 État 2 — Enregistrement en cours
|
||
|
||

|
||
|
||
**Ce que montre la capture**
|
||
|
||
- **L'onglet *Transcript* apparaît** dès le démarrage, avec une icône micro ; *Notes* reste l'onglet actif et éditable : la transcription tourne **en arrière-plan de l'édition**, l'utilisateur n'a pas à choisir entre écrire et transcrire.
|
||
- **Forme d'onde en direct** au centre de la barre d'outils : une suite de barres et de points dont la hauteur suit le niveau sonore capté. C'est le retour visuel « ça enregistre, ça entend quelque chose » — distinct d'un simple point rouge. Dans la capture, la forme retombe en points à droite : le silence est lui aussi visible.
|
||
- **Contrôles remplacés en place** : *Pause* (neutre) et *Stop* (rouge atténué) remplacent le bouton de démarrage, au même endroit. Les icônes ampoule et curseurs restent présentes.
|
||
- **Bandeau d'entitlement dans le bloc** : « ↑ *Upgrade for full access* — *You're on the free trial of AI Meeting Notes.* », fermable par une croix. Il apparaît **à partir de l'enregistrement**, pas sur le panneau initial de cette session, et il reste présent dans tous les états suivants.
|
||
- **Icône commentaire** en haut à droite, hors du bloc : les commentaires de page restent disponibles pendant la capture.
|
||
- **Ce qui n'apparaît pas** : aucun compteur de durée n'est visible dans la capture. Flowdeck ne doit pas copier cette absence : un chronomètre de session et le temps restant du quota sont ajoutés à la barre d'outils (§6.5), parce que l'utilisateur doit savoir depuis combien de temps il enregistre et quand le quota approche.
|
||
|
||
**Composants à implémenter pour Flowdeck**
|
||
|
||
| Composant | Rôle | Section |
|
||
|---|---|---|
|
||
| `waveform-visualizer` | Niveau RMS par canal calculé dans l'`AudioWorklet`, rendu en barres/points à ~10 images/s, sans stocker l'audio ; canal distant plat en mode B = déclencheur de l'alerte « je n'entends que vous » | §6.2, §11.3 |
|
||
| `pause-resume-controls` | *Pause* suspend l'envoi et le STT sans clore la session ; *Stop* clôt, fige le transcript et lance l'analyse ; les deux états sont des états de session en base, pas seulement d'interface | §9.3, §10.1 |
|
||
| `entitlement-trial-banner` | Bandeau d'essai / de quota, fermable par utilisateur et par bloc, réaffiché si le quota devient critique ; piloté par `feature.meeting_ai` et `minutes_transcribed` | §7.10 |
|
||
| `recording-session-timer` | **Ajout Flowdeck** (absent de la capture) : durée écoulée, état *en pause*, temps restant du plan | §6.5 |
|
||
|
||
### 3A.4 État 3 — Analyse en cours (« Thinking »)
|
||
|
||

|
||
|
||
**Ce que montre la capture**
|
||
|
||
- À l'arrêt, **l'onglet *Summary* naît et devient actif automatiquement** : l'utilisateur est emmené vers le résultat sans avoir à le chercher.
|
||
- À droite, les contrôles d'enregistrement disparaissent ; seule subsiste l'icône réglages, accompagnée d'une **pastille *Thinking*** : l'état global du traitement, au même emplacement que les anciens boutons.
|
||
- Le corps du bloc affiche **la liste des étapes du traitement, en langage humain**, chacune cochée quand elle se termine :
|
||
1. ✓ *Reading transcript…* — lecture / assemblage du transcript final ;
|
||
2. ✓ *Analyzing the transcript* — analyse du contenu transcrit ;
|
||
3. ✓ *Thinking about how to refer to people* — **résolution des références aux personnes** : décider comment désigner chaque locuteur (nom, rôle, pronom) dans le résumé ;
|
||
4. (en cours) *Understanding the content* — compréhension du contenu avant rédaction.
|
||
- Le curseur visible dans le corps et la croix du bandeau rappellent que la page reste interactive pendant l'analyse : rien n'est bloqué.
|
||
|
||
**Ce que cela change pour le pipeline Flowdeck.** La version 1.0 enchaînait « diarisation → normalisation → résumé » (§12.1). Les captures montrent **deux étapes distinctes supplémentaires**, désormais normatives au §12.7 :
|
||
|
||
- une étape de **résolution des références** (`speaker_reference_resolution`) entre l'analyse et la rédaction : c'est elle qui transforme « Locuteur 2 » en « Bruno » ou en « le participant » dans le résumé, avec un niveau de confiance — et qui s'abstient quand elle ne sait pas (§12.3) ;
|
||
- une étape de **compréhension / segmentation thématique** (`content_understanding`) avant la génération : sujets abordés, enchaînement, ce qui est une décision et ce qui est une digression.
|
||
|
||
Ces étapes doivent être **émises comme événements de progression** (`processing.step`, §10.3) et affichées par un composant dédié, avec repli : si le traitement dépasse un délai raisonnable, l'étape en cours affiche une durée et un bouton « réessayer » dès qu'un échec est connu — jamais un *Thinking* éternel sans issue (§16).
|
||
|
||
| Composant | Rôle | Section |
|
||
|---|---|---|
|
||
| `processing-steps-tracker` | Liste d'étapes nommées, états `pending / running / done / failed`, alimentée par les événements `processing.step` ; survit au rechargement de la page (état relu depuis `processing_steps`) | §9.3, §10.3, §12.7 |
|
||
| `thinking-indicator` | Pastille d'état global dans l'en-tête du bloc (`Thinking`, puis `Done` / `Failed`) | §6.5 |
|
||
|
||
### 3A.5 État 4 — Résultat, onglet *Summary*
|
||
|
||

|
||
|
||
**Ce que montre la capture**
|
||
|
||
- **Retitrage par l'IA** : l'en-tête du bloc devient « *Brief or Incomplete Meeting Recording* ». Le titre de page, en haut, reste « Meeting @Today 8:14 AM » : la génération du titre touche le **bloc/réunion**, pas le document hôte. Le titre généré est ici un **diagnostic** (réunion brève ou incomplète), pas un sujet — parce qu'il n'y avait pas de sujet discernable.
|
||
- **Barre de diffusion du résumé**, encadrée, juste sous les onglets : « *Share this summary* » à gauche ; à droite, trois actions — *Copy link* (lien avec icône chaîne), *Email* (enveloppe), *Slack* (logo) — et une croix pour masquer la barre. Elle n'existe qu'une fois un résumé disponible.
|
||
- **Structure du résumé dégradé** : une section *Overview* en puces, puis *Action Items*. Pas de section *Decisions* fabriquée de toutes pièces : quand il n'y a rien, la section est absente ou affiche son état vide — ici, *Action Items* affiche explicitement « *No action items could be identified from the available transcript* ».
|
||
- **Le résumé parle de ses propres limites**, en puces sourcées : l'enregistrement n'a capté qu'un échange court et fragmentaire, sans sujet ni ordre du jour discernable ; le contenu semble pris en pleine conversation et fait référence à quelqu'un qui n'était « pas vraiment en colère » ; les notes de l'utilisateur étaient vides et n'apportaient aucun contexte.
|
||
- **Citations numérotées** : chaque puce se termine par un petit marqueur ¹ qui renvoie au segment du transcript — ici le même segment unique pour toutes les puces, ce qui rend la faiblesse de la source immédiatement visible.
|
||
|
||
**Composants à implémenter pour Flowdeck**
|
||
|
||
| Composant / traitement | Rôle | Section |
|
||
|---|---|---|
|
||
| `completeness-classifier` | Classe la session **avant** la rédaction : `complete / brief / incomplete / fragmentary`, à partir de la durée, du nombre de mots et de segments, de la présence d'un ordre du jour et de notes non vides ; la classe pilote le format du résumé, ses avertissements et le titre | §12.8 |
|
||
| `title-generator` | Produit le titre de la réunion à partir du transcript et des notes ; en cas de classe `brief/incomplete`, produit un titre-diagnostic explicite plutôt qu'un faux sujet ; ne touche jamais le titre de page hôte ; titre toujours modifiable par l'humain | §12.8 |
|
||
| `summary-share-bar` | *Copy link* (lien vers la note avec ancre sur le résumé, soumis à l'ACL), *Email* et *Slack* (envois tracés dans `summary_distributions`), masquable par résumé | §7.1, §10.1 |
|
||
| `citation-marker-renderer` | Rend les `evidence_segment_ids` (§12.4) en marqueurs numérotés stables par résumé ; survol = aperçu du segment, clic = onglet *Transcript* ouvert au bon horodatage (§3A.7) | §6.3, §12.4 |
|
||
| États vides de section | Chaque section du schéma de résumé a un état vide explicite (« aucun élément identifié ») plutôt qu'une absence silencieuse ou un contenu inventé | §12.4 |
|
||
|
||
### 3A.6 État 5 — Résultat, onglet *Notes*
|
||
|
||

|
||
|
||
**Ce que montre la capture**
|
||
|
||
- L'onglet *Notes* contient **uniquement le texte de l'humain** : « *on inscrit des notes de meeting ici …* », conservé tel quel à travers l'enregistrement, l'analyse et la génération du résumé. L'IA ne l'a ni réécrit, ni déplacé, ni absorbé dans le résumé — elle a seulement constaté, dans le *Summary*, qu'il n'apportait pas de contexte exploitable.
|
||
- Sous le texte, l'aide de l'éditeur : « *Press 'space' for AI or '/' for commands* » — l'éditeur de notes du bloc est le même éditeur de blocs que le reste du produit (commandes `/`, assistance IA à la barre d'espace), pas un champ de texte séparé.
|
||
- L'en-tête du bloc affiche le titre généré (« *Brief or Incomplete Meeting Recording* ») : le retitrage est commun aux trois onglets, parce qu'il porte sur la réunion, pas sur l'onglet.
|
||
|
||
**Conséquence d'architecture (déjà un principe au §4, ici démontrée)** : l'onglet *Notes* est la vue éditable du document collaboratif (§6.3) filtrée sur les blocs humains ; les onglets *Summary* et *Transcript* sont des vues du même objet réunion, pas trois documents. Passer d'un onglet à l'autre ne change ni l'URL ni l'ACL ni l'en-tête — seulement le corps du bloc.
|
||
|
||
### 3A.7 État 6 — Résultat, onglet *Transcript*
|
||
|
||

|
||
|
||
**Ce que montre la capture**
|
||
|
||
- **Regroupement par source audio**, pas seulement par locuteur : une ligne d'en-tête « *Bruno Charest's audio* », précédée d'une icône de source. Le transcript est d'abord organisé **par piste** (l'audio de qui / de quel canal), puis par segments horodatés dans chaque piste.
|
||
- **Rail d'horodatage** : « 0:00 » à gauche du segment, texte à droite, reliés par un trait vertical. Cliquer une citation du résumé (§3A.5) doit amener ici, sur le segment exact de la bonne piste.
|
||
- **Marque de troncature** : le texte commence par « *--What I like first is…* » — le double tiret signale un segment qui commence **en pleine phrase** (la capture a démarré après le début de l'énoncé). C'est un métadonnée de segment (`starts_mid_utterance`), pas une coquetterie de transcription : le classifieur de complétude (§12.8) s'en sert.
|
||
- Le segment unique contient tout l'échange capté : « *…no, no, he wasn't really angry.* » — c'est exactement la phrase que le résumé cite en ¹ et commente comme « quelqu'un qui n'était pas vraiment en colère ». La chaîne citation → segment → audio source est vérifiable de bout en bout sur ce cas minimal.
|
||
|
||
**Composants à implémenter pour Flowdeck**
|
||
|
||
| Composant | Rôle | Section |
|
||
|---|---|---|
|
||
| `transcript-source-group` | Groupe de segments par piste/source (`self / remote / room` + propriétaire de la piste), avec en-tête nommé (« l'audio de X ») ; extension directe du modèle à canaux séparés du §6.2 | §9.3, §11 |
|
||
| `transcript-timeline-rail` | Horodatages cliquables, défilement jusqu'au segment cité, surbrillance temporaire du segment cible | §6.3 |
|
||
| Marqueurs de segment | `starts_mid_utterance / ends_mid_utterance` sur `transcript_segments`, produits par le STT / la segmentation, consommés par le classifieur de complétude et affichés (double tiret ou équivalent) | §9.3, §12.8 |
|
||
|
||
### 3A.8 Anatomie commune du bloc (tous états)
|
||
|
||
```text
|
||
┌─ Page hôte ─────────────────────────────────────────────────────┐
|
||
│ Titre de page (jamais retitré par l'IA) │
|
||
│ ┌─ Bloc Meeting ────────────────────────────────────────────┐ │
|
||
│ │ En-tête : [📅 ▾] Titre du bloc (retitrable par l'IA) │ │
|
||
│ │ ───────────────────────────────────────────────────────── │ │
|
||
│ │ Onglets (révélation progressive) ···· aide · réglages · │ │
|
||
│ │ contrôle d'état : │ │
|
||
│ │ Start / Pause+Stop / │ │
|
||
│ │ Thinking / — │ │
|
||
│ │ Corps : selon l'onglet actif et l'état │ │
|
||
│ │ Notes → éditeur de blocs humain │ │
|
||
│ │ Transcript→ forme d'onde (en direct) puis segments │ │
|
||
│ │ Summary → étapes Thinking, puis résumé + citations │ │
|
||
│ │ Barre de diffusion (si résumé disponible) │ │
|
||
│ │ Pied : Instructions · attestation consentement · │ │
|
||
│ │ bandeau d'essai / quota (fermable) │ │
|
||
│ └───────────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 3A.9 Enseignements des captures — écarts avec la version 1.0
|
||
|
||
| # | Observation (capture) | Écart en 1.0 | Correctif en 1.1 |
|
||
|---|---|---|---|
|
||
| 1 | Le bloc est une machine à états à révélation progressive (1 → 2 → 3 onglets) | Le document décrivait des modules, pas les états du bloc ni leurs transitions | §3A.1, §6.5 |
|
||
| 2 | Forme d'onde en direct dans la barre d'outils | Seuls des « indicateurs de niveau » textuels étaient prévus (§6.2) | `waveform-visualizer`, §3A.3 |
|
||
| 3 | *Pause* et *Stop* sont deux actions distinctes et simultanément visibles | *Pause* n'apparaissait pas dans l'API (§10.1) | Endpoint `pause`, état `paused`, §8.2 |
|
||
| 4 | Le traitement affiche 4 étapes nommées, dont « comment désigner les personnes » | Le pipeline allait de la diarisation au résumé sans étape de résolution des références ni de compréhension explicite | §12.7 |
|
||
| 5 | Une session de quelques secondes produit un résumé dégradé classé « bref / incomplet », pas une erreur | Le seuil « ~1 minute » était formulé comme une condition de production du résumé | §12.8 : classification, pas blocage |
|
||
| 6 | L'IA retitre le bloc, pas la page | Le titre généré n'existait pas dans le modèle (§9.3) | `generated_title`, `title-generator`, §12.8 |
|
||
| 7 | Barre « Share this summary » (lien / courriel / Slack) au-dessus du résumé | La diffusion n'existait qu'en notification d'arrière-plan (§7.1) | `summary-share-bar`, `summary_distributions`, §10.1 |
|
||
| 8 | Bandeau d'essai gratuit présent dès l'enregistrement, dans le bloc | L'entitlement était un concept back-end (§7.10) sans composant d'interface | `entitlement-trial-banner`, §3A.3 |
|
||
| 9 | Attestation de consentement par le clic de démarrage, en pied de bloc | Seuls les mécanismes actifs (message texte / vocal) étaient décrits | `consent-attestation-inline`, §14.1 |
|
||
| 10 | Transcript regroupé par piste source, segment marqué « début en pleine phrase » | Le modèle ne regroupait que par locuteur et ne traçait pas la troncature | §3A.7, colonnes §9.3 |
|
||
|
||
|
||
---
|
||
|
||
## 3B. Maquettes ASCII du panneau de prise de réunion — disposition exacte des composants
|
||
|
||
*Section ajoutée en version 1.2 (9 octobre 2026). La section 3A explique **quoi** contient chaque état du bloc ; cette section montre **où exactement** chaque composant se place dans le panneau, en reproduisant les 6 captures de référence en dessins ASCII (wireframes). Un développeur doit pouvoir implémenter la disposition du panneau Flowdeck à partir de cette seule section, sans rouvrir les captures.*
|
||
|
||
### 3B.1 Conventions de lecture des maquettes
|
||
|
||
- **Même gabarit pour les 6 panneaux** : largeur fixe (112 colonnes), coins arrondis (`╭ ╮ ╰ ╯`) comme le bloc réel, bordure haute du bloc toujours au même endroit. Ce qui ne change jamais d'un panneau à l'autre est dessiné à l'identique : titre de page, en-tête du bloc, rangée d'onglets, pied de bloc.
|
||
- **Le titre de page est hors du bloc**, en très gros caractères : « Meeting » en gras blanc, « @Today 8:14 AM » en gris. `@Today` est une mention de date.
|
||
- **Pastilles** : `( ✎ Notes )` = onglet actif (fond gris foncé, texte blanc). Un onglet inactif est dessiné sans parenthèses, en gris : `mic Transcript`. `( Thinking )` = pastille d'état, même forme que les onglets.
|
||
- **Boutons** : `[ Start transcribing | ▾ ]` = bouton rectangulaire à coins arrondis ; le `|` marque la séparation interne entre l'action principale et son menu (chevron `▾`). `[ Stop ]` est rouge atténué, `[ Pause ]` neutre, *Start transcribing* bleu — les couleurs ne se voient pas en ASCII, elles sont précisées dans la lecture de chaque panneau.
|
||
- **Icônes** : `[▤]` calendrier · `▾` chevron d'ouverture · `✎` crayon (Notes) · `☰` liste (Summary) · `mic` microphone (Transcript) · `☼` ampoule (suggestions) · `-o-` curseurs (réglages du bloc) · `♪` sortie audio · `⧉` copie · `✉` courriel · `↑` mise à niveau · `✕` fermer · `✓` étape terminée · `⊙` étape en cours · `¹` marqueur de citation · `[commentaires]` icône bulle, située **hors du bloc**, en haut à droite de la page.
|
||
- **Textes en gris** dans le produit (promesse de résumé, aide de l'éditeur, pied de bloc) sont dessinés comme les autres textes ; la lecture de chaque panneau précise ce qui est grisé.
|
||
|
||
### 3B.2 Le panneau annoté — les 8 zones
|
||
|
||
```text
|
||
① Meeting @Today 8:14 AM
|
||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||
│ ② [▤] ▾ Meeting @Today │
|
||
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||
│ ③ ( ✎ Notes ) mic Transcript ( ☰ Summary ) ④ ☼ -o- [ Start | ▾ ] / [ Pause ] [ Stop ] / ( Thinking ) │
|
||
│ ⑤ Corps : Notes (éditeur) / Transcript (forme d'onde, segments) / Summary (étapes, résumé) │
|
||
│ ⑥ [ Share this summary ............ Copy link | Email | Slack | ✕ ] (si résumé présent) │
|
||
│ ⑦ Instructions: Auto ▾ │ By starting, you confirm everyone being transcribed has given consent. │
|
||
│ ⑧ ↑ Upgrade for full access You're on the free trial of AI Meeting Notes. ✕ │
|
||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||
```
|
||
|
||
| Zone | Composant | Position exacte | Présence |
|
||
|---|---|---|---|
|
||
| ① | Titre de page | Hors bloc, au-dessus, très gros, aligné à gauche du bloc | Toujours ; jamais modifié par l'IA |
|
||
| ② | En-tête du bloc | Première rangée du bloc : `[▤] ▾` puis le titre du bloc | Toujours ; le titre devient le titre généré après analyse (§12.8) |
|
||
| — | Filet de séparation | Sous l'en-tête, pleine largeur | Toujours |
|
||
| ③ | Onglets | Deuxième rangée, à gauche, dans l'ordre *Summary · Notes · Transcript* quand les trois existent | Révélation progressive (§3A.1) |
|
||
| ④ | Contrôles d'état | Deuxième rangée, **à droite**, au même niveau que les onglets : ampoule, réglages, puis le contrôle propre à l'état (*Start* / *Pause+Stop* / *Thinking* / rien) | Toujours ; seul le contrôle d'état change |
|
||
| ⑤ | Corps | Sous la rangée d'onglets, pleine largeur, contenu selon l'onglet actif | Toujours |
|
||
| ⑥ | Barre de diffusion | **Dans le corps**, en haut de l'onglet *Summary*, sous forme de sous-cadre pleine largeur | Seulement quand un résumé existe |
|
||
| ⑦ | Pied de bloc — réglages de session | Dernière rangée du panneau initial : *Instructions* à gauche, attestation de consentement au centre après un séparateur vertical `│`, icônes audio et copie à droite | État initial seulement |
|
||
| ⑧ | Bandeau d'essai / quota | Dernière rangée du bloc, aligné à gauche, croix de fermeture à droite | À partir de l'enregistrement (captures 2 à 6) |
|
||
|
||
### 3B.3 Maquette 1 — Panneau initial (capture 1)
|
||
|
||
```text
|
||
Meeting @Today 8:14 AM
|
||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||
│ [▤] ▾ Meeting @Today │
|
||
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||
│ ( ✎ Notes ) ☼ -o- [ Start transcribing | ▾ ] │
|
||
│ │
|
||
│ Notion AI will summarize the notes and transcript │
|
||
│ │
|
||
│ │
|
||
│ Instructions: Auto ▾ │ By starting, you confirm everyone being transcribed has given consent. ♪ ⧉ │
|
||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||
```
|
||
|
||
**Lecture du panneau**
|
||
|
||
- Rangée d'onglets réduite à un seul élément : `( ✎ Notes )` à gauche. À droite, sur la **même rangée** : `☼`, `-o-`, puis le bouton bleu `[ Start transcribing | ▾ ]`, élément le plus à droite et le plus visible du panneau.
|
||
- Corps quasi vide : une seule ligne de texte gris, alignée à gauche sous les onglets — la promesse « *Notion AI will summarize the notes and transcript* ».
|
||
- Pied de bloc sur une rangée, en trois groupes : `Instructions: Auto ▾` à gauche ; séparateur vertical ; phrase de consentement au centre ; `♪` et `⧉` à droite. Aucun bandeau d'essai à cet état.
|
||
|
||
### 3B.4 Maquette 2 — Enregistrement en cours (capture 2)
|
||
|
||
```text
|
||
Meeting @Today 8:14 AM [commentaires]
|
||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||
│ [▤] ▾ Meeting @Today │
|
||
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||
│ ( ✎ Notes ) mic Transcript · · : | | ‖ ‖ | | : · · · · · · · · [ Pause ] [ Stop ] │
|
||
│ │
|
||
│ Notion AI will summarize the notes and transcript │
|
||
│ │
|
||
│ │
|
||
│ ↑ Upgrade for full access You're on the free trial of AI Meeting Notes. ✕ │
|
||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||
```
|
||
|
||
**Lecture du panneau**
|
||
|
||
- L'en-tête et le titre de page sont **inchangés**. Seule nouveauté hors bloc : `[commentaires]` en haut à droite.
|
||
- L'onglet `mic Transcript` est apparu à droite de `( ✎ Notes )` ; *Notes* reste actif. La **forme d'onde occupe le centre** de la rangée : points et barres de hauteurs variables (`· : | ‖`), qui retombent en points quand le son cesse — le silence se dessine aussi.
|
||
- À droite, le bouton de démarrage a été **remplacé en place** par deux boutons côte à côte : `[ Pause ]` (neutre) puis `[ Stop ]` (rouge atténué), *Stop* étant l'élément le plus à droite.
|
||
- Le corps garde la même ligne de promesse grisée : pendant l'enregistrement, l'utilisateur est dans l'onglet *Notes*.
|
||
- Le pied de bloc a changé de contenu : c'est maintenant le **bandeau d'essai** — flèche `↑` et « *Upgrade for full access* » en bleu à gauche, phrase d'essai à la suite, `✕` de fermeture tout à droite.
|
||
|
||
### 3B.5 Maquette 3 — Analyse en cours (capture 3)
|
||
|
||
```text
|
||
Meeting @Today 8:14 AM [commentaires]
|
||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||
│ [▤] ▾ Meeting @Today │
|
||
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||
│ ( ☰ Summary ) ✎ Notes mic Transcript -o- ( Thinking ) │
|
||
│ │
|
||
│ ✓ Reading transcript... │
|
||
│ ✓ Analyzing the transcript │
|
||
│ ✓ Thinking about how to refer to people │
|
||
│ ⊙ Understanding the content I │
|
||
│ │
|
||
│ ↑ Upgrade for full access You're on the free trial of AI Meeting Notes. ✕ │
|
||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||
```
|
||
|
||
**Lecture du panneau**
|
||
|
||
- Les trois onglets sont présents ; `( ☰ Summary )` est devenu l'onglet actif et s'est placé **en premier** à gauche — l'ordre d'affichage est *Summary, Notes, Transcript*.
|
||
- À droite : l'icône réglages `-o-` subsiste seule, suivie de la pastille `( Thinking )` qui occupe l'emplacement des anciens boutons *Pause / Stop*.
|
||
- Corps = la **liste des étapes**, alignée à gauche, une étape par ligne, coche `✓` devant les étapes terminées, `⊙` devant l'étape en cours (*Understanding the content*, en gras blanc). Le `I` isolé à droite de la dernière étape est le **curseur de texte** visible dans la capture : la page reste éditable pendant l'analyse.
|
||
- Bandeau d'essai inchangé, en dernière rangée.
|
||
|
||
### 3B.6 Maquette 4 — Résultat, onglet *Summary* (capture 4)
|
||
|
||
```text
|
||
Meeting @Today 8:14 AM [commentaires]
|
||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||
│ [▤] ▾ Brief or Incomplete Meeting Recording │
|
||
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||
│ ( ☰ Summary ) ✎ Notes mic Transcript -o- │
|
||
│ │
|
||
│ ╭────────────────────────────────────────────────────────────────────────────────────────────────────╮ │
|
||
│ │ Share this summary [ ⧉ Copy link ] [ ✉ Email ] [ Slack ] ✕ │ │
|
||
│ ╰────────────────────────────────────────────────────────────────────────────────────────────────────╯ │
|
||
│ │
|
||
│ Overview │
|
||
│ • The recording captured only a short, fragmentary exchange with no discernible meeting │
|
||
│ topic, agenda, or context ¹ │
|
||
│ • The content appears to be mid-conversation, referencing someone not being “really │
|
||
│ angry,” but no further context is available ¹ │
|
||
│ • The user's notes were empty, providing no additional context about the meeting's │
|
||
│ purpose │
|
||
│ │
|
||
│ Action Items │
|
||
│ • No action items could be identified from the available transcript │
|
||
│ │
|
||
│ ↑ Upgrade for full access You're on the free trial of AI Meeting Notes. ✕ │
|
||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||
```
|
||
|
||
**Lecture du panneau**
|
||
|
||
- Le titre de l'en-tête ② a été remplacé par le titre généré : « *Brief or Incomplete Meeting Recording* ». Le titre de page ①, lui, n'a pas bougé.
|
||
- Rangée d'onglets inchangée, *Summary* actif ; à droite, **plus aucun contrôle d'état** : seule l'icône réglages `-o-` subsiste.
|
||
- Juste sous les onglets, la **barre de diffusion** ⑥ : un sous-cadre pleine largeur dans le corps. À gauche « *Share this summary* » ; à droite, trois boutons côte à côte — `[ ⧉ Copy link ]`, `[ ✉ Email ]`, `[ Slack ]` (avec le logo Slack) — puis `✕` pour masquer la barre.
|
||
- Le résumé suit en dessous, dans le même corps : titres de section en gras blanc (« *Overview* », « *Action Items* »), puces `•` avec texte retourné à la ligne et **continuation indentée** sous la première ligne, marqueurs de citation `¹` en fin de puce. La section *Action Items* affiche son état vide en une puce ordinaire.
|
||
- Bandeau d'essai inchangé, en dernière rangée.
|
||
|
||
### 3B.7 Maquette 5 — Résultat, onglet *Notes* (capture 5)
|
||
|
||
```text
|
||
Meeting @Today 8:14 AM [commentaires]
|
||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||
│ [▤] ▾ Brief or Incomplete Meeting Recording │
|
||
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||
│ ( ☰ Summary ) ( ✎ Notes ) mic Transcript -o- │
|
||
│ │
|
||
│ on inscrit des notes de meeting ici ... │
|
||
│ ~~ ~~~~~~~ ~~~ ~~~~~ ~~ │
|
||
│ Press 'space' for AI or '/' for commands │
|
||
│ │
|
||
│ ↑ Upgrade for full access You're on the free trial of AI Meeting Notes. ✕ │
|
||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||
```
|
||
|
||
**Lecture du panneau**
|
||
|
||
- Même en-tête (titre généré), même rangée d'onglets ; c'est `( ✎ Notes )` qui est actif, *Summary* repassant en inactif à sa gauche.
|
||
- Corps = l'éditeur de notes, aligné à gauche : le texte de l'utilisateur tel quel (« *on inscrit des notes de meeting ici ...* »), avec des **soulignements ondulés rouges** (`~~`) sous la plupart des mots français — le correcteur orthographique de l'interface, réglé sur l'anglais, les signale ; c'est un détail réel de la capture, pas un élément du design à reproduire.
|
||
- Sous le texte, l'aide de l'éditeur en gris : « *Press 'space' for AI or '/' for commands* ».
|
||
- Aucune barre de diffusion dans cet onglet : elle appartient à l'onglet *Summary*.
|
||
|
||
### 3B.8 Maquette 6 — Résultat, onglet *Transcript* (capture 6)
|
||
|
||
```text
|
||
Meeting @Today 8:14 AM [commentaires]
|
||
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||
│ [▤] ▾ Brief or Incomplete Meeting Recording │
|
||
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||
│ ( ☰ Summary ) ✎ Notes ( mic Transcript ) -o- │
|
||
│ │
|
||
│ ◎ Bruno Charest's audio │
|
||
│ │
|
||
│ 0:00 │
|
||
│ │ --What I like first is... Let's turn the focus. I'm going to be happy, I'm just │
|
||
│ │ going to be like, no, no, he wasn't really angry. │
|
||
│ │
|
||
│ ↑ Upgrade for full access You're on the free trial of AI Meeting Notes. ✕ │
|
||
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||
```
|
||
|
||
**Lecture du panneau**
|
||
|
||
- Même en-tête et même rangée ; l'onglet actif est `( mic Transcript )`, dessiné en pastille comme les autres.
|
||
- Le corps est organisé **par source audio** : une ligne d'en-tête de piste en gris, « `◎ Bruno Charest's audio` », avant les segments de cette piste.
|
||
- Chaque segment : l'horodatage (`0:00`) en colonne à gauche, puis un **trait vertical** `│` qui longe le texte du segment, retourné à la ligne avec continuation alignée sur la première ligne de texte.
|
||
- Le premier segment commence par `--` : début en pleine phrase (§3A.7). C'est ce segment unique que le résumé de la maquette 4 cite avec le marqueur `¹`.
|
||
- Bandeau d'essai inchangé, en dernière rangée.
|
||
|
||
### 3B.9 Ce qui bouge, ce qui ne bouge jamais — règles de disposition
|
||
|
||
| Élément | Règle tirée des maquettes |
|
||
|---|---|
|
||
| Titre de page ①, en-tête ② (position), filet, rangée d'onglets (position) | **Ne bougent jamais** : ni position, ni hauteur. Seul le texte du titre de bloc change, une fois, à la fin de l'analyse |
|
||
| Contrôles d'état ④ | Toujours **à droite de la rangée d'onglets**, toujours au même emplacement : *Start* → *Pause + Stop* → *Thinking* → rien. L'utilisateur retrouve le contrôle là où il a laissé le précédent |
|
||
| Onglets ③ | Apparaissent **par la droite de la rangée** (*Transcript* après *Notes*), sauf *Summary* qui naît **en tête** et devient actif ; l'ordre final est fixe : *Summary · Notes · Transcript* |
|
||
| Corps ⑤ | Un seul contenu à la fois, déterminé par (état × onglet actif) : promesse grisée, étapes, résumé, éditeur de notes ou segments — jamais deux contenus empilés, sauf la barre de diffusion ⑥ au-dessus du résumé |
|
||
| Pied de bloc | Un seul rôle à la fois : réglages + consentement ⑦ à l'état initial, bandeau ⑧ ensuite. Les deux ne coexistent pas dans les captures |
|
||
| Hauteur du panneau | Variable selon le corps (le panneau *Summary* est le plus haut) ; la largeur et les alignements gauche/droite sont constants |
|
||
| Alignements | Tout le contenu du corps est aligné sur la même marge gauche que les onglets ; tout ce qui est « action globale » (contrôles d'état, fermeture du bandeau, actions de diffusion) est aligné à droite |
|
||
|
||
**Conséquence d'implémentation pour Flowdeck.** Le panneau se construit comme une coquille fixe (`meeting-block-shell`, §6.5) avec quatre emplacements — en-tête, rangée (onglets + contrôles), corps, pied — et des composants interchangeables par emplacement selon l'état. Aucun état ne doit introduire un nouvel emplacement : si un nouvel élément n'entre dans aucun des quatre, c'est le design qu'il faut questionner, pas la coquille qu'il faut casser.
|
||
|
||
---
|
||
|
||
## 4. Principes directeurs pour Flowdeck
|
||
|
||
1. **Le document est le produit, pas l'enregistrement.** L'audio est un moyen éphémère ; la note structurée est l'actif.
|
||
2. **Une réunion = une note.** Unicité garantie par contrainte en base, pas par convention (§9.2).
|
||
3. **Privé par défaut, partage explicite.** Le partage automatique est une préférence opt-in, jamais un défaut.
|
||
4. **Consentement avant capture, toujours.** Aucun chemin technique ne doit permettre de transcrire sans acte de consentement journalisé.
|
||
5. **Tout résumé est vérifiable.** Chaque bloc généré référence les segments du transcript qui le justifient.
|
||
6. **Les notes humaines et l'IA cohabitent sans s'écraser.** L'IA écrit dans ses propres blocs, versionnés ; elle ne réécrit jamais le texte d'un humain.
|
||
7. **Fournisseurs remplaçables.** STT, diarisation et LLM sont derrière des interfaces ; aucun format propriétaire ne fuit dans le modèle de données.
|
||
8. **Conçu pour l'échec.** Capture interrompue, réseau coupé, fournisseur IA en panne : la réunion et ses données partielles restent récupérables.
|
||
9. **Idempotence partout.** Webhooks calendrier, jobs de traitement et diffusions sont rejouables sans doublon.
|
||
10. **Monolithe modulaire d'abord.** Un déployable, des modules découplés par événements ; extraction de services seulement quand une charge le justifie.
|
||
|
||
## 5. Vue d'ensemble du système (C4)
|
||
|
||
### 5.1 Contexte (niveau 1)
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
orga["Organisateur / participant"] -->|prépare, capture, relit| fd["Flowdeck — Meetings"]
|
||
inv["Participant externe"] -->|consentement, récapitulatif| fd
|
||
admin["Admin de workspace"] -->|politiques, rétention, audit| fd
|
||
fd -->|OAuth, événements, webhooks| cal["Calendriers<br/>Google / Microsoft 365"]
|
||
fd -->|lien de réunion, rejoindre| visio["Visioconférence<br/>Meet / Zoom / Teams"]
|
||
fd -->|flux audio, segments| stt["Fournisseur STT<br/>transcription + diarisation"]
|
||
fd -->|transcript, instructions| llm["Fournisseur LLM<br/>résumé, décisions, actions"]
|
||
fd -->|récapitulatifs, alertes| notif["Courriel / Slack"]
|
||
fd -->|indexation| search["Moteur de recherche"]
|
||
```
|
||
|
||
### 5.2 Conteneurs (niveau 2)
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph Client["Client Web Flowdeck"]
|
||
hub["Hub Meetings (SPA)"]
|
||
editor["Éditeur de note collaboratif (CRDT)"]
|
||
capture["Moteur de capture audio"]
|
||
live["Vue transcript en direct"]
|
||
end
|
||
subgraph Edge["Accès"]
|
||
gw["API Gateway / BFF"]
|
||
ws["Passerelle temps réel (WebSocket)"]
|
||
end
|
||
subgraph Core["Back-end — monolithe modulaire"]
|
||
iam["Identité & workspaces"]
|
||
calmod["Calendrier & sync"]
|
||
meet["Meetings & documents"]
|
||
share["Partage & ACL"]
|
||
ai["Orchestration IA"]
|
||
tasks["Actions & tâches"]
|
||
notifmod["Notifications"]
|
||
gov["Gouvernance : consentement, rétention, audit"]
|
||
end
|
||
subgraph Async["Traitement asynchrone"]
|
||
queue["File de jobs + outbox"]
|
||
workers["Workers : ingest, STT, résumé, index, diffusion"]
|
||
end
|
||
subgraph Data["Données"]
|
||
pg[("PostgreSQL")]
|
||
obj[("Stockage objet — audio temporaire / imports")]
|
||
idx[("Index de recherche + vecteurs")]
|
||
cache[("Redis — présence, sessions, verrous")]
|
||
end
|
||
hub --> gw
|
||
editor --> gw
|
||
editor <--> ws
|
||
live <--> ws
|
||
capture -->|chunks audio signés| obj
|
||
capture <-->|contrôle de session| ws
|
||
gw --> Core
|
||
ws --> Core
|
||
Core --> pg
|
||
Core --> cache
|
||
Core --> queue --> workers
|
||
workers --> pg
|
||
workers --> obj
|
||
workers --> idx
|
||
workers -->|API externes| ext["STT / LLM / calendriers / Slack"]
|
||
```
|
||
|
||
### 5.3 Choix structurant : monolithe modulaire, extraction ciblée
|
||
|
||
| Composant | Dès le MVP | Raison |
|
||
|---|---|---|
|
||
| API + modules métier | Monolithe modulaire | Itération rapide, transactions simples (note + ACL + consentement) |
|
||
| Workers de traitement | **Processus séparés dès le jour 1** | Charges longues et bursty (STT, LLM), scalabilité indépendante |
|
||
| Passerelle temps réel | Service séparé | Connexions longues, présence, fan-out du transcript |
|
||
| Moteur de capture | Client uniquement | L'audio naît dans le navigateur ; aucun serveur ne peut le capter à sa place |
|
||
|
||
---
|
||
|
||
## 6. Architecture front-end web
|
||
|
||
### 6.1 Modules
|
||
|
||
| Module | Responsabilités |
|
||
|---|---|
|
||
| `meetings-hub` | Liste des réunions à venir / passées, filtres, recherche, état vide, CTA contextuels (Préparer, Rejoindre, Transcrire, Voir le résumé) |
|
||
| `meeting-editor` | Éditeur de blocs collaboratif : ordre du jour, notes libres, bloc transcript, bloc résumé, bloc actions |
|
||
| `capture-engine` | Acquisition audio, encodage, segmentation, envoi, reprise, indicateurs de niveau et de qualité |
|
||
| `consent-ui` | Modale de consentement, copie du message texte, lecture du message vocal (synthèse vocale), état des arrivants tardifs |
|
||
| `live-transcript` | Affichage incrémental des segments (partiels puis finaux), locuteurs, défilement, correction d'un locuteur |
|
||
| `meeting-player` | Relecture d'un import audio (si conservé), navigation par horodatage, clic sur une citation → segment |
|
||
| `sharing-ui` | Panneau de partage, partage auto, liens, participants externes |
|
||
| `settings-meetings` | Base / dossier par défaut, instructions de résumé, rétention personnelle, langue |
|
||
| `meeting-block-shell` | **(v1.1, §3A)** Coquille du bloc : en-tête (calendrier + titre), rangée d'onglets à révélation progressive, zone de contrôle d'état, pied (instructions, attestation, bandeau) ; implémente la machine à états du §6.5 |
|
||
| `waveform-visualizer` | **(v1.1, §3A.3)** Forme d'onde en direct par canal depuis l'`AudioWorklet` ; le silence du canal distant y est visible |
|
||
| `processing-tracker` | **(v1.1, §3A.4)** Étapes de traitement nommées (*Thinking*) : états par étape, reprise après rechargement, issue en cas d'échec |
|
||
| `summary-share-bar` | **(v1.1, §3A.5)** Barre « Share this summary » : copie de lien, courriel, Slack ; masquage par résumé |
|
||
| `entitlement-banner` | **(v1.1, §3A.3)** Bandeau d'essai / de quota dans le bloc, fermable, piloté par les entitlements du §7.10 |
|
||
|
||
### 6.2 Le problème central : capturer l'audio dans un navigateur
|
||
|
||
C'est **la** contrainte qui sépare une application web d'une application desktop, et elle explique la limite documentée de Notion sur navigateur.
|
||
|
||
| Source | API Web | Ce qu'elle donne | Limites |
|
||
|---|---|---|---|
|
||
| Microphone | `getUserMedia({audio})` | La voix de l'utilisateur + ce que le micro entend dans la pièce | En visio au casque : les autres participants sont inaudibles |
|
||
| Onglet / fenêtre / écran | `getDisplayMedia({video, audio})` | L'audio de l'onglet partagé (ex. onglet Google Meet) ou, selon le navigateur et l'OS, l'audio système | Chrome/Edge surtout ; l'utilisateur doit choisir la bonne source et cocher le partage audio ; Safari/Firefox : support partiel ou absent |
|
||
| Fichier | `<input type=file>` / glisser-déposer | Un enregistrement existant | Différé seulement |
|
||
|
||
**Design de capture recommandé pour Flowdeck (web) — 3 modes explicites :**
|
||
|
||
```text
|
||
Mode A « Présentiel / micro » getUserMedia
|
||
→ réunions en personne, appels sur haut-parleur. Défaut, toujours disponible.
|
||
|
||
Mode B « Appel dans un onglet » getDisplayMedia (audio d'onglet) + getUserMedia
|
||
→ deux canaux séparés : MOI (micro) et EUX (onglet).
|
||
→ bénéfice majeur : l'attribution « moi vs les autres » devient fiable,
|
||
comme le desktop de Notion en 1:1.
|
||
→ détection de capacité au runtime + repli guidé vers le mode A.
|
||
|
||
Mode C « Import » téléversement de fichier
|
||
→ aucun accès temps réel requis ; traitement 100 % asynchrone.
|
||
```
|
||
|
||
Règles d'implémentation du `capture-engine` :
|
||
|
||
- **Double canal quand c'est possible** (micro + onglet) : enregistrer les canaux séparément, ne jamais les mixer avant envoi — la séparation des canaux est la source de diarisation la moins chère et la plus fiable.
|
||
- Chaîne audio : `AudioContext` → `AudioWorkletNode` → resampling 16 kHz mono par canal → encodage Opus → **segments de 5 à 10 s** numérotés.
|
||
- Chaque segment reçoit un `segment_seq` monotone et un identifiant d'idempotence ; l'envoi se fait par URL signée vers le stockage objet, avec accusé de réception du serveur.
|
||
- **Tampon local** (`IndexedDB`) : les segments non acquittés survivent à un rechargement de page, une coupure réseau ou la fermeture accidentelle de l'onglet.
|
||
- Indicateurs en direct : niveau d'entrée par canal, silence prolongé (> 20 s sur le canal « eux » en mode B = probablement mauvais onglet partagé), canal muet, permission refusée.
|
||
- Arrêt propre : vider le tampon, fermer la session, déclencher le traitement ; arrêt brutal : la session passe en `interrupted` et propose la reprise à la prochaine visite.
|
||
- Ne jamais demander `video: true` pour l'audio seul sans expliquer pourquoi : la demande d'écran fait peur et fait chuter l'acceptation. Quand `getDisplayMedia` l'exige, afficher un écran d'explication préalable.
|
||
|
||
### 6.3 Éditeur collaboratif
|
||
|
||
- Modèle en **blocs** (comme la page Notion) : `heading`, `paragraph`, `agenda_item`, `note`, `transcript_ref`, `summary`, `decision_list`, `action_list`, `divider`…
|
||
- Synchronisation **CRDT** (par ex. Yjs) : édition simultanée de l'ordre du jour et des notes libres, présence et curseurs, fonctionnement hors ligne court.
|
||
- **Frontière stricte** : les blocs générés par l'IA vivent dans des zones identifiées (`generated_by = ai`, `summary_version_id`) ; l'humain peut les annoter, les épingler, les régénérer — mais une régénération crée une **nouvelle version**, elle n'écrase pas une version validée.
|
||
- Le transcript n'est **pas** un texte libre éditable caractère par caractère : c'est une suite de segments immuables ; seules les métadonnées (locuteur, étiquette) sont corrigeables, avec trace. Sinon, les citations du résumé deviennent invérifiables.
|
||
|
||
### 6.4 Accessibilité et i18n
|
||
|
||
- Tous les contrôles de session utilisables au clavier ; état d'enregistrement annoncé aux lecteurs d'écran (`aria-live` discret, pas de spam).
|
||
- Indicateur d'enregistrement **visible en permanence** pendant la capture (exigence éthique autant qu'UX).
|
||
- Langue de réunion détectée et affichée ; l'interface suit la langue de l'utilisateur, la transcription celle de la réunion.
|
||
|
||
### 6.5 Machine à états du bloc de réunion (v1.1 — d'après les captures du §3A)
|
||
|
||
Le bloc est **un seul composant à états**, pas une suite d'écrans. Toute la logique d'affichage découle de deux variables : l'état de la session et l'onglet actif.
|
||
|
||
| État du bloc | Onglets rendus | Contrôle d'état rendu | Corps par défaut |
|
||
|---|---|---|---|
|
||
| `idle` | Notes | *Start transcribing* (à menu) + sélecteur d'instructions + attestation de consentement | Promesse de résumé / notes |
|
||
| `recording` | Notes, Transcript | Forme d'onde + chronomètre **(ajout Flowdeck)** + *Pause* / *Stop* | Notes (éditable, transcription en arrière-plan) |
|
||
| `paused` | Notes, Transcript | Forme d'onde figée + *Reprendre* / *Stop* ; badge « en pause » | Notes |
|
||
| `processing` | Summary, Notes, Transcript | Pastille *Thinking* + `processing-tracker` | Étapes nommées, cochées au fil de l'eau |
|
||
| `done` | Summary, Notes, Transcript | — (réglages seulement) + barre de diffusion si résumé présent | Summary |
|
||
| `failed` | Summary, Notes, Transcript | Bouton *Réessayer le traitement* (les segments sont conservés) | Transcript + erreur expliquée |
|
||
|
||
Règles :
|
||
|
||
- Les transitions passent **toujours** par le serveur (état de session en base) : un rechargement de page en plein *Thinking* ou en pleine pause restaure l'état exact, jamais un bloc vierge.
|
||
- L'onglet actif par défaut change avec l'état (`processing`/`done` → *Summary*), mais un choix manuel de l'utilisateur n'est jamais écrasé par une transition ultérieure.
|
||
- Le titre du bloc peut être remplacé par le titre généré (§12.8) à l'entrée dans `done` ; le titre de la page hôte n'est **jamais** modifié par l'IA.
|
||
- Le pied de bloc (instructions, attestation) n'est rendu qu'en `idle` ; le bandeau d'entitlement peut apparaître dès `recording` et persiste jusqu'à fermeture explicite.
|
||
|
||
---
|
||
|
||
## 7. Architecture back-end
|
||
|
||
### 7.1 Modules et responsabilités
|
||
|
||
| Module | Responsabilités | Données maîtresses |
|
||
|---|---|---|
|
||
| `identity-workspaces` | Comptes, workspaces, membres, rôles, SSO (plus tard) | users, workspaces, memberships |
|
||
| `calendar-sync` | Connexions OAuth, sync initiale et incrémentale, webhooks, normalisation des événements et des récurrences | calendar_connections, calendar_events |
|
||
| `meetings` | Cycle de vie d'une réunion et de sa note, modèles, instructions de résumé | meetings, meeting_documents, templates |
|
||
| `recording` | Sessions de capture, segments audio, imports, reprise | recording_sessions, media_assets, audio_chunks |
|
||
| `ai-orchestration` | Appels STT/LLM, files d'attente, reprises, versions de résumé, évaluations | processing_jobs, summaries |
|
||
| `sharing-acl` | Permissions sur les notes, partage auto, invités externes | grants, sharing_policies |
|
||
| `actions-tasks` | Extraction → validation → conversion en tâches Flowdeck | action_items, tasks |
|
||
| `notifications` | Rappels pré-réunion, récapitulatifs, diffusions Slack/courriel | notification_deliveries |
|
||
| `search-qa` | Indexation texte + vecteurs, questions-réponses sourcées | index externe |
|
||
| `governance` | Consentements, rétention, suppressions, audit, entitlements et compteurs d'usage | consent_records, audit_logs, usage_counters |
|
||
|
||
### 7.2 Règles de dépendance
|
||
|
||
- Les modules communiquent en **synchrone** uniquement pour les lectures/écritures transactionnelles locales ; tout le reste passe par des **événements** (outbox transactionnelle → file).
|
||
- `ai-orchestration` ne connaît pas les ACL : il reçoit un `meeting_id` et un jeton de périmètre, et `meetings` revérifie les droits avant d'exposer un résultat.
|
||
- `sharing-acl` est consulté à **chaque** lecture de note, de transcript et de segment. Aucun cache d'ACL supérieur à quelques secondes sur les contenus de réunion.
|
||
|
||
### 7.3 Événements de domaine principaux
|
||
|
||
```text
|
||
calendar.event.upserted calendar.event.deleted
|
||
meeting.created meeting.linked_to_event
|
||
meeting.started meeting.ended
|
||
recording.started recording.chunk_received
|
||
recording.stopped recording.failed
|
||
transcript.segment.finalized transcript.completed
|
||
summary.generated summary.validated
|
||
action_items.extracted action_item.converted_to_task
|
||
meeting.shared consent.recorded
|
||
retention.due meeting.purged
|
||
```
|
||
|
||
### 7.4 Traitement asynchrone
|
||
|
||
- **Outbox transactionnelle** : l'événement est écrit dans la même transaction que la donnée métier — aucun événement perdu, aucun « fantôme ».
|
||
- **Jobs idempotents** : clé = `(type, meeting_id, input_hash)` ; un même transcript ne génère pas deux résumés facturés.
|
||
- **Files séparées par nature** : `stt-stream` (temps réel, prioritaire), `stt-batch` (imports), `llm-summary`, `indexing`, `delivery`. Un import massif ne doit jamais retarder un résumé de réunion en direct.
|
||
- **Dead-letter queue** + rejouabilité depuis la console d'exploitation, avec l'historique des tentatives.
|
||
|
||
### 7.5 Stockage
|
||
|
||
| Donnée | Support | Notes |
|
||
|---|---|---|
|
||
| Métier relationnel | PostgreSQL | Source de vérité ; JSONB seulement pour les payloads fournisseurs bruts |
|
||
| Contenu de document (blocs) | PostgreSQL (JSONB versionné) + snapshots CRDT | Snapshots périodiques + journal d'opérations |
|
||
| Audio temporaire | Stockage objet, préfixe par workspace | Chiffré, URL signées courtes, **suppression programmée dès la création** (lifecycle) |
|
||
| Imports audio | Stockage objet | Conservés jusqu'à suppression explicite (politique différente du direct) |
|
||
| Recherche | Moteur d'index (ex. OpenSearch) + vecteurs | Index filtré par ACL au moment de la requête, jamais après |
|
||
| Présence / verrous / sessions | Redis | Données volatiles uniquement |
|
||
|
||
### 7.6 Multi-fournisseurs IA
|
||
|
||
Interfaces internes minimales :
|
||
|
||
```text
|
||
SpeechToTextProvider
|
||
stream(session, channel) -> flux de segments partiels/finaux
|
||
transcribeBatch(asset, options) -> segments + locuteurs + mots horodatés
|
||
capabilities() -> langues, diarisation, horodatage par mot, streaming
|
||
|
||
Summarizer
|
||
summarize(transcript, notes_humaines, instructions, schéma) -> JSON structuré + citations
|
||
```
|
||
|
||
Le choix du fournisseur se fait par **politique** (workspace, langue, coût, région de traitement), jamais en dur dans le code métier.
|
||
|
||
### 7.7 à 7.10 — Points d'attention
|
||
|
||
- **7.7 Fuseaux horaires** : stocker les instants en UTC + le fuseau d'origine de l'événement ; les récurrences se calculent dans le fuseau de l'événement, jamais dans celui du serveur.
|
||
- **7.8 Récurrences calendrier** : un événement récurrent = une série + des occurrences ; chaque occurrence tenue donne lieu à **sa** réunion et **sa** note. Les exceptions (occurrence déplacée/annulée) sont des occurrences à part entière.
|
||
- **7.9 Limites et quotas** : durée max par session, taille max d'import, minutes de transcription par plan — vérifiés **avant** le démarrage et suivis en direct, avec dégradation propre (arrêt annoncé, jamais de coupure silencieuse).
|
||
- **7.10 Entitlements** : la fonction complète est typiquement un marqueur de plan supérieur (chez Notion, elle est réservée aux plans Business/Enterprise). Modéliser dès le MVP : `feature.meeting_ai` (booléen de plan) + compteur `minutes_transcribed` par période.
|
||
|
||
---
|
||
|
||
## 8. Flux et séquences clés
|
||
|
||
### 8.1 Création d'une note depuis le calendrier
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as Utilisateur
|
||
participant H as Hub Meetings
|
||
participant C as calendar-sync
|
||
participant M as meetings
|
||
participant S as sharing-acl
|
||
U->>H: Ouvrir « Réunions à venir »
|
||
H->>C: Lister les événements (fenêtre -1 j / +14 j)
|
||
C-->>H: Événements normalisés + note liée ?
|
||
U->>H: « Créer la note » sur un événement
|
||
H->>M: createMeetingFromEvent(event_occurrence_id)
|
||
M->>M: Vérifier l'unicité (event_occurrence_id)
|
||
M->>M: Appliquer le modèle selon le type de réunion
|
||
M->>S: Créer l'ACL (privée par défaut)
|
||
alt Partage auto activé par l'utilisateur
|
||
M->>S: Ajouter les participants internes (lecture/édition)
|
||
end
|
||
M-->>H: meeting_id + document
|
||
U->>H: Rédiger l'ordre du jour (CRDT)
|
||
```
|
||
|
||
### 8.2 Démarrage d'une transcription
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as Utilisateur
|
||
participant W as Client Web
|
||
participant R as recording
|
||
participant G as governance
|
||
participant STT as Fournisseur STT
|
||
U->>W: « Rejoindre et transcrire » (T-15 min et après)
|
||
W->>W: Choisir le mode de capture (A micro / B onglet+micro)
|
||
W->>U: Écran de consentement
|
||
U->>W: Confirmer le consentement obtenu
|
||
W->>G: recordConsent(meeting_id, méthode, message, horodatage)
|
||
G-->>W: consent_id
|
||
W->>R: startSession(meeting_id, canaux, langue)
|
||
R-->>W: session_id + URLs signées d'envoi
|
||
loop Pendant la réunion
|
||
W->>R: Segment audio n (par canal)
|
||
R->>STT: Flux / segment
|
||
STT-->>W: Segments partiels puis finaux (via WebSocket)
|
||
U->>W: Notes libres (CRDT, en parallèle)
|
||
end
|
||
U->>W: « Arrêter »
|
||
W->>R: stopSession(session_id)
|
||
R->>R: Événement recording.stopped
|
||
```
|
||
|
||
### 8.3 Traitement post-réunion
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
stop["recording.stopped"] --> agg["1 · Lecture du transcript<br/>agréger et ordonner les segments finaux"]
|
||
agg --> diar["Diarisation / fusion des canaux<br/>moi vs autres, puis locuteurs"]
|
||
diar --> norm["Normalisation du transcript<br/>ponctuation, horodatages, marques de troncature"]
|
||
norm --> ana["2 · Analyse du transcript"]
|
||
ana --> ref["3 · Résolution des références<br/>comment désigner chaque personne (§12.7)"]
|
||
ref --> und["4 · Compréhension du contenu<br/>sujets, enchaînement, décisions vs digressions (§12.7)"]
|
||
und --> cls["Classification de complétude<br/>complete / brief / incomplete / fragmentary (§12.8)"]
|
||
cls --> sum["Génération du résumé (LLM)<br/>transcript + notes humaines + instructions photographiées"]
|
||
sum --> title["Génération du titre du bloc<br/>(jamais du titre de page) (§12.8)"]
|
||
title --> val{"Validation du schéma<br/>et des citations ?"}
|
||
sum --> val{"Validation du schéma<br/>et des citations ?"}
|
||
val -->|non, 1 retry| sum
|
||
val -->|échec| fallback["Résumé dégradé : points clés<br/>sans actions + drapeau qualité"]
|
||
val -->|oui| persist["Persister résumé v1 + décisions + actions (brouillon)"]
|
||
fallback --> persist
|
||
persist --> idx["Indexation recherche / vecteurs"]
|
||
persist --> recap["Barre « Share this summary » dans le bloc<br/>+ récapitulatif courriel / Slack (§3A.5)"]
|
||
persist --> ui["Notification à l'organisateur : « Relire et partager »"]
|
||
```
|
||
|
||
*Note v1.1 — étapes exposées.* Les étapes 1 à 4 du diagramme ci-dessus sont exactement celles que l'utilisateur voit se cocher dans l'onglet *Summary* (capture 3, §3A.4). Chaque transition d'étape écrit une ligne dans `processing_steps` et émet l'événement `processing.step` (§10.3) : l'interface n'affiche jamais une progression inventée côté client.
|
||
|
||
### 8.4 Import d'un fichier audio
|
||
|
||
```text
|
||
Téléversement (multipart reprisables) → contrôle type/taille → media_asset(stored)
|
||
→ job stt-batch → transcript → même chaîne qu'au §8.3 à partir de « Agréger »
|
||
→ l'utilisateur est notifié ; l'actif reste conservé jusqu'à suppression explicite.
|
||
```
|
||
|
||
### 8.5 Rappel et détection de début de réunion
|
||
|
||
- Job planifié : à T-15 min et à T-0, si l'événement a une note liée (ou si l'utilisateur a activé la création automatique), envoyer une notification actionnable « Rejoindre et transcrire ».
|
||
- Ne **jamais** démarrer une capture automatiquement sans action explicite de l'utilisateur : le consentement l'interdit par design.
|
||
- Si deux participants internes démarrent une transcription pour la même réunion : une seule session maîtresse par réunion ; le second est invité à rejoindre la note existante (règle d'unicité, §9.2). Les captures concurrentes sont un vrai cas, pas un détail.
|
||
|
||
---
|
||
|
||
## 9. Modèle de données
|
||
|
||
### 9.1 Diagramme entités-relations (vue simplifiée)
|
||
|
||
```mermaid
|
||
erDiagram
|
||
WORKSPACE ||--o{ MEMBERSHIP : contient
|
||
USER ||--o{ MEMBERSHIP : appartient
|
||
WORKSPACE ||--o{ CALENDAR_CONNECTION : possède
|
||
CALENDAR_CONNECTION ||--o{ CALENDAR_EVENT : synchronise
|
||
CALENDAR_EVENT ||--o{ MEETING : "donne lieu à (par occurrence)"
|
||
MEETING ||--|| MEETING_DOCUMENT : a
|
||
MEETING ||--o{ MEETING_PARTICIPANT : implique
|
||
MEETING ||--o{ RECORDING_SESSION : capturée_par
|
||
RECORDING_SESSION ||--o{ AUDIO_CHUNK : composée_de
|
||
RECORDING_SESSION ||--o| MEDIA_ASSET : produit
|
||
MEETING ||--o{ TRANSCRIPT_SEGMENT : transcrite_en
|
||
TRANSCRIPT_SEGMENT }o--|| SPEAKER : attribué_à
|
||
MEETING ||--o{ SUMMARY_VERSION : résumée_par
|
||
SUMMARY_VERSION ||--o{ DECISION : contient
|
||
SUMMARY_VERSION ||--o{ ACTION_ITEM : contient
|
||
ACTION_ITEM }o--o| TASK : convertie_en
|
||
MEETING ||--o{ CONSENT_RECORD : journalisée_par
|
||
MEETING ||--o{ GRANT : partagée_via
|
||
MEETING }o--o| SUMMARY_INSTRUCTION : utilise
|
||
```
|
||
|
||
### 9.2 Règle d'unicité fondatrice
|
||
|
||
```sql
|
||
-- Une occurrence d'événement calendrier = au plus UNE réunion / note.
|
||
CREATE UNIQUE INDEX meetings_one_per_occurrence
|
||
ON meetings (calendar_event_occurrence_id)
|
||
WHERE calendar_event_occurrence_id IS NOT NULL;
|
||
```
|
||
|
||
Toutes les surfaces (hub, calendrier, page, notification) résolvent la réunion par cette clé avant d'en créer une. C'est l'application directe de la leçon n° 1 du §3.1.
|
||
|
||
### 9.3 Tables principales (extraits normatifs)
|
||
|
||
```sql
|
||
CREATE TABLE meetings (
|
||
id UUID PRIMARY KEY,
|
||
workspace_id UUID NOT NULL REFERENCES workspaces(id),
|
||
title TEXT NOT NULL,
|
||
status TEXT NOT NULL DEFAULT 'draft',
|
||
-- draft | prepared | live | processing | done | failed | cancelled
|
||
source TEXT NOT NULL, -- calendar | ad_hoc | import
|
||
calendar_event_occurrence_id TEXT, -- série + occurrence, stable côté fournisseur
|
||
starts_at TIMESTAMPTZ,
|
||
ends_at TIMESTAMPTZ,
|
||
timezone TEXT, -- fuseau d'origine de l'événement
|
||
meeting_type TEXT, -- standup | team | sales | one_to_one | custom...
|
||
conference_url TEXT,
|
||
organizer_id UUID REFERENCES users(id),
|
||
document_id UUID NOT NULL,
|
||
summary_instruction_id UUID,
|
||
retention_policy_id UUID,
|
||
created_by UUID NOT NULL,
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
|
||
CREATE TABLE recording_sessions (
|
||
id UUID PRIMARY KEY,
|
||
meeting_id UUID NOT NULL REFERENCES meetings(id),
|
||
mode TEXT NOT NULL, -- mic_only | tab_plus_mic | import
|
||
channels JSONB NOT NULL, -- [{kind: self|remote|room, label}]
|
||
language TEXT,
|
||
state TEXT NOT NULL, -- recording | paused | interrupted | stopped | processed | failed
|
||
consent_id UUID NOT NULL REFERENCES consent_records(id),
|
||
started_by UUID NOT NULL,
|
||
started_at TIMESTAMPTZ NOT NULL,
|
||
stopped_at TIMESTAMPTZ,
|
||
audio_retention TEXT NOT NULL DEFAULT 'ephemeral' -- ephemeral | stored
|
||
);
|
||
|
||
CREATE TABLE transcript_segments (
|
||
id UUID PRIMARY KEY,
|
||
meeting_id UUID NOT NULL REFERENCES meetings(id),
|
||
session_id UUID REFERENCES recording_sessions(id),
|
||
seq INTEGER NOT NULL, -- ordre global dans la réunion
|
||
start_ms INTEGER NOT NULL,
|
||
end_ms INTEGER NOT NULL,
|
||
channel TEXT NOT NULL, -- self | remote | room
|
||
speaker_id UUID REFERENCES speakers(id),
|
||
text TEXT NOT NULL,
|
||
is_final BOOLEAN NOT NULL DEFAULT true,
|
||
confidence REAL,
|
||
provider_raw JSONB, -- payload fournisseur, pour débogage/audit
|
||
UNIQUE (meeting_id, session_id, seq)
|
||
);
|
||
|
||
CREATE TABLE summary_versions (
|
||
id UUID PRIMARY KEY,
|
||
meeting_id UUID NOT NULL REFERENCES meetings(id),
|
||
version INTEGER NOT NULL,
|
||
instruction_id UUID,
|
||
model_ref TEXT NOT NULL, -- fournisseur + modèle, sans secret
|
||
input_hash TEXT NOT NULL, -- transcript + notes + instructions
|
||
content JSONB NOT NULL, -- voir schéma au §12.4
|
||
status TEXT NOT NULL DEFAULT 'draft', -- draft | validated | superseded
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
UNIQUE (meeting_id, version)
|
||
);
|
||
|
||
CREATE TABLE action_items (
|
||
id UUID PRIMARY KEY,
|
||
meeting_id UUID NOT NULL REFERENCES meetings(id),
|
||
summary_version_id UUID REFERENCES summary_versions(id),
|
||
title TEXT NOT NULL,
|
||
owner_user_id UUID REFERENCES users(id), -- NULL si non résolu : à valider par un humain
|
||
owner_label TEXT, -- nom tel que prononcé, si non résolu
|
||
due_at TIMESTAMPTZ,
|
||
status TEXT NOT NULL DEFAULT 'proposed', -- proposed | accepted | converted | dismissed
|
||
evidence_segment_ids UUID[] NOT NULL DEFAULT '{}',
|
||
task_id UUID -- tâche Flowdeck créée, si convertie
|
||
);
|
||
|
||
CREATE TABLE consent_records (
|
||
id UUID PRIMARY KEY,
|
||
meeting_id UUID NOT NULL REFERENCES meetings(id),
|
||
method TEXT NOT NULL, -- verbal | chat_text | audio_message | meet_addon | workspace_enforced | start_attestation (v1.1 : mention en pied de bloc, clic sur Start, §3A.2)
|
||
message_ref TEXT, -- version du message utilisé
|
||
attested_by UUID NOT NULL,
|
||
attested_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
participants_snapshot JSONB NOT NULL -- qui était présent au moment de l'attestation
|
||
-- Table en ajout seul (append-only) : aucune mise à jour, aucune suppression métier.
|
||
);
|
||
```
|
||
|
||
### 9.3bis Ajouts v1.1 — issus des captures du §3A
|
||
|
||
```sql
|
||
-- Titre et diagnostic portés par le bloc / la réunion (capture 4 : retitrage).
|
||
-- Le titre de la page hôte n'est pas dans ce modèle : il appartient au document hôte.
|
||
ALTER TABLE meetings
|
||
ADD COLUMN generated_title TEXT, -- titre produit par l'IA, modifiable par l'humain
|
||
ADD COLUMN title_source TEXT NOT NULL DEFAULT 'user', -- user | ai | template | calendar
|
||
ADD COLUMN completeness_class TEXT; -- complete | brief | incomplete | fragmentary
|
||
|
||
-- Valeur des instructions figée au démarrage (capture 1 : « Instructions: Auto » en pied de bloc).
|
||
ALTER TABLE recording_sessions
|
||
ADD COLUMN instruction_snapshot JSONB, -- instruction_id résolu + contenu, au moment du Start
|
||
ADD COLUMN paused_at TIMESTAMPTZ,
|
||
ADD COLUMN total_paused_ms INTEGER NOT NULL DEFAULT 0;
|
||
|
||
-- Marques de troncature (capture 6 : segment commençant par « -- », en pleine phrase).
|
||
ALTER TABLE transcript_segments
|
||
ADD COLUMN starts_mid_utterance BOOLEAN NOT NULL DEFAULT false,
|
||
ADD COLUMN ends_mid_utterance BOOLEAN NOT NULL DEFAULT false,
|
||
ADD COLUMN source_label TEXT; -- ex. « Bruno Charest's audio » : piste propriétaire
|
||
|
||
-- Étapes de traitement exposées à l'utilisateur (capture 3 : liste Thinking cochée).
|
||
CREATE TABLE processing_steps (
|
||
id UUID PRIMARY KEY,
|
||
meeting_id UUID NOT NULL REFERENCES meetings(id),
|
||
job_id UUID NOT NULL REFERENCES processing_jobs(id),
|
||
step_key TEXT NOT NULL, -- reading_transcript | analyzing_transcript |
|
||
-- resolving_references | understanding_content |
|
||
-- classifying_completeness | generating_summary |
|
||
-- generating_title | validating_citations | indexing
|
||
label TEXT NOT NULL, -- libellé humain affiché, dans la langue de l'interface
|
||
state TEXT NOT NULL, -- pending | running | done | failed | skipped
|
||
started_at TIMESTAMPTZ,
|
||
finished_at TIMESTAMPTZ,
|
||
detail JSONB,
|
||
UNIQUE (job_id, step_key)
|
||
);
|
||
|
||
-- Diffusions du résumé depuis la barre « Share this summary » (capture 4).
|
||
CREATE TABLE summary_distributions (
|
||
id UUID PRIMARY KEY,
|
||
summary_version_id UUID NOT NULL REFERENCES summary_versions(id),
|
||
channel TEXT NOT NULL, -- copy_link | email | slack
|
||
actor_id UUID NOT NULL,
|
||
recipients JSONB, -- courriels / canal Slack, selon le canal
|
||
status TEXT NOT NULL, -- created | sent | failed | link_copied
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
```
|
||
|
||
La classe de complétude est aussi copiée sur `summary_versions` (colonne `completeness_class`) : une régénération peut produire une classe différente, et c'est celle de la version affichée qui pilote les avertissements.
|
||
|
||
### 9.4 Autres tables (résumé)
|
||
|
||
| Table | Contenu essentiel |
|
||
|---|---|
|
||
| `calendar_connections` | fournisseur, compte, jetons OAuth chiffrés, scopes, canal de webhook, curseur de sync, état |
|
||
| `calendar_events` | id externe, série/occurrence, titre, début/fin, participants, lien visio, `etag`/version, supprimé (tombstone) |
|
||
| `meeting_participants` | user_id ou courriel externe, rôle (organisateur/participant), présence détectée, locuteur associé |
|
||
| `speakers` | étiquette affichée, user_id résolu (nullable), canal d'origine, corrigé par (nullable) |
|
||
| `meeting_documents` | blocs JSONB, version, snapshot CRDT, auteur des dernières modifications |
|
||
| `media_assets` | type, taille, durée, clé objet, politique de conservation, date de purge |
|
||
| `audio_chunks` | session, seq, canal, clé objet, taille, acquitté (booléen), purge |
|
||
| `decisions` | texte, version de résumé, segments de preuve |
|
||
| `grants` | sujet (user/groupe/externe), niveau (view/comment/edit/admin), source (manuel/auto/héritage) |
|
||
| `summary_instructions` | propriétaire, portée (privée/partagée), contenu du modèle, défaut (booléen) |
|
||
| `processing_jobs` | type, clé d'idempotence, état, tentatives, erreur, payload |
|
||
| `audit_logs` | acteur, action, cible, contexte — append-only |
|
||
| `usage_counters` | workspace, période, minutes transcrites, coût estimé |
|
||
| `processing_steps` | **(v1.1)** étapes nommées du traitement, états et durées — source de l'affichage *Thinking* (§3A.4) |
|
||
| `summary_distributions` | **(v1.1)** diffusions depuis la barre de partage du résumé : canal, acteur, destinataires, statut |
|
||
|
||
### 9.5 Indexation et recherche
|
||
|
||
- Index plein texte sur : titres de réunions, blocs humains, résumés validés, segments de transcript.
|
||
- Index vectoriel sur les segments et les blocs de résumé pour la Q&R — **toujours** filtré par la liste des `meeting_id` accessibles à l'utilisateur, calculée avant la recherche sémantique.
|
||
- Les segments portent `workspace_id` dénormalisé pour rendre ce filtrage rapide et sûr.
|
||
|
||
---
|
||
|
||
## 10. API et événements temps réel
|
||
|
||
*Conventions : REST JSON pour le métier, WebSocket pour le direct. Tous les identifiants sont opaques. Chaque écriture accepte un en-tête `Idempotency-Key`.*
|
||
|
||
### 10.1 Endpoints principaux
|
||
|
||
```http
|
||
# Hub et réunions
|
||
GET /api/workspaces/{ws}/meetings?window=upcoming|past&query=&type=
|
||
POST /api/workspaces/{ws}/meetings {source, calendar_event_occurrence_id?, title?, template_id?}
|
||
GET /api/meetings/{id}
|
||
PATCH /api/meetings/{id} {title, meeting_type, summary_instruction_id}
|
||
POST /api/meetings/{id}/link-event {calendar_event_occurrence_id}
|
||
|
||
# Calendrier
|
||
POST /api/workspaces/{ws}/calendar-connections {provider} -> URL OAuth
|
||
GET /api/workspaces/{ws}/calendar-events?from=&to=
|
||
POST /webhooks/calendar/google (notification de changement)
|
||
POST /webhooks/calendar/microsoft (notification de changement)
|
||
|
||
# Capture et transcription
|
||
POST /api/meetings/{id}/consents {method, message_ref, participants_snapshot}
|
||
POST /api/meetings/{id}/recording-sessions {mode, channels, language, consent_id}
|
||
POST /api/recording-sessions/{id}/chunks/presign {seq, channel} -> URL signée
|
||
POST /api/recording-sessions/{id}/chunks/{seq}/ack
|
||
POST /api/recording-sessions/{id}/pause
|
||
POST /api/recording-sessions/{id}/stop
|
||
POST /api/recording-sessions/{id}/resume
|
||
POST /api/meetings/{id}/audio-imports (téléversement reprisables)
|
||
|
||
# Résultats IA
|
||
GET /api/meetings/{id}/transcript?from_ms=&to_ms=
|
||
PATCH /api/transcript-segments/{id}/speaker {speaker_id | label}
|
||
POST /api/meetings/{id}/summaries:generate {instruction_id}
|
||
GET /api/meetings/{id}/summaries
|
||
POST /api/summaries/{id}:validate
|
||
GET /api/meetings/{id}/processing-steps
|
||
POST /api/meetings/{id}/processing:retry
|
||
POST /api/summaries/{id}/distributions {channel: copy_link|email|slack, recipients?}
|
||
PATCH /api/meetings/{id}/generated-title {title} (correction humaine du titre généré)
|
||
GET /api/meetings/{id}/action-items
|
||
POST /api/action-items/{id}:convert-to-task
|
||
POST /api/action-items/{id}:dismiss
|
||
|
||
# Partage et gouvernance
|
||
GET /api/meetings/{id}/grants
|
||
POST /api/meetings/{id}/grants {subject, level}
|
||
PUT /api/workspaces/{ws}/meeting-policies {consent_enforced, transcript_retention_days, store_audio}
|
||
GET /api/workspaces/{ws}/audit-logs?target=meeting:{id}
|
||
|
||
# Recherche / Q&R
|
||
GET /api/workspaces/{ws}/search?q=&scope=meetings
|
||
POST /api/workspaces/{ws}/meeting-qa {question} -> réponse + citations
|
||
```
|
||
|
||
### 10.2 Exemple — création depuis un événement
|
||
|
||
```json
|
||
POST /api/workspaces/ws_123/meetings
|
||
Idempotency-Key: 8d2f...
|
||
|
||
{
|
||
"source": "calendar",
|
||
"calendar_event_occurrence_id": "google:evt_456:2026-10-15T14:00:00Z",
|
||
"template_id": "tpl_standup"
|
||
}
|
||
|
||
201 Created
|
||
{
|
||
"id": "mtg_789",
|
||
"title": "Standup produit",
|
||
"status": "prepared",
|
||
"starts_at": "2026-10-15T14:00:00Z",
|
||
"document_id": "doc_321",
|
||
"already_existed": false
|
||
}
|
||
```
|
||
|
||
Un second appel avec la même occurrence renvoie la même réunion avec `"already_existed": true` — jamais un doublon.
|
||
|
||
### 10.3 Événements WebSocket (par réunion)
|
||
|
||
```text
|
||
Client → Serveur
|
||
session.join {meeting_id}
|
||
capture.state {session_id, state} (heartbeat de capture)
|
||
transcript.subscribe{meeting_id}
|
||
|
||
Serveur → Client
|
||
presence.updated {users:[...]}
|
||
transcript.partial {segment_temp_id, speaker_hint, text, start_ms}
|
||
transcript.final {segment_id, seq, speaker_id, text, start_ms, end_ms}
|
||
recording.warning {kind: silence_remote | low_level | quota_80pct}
|
||
processing.status {stage: aggregating|diarizing|summarizing|indexing, pct}
|
||
processing.step {step_key, label, state, started_at, finished_at} (v1.1, §3A.4)
|
||
recording.paused {session_id, at}
|
||
recording.resumed {session_id, at}
|
||
summary.title_generated {meeting_id, generated_title, completeness_class} (v1.1, §12.8)
|
||
summary.ready {summary_version_id}
|
||
document.ops (relais CRDT)
|
||
```
|
||
|
||
---
|
||
|
||
## 11. Collaboration temps réel et transcription en direct
|
||
|
||
### 11.1 Deux temps réels différents — ne pas les confondre
|
||
|
||
| Flux | Nature | Technologie | Exigence |
|
||
|---|---|---|---|
|
||
| Document (agenda, notes) | État partagé convergent | CRDT + WebSocket | Convergence, hors-ligne court, présence |
|
||
| Transcript en direct | Flux append-only d'événements | WebSocket / SSE | Ordre, faible latence (< 2 s perçues), pas de convergence |
|
||
|
||
Mélanger les deux dans le même mécanisme est une erreur classique : le transcript n'a pas besoin de CRDT, et le document ne supporte pas un simple flux d'événements.
|
||
|
||
### 11.2 Segments partiels et finaux
|
||
|
||
- Le fournisseur STT émet des résultats **partiels** (révisables) puis **finaux** (figés).
|
||
- L'UI affiche les partiels en grisé avec un identifiant temporaire ; le remplacement par le final se fait par cet identifiant.
|
||
- Seuls les **finaux** sont persistés dans `transcript_segments` et utilisables comme preuves de citations.
|
||
- En cas de reconnexion, le client demande les finaux depuis le dernier `seq` connu (`?since_seq=`).
|
||
|
||
### 11.3 Qualité en direct
|
||
|
||
- Mesures par canal : niveau moyen, % de silence, clipping.
|
||
- Alertes actionnables, formulées pour un non-technicien : « Je n'entends que vous. Si la réunion est dans un autre onglet, vérifiez que son audio est bien partagé. »
|
||
- Un **score de qualité de session** est persisté : il conditionne un avertissement sur le résumé (« transcription de faible qualité, à relire »).
|
||
|
||
### 11.4 Présence et rôles pendant la capture
|
||
|
||
- Un seul **hôte de capture** par réunion (celui qui a démarré la session) ; les autres participants voient « Transcription en cours par X » et le transcript en direct s'ils y ont accès.
|
||
- L'hôte peut transférer ou arrêter ; si l'hôte quitte brutalement, la session passe en `interrupted` et un autre participant autorisé peut reprendre (nouvelle session, même réunion, `seq` qui continue).
|
||
|
||
---
|
||
|
||
## 12. Pipeline IA : transcription, diarisation, résumé
|
||
|
||
### 12.1 Chaîne complète
|
||
|
||
```text
|
||
Audio (canaux séparés)
|
||
→ VAD / segmentation
|
||
→ STT streaming (direct) ou batch (import)
|
||
→ segments finaux horodatés + mots + confiances
|
||
→ diarisation (qui parle quand) — facilitée par les canaux
|
||
→ résolution des locuteurs (canal « self » = hôte ; calendrier = noms probables)
|
||
→ transcript normalisé (source de vérité)
|
||
→ [v1.1] lecture du transcript final (étape exposée 1)
|
||
→ [v1.1] analyse du transcript (étape exposée 2)
|
||
→ [v1.1] résolution des références aux personnes (étape exposée 3, §12.7)
|
||
→ [v1.1] compréhension du contenu / segmentation thématique (étape exposée 4, §12.7)
|
||
→ [v1.1] classification de complétude (§12.8)
|
||
→ résumé structuré (LLM, schéma contraint, citations obligatoires)
|
||
→ extraction décisions / actions
|
||
→ [v1.1] génération du titre du bloc (§12.8)
|
||
→ validation automatique des citations + relecture humaine
|
||
```
|
||
|
||
### 12.2 STT : critères de choix du fournisseur
|
||
|
||
- Streaming **et** batch chez le même fournisseur (sinon, deux intégrations à maintenir).
|
||
- Horodatage par mot, scores de confiance, ponctuation automatique.
|
||
- Diarisation intégrée ou découplée.
|
||
- Langues requises par la clientèle de Flowdeck — **dont le français** — et détection automatique de langue.
|
||
- Région de traitement et engagements contractuels (non-conservation, non-entraînement).
|
||
- Coût par minute prévisible, mesuré par `usage_counters`.
|
||
|
||
### 12.3 Diarisation et identification : deux problèmes distincts
|
||
|
||
- **Diarisation** = découper en locuteurs anonymes (« Locuteur 1 », « Locuteur 2 »). Automatisable, imparfaite en groupe et à micro partagé.
|
||
- **Identification** = attacher un nom. Sources, par fiabilité décroissante :
|
||
1. le canal (le canal `self` est l'hôte ; le canal `remote` en 1:1 est l'autre participant de l'événement) ;
|
||
2. les participants de l'événement calendrier lié ;
|
||
3. la correction manuelle dans l'UI (toujours possible, toujours tracée).
|
||
- Ne jamais présenter une identification incertaine comme un fait : afficher « Locuteur 2 (probablement Marie) » plutôt qu'un nom sec, tant qu'un humain n'a pas confirmé.
|
||
|
||
### 12.4 Résumé : schéma de sortie contraint
|
||
|
||
Le LLM ne renvoie **pas** de texte libre. Il renvoie un JSON validé par schéma :
|
||
|
||
```json
|
||
{
|
||
"title": "string",
|
||
"overview": "string (3-5 phrases)",
|
||
"key_points": [
|
||
{ "text": "string", "evidence_segment_ids": ["seg_..."] }
|
||
],
|
||
"decisions": [
|
||
{ "text": "string", "evidence_segment_ids": ["seg_..."] }
|
||
],
|
||
"action_items": [
|
||
{
|
||
"title": "string",
|
||
"owner_label": "string | null",
|
||
"due_hint": "string | null",
|
||
"evidence_segment_ids": ["seg_..."]
|
||
}
|
||
],
|
||
"open_questions": [
|
||
{ "text": "string", "evidence_segment_ids": ["seg_..."] }
|
||
],
|
||
"risks_or_blockers": [
|
||
{ "text": "string", "evidence_segment_ids": ["seg_..."] }
|
||
]
|
||
}
|
||
```
|
||
|
||
Règles de génération (à coder, pas seulement à écrire dans un prompt) :
|
||
|
||
1. **Citations obligatoires** : tout élément sans `evidence_segment_ids` non vide est rejeté ou marqué « non sourcé ».
|
||
2. **Entrées du résumé** = transcript final + notes libres de l'utilisateur + ordre du jour + instructions choisies. Les notes humaines priment en cas de contradiction apparente (elles peuvent contenir une décision prise hors micro) — le conflit est signalé, pas tranché silencieusement.
|
||
3. **Aucune invention de responsable ou d'échéance** : si ce n'est pas dit, le champ reste `null` et l'action arrive en statut `proposed` à compléter.
|
||
4. **Instructions par type** : `auto`, `standup`, `team`, `sales_call`, `one_to_one`, `interview`, + instructions personnalisées (documents versionnés, privés par défaut, partageables, définissables par défaut par utilisateur ou par workspace).
|
||
5. **Régénération = nouvelle version** (`summary_versions.version + 1`), l'ancienne passe en `superseded`, jamais supprimée tant qu'elle a été validée ou partagée.
|
||
6. **Échec de validation** : une nouvelle tentative avec retour d'erreur au modèle ; au-delà, résumé dégradé explicitement étiqueté.
|
||
|
||
### 12.5 Qualité et évaluation
|
||
|
||
- Jeu d'évaluation interne : 20–30 réunions de référence (audio + transcript + résumé attendu), rejoué à chaque changement de fournisseur, de modèle ou d'instructions.
|
||
- Métriques suivies : taux d'actions avec responsable correct, taux de citations valides, taux de corrections humaines du résumé, temps de génération p50/p95.
|
||
- Les corrections humaines (locuteur renommé, action rejetée, résumé édité) sont des **données d'évaluation**, pas seulement des interactions : les journaliser (sans contenu sensible au-delà du nécessaire) pour mesurer la dérive.
|
||
|
||
### 12.6 Coûts
|
||
|
||
- Postes : STT (par minute, dominant), LLM (par réunion, dépend de la longueur du transcript), stockage d'imports, indexation.
|
||
- Leviers : ne pas stocker l'audio du direct ; résumer à partir du transcript (pas de l'audio) ; tronquer intelligemment les très longues réunions (résumés par sections puis synthèse) ; cache par `input_hash` pour éviter les régénérations identiques facturées deux fois.
|
||
- Afficher le coût estimé par workspace dans l'administration : c'est un prérequis de tarification, pas un luxe.
|
||
|
||
### 12.7 Étapes de traitement exposées à l'utilisateur (v1.1 — capture 3)
|
||
|
||
Le traitement post-réunion n'est pas une boîte noire suivie d'un résultat : il publie des étapes nommées, dans l'ordre, chacune étant un vrai travail du pipeline.
|
||
|
||
| Étape (`step_key`) | Libellé observé chez Notion | Travail réel dans Flowdeck | Entrées → sorties |
|
||
|---|---|---|---|
|
||
| `reading_transcript` | *Reading transcript…* | Assembler les segments finaux de toutes les pistes, vérifier les trous de `seq`, figer le transcript de travail | segments → transcript figé + statistiques (mots, durée, pistes) |
|
||
| `analyzing_transcript` | *Analyzing the transcript* | Analyse linguistique et structurelle : tours de parole, questions, décisions candidates, actions candidates (pré-extraction déterministe + modèle) | transcript → annotations |
|
||
| `resolving_references` | *Thinking about how to refer to people* | **Résolution des références** : pour chaque locuteur et chaque personne mentionnée, décider de la désignation à employer dans le résumé (nom résolu, rôle, « un participant »), avec confiance ; appliquer les mêmes règles de prudence qu'au §12.3 ; traiter aussi les pronoms et les mentions de tiers absents (la session observée parle d'une personne qui « n'était pas vraiment en colère » sans la nommer : la bonne sortie est de ne pas l'inventer) | locuteurs + participants calendrier + mentions → table de désignations |
|
||
| `understanding_content` | *Understanding the content* | Compréhension / segmentation thématique : sujets, enchaînement, rapport avec l'ordre du jour et les notes humaines ; repère ce qui est hors sujet ou tronqué | transcript annoté → plan de résumé |
|
||
| `classifying_completeness` | (non affichée comme étape, visible dans le titre et le résumé) | Voir §12.8 | statistiques + plan → `completeness_class` |
|
||
| `generating_summary` | (suite de *Thinking*) | Génération du JSON contraint du §12.4 en utilisant la table de désignations — le LLM ne choisit pas lui-même comment nommer les gens | plan + désignations → résumé brouillon |
|
||
| `generating_title` | (visible dans l'en-tête du bloc) | Voir §12.8 | résumé + transcript → `generated_title` |
|
||
| `validating_citations` | (invisible) | Vérifier que chaque `evidence_segment_ids` existe, appartient à la réunion et soutient l'affirmation | résumé → résumé validé ou rejeté |
|
||
|
||
Exigences :
|
||
|
||
- Chaque étape écrit son état dans `processing_steps` **avant** d'émettre l'événement temps réel : l'affichage est une lecture de la base, rejouable après rechargement.
|
||
- Les libellés affichés sont des clés de traduction, pas les chaînes du fournisseur ni des journaux techniques.
|
||
- Une étape qui échoue passe en `failed` avec une explication affichable et un chemin de reprise (`processing:retry`) ; les étapes déjà `done` ne sont pas rejouées si leurs entrées n'ont pas changé (clés d'idempotence du §7.4).
|
||
|
||
### 12.8 Classification de complétude et titre généré (v1.1 — captures 4 et 6)
|
||
|
||
**Classification, pas blocage.** Une session courte ou tronquée produit un résultat dégradé et étiqueté, jamais une erreur ni un résumé qui fait semblant.
|
||
|
||
| Classe | Signaux (à calibrer) | Comportement du résumé |
|
||
|---|---|---|
|
||
| `complete` | Durée et volume suffisants, début et fin d'énoncés propres, sujet identifiable | Schéma complet du §12.4 |
|
||
| `brief` | Durée / mots sous les seuils, mais échange cohérent | *Overview* + actions si présentes ; mention « réunion brève » |
|
||
| `incomplete` | Début ou fin en pleine phrase (`starts/ends_mid_utterance`), un seul fragment, pas de sujet ni d'ordre du jour discernable | *Overview* limité à ce qui est sourçable, limites explicitées en puces, sections vides affichées comme telles |
|
||
| `fragmentary` | Plusieurs fragments disjoints, trous de segments | Idem `incomplete`, avec la liste des manques détectés |
|
||
|
||
- Les **limites font partie du résumé** : enregistrement fragmentaire, sujet absent, notes vides — chacune appuyée par ses segments de preuve, comme les autres affirmations.
|
||
- Une note humaine **vide** est un signal, pas une faute : elle est signalée parce qu'elle prive le résumé du contexte de l'ordre du jour (§12.4, règle 2).
|
||
|
||
**Titre généré.** Produit après le résumé, à partir du sujet dominant ; si la classe est `brief / incomplete / fragmentary` et qu'aucun sujet n'est discernable, le titre est un **diagnostic honnête** (chez Notion : « *Brief or Incomplete Meeting Recording* »), jamais un sujet inventé. Le titre généré s'écrit dans `meetings.generated_title`, s'affiche dans l'en-tête du bloc aux trois onglets, reste modifiable par l'humain (`title_source` passe alors à `user`), et une régénération du résumé peut proposer un nouveau titre sans écraser une correction humaine.
|
||
|
||
---
|
||
|
||
## 13. Intégrations calendrier et visioconférence
|
||
|
||
### 13.1 Calendriers
|
||
|
||
| Aspect | Google Calendar | Microsoft 365 |
|
||
|---|---|---|
|
||
| Auth | OAuth 2.0, scopes minimaux (lecture événements + écriture si création) | OAuth 2.0 / Microsoft Graph |
|
||
| Sync initiale | Liste par fenêtre (-30 j / +90 j recommandés) | Idem |
|
||
| Sync incrémentale | Jeton de synchronisation (`syncToken`) | Delta query |
|
||
| Changements temps réel | Canal de notification (`watch`) à renouveler avant expiration | Abonnement Graph à renouveler |
|
||
| Récurrences | Règles + instances + exceptions | Idem (formats différents → couche de normalisation) |
|
||
| Invités | Courriels + statut de réponse | Idem |
|
||
|
||
Principes :
|
||
|
||
- **Normaliser tôt** : tout événement externe devient un `calendar_event` Flowdeck avec occurrence stable ; le reste du système ne connaît pas les formats fournisseurs.
|
||
- **Réconciliation périodique** en plus des webhooks (les notifications se perdent) : balayage quotidien de la fenêtre active + renouvellement des canaux avant expiration.
|
||
- **Liaison note ↔ événement** dans les deux sens : depuis le calendrier on ouvre la note ; depuis la note on voit l'événement source et son lien visio.
|
||
- Désambiguïsation des comptes : un utilisateur peut connecter plusieurs comptes ; les réunions du hub précisent le compte source.
|
||
|
||
### 13.2 Visioconférence
|
||
|
||
- Flowdeck ne transporte pas l'appel : il **extrait le lien de conférence** de l'événement (Meet, Zoom, Teams, ou URL générique) et offre « Rejoindre » + « Rejoindre et transcrire ».
|
||
- Détection du type de lien par domaine, avec repli générique.
|
||
- Option Phase 3 : extension de navigateur pour Meet (avis de consentement épinglé dans le clavardage + indicateur), et/ou bot de réunion via un fournisseur spécialisé pour les organisations qui l'exigent — voir ADR-02 pour le compromis.
|
||
|
||
### 13.3 Fuseaux et récurrences — cas qui cassent tout
|
||
|
||
- Réunion récurrente dont **une** occurrence est déplacée : la note suit l'occurrence, pas la série.
|
||
- Participant dans un autre fuseau : toutes les heures affichées sont converties pour le lecteur, mais l'instant stocké ne change jamais.
|
||
- Événement supprimé côté calendrier après création de la note : la note **survit** (elle peut contenir un compte rendu), marquée « événement source supprimé ».
|
||
|
||
---
|
||
|
||
## 14. Sécurité, consentement et conformité
|
||
|
||
### 14.1 Consentement — exigence produit et légale
|
||
|
||
L'enregistrement de conversations est encadré différemment selon les juridictions : certaines exigent le consentement d'une seule partie, d'autres celui de **toutes** les parties, et les participants d'une même réunion peuvent relever de juridictions différentes. La règle de conception à retenir — qui est aussi celle que recommande Notion dans sa documentation — est la plus stricte :
|
||
|
||
> **Toujours obtenir le consentement de tous les participants, et en garder une trace.**
|
||
|
||
Mécanismes à implémenter dans Flowdeck :
|
||
|
||
| Mécanisme | Détail |
|
||
|---|---|
|
||
| Porte de démarrage | Aucune session sans `consent_record` préalable (§9.3) |
|
||
| Message texte | Modèle copiable en un clic, versionné (`message_ref`) |
|
||
| Message vocal | Lecture par synthèse vocale, langue de la réunion, avant démarrage |
|
||
| Avis dans l'appel | Extension Meet (Phase 3) : message épinglé + indicateur visible, y compris pour les arrivants tardifs |
|
||
| Arrivants tardifs | Détection d'un nouveau participant → l'hôte est invité à mettre en pause et à renouveler la demande |
|
||
| Imposition workspace | L'admin peut forcer le message automatique pour tous les membres |
|
||
| Refus | Un participant peut refuser : la transcription ne démarre pas (ou s'arrête), et ce choix est respecté sans friction |
|
||
|
||
*Ce document n'est pas un avis juridique. Avant la mise en production, faire valider les flux de consentement et de rétention par un conseil connaissant les marchés servis (au Canada : législation fédérale et provinciale, dont la Loi 25 au Québec ; en Europe : RGPD).*
|
||
|
||
### 14.2 Contrôle d'accès
|
||
|
||
- La note hérite d'une ACL propre (pas de celle de l'événement calendrier : les invités d'un événement ne deviennent pas automatiquement lecteurs du transcript).
|
||
- Partage auto limité aux participants **internes** (membres du workspace) ; les externes reçoivent un récapitulatif, pas un accès, sauf action explicite.
|
||
- Vérification d'ACL sur chaque ressource : réunion, document, segment, résumé, actif audio, export.
|
||
- Exports (Markdown, PDF, copie) journalisés dans l'audit.
|
||
|
||
### 14.3 Chiffrement et secrets
|
||
|
||
- TLS partout ; chiffrement au repos pour la base, le stockage objet et les sauvegardes.
|
||
- Jetons OAuth des calendriers et clés fournisseurs : coffre de secrets / chiffrement par enveloppe, jamais en clair en base applicative.
|
||
- URLs d'audio : signées, courte durée, liées à la session ; aucune URL publique permanente.
|
||
- Engagements fournisseurs IA : clauses de non-conservation et de non-entraînement à vérifier contractuellement avant intégration, et à refléter dans la politique de confidentialité de Flowdeck.
|
||
|
||
### 14.4 Rétention — politique par type de donnée
|
||
|
||
| Donnée | Défaut recommandé | Configurable |
|
||
|---|---|---|
|
||
| Audio de session en direct | **Non conservé** (tampon local + purge serveur < 24 h à 3 j en cas d'échec) | Stockage explicite par workspace (opt-in) |
|
||
| Audio importé | Conservé jusqu'à suppression par l'utilisateur | Purge automatique programmable |
|
||
| Transcript | Conservé avec la note | Suppression auto après N jours (le résumé survit), sauf retenue légale |
|
||
| Résumé + décisions + actions | Durée de vie de la note | Politique du workspace |
|
||
| Consentements + audit | Longue durée, append-only | Non réductible par un utilisateur standard |
|
||
|
||
### 14.5 Entreprise (Phase ultérieure)
|
||
|
||
SSO SAML/OIDC, provisionnement SCIM, journaux d'audit exportables (SIEM), retenues légales, résidence des données par région, désactivation complète de la fonction par workspace.
|
||
|
||
---
|
||
|
||
## 15. Exigences non fonctionnelles
|
||
|
||
| Exigence | Cible MVP | Cible mature |
|
||
|---|---|---|
|
||
| Latence transcript perçue | < 3 s | < 2 s |
|
||
| Délai résumé après arrêt | < 60 s (réunion d'1 h) | < 30 s |
|
||
| Création de note depuis le calendrier | < 500 ms | < 300 ms |
|
||
| Disponibilité API métier | 99,9 % | 99,95 % |
|
||
| Perte de données de capture | 0 segment acquitté perdu | Idem |
|
||
| Réunions simultanées par workspace | Selon plan, file d'attente explicite | Élasticité par file |
|
||
| Recherche sur les réunions | < 800 ms | < 400 ms |
|
||
|
||
**Ordres de grandeur de dimensionnement** (à recalculer avec les fournisseurs retenus) :
|
||
|
||
- 1 h d'audio Opus mono ≈ 30–60 Mo en transit tamponné — d'où l'intérêt de **ne pas le conserver** par défaut.
|
||
- 1 h de réunion ≈ 8 000–10 000 mots de transcript ≈ 12–15 k tokens : le coût LLM d'un résumé est modeste devant le coût STT par minute.
|
||
- Le poste de coût et de latence dominant est la **transcription**, pas le résumé : optimiser là en premier.
|
||
|
||
**Observabilité** : traces distribuées de bout en bout (`meeting_id` comme clé de corrélation), métriques par étape (chunks reçus/perdus, latence STT, taux d'échec de validation de résumé, coût par réunion), alertes sur les files et les dead-letters, tableau de bord « santé des réunions » par workspace.
|
||
|
||
---
|
||
|
||
## 16. Résilience et gestion des échecs
|
||
|
||
| Panne | Comportement attendu |
|
||
|---|---|
|
||
| Réseau coupé pendant la capture | Tampon local `IndexedDB`, reprise d'envoi automatique, indicateur « hors ligne — n segments en attente » |
|
||
| Onglet fermé / navigateur planté | Segments acquittés conservés ; session `interrupted` ; à la réouverture, proposition de reprendre ou de clore et générer un résumé partiel (étiqueté comme tel) |
|
||
| Fournisseur STT temps réel en échec | Bascule sur le traitement batch des segments déjà reçus (le régime « audio téléversé en secours ») ; l'utilisateur est informé, la réunion n'est pas perdue |
|
||
| LLM indisponible ou schéma invalide | File avec reprises exponentielles ; transcript et notes restent consultables ; résumé marqué « en attente » |
|
||
| Webhook calendrier perdu | Réconciliation périodique (§13.1) ; aucune note orpheline silencieuse |
|
||
| Double démarrage de capture | Verrou par réunion (§8.5) ; le second utilisateur rejoint la session existante |
|
||
| Quota atteint en cours de réunion | Avertissement à 80 %, arrêt annoncé et propre à 100 %, résumé généré sur ce qui existe |
|
||
| Suppression pendant un traitement | Les jobs vérifient l'existence et la politique de rétention avant chaque étape ; purge en cascade tracée |
|
||
| Session trop courte ou fragmentaire **(v1.1)** | Ce n'est **pas** une panne : classification `brief / incomplete / fragmentary` (§12.8), résumé dégradé sourcé, titre-diagnostic ; aucune section inventée pour « remplir » |
|
||
| Traitement bloqué sur une étape **(v1.1)** | L'étape passe en `failed` avec durée et explication ; `processing:retry` rejoue depuis la première étape non terminée ; la pastille *Thinking* ne reste jamais sans issue |
|
||
|
||
## 17. Déploiement et exploitation
|
||
|
||
- **Topologie** : client web statique (CDN) ; un déployable API ; un déployable temps réel ; workers par file ; PostgreSQL managé ; stockage objet ; Redis managé ; moteur de recherche managé ou service externe au MVP.
|
||
- **Environnements** : dev / staging / prod, avec un workspace de test « réunions synthétiques » (audios de référence) pour tester la chaîne IA sans données réelles.
|
||
- **Feature flags** par workspace : `meetings.hub`, `meetings.capture_tab` (mode B), `meetings.ai_summary`, `meetings.auto_share`, `meetings.import`.
|
||
- **Migrations** : migrations de schéma versionnées, rétro-compatibles sur deux déploiements (les sessions en cours ne doivent jamais casser sur un déploiement).
|
||
- **Déploiements en pleine réunion** : l'API de capture (presign/ack/stop) est la surface la plus critique ; la geler pendant les fenêtres de déploiement ou la rendre strictement additive.
|
||
- **Sauvegardes** : base et snapshots de documents ; les actifs audio temporaires sont **exclus** des sauvegardes longues (cohérence avec la politique de rétention affichée aux utilisateurs).
|
||
|
||
---
|
||
|
||
## 18. Plan d'implémentation par phases
|
||
|
||
*Durées indicatives pour une petite équipe (2–4 développeurs) déjà familière de la stack Flowdeck. Ce sont des ordres de grandeur de planification, pas des engagements.*
|
||
|
||
### Phase 0 — Fondations (1–2 semaines)
|
||
|
||
- Modèle de données §9 (sans IA) ; règle d'unicité ; ACL des notes.
|
||
- Connexion Google Calendar (OAuth, sync, webhooks + réconciliation).
|
||
- Hub Meetings (à venir / passé) en lecture seule.
|
||
- **Critère de sortie** : les réunions du calendrier s'affichent, une note vide se crée en un clic, sans doublon.
|
||
|
||
### Phase 1 — Document de réunion et préparation (2–3 semaines)
|
||
|
||
- Éditeur de blocs collaboratif (CRDT), ordre du jour, notes libres, modèles par type.
|
||
- Liaison note ↔ événement dans les deux sens ; partage manuel ; base/dossier de réunions par défaut.
|
||
- Rappels T-15 / T-0.
|
||
- **Critère de sortie** : une équipe peut préparer et partager ses réunions, sans aucune IA.
|
||
|
||
### Phase 2 — Capture Web et transcription (3–4 semaines)
|
||
|
||
- `capture-engine` mode A (micro) puis mode B (onglet + micro) ; tampon local ; reprise.
|
||
- Écran et journal de consentement ; politique d'imposition workspace.
|
||
- STT streaming, segments partiels/finaux, vue transcript en direct, correction des locuteurs.
|
||
- **(v1.1, §3A)** Machine à états du bloc et révélation progressive des onglets (§6.5), forme d'onde en direct, *Pause* / reprise comme états de session, attestation de consentement en pied de bloc, bandeau d'essai.
|
||
- Import audio (mode C) en batch.
|
||
- **Critère de sortie** : une réunion réelle d'une heure est transcrite en direct, récupérable après coupure réseau simulée ; une pause puis une reprise ne perdent aucun segment et restaurent l'état du bloc après rechargement.
|
||
|
||
### Phase 3 — Résumé IA et bouclage (2–3 semaines)
|
||
|
||
- Pipeline §12 : schéma contraint, citations, décisions, actions `proposed`.
|
||
- **(v1.1, §3A)** Étapes de traitement exposées et persistées (§12.7, dont la résolution des références), classification de complétude et titre généré (§12.8), barre « Share this summary ».
|
||
- Instructions par type + instructions personnalisées ; versions de résumé ; **photographie des instructions au démarrage** de la session.
|
||
- Validation des actions et conversion en tâches Flowdeck ; récapitulatifs courriel/Slack.
|
||
- Indexation recherche + Q&R sourcée.
|
||
- Compteurs d'usage, entitlements, rétentions et purges automatiques ; journal d'audit.
|
||
- **Critère de sortie** : de l'arrêt de la réunion au récapitulatif partagé, sans copier-coller, avec un taux de citations valides mesuré sur le jeu d'évaluation ; **et** le cas dégradé de référence du §3A (session de quelques secondes, notes vides) produit un résumé classé `incomplete`, un titre-diagnostic et aucun élément inventé.
|
||
|
||
### Phase 4 — Durcissement et extension (en continu)
|
||
|
||
- Extension navigateur (avis de consentement dans Meet, meilleure attribution des locuteurs).
|
||
- Microsoft 365 complet si pas déjà fait ; bot de réunion optionnel pour les clients qui l'exigent.
|
||
- SSO/SCIM, rétentions avancées, résidence des données.
|
||
- Companion desktop (capture d'audio système équivalente à l'expérience native) — **seulement** si la demande utilisateur le justifie : c'est un produit en soi.
|
||
|
||
### Backlog initial (epics)
|
||
|
||
```text
|
||
EPIC 1 Calendrier & hub EPIC 5 Transcription temps réel
|
||
EPIC 2 Document collaboratif EPIC 6 Résumé IA & actions
|
||
EPIC 3 Partage & ACL EPIC 7 Recherche & Q&R
|
||
EPIC 4 Capture & consentement EPIC 8 Gouvernance, rétention, coûts
|
||
```
|
||
|
||
---
|
||
|
||
## 19. Décisions d'architecture (ADR — résumé)
|
||
|
||
| # | Décision | Alternative écartée | Raison |
|
||
|---|---|---|---|
|
||
| ADR-01 | Monolithe modulaire + workers séparés | Microservices dès le départ | Vélocité MVP ; frontières encore instables |
|
||
| ADR-02 | Capture **sans bot** côté client d'abord | Bot qui rejoint chaque appel | Friction et méfiance moindres ; le bot reste une option d'entreprise (Phase 4) |
|
||
| ADR-03 | Deux canaux séparés (micro / onglet) non mixés | Mixage en un seul flux | Diarisation « moi vs autres » quasi gratuite ; mixage irréversible |
|
||
| ADR-04 | CRDT pour le document, flux d'événements pour le transcript | CRDT partout | Les deux problèmes sont de nature différente (§11.1) |
|
||
| ADR-05 | Audio du direct **non conservé** par défaut | Tout stocker « au cas où » | Risque juridique, coût, confiance — la conservation est un opt-in |
|
||
| ADR-06 | Résumé en JSON contraint avec citations obligatoires | Texte libre du LLM | Vérifiabilité, extraction d'actions fiable, testabilité |
|
||
| ADR-07 | Une note par occurrence d'événement (contrainte SQL) | Déduplication applicative | Les doublons réapparaissent toujours sans contrainte (§9.2) |
|
||
| ADR-08 | Fournisseurs STT/LLM derrière des interfaces | Intégration directe d'un fournisseur | Coût, langue, région et qualité évoluent vite ; éviter le verrouillage |
|
||
| ADR-09 | ACL propre à la note, distincte de l'événement | Hériter des invités du calendrier | Un invité d'événement n'est pas un lecteur de transcript légitime par défaut |
|
||
| ADR-10 | Consentement journalisé en append-only, bloquant | Case à cocher dans les réglages | Preuve, audit, et impossibilité technique de contourner |
|
||
| ADR-11 **(v1.1)** | Étapes de traitement **nommées et persistées**, affichées telles quelles (§12.7) | Barre de progression opaque ou spinner global | La confiance se construit pendant l'attente ; l'état survit au rechargement ; les échecs deviennent localisables par étape |
|
||
| ADR-12 **(v1.1)** | Contenu insuffisant = **classe de complétude**, pas une erreur ; titre-diagnostic admis | Refuser le résumé sous un seuil, ou générer un résumé d'apparence normale | La session observée (§3A) montre que l'utilisateur préfère un résultat honnête et sourcé à un refus ; un faux résumé complet serait pire qu'un résumé dégradé |
|
||
|
||
---
|
||
|
||
## 20. Risques et mitigations
|
||
|
||
| Risque | Impact | Mitigation |
|
||
|---|---|---|
|
||
| Les utilisateurs oublient de démarrer la capture | Élevé — la valeur disparaît | Rappels T-15/T-0 actionnables ; création de note à l'avance ; reprise facile |
|
||
| Capture d'onglet mal comprise (mauvais onglet, audio non coché) | Élevé sur le Web | Détection de silence du canal distant + message d'aide en contexte (§11.3) |
|
||
| Résumés qui inventent des décisions | Élevé — perte de confiance immédiate | Citations obligatoires, schéma contraint, statut `proposed` des actions, jeu d'évaluation (§12.4–12.5) |
|
||
| Non-conformité d'un enregistrement | Élevé — juridique | Porte de consentement bloquante, règle du consentement de tous, journal append-only (§14.1) |
|
||
| Coûts STT qui dérivent | Moyen | Compteurs par workspace, alertes budgétaires, quotas de plan (§12.6) |
|
||
| Deux notes pour la même réunion | Moyen | Contrainte d'unicité + résolution par occurrence partout (§9.2) |
|
||
| Verrouillage fournisseur IA | Moyen | Interfaces + payloads bruts conservés pour rejeu (§7.6) |
|
||
| Safari / Firefox sans capture d'onglet fiable | Moyen | Détection de capacité, mode A en repli, import en secours ; communiquer honnêtement les limites |
|
||
| Données de réunion très sensibles qui fuient par la recherche | Élevé | Filtrage ACL **avant** la recherche sémantique (§9.5) |
|
||
|
||
---
|
||
|
||
## 21. Questions ouvertes pour Flowdeck
|
||
|
||
Ces réponses changeront des parties précises du document — les trancher avant la Phase 2 :
|
||
|
||
1. **Stack actuelle de Flowdeck** : langage/framework back-end, base de données, hébergeur ? (§5, §7)
|
||
2. **L'éditeur de documents existe-t-il déjà** dans Flowdeck, et est-il déjà collaboratif temps réel ? Si oui, le §6.3 se réduit à l'ajout des blocs « réunion ». Sinon, c'est le plus gros chantier du projet.
|
||
3. **Calendriers prioritaires** : Google seul au MVP, ou Microsoft 365 requis par les premiers clients ? (§13.1)
|
||
4. **Marchés et langues** : français/anglais seulement, ou plus ? Cela conditionne le fournisseur STT et ses régions de traitement. (§12.2)
|
||
5. **Modèle d'affaires** : la fonction est-elle un palier payant, un compteur de minutes, ou incluse ? (§7.10)
|
||
6. **Les tâches vivent-elles dans Flowdeck** ou dans un outil externe (auquel cas les actions deviennent des intégrations sortantes) ? (§7.1)
|
||
7. **Politique audio** : Flowdeck accepte-t-il le principe « audio non conservé par défaut », y compris face à des clients qui réclameront la réécoute ? (§14.4)
|
||
8. **Bot ou pas bot** : certains clients entreprise exigeront une capture sans dépendre du poste d'un participant. À quel horizon ? (ADR-02)
|
||
|
||
---
|
||
|
||
## Annexe A — Correspondance Notion → Flowdeck
|
||
|
||
| Capacité observée chez Notion | Équivalent Flowdeck proposé | Phase |
|
||
|---|---|---|
|
||
| Onglet *Meetings* (à venir + historique) | Hub Meetings | 0 |
|
||
| Note liée à un événement calendrier | `meetings` + unicité par occurrence | 0 |
|
||
| Bloc notes de réunion (`/meet`) | Bloc `meeting` dans l'éditeur + création ad hoc | 1 |
|
||
| Modèles de notes par type de réunion | Templates + instructions de résumé liées | 1 |
|
||
| Base de réunions par défaut | Dossier/base par défaut du workspace | 1 |
|
||
| Notes privées par défaut, partage auto optionnel | ACL propre + politique de partage auto (opt-in) | 1 |
|
||
| Capture desktop (système + micro), sans bot | Modes Web A/B ; companion desktop éventuel | 2 / 4 |
|
||
| Capture navigateur (micro seul) | Mode A, avec avertissement explicite des limites | 2 |
|
||
| Consentement texte / vocal / imposé | Porte de consentement + journal append-only | 2 |
|
||
| Transcription en direct, locuteurs | STT streaming, canaux séparés, correction manuelle | 2 |
|
||
| Import audio (AAC, M4A, MP3, WAV) | Mode C, téléversement reprisables, batch | 2 |
|
||
| Résumé structuré par type / instructions perso | Schéma JSON contraint + instructions versionnées | 3 |
|
||
| Citations résumé → transcript | `evidence_segment_ids` obligatoires | 3 |
|
||
| Actions extraites | `action_items` en `proposed`, conversion en tâches | 3 |
|
||
| Récapitulatif diffusé (Slack, courriel) | Module notifications + diffusions tracées | 3 |
|
||
| Recherche et Q&R sur les réunions | Index filtré ACL + Q&R sourcée | 3 |
|
||
| Rétention configurable du transcript | Politiques de rétention + purges automatiques | 3 |
|
||
| Audio du direct éphémère | `audio_retention = ephemeral` par défaut | 2 |
|
||
| Bloc à états, onglets révélés progressivement **(v1.1, §3A.1)** | `meeting-block-shell` + machine à états §6.5 | 2 |
|
||
| Forme d'onde en direct, *Pause* / *Stop* **(v1.1, §3A.3)** | `waveform-visualizer`, états `paused` de session | 2 |
|
||
| Attestation de consentement au clic *Start* **(v1.1, §3A.2)** | `consent-attestation-inline`, `method = start_attestation` | 2 |
|
||
| Bandeau d'essai dans le bloc **(v1.1, §3A.3)** | `entitlement-banner` piloté par §7.10 | 2 |
|
||
| Étapes *Thinking* nommées, dont la résolution des références **(v1.1, §3A.4)** | `processing_steps` + `processing-tracker` (§12.7) | 3 |
|
||
| Résumé dégradé « bref / incomplet » et titre-diagnostic **(v1.1, §3A.5)** | Classification de complétude + `title-generator` (§12.8) | 3 |
|
||
| Barre « Share this summary » (lien, courriel, Slack) **(v1.1, §3A.5)** | `summary-share-bar` + `summary_distributions` | 3 |
|
||
| Transcript regroupé par piste source, marques de troncature **(v1.1, §3A.7)** | `transcript-source-group`, `starts/ends_mid_utterance` | 2–3 |
|
||
|
||
## Annexe B — Glossaire
|
||
|
||
| Terme | Sens dans ce document |
|
||
|---|---|
|
||
| **Diarisation** | Découpage d'un enregistrement en locuteurs anonymes (« qui parle quand »), sans les nommer |
|
||
| **STT** | *Speech-to-text* : transcription automatique de l'audio en texte |
|
||
| **Segment** | Unité de transcript horodatée, attribuée à un canal et à un locuteur |
|
||
| **Occurrence** | Instance concrète d'un événement calendrier, y compris dans une série récurrente |
|
||
| **Outbox** | Table d'événements écrite dans la même transaction que la donnée métier, puis publiée de façon fiable |
|
||
| **CRDT** | Structure de données permettant l'édition simultanée convergente d'un document partagé |
|
||
| **Entitlement** | Droit d'accès à une fonction selon le plan du workspace |
|
||
| **Consentement (record)** | Trace horodatée et non modifiable de la manière dont le consentement a été demandé et attesté |
|
||
|
||
## Sources
|
||
|
||
Analyse fonctionnelle de la section 3 établie à partir de la documentation publique de Notion, consultée le 8 octobre 2026 :
|
||
|
||
- **Captures d'écran d'une session réelle Notion AI Meeting Notes, fournies par Bruno le 9 octobre 2026** (6 images, ordre chronologique) — source primaire de la section 3A et des ajouts v1.1 : `meetings-notion-reference/01-panneau-initial.png` à `06-resultat-transcript.png`, conservées à côté de ce document.
|
||
- [Prendre des notes de réunion IA dans Notion — Centre d'aide Notion](https://www.notion.com/help/ai-meeting-notes)
|
||
- [AI Meeting Notes — page produit Notion](https://www.notion.com/product/ai-meeting-notes)
|
||
- [Notion lance une application calendrier — TechCrunch, 17 janvier 2024](https://techcrunch.com/2024/01/17/notion-launches-a-calendar-app/)
|
||
- [Notion s'attaque aux preneurs de notes IA — TechCrunch, 13 mai 2025](https://techcrunch.com/2025/05/13/notion-takes-on-ai-notetakers-like-granola-with-its-own-transcription-feature/)
|
||
|
||
*Les éléments des sections 4 à 21 sont une proposition d'architecture originale pour Flowdeck et ne décrivent pas les systèmes internes de Notion.*
|
||
|
||
---
|
||
|
||
*Fin du document — version 1.2, 9 octobre 2026 (version 1.0 : 8 octobre 2026).*
|