Bỏ qua để đến nội dung

Vòng đời phiếu

Trạng thái Chuỗi lưu trữ Mô tả
backlog backlog Đã ghi nhận, chưa được phân loại vào hàng đợi đang chạy
open open Đã phân loại và sẵn sàng để làm, chưa bắt đầu
inProgress inProgress Đang được xử lý
blocked blocked Đã bắt đầu nhưng bị chặn bởi một thứ gì đó bên ngoài
inReview inReview Đã xong việc, đang chờ đánh giá
done done Hoàn tất thành công (trạng thái kết thúc)
failed failed Kết thúc với lỗi (trạng thái kết thúc)
cancelled cancelled Bị bỏ dở (trạng thái kết thúc)

Các giá trị trạng thái được lưu ở dạng camelCase (inProgress, inReview), không bao giờ là in_progress. Một giá trị lưu là null được phân tích thành open; một giá trị không xác định sẽ ném lỗi thay vì ép kiểu.

tryParseLoose chấp nhận các bí danh do agent cung cấp, bỏ qua chữ hoa chữ thường và - / _ / dấu cách:

Trạng thái Bí danh được chấp nhận
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
backlog ──→ open ──→ inProgress ──→ inReview ──→ done
│ │ │
│ └──→ failed ┘
└──→ blocked ──→ inProgress
Any non-terminal status ──→ cancelled; inReview ──→ failed

Đồ thị này chỉ ràng buộc agent và tự động hóa. TicketWorkflowService.transitionStatus kiểm tra nó khi force là false — tức các công cụ MCP và các bộ đối soát. Một chuyển trạng thái không hợp lệ ở đó sẽ bị ghi log và bỏ qua. Mọi thay đổi trạng thái do người dùng thực hiện trong giao diện đều truyền force: true và bỏ qua hoàn toàn đồ thị, nên con người có thể chuyển một phiếu sang bất kỳ trạng thái nào mà hộp chọn liệt kê (mọi trạng thái trừ failed), kể cả mở lại một trạng thái kết thúc. Agent đánh dấu failed bằng fail_ticket.

Một trạng thái luôn có thể chuyển sang chính nó. Các trạng thái kết thúc không có cạnh đi ra.

Từ Đích được phép
backlog open, cancelled
open inProgress, blocked, cancelled
inProgress blocked, inReview, done, failed, cancelled
blocked inProgress, cancelled
inReview inProgress, done, failed, cancelled
done — (trạng thái kết thúc)
failed — (trạng thái kết thúc)
cancelled — (trạng thái kết thúc)

Được lưu dưới dạng số nguyên theo thang 0–4 gốc của Linear. Một giá trị không xác định được phân tích thành none.

Độ ưu tiên Lưu dưới dạng
none 0
urgent 1
high 2
medium 3
low 4

Một giá trị lưu không xác định hoặc null được phân tích thành local.

Nhà cung cấp Trạng thái
local Được lưu hoàn toàn trong cơ sở dữ liệu không gian làm việc; mặc định
linear Do hệ thống từ xa sở hữu, được sao gương cục bộ

Các adapter đồng bộ nằm trong packages/cc_infra/lib/src/tickets/sync/ cho Linear, GitHub Issues, Jira Cloud và ClickUp. GitHub Issues chỉ là một vendor của adapter đồng bộ (vendorId: github) — nó không phải là một giá trị TicketProvider, nên một issue GitHub được kéo về sẽ được lưu với originKind: externalSync và provider: local mặc định. Ánh xạ vendor nằm trên ticket_sync_links.

createTicket ghi manual. Một lần kéo từ vendor ghi externalSync. Các phiếu con được ủy thác vẫn giữ manual.

Giá trị Ý nghĩa
manual Mặc định trên createTicket (hàng do con người, agent và ủy thác tạo)
externalSync Được TicketSyncEngine đặt khi kéo từ vendor

Thực thể tổng hợp trải hai mối quan tâm trên cùng một hàng. Bản gương (nhà cung cấp, khóa, tiêu đề, mô tả, mức ưu tiên, nhãn, trạng thái, dấu thời gian) là bộ đệm cho một nhà cung cấp từ xa và bị một lần làm mới ghi lại toàn bộ. Lớp phủ (phân công, ủy thác, space, phiếu cha, dự án, các PR được liên kết) chỉ thuộc về Control Center và một lần làm mới không bao giờ chạm tới nó.

