feat: implement Phase 1 Foundation for AutoScheduler GTD System

- Initialize npm workspaces monorepo (backend, frontend, shared-types)
- Scaffold NestJS backend with modules: Auth, Users, Tasks, Projects, Inbox, Health
- Create React frontend with Vite, TailwindCSS, Radix UI
- Implement TypeORM entities: User, InboxItem, Task, Project
- Add JWT authentication with Passport.js and bcrypt
- Build Inbox capture API (POST /inbox, GET /inbox, POST /inbox/:id/process)
- Create Inbox UI with quick-add form and GTD processing workflow modal
- Configure Docker Compose stack (postgres, redis, backend, frontend)
- Add health check endpoint with database/Redis status
- Write unit tests for auth and inbox services

Phase 1 features complete:
- GTD Inbox Capture: Manual tasks via web form quick-add
- GTD Processing Workflow: Interactive inbox processing interface

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Debian
2026-01-11 08:42:54 +00:00
parent ce0e5f1769
commit 64b8e0d80c
90 changed files with 21021 additions and 2 deletions

View File

@@ -0,0 +1,27 @@
{
"name": "@nick-tracker/shared-types",
"version": "1.0.0",
"description": "Shared TypeScript types for nick-tracker",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
}
},
"scripts": {
"build": "tsup src/index.ts --dts --format cjs,esm",
"dev": "tsup src/index.ts --dts --format cjs,esm --watch",
"clean": "rm -rf dist",
"lint": "echo 'No lint configured'",
"test": "echo 'No tests'",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"tsup": "^8.0.1",
"typescript": "^5.3.3"
}
}

View File

@@ -0,0 +1,243 @@
// Enums
export enum TaskStatus {
NEXT_ACTION = 'NEXT_ACTION',
WAITING_FOR = 'WAITING_FOR',
SOMEDAY_MAYBE = 'SOMEDAY_MAYBE',
TICKLER = 'TICKLER',
COMPLETED = 'COMPLETED',
}
export enum TaskContext {
DESK = 'DESK',
PHONE = 'PHONE',
ERRAND = 'ERRAND',
HOMELAB = 'HOMELAB',
ANYWHERE = 'ANYWHERE',
}
export enum TaskDomain {
WORK = 'WORK',
HOMELAB = 'HOMELAB',
DAILY_ROUTINES = 'DAILY_ROUTINES',
HOUSE = 'HOUSE',
PROFESSIONAL_DEVELOPMENT = 'PROFESSIONAL_DEVELOPMENT',
}
export enum InboxSource {
MANUAL = 'MANUAL',
EMAIL = 'EMAIL',
CONNECTWISE = 'CONNECTWISE',
TICKLER = 'TICKLER',
}
export enum ProcessAction {
TASK = 'TASK',
PROJECT = 'PROJECT',
WAITING_FOR = 'WAITING_FOR',
SOMEDAY_MAYBE = 'SOMEDAY_MAYBE',
TICKLER = 'TICKLER',
REFERENCE = 'REFERENCE',
TRASH = 'TRASH',
}
// DTOs - Auth
export interface RegisterDto {
email: string;
password: string;
name: string;
timezone: string;
}
export interface LoginDto {
email: string;
password: string;
}
export interface AuthResponseDto {
token: string;
user: UserResponseDto;
}
export interface RefreshTokenDto {
refreshToken: string;
}
// DTOs - User
export interface UserResponseDto {
id: string;
email: string;
name: string;
timezone: string;
createdAt: string;
updatedAt: string;
}
export interface UpdateUserPreferencesDto {
workingHours?: WorkingHours;
timezone?: string;
notificationPreferences?: NotificationPreferences;
weeklyReviewDay?: number;
weeklyReviewTime?: string;
}
export interface WorkingHours {
monday?: DayHours;
tuesday?: DayHours;
wednesday?: DayHours;
thursday?: DayHours;
friday?: DayHours;
saturday?: DayHours;
sunday?: DayHours;
}
export interface DayHours {
start: string;
end: string;
}
export interface NotificationPreferences {
email: boolean;
webhook: boolean;
webhookUrl?: string;
}
// DTOs - Inbox
export interface CreateInboxItemDto {
content: string;
sourceMetadata?: Record<string, unknown>;
}
export interface InboxItemResponseDto {
id: string;
content: string;
source: InboxSource;
sourceMetadata?: Record<string, unknown>;
processed: boolean;
createdAt: string;
updatedAt: string;
}
export interface ProcessInboxItemDto {
action: ProcessAction;
title?: string;
context?: TaskContext;
domain?: TaskDomain;
priority?: number;
estimatedDuration?: number;
dueDate?: string;
projectId?: string;
followUpDate?: string;
ticklerDate?: string;
notes?: string;
}
// DTOs - Task
export interface CreateTaskDto {
title: string;
domain: TaskDomain;
context?: TaskContext;
priority?: number;
estimatedDuration?: number;
dueDate?: string;
projectId?: string;
notes?: string;
status?: TaskStatus;
followUpDate?: string;
ticklerDate?: string;
}
export interface UpdateTaskDto {
title?: string;
domain?: TaskDomain;
context?: TaskContext;
priority?: number;
estimatedDuration?: number;
dueDate?: string;
projectId?: string;
notes?: string;
status?: TaskStatus;
followUpDate?: string;
ticklerDate?: string;
scheduledStart?: string;
scheduledEnd?: string;
isLocked?: boolean;
}
export interface TaskResponseDto {
id: string;
title: string;
domain: TaskDomain;
context?: TaskContext;
status: TaskStatus;
priority?: number;
estimatedDuration?: number;
dueDate?: string;
scheduledStart?: string;
scheduledEnd?: string;
isLocked: boolean;
projectId?: string;
notes?: string;
followUpDate?: string;
ticklerDate?: string;
connectwisePriority?: string;
connectwiseSLA?: string;
createdAt: string;
updatedAt: string;
}
export interface TaskFilterDto {
status?: TaskStatus;
context?: TaskContext;
domain?: TaskDomain;
projectId?: string;
}
// DTOs - Project
export interface CreateProjectDto {
name: string;
domain: TaskDomain;
description?: string;
desiredOutcome?: string;
connectwiseProjectId?: string;
}
export interface UpdateProjectDto {
name?: string;
domain?: TaskDomain;
description?: string;
desiredOutcome?: string;
status?: ProjectStatus;
}
export enum ProjectStatus {
ACTIVE = 'ACTIVE',
ON_HOLD = 'ON_HOLD',
COMPLETED = 'COMPLETED',
}
export interface ProjectResponseDto {
id: string;
name: string;
domain: TaskDomain;
description?: string;
desiredOutcome?: string;
status: ProjectStatus;
connectwiseProjectId?: string;
createdAt: string;
updatedAt: string;
}
// Health check
export interface HealthCheckResponseDto {
status: 'ok' | 'error';
database: 'connected' | 'disconnected';
redis: 'connected' | 'disconnected';
}
// Error response
export interface ErrorResponseDto {
statusCode: number;
message: string;
timestamp: string;
path?: string;
}

View File

@@ -0,0 +1,18 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}