Initial Ralph scaffold

This commit is contained in:
Debian
2026-01-11 07:51:30 +00:00
commit ce0e5f1769
21 changed files with 2858 additions and 0 deletions

33
docs/architecture.md Normal file
View File

@@ -0,0 +1,33 @@
# Architecture
## Application Type
**web**
The application is explicitly described as a 'self-hosted web application' with a React or Vue SPA frontend and calendar week view interface, accessed via browser rather than native desktop or mobile apps.
## Interface Types
- rest_api
- websocket
REST API is required for external integrations (iOS Shortcuts, CLI scripts, browser extensions, capture endpoint). WebSocket enables real-time updates for automatic task rescheduling when calendar conflicts arise and notifications for displaced tasks without page refresh.
## Persistence
**local_db**
Designed for self-hosted deployment with SQLite or PostgreSQL options specified. While PostgreSQL could be remote_db, the self-hosted context and SQLite option indicate local database persistence on the same infrastructure where the app runs.
## Deployment
**self_hosted**
Explicitly stated as 'self-hosted' with containerized Docker Compose deployment for user-managed infrastructure, not cloud platforms or app stores. Users deploy and maintain on their own servers.
## Suggested Tech Stack
- **Language**: TypeScript
- **Framework**: Node.js (NestJS backend) + React (Vite frontend) + PostgreSQL
TypeScript provides type safety across full stack for complex scheduling logic and GTD workflows. NestJS offers robust REST API structure, dependency injection for external integrations (CalDAV, ConnectWise, IMAP, Microsoft Graph), scheduled jobs for recurring reviews, and WebSocket support. React with a calendar library (FullCalendar or react-big-calendar) handles the interactive drag-drop week view. PostgreSQL over SQLite for better concurrency with multiple capture sources and complex scheduling queries. Docker Compose orchestrates backend, database, and frontend nginx container for simple self-hosted deployment.

233
docs/data-models.md Normal file
View File

