Files
flowdeck/docs/API_GUIDE_V6.md
T
bruno b5207216f1 feat: v6.0.0 PWA offline support
- manifest + icones, service worker (precache, network-first, Background Sync)

- module client FlowOffline (IndexedDB, queue, delta, flush) + hook editeur

- endpoints /api/v2/sync/{delta,batch,status} + moteur de sync (conflits LWW/orpheline/copie offline)

- migrations offline_sync_queue + sync_version (triggers)

- UI offline (banner, badge sync, toasts, icone dirty) + doc /help

- tests pytest (sync, migrations, SW, offline) + E2E Playwright; bump 6.0.0
2026-09-18 13:05:40 -04:00

36 KiB

Guide des API FlowDeck — Référence d'implémentation v6.0.0

Statut : référence de conception pour la mise en place de l'API publique complète (v6.0.0). Dernière mise à jour : 2026-09-04 Portée : inventaire de l'API existante, conventions cibles, design CRUD par ressource, webhooks, sécurité, checklist d'implémentation.


1. Vision & architecture

FlowDeck est API-first (FastAPI). Deux couches d'API coexistent :

Couche Préfixe Auth Usage
API interne (existant) /api, /workspace, /db, /board… Session cookie flowdeck_session + CSRF Le frontend HTMX/Alpine
API publique v1 (existant, lecture seule) /api/v1 Bearer token Intégrations externes minimales
API publique v2 (cible v6.0.0) /api/v2 Bearer token + scopes CRUD complet, usage externe (clone Notion API)

Principe : l'API v2 expose les mêmes opérations que l'API interne, mais avec une surcouche de contrôle (auth par token, scopes, pagination, filtres, erreurs normalisées). Elle est implémentée comme des wrappers sur les mêmes services/logique métier — jamais de duplication.

Règles d'or

  1. Un endpoint public = un wrapper autour de la logique existante (un seul chemin de code).
  2. L'API publique ne renvoie jamais de HTML, de secrets, ni de colonnes internes (password_hash, tokens OAuth).
  3. Toute mutation passe par les mêmes validations que l'UI (CSRF concerne l'UI seule ; les tokens remplacent CSRF).
  4. Versionnage par préfixe d'URL (/api/v1, /api/v2) — jamais de breaking change sur une version publiée.

2. État actuel — inventaire de l'API

2.1 Schéma global des routeurs (app/main.py)

Routeur Fichier Préfixe Rôle
auth routers/auth.py /auth Login OAuth/local, register, logout, sessions
dashboard routers/dashboard.py — Pages HTML (landing, workspace, settings…)
board routers/board.py /board Kanban Gitea (legacy, compatible)
notes routers/notes.py /notes Notes Markdown par projet
api routers/api.py /api Pages, workspaces, tags, trash, favoris, settings
webhooks routers/webhooks.py /api/webhook Réception webhooks Gitea (issues/PR/repo)
collections routers/collections.py /db Databases Notion-style (CRUD)
my_tasks routers/my_tasks.py /my-tasks Agrégation tâches
workspace routers/workspace.py /workspace Local workspace, arborescence, webhooks sortants
library routers/library.py /api/library Bibliothèque (sources local/Gitea/GitHub)
admin routers/admin.py /api/admin Admin utilisateurs + audit
gitea routers/gitea.py /api/gitea Projets, fichiers, commits, labels
github routers/github_routes.py /api/github Intégration GitHub
public_api routers/public_api.py /api/v1 API publique existante (lecture seule)
sharing routers/sharing.py /api Share/publish pages
sidebar_config routers/sidebar_config.py /api/sidebar Customisation sidebar
export routers/export.py /api/export Export MD/PDF/HTML/CSV
notifications routers/notifications.py /api/notifications Notifications in-app
collaboration routers/collaboration.py /api Commentaires inline, mentions, historique

2.2 Récapitulatif des endpoints existants (par domaine)

Liste non exhaustive côté pages HTML ; les endpoints API sont tous listés.

Auth & users

GET    /auth/login, /auth/register, /auth/callback, /auth/logout, /auth/user
POST   /auth/local-login, /auth/register, /auth/register/{owner}/{repo}
GET    /api/users, /api/users/me, /api/users/search
PUT    /api/users/me, /api/user/profile, /api/user/password
POST   /api/user/token, /api/settings/avatar, /api/settings/avatar-color, /api/settings/tags
GET    /api/settings/account, /api/settings/avatar/{filename}
PUT    /api/settings/tags/{tag_id}, /api/settings/tags/all (GET)
DELETE /api/settings/tags/{tag_id}, /api/user/forge/{provider}

Workspaces & membres

