Files
ClaudeDo/docs/superpowers/specs/2026-10-01-ticket-import-all-design.md
T

6.7 KiB

Ticket-Import über alle Projekte + Tagesplanung — Design

Datum: 2026-10-01 · Status: abgenommen

Ziel

Ein Lauf holt alle Mika zugewiesenen, offenen Ticket-Items (Tickets, Tasks, Subtasks) aus dem Bandel-Ticketsystem, lässt Claude jedes Item nach Inhalt der passenden ClaudeDo-Liste zuordnen und plant danach den Tag (bestehender FillMyDay-Lauf). Auslösbar per Button und als Prime-Schedule.

Warum nicht der bestehende Import

TicketImportService.ImportAsync arbeitet pro Liste über die feste Verknüpfung ListConfigEntity.TicketProjectId und nur für Board-Items vom Typ Ticket. Live-Stand 2026-10-01:

  • 6 von 10 offenen, zugewiesenen Items sind Tasks/Subtasks (z.B. 595/596/598/668 unter „Lager Technik Plugin“) — der heutige Import sieht sie nie.
  • Projekt „Lager“ (493) enthält Items für mehrere Repos (Hub Lagertechnik, SorterController) und ist mit zwei Listen verknüpft. Projekt→Liste ist die falsche Zuordnungsachse; Inhalt ist die richtige.
  • DueDate ist fast überall null, Priorität fast überall „Niedrig“ — was heute dran ist, entscheidet weiterhin FillMyDay, nicht die Ticketdaten.

Entscheidungen

Frage Entscheidung
Zuordnung Claude nach Inhalt (Titel, Parent, Projekt). Projekt-Verknüpfung einer Liste ist nur ein Hinweis.
Granularität Flach: jedes zugewiesene Ticket/Task/Subtask wird ein eigener ClaudeDo-Task. Parent steht in der Beschreibung. Keine Hierarchie.
Ablauf Ein Lauf, zwei Schritte: Zuordnungs-Lauf, danach FillMyDay — im selben PrimeRunner-Gate.
Kein Treffer Item geht in die Fallback-Liste (App-Setting). Signal für Mika: dafür fehlt eine Liste. Ist keine gesetzt → übersprungen und in der Zusammenfassung genannt.
Fallback anwenden Der Worker, nicht Claude: import_ticket ohne list → Fallback-Liste.

Komponenten

1. Datenquelle (Worker/Tickets/)

BandelTicketClient.GetAssignedItemsAsync(ct): GET /api/ticketsystem/pat/me (userName) → GET /api/ticketsystem/users/username/{u} (userId) → GET /api/board/global/{userId}. Filter wie bisher: ticketAssignees[].assigneeName == userName und statusId ∈ {1, 2}.

⚠️ Erster Implementierungsschritt: live verifizieren, bevor ein DTO geschrieben wird — liefert das globale Board Tasks/Subtasks (itemType 2/3) samt parentId/Parent-Titel und Projekt? Feldweise über alle Datensätze prüfen, nicht an einem Sample (siehe Memory ticketsystem-integration: assigneeName war im DTO vorhanden und live immer null). Fallback, falls nicht: das Ticket-MCP list_assigned_items zeigt, dass die Daten existieren — dessen Route in Bandel.APIs/TicketSystem-MCP nachschlagen.

Ebenfalls live prüfen: PATCH /api/ticket/{id}/status für ein Item vom Typ Task (Write-back muss für Tasks/Subtasks funktionieren; laut Bandel.APIs-Breadcrumb dieselbe Tabelle).

