namespace Nexus.Api.Data; public enum OperationalStatus { Online, Degraded, Offline, Unknown } /// /// Strongly-typed task lifecycle states. /// String values (e.g. "In progress") are preserved for API compatibility /// via ; the WorkTask entity continues to store /// state as a string in the database. /// public enum TaskState { Backlog, InProgress, Delegated, Blocked, Done, Review } public static class TaskStateHelper { private static readonly Dictionary StateToString = new() { [TaskState.Backlog] = "Backlog", [TaskState.InProgress] = "In progress", [TaskState.Delegated] = "Delegated", [TaskState.Blocked] = "Blocked", [TaskState.Done] = "Done", [TaskState.Review] = "Review" }; private static readonly Dictionary StringToState = new(StringComparer.OrdinalIgnoreCase) { ["Backlog"] = TaskState.Backlog, ["In progress"] = TaskState.InProgress, ["Delegated"] = TaskState.Delegated, ["Blocked"] = TaskState.Blocked, ["Done"] = TaskState.Done, ["Review"] = TaskState.Review }; /// Mapping from state string to display label. private static readonly Dictionary DisplayLabels = new(StringComparer.OrdinalIgnoreCase) { ["Backlog"] = "Offen", ["In progress"] = "In Bearbeitung", ["Delegated"] = "Delegiert", ["Review"] = "Review", ["Blocked"] = "Blockiert", ["Done"] = "Erledigt" }; /// Valid task-state string values for API validation. public static readonly string[] AllStates = ["Backlog", "In progress", "Delegated", "Blocked", "Done", "Review"]; /// Convert a TaskState enum to its API string representation. public static string ToStateString(this TaskState state) => StateToString[state]; /// Parse a string to TaskState; defaults to Backlog for unrecognized input. public static TaskState ToTaskState(this string state) => StringToState.TryGetValue(state, out var result) ? result : TaskState.Backlog; /// Returns true if the string is a recognized task state (case-insensitive). public static bool IsValidState(string? state) => !string.IsNullOrWhiteSpace(state) && StringToState.ContainsKey(state); /// Returns the German display label for a state string. public static string ToDisplayString(string? state) => state is not null && DisplayLabels.TryGetValue(state, out var label) ? label : state ?? ""; public static bool IsInProgressOrBlocked(string? state) => string.Equals(state, "In progress", StringComparison.OrdinalIgnoreCase) || string.Equals(state, "Blocked", StringComparison.OrdinalIgnoreCase); public static bool IsDoneOrBacklog(string? state) => string.Equals(state, "Done", StringComparison.OrdinalIgnoreCase) || string.Equals(state, "Backlog", StringComparison.OrdinalIgnoreCase); /// Group key for board responses (lowercased English state). public static string BoardGroupKey(string? state) { if (string.IsNullOrWhiteSpace(state)) return "offen"; var lower = state.ToLowerInvariant(); return lower switch { "backlog" => "offen", "in progress" => "inProgress", "delegated" => "delegated", "review" => "review", "blocked" => "blocked", "done" => "done", _ => "offen" }; } /// Map a board group key back to the canonical state string. public static string? BoardGroupToState(string? groupKey) { if (string.IsNullOrWhiteSpace(groupKey)) return null; var lower = groupKey.ToLowerInvariant(); return lower switch { "offen" => "Backlog", "inprogress" => "In progress", "delegated" => "Delegated", "review" => "Review", "blocked" => "Blocked", "done" => "Done", _ => null }; } } public sealed class Project { public Guid Id { get; init; } = Guid.NewGuid(); public required string Name { get; set; } public string Description { get; set; } = string.Empty; public int Progress { get; set; } public OperationalStatus Status { get; set; } = OperationalStatus.Unknown; public DateTimeOffset UpdatedAt { get; set; } = DateTimeOffset.UtcNow; } public sealed class WorkTask { public Guid Id { get; init; } = Guid.NewGuid(); public required string Title { get; set; } public string? Detail { get; set; } public string State { get; set; } = "Backlog"; public string Priority { get; set; } = "Normal"; public string Source { get; set; } = "bao"; public string? AssignedTo { get; set; } public Guid? ParentTaskId { get; set; } public WorkTask? ParentTask { get; set; } public ICollection ChildTasks { get; set; } = new List(); public Guid? ProjectId { get; set; } public DateTimeOffset? DueDate { get; set; } public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; public DateTimeOffset UpdatedAt { get; set; } = DateTimeOffset.UtcNow; } public sealed class Notification { public Guid Id { get; init; } = Guid.NewGuid(); public required string Type { get; set; } // "task_assigned", "task_review", "task_blocked" public required string Title { get; set; } // "Neue Aufgabe: Memory-Index reparieren" public string? Message { get; set; } // Detailtext public required string ForUser { get; set; } // "bao" oder "iris" public Guid? TaskId { get; set; } // Verknüpfte Task public bool IsRead { get; set; } = false; public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; } public sealed class ActivityEvent { public long Id { get; init; } public required string Type { get; set; } public required string Message { get; set; } public Guid? TaskId { get; set; } public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; }