Cykl życia zgłoszenia
Statusy zgłoszeń
Dział zatytułowany „Statusy zgłoszeń”| Status | Zapisany ciąg | Opis |
|---|---|---|
backlog |
backlog |
Zarejestrowane, jeszcze nieprzeniesione do aktywnej kolejki |
open |
open |
Rozpatrzone i gotowe do pracy, jeszcze nie rozpoczęte |
inProgress |
inProgress |
Praca trwa |
blocked |
blocked |
Rozpoczęte, ale zablokowane przez coś zewnętrznego |
inReview |
inReview |
Praca wykonana, oczekuje na recenzję |
done |
done |
Zakończone pomyślnie (stan końcowy) |
failed |
failed |
Zakończone błędem (stan końcowy) |
cancelled |
cancelled |
Porzucone (stan końcowy) |
Wartości statusu są zapisywane w camelCase (inProgress, inReview), nigdy jako in_progress. Zapisana wartość null jest parsowana jako open; nieznana wartość zgłasza wyjątek, a nie jest rzutowana.
tryParseLoose przyjmuje aliasy podane przez agenta, ignorując wielkość liter oraz znaki - / _ / spację:
| Status | Akceptowane aliasy |
|---|---|
open |
todo, ready, pending, new |
inProgress |
doing, started, active, wip |
blocked |
stuck |
inReview |
review, reviewing |
done |
closed, complete, completed, finished |
failed |
error, errored |
cancelled |
canceled, abandoned, dropped |
Przejścia statusów
Dział zatytułowany „Przejścia statusów”backlog ──→ open ──→ inProgress ──→ inReview ──→ done │ │ │ │ └──→ failed ┘ └──→ blocked ──→ inProgress
Any non-terminal status ──→ cancelled; inReview ──→ failedTen graf wiąże wyłącznie agentów i automatyzację. TicketWorkflowService.transitionStatus sprawdza go, gdy force ma wartość false — czyli w narzędziach MCP i reconcilerach. Niedozwolone przejście jest tam logowane i ignorowane. Każda zmiana statusu wywołana przez użytkownika w interfejsie przekazuje force: true i całkowicie omija graf, więc człowiek może przenieść zgłoszenie do dowolnego statusu z listy selektora (każdego poza failed), w tym ponownie otworzyć stan końcowy. Agenci oznaczają failed za pomocą fail_ticket.
Status może zawsze przejść sam w siebie. Stany końcowe nie mają krawędzi wychodzących.
| Ze stanu | Dozwolone stany docelowe |
|---|---|
backlog |
open, cancelled |
open |
inProgress, blocked, cancelled |
inProgress |
blocked, inReview, done, failed, cancelled |
blocked |
inProgress, cancelled |
inReview |
inProgress, done, failed, cancelled |
done |
— (stan końcowy) |
failed |
— (stan końcowy) |
cancelled |
— (stan końcowy) |
Priorytety zgłoszeń
Dział zatytułowany „Priorytety zgłoszeń”Przechowywany jako liczba całkowita w natywnej skali 0–4 Linear. Nieznana wartość jest parsowana jako none.
| Priorytet | Zapisywany jako |
|---|---|
none |
0 |
urgent |
1 |
high |
2 |
medium |
3 |
low |
4 |
Dostawcy zgłoszeń
Dział zatytułowany „Dostawcy zgłoszeń”Nieznana zapisana wartość lub wartość null jest parsowana jako local.
| Dostawca | Status |
|---|---|
local |
Przechowywane w całości w bazie obszaru roboczego; wartość domyślna |
linear |
Należące do systemu zdalnego, odzwierciedlane lokalnie |
Adaptery synchronizacji znajdują się w packages/cc_infra/lib/src/tickets/sync/ dla Linear,
GitHub Issues, Jira Cloud i ClickUp. GitHub Issues jest wyłącznie dostawcą adaptera
synchronizacji (vendorId: github) — nie jest wartością TicketProvider, więc pobrane
zgłoszenie z GitHub jest zapisywane z originKind: externalSync i domyślnym
provider: local. Mapowanie dostawcy znajduje się w ticket_sync_links.
Pochodzenie zgłoszenia
Dział zatytułowany „Pochodzenie zgłoszenia”createTicket zapisuje manual. Pobranie od dostawcy zapisuje externalSync. Delegowane
zgłoszenia potomne pozostają manual.
| Wartość | Znaczenie |
|---|---|
manual |
Wartość domyślna w createTicket (wiersze człowieka, agenta i delegowane) |
externalSync |
Ustawiana przez TicketSyncEngine przy pobraniu od dostawcy |
Pola zgłoszenia
Dział zatytułowany „Pola zgłoszenia”Agregat obejmuje dwa zagadnienia w jednym wierszu. Kopia lustrzana (dostawca, klucze, tytuł, opis, priorytet, etykiety, statusy, znaczniki czasu) jest pamięcią podręczną dla zdalnego dostawcy i jest w całości przepisywana przez odświeżenie. Nakładka (przypisanie, delegowanie, przestrzeń, element nadrzędny, projekt, powiązane PR-y) należy wyłącznie do Control Center i odświeżenie nigdy jej nie dotyka.
| Pole | Typ | Opis |
|---|---|---|
id |
String |
UUID v4 |
workspaceId |
String |
Obszar roboczy będący właścicielem |
provider |
TicketProvider |
Backend będący właścicielem danych kanonicznych (domyślnie local) |
externalKey |
String? |
Klucz natywny dla dostawcy (np. LIN-123). Lokalny createTicket zapisuje tutaj osobny UUID, a nie id wiersza |
url |
String? |
URL internetowy u zdalnego dostawcy |
title |
String |
Krótkie podsumowanie; nie może być puste |
description |
String? |
Dłuższa treść w formacie Markdown |
priority |
TicketPriority |
Domyślnie none |
labels |
List<String> |
Etykiety o dowolnej treści |
status |
TicketStatus |
Znormalizowany status kanoniczny |
rawStatus |
String? |
Natywna nazwa stanu u zdalnego dostawcy, zachowana na potrzeby bezstratnego wyświetlania |
externalSyncedAt |
DateTime? |
Ostatnia synchronizacja wielu dostawców; null aż do pierwszej. Mapowanie poszczególnych dostawców znajduje się w ticket_sync_links |
parentTicketId |
String? |
Element nadrzędny w drzewie delegowania / podziału |
projectId |
String? |
Projekt będący właścicielem; nigdy nie jest wysyłany do systemu zdalnego |
assignedAgentId |
String? |
Identyfikator przypisanego podmiotu (tylko metadane — przypisanie nic nie wysyła) |
assigneeType |
PrincipalType |
Rodzaj podmiotu, który wskazuje assignedAgentId — user lub agent (domyślnie agent) |
createdByType |
PrincipalType? |
Rodzaj podmiotu, który utworzył zgłoszenie (user lub agent); null dla wierszy zastanych/systemowych |
createdById |
String? |
Identyfikator podmiotu tworzącego |
assignedTeamId |
String? |
Przypisany zespół (tylko metadane) |
delegatedByAgentId |
String? |
Agent, który delegował to zgłoszenie |
delegationDepth |
int |
Głębokość w łańcuchu delegowania; korzeń to 0, sprawdzana względem pułapu maksymalnej głębokości |
delegationRootTicketId |
String? |
Korzeń łańcucha delegowania; null dla zgłoszenia korzenia |
spaceId |
String? |
Rozmowa, z której wyodrębniono zgłoszenie, albo przestrzeń delegującego agenta |
errorMessage |
String? |
Ustawiany, gdy status ma wartość failed |
linkedPrIds |
List<String> |
Identyfikatory węzłów PR, z którymi powiązano to zgłoszenie |
metadata |
Map<String, dynamic> |
Dowolny zbiór wartości |
createdAt |
DateTime |
Czas utworzenia |
startedAt |
DateTime? |
Czas rozpoczęcia pracy |
blockedAt |
DateTime? |
Czas zablokowania zgłoszenia |
cancelledAt |
DateTime? |
Czas anulowania zgłoszenia |
completedAt |
DateTime? |
Czas pomyślnego zakończenia zgłoszenia |
finishedAt |
DateTime? |
Czas osiągnięcia dowolnego stanu końcowego przez zgłoszenie |
updatedAt |
DateTime |
Ostatnia mutacja (odświeżenie kopii lustrzanej lub zmiana nakładki) |
version |
int |
Licznik współbieżności optymistycznej, zwiększany przy każdej mutacji |
originKind |
TicketOriginKind |
Sposób utworzenia zgłoszenia (domyślnie manual) |
collaborators |
List<TicketCollaborator> |
Uzupełniani przez repozytorium na żądanie |
Wartości pochodne: isTerminal, isRemote (provider != local), isAssignedToUser oraz displayKey (externalKey ?? id — zgłoszenia lokalne wyświetlają więc osobny UUID z czasu utworzenia, a nie id wiersza).
Relacje zgłoszeń
Dział zatytułowany „Relacje zgłoszeń”Zapisane krawędzie to skierowane wiersze w ticket_links:
| Typ | Zapisany ciąg | Znaczenie |
|---|---|---|
blocks |
blocks |
Źródło blokuje cel |
relatesTo |
relates_to |
Relacja symetryczna |
duplicateOf |
duplicate_of |
Źródło jest duplikatem celu |
Słownictwo, którym posługują się interfejs i ticket_relation, to TicketRelationKind, wyprowadzane z zapisanej krawędzi oraz z tego, na którym końcu znajduje się podmiot:
| Rodzaj | Wyprowadzany z |
|---|---|
blockedBy |
Wiersz blocks, w którym podmiot jest celem |
blocking |
Wiersz blocks, w którym podmiot jest źródłem |
relatedTo |
Wiersz relates_to (symetrycznie) |
duplicateOf |
Wiersz duplicate_of, w którym podmiot jest źródłem |
duplicatedBy |
Wiersz duplicate_of, w którym podmiot jest celem |
subIssueOf |
tickets.parent_ticket_id w podmiocie |
parentOf |
tickets.parent_ticket_id w drugim zgłoszeniu |
Powiązania nadrzędne i podzgłoszenia nie są wierszami ticket_links — żyją w tickets.parent_ticket_id.
Zdarzenia domenowe
Dział zatytułowany „Zdarzenia domenowe”Te osiem klas znajduje się w packages/cc_domain/lib/core/domain/events/ticketing_events.dart. Nie istnieje TicketStarted, TicketDelegated, TicketCollaboratorAdded ani ExternalTicketWebhookReceived.
| Zdarzenie | Wyzwalane, gdy |
|---|---|
TicketCreated |
Zgłoszenie zostaje utworzone |
TicketAssigned |
Zgłoszenie zostaje przypisane do podmiotu lub zespołu |
TicketCompleted |
Praca kończy się pomyślnie |
TicketFailed |
Praca kończy się niepowodzeniem |
TicketCancelled |
Zgłoszenie zostaje anulowane |
TicketStatusChanged |
Dowolna zmiana statusu |
TicketReassigned |
Zgłoszenie zostaje przypisane ponownie |
TicketDetailsUpdated |
Zmienia się tytuł, opis, priorytet lub etykiety |
TicketAssigned jest sygnałem audytowym i powiadomieniem oraz wyzwalaczem potoku. Przypisanie do agenta nie rozpoczyna żadnego uruchomienia — nie istnieje dyspozytor zgłoszeń, który obserwuje assignedAgentId. Wyjątkiem jest przypisanie do zespołu: TeamRoutingService wysyła lidera zespołu. Dodanie współpracownika zapisuje wiersz i niczego nie publikuje. Webhook dostawcy jest stosowany przez TicketSyncEngine bez zdarzenia domenowego.
Punkt kontrolny mutacji
Dział zatytułowany „Punkt kontrolny mutacji”TicketWorkflowService włada każdą mutacją.
| Mechanizm | Szczegóły |
|---|---|
| Pojedynczy punkt kontrolny | Wszystkie mutacje przechodzą przez _mutate, który wczytuje wiersz i wywołuje _assertWorkspace przed zastosowaniem zmian |
| Izolacja obszarów roboczych | _assertWorkspace zgłasza WorkspaceMismatchException, gdy workspaceId wczytanego wiersza nie zgadza się z obszarem wywołującego |
| Współbieżność optymistyczna | _mutate zapisuje z expectedVersion ustawionym na version, którą właśnie odczytał, a przy ConcurrencyConflictException ponawia próbę po odczytaniu świeżego stanu |
| Wyłączność przejęcia | tryCheckout / releaseCheckout; drugi agent próbujący przejąć już przejęte zgłoszenie otrzymuje CheckoutConflictException |
| Strażnik przejść | canTransitionTo, stosowany tylko wtedy, gdy force ma wartość false |