# Changelog — FlowDeck ## v4.9.0 (2026-09-04) — Collaboration : commentaires inline, mentions @, notifications > Implémentation complète du pilier « Collaboration » — basée sur la revue des docs Notion > (`docs/Guide_Complet_Notion_sharing_collaborartion.md`) : commentaires avec ancres inline, > mentions `@` avec autocomplétion, centre de notifications in-app et emails SMTP. ### Added - **Commentaires inline sur les pages** : sélection d'un texte dans l'éditeur → bouton flottant « 💬 Comment » → commentaire ancré (`block_id` + offsets). Table `comments` étendue (`target_type`, `target_id`, `anchor_block_id`, `anchor_start`, `anchor_end`) et **migrée** de son FK `collection_pages` vers un schéma générique (aucune perte de données, idempotente). - **Panneau de commentaires** dans l'éditeur : liste, résolution (✔/↪), suppression, compteur dans la topbar. - **Mentions `@`** : autocomplétion en temps réel (recherche d'utilisateurs), insertion de `@login` dans un bloc ou un commentaire → notification ciblée à l'utilisateur mentionné. - **Centre de notifications in-app** : cloche dans la topbar (badge non-lus, polling 30s), panneau déroulant, « mark as read » / « mark all read ». Table `notifications`. - **Emails de notification** : service SMTP (`app/services/mailer.py`) + templates HTML ; préférences email par utilisateur (comments/mentions) réglables dans Settings → Notifications. Sans SMTP configuré, seules les notifications in-app sont émises (aucune erreur). - **API** : `GET/POST /api/notifications`, `/api/notifications/read|read-all|prefs`, `/api/notifications/users/search`, `GET/POST /api/pages/{id}/comments`, `PUT/DELETE /api/comments/{id}`, `POST /api/pages/{id}/mentions`. - **Config SMTP** (`SMTP_HOST/PORT/USER/PASSWORD/FROM/USE_TLS`, `APP_BASE_URL`) dans `.env.example`. ### Infra - `VERSION` → 4.9.0 ; `app/main.py` (log + `version=`) ; router `notifications` + `collaboration` enregistrés ; exclusions CSRF (`/api/notifications`, `/api/comments`) ; le `RateLimitMiddleware` respecte désormais `settings.rate_limit_enabled`. ### Tests - **208 tests verts** (+9 v4.9.0 : table notifications, commentaires inline + mentions, centre de notifications, préférences, recherche utilisateurs, résolution/suppression, mentions de page). ### Fixed - **Bouton « + Row » (bas du tableau) inopérant** — le code passait la nouvelle ligne en argument `deleteCount` de `Array.splice` au lieu d'utiliser `splice(index, 0, ligne)` : aucune ligne n'était jamais insérée. Corrigé ; les insertions de lignes (menu contextuel aussi) fonctionnent. - Coloration/handles alignés sur l'en-tête. ### Added - **Bouton « + » à droite du tableau** (sur toute la hauteur) → ajoute une colonne à la droite (équivalent d'un « Add column » comme « Add Row »). - **Redimensionnement des colonnes à la souris** : au survol d'une bordure de colonne (en-tête) le curseur devient `col-resize` ; glisser ajuste la largeur. Les largeurs sont persistées dans le bloc (`colsW`) → conservées au rechargement, à l'ajout/suppression et dans l'auto-save. ### Infra - `VERSION` → 4.8.1 ; cache CSS `app.css?v=4.8.1`. ## v4.8.0 (2026-09-03) — Bloc Tableau simple (mode édition Notion) > Insertion via `/table`, cellules éditables au clic, ajout/suppression/modification de lignes et colonnes comme dans Notion. ### Added - **Bloc `table` dans l'éditeur de page.** Nouvelles commandes slash `/table` (menu « BASIC ») → tableau 3×3 avec en-tête ; première ligne stylée en en-tête, cellules `contenteditable` éditées au clic, auto-sauvegarde (format de bloc conservé : `{type:'table', rows:[...]}`). - **Gestion des colonnes** : bouton de poignée (⋮⋮) au-dessus de chaque colonne → menu contextuel Insert left / Insert right / Duplicate / Clear contents / Delete column / Delete table. - **Gestion des lignes** : bouton « + Row » sous le tableau (clic = ajouter une ligne) + menu contextuel (clic droit sur une cellule de corps) → Insert above / Insert below / Duplicate / Clear row / Delete row / Delete table. - **Import Markdown (GFM)** : `md2b` détecte les tableaux pipe (`| a | b |` + ligne de séparateurs) et produit un bloc `table` éditable au lieu de paragraphes aplatis (pages `.md`/markdown). - **Roundtrip Markdown** : `blocksToMarkdown` (JS) et l'export Python reconstruisent un tableau pipe valide depuis les blocs. - **Export** : les pages contenant un bloc `table` sortent correctement en Markdown / HTML / PDF (géré côté serveur). - UX : cliquer sous un tableau en fin de page ajoute un paragraphe pour continuer la rédaction. ### Infra - `VERSION` → 4.8.0 ; `app/main.py` (log + `version=`) ; cache CSS `app.css?v=4.8.0` ; ROADMAP renuméroté (v4.8.0 Bloc Tableau, Collaboration → v4.9.0, Agent → v4.10.0). ### Tests - Suite pytest verte (199) ; vérification syntaxe JS du template via `node --check`. ## v4.7.3 (2026-09-03) — Fix export PDF/HTML : tableaux + émojis ### Fixed - **Tableaux Markdown rendus comme du texte brut** dans les exports HTML/PDF (les lignes `| a | b |` ressortaient en paragraphes). Ajout d'un parseur GFM de tableaux (`_md_to_blocks` → bloc `table`) et d'un rendu en vrai `` (en-tête `
`, corps ``, alignement gauche/centre/droite, bordures fines via `.ftable`). Le format Markdown reconstruit un tableau pipe valide. - **Émojis en « carrés noirs » dans le PDF.** Cause : le moteur `xhtml2pdf` (reportlab) n'embarque que des polices de base sans glyphes Unicode/émojis. Le moteur PDF passe à **WeasyPrint** (vraies tables CSS + émojis couleur via Pango + `fonts-noto-color-emoji`, installés dans l'image Docker). Repli automatique sur `xhtml2pdf` si WeasyPrint n'a pas ses libs natives (ex. poste de dev Windows) — le contenu s'exporte quand même. ### Infra - `Dockerfile` : ajout des libs WeasyPrint (pango/harfbuzz/gdk-pixbuf/shared-mime-info) + polices `fonts-dejavu-core` et `fonts-noto-color-emoji`. - `requirements.txt` : + `weasyprint==69.0` (xhtml2pdf conservé en repli). ### Tests - **199 tests** (4 nouveaux) : parse table → `` HTML réel + alignements ; standalone HTML embarque `.ftable` ; roundtrip table → markdown pipe ; PDF d'une page avec table = PDF valide. - Vérifié en réel sur `README.md` : PDF avec tableau structuré + émojis en couleur (pixels colorés confirmés), HTML avec tableau bordé. ## v4.7.2 (2026-09-03) — Fix export : le contenu des documents était absent ### Fixed - **Export Markdown / HTML / PDF : seuls le nom de page et le titre étaient inclus, jamais le contenu.** Cause : le service d'export ne lisait que les pages en `content_format='blocks'`. Or les documents peuvent être stockés autrement : - `content_format='file'` (fichiers `.md`/code uploadés) : le `content` de la page n'est que des métadonnées JSON — le vrai texte est un fichier sur disque (`/data/uploads/workspace_*`). L'export n'allait jamais le lire → uniquement le titre. - `content_format='markdown'` : le HTML/PDF se contentait d'envelopper chaque ligne en `

