Files
nick-tracker/PROMPT.md
2026-01-11 07:51:30 +00:00

226 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PROMPT.md nick-tracker (AutoScheduler GTD System)
## Objective
Build **AutoScheduler**, a self-hosted web application implementing the Getting Things Done (GTD) methodology with automatic calendar scheduling. The system ingests tasks from multiple sources (manual capture, email via IMAP/Microsoft Graph, read-only ConnectWise Manage sync), processes them through GTD workflows (Inbox → Next Actions/Projects/Waiting For/Someday-Maybe/Tickler), and automatically schedules actionable tasks into available calendar slots from CalDAV-compatible sources (Nextcloud, Google Calendar, Outlook). The scheduling engine respects user-defined working hours, context constraints (@desk, @phone, @errand, @homelab, @anywhere), deadlines, and manual priorities, batching similar tasks when possible and automatically rescheduling displaced tasks when calendar conflicts arise. A React SPA with interactive week-view calendar supports drag-and-drop manual overrides and task locking. Weekly Review interface auto-schedules and presents comprehensive system review. Real-time notifications via WebSocket, email, and optional webhook inform users of schedule changes and follow-up reminders.
**Core Value Proposition:** Unified GTD task management across work (ConnectWise) and personal domains (Homelab, Daily Routines, House, Professional Development) with intelligent automatic scheduling that respects context, time constraints, and priorities, eliminating manual time-blocking while maintaining GTD methodology integrity.
---
## Application Type
**web** Self-hosted web application with React SPA frontend and NestJS backend API, accessed via browser. Containerized deployment via Docker Compose for user-managed infrastructure. No native desktop or mobile apps required; responsive web UI serves all devices.
---
## Architecture
### Core Components
1. **Frontend (React SPA)**
- Interactive week-view calendar with drag-and-drop task scheduling
- GTD workflow interfaces: Inbox processing, Next Actions, Projects, Weekly Review
- Real-time updates via WebSocket for automatic rescheduling notifications
- Task capture quick-add form and external REST API endpoint
- Settings UI for calendar connections, email/ConnectWise integration, working hours
2. **Backend (NestJS API)**
- REST API for CRUD operations on tasks, projects, inbox items, connections
- WebSocket gateway for real-time notifications and schedule updates
- Scheduled jobs (cron) for: email polling, ConnectWise sync, calendar sync, Tickler activation, Weekly Review scheduling
- Task scheduling engine with constraint satisfaction and conflict resolution
- Integration services: CalDAV client, Microsoft Graph client, Google Calendar API, ConnectWise Manage API, IMAP/SMTP
3. **Database (PostgreSQL)**
- Relational schema: Users, InboxItems, Tasks, Projects, CalendarEvents, ReschedulingEvents, Notifications
- Foreign keys enforce referential integrity; indexes optimize scheduler queries
- JSON columns for flexible metadata (workingHours, notificationPreferences, sourceMetadata)
4. **Message Queue (Redis + Bull)**
- Asynchronous job processing for long-running syncs (ConnectWise, email, calendar)
- Rate limiting and retry logic for external API calls
- Queue-based scheduling engine to prevent concurrent conflicts
5. **Container Orchestration (Docker Compose)**
- Services: backend (NestJS), database (PostgreSQL), cache (Redis), frontend (nginx serving static build)
- Volumes for PostgreSQL persistence, file uploads (reference materials)
- Health checks, restart policies, environment-based configuration
### Interfaces
- **REST API:** Full CRUD for all entities, connection management, manual scheduling overrides, Weekly Review operations
- **WebSocket:** Real-time push notifications for rescheduling events, Waiting For follow-ups, Tickler activations
- **External Integrations:** CalDAV (Nextcloud/generic), Microsoft Graph (Outlook/Google Calendar via OAuth), ConnectWise Manage REST API, IMAP/SMTP
### Deployment
**self_hosted** Docker Compose stack deployed to user's infrastructure (home server, VPS). Users manage environment variables (API keys, DB credentials), backups, and reverse proxy (Traefik/nginx) for HTTPS. Optional OIDC authentication for enterprise users; local account authentication default.
---
## Tech Stack
- **Language:** TypeScript (strict mode, ES2022 target)
- **Runtime:** Node.js 20 LTS
- **Backend Framework:** NestJS 10 (modules, dependency injection, guards, interceptors)
- **Frontend Framework:** React 18 (functional components, hooks) + Vite 5 (build tool)
- **Database:** PostgreSQL 16 (relational, JSONB support)
- **ORM:** TypeORM 0.3 (Active Record pattern, migrations, query builder)
- **State Management:** Zustand (lightweight, minimal boilerplate)
- **Data Fetching:** TanStack Query (React Query v5) for server state caching
- **Routing:** React Router v6 (nested routes, loaders)
- **Calendar UI:** FullCalendar (drag-drop, resource timeline, week view)
- **Drag-and-Drop:** react-beautiful-dnd (accessible drag-drop for task lists)
- **WebSocket:** socket.io (NestJS WS adapter, auto-reconnect)
- **Job Queue:** Bull (Redis-backed task queues, cron scheduling)
- **Cache:** Redis 7 (Bull queue storage, session cache)
- **Authentication:** Passport.js (JWT strategy, optional OIDC)
- **Validation:** class-validator, class-transformer (backend DTOs), Zod (frontend forms)
- **Styling:** TailwindCSS 3 + Radix UI (accessible component primitives)
- **Date Handling:** date-fns (timezone-aware, immutable)
- **Calendar Protocols:** ical.js (iCal parsing), node-caldav (CalDAV client)
- **External APIs:** @microsoft/microsoft-graph-client (Outlook/Graph), axios (ConnectWise REST), imap (email polling)
- **Testing:** Jest (backend unit/integration), Vitest (frontend unit), Supertest (API e2e)
- **Containerization:** Docker, Docker Compose v2
- **Monorepo:** pnpm workspaces (shared types package)
- **Build Tools:** tsup (backend bundling), Vite (frontend HMR and build)
---
## Phases & Completion Criteria
### Phase 1: Foundation
**Goal:** Establish project structure, core infrastructure, authentication, and basic database schema. Prove Docker Compose stack runs and REST API accepts requests.
#### Completion Criteria
- [ ] **Monorepo initialized** with pnpm workspaces: `packages/backend`, `packages/frontend`, `packages/shared-types`. Root `package.json` has workspace scripts: `pnpm dev`, `pnpm build`, `pnpm test`. Verify: `pnpm install && pnpm -r list` shows all three workspaces.
- [ ] **Backend NestJS app** scaffolded with modules: `AuthModule`, `UsersModule`, `TasksModule`, `ProjectsModule`, `InboxModule`. Verify: `pnpm --filter backend build` succeeds, `dist/` contains compiled JS.
- [ ] **Frontend React app** created with Vite, TailwindCSS configured, Radix UI installed. Basic route structure: `/login`, `/inbox`, `/calendar`, `/projects`, `/settings`. Verify: `pnpm --filter frontend dev` starts dev server on port 5173, homepage renders.
- [ ] **PostgreSQL database** schema created via TypeORM migrations: `User`, `InboxItem`, `Task`, `Project`, `CalendarConnection`, `CalendarEvent`, `ConnectWiseConnection`, `EmailConnection`, `ReferenceMaterial`, `ReschedulingEvent`, `Notification` entities with all fields and relationships from spec. Verify: `pnpm --filter backend migration:run` succeeds, `psql -d autoscheduler -c "\dt"` lists 11 tables.
- [ ] **Docker Compose** stack configured: `backend`, `postgres`, `redis`, `frontend` services. Backend exposes port 3000, frontend port 80, PostgreSQL port 5432 (internal only). Environment variables loaded from `.env` file. Verify: `docker compose up -d && docker compose ps` shows all services healthy, `curl http://localhost:3000/health` returns `{"status":"ok"}`.
- [ ] **Authentication implemented:** JWT-based auth with Passport.js. `/api/v1/auth/register`, `/api/v1/auth/login`, `/api/v1/auth/refresh` endpoints functional. Password hashing with bcrypt (12 rounds). JWT guard protects all routes except auth endpoints. Verify: `curl -X POST http://localhost:3000/api/v1/auth/register -d '{"email":"test@example.com","password":"SecurePass123!","name":"Test User","timezone":"America/New_York"}' -H "Content-Type: application/json"` returns 201 with JWT, subsequent `curl -H "Authorization: Bearer <token>" http://localhost:3000/api/v1/users/me` returns user object.
- [ ] **Frontend authentication flow:** Login form posts to `/api/v1/auth/login`, stores JWT in memory (Zustand), redirects to `/inbox`. Protected routes require auth token, redirect to `/login` if missing. Axios interceptor adds `Authorization` header. Verify: Manual test in browser: register user, log in, see redirect to inbox, refresh page maintains session.
- [ ] **Basic error handling:** Global exception filter in NestJS logs errors, returns standardized JSON error responses (status, message, timestamp). Frontend axios interceptor catches 401, clears token, redirects to login. Verify: `curl http://localhost:3000/api/v1/nonexistent` returns 404 JSON, `curl -H "Authorization: Bearer invalid" http://localhost:3000/api/v1/users/me` returns 401 JSON.
- [ ] **Logging configured:** NestJS Logger configured with timestamps, log levels (dev: debug, prod: info). Winston logger optional enhancement but basic Logger functional. Verify: Backend console shows structured logs on startup and per request.
- [ ] **Type safety enforced:** `shared-types` package exports DTOs (CreateTaskDto, TaskResponseDto, etc.) used by both backend validators and frontend Zod schemas. Verify: Change a field type in `shared-types`, run `pnpm build`, see TypeScript errors in both frontend and backend if mismatched.
- [ ] **Health checks:** `/health` endpoint returns database connection status, Redis connection status. Docker Compose health checks configured for backend (GET /health every 30s). Verify: `curl http://localhost:3000/health` returns `{"status":"ok","database":"connected","redis":"connected"}`, `docker compose ps` shows backend as `healthy`.
**Phase 1 Verification Command:**
```bash
pnpm install && pnpm build && docker compose up -d && sleep 10 && \
curl -f http://localhost:3000/health && \
curl -X POST http://localhost:3000/api/v1/auth/register \
-d '{"email":"verify@test.com","password":"Test123!","name":"Verify User","timezone":"UTC"}' \
-H "Content-Type: application/json" | grep -q "token" && \
echo "✓ Phase 1 Complete"
```
---
### Phase 2: Core Features
**Goal:** Implement GTD workflows (Inbox capture and processing, Next Actions, Projects, Someday/Maybe, Waiting For, Tickler), basic scheduling engine, and interactive calendar week view with drag-and-drop.
#### Completion Criteria
- [ ] **Inbox capture endpoints:** `POST /api/v1/inbox` creates unprocessed InboxItem with source=MANUAL. Fields: content (text), source (enum), sourceMetadata (JSON). Returns created item with ID. Verify: `curl -X POST -H "Authorization: Bearer <token>" http://localhost:3000/api/v1/inbox -d '{"content":"Test inbox item"}' -H "Content-Type: application/json"` returns 201 with `{"id":"uuid","content":"Test inbox item","processed":false}`.
- [ ] **Inbox list and processing:** `GET /api/v1/inbox` returns all unprocessed items for authenticated user. `POST /api/v1/inbox/:id/process` accepts action payload (e.g., `{"action":"task","context":"@desk","domain":"work","title":"Do thing"}`) and converts inbox item to Task, Project, or marks as Trash, setting `processed=true`. Verify: Create inbox item, process to task, GET inbox returns empty array, `GET /api/v1/tasks` includes new task.
- [ ] **Task CRUD:** Full CRUD endpoints for Tasks with validation: `POST /api/v1/tasks` (required: title, domain; optional: context, priority, dueDate, estimatedDuration, projectId), `GET /api/v1/tasks` (with filters: status, context, domain), `PATCH /api/v1/tasks/:id` (partial updates), `DELETE /api/v1/tasks/:id` (soft delete or hard delete based on policy). Task status enum: NEXT_ACTION, WAITING_FOR, SOMEDAY_MAYBE, TICKLER, COMPLETED. Context enum: DESK, PHONE, ERRAND, HOMELAB, ANYWHERE. Domain enum: WORK, HOMELAB, DAILY_ROUTINES, HOUSE, PROFESSIONAL_DEVELOPMENT. Verify: Create task with all fields, GET task by ID returns full object, PATCH updates priority, DELETE removes task.
- [ ] **Task filtering views:** Separate endpoints or query params for GTD views: `GET /api/v1/tasks?status=NEXT_ACTION` (Next Actions), `GET /api/v1/tasks?status=WAITING_FOR` (Waiting For items with follow-up dates), `GET /api/v1/tasks?status=SOMEDAY_MAYBE` (Someday/Maybe list), `GET /api/v1/tasks?status=TICKLER` (future Tickler items). Verify: Create 5 tasks with different statuses, each GET returns only matching tasks.
- [ ] **Project CRUD:** Full CRUD for Projects: `POST /api/v1/projects` (required: name, domain; optional: description, desiredOutcome, connectwiseProjectId), `GET /api/v1/projects` (filter by status: active, on-hold, completed, domain), `PATCH /api/v1/projects/:id`, `DELETE /api/v1/projects/:id`. Verify: Create project, assign task to project via `PATCH /api/v1/tasks/:id` with `projectId`, `GET /api/v1/projects/:id/tasks` returns associated tasks.
- [ ] **Reference material attachments:** `POST /api/v1/projects/:id/reference` accepts multipart file upload or URL/text reference. Creates ReferenceMaterial entity linked to project. File uploads stored in Docker volume, path saved in DB. `GET /api/v1/projects/:id` includes references array. Verify: Upload PDF to project, GET project returns reference with file path, file accessible at `/uploads/:filename` route.
- [ ] **Waiting For follow-up dates:** Tasks with status=WAITING_FOR accept `followUpDate` timestamp. Scheduled job (cron) runs daily, identifies Waiting For items where `followUpDate <= NOW()`, creates Notification for user. Verify: Create Waiting For task with followUpDate tomorrow, manually trigger cron (`POST /api/v1/debug/trigger-cron`), next day notification appears in `GET /api/v1/notifications`.
- [ ] **Tickler activation:** Tasks with status=TICKLER have `ticklerDate`. Daily cron job checks for `ticklerDate <= NOW()`, converts to InboxItem with source=TICKLER, status=PROCESSED, creates notification. Verify: Create Tickler task for tomorrow, run cron job manually, InboxItem appears with content from task title, notification created.
- [ ] **User preferences:** `GET /api/v1/user/preferences` returns user's workingHours (JSON: `{"monday":{"start":"09:00","end":"17:00"},...}`), timezone, notificationPreferences (JSON: `{"email":true,"webhook":false,"webhookUrl":""}`). `PATCH /api/v1/user/preferences` updates preferences. Verify: Update working hours, GET preferences returns new hours.
- [ ] **Basic scheduling engine:** Service (`SchedulingService`) finds available time slots in user's calendar based on working hours and existing CalendarEvents. `POST /api/v1/schedule/regenerate` triggers scheduling: fetches all NEXT_ACTION tasks without `scheduledStart`, assigns `scheduledStart`/`scheduledEnd` within available slots, respecting `estimatedDuration` (default 30 min) and constraints (work contexts only during work hours). Persists scheduled times to Task table. Returns scheduled task count. Verify: Create 3 Next Action tasks (2 @desk, 1 @phone), set working hours 9-5, run regenerate, GET tasks shows scheduledStart/scheduledEnd within 9-5.
- [ ] **Context-based batching:** Scheduling engine groups consecutive tasks with same context when possible (e.g., 3 @phone tasks scheduled 10:00, 10:30, 11:00). Verify: Create 5 @phone tasks, regenerate schedule, GET schedule shows consecutive phone blocks.
- [ ] **Priority and deadline respect:** Scheduling engine sorts tasks by manual priority (1=highest) and dueDate before assigning slots. Higher priority tasks scheduled earlier in available slots. Verify: Create 3 tasks with priorities 1, 2, 3 and no due dates, regenerate, task with priority=1 gets earliest slot; create task with dueDate=today, regenerate, it schedules before lower-priority tasks with later due dates.
- [ ] **Frontend inbox UI:** React component renders unprocessed inbox items as list. Quick-add form at top posts to `/api/v1/inbox`. Each item has "Process" button opening modal with GTD decision tree (Is it actionable? → Yes: Is it multi-step? → Project vs. Next Action; No: Reference/Trash). Modal form submits to `/api/v1/inbox/:id/process`. Optimistic UI updates with React Query mutations. Verify: Manual browser test: add inbox item, process to Next Action with @desk context, see item disappear from inbox.
- [ ] **Frontend calendar week view:** FullCalendar component configured with timeGridWeek view, displays Tasks with `scheduledStart`/`scheduledEnd` as events. Color-coded by context (custom CSS or FullCalendar event color prop). Verify: Create 5 scheduled tasks, navigate to `/calendar`, see tasks rendered in week grid with correct times and colors.
- [ ] **Drag-and-drop manual scheduling:** FullCalendar `eventDrop` callback fires on drag, PATCH `/api/v1/tasks/:id` with new `scheduledStart`/`scheduledEnd`, sets `isLocked=true` to prevent auto-rescheduling. `eventResize` callback handles duration changes. Verify: Drag task in calendar, reload page, task remains at new time, `isLocked=true` in DB.
- [ ] **Task lock/unlock:** `POST /api/v1/tasks/:id/lock` sets `isLocked=true`, `POST /api/v1/tasks/:id/unlock` sets `isLocked=false`. Scheduling engine skips locked tasks. Lock icon displayed in calendar for locked tasks. Verify: Lock task, run schedule regenerate, task time unchanged; unlock, regenerate, task can move.
- [ ] **Next Actions list UI:** React component at `/next-actions` fetches `GET /api/v1/tasks?status=NEXT_ACTION`, renders grouped by context. Filter dropdown by context. Click task opens detail modal with edit form. Verify: Create 10 Next Actions across 3 contexts, filter by @phone, see only phone tasks.
- [ ] **Projects list UI:** React component at `/projects` fetches `GET /api/v1/projects`, renders cards with name, domain, active task count. Click card navigates to `/projects/:id` detail view showing tasks, references, edit form. Verify: Create 3 projects with tasks, navigate to project detail, see tasks listed, add reference material, see it appear.
- [ ] **Waiting For UI:** React component at `/waiting-for` fetches `GET /api/v1/tasks?status=WAITING_FOR`, displays with follow-up dates. Overdue follow-ups highlighted red. Verify: Create Waiting For task with past follow-up date, see red highlight.
- [ ] **Someday/Maybe UI:** React component at `/someday-maybe` fetches `GET /api/v1/tasks?status=SOMEDAY_MAYBE`, allows activation (status change to NEXT_ACTION). Verify: Create Someday task, click "Activate" button, task disappears from Someday list, appears in Next Actions.
**Phase 2 Verification Command:**
```bash
TOKEN=$(curl -s -X POST http://localhost:3000/api/v1/auth/login \
-d '{"email":"verify@test.com","password":"Test123!"}' \
-H "Content-Type: application/json" | jq -r .token) && \
curl -f -X POST -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/v1/inbox \
-d '{"content":"Phase 2 verify"}' -H "Content-Type: application/json" && \
TASK_ID=$(curl -s -X POST -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/v1/tasks \
-d '{"title":"Test task","domain":"WORK","context":"DESK"}' \
-H "Content-Type: application/json" | jq -r .id) && \
curl -f -X POST -H "Authorization: Bearer $TOKEN" \
http://localhost:3000/api/v1/schedule/regenerate && \
curl -s -H "Authorization: Bearer $TOKEN" \
http://localhost:3000/api/v1/tasks/$TASK_ID | jq .scheduledStart | grep -q "T" && \
echo "✓ Phase 2 Complete"
```
---
### Phase 3: Integration
**Goal:** Implement external integrations (CalDAV, Microsoft Graph, ConnectWise Manage, IMAP email capture), real-time WebSocket notifications for rescheduling, conflict detection and automatic rescheduling, Weekly Review scheduling and interface.
#### Completion Criteria
- [ ] **CalDAV connection CRUD:** `POST /api/v1/connections/calendar` creates CalendarConnection with provider=CALDAV, calendarUrl, credentials (username/password encrypted at rest). `GET /api/v1/connections/calendar` lists user's connections. `DELETE /api/v1/connections/calendar/:id` removes connection. Verify: Create CalDAV connection with Nextcloud URL, GET returns connection with masked credentials.
- [ ] **CalDAV sync job:** `CalendarSyncService` using `node-caldav` library queries CalDAV server for events in date range (next 30 days). Creates/updates CalendarEvent entities with externalId, startTime, endTime. Cron job runs every 15 minutes. Manual trigger: `POST /api/v1/connections/calendar/:id/sync`. Verify: Configure CalDAV connection to test Nextcloud instance, create event in Nextcloud, trigger sync, `GET /api/v1/calendar/events?start=<today>&end=<+7days>` returns event.
- [ ] **Microsoft Graph calendar connection:** `POST /api/v1/connections/calendar` with provider=MICROSOFT_GRAPH initiates OAuth flow, stores refresh token. `CalendarSyncService` uses `@microsoft/microsoft-graph-client` to fetch events from Outlook. Verify: Mock Microsoft Graph client in tests to return sample events, trigger sync, events persisted.
- [ ] **Google Calendar API connection:** `POST /api/v1/connections/calendar` with provider=GOOGLE initiates OAuth flow (or accepts service account JSON). `CalendarSyncService` uses Google Calendar API via axios/googleapis. Verify: Mock Google API responses, trigger sync, events persisted with externalId.
- [ ] **ConnectWise Manage connection:** `POST /api/v1/connections/connectwise` accepts companyId, publicKey, privateKey, apiUrl, memberId. `ConnectWiseService` using axios queries `/service/tickets`, `/project/tickets`, `/project/projects` with conditions `owner/id={memberId}`. Creates InboxItems with source=CONNECTWISE, sourceMetadata includes ticketId, priority, SLA. Cron job runs hourly. Verify: Mock ConnectWise API responses (3 tickets), trigger sync, inbox has 3 items with sourceMetadata.
- [ ] **ConnectWise zero-ticket projects:** ConnectWise sync queries projects assigned to user with `/project/projects/:id/tickets` count=0. Creates InboxItem with content="Plan project: {projectName}" and sourceMetadata.connectwiseProjectId. Verify: Mock API returns project with zero tickets, sync creates planning task inbox item.
- [ ] **ConnectWise priority display:** Tasks sourced from ConnectWise store `connectwisePriority` and `connectwiseSLA` fields (strings). Displayed in UI for reference but do not affect scheduling priority (user manually sets `priority` integer). Verify: Process ConnectWise inbox item to task, task has `connectwisePriority="High"`, `priority=null`, user updates `priority=1`, scheduling uses user priority.
- [ ] **IMAP email connection:** `POST /api/v1/connections/email` with provider=IMAP accepts imapHost, imapPort, credentials, inboxFolder. `EmailSyncService` using `imap` library connects, fetches UNSEEN messages, creates InboxItem with content=email subject+body, sourceMetadata includes from, date. Marks email as SEEN. Cron job runs every 5 minutes. Verify: Mock IMAP responses, trigger sync, inbox items created from emails.
- [ ] **Microsoft Graph email connection:** `POST /api/v1/connections/email` with provider=MICROSOFT_GRAPH uses OAuth token to fetch messages from inbox folder via Graph API. Same InboxItem creation logic. Verify: Mock Graph API responses, sync creates inbox items.
- [ ] **Conflict detection on calendar sync:** After calendar sync, `ConflictDetectionService` compares new CalendarEvents against scheduled Tasks. If CalendarEvent overlaps Task's `scheduledStart`/`scheduledEnd` and task is not locked, marks task for rescheduling. Verify: Create scheduled task 10:00-11:00, sync calendar event 10:30-11:30, task marked for rescheduling.
- [ ] **Automatic rescheduling on conflict:** `ReschedulingService` finds next available slot for displaced tasks (respecting working hours, context, priority), updates `scheduledStart`/`scheduledEnd`, creates ReschedulingEvent record with reason, original/new times. Verify: Trigger conflict, rescheduling runs, task moves to 11:30-12:30, ReschedulingEvent created.
- [ ] **WebSocket gateway setup:** NestJS WebSocket gateway (`@WebSocketGateway()`) with JWT authentication guard. Clients connect to `ws://localhost:3000`. On connection, server stores userId-to-socketId mapping. Verify: Frontend connects via socket.io-client, connection established, `getaddrinfo` command shows WebSocket connection in logs.
- [ ] **Real-time rescheduling notifications:** When ReschedulingService reschedules task, emits WebSocket event `task:rescheduled` with payload `{taskId, originalStart, newStart, reason}` to user's socket. Frontend socket.io client listens, shows toast notification, refetches calendar via React Query invalidation. Verify: Open browser with WebSocket devtools, trigger reschedule via API, see WebSocket message received, toast appears.
- [ ] **Notification persistence:** All rescheduling events create Notification entity with type=RESCHEDULING, message, relatedEntityId=taskId. `GET /api/v1/notifications` returns unread notifications. `PATCH /api/v1/notifications/:id/read` marks as read. Frontend shows notification bell icon with count. Verify: Reschedule task, GET notifications returns 1 unread, click mark read, count decreases.
- [ ] **Email notification for rescheduling:** If user's `notificationPreferences.email=true`, `NotificationService` sends email via SMTP (nodemailer) with rescheduling details. Email template includes task title, old/new times, reason. Verify: Mock SMTP server (MailHog), trigger reschedule, check MailHog for email.
- [ ] **Webhook notification:** If `notificationPreferences.webhook=true` and `webhookUrl` configured, `NotificationService` posts JSON payload to webhook URL on rescheduling. Verify: Mock webhook endpoint (webhook.site), trigger reschedule, see POST request received with correct payload.
- [ ] **Weekly Review auto-scheduling:** On user creation or preferences update, `WeeklyReviewService` creates recurring Task with status=WEEKLY_REVIEW, `scheduledStart` at user-configured day/time (e.g., Friday 4 PM), duration 60 min, `isLocked=true`. Cron job checks weekly, ensures review task exists for upcoming week. Verify: Set weekly review time in preferences, trigger cron, GET tasks shows recurring review task at configured time.
- [ ] **Weekly Review interface:** `GET /api/v1/weekly-review` endpoint returns aggregated data: active projects count, projects without next actions (flagged), total Next Actions grouped by project, unprocessed inbox count, Waiting For items with overdue follow-ups, Someday/Maybe count. Frontend `/weekly-review` page displays checklist UI. Verify: Create 2 projects (1 with tasks, 1 without), 5 inbox items, GET weekly-review returns `{"activeProjects":2,"projectsWithoutNextActions":1,"inboxCount":5,...}`.
- [ ] **Weekly Review completion:** `POST /api/v1/weekly-review/complete` updates User.lastWeeklyReview timestamp. Verify: Complete review, GET user preferences shows lastWeeklyReview updated.
- [ ] **Rate limiting on external API calls:** Bull queue configured for calendar, ConnectWise, email sync jobs with concurrency=1, rate limiter (1 request per 2 seconds to respect API limits). Verify: Queue 10 sync jobs, monitor logs, jobs execute sequentially with delay.
- [ ] **Error handling for external APIs:** Sync services wrap API calls in try-catch, log errors, create system Notification for user if sync fails (e.g., "ConnectWise sync failed: invalid credentials"). Failed jobs retry 3 times with exponential backoff (Bull retry strategy). Verify: Mock ConnectWise API to return 401, trigger sync, see error notification created, job retries logged.
- [ ] **Encryption for credentials:** Database credentials (IMAP passwords, API keys) encrypted with AES-256 using secret from environment variable before persisting. Decrypted on retrieval. Use `crypto` module or `@nestjs/config` with encryption utility. Verify: Inspect database, credentials columns show encrypted strings; GET connection via API returns functional connection (decrypt succeeds).
**Phase 3 Verification Command:**
```bash
TOKEN=$(curl -s -X POST http://localhost:3000/api/v1/auth/login \
-d '{"email":"verify@test.com","password":"Test123!"}' \
-H "Content-Type: application/json" | jq -r .token) && \
curl -f -X POST -H "Authorization: Bearer $TOKEN" \
http://localhost:3000/api/v1/connections/calendar \
-d '{"provider":"CALDAV","calendarUrl":"http://mock","credentials":{"username":"test","password":"pass"}}' \
-H "Content-Type: application/json" && \
curl -f -X GET -H "Authorization: Bearer $TOKEN" \
http://localhost:3000/api/v1/weekly-review | jq .inboxCount | grep -E '^[0-9]+$' && \
echo "✓ Phase 3 Complete"
```
---
### Phase 4: Polish
**Goal:** Comprehensive documentation, deployment hardening, performance optimization, accessibility audit, error boundary improvements, and final testing. Prepare for production self-hosted deployment.
#### Completion Criteria
- [ ] **README.md complete:** Root README includes: project overview, architecture diagram (Mermaid or ASCII), prerequisites (Docker, Docker Compose, Node.js for dev), quick-start instructions (clone, `cp .env.example .env`, `docker compose up`), environment variable documentation (all required vars listed with descriptions), default ports, access URLs. Verify: Fresh clone on new machine, follow README, app starts successfully.
- [ ] **Docker Compose production configuration:** `docker-compose.prod.yml` with: PostgreSQL persistent volume, Redis persistent volume, backend health checks, restart policies (`unless-stopped`), resource limits (CPU/memory), nginx serving frontend static files with gzip, security headers (Helmet). Verify: `docker compose -f docker-compose.prod.yml up -d`, all services start with resource constraints visible in `docker stats`.
- [ ] **Environment variable validation:** Backend startup validates required env vars (DATABASE_URL, REDIS_URL, JWT_SECRET, ENCRYPTION_KEY) using `@nestjs/config` with Joi schema. Missing vars log error and exit process. Verify: Remove DATABASE_URL from `.env`, start backend, see error "Missing required env var: DATABASE_URL" and exit code 1.
- [ ] **Database migrations documentation:** `packages/backend/README.md` documents migration workflow: `pnpm migration:generate -n MigrationName`, `pnpm migration:run`, `pnpm migration:revert`. Includes note on production migrations (run before deploying new backend version). Verify: Generate dummy migration, run it, verify in DB, re