# Sprint 1.1 — Domain Model, Grow Recipe, AI Validator **Status:** Implemented **Epics:** E1, E2 (Grow subset), E6 ## Goal Campaign-centric warmup model with workspace scoping, Grow recipe schedules, and AI content validation — without campaign-aware sending yet. ## Acceptance checklist - [x] Default workspace exists; all inboxes scoped to workspace - [x] Create primary + satellites via API with `google_workspace` provider preset - [x] Create campaign; assign shared satellite across primaries in same workspace - [x] `POST /api/campaigns/:id/start` generates `durationDays` DailySchedule rows - [x] `POST /api/recipes/preview` returns Grow ramp - [x] `POST /api/campaigns/:id/pause` / `resume` lifecycle - [x] `transitionToMaintenance()` adds 20% maintenance schedule row - [x] AI content validator rejects placeholders, spam triggers, URLs - [x] Legacy flat dispatcher skipped when any campaign exists - [x] `npm run build` and `npm test` pass ## New API endpoints | Method | Path | |--------|------| | POST/GET/PATCH/DELETE | `/api/campaigns` | | POST | `/api/campaigns/:id/start` | | POST | `/api/campaigns/:id/pause` | | POST | `/api/campaigns/:id/resume` | | GET/POST/DELETE | `/api/campaigns/:id/satellites` | | POST | `/api/recipes/preview` | | GET | `/api/recipes/templates` | | POST | `/api/ai/test-generate` | | * | `/api/mailboxes` (alias of `/api/inboxes`) | ## Manual QA script ```bash # Start server npm run dev # 1. Primary (Google Workspace preset — any email) curl -s -X POST http://localhost:3000/api/inboxes \ -H "Content-Type: application/json" \ -d '{ "email": "hello@yourdomain.com", "provider": "google_workspace", "username": "hello@yourdomain.com", "password": "your-app-password", "role": "primary", "industry": "Childcare", "senderName": "Jon", "companyName": "FillCare" }' # 2. Satellites (repeat for 2+ accounts) curl -s -X POST http://localhost:3000/api/inboxes \ -H "Content-Type: application/json" \ -d '{ "email": "satellite@gmail.com", "provider": "gmail", "username": "satellite@gmail.com", "password": "app-password", "role": "satellite" }' # 3. Preview Grow ramp curl -s -X POST http://localhost:3000/api/recipes/preview \ -H "Content-Type: application/json" \ -d '{"recipe":"grow","durationDays":30,"minEmailsPerDay":1,"maxEmailsPerDay":40,"replyRatePercent":30}' # 4. Create campaign (use IDs from step 1–2) curl -s -X POST http://localhost:3000/api/campaigns \ -H "Content-Type: application/json" \ -d '{ "name": "Primary warmup", "primaryMailboxId": "", "recipe": "grow", "durationDays": 30, "satelliteMailboxIds": ["", ""] }' # 5. Start campaign → verify 30 schedule rows curl -s -X POST http://localhost:3000/api/campaigns//start curl -s http://localhost:3000/api/campaigns/ | jq '.dailySchedules | length' # 6. Pause curl -s -X POST http://localhost:3000/api/campaigns//pause # 7. Test AI validator (requires AI_API_KEY) curl -s -X POST http://localhost:3000/api/ai/test-generate \ -H "Content-Type: application/json" \ -d '{"industry":"Childcare","senderName":"Jon","companyName":"FillCare"}' ``` ## Out of scope (Sprint 1.3+) - Campaign-aware dispatcher sends - Reply rate sampling - Statistics dashboard API - Flat / Randomized / Custom recipes ## Key files - [`prisma/schema.prisma`](../prisma/schema.prisma) - [`src/services/campaign.service.ts`](../src/services/campaign.service.ts) - [`src/services/recipe.service.ts`](../src/services/recipe.service.ts) - [`src/services/content-validator.service.ts`](../src/services/content-validator.service.ts) - [`src/routes/campaigns.routes.ts`](../src/routes/campaigns.routes.ts)