2. TicketImportService

  • GetCandidatesAsync(ct) → zugewiesene offene Items, deren bandel:<id> noch in keiner Liste als TicketRef existiert, plus alle User-Listen (Id, Name, WorkingDir, verknüpftes Ticket-Projekt) als Zuordnungskontext.
  • ImportItemAsync(itemId, listId?, ct) → lädt Details via GET /api/ticket/{id} (Beschreibung, HTML→Markdown über das bestehende HtmlToMarkdown), legt einen Idle-Task an: TicketRef = bandel:<id>, CreatedBy = "ticketsystem", Beschreibung endet mit Ticket #<id> und bei Kind-Items Teil von #<parentId> <parentTitle>. listId == null → AppSettings.TicketFallbackListId; ist die auch null → kein Task, Ergebnis meldet „übersprungen“. Bereits importiert (global) → No-op mit entsprechender Meldung.
  • Fix im bestehenden ImportAsync: Dedupe über TicketRef listenübergreifend statt nur t.ListId == listId — sonst legt „Aus Ticketsystem aktualisieren“ ein bereits global zugeordnetes Item ein zweites Mal an.

3. MCP-Tools (External-MCP, neue External/TicketMcpTools)

  • get_ticket_import_candidates() → { available, items[], lists[], fallbackList }. available = false mit Grund, wenn das Ticketsystem nicht eingerichtet ist.
  • import_ticket(ticketId, list = null) → Bestätigungs-Record (created, taskNumber, listName, usedFallback, skippedReason). list akzeptiert Name oder Id.

Konventionen aus src/ClaudeDo.Worker/CLAUDE.md gelten (C#-Default für optionale Parameter, kein nacktes Task-Return, Tool-Doku nach McpToolDocs).

4. Ablauf (Worker/Prime/)

  • PrimeActionKind.ImportTickets, DB-Wert import_tickets (Converter in PrimeScheduleEntityConfiguration).
  • TicketImportPrompt (analog DailyPrepPrompt): Prompt über PromptFiles (PromptKind.TicketImport), Args --allowedTools nur die zwei Tools, --permission-mode acceptEdits. Prompt-Kern: Kandidaten holen, jedes Item der inhaltlich passenden Liste zuordnen (Projekt-Verknüpfung = Hinweis), bei Unsicherheit list weglassen, am Ende Zusammenfassung (importiert pro Liste, Fallback, übersprungen).
  • PrimeRunner.RunImportTicketsAsync: Log einmal leeren, PrepStarted, Zuordnungs-Lauf, dann den FillMyDay-Teil (bestehende Logik ohne erneutes Leeren/PrepStarted), PrepFinished. Schlägt der Import fehl, läuft FillMyDay trotzdem (bestehende Tasks sind weiter planbar); das Outcome meldet den Importfehler.
  • Ist das Ticketsystem nicht eingerichtet, fällt der Lauf auf reines FillMyDay zurück.

5. Hub + UI

  • WorkerHub.RunTicketImportNow() (synthetischer Schedule, Kind fix ImportTickets, wie RunDailyPrepNow); IWorkerClient/WorkerClient + Test-Fakes nachziehen.
  • Prep-Panel (DetailsIslandView, neben „Plan day“): Button „Tickets + Tag planen“, nur sichtbar wenn das Ticketsystem eingerichtet ist; gleiche Enable-Logik wie PlanDayCommand.
  • Prime-Tab: neuer Aktionstyp wählbar.
  • Settings → Ticketsystem: Dropdown „Fallback-Liste“ (User-Listen + „keine“).
  • AppSettingsEntity.TicketFallbackListId (nullable) + EF-Migration. Locale-Keys en + de.

Tests

  • GetCandidatesAsync: Status-Filter, Assignee-Filter über ticketAssignees, globale Dedupe.
  • ImportItemAsync: explizite Liste, Fallback, keine Fallback-Liste → übersprungen, Duplikat.
  • ImportAsync: Item bereits in anderer Liste → nicht erneut angelegt.
  • PrimeRunner: ImportTickets → zwei Claude-Läufe in Reihenfolge, ein Gate, Import-Fehler blockiert FillMyDay nicht.
  • Fake-Client/Fake-Claude, kein echtes Claude. Live-Verifikation (Schritt 1) und Sichtprüfung der UI sind manuelle Punkte → docs/open.md.

Bewusst nicht drin

  • Rückabgleich „Ticket im Ticketsystem erledigt, Task in ClaudeDo noch offen“.
  • Ticket-Hierarchie als ClaudeDo-Parent/Subtasks.
  • Aktualisieren bereits importierter Items (würde Notizen überschreiben — gleiche Regel wie heute).