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, Blocked, Done, Review } public static class TaskStateHelper { private static readonly Dictionary StateToString = new() { [TaskState.Backlog] = "Backlog", [TaskState.InProgress] = "In progress", [TaskState.Blocked] = "Blocked", [TaskState.Done] = "Done", [TaskState.Review] = "Review" }; private static readonly Dictionary StringToState = new(StringComparer.OrdinalIgnoreCase) { ["Backlog"] = TaskState.Backlog, ["In progress"] = TaskState.InProgress, ["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", ["Review"] = "Review", ["Blocked"] = "Blockiert", ["Done"] = "Erledigt" }; /// Valid task-state string values for API validation. public static readonly string[] AllStates = ["Backlog", "In progress", "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", "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", "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? ProjectId { get; set; } public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; public DateTimeOffset UpdatedAt { 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 DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow; }