Files
flowdeck/CHANGELOG.md
T
bruno e4b196a528
FlowDeck CI / test (push) Failing after 12s
FlowDeck CI / docker (push) Skipped
feat(db): v5.3.0 inline databases, predefined templates & property validation
- Slash command /database (DATA group) -> template picker -> inline DB
  embed block rendered by FlowDeckDB. 'Get Started > Database' uses it too.
- 6 seeded database templates (CRM, Project tracker, Task list, Content
  calendar, Meeting notes, Reading list) with icon + schema; new service
  app/services/db_templates.py (materialize_properties, create_from_template).
- POST /db/api and /db/inline/api accept 'template' and materialize
  collection_properties. database_templates gets an icon column (migration v4).
- Property validation: collection_properties.validation_json (migration v4);
  validate_property_rule() in property_types (required/unique/min/max/
  min_length/max_length); enforced in create/update page API (400 + message,
  unique excludes current row); property API accepts 'validation'.
- UI: add-property modal exposes Required/Unique/Min/Max; cell edit shows
  validation errors (red outline + toast) and reverts.
- VERSION + app.main -> 5.1.0; CHANGELOG + ROADMAP updated.
- +9 tests (tests/test_db_advanced.py). 271 passed.
2026-09-07 00:53:13 -04:00