@@ -0,0 +1,233 @@
# Data Models
## User
| Field | Type | Required |
|-------|------|----------|
| id | UUID | Yes |
| email | string | Yes |
| passwordHash | string | Yes |
| name | string | Yes |
| timezone | string | Yes |
| workingHours | JSON | Yes |
| notificationPreferences | JSON | Yes |
| lastWeeklyReview | timestamp | No |
| createdAt | timestamp | Yes |
| updatedAt | timestamp | Yes |
### Relationships
- Has many InboxItems
- Has many Tasks
- Has many Projects
- Has many CalendarConnections
## InboxItem
| Field | Type | Required |
|-------|------|----------|
| id | UUID | Yes |
| userId | UUID | Yes |
| content | text | Yes |
| source | enum | Yes |
| sourceMetadata | JSON | No |
| processed | boolean | Yes |
| processedAt | timestamp | No |
| createdAt | timestamp | Yes |
### Relationships
- Belongs to User
- Can convert to Task or Project
## Task
| Field | Type | Required |
|-------|------|----------|
| id | UUID | Yes |
| userId | UUID | Yes |
| projectId | UUID | No |
| title | string | Yes |
| description | text | No |
| status | enum | Yes |
| context | enum | No |
| domain | enum | Yes |
| priority | integer | No |
| dueDate | timestamp | No |
| estimatedDuration | integer | No |
| scheduledStart | timestamp | No |
| scheduledEnd | timestamp | No |
| isLocked | boolean | Yes |
| completedAt | timestamp | No |
| connectwiseTicketId | string | No |
| connectwisePriority | string | No |
| connectwiseSLA | string | No |
| waitingForDetails | text | No |
| followUpDate | timestamp | No |
| ticklerDate | timestamp | No |
| createdAt | timestamp | Yes |
| updatedAt | timestamp | Yes |
### Relationships
- Belongs to User
- Belongs to Project (optional)
- Has many ReschedulingEvents
## Project
| Field | Type | Required |
|-------|------|----------|
| id | UUID | Yes |
| userId | UUID | Yes |
| name | string | Yes |
| description | text | No |
| desiredOutcome | text | No |
| domain | enum | Yes |
| status | enum | Yes |
| connectwiseProjectId | string | No |
| completedAt | timestamp | No |
| createdAt | timestamp | Yes |
| updatedAt | timestamp | Yes |
### Relationships
- Belongs to User
- Has many Tasks
- Has many ReferenceMaterials
## ReferenceMaterial
| Field | Type | Required |
|-------|------|----------|
| id | UUID | Yes |
| projectId | UUID | Yes |
| title | string | Yes |
| content | text | No |
| url | string | No |
| filePath | string | No |
| createdAt | timestamp | Yes |
### Relationships
- Belongs to Project
## CalendarConnection
| Field | Type | Required |
|-------|------|----------|
| id | UUID | Yes |
| userId | UUID | Yes |
| provider | enum | Yes |
| calendarUrl | string | No |
| credentials | JSON | Yes |
| isActive | boolean | Yes |
| lastSyncAt | timestamp | No |
| createdAt | timestamp | Yes |
### Relationships
- Belongs to User
- Has many CalendarEvents
## CalendarEvent
| Field | Type | Required |
|-------|------|----------|
| id | UUID | Yes |
| calendarConnectionId | UUID | Yes |
| externalId | string | Yes |
| title | string | Yes |
| startTime | timestamp | Yes |
| endTime | timestamp | Yes |
| isAllDay | boolean | Yes |
| syncedAt | timestamp | Yes |
### Relationships
- Belongs to CalendarConnection
## ConnectWiseConnection
| Field | Type | Required |
|-------|------|----------|
| id | UUID | Yes |
| userId | UUID | Yes |
| companyId | string | Yes |
| publicKey | string | Yes |
| privateKey | string | Yes |
| apiUrl | string | Yes |
| memberId | string | Yes |
| isActive | boolean | Yes |
| lastSyncAt | timestamp | No |
| createdAt | timestamp | Yes |
### Relationships
- Belongs to User
## EmailConnection
| Field | Type | Required |
|-------|------|----------|
| id | UUID | Yes |
| userId | UUID | Yes |
| provider | enum | Yes |
| imapHost | string | No |
| imapPort | integer | No |
| credentials | JSON | Yes |
| inboxFolder | string | Yes |
| isActive | boolean | Yes |
| lastCheckAt | timestamp | No |
| createdAt | timestamp | Yes |
### Relationships
- Belongs to User
## ReschedulingEvent
| Field | Type | Required |
|-------|------|----------|
| id | UUID | Yes |
| taskId | UUID | Yes |
| originalStart | timestamp | Yes |
| originalEnd | timestamp | Yes |
| newStart | timestamp | Yes |
| newEnd | timestamp | Yes |
| reason | string | Yes |
| notificationSent | boolean | Yes |
| createdAt | timestamp | Yes |
### Relationships
- Belongs to Task
## Notification
| Field | Type | Required |
|-------|------|----------|
| id | UUID | Yes |
| userId | UUID | Yes |
| type | enum | Yes |
| title | string | Yes |
| message | text | Yes |
| relatedEntityId | UUID | No |
| read | boolean | Yes |
| sentAt | timestamp | Yes |
### Relationships
- Belongs to User

207
docs/features.md Normal file
View File

