feat: unify Ticket posts and simplify detail layout

Checkpoint requested before the targets read-tool correction. Includes canonical initial posts, creator/edit metadata, migration and UI work, and removal of delivery diagnostics from Ticket details.\n\nIntegration remains incomplete: the Client post-edit trait implementation and server post routes/dispatch are not yet connected; cargo check currently fails. This commit does not assert validation or delivery completion.
This commit is contained in:
2026-10-14 02:42:58 +09:00
parent 26ab6130e0
commit 8611078058
45 changed files with 5862 additions and 668 deletions
+38
View File
@@ -342,6 +342,8 @@ impl_openapi_schema!(
TextResponse,
TicketDependencyCheckResponse,
TicketDetail,
TicketEventDetail,
TicketPostEditRequest,
TicketCaseUpdateRequest,
TicketAssignmentTrackingUpdateRequest,
TicketAssignmentTrackingRecord,
@@ -3331,10 +3333,29 @@ pub trait ServerApi {
#[patch("/api/w/{workspace_id}/tickets/{id}", status = 200, error_status = 400, additional_error_statuses = [401, 403, 404, 409, 500], bearer_auth = true, browser_auth = true)]
async fn ticket_edit(
&self,
#[extension] context: ServerRequestContext,
#[path] workspace_id: String,
#[path] id: String,
#[body] request: BrowserEditTicketRequest,
) -> Result<TicketDetail, RepositoryApiError>;
#[get("/api/w/{workspace_id}/tickets/{id}/posts/{event_ref}", status = 200, error_status = 400, additional_error_statuses = [401, 403, 404, 500], bearer_auth = true, browser_auth = true)]
async fn ticket_post_get(
&self,
#[path] workspace_id: String,
#[path] id: String,
#[path] event_ref: String,
) -> Result<TicketEventDetail, RepositoryApiError>;
#[patch("/api/w/{workspace_id}/tickets/{id}/posts/{event_ref}", status = 200, error_status = 400, additional_error_statuses = [401, 403, 404, 409, 500], bearer_auth = true, browser_auth = true)]
async fn ticket_post_edit(
&self,
#[extension] context: ServerRequestContext,
#[path] workspace_id: String,
#[path] id: String,
#[path] event_ref: String,
#[body] request: TicketPostEditRequest,
) -> Result<TicketDetail, RepositoryApiError>;
#[post("/api/w/{workspace_id}/tickets/{id}/show", status = 200, error_status = 400, additional_error_statuses = [401, 403, 404, 500], bearer_auth = true, browser_auth = true)]
async fn ticket_show(
&self,
@@ -3390,6 +3411,7 @@ pub trait ServerApi {
#[post("/api/w/{workspace_id}/tickets/{id}/events", status = 200, error_status = 400, additional_error_statuses = [401, 403, 404, 409, 500], bearer_auth = true, browser_auth = true)]
async fn ticket_event_append(
&self,
#[extension] context: ServerRequestContext,
#[path] workspace_id: String,
#[path] id: String,
#[body] request: BrowserAppendTicketEventRequest,
@@ -7391,6 +7413,12 @@ pub struct TicketListResponse {
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
#[serde(deny_unknown_fields)]
pub struct TicketEventDetail {
pub is_initial: bool,
pub edited_at: Option<String>,
pub edited_by: Option<String>,
pub body_digest: String,
pub body_truncated: bool,
pub editable: bool,
#[cfg_attr(feature = "typescript", ts(type = "number"))]
#[schemars(range(min = 0, max = 9_007_199_254_740_991_usize))]
pub sequence: usize,
@@ -7800,6 +7828,8 @@ pub struct TicketShowRequest {
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
#[serde(deny_unknown_fields)]
pub struct TicketDetail {
pub created_by: Option<String>,
pub initial_post: TicketEventDetail,
pub id: String,
#[cfg_attr(feature = "typescript", ts(type = "Array<WorkspaceTag>"))]
pub tags: Vec<ticket::WorkspaceTag>,
@@ -8182,6 +8212,14 @@ impl From<ticket::TicketState> for BrowserTicketState {
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
#[serde(deny_unknown_fields)]
pub struct TicketPostEditRequest {
pub body: String,
pub expected_body_digest: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
#[serde(deny_unknown_fields)]
@@ -494,6 +494,20 @@ fn validate_ticket_browser_operations(
request: Some("BrowserEditTicketRequest"),
successes: &[("200", "TicketDetail")],
},
OperationContract {
path: "/api/w/{workspace_id}/tickets/{id}/posts/{event_ref}",
method: "get",
operation_id: "ticket_post_get",
request: None,
successes: &[("200", "TicketEventDetail")],
},
OperationContract {
path: "/api/w/{workspace_id}/tickets/{id}/posts/{event_ref}",
method: "patch",
operation_id: "ticket_post_edit",
request: Some("TicketPostEditRequest"),
successes: &[("200", "TicketDetail")],
},
OperationContract {
path: "/api/w/{workspace_id}/tickets/{id}/assignments/{role}",
method: "put",