GET    /api/workspaces, POST /api/workspaces
GET    /api/workspace/{ws_id}/members, POST /api/workspace/{ws_id}/members
PUT    /api/workspace/{ws_id}/members/{user_id}, DELETE /api/workspace/{ws_id}/members/{user_id}
PUT    /api/workspaces/{ws_id}, DELETE /api/workspaces/{ws_id}
POST   /api/workspaces/{ws_id}/select

Pages (éditeur blocs)

GET    /api/pages/{page_id}, PUT /api/pages/{page_id}, DELETE /api/pages/{page_id}
POST   /api/pages (création), /api/pages/{page_id}/blocks, /api/pages/{page_id}/content
PUT    /api/pages/{page_id}/rename, /api/pages/{page_id}/move
POST   /api/pages/{page_id}/trash, /api/trash/{page_id}/restore
GET    /api/trash, DELETE /api/trash/{page_id}
POST   /api/pages/{page_id:int}/convert-to-database
GET    /api/local-workspace/tree, /api/sidebar/workspace-tree, /api/nav/menu
GET    /api/local-workspace/page-content/{page_id}, /children/{page_id}

Collections (databases)

GET    /db/{collection_id}/api (détail), DELETE /db/{collection_id}
POST   /db/inline/api (créer inline)
POST   /db/{id}/linked/api, /db/{id}/toggle-inline/api, PUT /db/{id}/toggle-task/api
GET    /db/{id}/sources/api, POST /db/{id}/sources/api, DELETE /db/{id}/sources/{sid}/api
GET    /db/{id}/properties/api, POST /db/{id}/properties/api
PUT    /properties/{prop_id}/api, DELETE /properties/{prop_id}/api
POST   /db/{id}/properties/relation, /db/{id}/properties/relation/link
GET    /db/{id}/views/api, POST /db/{id}/views/save-as, PUT /views/{view_id}/config
GET    /property-types/api

Collection pages & tâches

GET    /db/{id}/pages/api, POST /db/{id}/pages/api, PUT /pages/{page_id}/api, DELETE /pages/{page_id}/api
POST   /db/{id}/pages/{pid}/sub-items, GET /db/{id}/pages/{pid}/sub-items
GET    /db/{id}/pages/{pid}/dependencies/api, POST /db/{id}/pages/{pid}/dependencies/api
DELETE /db/{id}/pages/{pid}/dependencies/{dep_id}/api
POST   /db/{id}/pages/{pid}/auto-shift/api, /db/{id}/pages/{pid}/check-deps
GET    /db/{id}/pages/{pid}/status-aggregate
POST   /formula/evaluate, /rollup/compute

Sprints, dashboards, templates

GET/POST /workspace/collections/{id}/sprints, PUT/DELETE /workspace/collections/{id}/sprints/{sid}
POST /workspace/collections/{id}/sprints/{sid}/assign, DELETE .../assign/{page_id}
GET  /workspace/collections/{id}/sprints/burndown/{sid}
GET/POST/PUT/DELETE /workspace/collections/{id}/dashboards[/{did}]
GET/POST /workspace/collections/{id}/templates/page, PUT/DELETE .../templates/page/{tid}
POST .../templates/page/{tid}/apply
GET/POST /templates/database, POST /templates/database/{tid}/apply

Favoris, tags, recents

GET/POST /api/favorites, DELETE /api/favorites/{page_id}
GET/POST /db/{id}/pages/api… (tags par page via /api/local-workspace/items/{id}/tags)
GET    /api/local-workspace/tags, /api/local-workspace/tags/search
POST   /api/local-workspace/items/{id}/tags, DELETE .../tags/{tag_id}
GET    /api/recents, POST /api/recents/track

Partage & publication

POST /api/share/{page_id}, GET /api/pages/{page_id}/shares, DELETE /api/pages/{page_id}/share/{share_id}
POST /pages/{page_id}/share, POST /pages/{page_id}/publish, DELETE /pages/{page_id}/publish
GET  /public/{collection_id}, /published, /shared, /private, /p/{slug}

Commentaires & notifications (v4.9.0)

GET/POST /pages/{page_id}/comments, PUT/DELETE /comments/{comment_id}
POST /pages/{page_id}/mentions
GET /api/notifications, /api/notifications/unread-count
POST /api/notifications/read, /api/notifications/read-all

Historique

GET/POST /pages/{page_id}/history

Import / Export

GET  /api/collections/{id}/export/csv, POST /api/collections/{id}/import/csv
GET  /api/export/markdown|pdf|html (via /export et /markdown/{page_id}, /pdf/{page_id}, /html/{page_id})

Forge Gitea / GitHub

