feat(sprints): modèle de sprints — domaine, use-cases, persistance et surfaces (backend)
Ticket #10 — introduction du modèle de sprints côté backend. - Domaine : nouvel agrégat Sprint (sprint.rs), IDs, événements et invariants ; rattachement des issues à un sprint (issue.rs) et ports associés. - Application : use-cases sprints (application/src/sprints) + erreurs dédiées. - Infrastructure : store de sprints (infrastructure/src/sprints.rs), adaptation du store d'issues et exposition MCP via orchestrator/mcp/tickets.rs. - app-tauri : commandes, state et events pour piloter les sprints depuis l'UI. Tests domaine/application/infra/app-tauri verts (sprint_usecases, sprint_store, issue_store, mcp_server). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -299,6 +299,52 @@ pub enum DomainEventDto {
|
||||
/// New optimistic version.
|
||||
version: u64,
|
||||
},
|
||||
/// A sprint was created.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SprintCreated {
|
||||
/// Stable sprint id.
|
||||
sprint_id: String,
|
||||
/// Reorderable order.
|
||||
order: u32,
|
||||
},
|
||||
/// A sprint was renamed.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SprintRenamed {
|
||||
/// Stable sprint id.
|
||||
sprint_id: String,
|
||||
/// New name.
|
||||
name: String,
|
||||
/// New optimistic version.
|
||||
version: u64,
|
||||
},
|
||||
/// A sprint was reordered.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SprintReordered {
|
||||
/// Stable sprint id.
|
||||
sprint_id: String,
|
||||
/// New order.
|
||||
order: u32,
|
||||
/// New optimistic version.
|
||||
version: u64,
|
||||
},
|
||||
/// A sprint was deleted.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
SprintDeleted {
|
||||
/// Stable sprint id.
|
||||
sprint_id: String,
|
||||
},
|
||||
/// A ticket changed sprint membership.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
IssueSprintChanged {
|
||||
/// Public ticket reference (`#N`).
|
||||
issue_ref: String,
|
||||
/// Previous sprint id.
|
||||
from: Option<String>,
|
||||
/// New sprint id.
|
||||
to: Option<String>,
|
||||
/// New optimistic version.
|
||||
version: u64,
|
||||
},
|
||||
/// An orchestrator request was processed on behalf of a requester agent.
|
||||
#[serde(rename_all = "camelCase")]
|
||||
OrchestratorRequestProcessed {
|
||||
@ -773,6 +819,42 @@ impl From<&DomainEvent> for DomainEventDto {
|
||||
agent_id: agent_id.to_string(),
|
||||
version: version.get(),
|
||||
},
|
||||
DomainEvent::SprintCreated { sprint_id, order } => Self::SprintCreated {
|
||||
sprint_id: sprint_id.to_string(),
|
||||
order: order.get(),
|
||||
},
|
||||
DomainEvent::SprintRenamed {
|
||||
sprint_id,
|
||||
name,
|
||||
version,
|
||||
} => Self::SprintRenamed {
|
||||
sprint_id: sprint_id.to_string(),
|
||||
name: name.clone(),
|
||||
version: version.get(),
|
||||
},
|
||||
DomainEvent::SprintReordered {
|
||||
sprint_id,
|
||||
order,
|
||||
version,
|
||||
} => Self::SprintReordered {
|
||||
sprint_id: sprint_id.to_string(),
|
||||
order: order.get(),
|
||||
version: version.get(),
|
||||
},
|
||||
DomainEvent::SprintDeleted { sprint_id } => Self::SprintDeleted {
|
||||
sprint_id: sprint_id.to_string(),
|
||||
},
|
||||
DomainEvent::IssueSprintChanged {
|
||||
issue_ref,
|
||||
from,
|
||||
to,
|
||||
version,
|
||||
} => Self::IssueSprintChanged {
|
||||
issue_ref: issue_ref.to_string(),
|
||||
from: from.map(|id| id.to_string()),
|
||||
to: to.map(|id| id.to_string()),
|
||||
version: version.get(),
|
||||
},
|
||||
DomainEvent::OrchestratorRequestProcessed {
|
||||
requester_id,
|
||||
action,
|
||||
@ -981,4 +1063,22 @@ mod tests {
|
||||
assert_eq!(json["agentId"], agent(11).to_string());
|
||||
assert_eq!(json["resetsAtMs"], 1_700_000_000_000_i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_sprint_changed_relays_to_dto_and_wire() {
|
||||
let from = domain::SprintId::from_uuid(uuid::Uuid::from_u128(41));
|
||||
let to = domain::SprintId::from_uuid(uuid::Uuid::from_u128(42));
|
||||
let dto = DomainEventDto::from(&DomainEvent::IssueSprintChanged {
|
||||
issue_ref: domain::IssueRef::from(domain::IssueNumber::new(7).unwrap()),
|
||||
from: Some(from),
|
||||
to: Some(to),
|
||||
version: domain::IssueVersion::new(3).unwrap(),
|
||||
});
|
||||
let json = serde_json::to_value(&dto).expect("serialisable");
|
||||
assert_eq!(json["type"], "issueSprintChanged");
|
||||
assert_eq!(json["issueRef"], "#7");
|
||||
assert_eq!(json["from"], from.to_string());
|
||||
assert_eq!(json["to"], to.to_string());
|
||||
assert_eq!(json["version"], 3);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user