@@ -0,0 +1,207 @@
# Features
## 1. GTD Inbox Capture
**ID**: `gtd_inbox_capture`
Multi-source task capture system that ingests tasks from manual web form, REST API, email (IMAP/Microsoft Graph), and ConnectWise Manage sync into an unprocessed inbox for later GTD clarification
### User Story
As a user, I want to capture tasks from multiple sources into a single inbox, so that I can process them later using GTD methodology without losing any input
### Acceptance Criteria
- [ ] Manual tasks can be submitted via web form quick-add and appear in inbox
- [ ] REST API endpoint accepts task capture from external tools and creates inbox items
- [ ] IMAP or Microsoft Graph email monitor converts incoming emails to inbox items
- [ ] ConnectWise Manage sync creates inbox items for new service/project tickets and zero-ticket projects
- [ ] All inbox items retain source metadata (timestamp, origin, attachments) until processed
## 2. GTD Processing Workflow
**ID**: `gtd_processing_workflow`
Interactive inbox processing interface that guides users through GTD clarification: converting raw inbox items into Next Actions with context tags, Projects, Waiting For items, Someday/Maybe, Reference Material, Tickler items, or Trash
### User Story
As a user, I want to process inbox items using GTD decision tree, so that each item becomes actionable or is appropriately filed
### Acceptance Criteria
- [ ] Inbox view displays unprocessed items with processing workflow controls
- [ ] User can clarify items into: Next Action (@context), Project, Waiting For, Someday/Maybe, Reference, Tickler, or Trash
- [ ] Next Actions require context label assignment (@desk, @phone, @errand, @homelab, @anywhere)
- [ ] Waiting For items accept optional follow-up date
- [ ] Tickler items accept future date and automatically surface to inbox on that date
- [ ] Processed items disappear from inbox and appear in appropriate GTD list
## 3. ConnectWise Manage Integration
**ID**: `connectwise_integration`
Read-only sync from ConnectWise Manage that imports service tickets, project tickets, and projects assigned to user. Projects with zero tickets surface as planning tasks. ConnectWise priority/SLA displayed for reference only; user assigns manual priority
### User Story
As a ConnectWise user, I want my assigned tickets and projects to flow into my GTD system automatically, so that I can manage work context alongside personal tasks
### Acceptance Criteria
- [ ] ConnectWise API integration syncs assigned service tickets as inbox items
- [ ] ConnectWise project tickets sync as inbox items with project association
- [ ] ConnectWise projects with zero tickets create planning task inbox items
- [ ] ConnectWise priority and SLA data displayed on task for reference but does not affect scheduling
- [ ] User can manually assign priority to all ConnectWise-sourced tasks
- [ ] Sync runs on configurable schedule and detects ticket status changes
## 4. Intelligent Calendar Scheduling
**ID**: `intelligent_calendar_scheduling`
Automatic scheduling engine that pulls from CalDAV calendars (Nextcloud, Google Calendar, Outlook via Microsoft Graph) and places actionable tasks into available time slots, respecting working hours, context constraints, deadlines, and manual priority. Supports drag-drop manual override and task locking
### User Story
As a user, I want the system to automatically schedule my next actions into my calendar based on context and availability, so that I have a realistic daily plan without manual time blocking
### Acceptance Criteria
- [ ] Engine reads existing events from CalDAV/Google/Outlook calendars
- [ ] Tasks scheduled only during user-defined working hours per day-of-week
- [ ] Work-context tasks (@desk, @phone) constrained to work hours; personal tasks schedulable anytime
- [ ] Scheduling batches tasks by context (consecutive @phone calls, grouped deep work)
- [ ] Manual priority rankings respected; deadlines enforced
- [ ] When calendar conflicts arise from new meetings, displaced tasks automatically reschedule
- [ ] Users can drag-drop tasks to override placement and lock tasks to fixed slots
- [ ] Weekly Review block auto-scheduled at recurring time
## 5. Interactive Calendar Week View
**ID**: `calendar_week_view`
React SPA with interactive week-view calendar displaying scheduled tasks and calendar events. Supports drag-and-drop task rescheduling, manual time adjustments, and real-time updates when scheduling changes occur
### User Story
As a user, I want a visual week view of my scheduled tasks and events with drag-and-drop editing, so that I can see and adjust my plan at a glance
### Acceptance Criteria
- [ ] Week view renders all scheduled tasks and synced calendar events
- [ ] Tasks draggable to different time slots and days
- [ ] Drag-drop updates trigger rescheduling of dependent tasks
- [ ] Tasks visually color-coded by context (@desk, @phone, etc.)
- [ ] Locked tasks display lock indicator and resist auto-rescheduling
- [ ] Real-time updates via WebSocket when scheduler makes changes
- [ ] Click-to-edit task details and priority in modal
## 6. Weekly Review Interface
**ID**: `weekly_review_interface`
Dedicated GTD Weekly Review interface with auto-scheduled recurring review block. Shows all active projects, next actions per project, unprocessed inbox count, waiting-for items, and someday/maybe list for systematic review
### User Story
As a GTD practitioner, I want a comprehensive weekly review interface, so that I can maintain clarity on all commitments and keep my system current
### Acceptance Criteria
- [ ] Weekly Review block auto-scheduled at user-configured recurring time
- [ ] Review interface displays all active projects with status
- [ ] Next actions grouped by project with completion status
- [ ] Unprocessed inbox item count prominently displayed
- [ ] Waiting For items listed with follow-up dates
- [ ] Someday/Maybe list accessible for potential activation
- [ ] Review completion checkbox updates last-review timestamp
## 7. GTD Contexts and Life Domains
**ID**: `gtd_contexts_and_domains`
Context label system (@desk, @phone, @errand, @homelab, @anywhere) and domain organization covering Work (ConnectWise tasks), Homelab (Proxmox, networking, 3D printing, NAS), Daily Routines (meals, exercise, supplements), House (maintenance, errands, cleaning), and Professional Development (Azure certification)
### User Story
As a user, I want to organize tasks by context and life domain, so that I can work efficiently based on my current situation and maintain balance across life areas
### Acceptance Criteria
- [ ] Tasks taggable with context labels (@desk, @phone, @errand, @homelab, @anywhere)
- [ ] Tasks assignable to domains: Work, Homelab, Daily Routines, House, Professional Development
- [ ] Filtering views by context show only relevant tasks
- [ ] Scheduling engine respects context constraints (work contexts during work hours)
- [ ] Domain views aggregate tasks and projects per life area
- [ ] Context-based batching groups similar tasks in schedule
## 8. Waiting For and Tickler System
**ID**: `waiting_for_and_tickler`
Waiting For list tracks items delegated or awaiting external input with optional follow-up dates. Tickler/Deferred items stored with future activation dates and automatically surface to inbox on specified date
### User Story
As a user, I want to track delegated tasks and future reminders, so that I follow up appropriately and activate tasks at the right time
### Acceptance Criteria
- [ ] Waiting For list displays all items awaiting external action
- [ ] Waiting For items accept optional follow-up date
- [ ] Items with follow-up dates highlighted when date arrives
- [ ] Tickler items stored with future date and hidden until activation
- [ ] Scheduled job checks daily for Tickler items reaching activation date
- [ ] Activated Tickler items automatically appear in inbox for processing
## 9. GTD Project Management
**ID**: `project_management`
Project hierarchy supporting multi-step outcomes with next actions, reference material attachments, notes, and project status tracking. ConnectWise projects with zero tickets surface as planning tasks requiring work breakdown
### User Story
As a user, I want to manage projects with next actions and reference materials, so that I maintain forward motion on multi-step goals
### Acceptance Criteria
- [ ] Projects created with name, description, desired outcome, and domain
- [ ] Each project can have multiple next actions with completion tracking
- [ ] Reference material (files, links, notes) attachable to projects
- [ ] Project status tracked (active, on-hold, completed)
- [ ] Projects without next actions flagged in Weekly Review
- [ ] ConnectWise projects with zero tickets create planning task to define work breakdown
- [ ] Project completion requires all next actions completed
## 10. Notifications and Rescheduling Alerts
**ID**: `notifications_and_rescheduling`
Real-time notification system via WebSocket, email, and optional webhook when automatic rescheduling occurs due to calendar conflicts, when Waiting For follow-ups are due, or when Tickler items activate
### User Story
As a user, I want to be notified when my schedule changes automatically, so that I stay aware of my updated commitments
### Acceptance Criteria
- [ ] WebSocket push notifications to active browser sessions when tasks reschedule
- [ ] Email notifications sent for rescheduling events if user preferences allow
- [ ] Webhook endpoint configurable for external notification integrations
- [ ] Notification includes displaced task, original time, new time, and reason
- [ ] Waiting For follow-up notifications sent when follow-up date arrives
- [ ] Tickler activation notifications sent when item surfaces to inbox
- [ ] Notification preferences configurable per notification type