GET  /api/workspace/projects, POST /api/workspace/projects
GET  /projects/{owner}/{repo}/tree|labels|commits|private-pages|file
PUT  /projects/{owner}/{repo}/file, DELETE /projects/{owner}/{repo}/file
POST /projects/{owner}/{repo}/upload, /sync-labels, /private-pages
GET/POST /issues/{owner}/{repo}, PATCH /issues/{owner}/{repo}/{issue_id}
POST /api/sync/{owner}/{repo}, /api/ai-keywords/{owner}/{repo}/extract

Admin

GET  /api/admin/users, PUT /api/admin/users/{user_id}, DELETE /api/admin/users/{user_id}
GET  /audit, /api/frontend-errors, POST /api/frontend-error

Santé & divers

GET /api/health, /api/stats, /api/config, PUT /api/config, /api/favorites…
POST /api/move, /col-mapping (GET/DELETE/POST), /board-config/{owner}/{repo} (GET/POST)

2.3 API publique v1 existante (app/routers/public_api.py)

Méthode Route Description
POST /api/v1/token Génère un token fd_xxx (inséré dans user_tokens)
GET /api/v1/collections Liste des collections (id, name, description, icon, created_at)
GET /api/v1/collections/{id} Collection + ses pages
GET /api/v1/collections/{id}/pages Pages racine de la collection
GET /api/v1/pages/{page_id} Page détaillée
GET /api/v1/my-tasks Tâches (limit 50)

Auth v1 : header Authorization: Bearer <token>. Token par défaut : fd-public-key (fallback dev). Vérification dans la table user_tokens (colonne gitea_token).

Limites de v1 (ce que v2 doit corriger) :

  • Lecture seule — aucun POST/PUT/DELETE sur les ressources.
  • Un seul token par utilisateur (UNIQUE(gitea_user_id)) et stocké dans une table prévue pour les tokens Gitea.
  • Pas de scopes, pas d'expiration, pas de nom d'affichage, pas de révocation individuelle.
  • Pas de pagination, filtres, tri.
  • Pas de documentation OpenAPI en production (docs_url n'est actif qu'en DEBUG).

3. Conventions cibles pour l'API v2

3.1 Auth & tokens

