110 lines
3.7 KiB
Markdown
110 lines
3.7 KiB
Markdown
# 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": "<PRIMARY_ID>",
|
||
"recipe": "grow",
|
||
"durationDays": 30,
|
||
"satelliteMailboxIds": ["<SAT1_ID>", "<SAT2_ID>"]
|
||
}'
|
||
|
||
# 5. Start campaign → verify 30 schedule rows
|
||
curl -s -X POST http://localhost:3000/api/campaigns/<CAMPAIGN_ID>/start
|
||
curl -s http://localhost:3000/api/campaigns/<CAMPAIGN_ID> | jq '.dailySchedules | length'
|
||
|
||
# 6. Pause
|
||
curl -s -X POST http://localhost:3000/api/campaigns/<CAMPAIGN_ID>/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)
|