Siklus hidup tiket
Status tiket
Bagian berjudul “Status tiket”| Status | String penyimpanan | Deskripsi |
|---|---|---|
backlog |
backlog |
Tercatat, belum ditriase ke antrean aktif |
open |
open |
Sudah ditriase dan siap dikerjakan, belum dimulai |
inProgress |
inProgress |
Sedang dikerjakan secara aktif |
blocked |
blocked |
Sudah dimulai tetapi tertahan oleh hal eksternal |
inReview |
inReview |
Pekerjaan selesai, menunggu tinjauan |
done |
done |
Selesai dengan sukses (terminal) |
failed |
failed |
Selesai dengan galat (terminal) |
cancelled |
cancelled |
Ditinggalkan (terminal) |
Nilai status disimpan dalam camelCase (inProgress, inReview), tidak pernah in_progress. Nilai tersimpan yang null diurai sebagai open; nilai yang tidak dikenal melempar galat alih-alih dikonversi paksa.
tryParseLoose menerima alias yang diberikan agen, dengan mengabaikan huruf besar-kecil serta - / _ / spasi:
| Status | Alias yang diterima |
|---|---|
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 |
Transisi status
Bagian berjudul “Transisi status”backlog ──→ open ──→ inProgress ──→ inReview ──→ done │ │ │ │ └──→ failed ┘ └──→ blocked ──→ inProgress
Any non-terminal status ──→ cancelled; inReview ──→ failedGraf ini hanya mengikat agen dan otomatisasi. TicketWorkflowService.transitionStatus memeriksanya saat force bernilai false — alat MCP dan reconciler. Transisi ilegal di sana dicatat ke log dan diabaikan. Setiap perubahan status yang dipicu pengguna di UI meneruskan force: true dan melewati graf sepenuhnya, sehingga manusia boleh memindahkan tiket ke status mana pun yang tercantum di pemilih (semua status kecuali failed), termasuk membuka kembali tiket berstatus terminal. Agen menandai failed dengan fail_ticket.
Sebuah status selalu boleh bertransisi ke dirinya sendiri. Status terminal tidak memiliki sisi keluar.
| Dari | Target yang diizinkan |
|---|---|
backlog |
open, cancelled |
open |
inProgress, blocked, cancelled |
inProgress |
blocked, inReview, done, failed, cancelled |
blocked |
inProgress, cancelled |
inReview |
inProgress, done, failed, cancelled |
done |
— (terminal) |
failed |
— (terminal) |
cancelled |
— (terminal) |
Prioritas tiket
Bagian berjudul “Prioritas tiket”Disimpan sebagai bilangan bulat pada skala asli Linear 0–4. Nilai yang tidak dikenal diurai menjadi none.
| Prioritas | Disimpan sebagai |
|---|---|
none |
0 |
urgent |
1 |
high |
2 |
medium |
3 |
low |
4 |
Penyedia tiket
Bagian berjudul “Penyedia tiket”Nilai tersimpan yang tidak dikenal atau null diurai menjadi local.
| Penyedia | Status |
|---|---|
local |
Disimpan sepenuhnya di basis data ruang kerja; default |
linear |
Dimiliki jarak jauh, dicerminkan secara lokal |
Adaptor sinkronisasi berada di bawah packages/cc_infra/lib/src/tickets/sync/ untuk Linear,
GitHub Issues, Jira Cloud, dan ClickUp. GitHub Issues hanyalah vendor adaptor
sinkronisasi (vendorId: github) — bukan nilai TicketProvider, sehingga issue
GitHub yang ditarik disimpan dengan originKind: externalSync dan provider: local default. Pemetaan vendor berada di ticket_sync_links.
Asal-usul tiket
Bagian berjudul “Asal-usul tiket”createTicket menulis manual. Penarikan dari vendor menulis externalSync.
Anak yang didelegasikan tetap manual.
| Nilai | Arti |
|---|---|
manual |
Default pada createTicket (baris manusia, agen, dan delegasi) |
externalSync |
Ditetapkan oleh TicketSyncEngine saat penarikan dari vendor |
Kolom tiket
Bagian berjudul “Kolom tiket”Agregat ini mencakup dua urusan pada satu baris. Cermin (penyedia, kunci, judul, deskripsi, prioritas, label, status, stempel waktu) adalah cache untuk penyedia jarak jauh dan ditulis ulang sepenuhnya oleh penyegaran. Lapisan tambahan (penugasan, delegasi, space, induk, proyek, PR tertaut) hanya milik Control Center dan penyegaran tidak pernah menyentuhnya.
| Kolom | Tipe | Deskripsi |
|---|---|---|
id |
String |
UUID v4 |
workspaceId |
String |
Ruang kerja yang memiliki |
provider |
TicketProvider |
Backend yang memiliki data kanonis (default local) |
externalKey |
String? |
Kunci asli penyedia (mis. LIN-123). createTicket lokal menulis UUID terpisah di sini, bukan id baris |
url |
String? |
URL web pada penyedia jarak jauh |
title |
String |
Ringkasan singkat; tidak boleh kosong |
description |
String? |
Isi Markdown yang lebih panjang |
priority |
TicketPriority |
Default none |
labels |
List<String> |
Label bentuk bebas |
status |
TicketStatus |
Status kanonis yang dinormalisasi |
rawStatus |
String? |
Nama state asli penyedia jarak jauh, disimpan demi tampilan tanpa kehilangan informasi |
externalSyncedAt |
DateTime? |
Sinkronisasi multi-vendor terakhir; null hingga yang pertama. Pemetaan per vendor berada di ticket_sync_links |
parentTicketId |
String? |
Induk dalam pohon delegasi / perincian |
projectId |
String? |
Proyek yang memiliki; tidak pernah didorong ke jarak jauh |
assignedAgentId |
String? |
Id prinsipal penerima tugas (hanya metadata — menugaskan tidak mengirim apa pun) |
assigneeType |
PrincipalType |
Jenis prinsipal yang ditunjuk assignedAgentId — user atau agent (default agent) |
createdByType |
PrincipalType? |
Jenis prinsipal yang membuat tiket (user atau agent); null untuk baris lama/sistem |
createdById |
String? |
Id prinsipal pembuat |
assignedTeamId |
String? |
Tim penerima tugas (hanya metadata) |
delegatedByAgentId |
String? |
Agen yang mendelegasikan tiket ini |
delegationDepth |
int |
Kedalaman dalam rantai delegasi; akar bernilai 0, diperiksa terhadap batas kedalaman maksimum |
delegationRootTicketId |
String? |
Akar rantai delegasi; null untuk tiket akar |
spaceId |
String? |
Percakapan asal tiket dibentuk, atau space agen yang mendelegasikan |
errorMessage |
String? |
Ditetapkan saat status bernilai failed |
linkedPrIds |
List<String> |
Id node PR yang ditautkan ke tiket ini |
metadata |
Map<String, dynamic> |
Kantong bentuk bebas |
createdAt |
DateTime |
Waktu pembuatan |
startedAt |
DateTime? |
Saat pekerjaan dimulai |
blockedAt |
DateTime? |
Saat tiket tertahan |
cancelledAt |
DateTime? |
Saat tiket dibatalkan |
completedAt |
DateTime? |
Saat tiket selesai dengan sukses |
finishedAt |
DateTime? |
Saat tiket mencapai status terminal apa pun |
updatedAt |
DateTime |
Mutasi terakhir (penyegaran cermin atau perubahan lapisan tambahan) |
version |
int |
Penghitung konkurensi optimistis, ditambah pada setiap mutasi |
originKind |
TicketOriginKind |
Cara tiket dibuat (default manual) |
collaborators |
List<TicketCollaborator> |
Dihidrasi oleh repositori sesuai permintaan |
Turunan: isTerminal, isRemote (provider != local), isAssignedToUser, dan displayKey (externalKey ?? id — karena itu tiket lokal menampilkan UUID terpisah saat pembuatan, bukan id baris).
Relasi tiket
Bagian berjudul “Relasi tiket”Sisi tersimpan adalah baris berarah di ticket_links:
| Jenis | String penyimpanan | Arti |
|---|---|---|
blocks |
blocks |
Sumber memblokir target |
relatesTo |
relates_to |
Relasi simetris |
duplicateOf |
duplicate_of |
Sumber adalah duplikat dari target |
Kosakata yang dipakai UI dan ticket_relation adalah TicketRelationKind, yang diturunkan dari sisi tersimpan plus ujung mana yang menjadi subjek:
| Jenis | Diturunkan dari |
|---|---|
blockedBy |
Baris blocks dengan subjek sebagai target |
blocking |
Baris blocks dengan subjek sebagai sumber |
relatedTo |
Baris relates_to (simetris) |
duplicateOf |
Baris duplicate_of dengan subjek sebagai sumber |
duplicatedBy |
Baris duplicate_of dengan subjek sebagai target |
subIssueOf |
tickets.parent_ticket_id pada subjek |
parentOf |
tickets.parent_ticket_id pada tiket lainnya |
Tautan induk dan sub-isu bukan baris ticket_links — tautan itu berada di tickets.parent_ticket_id.
Peristiwa domain
Bagian berjudul “Peristiwa domain”Delapan kelas ini berada di packages/cc_domain/lib/core/domain/events/ticketing_events.dart. Tidak ada TicketStarted, TicketDelegated, TicketCollaboratorAdded, atau ExternalTicketWebhookReceived.
| Peristiwa | Dipicu saat |
|---|---|
TicketCreated |
Tiket dibuat |
TicketAssigned |
Tiket ditugaskan ke prinsipal atau tim |
TicketCompleted |
Pekerjaan selesai dengan sukses |
TicketFailed |
Pekerjaan gagal |
TicketCancelled |
Tiket dibatalkan |
TicketStatusChanged |
Setiap perubahan status |
TicketReassigned |
Tiket ditugaskan ulang |
TicketDetailsUpdated |
Judul, deskripsi, prioritas, atau label berubah |
TicketAssigned adalah sinyal audit dan notifikasi sekaligus pemicu pipeline. Penugasan kepada agen tidak memulai run apa pun — tidak ada pengirim tiket yang memantau assignedAgentId. Penugasan kepada tim adalah pengecualiannya: TeamRoutingService mengirimkan pemimpin tim. Menambahkan kolaborator menulis satu baris dan tidak menerbitkan apa pun. Webhook vendor diterapkan melalui TicketSyncEngine tanpa peristiwa domain.
Titik penyempitan mutasi
Bagian berjudul “Titik penyempitan mutasi”TicketWorkflowService memegang setiap mutasi.
| Mekanisme | Detail |
|---|---|
| Titik penyempitan tunggal | Semua mutasi dialirkan melalui _mutate, yang memuat barisnya dan memanggil _assertWorkspace sebelum menerapkan |
| Isolasi ruang kerja | _assertWorkspace melempar WorkspaceMismatchException saat workspaceId baris yang dimuat tidak cocok dengan milik pemanggil |
| Konkurensi optimistis | _mutate menulis dengan expectedVersion diatur ke version yang baru dibacanya dan mencoba ulang saat ConcurrencyConflictException dengan membaca ulang state yang baru |
| Klaim eksklusif | tryCheckout / releaseCheckout; agen kedua yang mengklaim tiket yang sudah di-checkout mendapat CheckoutConflictException |
| Pagar transisi | canTransitionTo, hanya diterapkan saat force bernilai false |