feat(palier-2): webhooks Gitea signés, flux SSE, étiquettes, milestones

- POST /webhooks/gitea: HMAC-SHA256 si KANBANTE_WEBHOOK_SECRET,
  applique fermetures/réouvertures externes de façon idempotente
  (l'écho de nos propres appels est un no-op, journal source=webhook),
  invalide le cache, diffuse sur le hub SSE
- GET /api/stream (SSE) + LiveHub; générateur testable séparément
- synchro d'étiquettes kanban:* à chaque déplacement (ensure/add/
  remove granulaires, étiquettes utilisateur intactes, flag
  KANBANTE_SYNC_LABELS, échec rapporté label_sync sans casser le move)
- board ?milestone=<titre|id>: filtre, échéance, progression;
  client: get_milestones, labels, invalidate_cache public
- dashboard: métriques 30 j du journal exposées au template
This commit is contained in:
Spark
2026-10-11 10:23:50 -04:00
parent 3cac4fe9c3
commit 23e63c7f6e
3 changed files with 302 additions and 7 deletions
+10 -1
View File
@@ -23,6 +23,11 @@ Environment variables:
warns, moves are never blocked.
KANBANTE_AGING_DAYS Days in the same column before a card is
flagged as aging (default 7; "stale" at 2x).
KANBANTE_WEBHOOK_SECRET Shared secret for the Gitea webhook
(POST /webhooks/gitea). When set, the
X-Gitea-Signature HMAC is enforced.
KANBANTE_SYNC_LABELS "1" (default) = mirror intermediate
columns to Gitea labels named kanban:<col>.
"""
import os
@@ -31,7 +36,7 @@ from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
APP_VERSION = "0.3.0"
APP_VERSION = "0.4.0"
def _env_bool(name: str, default: bool) -> bool:
@@ -81,6 +86,8 @@ class Settings:
sync_gitea: bool = True
wip_limits: dict | None = None
aging_days: int = 7
webhook_secret: str = ""
sync_labels: bool = True
@property
def auth_enabled(self) -> bool:
@@ -104,4 +111,6 @@ def get_settings() -> Settings:
sync_gitea=_env_bool("KANBANTE_SYNC_GITEA", True),
wip_limits=_env_wip_limits("KANBANTE_WIP_LIMITS"),
aging_days=_env_int("KANBANTE_AGING_DAYS", 7),
webhook_secret=os.getenv("KANBANTE_WEBHOOK_SECRET", ""),
sync_labels=_env_bool("KANBANTE_SYNC_LABELS", True),
)