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 Memoryticketsystem-integration:assigneeNamewar im DTO vorhanden und live immer null). Fallback, falls nicht: das Ticket-MCPlist_assigned_itemszeigt, dass die Daten existieren — dessen Route inBandel.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, derenbandel:<id>noch in keiner Liste alsTicketRefexistiert, plus alle User-Listen (Id, Name, WorkingDir, verknüpftes Ticket-Projekt) als Zuordnungskontext.ImportItemAsync(itemId, listId?, ct)→ lädt Details viaGET /api/ticket/{id}(Beschreibung, HTML→Markdown über das bestehendeHtmlToMarkdown), legt einenIdle-Task an:TicketRef = bandel:<id>,CreatedBy = "ticketsystem", Beschreibung endet mitTicket #<id>und bei Kind-ItemsTeil 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 überTicketReflistenübergreifend statt nurt.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 = falsemit Grund, wenn das Ticketsystem nicht eingerichtet ist.import_ticket(ticketId, list = null)→ Bestätigungs-Record (created,taskNumber,listName,usedFallback,skippedReason).listakzeptiert 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-Wertimport_tickets(Converter inPrimeScheduleEntityConfiguration).TicketImportPrompt(analogDailyPrepPrompt): Prompt überPromptFiles(PromptKind.TicketImport), Args--allowedToolsnur die zwei Tools,--permission-mode acceptEdits. Prompt-Kern: Kandidaten holen, jedes Item der inhaltlich passenden Liste zuordnen (Projekt-Verknüpfung = Hinweis), bei Unsicherheitlistweglassen, 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 fixImportTickets, wieRunDailyPrepNow);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 wiePlanDayCommand. - 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 überticketAssignees, 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).