# System Architecture ## Deployment model (hybrid) **Phase 1–2:** Self-hosted single-tenant (FillCare) with web UI **Phase 3+:** Multi-tenant SaaS on shared infrastructure Design all entities with optional `workspaceId` from day one. ## High-level architecture ```mermaid flowchart TB subgraph client [Client Layer] WebUI[Web Dashboard] API_Consumers[API / CLI] end subgraph app [Application Layer] API[Express API] Auth[Auth Middleware] CampaignSvc[Campaign Service] RecipeSvc[Recipe Engine] StatsSvc[Statistics Service] ContentSvc[AI Content Service] end subgraph workers [Worker Layer] Scheduler[Cron Scheduler] SendWorker[Send Queue Worker] RescueWorker[Rescuer Worker] StatsWorker[Stats Rollup Worker] end subgraph connectors [Connectors] SMTP[nodemailer] IMAP[imapflow] AI[OpenRouter] end subgraph data [Data Layer] DB[(SQLite → Postgres)] Queue[(Job Queue)] end WebUI --> API API_Consumers --> API API --> Auth API --> CampaignSvc API --> StatsSvc Scheduler --> SendWorker Scheduler --> RescueWorker SendWorker --> SMTP SendWorker --> ContentSvc ContentSvc --> AI RescueWorker --> IMAP RescueWorker --> ContentSvc workers --> DB API --> DB SendWorker --> Queue ``` ## Component responsibilities | Component | Responsibility | |-----------|----------------| | **API** | CRUD mailboxes, campaigns, settings; stats queries | | **Campaign Service** | Lifecycle: draft → active → paused → completed | | **Recipe Engine** | Compute `DailySchedule` from recipe params | | **Dispatcher / Send Worker** | Enqueue sends with jitter; role-aware pairing | | **Rescuer Worker** | IMAP spam scan, rescue, reply sampling | | **AI Content Service** | Generate + validate email bodies | | **Stats Service** | Aggregations, rollups, on-track calculation | | **Scheduler** | Cron triggers; reload on settings change | ## Data store evolution | Phase | Database | Queue | |-------|----------|-------| | MVP (now) | SQLite | In-process cron | | Phase 2 | SQLite | SQLite-backed queue or BullMQ | | SaaS | PostgreSQL | Redis + BullMQ | Use Prisma driver adapters; swap datasource URL for Postgres. ## Multi-tenant (future) ```mermaid flowchart LR subgraph tenantA [Workspace A] A1[Primary] A2[Satellites] end subgraph tenantB [Workspace B] B1[Primary] B2[Satellites] end API --> tenantA API --> tenantB ``` - Row-level isolation via `workspaceId` - JWT auth with workspace scope - Encrypted credentials per workspace key (KMS in SaaS) ## Frontend architecture (recommended) | Layer | Tech options | |-------|----------------| | Framework | Next.js or Vite + React | | UI | shadcn/ui + Tailwind | | Data | TanStack Query | | Charts | Recharts | | Auth | Clerk / Auth.js (SaaS) | Serve as separate app or static build proxied by Express. ## Observability | Concern | Tool | |---------|------| | Logs | Pino (existing) | | Errors | Sentry | | Metrics | Prometheus / Grafana (SaaS) | | Job tracing | Correlation ID per send | ## Security boundaries - Credentials encrypted at rest (AES-256-GCM) - API key (self-hosted) → JWT (SaaS) - No plaintext passwords in logs - IMAP/SMTP connections TLS-only ## Integration points (external) | System | Integration | Phase | |--------|-------------|-------| | Instantly / Smartlead | Read-only: pause warmup when they send | 3 | | Google Postmaster | Pull domain stats | 3 | | Webhooks | Campaign events | 2 | | Stripe | Billing per primary | SaaS | ## Directory structure (target) ``` warmbox/ ├── apps/ │ ├── api/ # Express (current src/) │ └── web/ # Dashboard ├── packages/ │ ├── database/ # Prisma schema │ ├── recipe-engine/ │ └── content-validator/ ├── docs/ └── prisma/ ``` Monorepo optional; single package acceptable through phase 2.