12
docs/idea-dump.md Normal file
View File

@@ -0,0 +1,12 @@
# Original Idea
AutoScheduler: Self-Hosted GTD Task Scheduler with ConnectWise Integration
AutoScheduler is a self-hosted web application that implements the Getting Things Done methodology with automatic calendar scheduling. It ingests tasks from multiple sources: a manual capture inbox, email (via IMAP or Microsoft Graph API), and read-only sync from ConnectWise Manage (service tickets, project tickets, and projects assigned to the user). Projects imported from ConnectWise with zero tickets surface as planning tasks requiring work breakdown. The system supports full GTD constructs: Inbox for capture, Next Actions with context labels (@desk, @phone, @errand, @homelab, @anywhere), Waiting For items with optional follow-up dates, Someday/Maybe for uncommitted ideas, Reference Material attachments on projects, and Tickler/Deferred items that surface to inbox on a specified date. All task priorities are manually assigned by the user; ConnectWise priority/SLA data is displayed for reference only.
The scheduling engine pulls from CalDAV-compatible calendars (Nextcloud, Google Calendar via API, or Microsoft Graph for Outlook) and places actionable tasks into available time slots. Scheduling respects user-defined working hours per day-of-week, with work-context tasks constrained to work hours and personal tasks schedulable outside them. The engine batches tasks by context when possible (consecutive @phone calls, grouped deep work blocks) while respecting deadlines and manual priority rankings. When calendar conflicts arise from new meetings, displaced tasks automatically reschedule to the next available slot. Users can manually override any placement via drag-drop, and lock specific tasks to fixed time slots. A recurring Weekly Review block is auto-scheduled, with a dedicated review interface showing all active projects, next actions per project, unprocessed inbox items, waiting-for items, and the someday/maybe list.
The personal life domain covers four areas: Homelab (Proxmox, networking, 3D printing, NAS projects), Daily Routines (meals, exercise, supplements), House (maintenance, errands, cleaning), and Professional Development (Microsoft Azure certification study). Work domain tasks flow from ConnectWise Manage and email, processed through the GTD inbox. The tech stack should prioritise self-hosting simplicity: containerised deployment (Docker Compose), SQLite or PostgreSQL for persistence, and a React or Vue SPA frontend with a calendar week view. Authentication via local accounts or OIDC. Notifications for rescheduling events via webhook or email.
Capture Methods
The system must support multiple task capture mechanisms for the GTD inbox: a quick-add form in the web UI for manual entry, a REST API endpoint for external integrations (iOS Shortcuts, CLI scripts, browser extensions), an email-to-inbox address or IMAP folder monitor that converts emails to inbox items, and optionally a Telegram/Signal bot or webhook receiver for mobile capture. Inbox items arrive as raw text with optional metadata (source, timestamp, attached links) and remain unprocessed until the user clarifies them into actionable tasks, projects, reference material, or trash during the processing workflow.

