چرخهٔ عمر تیکت
وضعیتهای تیکت
بخش با عنوان “وضعیتهای تیکت”| وضعیت | رشتهٔ ذخیرهسازی | توضیح |
|---|---|---|
backlog |
backlog |
ثبتشده، هنوز به صف فعال تریاژ نشده |
open |
open |
تریاژشده و آمادهٔ کار، ولی شروعنشده |
inProgress |
inProgress |
فعالانه در حال انجام |
blocked |
blocked |
شروعشده اما بر چیزی بیرونی مسدود |
inReview |
inReview |
کار انجامشده، در انتظار بازبینی |
done |
done |
با موفقیت تمام شد (پایانی) |
failed |
failed |
با خطا تمام شد (پایانی) |
cancelled |
cancelled |
رهاشده (پایانی) |
مقدارهای وضعیت بهصورت camelCase ذخیره میشوند (inProgress، inReview)، هرگز in_progress. یک مقدار ذخیرهشدهٔ null بهصورت open تفسیر میشود؛ یک مقدار ناشناخته بهجای تبدیل اجباری، خطا میاندازد.
tryParseLoose نامهای مستعار عرضهشده از سوی عامل را میپذیرد و بزرگی و کوچکی حروف و - / _ / فاصله را نادیده میگیرد:
| وضعیت | نامهای مستعار پذیرفتهشده |
|---|---|
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این گراف فقط عاملها و خودکارسازی را مقید میکند. TicketWorkflowService.transitionStatus آن را وقتی force برابر false است بررسی میکند — ابزارهای MCP و تطبیقدهندهها. یک گذار غیرمجاز در آنجا ثبت و نادیده گرفته میشود. هر تغییر وضعیت کاربرمحور در رابط کاربری با force: true عبور میکند و گراف را کاملاً دور میزند، پس یک انسان میتواند تیکت را به هر وضعیتی که انتخابگر فهرست میکند ببرد (هر وضعیتی جز failed)، از جمله بازگشایی یک وضعیت پایانی. عاملها failed را با fail_ticket علامت میزنند.
یک وضعیت همیشه میتواند به خودش گذار کند. وضعیتهای پایانی هیچ یال خروجی ندارند.
| از | مقصدهای مجاز |
|---|---|
backlog |
open, cancelled |
open |
inProgress, blocked, cancelled |
inProgress |
blocked, inReview, done, failed, cancelled |
blocked |
inProgress, cancelled |
inReview |
inProgress, done, failed, cancelled |
done |
— (پایانی) |
failed |
— (پایانی) |
cancelled |
— (پایانی) |
اولویتهای تیکت
بخش با عنوان “اولویتهای تیکت”بهصورت یک عدد صحیح روی مقیاس بومی ۰ تا ۴ در Linear ذخیره میشود. یک مقدار ناشناخته به none تفسیر میشود.
| اولویت | ذخیرهشده بهصورت |
|---|---|
none |
0 |
urgent |
1 |
high |
2 |
medium |
3 |
low |
4 |
ارائهدهندههای تیکت
بخش با عنوان “ارائهدهندههای تیکت”یک مقدار ذخیرهشدهٔ ناشناخته یا null به local تفسیر میشود.
| ارائهدهنده | وضعیت |
|---|---|
local |
تماماً در پایگاهدادهٔ فضای کاری ذخیره میشود؛ پیشفرض |
linear |
در مالکیت راه دور، بهصورت محلی آینه میشود |
آداپتورهای همگامسازی برای Linear، GitHub Issues، Jira Cloud و ClickUp زیر
packages/cc_infra/lib/src/tickets/sync/ زندگی میکنند. GitHub Issues فقط یک
فروشندهٔ آداپتور همگامسازی است (vendorId: github) — یک مقدار TicketProvider
نیست، بنابراین یک ایشوی واکشیشده از GitHub با originKind: externalSync و
provider: local پیشفرض ذخیره میشود. نگاشت فروشنده روی ticket_sync_links
زندگی میکند.
منشأ تیکت
بخش با عنوان “منشأ تیکت”createTicket مقدار manual را مینویسد. یک واکشی از فروشنده externalSync را
مینویسد. فرزندان واگذارشده manual میمانند.
| مقدار | معنا |
|---|---|
manual |
پیشفرض در createTicket (ردیفهای انسان، عامل و واگذاری) |
externalSync |
توسط TicketSyncEngine هنگام واکشی از فروشنده تنظیم میشود |
فیلدهای تیکت
بخش با عنوان “فیلدهای تیکت”این تجمیع دو دغدغه را روی یک ردیف میگستراند. آینه (ارائهدهنده، کلیدها، عنوان، شرح، اولویت، برچسبها، وضعیتها، برچسبهای زمانی) کشی برای یک ارائهدهندهٔ راه دور است و با یک تازهسازی یکسره بازنویسی میشود. لایهٔ رویی (تخصیص، واگذاری، فضا، والد، پروژه، PRهای پیوندشده) فقط مخصوص Control Center است و تازهسازی هرگز به آن دست نمیزند.
| فیلد | نوع | توضیح |
|---|---|---|
id |
String |
UUID v4 |
workspaceId |
String |
فضای کاری مالک |
provider |
TicketProvider |
بکاندی که مالک دادهٔ متعارف است (پیشفرض local) |
externalKey |
String? |
کلید بومی ارائهدهنده (مثلاً LIN-123). createTicket محلی یک UUID جداگانه را اینجا مینویسد، نه id ردیف |
url |
String? |
URL وب روی ارائهدهندهٔ راه دور |
title |
String |
خلاصهٔ کوتاه؛ نباید خالی باشد |
description |
String? |
متن Markdown بلندتر |
priority |
TicketPriority |
پیشفرض none |
labels |
List<String> |
برچسبهای آزاد |
status |
TicketStatus |
وضعیت نرمالشدهٔ متعارف |
rawStatus |
String? |
نام حالت بومی ارائهدهندهٔ راه دور، نگهداشتهشده برای نمایش بیاتلاف |
externalSyncedAt |
DateTime? |
آخرین همگامسازی چندفروشندگی؛ تا نخستین مورد null است. نگاشت هر فروشنده در ticket_sync_links زندگی میکند |
parentTicketId |
String? |
والد در درخت واگذاری / تجزیه |
projectId |
String? |
پروژهٔ مالک؛ هرگز به راه دور فرستاده نمیشود |
assignedAgentId |
String? |
شناسهٔ principal تخصیصیافته (فقط فراداده — تخصیص دادن چیزی را اعزام نمیکند) |
assigneeType |
PrincipalType |
اینکه assignedAgentId نام کدام نوع principal را میبرد — user یا agent (پیشفرض agent) |
createdByType |
PrincipalType? |
نوع principalی که تیکت را ساخت (user یا agent)؛ برای ردیفهای قدیمی/سیستمی null است |
createdById |
String? |
شناسهٔ principal سازنده |
assignedTeamId |
String? |
تیم تخصیصیافته (فقط فراداده) |
delegatedByAgentId |
String? |
عاملی که این تیکت را واگذار کرد |
delegationDepth |
int |
عمق در زنجیرهٔ واگذاری؛ ریشه 0 است و با سقف بیشینهٔ عمق بررسی میشود |
delegationRootTicketId |
String? |
ریشهٔ زنجیرهٔ واگذاری؛ برای یک تیکت ریشه null است |
spaceId |
String? |
گفتوگویی که تیکت از آن بیرون کشیده شد، یا فضای عامل واگذارکننده |
errorMessage |
String? |
وقتی status برابر failed است تنظیم میشود |
linkedPrIds |
List<String> |
شناسههای گره PR که این تیکت به آنها پیوند دارد |
metadata |
Map<String, dynamic> |
کیسهٔ آزاد |
createdAt |
DateTime |
زمان ساخت |
startedAt |
DateTime? |
زمان شروع کار |
blockedAt |
DateTime? |
زمان مسدود شدن تیکت |
cancelledAt |
DateTime? |
زمان لغو شدن تیکت |
completedAt |
DateTime? |
زمان تکمیل موفق تیکت |
finishedAt |
DateTime? |
زمان رسیدن تیکت به هر وضعیت پایانی |
updatedAt |
DateTime |
آخرین جهش (تازهسازی آینه یا تغییر لایهٔ رویی) |
version |
int |
شمارندهٔ همزمانی خوشبینانه که با هر جهش یک واحد زیاد میشود |
originKind |
TicketOriginKind |
اینکه تیکت چگونه ساخته شد (پیشفرض manual) |
collaborators |
List<TicketCollaborator> |
بنا به درخواست توسط مخزن پُر میشود |
مشتقشده: isTerminal، isRemote (provider != local)، isAssignedToUser و displayKey (externalKey ?? id — بنابراین تیکتهای محلی UUID جداگانهٔ زمان ساخت را نشان میدهند، نه id ردیف).
رابطههای تیکت
بخش با عنوان “رابطههای تیکت”یالهای ذخیرهشده ردیفهای جهتدار در ticket_links هستند:
| نوع | رشتهٔ ذخیرهسازی | معنا |
|---|---|---|
blocks |
blocks |
مبدأ مقصد را مسدود میکند |
relatesTo |
relates_to |
رابطهٔ متقارن |
duplicateOf |
duplicate_of |
مبدأ تکرار مقصد است |
واژگانی که رابط کاربری و ticket_relation به کار میبرند TicketRelationKind است، برگرفته از یک یال ذخیرهشده بهعلاوهٔ اینکه سوژه روی کدام سر یال مینشیند:
| نوع | برگرفته از |
|---|---|
blockedBy |
یک ردیف blocks که سوژه در آن مقصد است |
blocking |
یک ردیف blocks که سوژه در آن مبدأ است |
relatedTo |
یک ردیف relates_to (متقارن) |
duplicateOf |
یک ردیف duplicate_of که سوژه در آن مبدأ است |
duplicatedBy |
یک ردیف duplicate_of که سوژه در آن مقصد است |
subIssueOf |
tickets.parent_ticket_id روی سوژه |
parentOf |
tickets.parent_ticket_id روی تیکت دیگر |
پیوندهای والد و زیرایشو ردیفهای ticket_links نیستند — آنها روی tickets.parent_ticket_id زندگی میکنند.
رویدادهای دامنه
بخش با عنوان “رویدادهای دامنه”این هشت کلاس در packages/cc_domain/lib/core/domain/events/ticketing_events.dart زندگی میکنند. TicketStarted، TicketDelegated، TicketCollaboratorAdded یا ExternalTicketWebhookReceived وجود ندارد.
| رویداد | زمان انتشار |
|---|---|
TicketCreated |
تیکت ساخته میشود |
TicketAssigned |
تیکت به یک principal یا تیم تخصیص مییابد |
TicketCompleted |
کار با موفقیت به پایان میرسد |
TicketFailed |
کار شکست میخورد |
TicketCancelled |
تیکت لغو میشود |
TicketStatusChanged |
هر تغییر وضعیت |
TicketReassigned |
تیکت دوباره تخصیص مییابد |
TicketDetailsUpdated |
عنوان، شرح، اولویت یا برچسبها تغییر میکند |
TicketAssigned یک سیگنال حسابرسی و اعلان و یک تریگر پایپلاین است. تخصیص به یک عامل هیچ اجرایی را شروع نمیکند — هیچ اعزامکنندهٔ تیکتی وجود ندارد که assignedAgentId را بپاید. تخصیص به یک تیم استثناست: TeamRoutingService سرگروه تیم را اعزام میکند. افزودن یک همکار یک ردیف مینویسد و هیچ چیزی منتشر نمیکند. یک وبهوک فروشنده بدون هیچ رویداد دامنهای از راه TicketSyncEngine اعمال میشود.
گلوگاه جهش
بخش با عنوان “گلوگاه جهش”TicketWorkflowService مالک هر جهش است.
| سازوکار | جزئیات |
|---|---|
| گلوگاه واحد | همهٔ جهشها از _mutate عبور میکنند، که ردیف را بارگذاری میکند و پیش از اعمال، _assertWorkspace را صدا میزند |
| ایزولهسازی فضای کاری | _assertWorkspace وقتی workspaceId ردیف بارگذاریشده با فضای کاری فراخوان نمیخواند، WorkspaceMismatchException میاندازد |
| همزمانی خوشبینانه | _mutate با expectedVersion برابر با versionی که تازه خوانده مینویسد و در صورت ConcurrencyConflictException با بازخوانی وضعیت تازه دوباره میکوشد |
| ادعای انحصاری | tryCheckout / releaseCheckout؛ عامل دومی که تیکتی را که پیشتر checkout شده است ادعا کند، CheckoutConflictException میگیرد |
| گارد گذار | canTransitionTo، فقط وقتی force برابر false است اعمال میشود |