` (titres et listes aplatis). - Le service résout désormais la vraie source pour les 3 formats : lit le fichier sur disque pour les pages `file`, rend les pages `markdown`/fichiers `.md` en blocs (headings, listes, code…), et traite les fichiers texte non-markdown comme bloc de code. Les fichiers binaires (PDF/images) sont laissés de côté (rien d'exploitable). - Chemin des uploads rendu configurable pour les tests via `FLOWDECK_DATA_DIR` (défaut `/data`, identique à `dashboard.py`). ### Tests - **195 tests au total** (5 nouveaux v4.7.2) : page markdown → corps exporté ; page markdown → HTML avec headings/listes ; fichier `.md` uploadé → contenu réel dans Markdown/HTML/PDF ; fichier code → exporté ; fichier binaire → non déversé. - Vérifié en réel sur `/data` (page `README.md` et arborescence « Base de Connaissances » → fichiers `.md`) : le corps complet est maintenant présent dans les 3 formats. ## v4.7.1 (2026-09-03) — Fix UI éditeur : menus Share / More invisibles ### Fixed - **Boutons « Share » et « ⋯ » (More) sans réaction visible dans l'éditeur de page** — les popovers (share-dialog, more-menu, activity-popover, move-dialog), enfants de `.page-editor-wrapper` (conteneur à `overflow-y:auto`), étaient ancrés en `absolute; top:100%` → rendus SOUS le viewport, donc invisibles. Repositionnés en `position:fixed` sous la topbar (scoped `.page-editor-wrapper > …` pour ne pas casser les `.more-menu` des pages library/local_workspace) + variantes mobile dans le media query < 768px. - **Sous-menu Export se refermait** — l'itém « ↗ Export » faisait `moreOpen=false` avant d'ouvrir `exportOpen` : les 4 formats restaient inaccessibles au clic. Devient un toggle (`exportOpen = !exportOpen`), le menu More reste ouvert. - **Cache CSS** — version du query string `app.css` bumpée (`v=3.0.0` → `v=4.7.1`) pour invalider le cache navigateur. ### Vérifié - Playwright headless (desktop 1280×800) : Share, More, sous-menu Export, popover Activity et menu More après scroll = tous visibles dans le viewport ; téléchargement Markdown + toast « Exported as Markdown » OK ; zéro pageerror. - 190/190 tests pytest passent. ## v4.7.0 (2026-09-03) — Export ### Added - **Export Markdown** — conversion serveur complète de tous les blocs (headings, listes, to-do, quote, code, math, toggle, colonnes, callout, image), images incluses - **Export Markdown récursif** — les sous-pages sont incluses automatiquement - **Export PDF** — via `xhtml2pdf` (pur Python, aucun lib système), rendu print-friendly - **Export HTML** — document autonome self-contained (styles inline) - **Export Site** — site statique multi-pages en `.zip` (index.html + une page HTML par sous-page) - **4 endpoints serveur** : `/api/export/markdown|html|pdf|site/{page_id}` - **UI** : menu « More › Export » dans l'éditeur (Markdown, HTML, PDF, Site .zip) ### Améliorations - Nouveau service `app/services/export.py` (conversion blocs → Markdown / HTML / PDF réutilisable) - Nouveau routeur `app/routers/export.py` - Téléchargements via `Content-Disposition` (avec nom de fichier encodé UTF-8) ### Tests - **190 tests au total** (6 nouveaux tests v4.7.0) : Markdown, sous-pages, HTML, PDF, Site zip, 404 ## v4.6.0 (2026-09-02) — Content Blocks Enrichis ### Added - **Callout blocks** — boîtes colorées avec sélecteur d'emoji/icône cliquable - **Table of contents** — bloc auto-généré depuis les headings, avec ancres de navigation - **Math equations** — bloc LaTeX/KaTeX avec aperçu en temps réel (édition inline) - **`table_of_contents` et `math`** — nouveaux types dans le slash menu (éditeur) - **Multi-colonnes** — bloc `columns` avec layout flexible, bouton "+ Add column" / retrait - **Toggle lists enrichis** — contenu expandable/collapsible avec blocs enfants imbriqués ### Améliorations - Intégration **KaTeX 0.16.11 self-hosté** (`/static/js/katex.min.js`, `/static/css/katex.min.css`, `/static/fonts/`) — aucun CDN externe - Rendu des nouveaux blocs dans les **pages publiques** (`/p/`): TOC ancré, KaTeX, colonnes flex, toggle `