Nouvelle table api_tokens (remplace l'usage détourné de user_tokens) :

CREATE TABLE api_tokens (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id     INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    name        TEXT NOT NULL DEFAULT 'default',      -- ex: "CI production"
    token_hash  TEXT NOT NULL UNIQUE,                 -- sha256 du token, jamais en clair
    scopes      TEXT NOT NULL DEFAULT 'read',         -- 'read' | 'read,write' | 'read,write,admin'
    expires_at  TIMESTAMP,                            -- NULL = jamais
    last_used_at TIMESTAMP,
    created_at  TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    revoked     INTEGER NOT NULL DEFAULT 0
);
  • Format token : fd_{user_id}_{urlsafe(32)} — l'utilisateur ne le voit qu'une fois. Stockage en sha256.
  • Crud tokens : POST /api/v2/tokens, GET /api/v2/tokens, DELETE /api/v2/tokens/{id} (révocation), POST /api/v2/tokens/rotate.
  • Scopes : read (GET), write (POST/PUT/PATCH), admin (gestion users/admin). Dépendance FastAPI require_scope("write").
  • Compat v1 : garder le fallback fd-public-key uniquement si settings.public_api_insecure_ok=true (défaut : false en prod).

3.2 Format des réponses

  • JSON brut (pas d'enveloppe {data: …}) — style Notion API.
  • Timestamps ISO-8601 UTC (2026-09-04T14:30:00Z). SQLite stocke YYYY-MM-DD HH:MM:SS → convertir dans le convertisseur de sortie.
  • IDs : entiers SQLite (int). Exposés tels quels (pas de UUID) — ponytail: garder int, passer en UUID seulement si exposition publique nécessaire.
  • Champs *_json stockés en SQLite (ex: property_values_json, config_json) → déjà parsés en objets JSON dans les réponses API.

3.3 Erreurs (RFC 7807 application/problem+json)

{
  "type": "https://flowdeck/api/errors/not-found",
  "title": "Resource not found",
  "status": 404,
  "detail": "Collection 42 n'existe pas",
  "instance": "/api/v2/collections/42"
}

Codes : 400 validation (détail = liste des champs), 401 token manquant/invalide, 403 scope insuffisant / permissions, 404 inexistant, 409 conflit (nom dupliqué, dépendance bloquante), 422 erreur de schéma (FastAPI), 429 rate limit, 500 interne.

Handler global : @app.exception_handler(HTTPException) + adaptation des erreurs internes → problème JSON pour tout préfixe /api/v2.

3.4 Pagination, filtres, tri

Pagination offset (simple, SQLite) :

GET /api/v2/collections?limit=30&offset=0
→ response headers: X-Total-Count: 142

Requête : limit (défaut 30, max 100), offset (défaut 0). Utilise SELECT COUNT(*) + LIMIT ? OFFSET ? — ponytail: offset OK jusqu'à ~10k lignes, passer à keyset (cursor) si besoin.

Filtres (par propriété de la ressource) :

GET /api/v2/collections/{id}/pages?filter[status]=Done&filter[assignee]=bruno
GET /api/v2/pages?query=mot&workspace_id=3

Convention : filter[<property>]=<value> (AND implicite), sort=<property>, sort=-<property> (desc), fields=a,b,c (projection).

Recherche FTS : réserver ?query= sur les listes → recherche plein texte (table FTS5 à créer, indexant pages + collection_pages).

3.5 Idempotence & mutations

  • POST de création accepte un header optionnel Idempotency-Key — sur conflit, renvoyer la ressource existante créée avec cette clé (table idempotency_keys).
  • Les PATCH sont partiels (seuls les champs présents sont modifiés).

3.6 Rate limiting par token

Étendre RateLimitMiddleware (actuellement 100 req/min/IP sur /api/, /board/api/, /auth/) :

  • /api/v2/* : quota par token (défaut 300 req/min, configurable par scope), en plus du quota IP.
  • Remplacer le store defaultdict in-memory par une clé composite (ip|token_id) — ponytail: in-memory OK mono-instance, Redis si multi-workers.
  • Header de réponse : X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
  • Exemptés : /api/health, /api/v2/tokens (auth).

4. Design des endpoints v2 — CRUD par ressource

Pour chaque ressource : table(s) SQLite, endpoints internes existants (réutilisables), endpoints publics v2 à créer. GET /collections → wrapper public_list_collections existant à enrichir ; les mutations s'appuient sur les routeurs collections.py (préfixe /db).

4.1 Users

Table users
Colonnes clés id, login, full_name, email, avatar_url, avatar_color, is_admin, is_active, auth_method, sidebar_config, notification_prefs
Interne GET/PUT /api/users/me, GET /api/users, PUT/DELETE /api/users/{id} (admin)

Endpoints publics v2 :

Méthode Route Description
GET /api/v2/users/me Profil du user courant (sans password_hash)
PATCH /api/v2/users/me Mettre à jour profil (full_name, email, avatar_color, notification_prefs)
GET /api/v2/users admin — lister (pagination)
GET /api/v2/users/search?q= Recherche par login/email (pour @mentions)

4.2 Workspaces & membres

Tables workspaces, workspace_members (role: owner/admin/editor/viewer)
Interne GET/POST /api/workspaces, PUT/DELETE /api/workspaces/{ws_id}, GET/POST /api/workspace/{ws_id}/members, PUT/DELETE …/members/{user_id}

Endpoints publics v2 :

Méthode Route Description
GET /api/v2/workspaces Workspaces de l'utilisateur (avec rôle)
POST /api/v2/workspaces Créer (body: name, settings_json)
GET /api/v2/workspaces/{id} Détail + membres
PATCH /api/v2/workspaces/{id} Renommer / settings
DELETE /api/v2/workspaces/{id} Supprimer (owner only)
GET /api/v2/workspaces/{id}/members Lister membres
POST /api/v2/workspaces/{id}/members Inviter (user_id ou email)
PATCH /api/v2/workspaces/{id}/members/{uid} Changer le rôle
DELETE /api/v2/workspaces/{id}/members/{uid} Retirer un membre

⚠️ Dépendance v6 : créer app/services/permission_manager.py (la roadmap y fait référence mais le fichier n'existe pas). Centraliser : require_workspace_role(ws_id, "editor"), can_read(workspace_id|collection_id|page_id, user).

4.3 Collections (databases)

Tables collections (+ workspace_id, created_by, is_inline, parent_page_id, is_task)
Interne POST /db/inline/api, GET/DELETE /db/{id}/api, POST /db/{id}/linked/api, POST /db/{id}/toggle-inline/api, PUT /db/{id}/toggle-task/api, sources (/db/{id}/sources/api)

Endpoints publics v2 :

Méthode Route Description
GET /api/v2/collections?workspace_id=&query= Liste (paginée) — wrapper de v1 enrichi
POST /api/v2/collections Créer (name, description, icon, workspace_id, schema_json)
GET /api/v2/collections/{id} Détail + pages (existant v1)
PATCH /api/v2/collections/{id} Renommer, icon, description, schema
DELETE /api/v2/collections/{id} Supprimer (cascade pages/vues/props)
POST /api/v2/collections/{id}/linked Créer une DB liée
POST /api/v2/collections/{id}/task toggler is_task
GET /api/v2/collections/{id}/sources Sources / DB liées — wrapper v1
POST /api/v2/collections/{id}/sources Ajouter une source
DELETE /api/v2/collections/{id}/sources/{sid} Retirer une source

4.4 Pages de collection (collection_pages)

Tables collection_pages (property_values_json, parent_id, position, gitea_issue_*)
Interne GET/POST /db/{id}/pages/api, GET/PUT/DELETE /pages/{page_id}/api, sub-items, dependencies, auto-shift, status-aggregate, move

Endpoints publics v2 :

Méthode Route Description
GET /api/v2/collections/{id}/pages?filter[status]=…&sort=… Lister (pagination, filtres, tri, fields)
POST /api/v2/collections/{id}/pages Créer (title, icon, property_values, parent_id)
GET /api/v2/pages/{id} Détail (propriétés parsées)
PATCH /api/v2/pages/{id} Titre, icon, position, property_values (merge)
DELETE /api/v2/pages/{id} Corbeille (soft delete via deleted_at)
POST /api/v2/pages/{id}/restore Restaurer
POST /api/v2/pages/{id}/move Reordonner (position / parent_id)
GET /api/v2/pages/{id}/sub-items Sous-tâches
POST /api/v2/pages/{id}/sub-items Créer sous-item
GET/POST/DELETE /api/v2/pages/{id}/dependencies[/{dep_id}] Dépendances

Détail property_values : objet JSON {"<property_id>": <valeur typée>} — utiliser property_types.py (validation/formatage) déjà en place.

4.5 Propriétés (collection_properties)

Colonnes clés name, prop_type (21 types), options_json, number_format, related_collection_id, reverse_name, relation_property_id, target_property_id, rollup_function, formula_expression, required, visible_in_views
Interne GET/POST /db/{id}/properties/api, PUT/DELETE /properties/{prop_id}/api, POST …/properties/relation, …/relation/link, POST /formula/evaluate, POST /rollup/compute, GET /property-types/api

Endpoints publics v2 :

Méthode Route Description
GET /api/v2/collections/{id}/properties Types + configuration (wrapper)
POST /api/v2/collections/{id}/properties Créer (name, prop_type, options…)
PATCH /api/v2/properties/{id} Modifier (options, required, formula, rollup…)
DELETE /api/v2/properties/{id} Supprimer
POST /api/v2/properties/{id}/relation Créer relation bidirectionnelle
POST /api/v2/properties/evaluate-formula Moteur formula (debug)
POST /api/v2/properties/compute-rollup Moteur rollup (debug)

4.6 Vues (collection_views) & Dashboards (collection_dashboards)

Interne GET /db/{id}/views/api, POST /db/{id}/views/save-as, PUT /views/{view_id}/config, GET/POST/PUT/DELETE /workspace/collections/{id}/dashboards[/{did}]
Méthode Route Description
GET /api/v2/collections/{id}/views Lister les vues (config_json parsé)
POST /api/v2/collections/{id}/views Créer (name, view_type, config)
PATCH /api/v2/views/{id} Modifier config (filtres, tri, group_by, layout)
DELETE /api/v2/views/{id} Supprimer
POST /api/v2/views/{id}/save-as Dupliquer sous un autre nom
GET/POST/PUT/DELETE /api/v2/collections/{id}/dashboards[/{did}] Dashboards (layout_json)

4.7 Commentaires (comments, v4.9.0)

Colonnes clés target_type ('page'/'collection_page'), target_id, user_id, body, parent_id, resolved, anchor_block_id, anchor_start, anchor_end
Interne GET/POST /pages/{page_id}/comments, PUT/DELETE /comments/{comment_id}, POST /pages/{page_id}/mentions
Méthode Route Description
GET /api/v2/pages/{id}/comments Lister (avec tri chronologique)
POST /api/v2/pages/{id}/comments Ajouter (body, anchor_block_id/start/end optionnels)
PATCH /api/v2/comments/{id} Éditer / résoudre (resolved: true)
DELETE /api/v2/comments/{id} Supprimer
POST /api/v2/pages/{id}/mentions Mentionner des users (déclenche notification + email)

4.8 Notifications (notifications)

ntype 'mention' / 'comment' / 'page' — resource_type, resource_id, url, is_read
Interne GET /api/notifications, GET /unread-count, POST /read, POST /read-all
Méthode Route Description
GET /api/v2/notifications?unread=1 Lister (pagination)
POST /api/v2/notifications/{id}/read Marquer lue
POST /api/v2/notifications/read-all Tout marquer lu
GET /api/v2/notifications/unread-count Compteur (badge)
PATCH /api/v2/users/me/preferences prefs email (comments/mentions)

4.9 Favoris & Tags & Recents

Tables favorites, tags (per-user), page_tags, recents
Interne GET/POST /api/favorites, DELETE /api/favorites/{page_id}, /api/settings/tags*, /api/local-workspace/items/{id}/tags*, /api/recents*
Méthode Route Description
GET /api/v2/favorites Lister
POST /api/v2/favorites Ajouter {page_id}
DELETE /api/v2/favorites/{page_id} Retirer
GET /api/v2/tags?q= Tags de l'utilisateur
POST /api/v2/tags Créer (name, color)
PUT/DELETE /api/v2/tags/{id} Modifier / supprimer
POST /api/v2/pages/{id}/tags Attacher {tag_id}
DELETE /api/v2/pages/{id}/tags/{tag_id} Détacher
GET /api/v2/recents?source_type= Récents (limit 20)

4.10 Partage & publication (page_shares)

Colonnes clés page_id, shared_with_user_id, shared_with_email, permission ('view'/'edit'), created_by + colonnes pages (is_published, publish_slug, is_shared, share_mode)
Interne POST /api/share/{page_id}, GET /api/pages/{id}/shares, DELETE /api/pages/{id}/share/{share_id}, POST /pages/{id}/publish, DELETE /pages/{id}/publish
Méthode Route Description
GET /api/v2/pages/{id}/shares Liste des accès
POST /api/v2/pages/{id}/shares Partager `{email
PATCH /api/v2/shares/{share_id} Changer permission
DELETE /api/v2/shares/{share_id} Révoquer
POST /api/v2/pages/{id}/publish Publier ({slug}) → page publique /p/{slug}
DELETE /api/v2/pages/{id}/publish Dé-publier

4.11 Historique (page_history)

Colonnes clés page_id, user_id, change_type, snapshot_json, created_at
Interne GET/POST /pages/{page_id}/history
Méthode Route Description
GET /api/v2/pages/{id}/history Liste des versions (change_type, created_at, user)
POST /api/v2/pages/{id}/history/restore Restaurer {history_id}

4.12 Sprints (sprints, sprint_pages)

Interne /workspace/collections/{id}/sprints[/{sid}], assign, burndown
Méthode Route Description
GET/POST /api/v2/collections/{id}/sprints Lister / créer
PATCH/DELETE /api/v2/sprints/{sid} Mettre à jour / supprimer
POST /api/v2/sprints/{sid}/assign Assigner {page_id, velocity_points}
DELETE /api/v2/sprints/{sid}/assign/{page_id} Retirer
GET /api/v2/sprints/{sid}/burndown Points (total/completed/remaining/ideal)

4.13 Templates (page_templates, database_templates)

Interne /workspace/collections/{id}/templates/page*, /templates/database*, apply
Méthode Route Description
GET/POST /api/v2/collections/{id}/templates Lister / créer un template de page
PATCH/DELETE /api/v2/templates/{tid} Modifier / supprimer
POST /api/v2/templates/{tid}/apply Instancier (crée une page depuis le template)
GET /api/v2/templates/database Templates de DB (Project tracker, CRM…)
POST /api/v2/templates/database/{tid}/apply Créer une collection depuis le template

4.14 Export & Import

Interne GET /api/collections/{id}/export/csv, POST /api/collections/{id}/import/csv, /export, /markdown/{page_id}, /pdf/{page_id}, /html/{page_id} (routers/export.py)
Méthode Route Description
GET /api/v2/pages/{id}/export `?format=markdown
GET /api/v2/collections/{id}/export/csv CSV
POST /api/v2/collections/{id}/import/csv Import CSV (multipart)

Les exports PDF/HTML/MD existent déjà (export.py) — v2 ne fait que les exposer avec auth token. Générer le fichier puis le renvoyer (FileResponse) ou une URL signée temporaire.

4.15 Forges (Gitea / GitHub)

Interne routers/gitea.py + services/gitea_client.py (adapter), routers/github_routes.py + services/github_adapter.py
Méthode Route Description
GET /api/v2/projects Projets forges liés (workspace)
GET /api/v2/projects/{owner}/{repo}/tree Arborescence
GET /api/v2/projects/{owner}/{repo}/file?path= Lire un fichier
PUT /api/v2/projects/{owner}/{repo}/file Écrire {path, content, message} (commit)
DELETE /api/v2/projects/{owner}/{repo}/file Supprimer (commit)
GET /api/v2/projects/{owner}/{repo}/commits?path= Historique
GET /api/v2/projects/{owner}/{repo}/issues Issues (provider-agnostic via ForgeAdapter)
PATCH /api/v2/issues/{provider}/{owner}/{repo}/{id} Mettre à jour

Cible v6 (roadmap) : interface ForgeAdapter commune (Gitea + GitHub) — les endpoints v2 consomment l'adapter, pas les clients bruts.

4.16 Admin & Audit

Interne routers/admin.py (/api/admin), /audit
Méthode Route Description
GET /api/v2/admin/users scope admin — lister (pagination)
PATCH /api/v2/admin/users/{id} Activer/désactiver, rôle admin
DELETE /api/v2/admin/users/{id} Supprimer
GET /api/v2/admin/audit-logs Dernières actions (login, exports, changements rôle)

4.17 Recherche

Métier FTS5 sur pages + collection_pages (+ tags) — table d'index à créer à la migration v6
Méthode Route Description
GET `/api/v2/search?query=&workspace_id=&type=page collection

4.18 Synchronisation offline (PWA)

Interne routers/sync.py + services/sync_engine.py — auth session (flowdeck_session), CSRF-exempt (/api/v2)
Méthode Route Description
GET /api/v2/sync/delta?since=<epoch>&workspace_id=<id> Changements serveur depuis since (pages créées/màj/supprimées, collections) → {changes, server_time, has_more}
POST /api/v2/sync/batch Rejoue un lot de mutations offline → {results, conflicts, server_time}
GET /api/v2/sync/status?workspace_id=<id> {pending_count, last_sync, is_syncing, server_time}

Format batch : {device_id, mutations:[{id, type, payload, client_timestamp}]} — type ∈ page_create|page_update|page_delete|page_move|collection_create|collection_update|collection_delete. page_update accepte base_version (colonne sync_version) pour la détection de conflit.

Conflits : edit_edit (last-write-wins + rapport), edit_delete (page orpheline recréée), create_create (renommage « … (copie offline) »). Chaque mutation est tracée dans offline_sync_queue.


5. Webhooks sortants (à étendre en v2)

Mécanisme existant (app/services/webhook_outbound.py) :

  • Table webhook_subscriptions: id, url, event, secret, active, created_at.
  • Événements actuels (8) :
EVENTS = [
    "page.created", "page.updated", "page.deleted",
    "collection.created", "collection.updated", "collection.deleted",
    "comment.added", "page.moved",
]
  • Dispatch fire_event(event, payload) → POST JSON avec headers X-FlowDeck-Event + X-FlowDeck-Secret.

Endpoints v2 webhooks (wrapper du CRUD sortant existant + gestion des abonnements) :

Méthode Route Description
GET /api/v2/webhooks Abonnements de l'utilisateur
POST /api/v2/webhooks Créer {url, event, secret}
PATCH /api/v2/webhooks/{id} Activer/désactiver, changer url/secret
DELETE /api/v2/webhooks/{id} Supprimer
POST /api/v2/webhooks/{id}/test Événement de test ping
GET /api/v2/webhooks/{id}/deliveries Journal des livraisons (à ajouter : table webhook_deliveries)

Événements à ajouter (parité Notion + besoins v6) :

"page.created", "page.updated", "page.deleted", "page.restored",
"collection.created", "collection.updated", "collection.deleted",
"collection_page.created", "collection_page.updated", "collection_page.deleted",
"comment.added", "comment.resolved",
"mention.created", "notification.created",
"sprint.created", "sprint.updated", "sprint.completed",
"share.created", "share.revoked", "page.published", "page.unpublished",
"agent.run.completed",

Payload type :

{
  "event": "page.updated",
  "data": { "id": 42, "workspace_id": 3, "updated_at": "2026-09-04T14:30:00Z" },
  "actor": { "id": 1, "login": "bruno" },
  "timestamp": "2026-09-04T14:30:00Z"
}
  • Signature : HMAC-SHA256 du body avec secret, header X-FlowDeck-Signature.
  • Retry : 3 tentatives (2s, 10s, 60s) + journal webhook_deliveries (status, http_code, error, duration_ms).

6. Schéma de données — résumé par ressource

Schéma complet dans app/db.py (init_db() + migrations). Tables principales :

Domaine Tables
Auth users, login_history, user_tokens (Gitea), user_oauth_tokens, api_tokens (à créer)
Kanban legacy boards, cards, col_mapping, checklists, checklist_items, notes
Pages pages (content_format='markdown'/'blocks', deleted_at, share_mode, is_published, publish_slug, is_shared, collection_id)
Databases collections, collection_pages, collection_views, collection_properties, collection_data_sources, collection_dashboards
Multi-utilisateur workspaces, workspace_members, comments (target_type/target_id/anchors), page_history, favorites, recents, page_shares
Templates database_templates, page_templates (is_recurring, recurrence_rule)
Tags tags (per-user), page_tags
Tâches page_dependencies (blocks/related, auto_shift), sprints, sprint_pages
Notifications notifications (+ users.notification_prefs)
Forges gitea_private_pages, (projets via adapters)
Webhooks webhook_subscriptions, webhook_deliveries (à créer)
Agent (v4.10.0 — à créer : agents, agent_conversations, agent_messages, agent_actions, agent_skills, agent_triggers)

Règles :

  • FKs avec ON DELETE CASCADE là où la suppression parent doit purger (pages, vues, props, membres, dépendances).
  • property_values_json, schema_json, config_json, layout_json, options_json : JSON textuel, parse/validate côté service (property_types.py).
  • WAL mode + PRAGMA foreign_keys=ON (déjà en place dans get_conn()).

7. Sécurité (v2)

Menace Contre-mesure
Token volé Hash sha256 en DB, révocation, rotation, expires_at, scopes minimaux
Rejeu CSRF N/A côté token (Bearer) ; l'UI garde son CSRF middleware
Brute force / abus Rate limit par token + par IP (middleware existant étendu), 429
Injection SQL SQL paramétré (? seul, jamais de f-string dans les requêtes)
XSS (contenu) Sanitisation à la sortie HTML (UI) ; l'API renvoie du JSON brut (aucun rendu)
Exfiltration de secrets Projection stricte : jamais password_hash, *_token, clés OAuth dans les réponses
CORS Configurer allow_origins pour les clients externes (settings v2)
Fichiers validate_upload() existant : extensions whitelist + 10 MB max
Audit Journaliser chaque mutation v2 (user, token_id, action, resource, ts) — table api_audit_log

8. OpenAPI & documentation

  • Activer docs_url="/docs" et redoc_url="/redoc" en production sur le routeur v2 uniquement (ou protéger par token admin).
  • Générer openapi.json à la release et le versionner dans docs/openapi-v2.json.
  • Tags OpenAPI par domaine (workspaces, collections, pages, properties, views, comments…).
  • Exemples request/response réels dans les docstrings (FastAPI le génère automatiquement en OpenAPI).
  • Garder docs_url=None tant que v1 est seule (comportement actuel), l'activer lors du merge v2.

9. Checklist d'implémentation v6.0.0 (ordre recommandé)

  1. Migration DB : table api_tokens (+ index sur token_hash), webhook_deliveries, api_audit_log, FTS5 index de recherche.
  2. PermissionManager (app/services/permission_manager.py) — prerequisite de toute la v2 : can_read/can_write/can_admin par workspace + collection + page.
  3. Conventions : handler d'erreurs RFC 7807, convertisseur ISO-8601, helper pagination (paginate(query, limit, offset)), dépendances require_scope.
  4. Wrappers v2 read : reprendre public_api.py → /api/v2 avec pagination/filtres (collections, pages, my-tasks).
  5. Wrappers v2 write : collections, pages, properties, views (mutation) — les plus demandés par les intégrations.
  6. Webhooks v2 : CRUD abonnements + déliveries + retry + signature HMAC + événements étendus.
  7. Reste des ressources : sprints, templates, dashboards, favoris, tags, partage, notifications, admin.
  8. Recherche FTS (/api/v2/search).
  9. OpenAPI : activer /docs + générer openapi-v2.json + exemples.
  10. Tests (tests/test_public_api_v2.py) : auth token + scopes, CRUD complet par ressource, pagination, erreurs, rate limit, webhook delivery (mock httpx). Cible : couverture ≥ 80 % sur le routeur v2.
  11. Documentation utilisateur : page /help + ce guide référencé depuis le README.

10. Références

  • Schéma DB : app/db.py
  • Routeurs existants : app/routers/*.py
  • Frontend : app/templates/*.html, static/js/app.js
  • Webhooks sortants : app/services/webhook_outbound.py
  • Types de propriétés : app/services/property_types.py
  • Roadmap : ROADMAP.md (v6.0.0 — API publique, realtime, synced blocks, web clipper, permissions granulaires)

11. Documents de conception détaillée v6.0.0

Chaque feature v6.0.0 dispose d'un document de conception détaillé dans /docs/ :

Feature Document Description
PWA V6_PWA_Progressive_Web_App.md Offline support, service worker, IndexedDB, sync batch
SSO/SAML V6_SSO_SAML_Enterprise_Auth.md SAML 2.0, OIDC, auto-provisioning, group mapping
Permissions granulaires V6_Granular_Permissions.md Page-level, property-level, collection-level, groupes
Web Clipper V6_Web_Clipper.md Extension navigateur, capture d'articles, OAuth

Note

: Le présent guide couvre la couche API v2 commune à toutes les features. Chaque document de conception ci-dessus détaille les endpoints, tables, services et UI spécifiques à sa feature.