| Crates.io | kanban-domain |
| lib.rs | kanban-domain |
| version | 0.1.16 |
| created_at | 2025-10-12 22:13:23.887077+00 |
| updated_at | 2025-12-21 20:47:54.533188+00 |
| description | Domain models and business logic for the kanban project management tool |
| homepage | https://github.com/fulsomenko/kanban |
| repository | https://github.com/fulsomenko/kanban |
| max_upload_size | |
| id | 1879787 |
| size | 115,974 |
Domain models and business logic for the kanban project management tool. Pure domain layer with no infrastructure dependencies.
Add to your Cargo.toml:
[dependencies]
kanban-domain = { path = "../kanban-domain" }
Board - Top-level kanban board
pub struct Board {
pub id: BoardId,
pub name: String,
pub description: Option<String>,
pub sprint_prefix: Option<String>,
pub card_prefix: Option<String>,
pub sprint_duration_days: Option<u32>,
pub task_sort_field: SortField,
pub task_sort_order: SortOrder,
// ...more fields
}
pub enum SortField { Points, Priority, CreatedAt, UpdatedAt, Status, Default }
pub enum SortOrder { Ascending, Descending }
Card - Task with lifecycle and metadata
pub struct Card {
pub id: CardId,
pub column_id: ColumnId,
pub title: String,
pub description: Option<String>,
pub priority: CardPriority,
pub status: CardStatus,
pub points: Option<u8>, // 1-5 scale
pub card_number: u32, // Auto-assigned from board prefix counter
pub assigned_prefix: Option<String>,
pub due_date: Option<DateTime<Utc>>,
pub sprint_id: Option<SprintId>,
// ...more fields
}
pub enum CardStatus { Todo, InProgress, Blocked, Done }
pub enum CardPriority { Low, Medium, High, Critical }
Sprint - Sprint lifecycle management
pub struct Sprint {
pub id: SprintId,
pub board_id: BoardId,
pub sprint_number: u32,
pub name_index: usize,
pub prefix: Option<String>,
pub card_prefix: Option<String>,
pub status: SprintStatus,
pub start_date: Option<DateTime<Utc>>,
pub end_date: Option<DateTime<Utc>>,
// ...timestamps
}
pub enum SprintStatus { Planning, Active, Completed, Cancelled }
Column - Board organization
pub struct Column {
pub id: ColumnId,
pub board_id: BoardId,
pub name: String,
pub position: u32,
pub wip_limit: Option<u32>,
// ...timestamps
}
Supporting Types
pub struct ArchivedCard {
pub card: Card,
pub archived_at: DateTime<Utc>,
pub original_column_id: ColumnId,
pub original_position: u32,
}
pub struct SprintLog {
pub sprint_id: SprintId,
pub sprint_number: u32,
pub sprint_name: Option<String>,
pub started_at: DateTime<Utc>,
pub ended_at: Option<DateTime<Utc>>,
pub status: SprintStatus,
}
pub struct Tag {
pub id: TagId,
pub name: String,
pub color: String,
}
pub enum TaskListView { Flat, GroupedByColumn, ColumnView }
// DTOs for safe entity modification
pub struct BoardSettingsDto {
pub sprint_prefix: Option<String>,
pub card_prefix: Option<String>,
pub sprint_duration_days: Option<u32>,
pub sprint_names: Vec<String>,
}
pub struct CardMetadataDto {
pub priority: CardPriority,
pub status: CardStatus,
pub points: Option<u8>,
pub due_date: Option<DateTime<Utc>>,
}
Pure domain layer depending only on kanban-core. Implements rich domain models with encapsulated business logic:
kanban-core
↑
└── kanban-domain (pure business logic)
↑
└── kanban-tui, kanban-cli
Prefix Hierarchy - Git branch naming with fallback chain:
Counter System - Per-prefix independent numbering:
feature-1, bugfix-1, hotfix-1 all starting at 1Sprint History - Audit trail of card movements:
SprintLog entries when assigned to sprintsEntity Update Safety - DTO pattern via Editable trait:
use kanban_domain::{Board, Card, Sprint};
let mut board = Board::new("My Project", None);
board.update_card_prefix(Some("task".into()));
let mut card = Card::new(&mut board, column_id, "Fix bug", 0, "task");
card.set_assigned_prefix(Some("urgent".into()));
// Card prefix wins in hierarchy
let branch = card.branch_name(&board, &sprints, "task");
// Result: "urgent-1/fix-bug"
use kanban_domain::Board;
let mut board = Board::new("My Project", None);
// Feature cards start at 1
let feature1 = board.get_next_card_number("feature"); // 1
let feature2 = board.get_next_card_number("feature"); // 2
// Bugfix cards are independent sequence
let bugfix1 = board.get_next_card_number("bugfix"); // 1
let bugfix2 = board.get_next_card_number("bugfix"); // 2
use kanban_domain::{Sprint, SprintStatus};
let mut sprint = Sprint::new(board_id, 1, None, None);
assert_eq!(sprint.status, SprintStatus::Planning);
// Start sprint (sets start_date and end_date)
sprint.activate(14); // 14-day sprint
assert_eq!(sprint.status, SprintStatus::Active);
// Complete sprint
sprint.complete();
assert_eq!(sprint.status, SprintStatus::Completed);
use kanban_domain::Card;
let mut card = Card::new(&mut board, column_id, "Implement UI", 0, "task");
// Assign to sprint (creates SprintLog entry)
card.assign_to_sprint(sprint_id, 1, None, "Active");
// Get sprint history
let logs = card.get_sprint_history();
assert_eq!(logs.len(), 1);
assert_eq!(logs[0].sprint_number, 1);
use kanban_domain::{CardMetadataDto, CardPriority, CardStatus};
use kanban_core::Editable;
let update = CardMetadataDto {
priority: CardPriority::High,
status: CardStatus::InProgress,
points: Some(5),
due_date: None,
};
// Apply to card with validation
update.apply_to(&mut card)?;
assert_eq!(card.priority, CardPriority::High);
assert_eq!(card.points, Some(5));
kanban-core - Foundation types and traitsserde, serde_json - Serialization for JSON persistenceuuid - ID generation and UUID typeschrono - Date/time handlingasync-trait - Async trait support for future extensionsApache 2.0 - See LICENSE.md for details