# Self-Host Hardening Breakpoint Warmbox pauses new feature work here (before Phase 3 SaaS). Phases 1–2 are implemented for **local self-host** daily operator use. ## What works today | Area | Location | Operator actions | |------|----------|------------------| | API + jobs | `apps/api/` | Cron dispatcher, rescuer, stats, send queue | | Dashboard | `apps/web/` | Mailboxes, campaigns, stats, compliance, settings | | Shared types | `packages/shared/` | API DTOs used by web + api | | Database | `prisma/` | SQLite via `DATABASE_URL` in root `.env` | ### Run locally ```bash npm install npx prisma migrate dev npm run dev # API :3000, dashboard :5173 # or production: npm run build && npm run start ``` ### Run on Ubuntu / VPS (Docker) For a **30-day live test** without keeping your laptop on, see **[deploy-ubuntu-docker.md](./deploy-ubuntu-docker.md)** (Docker Compose + Cloudflare Tunnel or Caddy). ## Operator workflows (no curl required) 1. **Mailboxes** — add, edit credentials, test connection, DNS check 2. **Campaigns** — 4-step wizard, start/pause/resume, edit settings tab 3. **Compliance** — automatic domain age (RDAP), DNS, Postmaster when connected 4. **Monitoring** — dashboard overview, placement charts, job triggers in Settings ## Google Postmaster Tools (compliance auto-check) 1. Settings → **Google Postmaster Tools** 2. Enable [Gmail Postmaster Tools API](https://console.cloud.google.com/apis/library/gmailpostmastertools.googleapis.com) 3. Create OAuth Web credentials with redirect URI: `http://localhost:3000/api/integrations/google/callback` 4. Verify your domain at [postmaster.google.com](https://postmaster.google.com) 5. Paste Client ID + Secret → Save → **Connect Google Postmaster** 6. Campaign compliance tab will show pass/fail for your primary domain Optional: set `PUBLIC_BASE_URL` in `.env` if not using `http://localhost:3000`. ## Microsoft Outlook (@live.com / @outlook.com) Microsoft **disabled basic authentication** for consumer accounts. App passwords from [account.live.com/proofs/AppPassword](https://account.live.com/proofs/AppPassword) will fail with `535 5.7.139 basic authentication is disabled`. Use OAuth instead: 1. Settings → **Microsoft Outlook** 2. Register an app in [Azure App registrations](https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade) (personal Microsoft accounts) 3. Redirect URI: `http://localhost:3000/api/integrations/microsoft/callback` 4. API permissions: delegated `IMAP.AccessAsUser.All`, `SMTP.Send` 5. Save Client ID + Secret in Settings 6. Mailboxes → Add → Outlook → **Connect Microsoft** → Add Mailbox To fix an existing Outlook mailbox: Mailbox detail → **Edit** → **Connect Microsoft** → Save. ## Gmail connection errors (535 BadCredentials) Use a Google **App Password**, not your normal login password: 1. Enable 2FA on the Google account 2. Create an app password at https://myaccount.google.com/apppasswords 3. Mailbox detail → **Edit** → paste app password → Save → **Test Connection** ## “Off track” on dashboard Means today's sends or reply rate are behind the daily plan. Early in the day (first 1–2 sends), campaigns stay **on track** until enough volume accumulates. Sends are spaced by design (45+ min jitter + cron interval), so a 10-email day ramps over many hours. ## Campaign editing limits | Status | Editable fields | |--------|-----------------| | Draft | All fields | | Active / Maintenance | Name, timezone, send window, reply rate; satellites tab (add/remove) | | Paused | Above + duration, min/max volume, recipe (future schedule rebuilt) | | Completed / Failed | None | **One primary per mailbox** — a mailbox can only be the primary on one non-completed campaign at a time (draft, active, paused, or maintenance). Delete draft campaigns from the campaigns list to free a mailbox. **Compliance tab** — checks run live on each load. Use **Re-run compliance check** after DNS fixes, Postmaster connection, or mailbox changes. ## Mailbox roles - New mailboxes start as **unassigned** - Campaign creation assigns **primary** and **satellite** roles - Edit role on mailbox detail: satellite ↔ unassigned (remove from campaigns first); primary is set via campaigns only - Adding a mailbox runs a connection test first — failed connections are rejected with a clear error ## Paused here (Phase 3+) - Multi-tenant JWT auth - Postgres migration - Stripe billing - Webhooks / Postmaster push alerts See `docs/16-roadmap.md` for the full roadmap.