62
docs/interfaces.md Normal file
View File

@@ -0,0 +1,62 @@
# Interface Contracts
## REST API
**Type**: rest_endpoints
### Endpoints
| Method | Path | Description |
|--------|------|-------------|
| POST | /api/v1/auth/register | Register new user account |
| POST | /api/v1/auth/login | Authenticate user and return JWT |
| POST | /api/v1/auth/refresh | Refresh JWT token |
| GET | /api/v1/inbox | Get all unprocessed inbox items |
| POST | /api/v1/inbox | Create inbox item via quick capture |
| POST | /api/v1/inbox/:id/process | Process inbox item into task/project/etc |
| DELETE | /api/v1/inbox/:id | Delete/trash inbox item |
| GET | /api/v1/tasks | Get tasks with filtering (context, status, domain) |
| POST | /api/v1/tasks | Create new task |
| PATCH | /api/v1/tasks/:id | Update task details, priority, or status |
| DELETE | /api/v1/tasks/:id | Delete task |
| POST | /api/v1/tasks/:id/schedule | Manually schedule or reschedule task |
| POST | /api/v1/tasks/:id/lock | Lock task to fixed time slot |
| POST | /api/v1/tasks/:id/unlock | Unlock task for auto-scheduling |
| GET | /api/v1/tasks/waiting-for | Get all Waiting For items |
| GET | /api/v1/tasks/someday-maybe | Get Someday/Maybe list |
| GET | /api/v1/tasks/tickler | Get future Tickler items |
| GET | /api/v1/projects | Get all projects |
| POST | /api/v1/projects | Create new project |
| PATCH | /api/v1/projects/:id | Update project details or status |
| DELETE | /api/v1/projects/:id | Delete project |
| GET | /api/v1/projects/:id/tasks | Get all tasks for a project |
| POST | /api/v1/projects/:id/reference | Add reference material to project |
| GET | /api/v1/calendar/events | Get calendar events for date range |
| GET | /api/v1/schedule | Get scheduled tasks for date range |
| POST | /api/v1/schedule/regenerate | Trigger full schedule regeneration |
| GET | /api/v1/weekly-review | Get Weekly Review data |
| POST | /api/v1/weekly-review/complete | Mark Weekly Review as completed |
| GET | /api/v1/connections/calendar | Get calendar connections |
| POST | /api/v1/connections/calendar | Create calendar connection |
| PATCH | /api/v1/connections/calendar/:id | Update calendar connection |
| DELETE | /api/v1/connections/calendar/:id | Remove calendar connection |
| POST | /api/v1/connections/calendar/:id/sync | Trigger manual calendar sync |
| GET | /api/v1/connections/connectwise | Get ConnectWise connection status |
| POST | /api/v1/connections/connectwise | Create ConnectWise connection |
| PATCH | /api/v1/connections/connectwise/:id | Update ConnectWise connection |
| DELETE | /api/v1/connections/connectwise/:id | Remove ConnectWise connection |
| POST | /api/v1/connections/connectwise/:id/sync | Trigger manual ConnectWise sync |
| GET | /api/v1/connections/email | Get email connection status |
| POST | /api/v1/connections/email | Create email connection |
| PATCH | /api/v1/connections/email/:id | Update email connection |
| DELETE | /api/v1/connections/email/:id | Remove email connection |
| GET | /api/v1/notifications | Get user notifications |
| PATCH | /api/v1/notifications/:id/read | Mark notification as read |
| GET | /api/v1/user/preferences | Get user preferences and settings |
| PATCH | /api/v1/user/preferences | Update user preferences |
## WebSocket Events
**Type**: websocket_events

1239
docs/research-notes.md Normal file

File diff suppressed because it is too large Load Diff

44
docs/tech-stack.md Normal file
View File

@@ -0,0 +1,44 @@
# Tech Stack
- **Language**: TypeScript
- **Runtime**: Node.js 20
- **Framework**: NestJS 10
- **Testing**: Jest (backend), Vitest (frontend)
- **Build Tool**: Docker Compose, pnpm workspaces, tsup
## Libraries
- TypeORM
- PostgreSQL
- @nestjs/jwt
- @nestjs/passport
- @nestjs/websockets
- @nestjs/platform-socket.io
- @nestjs/schedule
- @nestjs/config
- class-validator
- class-transformer
- bcrypt
- date-fns
- ical.js
- node-caldav
- @microsoft/microsoft-graph-client
- imap
- axios
- bull
- ioredis
- helmet
- express-rate-limit
- React 18
- Vite 5
- React Router
- TanStack Query (React Query)
- Zustand
- FullCalendar
- react-beautiful-dnd
- socket.io-client
- date-fns
- React Hook Form
- Zod
- TailwindCSS
- Radix UI