feat(tickets): suppression d'un ticket (backend + frontend)

Ajoute la suppression complète d'un ticket (#6).

Backend Rust :
- port IssueStore::delete (NotFound si absent) + event IssueDeleted{freed_sprint}
- FsIssueStore::delete : supprime .ideai/tickets/<N>/ et l'index sous lock
- use case DeleteIssue + adaptations des tests sprint/ticket_assistant au port
- commande Tauri ticket_delete + câblage events/state/lib

Frontend :
- gateway delete (ports, adapter ticket + mock, domain)
- useTicketDetail : retrait de la liste et fermeture du détail via event issueDeleted
- intégration TicketDetail + tests

Tests verts : application/issue_usecases (6), infrastructure/issue_store (7),
app-tauri --lib (56), frontend vitest (503), npm run build (exit 0).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 06:27:09 +02:00
parent d25e340b44
commit 5417bd756b
20 changed files with 689 additions and 95 deletions

View File

@ -15,10 +15,10 @@ use uuid::Uuid;
use application::{
AppError, AssignIssueAgentInput, AssignTicketToSprintInput, CloseTicketAssistantInput,
CreateIssueInput, CreateSprintInput, DeleteSprintInput, LinkIssuesInput, ListIssuesInput,
ListSprintsInput, OpenProjectInput, OpenTicketAssistantInput, ReadIssueCarnetInput,
ReadIssueInput, RenameSprintInput, ReorderSprintsInput, UnassignTicketFromSprintInput,
UnlinkIssuesInput, UpdateIssueCarnetInput, UpdateIssueInput,
CreateIssueInput, CreateSprintInput, DeleteIssueInput, DeleteSprintInput, LinkIssuesInput,
ListIssuesInput, ListSprintsInput, OpenProjectInput, OpenTicketAssistantInput,
ReadIssueCarnetInput, ReadIssueInput, RenameSprintInput, ReorderSprintsInput,
UnassignTicketFromSprintInput, UnlinkIssuesInput, UpdateIssueCarnetInput, UpdateIssueInput,
};
use domain::{
AgentId, AgentIssueRole, Issue, IssueActor, IssueCarnet, IssueIndexEntry, IssueLink,
@ -180,6 +180,15 @@ pub struct TicketReadRequestDto {
pub include_carnet: Option<bool>,
}
/// Delete request.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TicketDeleteRequestDto {
#[serde(default)]
pub project_id: String,
pub r#ref: String,
}
/// List request.
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
@ -612,6 +621,23 @@ pub async fn ticket_read(
Ok(TicketDto::from_issue(issue, carnet))
}
#[tauri::command]
pub async fn ticket_delete(
request: TicketDeleteRequestDto,
state: State<'_, AppState>,
) -> Result<(), ErrorDto> {
let project = resolve_project(&state, &request.project_id).await?;
state
.delete_issue
.execute(DeleteIssueInput {
project,
issue_ref: parse_ref_dto(&request.r#ref)?,
})
.await
.map(|_| ())
.map_err(ErrorDto::from)
}
#[tauri::command]
pub async fn open_ticket_chat(
request: OpenTicketChatRequestDto,