` - Export Markdown étendu aux nouveaux types de blocs - Correction d'un bug pré-existant : `public_page.html` n'importait pas la macro `fd_icon` → erreur de rendu des pages publiées ### Tests - **183 tests au total** (5 nouveaux tests v4.6.0) couvrant le rendu public TOC/math/colonnes/toggle et la persistance `children` ## v2.7.1 (2026-07-13) — Private Pages Gitea ### Added - **Table `gitea_private_pages`**: pages FlowDeck locales liées à un projet Gitea (user_id, owner, repo) - **API CRUD**: GET/POST/PUT/DELETE `/api/gitea/projects/{owner}/{repo}/private-pages` - **UI**: liste des pages privées + éditeur titre/contenu dans le workspace Gitea - **Sidebar**: lien "Private Pages" dans l'arborescence du workspace - **Persistance**: les pages survivent au changement de workspace / session ### Fixed - `get_user_repos(limit=100)` — `bruno/flowdeck` était tronqué à la page 2 (30 repos par défaut) ## v2.7.0 (2026-07-13) — Intégration Gitea Phase 1 ### Added - **OAuth2 Provider**: Gitea comme fournisseur OAuth2 pour FlowDeck (Client ID/Secret dans `.env`) - **Redirect URI dynamique**: basé sur le header `Host` — fonctionne depuis `localhost` et `192.168.x.x` - **Workspace listing**: 2 sections — My Workspaces + Gitea Projects (groupés par organisation) - **Tabs par org**: All | user | org1 | org2 avec compteurs de projets - **Barre de recherche**: filtrage live par nom/description dans Gitea Projects - **Lazy tree**: arborescence chargée un dossier à la fois (API Gitea `GET /repos/{o}/{r}/contents`) - **File viewer**: lecture fichiers Gitea avec décodage base64 - **Éditeur + commit**: modifier un fichier et commiter dans Gitea avec message personnalisé - **Delete fichier**: suppression avec confirmation + commit - **Arborescence dans le sidebar**: comme un workspace local, avec lazy-load des sous-dossiers - **Settings › Integrations**: connecter/déconnecter Gitea (`GET /api/gitea/status`, `DELETE /api/gitea/disconnect`) - **Fallback token admin**: opérations GET utilisent le token serveur si pas de token OAuth utilisateur - **Write ops protégées**: commit et delete exigent un token OAuth utilisateur - **Routes API**: `/api/gitea/orgs`, `/api/gitea/projects`, `/api/gitea/projects/{o}/{r}/tree`, `/api/gitea/projects/{o}/{r}/file`, `/api/gitea/projects/{o}/{r}/labels` ### Fixed - Bouton "Register with Gitea" ne crée plus de session admin fantôme (fallback retiré) - `_sidebar_data` gère le cookie `gitea:owner:repo` pour l'arborescence ## v2.6.0 (2026-07-13) — My Account & Auth Locale ### Added - **Section My Account**: modifier username, full name, email, mot de passe - **Toggle mot de passe**: bouton voir/cacher dans les formulaires login/register - **Label "Email or username"**: login accepte les deux formats - **Refresh cookie session**: après modification du compte, le cookie est mis à jour - **Register avec Gitea**: boutons dynamiques "Login/Register with Gitea" selon l'onglet actif ### Fixed - Session cookie non rafraîchi après `PUT /api/settings/account` (création nouvelle session) - Input login `type="email"` → `type="text"` (accepte usernames non-email) ## v2.5.0 (2026-07-13) — Administration Avancée ### Added - **Premier compte = admin automatique**: `is_admin=1` pour le premier utilisateur créé - **Panneau Admin dans Settings**: visible uniquement pour les admins - **Users & Roles**: créer/modifier/supprimer utilisateurs, changer rôles - **Table `login_history`**: audit des connexions (IP, user_agent, timestamp) - **Statistiques par utilisateur**: workspaces, pages, dernière connexion - **API `/api/admin/*`**: users, stats, audit — protégées par `admin_required` - **CSRF fix**: token CSRF dans toutes les requêtes admin (`adminFetch`) ## v2.4.0 (2026-07-13) — Tags Personnalisés par Utilisateur ### Added - **Tags isolés par `user_id`**: chaque utilisateur voit uniquement ses propres tags - **`UNIQUE(name, user_id)`**: remplace `UNIQUE(name)` dans la table `tags` - **Migration**: tags existants assignés au premier utilisateur - **Filtrage transparent**: l'API retourne les tags filtrés par `user_id` (session cookie) ### Fixed - Affichage des tags dans le menu contextuel workspace (sync Alpine.js) - Création de tag avec couleur persistée - Fermeture auto du menu contextuel après ajout de tag - Filtrage par tags: `toggleTagFilter()` appelle `doFilter()` - Pastilles tags: fond = couleur du tag, sans rond séparé ## v2.3.0 (2026-07-12) — Multi-Vues Workspace & Preview Panel ### Added - **Sélecteur de vue**: Tree, List, Details, Title, Content — 5 modes d'affichage - **Vue List**: liste compacte avec Name, Type, Size, Modified - **Vue Details**: table complète avec Path, Author, Tags - **Vue Title**: grille de cartes avec icônes et métadonnées - **Vue Content**: liste avec aperçu inline (taille ou nombre d'items) - **Preview Panel**: panneau latéral droit avec contenu du fichier sélectionné - Header avec icône + titre + bouton fermer - Métadonnées (type, taille, date) - Tags affichés en chips - Corps avec rendu du contenu (blocks JSON → HTML, texte brut) - Actions: Open, Rename, Delete - Animation slide-in/out - **Tri par date**: options Oldest/Newest dans le selecteur de tri ## v2.2.0 (2026-07-12) — Tags & Recherche Avancée ### Added - **Tags**: système complet de tags avec tables `tags` + `page_tags`, CRUD API - **API Tags**: `GET/POST/DELETE /api/local-workspace/items/{id}/tags`, `GET /api/local-workspace/tags` - **Vue Table enrichie**: colonnes Name, Path, Size, Modified, Type, Author, Tags - **Filtrage par tags**: barre de chips avec compteurs, clic pour filtrer - **Ajout/retrait tags inline**: bouton + dans la table, chips avec × pour retirer - **Tree endpoint enrichi**: chaque nœud retourne `size`, `size_display`, `created_at`, `updated_at`, `author`, `tags` - **Filtre "Dossiers"**: nouveau chip Folders dans la barre de filtres - **Auto-switch table**: quand recherche/filtre actif, passe en vue table automatiquement ## v2.1.1 (2026-07-12) — Fix Arborescence Workspace ### Fixed - **Arborescence**: création fichier/dossier dans un sous-dossier met à jour l'arbre sans rechargement - **parentFolder**: corrigé le bug où `parentFolder` était nullifié avant l'insertion dans l'arbre JS - **displayTree**: nouvelle référence array après chaque mutation pour forcer le re-render Alpine.js - **doSort/doFilter**: gèrent maintenant le cas où un filtre/tri est actif après création ## v2.1.0 (2026-07-10) — Intégrations Avancées ### Added - **API publique**: `/api/v1` (collections, pages, my-tasks) avec token auth - **Token generation**: `POST /api/v1/token` - **Webhooks sortants**: `GET/POST/DELETE /workspace/webhooks` + dispatcher - **PWA**: `GET /manifest.json` - **CSRF**: `/api/v1` exempté ### Tests - 73/73 passent (+6 tests v2.1) ## v2.0.0 (2026-07-10) — Multi-User Workspaces & Editor Complete ### Added - **Workspaces**: tables `workspaces` + `workspace_members`, CRUD API, roles admin/editor/commenter/viewer - **Comments**: table `comments` avec thread (parent_id), resolved - **Page History**: table `page_history`, snapshot JSON - **Favorites**: table `favorites`, add/remove/list - **Templates**: `database_templates` + `page_templates`, apply API - **CSV Import/Export**: `POST .../import/csv`, `GET .../export/csv` - **Public Sharing**: `GET /workspace/public/{id}` (read-only, no auth) ### Tests - 67/67 passent (+7 tests v2.0) ## v1.9.0 (2026-07-10) — My Tasks Dashboard ### Added - **My Tasks**: `GET /my-tasks` (HTML), `GET /my-tasks/api` (JSON) - Agrégation cross-collection, vues All/Today/Overdue/Next 7 days ## v1.8.0 (2026-07-10) — Sub-items & Dependencies ### Added - **Sub-items**: parent_id auto-référence, GET/POST sub-items - **Status aggregate**: `GET .../status-aggregate` - **Dependencies**: `POST .../dependencies`, `POST .../check-deps` ## v1.7.0 (2026-07-10) — Vues Améliorées ### Added - **View config**: `PUT /db/views/{id}/config` (group_by, card_size, cover, visible) - **Save view as**: `POST /db/{id}/views/save-as` - **List views**: `GET /db/{id}/views/api` ## v1.6.0 (2026-07-10) — Vues Manquantes ### Added - **Calendar**: grid mensuel, navigation mois - **Gallery**: cartes visuelles, card_size configurable - **List**: vue compacte avec preview - **Timeline**: barres horizontales Gantt - **Table**: rendu SSR avec colonnes properties - **View tabs**: navigation Table/Board/Calendar/Gallery/List/Timeline ## v1.5.0 (2026-07-10) — Relations & Rollups ### Added - **FormulaEngine**: 19 fonctions (prop, if, concat, round, now, today, dateAdd, replace, ...) - **RollupEngine**: 12 agrégations (count, sum, avg, min, max, range, unique, percent_checked) - **Relation**: lien bidirectionnel, API create/link ## v1.4.0 (2026-07-10) — Propriétés Avancées ### Added - **Table `collection_properties`**: 21 types Notion - **Service `property_types.py`**: validation, formatage, auto-values ## v1.3.0 (2026-07-10) — Database Concept ### Added - **Tables**: `collections`, `collection_pages`, `collection_views` - **Router `/db`**: CRUD collections + pages (16 endpoints) - **GiteaBoardCompat**: adaptateur boards legacy → Collections ## v1.0.0 (2026-07-08) — Production ### Added - FastAPI lifespan, 28 tests, CI/CD Gitea Actions, CSS 31KB, 10 templates - 5 vues: Kanban, Table, Status Overview, Team Load, Detailed Board - Filtres cumulables AND, tri multi-critères - Card detail modal, checklists, commentaires Gitea - Propriétés custom, AI keywords, sync API