Skip to main content

levi_core/entities/
task.rs

1use myko::prelude::*;
2
3#[myko_subtype(derive(Default, Eq, Hash, PartialOrd, Ord, Copy))]
4pub enum Priority {
5    P0,
6    P1,
7    #[default]
8    P2,
9    P3,
10}
11
12impl Priority {
13    pub fn rank(self) -> u8 {
14        match self {
15            Priority::P0 => 0,
16            Priority::P1 => 1,
17            Priority::P2 => 2,
18            Priority::P3 => 3,
19        }
20    }
21
22    pub fn parse(s: &str) -> Option<Self> {
23        match s.to_ascii_lowercase().as_str() {
24            "p0" | "0" => Some(Priority::P0),
25            "p1" | "1" => Some(Priority::P1),
26            "p2" | "2" => Some(Priority::P2),
27            "p3" | "3" => Some(Priority::P3),
28            _ => None,
29        }
30    }
31
32    pub fn label(self) -> &'static str {
33        match self {
34            Priority::P0 => "P0",
35            Priority::P1 => "P1",
36            Priority::P2 => "P2",
37            Priority::P3 => "P3",
38        }
39    }
40}
41
42/// A tracked task. NOTE (spec): status is *not* a field — it is derived
43/// per-checkout from [`crate::StatusChange`] records. Metadata edits are
44/// ordinary myko SET events; last-writer-wins by event `created_at`, ties
45/// broken by event id (levi sorts before replay — see `materialize`).
46#[myko_item]
47pub struct Task {
48    pub project_id: String,
49    #[searchable]
50    pub title: String,
51    #[serde(default)]
52    #[searchable]
53    pub body: String,
54    #[serde(default)]
55    pub priority: Priority,
56    #[serde(default)]
57    pub labels: Vec<String>,
58    pub created_by_dev: String,
59    pub created_by_machine: String,
60    /// RFC3339
61    // Named `created` (not created_at): a query-flattened field serializing
62    // as "createdAt" collides with QueryRequest's own timestamp on the wire.
63    pub created: String,
64}