Trường Kiểu Mô tả
id String UUID v4
workspaceId String Không gian làm việc sở hữu
provider TicketProvider Backend sở hữu dữ liệu chuẩn tắc (mặc định local)
externalKey String? Khóa gốc của nhà cung cấp (ví dụ LIN-123). createTicket cục bộ ghi một UUID riêng vào đây, chứ không phải id của hàng
url String? URL web trên nhà cung cấp từ xa
title String Tóm tắt ngắn; không được để trống
description String? Nội dung Markdown dài hơn
priority TicketPriority Mặc định none
labels List<String> Nhãn tự do
status TicketStatus Trạng thái chuẩn hóa chuẩn tắc
rawStatus String? Tên trạng thái gốc của nhà cung cấp từ xa, được giữ để hiển thị không mất mát
externalSyncedAt DateTime? Lần đồng bộ đa vendor gần nhất; null cho đến lần đầu tiên. Ánh xạ theo từng vendor nằm trong ticket_sync_links
parentTicketId String? Phiếu cha trong cây ủy thác / chia nhỏ
projectId String? Dự án sở hữu; không bao giờ được đẩy lên hệ thống từ xa
assignedAgentId String? Id của chủ thể được gán (chỉ là siêu dữ liệu — gán không điều phối gì cả)
assigneeType PrincipalType Loại chủ thể mà assignedAgentId chỉ tới — user hoặc agent (mặc định agent)
createdByType PrincipalType? Loại chủ thể đã tạo phiếu (user hoặc agent); null với các hàng cũ/hệ thống
createdById String? Id của chủ thể đã tạo
assignedTeamId String? Đội được gán (chỉ là siêu dữ liệu)
delegatedByAgentId String? Agent đã ủy thác phiếu này
delegationDepth int Độ sâu trong chuỗi ủy thác; gốc là 0, được kiểm tra với giới hạn độ sâu tối đa
delegationRootTicketId String? Gốc của chuỗi ủy thác; null với một phiếu gốc
spaceId String? Cuộc hội thoại mà phiếu được tách ra từ đó, hoặc space của agent ủy thác
errorMessage String? Được đặt khi status là failed
linkedPrIds List<String> Id nút PR mà phiếu này được liên kết tới
metadata Map<String, dynamic> Túi dữ liệu tự do
createdAt DateTime Thời điểm tạo
startedAt DateTime? Khi công việc bắt đầu
blockedAt DateTime? Khi phiếu bị chặn
cancelledAt DateTime? Khi phiếu bị hủy
completedAt DateTime? Khi phiếu hoàn tất thành công
finishedAt DateTime? Khi phiếu đạt tới bất kỳ trạng thái kết thúc nào
updatedAt DateTime Lần thay đổi gần nhất (làm mới bản gương hoặc thay đổi lớp phủ)
version int Bộ đếm đồng thời lạc quan, tăng lên sau mỗi thay đổi
originKind TicketOriginKind Cách phiếu được tạo (mặc định manual)
collaborators List<TicketCollaborator> Được repository nạp theo yêu cầu

Suy ra: isTerminal, isRemote (provider != local), isAssignedToUser và displayKey (externalKey ?? id — do đó phiếu cục bộ hiển thị UUID riêng được tạo lúc tạo phiếu, chứ không phải id của hàng).

Các cạnh được lưu là những hàng có hướng trong ticket_links:

Loại Chuỗi lưu trữ Ý nghĩa
blocks blocks Phiếu nguồn chặn phiếu đích
relatesTo relates_to Quan hệ đối xứng
duplicateOf duplicate_of Phiếu nguồn là bản trùng của phiếu đích

Từ vựng mà giao diện và ticket_relation dùng là TicketRelationKind, được suy ra từ một cạnh đã lưu cộng với việc chủ thể nằm ở đầu nào của cạnh đó:

Loại Suy ra từ
blockedBy Một hàng blocks trong đó chủ thể là phiếu đích
blocking Một hàng blocks trong đó chủ thể là phiếu nguồn
relatedTo Một hàng relates_to (đối xứng)
duplicateOf Một hàng duplicate_of trong đó chủ thể là phiếu nguồn
duplicatedBy Một hàng duplicate_of trong đó chủ thể là phiếu đích
subIssueOf tickets.parent_ticket_id trên chủ thể
parentOf tickets.parent_ticket_id trên phiếu kia

Các liên kết cha và vấn đề con không phải là hàng ticket_links — chúng nằm trên tickets.parent_ticket_id.

Tám lớp này nằm trong packages/cc_domain/lib/core/domain/events/ticketing_events.dart. Không có TicketStarted, TicketDelegated, TicketCollaboratorAdded hay ExternalTicketWebhookReceived.

Sự kiện Kích hoạt khi
TicketCreated Phiếu được tạo
TicketAssigned Phiếu được gán cho một chủ thể hoặc một đội
TicketCompleted Công việc kết thúc thành công
TicketFailed Công việc thất bại
TicketCancelled Phiếu bị hủy
TicketStatusChanged Mọi thay đổi trạng thái
TicketReassigned Phiếu được gán lại
TicketDetailsUpdated Tiêu đề, mô tả, mức ưu tiên hoặc nhãn thay đổi

TicketAssigned là một tín hiệu kiểm toán và thông báo, đồng thời là một trình kích hoạt quy trình. Gán cho một agent không khởi động lần chạy nào — không có bộ điều phối phiếu nào theo dõi assignedAgentId. Gán cho một đội là ngoại lệ: TeamRoutingService điều phối trưởng đội. Thêm một cộng tác viên chỉ ghi một hàng và không phát ra gì. Một webhook từ vendor được áp dụng qua TicketSyncEngine mà không có sự kiện miền nào.

TicketWorkflowService sở hữu mọi thay đổi.

Cơ chế Chi tiết
Điểm nghẽn duy nhất Mọi thay đổi đều đi qua _mutate, hàm này nạp hàng và gọi _assertWorkspace trước khi áp dụng
Cô lập không gian làm việc _assertWorkspace ném WorkspaceMismatchException khi workspaceId của hàng được nạp không khớp với workspaceId của bên gọi
Đồng thời lạc quan _mutate ghi với expectedVersion được đặt bằng version mà nó vừa đọc và thử lại khi gặp ConcurrencyConflictException bằng cách đọc lại trạng thái mới
Giành quyền độc quyền tryCheckout / releaseCheckout; agent thứ hai giành một phiếu đã được checkout sẽ nhận CheckoutConflictException
Chốt chuyển trạng thái canTransitionTo, chỉ được áp dụng khi force là false