842 lines
54 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Changelog — FlowDeck
## v5.1.0 (2026-09-06) — Database Avancée : inline DB, templates prédéfinis & validation
> Livre la **v5.3.0** du roadmap : databases inline dans les pages (slash `/database`),
> galerie de **templates prédéfinis** (CRM, Project tracker, …) et **validation des
> propriétés** (required / unique / min / max) côté serveur + UI.
### Added — Inline databases (slash `/database`)
- Commande slash **`/database`** (groupe DATA) dans l'éditeur : ouvre un **sélecteur de
templates**, crée une database inline liée à la page et insère un bloc
`embed_type:'collection'` rendu par `FlowDeckDB.renderInto`.
- Le bouton « Database » de la barre *Get Started* ouvre désormais le même sélecteur
(au lieu de créer une database vide directement).
### Added — Templates de database prédéfinis
- **6 templates intégrés** seedés (migration v4) : Project tracker, CRM / Contacts,
Task list, Content calendar, Meeting notes, Reading list — avec icône, description et
schéma de propriétés.
- `app/services/db_templates.py` : `materialize_properties()` (schéma → `collection_properties`)
et `create_from_template()` (collection + propriétés + vue par défaut).
- `POST /db/api` et `POST /db/inline/api` acceptent `"template": "<nom>"` et matérialisent
les propriétés (titre exclu — c'est le titre de ligne). Colonne `icon` ajoutée à
`database_templates` (migration v4).
- `apply_db_template` (`/workspace/templates/database/{id}/apply`) matérialise les propriétés.
### Added — Validation des propriétés (required / unique / min / max)
- Nouvelle colonne `collection_properties.validation_json` (migration v4) ; le type/format
et les règles de validation sont portés par `validate_property_rule()` dans
`property_types.py` (required, unique, min, max, min_length, max_length).
- **Serveur** : `create_page_api` et `update_page_api` (`/db/{c}/pages/api`,
`/db/pages/{id}/api`) valident les valeurs avant écriture → 400 + message clair. La règle
`unique` exclut la page en cours d'édition. Les valeurs sont résolues par id **ou** par nom.
- **API propriétés** : `POST/PUT /db/{c}/properties/api` acceptent `validation` (persisté).
- **UI** (`_database_table_scripts.html`) : la modale « Add property » expose Required,
Unique, Min, Max ; en cas de 400 à l'édition d'une cellule, la cellule est marquée en rouge
et un toast affiche le message (valeur restaurée).
### Tests
- **271 tests** (+9 dans `tests/test_db_advanced.py`) : templates seedés, création de
collection/inline depuis template (propriétés matérialisées), apply template, validation
required/unique/min-max (create + update, exclusion de la ligne courante), persistance de
la config de validation, payload collection.
> Livre deux chantiers du roadmap v5 : la **migration au système de schéma versionné**
> (v5.2.0, priorité n°1 — débloque tout le reste) et la **Command Palette + recherche
> full-text** (v5.0.0).
### Added — Command palette (v5.0.0)
- **Palette de commandes `Ctrl+K` / `Ctrl+P`** dans `base.html` : modale centrée
autofocusée, navigation clavier (↑/↓/Enter/Esc), surlignage fuzzy des correspondances,
recherche universelle et **quick actions** (Nouvelle page, Library, My Tasks, Trash,
Settings, Help). Le bouton Search de la sidebar et `openQuickFind()` ouvrent désormais
la palette (fini le toast « Quick Find — Ctrl+K »).
- **Endpoint `GET /api/search?q=`** (`app/routers/search.py`) + service
`app/services/search.py` : recherche unifiée des **pages** (titre + contenu) et des
**databases** (nom + description), scopée aux workspaces accessibles de l'utilisateur.
- **Index full-text FTS5** (`pages_fts`, migration v3) avec triggers de synchronisation
(insert/update/delete) sur la table `pages` ; repli automatique sur `LIKE` si FTS5
absent. Exclusions automatiques des pages supprimées (corbeille).
### Added — Migrations versionnées (v5.2.0)
- **Runner léger `app/migrations.py`** (alternative à Alembic pour ce projet SQLite) :
table `schema_version` enregistrant la version appliquée ; le schéma de base existant
(`init_db`) devient la **baseline v1**, et chaque changement futur est une étape
versionnée appliquée une seule fois, dans l'ordre.
- **Migration v2 — indexes manquants** : `users(email)`, `user_oauth_tokens(user_id,
provider)`, `collections(workspace_id)`, `pages(workspace_id)`, `pages(deleted_at)`.
- **Migration v3 — FTS5** : `pages_fts` + triggers `pages_fts_ai/ad/au` + backfill.
- `init_db()` termine désormais par `apply_migrations(conn)` : nouveau schéma et bases
existantes convergent sans rejouer les migrations déjà appliquées.
### Tests
- **267 tests** (8 nouveaux dans `tests/test_search_migrations.py`) : suivi de la version
`schema_version`, indexes créés, table/triggers FTS5, synchronisation de l'index,
recherche pages+collections, exclusions de la corbeille, requête vide et sans résultat.
### Corrections
- **Test de connexion multi-provider** : le modèle configuré globalement (ex. `deepseek-v4-flash`)
n'est plus envoyé lorsqu'on teste un **autre** provider (ex. nvidia) — c'était la cause d'un
HTTP 404 « model not found ». Chaque provider utilise désormais son modèle par défaut tant que
le modèle global ne le concerne pas.
- **Presets NVIDIA actualisés** : les anciens modèles (`nvidia/llama-3.1-70b-instruct`,
`nvidia/nemotron-4-340b-instruct`) étaient retirés de la plateforme ou soumis à abonnement ;
liste remplacée par des modèles disponibles (`nvidia/nemotron-3-super-120b-a12b`,
`meta/llama-3.1-70b-instruct`, `deepseek-ai/deepseek-v4-pro`, `z-ai/glm-5.2`, …).
> Note : un 404 persistant après cette correction vient de NVIDIA lui-même (code
> « Function … : Not found for account ») — cause fréquente : le droit « Public API Endpoints »
> pas activé sur le compte/clé pour le modèle choisi.
## v4.15.4 (2026-09-06) — Correctifs listes agent (@ et /)
### Corrections
- **Menus « @ » vides** : le template Alpine du menu de mentions avait deux racines
(Alpine n'en accepte qu'une) — seuls les titres de sections s'affichaient, sans éléments.
Les éléments sont maintenant bien rendus sous chaque section.
- **Sélection clavier visible dans le menu « / »** : le changement de focus (↑/↓) n'était pas
visible faute de style `.focus` ; ajout d'un surlignage (fond + barre d'accent à gauche).
## v4.15.3 (2026-09-06) — Agent : mentions @ par espace courant + skills composés en arrière-plan
> La commande « @ » propose en priorité les **fichiers de l'espace de travail ouvert**, puis les
> autres contextes (collections, pages de collections, autres documents). La navigation clavier
> (↑/↓) positionne maintenant visuellement la sélection dans la fenêtre (défilement), et les
> fichiers identiques ne sont plus affichés plusieurs fois (déduplication par titre).
### Améliorations
- **Mentions @ contextuelles** : nouvelle API `/api/agent/mentions` par **sections** :
*Fichiers de l'espace courant* (« `workspace_id` transmis par le frontend »), *Collections / bases*,
*Pages de collections*, *Autres documents*.
- **Navigation clavier corrigée** : ↑/↓ font défiler la liste ouverte pour garder la sélection
visible à l'écran (aussi appliqué au menu `/`). Entrée/Tab sélectionne toujours l'élément focalisé.
- **Déduplication** : deux fichiers du même type et même titre (ex. « Sans titre », « Aussi Vide »)
n'apparaissent qu'une seule fois dans les propositions.
- **Skills composés en arrière-plan** : sélectionner un skill n'injecte plus son texte dans la boîte
d'édition. À l'envoi la requête est assemblée : `contexte1 + contexte2 + skill-1 + skill-2 + texte`.
Les skills intégrés (templace) et enregistrés (skill_ids) sont tous deux pris en compte ; les
contextes @ continuent d'être résolus en contenu côté serveur.
## v4.15.2 (2026-09-06) — Agent : skills multi-épinglés en bulles + chips de contexte cliquables
> Les skills s'épinglent désormais au contexte **comme les mentions @** (bulles « / » purples dans
> l'éditeur du chat), on peut en associer **plusieurs** à un même post, et chaque bulle de contexte
> référencée s'ouvre d'un clic comme document courant.
### Améliorations
- **Skills en bulles** : sélectionner un skill (menu `/`, intégré *ou* enregistré) ajoute une vraie
bulle dans le composer, comportement identique aux mentions `@`. La bulle d'un skill intégré greffe
son modèle de demande dans le texte ; plusieurs skills peuvent coexister.
- **Plusieurs skills par post** : l'API `/run` accepte `skill_ids` (tableau) et l'engine injecte tous
leurs prompts dans les instructions système (`skill_id` reste supporté pour la rétro-compatibilité).
- **Chips de contexte cliquables** : cliquer sur une bulle de contexte (`@ document / page / base`)
ouvre l'élément comme document courant — `document:<id>`/`page:<id>` → `/pages/<id>`,
`collection:<id>` → `/db/<id>`. Le bouton « ✕ » retire toujours la bulle (sans ouvrir).
- Envoi possible avec uniquement des skills (sans texte) : « Applique le(s) skill(s) sélectionné(s)… ».
### Correctifs
- L'écriture du chat (`send`) renvoie désormais tous les `skill_id` épinglés via `skill_ids`.
## v4.15.1 (2026-09-06) — Agent : réparation des conversations réelles (protocole tool_calls)
> Le chatbot ne « répondait » plus : avec un fournisseur réel, dès qu'un **outil** était appelé la passe
> suivante était refusée par l'API (message assistant sans ses `tool_calls`) et l'agent retombait
> silencieusement sur le **mock hors-ligne**, qui se contentait de répéter la question.
### Correctifs
- **Protocole tool-calling conforme** (`agent_engine.py`) : le message assistant qui annonce un appel
d'outil transporte désormais ses `tool_calls` (avec `id`), et chaque résultat d'outil répond avec le
`tool_call_id` correspondant (y compris en cas de refus/permission). Le run se poursuit alors
correctement et se termine par une vraie réponse du modèle.
- **Plus de repli silencieux** (`llm_client.py`) : quand un fournisseur **réel** configuré échoue,
l'erreur remonte (événement SSE `error`) au lieu de produire silencieusement un écho hors-ligne.
Le mock n'est utilisé que si le fournisseur est réellement non configuré (`offline` / pas de clé).
- Les `tool_calls` analysés conservent leur `id` et les arguments bruts (`arguments_raw`).
- Test de régression `test_engine_tool_protocol_messages`.
## v4.15.0 (2026-09-06) — Agent : actions sous chaque réponse, mentions @ & skills /
> Le panneau FlowDeck Agent gagne l'expérience « type Notion AI » : chaque réponse de l'agent expose
> des actions rapides (copier, insérer dans la page, feedback 👍/👎), on peut **épingler au contexte**
> plusieurs documents / pages / bases via la commande **@** (ou le bouton **+**), et la commande **/**
> propose des **skills** de travail réutilisables en plus des commandes admin existantes.
### Sous chaque réponse de l'agent
- **⧉ / ➕ / 👍 / 👎** : boutons **à icônes seules** (infobulle au survol) — copier la réponse,
insérer dans la page ouverte, feedback 👍/👎 enregistré en base.
- Le bandeau statique « Contexte : … » du haut du panneau est supprimé.
### Contexte épinglé — commande « @ » / bouton « + » (style Notion AI)
- Le composeur est maintenant un éditeur **contenteditable** : les références sélectionnées
s'insèrent **inline** comme des pastilles cliquables (icône + nom) directement dans le message.
- Au-dessus du composeur, une **barre de contexte groupée** rassemble les fichiers épinglés
(rangée documents, icônes 📄) et les **skills** (rangée séparée, icône ✨), chacun retirable.
- **@** ouvre le sélecteur (icône + titre + chemin) listant documents, pages et bases ; l'élément
choisi devient un jeton inline **et** une puce de contexte. **+** épingle un élément au contexte
sans l'insérer inline. Les puces persistent jusqu'au retrait (et sont vidées en nouveau chat).
- **Contexte d'ouverture** : ouvrir l'agent sur un document (`/pages/:id`) ou une base (`/db/:id`)
ajoute automatiquement ce contexte comme **mention** (puce épinglée) — plus de bandeau statique.
- À l'envoi, chaque référence est transmise comme **mention** ; le backend résout son **contenu réel**.
### Skills — commande « / »
- Le menu **/** liste les **skills intégrés** (research, resume, brainstorm, plan, meeting-note,
livrable…), les **skills enregistrés** (table `agent_skills`) et les commandes admin classiques.
- Un skill intégré pré-remplit le composeur d'un modèle à compléter ; un skill en base s'épingle en
chip et est appliqué via `skill_id` à chaque envoi.
- Navigation clavier (↑/↓/Entrée/Échap) dans les menus ; aucun envoi parasite pour « / » seul.
### Infra & API
- Nouvelle table `agent_feedback` (rating, conversation/message, extrait, commentaire).
- `GET /api/agent/mentions?q=` : recherche des éléments mentionnables du workspace.
- `POST /api/agent/feedback` : enregistre un retour 👍/👎.
- `VERSION` → 4.15.0 ; `app/main.py` version → 4.15.0.
## v4.14.0 (2026-09-06) — Agent : création de documents dans un espace + nouveaux outils & titre auto
> L'agent sait enfin **créer, lire, modifier et supprimer des documents** (pages éditeur) **dans un
> espace de travail** — la demande « crée un document « Projet » dans le workspace « TEST WS 1 » »
> ne se termine plus par un simple `search_workspace` vide. Il liste aussi les espaces, et **renomme
> automatiquement les conversations** avec un titre descriptif au lieu de « Nouvelle conversation ».
### Outils (nouveaux / corrigés)
- **`create_document`** : crée une page éditeur (`pages`) dans un espace (par `workspace_id` ou
`workspace_name`), avec contenu Markdown optionnel — snapshot d'undo.
- **`read_document`** : lit un document (titre + contenu + métadonnées).
- **`read_workspaces`** : liste les espaces accessibles (rôle, nb de documents/collections).
- **`delete_document`** : suppression → corbeille (`deleted_at`), annulable (`softdelete`).
- **`write_blocks`** étendu : renommage de titre et/ou écriture des blocs ; undo restaure titre + contenu.
- **`search_workspace`** étendu : recherche désormais aussi les **documents** et les **espaces de travail**.
### Contexte & planification
- Contexte de l'agent enrichi : sections « Documents » et « Espaces de travail » (avec ids) pour que
le LLM cible le bon espace. Guide mis à jour. Mock hors-ligne : détection
« créer un document dans un espace » / « lister les espaces ».
### Conversations
- Auto-titre : après la première exécution d'une conversation encore nommée « Nouvelle conversation »,
l'agent génère un titre descriptif (déterministe, hors-ligne sûr) ; l'historique devient navigable.
### UX
- Indication claire dans le composeur du panneau : **Entrée ↵ = envoyer · Maj+Entrée = nouvelle ligne**
(le comportement existait déjà, il est maintenant visible + placeholder mis à jour).
### Infra
- `VERSION` → 4.14.0 ; `app/main.py` version → 4.14.0.
## v4.13.2 (2026-09-06) — Saisie libre « écrire un texte » → proposition à appliquer au document
> Quand un **document est ouvert** et qu'on tape directement une demande de **rédaction/contenu**
> dans le chat (« Écrire un texte sur… », « Rédige… », « Résume… », « Traduis… »), la requête est
> maintenant routée vers la **génération de texte** (sans outils) et affichée comme **proposition
> à appliquer ou rejeter** — au lieu d'un `search_workspace` puis d'un simple « Objectif traité ».
> « Traduire » remplace le contenu de la page ; les autres demandes l'insèrent en fin de page.
### Fix
- Envoi libre avec contexte document : détection d'intention de contenu (écrire/rédiger/générer/
résumer/traduire/améliorer/note de réunion/texte sur/série…) → `POST /api/agent/generate` +
aperçu « ✓ Appliquer au document / ✕ Rejeter ».
- Mock : « écrire » (infinitif) reconnu comme verbe de rédaction.
### Infra
- `VERSION` → 4.13.2 ; `app/main.py` version → 4.13.2.
## v4.13.1 (2026-09-06) — Corrections actions contenu Agent & aperçu à approuver
> Corrige les actions de contenu sur document (« Résumer », « Traduire cette page », « Proposer
> des améliorations », « Créer une note de réunion ») qui partaient en recherche (`search_workspace`)
> sans retour utile, et ajoute un flux **aperçu des changements → Appliquer / Rejeter**.
### Fix
- **Le contenu du document n'est plus interprété comme des intentions d'outil** : le planificateur
(mock) n'analyse que l'objectif de l'utilisateur, jamais le texte injecté dans `# Contexte`. Un
document contenant « recherche », « collection », etc. ne déclenche plus `search_workspace` /
`create_collection` intempestifs.
- **Ask AI** n'emprunte plus le canal outil : il utilise la génération de texte directe.
### Added
- **Endpoint `POST /api/agent/generate`** : génération de texte **sans outils** (l'IA répond à
partir du contexte du document fourni, sans chercher/créer dans le workspace).
- **Aperçu & approbation** : les actions de contenu sur document affichent la **proposition** de
l'agent dans le panneau avec boutons **« ✓ Appliquer au document » / « ✕ Rejeter »**. Appliquer
insère la proposition (mode `insert`) ou **remplace** le contenu de la page (mode `replace` pour
« Traduire cette page ») via `window.fdApplyDocument()` ; rejeter la conserve sans modification.
En mode hors-ligne, l'action explique que la modification nécessite un modèle connecté (pas
d'application accidentelle).
### Infra
- `VERSION` → 4.13.1 ; `app/main.py` version → 4.13.1.
## v4.13.0 (2026-09-06) — Agent : panneau « Notion AI », ouverture fiable (Ctrl+J) & contexte universel
> Refonte complète du panneau Agent (style Notion AI) : ouverture/fermeture **fiable** (API
> `window.fdAgent.open/close/toggle`, bouton flottant + sidebar « Agents » + raccourci `Ctrl/Cmd+J`),
> **contexte détecté et épinglé à l'ouverture** (document en cours, bibliothèque, My Tasks,
> espaces, base de données, board, corbeille…) et sélecteur **fournisseur + modèle** intégré à la
> zone de saisie.
### Added
- **Ouverture robuste** : `window.fdAgent.open()/close()/toggle()` appliquent l'état directement
(classe `.open` + attribut) ; FAB, entrée « Agents » du sidebar, icône Chat et `fdAgent.ask`
ouvrent explicitement le panneau (fini le toggle silencieux). Raccourci **`Ctrl/Cmd+J`** global.
- **Contexte universel `window.FlowDeckCtx`** : détection par priorité —
(1) marqueur d'écran (`window.fdViewContext` / `data-fd-context`), (2) **document ouvert**
(éditeur : titre + contenu des blocs), (3) **route** de l'application (Accueil, Bibliothèque,
Corbeille, My Tasks, Espaces, Espace local/Gitea, Base `/db`, Board, Notes, Paramètres…).
Le contexte est **épinglé à l'ouverture** du panneau, affiché en chip (« Contexte : … ») et
**rafraîchi** automatiquement si l'utilisateur ouvre un autre document avant d'envoyer.
- **Fournisseur & modèle affichés** : sous-titre du panneau `Provider · Modèle` (ex. `OpenAI ·
gpt-4o`) dès qu'un modèle réel fonctionnel est sélectionné ; « hors-ligne (mock) » n'apparaît
que lorsqu'aucun fournisseur actif n'existe. Sélecteurs provider → modèle regroupés dans une
pastille « Auto · <model> » au-dessus de la zone de saisie.
- **Actions rapides contextuelles** (état vide) en français selon la section : Résumer / Traduire /
Améliorer un document, Créer une note de réunion, Analyser une base, Mes tâches / planifier,
ou guides « Comment utiliser FlowDeck ? » et création de collection/board.
### Changed
- **Panneau redessiné façon Notion AI** : largeur 470 px, en-tête « How can I help you today? »,
icône avatar, ligne de contexte, historique, grande `textarea` arrondie auto-redimensionnable
(jusqu'à ~220 px) avec toolbar (`+`-équivalent, contexte, modèle, flèche d'envoi) et sélection
de modèle en popover.
### Infra
- `VERSION` → 4.13.0 ; `app/main.py` version → 4.13.0.
## v4.12.1 (2026-09-05) — Corrections configuration Agent & IA + AI Meeting Note
> Correctifs UI sur la section **Settings → Agent & IA** et remplacement de l'ancien bouton
> « AI meeting note » (qui insérait du texte) par une vraie **boîte de réunion interactive**.
### Fix
- **Champs « Clé API »** : le `x-text` embarquait le SVG de l'icône œil dans l'attribut HTML, ce qui
cassait l'attribut et laissait du texte résiduel (`sk-…': '👁'" style="top:50%;">`). Les boutons
d'affichage/masquage utilisent désormais deux `<span x-show>` avec l'icône en contenu.
- **Champs « URL API »** : pré-remplis avec l'URL réellement utilisée par l'application (base par
défaut du fournisseur, ex. `https://api.openai.com/v1`) quand aucune URL personnalisée n'est
stockée — exposée via `base_url` dans `/api/agent/providers` (fournisseur par défaut + au
changement de provider).
### Changed
- **AI Meeting Note** : le bouton « Get started » ne génère plus du texte via l'agent. Il crée un
bloc **`meeting`** interactif dans la page (page renommée « Meeting @date » si vide) :
- Étape 1 — consentement (moi-même / message audio auto) + « Start transcribing » ;
- Étape 2 — transcription **live** via Web Speech API (fr-FR, horodatée), boutons Pause / Stop,
fallback « sans audio » (transcript à saisir/coller) si le navigateur ne supporte pas ;
- Étape 3 — onglets Notes / Transcript / Summary, bouton « Générer le résumé » (helper headless
`window.fdAgent.generate` sur le FlowDeck Agent) produisant Résumé / Décisions / Action items,
copie presse-papiers et « Nouvelle transcription ».
- Persistance du bloc et de son état dans la page (champ `meeting` ajouté aux blocs sauvegardés).
### Infra
- `VERSION` → 4.12.1 ; `app/main.py` version → 4.12.1.
## v4.12.0 (2026-09-05) — Agent & IA : refonte des réglages, fournisseurs activés/fonctionnels dans le panneau, contexte document & guide
> Refonte de la section **Settings → Agent & IA** pour la rendre plus claire, et aligne le panneau
> Agent sur la réalité de la configuration : **seuls les fournisseurs configurés ET dont le test de
> connexion a réussi** sont proposés (avant, tous les fournisseurs connus apparaissaient, même non
> configurés). Le panneau sait aussi sur quel **document** l'utilisateur travaille et peut guider
> sur l'utilisation de l'application quand aucun document n'est ouvert.
### Added
- **Vérification des fournisseurs** : colonnes `verified` / `verified_at` / `last_error` sur
`user_llm_keys` et `llm_config` (migration automatique au démarrage). Un fournisseur est
« fonctionnel » après un test de connexion réussi ou un chargement de modèles réussi.
- **Endpoint non-admin** `POST /api/agent/keys/{provider}/test` : teste la clé enregistrée de
l'utilisateur (sans mock) et met à jour l'état `verified` ; l'endpoint admin `/providers/test`
marque le fournisseur par défaut de l'espace.
- **`/api/agent/providers` enrichi** : chaque provider expose `configured`, `verified`,
`functional`, `last_error` et `source` (user/global/open) ; `default_provider` + `default_verified`
en tête de réponse.
- **Panneau Agent** : les listes fournisseur/modèle ne contiennent plus que les providers
**activés et fonctionnels** (+ mode hors-ligne). Bandeau « Aucun fournisseur activé » avec lien
vers les réglages et rappel des clés « à tester » le cas échéant.
- **Contexte document** : le panneau joint automatiquement la page ouverte (titre + contenu des
blocs) à chaque requête — l'agent peut interagir avec le document courant.
- **Guide d'utilisation** : le prompt système intègre un guide FlowDeck concis pour répondre aux
questions « comment faire… ? » (pages, collections/vues, Gitea, corbeille, réglages…) lorsqu'aucun
document n'est fourni.
### Changed
- **Settings → Agent & IA refondu** : carte de statut (prêt / N fournisseurs actifs / mode
hors-ligne), cartes de fournisseurs avec badges d'état, erreur du dernier test, boutons
« Enregistrer & tester », « Tester », « Modèles », « Supprimer » et encart d'aide.
- Le bouton **Save configuration** admin gagne un rappel « Tester la connexion » pour activer le
fournisseur pour tous ; changer de clé réinitialise la vérification.
### Fix
- Saisie clé : une clé vide conserve désormais l'existante aussi pour la config globale (au lieu de
l'effacer), et un changement de clé invalide l'ancien statut `verified`.
### Infra
- `VERSION` → 4.12.0 ; `app/main.py` version → 4.12.0.
## v4.11.1 (2026-09-05) — Correction & intégration des points d'entrée IA
> Aligne les entrées AI de l'interface sur le FlowDeck Agent (alignement Guide Notion AI) et corrige
> les trois boutons qui ne fonctionnaient pas : **Ask AI**, **AI meeting note** (toolbar « Get
> started » de l'éditeur de page) et le **bouton rond flottant FlowDeck Agent** (coin bas-droit).
### Fix
- **Bouton flottant Agent 🤖 (coin bas-droit)** : le chat restait inerte tant qu'aucune conversation
n'existait (`send()` retournait silencieusement sans `currentConv`). Ajout d'une création de
conversation **lazy** (`ensureConversation()`) effectuée avant chaque envoi — la 1ère saisie crée
la conversation puis l'exécute (mode offline ou LLM réel).
- **Mode hors-ligne plus utile** : le mock LLM (`_draft_reply`) génère désormais un **vrai contenu
structuré** pour les demandes de rédaction de page (« Ask AI », titre détecté via « intitulée »)
et les **AI meeting notes** (squelette Résumé / Décisions / Action items), au lieu de se contenter
de renvoyer le prompt tel quel — les boutons produisent donc du contenu même sans clé API.
- **« Ask AI » & « AI meeting note »** : ne faisaient qu'insérer du texte placeholder
(« Ask AI to write... » / « AI Meeting Note ») sans aucun appel IA. Ils déclenchent désormais une
**génération inline réelle** via le FlowDeck Agent :
- méthodes `askAI()` / `meetingNote()` / `aiRun()` / `applyAIBlocks()` sur l'éditeur de page ;
- un prompt contextuel est envoyé au panneau agent (exposition d'`window.fdAgent.ask`) ;
- la réponse (`event final` du flux SSE) est **insérée automatiquement dans la page** sous forme
de blocs édités (hook `window.__fdInsertAI`).
- Un état `aiBusy` évite les doubles envois pendant la génération.
### Infra
- `VERSION` → 4.11.1.
## v4.11.0 (2026-09-05) — Agent IA : clés API par utilisateur & chargement dynamique des modèles
> Suite de v4.10.1 : migre la config LLM d'un **global admin** vers des **credentials par
> utilisateur**. Chacun peut enregistrer plusieurs provider + clé API dans son profil, les modèles
> disponibles sont **chargés automatiquement depuis le fournisseur**, et le provider/modèle actif
> d'une conversation se pilote **directement dans le chat** via des commandes slash.
### Added
- **Clés par utilisateur** : table `user_llm_keys` (UNIQUE(user_id, provider)) + service
`app/services/llm_config.py` : `get_user_llm_key`, `list_user_llm_keys` (masqué),
`upsert_user_llm_key`, `delete_user_llm_key`. Une clé vide conserve l'existante.
- **Chargement dynamique des modèles** : `fetch_provider_models()` (httpx) — GET `{base}/models`
pour OpenAI-compatible (Bearer), headers `x-api-key`/`anthropic-version` (Anthropic),
`x-goog-api-key` (Gemini) ; stockés dans `models_json` et fusionnés dans `GET /providers`.
- **Endpoints API** (tout utilisateur authentifié) :
- `GET /api/agent/keys`, `PUT/DELETE /api/agent/keys/{provider}`,
- `POST /api/agent/keys/{provider}/models` (fallback sur la clé stockée, pas de fuite de clé),
- `PATCH /api/agent/conversations/{id}` (title / provider / model — commande slash).
- **`POST /run`** : utilise la clé API de l'utilisateur pour le provider de la conversation
(sinon config globale / `.env` / offline mock).
- **UI Settings → Agent & IA** (visible pour tous, plus seulement admin) : carte par provider
(clé API masquée, URL API, « Charger les modèles » en live, modèle par défaut,
Enregistrer / Supprimer). La config globale reste admin sous « Configuration globale ».
- **Commandes slash dans le panel agent** : `/help`, `/providers`, `/keys`,
`/provider <nom>`, `/model <nom>` — menu de suggestions live, appliquées via `PATCH`
et sans appel LLM.
### Infra
- `VERSION` → 4.11.0 ; migration idempotente (création table `user_llm_keys` + index).
### Tests
- **239 tests verts** (+7 : CRUD clés + masquage des secrets, isolation par utilisateur,
provider invalide, fetch modèles (clé stockée / body gagnant / erreur), PATCH conversation,
`/run` utilise la clé de l'utilisateur).
> Comble le trou UX de v4.10.0 : l'utilisateur pouvait discuter avec l'agent mais **ne pouvait
> configurer ni provider ni modèle**. Ajout d'un sélecteur provider/modèle dans le panneau, d'une
> config runtime persistée en base (table `llm_config`) et d'un écran admin avec test de connexion.
### Added
- **Sélecteur provider/modèle dans le panneau agent** (`agent_panel.html`) : deux `<select>`
(provider + modèles connus par provider) dans l'en-tête du chat, branchés sur `POST /run` et
**persistés par conversation** (colonnes `provider`/`model` sur `agent_conversations`,
migrées automatiquement). Bouton ⚙️ pointant vers la config admin.
- **Endpoints API** :
- `GET /api/agent/providers` enrichi : liste complète des providers avec modèles connus,
`requires_key`, `api_base` et `has_api_key`.
- `PATCH /api/agent/providers` (admin) : persiste provider/modèle/clé/base en runtime.
- `POST /api/agent/providers/test` (admin) : test de connexion **sans fallback mock**
(méthode `LLMClient.ping()`) ; le provider `offline` répond sans réseau.
- **Table `llm_config`** (1 ligne, id=1) + service `app/services/llm_config.py` :
précédence **base (runtime) > `.env`**, créée seulement au premier enregistrement.
- **Écran admin** : nouvelle section *Agent & IA* dans Settings (onglet Admin) : provider,
modèle, clé API (masquée / réaffichable), URL API optionnelle, boutons
**Save configuration** et **Test connection** avec retour d'état inline.
### Fixed
- `LLMClient.__init__` : le modèle par défaut suit maintenant la config runtime
(DB > `.env`) au lieu d'être toujours `gpt-4o` ; `PROVIDER_MODELS` documente les modèles
connus par provider.
### Infra
- `VERSION` → 4.10.1 ; migration idempotente des colonnes `agent_conversations.provider/model`.
### Tests
- **232 tests verts** (+6 : providers enrichi, PATCH config (admin + 403 non-admin),
test connexion offline, test connexion clé manquante, persistance provider/modèle par conversation).
## v4.10.0 (2026-09-05) — FlowDeck Agent : agent IA natif conversationnel
> Implémentation complète du pilier « Agent IA » : un agent ReAct intégré qui **agit** sur le
> workspace (pas seulement répond) — panneau de chat, boucle raisonnement→action, streaming SSE,
> 18 outils avec snapshots rollback, permissions par rôle, contexte automatique, custom agents,
> déclencheurs planifiés, skills réutilisables et multi-LLM (offline mock + 8 providers).
### Added
- **Interface conversationnelle** : panneau agent dans le sidebar (🤖 Agents) piloté par Alpine.js +
streaming SSE ; FAB ouvrant le chat ; historique de conversations.
- **Boucle ReAct** (`app/services/agent_engine.py`) : raisonnement → action → observation, max 12
itérations, budget de tokens, timeout, journal d'audit + fonction `undo_action()` (rollback).
- **Streaming SSE** : endpoint `/api/agent/conversations/{id}/run` qui émet `reasoning`, `action`
et `final` en temps réel.
- **18 outils** (`app/services/tool_registry.py`) : `search_workspace`, `read_collection`,
`read_page`, `create_collection`, `create_view`, `add_property`, `create_page`, `update_page`,
`write_blocks`, `add_relation`, `create_sub_item`, `add_dependency`, `apply_template`,
`delete_page`, `delete_collection`, `read_gitea_issues`, `sync_gitea`, `create_gitea_issue` —
chacun avec `ToolResult` + snapshot d'undo réversible.
- **Permissions** (`app/services/permission_manager.py`) : même ACL que l'utilisateur par rôle
workspace (viewer/editor/admin/owner) + gating des outils.
- **Contexte automatique** (`app/services/context_builder.py`) : snapshot du workspace actif,
collections, pages, mentions `@`, fichiers uploadés injectés dans le prompt système.
- **Multi-LLM** (`app/services/llm_client.py`) : OpenAI, Anthropic, Google, Ollama, DeepSeek,
QwenCloud, NVIDIA, OpenRouter + **offline mock** (planner déterministe, aucune clé requise).
- **Custom agents, skills, déclencheurs** : CRUD agents + conversations, `agent_*` tables
(`agents`, `agent_conversations`, `agent_messages`, `agent_actions`, `agent_skills`,
`agent_triggers`), skills (`/api/agent/skills`, apply), scheduler de fond pour triggers planifiés.
### Infra
- `VERSION` → 4.10.0 ; config LLM (`LLM_PROVIDER/MODEL/API_KEY/API_BASE`, `AGENT_MAX_*`) ;
exclusions CSRF `/api/agent` ; routeur agent + tâche scheduler dans le lifespan de `app/main.py`.
### Tests
- **226 tests verts** (+18 v4.10.0 : schéma DB, mock LLM, permissions, outils+undo, engine ReAct +
audit + rollback, CRUD agents/conversations, streaming SSE, skills, tools, providers).
## 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 `<table>` (en-tête `<th>`, corps `<td>`, 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 → `<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 `<p>` (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/<slug>`): TOC ancré, KaTeX, colonnes flex, toggle `<details>`
- 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