Feature #85
closedSecOps ticket type + Feature/Bug/SecOps ticketing tabs — extends #24/#70
0%
conversation:secops-tracker-tabs
Description
**Lié à :** #24/#70 · **Surface :** Client-Dashboard fullstack (`api/` + `src/`)
Les tickets de sécurité (hook scan→ticket) doivent être d'un **type distinct (tracker `SecOps`, id 4)** et le ticketing doit offrir des onglets **Feature / Bug / SecOps**.
**Backend (`api/`)** :
- `infrastructure/config.py` : `redmine_secops_tracker_id` défaut **4** (env `REDMINE_SECOPS_TRACKER_ID`).
- `infrastructure/redmine/scan_adapter.py` : `create_ticket` crée le ticket avec **tracker_id = SecOps (4)** (passer `tracker_id` à `RedmineClient.create_issue` ; l'ajouter au client si besoin).
- `domain/redmine/value_objects.py` : `RedmineIssue` porte le `tracker` (id + name) si pas déjà ; le board le lit.
- `domain/tasks/value_objects.py` + `application/task_board.py` : ajouter `category: "secops" | "bug" | "feature"` à `TaskSummary`/`TaskDetail` — `secops` si tracker==SecOps(4), sinon dérivé de la classification existante (#26 : `issue_type`/classification dans la description → `bug`|`feature`, défaut `feature`).
- `presentation/api/tasks.py` : exposer `category` sur `TaskSummaryOut` (+ detail). Pas de nouvel appel upstream.
**Frontend (`src/`)** :
- Une nav d'onglets **Feature / Bug / SecOps** au-dessus du board de ticketing (`app/projects/[id]/ticketing/page.tsx`), filtrant les colonnes par `task.category`. SecOps = uniquement les tickets de sécurité. Réutiliser les composants/tokens existants (pas de nouvelle couleur). i18n `en.ts`.
## Critères d'acceptation
- Les tickets créés par le hook scan→ticket sont de tracker **SecOps** (4).
- `TaskSummaryOut.category` = secops/bug/feature exposé (multi-tenant, pas d'appel upstream).
- Onglets Feature/Bug/SecOps filtrent le board ; SecOps n'affiche que les tickets de sécurité.
- FR/EN ; gates verts backend (pytest/ruff/mypy) + frontend (vitest/tsc/eslint/build). TDD.