- A29 — `app/services/publish.py` : slugify titré unique (fallback aléatoire), 404 si la page n'existe pas, événements centralisés. Les 3 paires publish/unpublish déléguent (sharing = front, board, v2) : · board : mise à jour aveugle → 404 + contrôle de session ajouté · board : perd `share_mode='anyone'` en bonus, v2 : perd `is_shared=1` — le share dialog reste l'unique propriétaire de ces drapeaux · v2 : slug fourni conservé, slug vidé aussi à la dépublication (avant : laissé) · `/users/me` ×2 et listings collections ×3 = contrats versionnés distincts, décision documentée (on garde) - Byproduct sécurité — `GET /api/users/me` (v1) et le contexte de `/accounts` faisaient `SELECT *` sur users → password_hash / login_attempts / locked_until exposés → colonnes whitelistées (liste v2) - A42 (partiel) — 9 copies de `Path(os.environ.get("FLOWDECK_DATA_DIR", "/data"))` → `settings.data_dir` (property : lecture à chaque accès, les tests monkeypatchent l'env) ; cache Gitea : évacuation des entrées expirées à chaque écriture. Reste : client httpx partagé (52 créations, cache par event loop) tests : test_publish_service_shared_and_safe, test_users_me_no_secret_columns, test_gitea_cache_evicts_expired suite **1034/1034** · `ruff check app tests` OK · OpenAPI 511 chemins / 7.5.0 docs (ROADMAP/CHANGELOG/WORKLOAD/VERSION) à jour