chore: initial commit of TaskTracker project

Existing ASP.NET API with vanilla JS SPA, WindowWatcher, Chrome extension, and MCP server.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 22:08:45 -05:00
commit e12f78c479
66 changed files with 5170 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
namespace TaskTracker.Core.DTOs;
public class ApiResponse<T>
{
public bool Success { get; set; }
public T? Data { get; set; }
public string? Error { get; set; }
public static ApiResponse<T> Ok(T data) => new() { Success = true, Data = data };
public static ApiResponse<T> Fail(string error) => new() { Success = false, Error = error };
}
public class ApiResponse
{
public bool Success { get; set; }
public string? Error { get; set; }
public static ApiResponse Ok() => new() { Success = true };
public static ApiResponse Fail(string error) => new() { Success = false, Error = error };
}

View File

@@ -0,0 +1,9 @@
namespace TaskTracker.Core.DTOs;
public class ContextEventRequest
{
public string Source { get; set; } = string.Empty;
public string AppName { get; set; } = string.Empty;
public string WindowTitle { get; set; } = string.Empty;
public string? Url { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace TaskTracker.Core.DTOs;
public class ContextSummaryItem
{
public string AppName { get; set; } = string.Empty;
public string Category { get; set; } = string.Empty;
public int EventCount { get; set; }
public DateTime FirstSeen { get; set; }
public DateTime LastSeen { get; set; }
}

View File

@@ -0,0 +1,9 @@
namespace TaskTracker.Core.DTOs;
public class CreateAppMappingRequest
{
public string Pattern { get; set; } = string.Empty;
public string MatchType { get; set; } = string.Empty;
public string Category { get; set; } = string.Empty;
public string? FriendlyName { get; set; }
}

View File

@@ -0,0 +1,9 @@
using TaskTracker.Core.Enums;
namespace TaskTracker.Core.DTOs;
public class CreateNoteRequest
{
public string Content { get; set; } = string.Empty;
public NoteType Type { get; set; } = NoteType.General;
}

View File

@@ -0,0 +1,9 @@
namespace TaskTracker.Core.DTOs;
public class CreateTaskRequest
{
public string Title { get; set; } = string.Empty;
public string? Description { get; set; }
public string? Category { get; set; }
public int? ParentTaskId { get; set; }
}

View File

@@ -0,0 +1,6 @@
namespace TaskTracker.Core.DTOs;
public class TaskActionRequest
{
public string? Note { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace TaskTracker.Core.Entities;
public class AppMapping
{
public int Id { get; set; }
public string Pattern { get; set; } = string.Empty;
public string MatchType { get; set; } = string.Empty; // ProcessName, UrlContains, TitleContains
public string Category { get; set; } = string.Empty;
public string? FriendlyName { get; set; }
}

View File

@@ -0,0 +1,14 @@
namespace TaskTracker.Core.Entities;
public class ContextEvent
{
public int Id { get; set; }
public int? WorkTaskId { get; set; }
public string Source { get; set; } = string.Empty;
public string AppName { get; set; } = string.Empty;
public string WindowTitle { get; set; } = string.Empty;
public string? Url { get; set; }
public DateTime Timestamp { get; set; }
public WorkTask? WorkTask { get; set; }
}

View File

@@ -0,0 +1,14 @@
using TaskTracker.Core.Enums;
namespace TaskTracker.Core.Entities;
public class TaskNote
{
public int Id { get; set; }
public int WorkTaskId { get; set; }
public string Content { get; set; } = string.Empty;
public NoteType Type { get; set; }
public DateTime CreatedAt { get; set; }
public WorkTask WorkTask { get; set; } = null!;
}

View File

@@ -0,0 +1,22 @@
using TaskTracker.Core.Enums;
namespace TaskTracker.Core.Entities;
public class WorkTask
{
public int Id { get; set; }
public string Title { get; set; } = string.Empty;
public string? Description { get; set; }
public WorkTaskStatus Status { get; set; }
public string? Category { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? StartedAt { get; set; }
public DateTime? CompletedAt { get; set; }
public int? ParentTaskId { get; set; }
public WorkTask? ParentTask { get; set; }
public List<WorkTask> SubTasks { get; set; } = new();
public List<TaskNote> Notes { get; set; } = [];
public List<ContextEvent> ContextEvents { get; set; } = [];
}

View File

@@ -0,0 +1,8 @@
namespace TaskTracker.Core.Enums;
public enum NoteType
{
PauseNote,
ResumeNote,
General
}

View File

@@ -0,0 +1,10 @@
namespace TaskTracker.Core.Enums;
public enum WorkTaskStatus
{
Pending,
Active,
Paused,
Completed,
Abandoned
}

View File

@@ -0,0 +1,13 @@
using TaskTracker.Core.Entities;
namespace TaskTracker.Core.Interfaces;
public interface IAppMappingRepository
{
Task<List<AppMapping>> GetAllAsync();
Task<AppMapping?> GetByIdAsync(int id);
Task<AppMapping> CreateAsync(AppMapping mapping);
Task UpdateAsync(AppMapping mapping);
Task DeleteAsync(int id);
Task<AppMapping?> FindMatchAsync(string appName, string windowTitle, string? url);
}

View File

@@ -0,0 +1,10 @@
using TaskTracker.Core.Entities;
namespace TaskTracker.Core.Interfaces;
public interface IContextEventRepository
{
Task<ContextEvent> CreateAsync(ContextEvent contextEvent);
Task<List<ContextEvent>> GetRecentAsync(int minutes = 30);
Task<List<ContextEvent>> GetByTaskIdAsync(int taskId);
}

View File

@@ -0,0 +1,15 @@
using TaskTracker.Core.Entities;
using TaskTracker.Core.Enums;
namespace TaskTracker.Core.Interfaces;
public interface ITaskRepository
{
Task<List<WorkTask>> GetAllAsync(WorkTaskStatus? status = null, int? parentId = null, bool includeSubTasks = false);
Task<WorkTask?> GetByIdAsync(int id);
Task<WorkTask?> GetActiveTaskAsync();
Task<List<WorkTask>> GetSubTasksAsync(int parentId);
Task<WorkTask> CreateAsync(WorkTask task);
Task UpdateAsync(WorkTask task);
Task DeleteAsync(int id);
}

View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>