DLRSDLRS
Getting Started

Architecture — Full System Design

Beginner to advanced: how DLRS works end-to-end. Covers every module, data flow, database, agents, and design decisions with keywords explained.

High-Level System

DLRS Personal OS
Web App (PWA)
Next.js 16 + React 19 + Tailwind + shadcn
App Router
API (/api/*)
Tenancy Guards (DAL)
Route handlers
Assistant
Multi-Agent System (9 agents)
Orchestrator
Intelligence Layer
Agents · Extraction · Scoring · Context Engine
PostgreSQL (Prisma 7.10)
+ @prisma/adapter-pg · DAL tenancy guards
Background Job Queue
ioredis · extract · gmail_ingest · reminders
npm run worker

Beginner: Monolith vs Platform

DLRS is a Next.js monolith that acts like a platform: web app, API, and agents live together for simplicity, but background jobs run separately via Redis queue. No microservices complexity for beginners.

Tech Stack: Every Layer Explained

  • Next.js 16.2 (App Router) — File-based routing: app/w/[workspace]/tasks/page.tsx becomes /w/my-studio/tasks. Server Components by default, Client Components with "use client".
  • React 19.2 — UI library. Tailwind handles styling.
  • Tailwind CSS v4 — Utility classes (flex p-4 bg-muted) compiled via @tailwindcss/postcss.
  • shadcn/base-mira — Pre-built components (Button, Card, Dialog) in components/ui. Customizable via CSS vars in app/globals.css.
  • Fumadocs UI — Docs theme (this site). Imports fumadocs-ui/css/shadcn.css + preset.css.
  • PWA — public/manifest.json + public/sw.js make it installable on phone/desktop, offline queue.
  • next-themes — Light/dark toggle (`D` hotkey), ThemeProvider in app/layout.tsx.

Entity Graph — How Everything Connects

Not just “tasks” — a graph of 20+ entities. Every row has workspace_id.

users— workspace_members— workspaces
clients
contact_email
projects
client_id
tasks
project_id · client_id
calendar_events
starts_at
transactions
subscriptions
Task
task_files → files (Drive/uploads)
workspace_id · ai_confidence
task_links — links
task_notes
task_checklist_items
task_work_sessions (timer)
task_dependencies (blocks)
task_activity (audit)
emails— attachments— documents
reminders— notifications— activity_log
automation_rules—jobs—job_runs

Beginner: Why Graph > List

A task isn't isolated. “GB reel” task links to client GB, project Social Media, 3 emails, Drive folder, 2 previous reels, and a calendar hold. Click Start Work and you get it all. No manual linking.

Every row has workspace_id. Every important field has provenance:

tasks row: {
  title: "Create 3 reels",
  source_type: "gmail",
  source_id: "email_abc123",
  ai_confidence: 0.94,
  created_by: "Email Intelligence Agent"
}

Ask “Why deadline Friday?” → shows snippet from Gmail ID abc123.

Data Flow: Capture → Intelligence → Action

Capture (Ingestion)

User: paste/screenshot/file/voice/URL/Gmail webhook
→ POST /api/inbox or /api/webhooks/inbox
→ Store raw in inbox_items { content, type, workspace_id }
→ Enqueue job: "extract" via ioredis

Intelligence (Agents)

Worker picks job → Inbox Agent:
- Classify: task|invoice|meeting|subscription|personal
- Extract: client, project, tasks[], deadline (date-fns), people, links, priority
- Detect relationships: does client exist? link to project?

If email → Email Agent adds classification.
If file → Drive Agent indexes, Document Agent parses tables/dates.
If statement → Finance Agent validates totals.

Action (Proposal → Execution)

Orchestrator proposes:
- Create tasks (safe, auto)
- Find Drive assets (safe)
- Schedule reminders (safe)
- Send email (sensitive → needs confirm)

User reviews modal → Confirm → rows created, search indexed, notifications sent.

Orchestrator & 9 Agents

Inbox Agent
Classify input, extract entities & relationships
Task Agent
Prioritize, deps, at-risk, next-action, score 0–100
Project Agent
Health, milestones, summaries, progress
Email Agent
Gmail ingest → task vs receipt vs subscription
Drive / File Agent
Index Drive, link to client/project, search
Document Agent
PDF/DOCX tables, requirements, dates, summarization
Calendar Agent
Events, conflicts, commitment graph, daily briefing
Finance Agent
Statements (deterministic totals), categorization, subs
Search Agent
Personal memory: Drive + emails + tasks in one query

Input: “Bro 3 reels for GB before Saturday. Photos in Drive.”

Inbox Agent → Tasks: 3 reels, Deadline: Saturday, Assets: Drive
→ Creates project if missing, queues Drive search
→ Notification Agent schedules reminders

Permissions & Safety

ClassExamplesNeeds Confirm?
ReadRead emails, Drive, calendar, financeNo (scoped to workspace)
Write (Safe)Create task, note, reminder, attach fileNo
SensitiveSend email, delete file, modify finance, cancel subYes — modal + audit

Every tool call logged to activity_log with workspace_id, user_id, tool, args, result, provenance.

Context Engine & Packs

For task “Create GB Event Reel” — tap Start Work to open:

Context
GB Banquet→ brand, contacts
Social Media→ milestones
Drivelogo, GB-Dec-2025 photos, previous reels
2 threads mentioning GB
“Use summer banner”
Details
High · Score 84 · Due Saturday
Checklist: ☑ Download ☐ Select ☐ Edit ☐ Export
Blocked by “Client sends photos”
Next: “Ask client for final logo”
Requirements from extraction → Instructions + Files + Emails + Checklist assembled — no manual hunting.

Beginner: Where is it?

Click any task → Start Work → full page /w/[workspace]/tasks/[id] has two columns: Context (left) + Details (right). Also available as drawer from any page.

Priority Scoring & At-Risk

Score 0–100 — auto, transparent
Adds up from deadline + context. No manual guessing.
Due ≤7 days+10
Due ≤3 days+20
Due ≤1 day+30
Overdue+40
Client waiting+20
Blocks other tasks+15
High-value client+10
Project at risk+15
Maps to
0–24
Low
25–49
Medium
50–74
High
75+
Critical
At-Risk
remaining_estimated (90m) > available_working_time (2h before deadline) → badge red
At-Risk
Displayed: “High · Due Aug 28 · 84 score · Blocks 1”

Jobs, Queue & Tenancy

Job Queue (ioredis)

Queue: "extract", "gmail_ingest", "drive_index", "reminder"
Worker: npm run worker (separate process)
Job: { id, workspace_id, type, payload, attempts }
Run: jobs → job_runs (logs output/error)

Tenancy Enforcement

Every query: db.task.findMany({ where: { workspaceId } })
Check: npm run check:tenancy → scans lib/** for unscoped findMany/update/delete
Fail CI if missing workspaceId

Why Deterministic > AI for Some Tasks

Design Decision

AI for: understanding messages, extraction, summarization, classification, planning.
Code for: dates, reminders, cron, recurring, totals, balances — cheaper, reliable, testable. Never let LLM do arithmetic.

Example: Bank totals validated in TypeScript: openingMinor + sum(credits) − sum(debits) === closingMinor — LLM only categorizes merchant names.

On this page