feat(0.30.0): colonnes personnalisables par espace + mapping étiquette ↔ colonne
CI / test (push) Successful in 2m17s

- Table board_columns par espace (clé immuable, nom/couleur/
  ordre libres, étiquette mappée + alias, drapeau Focus) ;
  définitions semées paresseusement depuis les valeurs
  historiques — sans personnalisation, comportement identique.
- Service app/board_columns.py : résolution, mapping
  étiquette→colonne (alias compris, ex. kanban_a_faire de
  Flowdeck), colonnes Focus/Wallboard.
- Board, API, adoption, miroirs d'étiquettes, déplacements,
  capture, santé, focus, wall, dashboard branchés sur les
  colonnes de l'espace ; validations dynamiques dans models
  (move_issue, set_column_order) et rules.
- Administration → Colonnes : ajouter (avant Terminé),
  renommer, réordonner, mapper, supprimer avec migration des
  cartes vers une colonne choisie, réinitialiser ; bouton
  🧱 Colonnes sur le board ; journal d'audit.
- Backlog et Terminé : colonnes système non supprimables.
- 254 tests verts (7 nouveaux, palier 20) ; smoke réel contre
  le vrai Gitea : création, affichage au board, suppression.
This commit is contained in:
Spark
2026-10-23 08:38:02 -04:00
parent 3964323abd
commit 28322c12cf
13 changed files with 1073 additions and 83 deletions
+4 -1
View File
@@ -20,6 +20,7 @@ rule can never close an issue or move a card between columns.
import json
from app import models
from app.models import KANBAN_COLUMNS
CONDITION_KEYS = {"column", "min_age_days", "label", "wip_over"}
@@ -60,7 +61,9 @@ def parse_rules(raw: str) -> tuple[list[dict], list[str]]:
"(fermer/déplacer une carte par règle est interdit en v1)"
)
continue
if "column" in when and when["column"] not in KANBAN_COLUMNS:
if "column" in when and when["column"] not in (
set(KANBAN_COLUMNS) | set(models.column_keys(1))
):
errors.append(f"{name} : colonne inconnue « {when['column']} »")
continue
if "min_age_days" in when and (