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
Beginner: Monolith vs Platform
Tech Stack: Every Layer Explained
- Next.js 16.2 (App Router) — File-based routing:
app/w/[workspace]/tasks/page.tsxbecomes/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) incomponents/ui. Customizable via CSS vars inapp/globals.css. - Fumadocs UI — Docs theme (this site). Imports
fumadocs-ui/css/shadcn.css+preset.css. - PWA —
public/manifest.json+public/sw.jsmake it installable on phone/desktop, offline queue. - next-themes — Light/dark toggle (`D` hotkey),
ThemeProviderinapp/layout.tsx.
Entity Graph — How Everything Connects
Not just “tasks” — a graph of 20+ entities. Every row has workspace_id.
Beginner: Why Graph > List
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 ioredisIntelligence (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
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 remindersPermissions & Safety
| Class | Examples | Needs Confirm? |
|---|---|---|
| Read | Read emails, Drive, calendar, finance | No (scoped to workspace) |
| Write (Safe) | Create task, note, reminder, attach file | No |
| Sensitive | Send email, delete file, modify finance, cancel sub | Yes — 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:
Beginner: Where is it?
/w/[workspace]/tasks/[id] has two columns: Context (left) + Details (right). Also available as drawer from any page.Priority Scoring & At-Risk
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 workspaceIdWhy Deterministic > AI for Some Tasks
Design Decision
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.