Campaigns
This folder documents the Campaigns section of Leadmetrics — a unified hub for planning, executing, and measuring marketing campaigns across all channels.
Related: Workflow Model — how campaigns link to Strategy → Deliverables → Activities | Channels — connected channel integrations | Agents — AI workers used in campaign generation
Contents
- Overview
- Campaign Types
- Data Model
- AI Agents
- API Routes
- Dashboard UI
- Workflow & Permissions
- Open Questions
Overview
Campaigns is a first-class section of the Leadmetrics platform. It provides a unified hub with channel-specific detail views for managing all marketing campaigns — paid ads, email marketing, social media, SEO outreach, and review generation.
Design principles:
- Unified model: One
Campaignentity withtypeandchannel[]fields rather than separate tables per campaign type. Channel-specific behaviour surfaces in the detail views. - AI-assisted at every stage: Agents help generate briefs, write copy, suggest audiences, and recommend optimisations. Every AI action is gated behind human approval.
- DM creates, client approves: The DM team manages the full campaign lifecycle. Clients are brought in at the
client_reviewstage to approve before launch. - Optional workflow integration: Campaigns can exist standalone or be linked to a
DeliverablePeriodso they appear in the monthly deliverables plan. - Double-approval for auto-pilot: When auto-pilot is enabled for paid ads campaigns, every AI-initiated optimisation batch still requires DM + client approval before executing on the platform.
- Import or create: Paid ads campaigns can be imported from a connected platform (Google Ads, Meta Ads, LinkedIn Ads) or created in Leadmetrics first. Either way, metrics are synced back per campaign once a
CampaignExternalMappingis established.
Campaign Types
| Type | Channels | Primary AI Workers |
|---|---|---|
paid_ads | Google Ads, Meta Ads, LinkedIn Ads | google-ads-writer, meta-ads-writer, linkedin-ads-writer, ads-analyst |
email_marketing | Mailchimp, Klaviyo | email-writer, campaign-brief-writer |
social_media | Facebook, Instagram, LinkedIn, X, TikTok | social-post-writer, social-post-designer, campaign-brief-writer |
seo_outreach | Email (backlink outreach) | backlink-outreach-writer |
review_generation | Email, SMS (GBP review drip) | review-campaign-writer |
Existing Foundations
The following are already built and will be reused or extended:
- Models:
Campaign+CampaignEmail(currently backlink-outreach only) — to be generalised - Workers:
google-ads-writer,meta-ads-writer,ads-analyst,google-ads-insights,meta-ads-insights,email-writer,backlink-outreach-writer - Channel integrations: Google Ads, Meta Ads, LinkedIn Ads, Facebook, Instagram, LinkedIn, GBP (all via
ConnectedChannel) - Platform API wrappers:
getCampaignsAsLookup()(Google Ads) andgetMetaCampaignPerformanceSummary()(Meta) already exist in the provider packages — used by Flow A and Flow B - Workflow pattern:
dm_review → dm_approved → client_review → client_approved— same as blog/social - DM portal: Existing campaign routes at
GET/PATCH /dm/v1/campaigns— to be aligned with the new unified model
Open Questions
Activity FK: Should✅ Resolved —Activitygain acampaignIdFK to link generated content back to the campaign?Activity.campaignIdFK added (model #7 in data-model.md).- Credits / quota: Should campaign content generation draw from the existing deliverable-period quota, or should campaigns have a separate credit budget tracked at the campaign level?
Notifications: Should status transitions trigger in-app + email notifications to relevant users?✅ Resolved — notification triggers are fully spec’d in workflow.md.- Scheduled sync frequency: How often should the daily metrics sync run for active
paid_adscampaigns? (Suggested: once per day at midnight tenant-local time, or a fixed UTC schedule.) LinkedIn Ads metrics: Does the LinkedIn Ads provider need new methods for per-campaign metrics?✅ Resolved — newpackages/providers/linkedin/src/linkedin-ads.tsprovider file spec’d in api.md.
Out of Scope (v1)
- SMS infrastructure (beyond review drip trigger)
- WhatsApp campaigns
- TikTok Ads
- Native A/B test framework (variants are written by the agent but split-testing infrastructure is deferred)
- In-app SMTP (email sending continues via Mailchimp / Klaviyo)
Future Work (Post-v1 Backlog)
Identified gaps to be specced and built after v1. Grouped by priority.
High Priority
UTM Parameter Management
Every campaign URL should have auto-generated UTM parameters (utm_source, utm_medium, utm_campaign, utm_content). Without this, Google Analytics cannot attribute traffic to campaigns.
- Add
CampaignUtmConfigmodel (or UTM fields onCampaign) — source, medium, campaign name, content variant, optional custom slug - UTM builder step in the creation wizard (Step 2 — Details)
- Short-link / redirect option (integrate with a link shortener or use Leadmetrics tracking domain)
- UTM preview + copy-to-clipboard per campaign URL
- All ad copy and email CTAs should reference the configured UTM-appended URL
Budget Pacing & Spend Alerts
Campaign.budget exists but there is no pacing logic. A campaign burning through its monthly budget in week 2 needs an alert.
- Add
totalSpentas a computed/rolled-up field (sum ofCampaignMetrics.spend) - Add pacing indicator: spent % vs time elapsed % — shown on the Overview tab and Performance tab
- Add
budget_overpacerecommendation type toCampaignOptimizationRecommendation(threshold: spent > 60% of budget in first 40% of the campaign period) - Add
budget_underpacealert too — campaign is underdelivering
Campaign Goal / KPI Progress Tracking
Campaign.brief holds KPI targets as free text only. The “goal progress widget” on the Overview tab has no structured data source.
- Add target KPI fields to
Campaign:targetImpressions,targetClicks,targetLeads,targetConversions,targetRoas,targetReviews,targetBacklinks— nullable, filled by the DM during setup or bycampaign-brief-writer - Overview tab progress bars: each KPI field vs the matching metric from
CampaignMetrics campaign-brief-writershould write structured KPI targets as JSON alongside the free-text brief
Contact List Management
ReviewCampaign.contactListId and CampaignAudience reference contact lists, but there is no spec for how those lists are built.
- Define how contacts are selected: CRM lead tag filter, saved query, manual CSV upload, or dynamic query (re-evaluated on each enroll run)
- Add a Contact List builder UI step in the wizard for
email_marketingandreview_generationcampaigns - Show enrolled count, pending count, completed count, opted-out count on the Sequence tab
- Handle unsubscribes / opt-outs — sync back from ESP or flag manually; exclude from future steps
Campaign Templates DMs setting up the same type of campaign repeatedly should be able to start from a pre-built template.
- Add
CampaignTemplatemodel: type, channels, goal, brief skeleton, default sequence steps, default audience filters, optional UTM config skeleton - Template picker in the Creation Wizard step 1 — “Start from template” or “Start from scratch”
- Platform-seeded templates: e.g. “Local Business Google Ads Lead Gen”, “B2B LinkedIn Ads Awareness”, “Post-Purchase Review Drip”, “Monthly Newsletter”, “Backlink Outreach — Resource Page”
- DMs can save any completed campaign as a template
Medium Priority
Campaign Cloning / Duplication
A DM should be able to duplicate an existing campaign into a new draft — useful when re-running the same campaign for a new month or a similar client.
- Add
POST /tenant/v1/campaigns/:id/cloneendpoint - Clones: brief, audiences, sequence structure, UTM config, target KPIs — with a new name and reset status to
draft - Does NOT clone: metrics, external mappings, generated content (Activities)
- Clone button on the Campaign Detail Settings tab
Email Platform Sync (Flow A/B for Email)
Paid ads have import (Flow A) and metrics sync (Flow B). Email marketing campaigns have neither. The email metrics fields in CampaignMetrics currently have no data source.
- Flow A: import existing Mailchimp / Klaviyo campaigns into Leadmetrics (
GET /campaigns/import?channel=mailchimp) - Flow B: sync open rates, click rates, unsubscribes back from the ESP per campaign on a daily schedule
- Requires new provider methods in
packages/providers/mailchimp/andpackages/providers/klaviyo/(or a shared email-provider abstraction) - Optionally: push sequences created in Leadmetrics to the ESP as an automation flow
Social Media Post Scheduling
social_media campaigns generate content but there is no scheduling model. There is no link between a generated post (Activity) and a publish date.
- Add
scheduledAtandpublishedAtfields to theActivitymodel (or a join tableCampaignPostSchedule) - Calendar view in the Campaign Content tab showing scheduled posts per platform per day
- Integrate with the existing
social-calendar-plannerworker — it should write scheduled dates per post back to the campaign - Publish action: when
scheduledAtis reached, enqueue a publish job per connected social channel
Campaign Activity Feed / Timeline No per-campaign timeline view. DMs and clients need a chronological log of everything that happened inside a campaign.
- Add a Timeline tab (or collapsible panel) to Campaign Detail
- Renders filtered audit log entries scoped to
entityId === campaign.idand linkedActivity/CampaignOptimizationRecommendationrecords - Events to surface: brief generated, content approved, campaign submitted, client approved, metrics synced, optimisation applied, status changes
- Add
GET /tenant/v1/campaigns/:id/timelineendpoint
Landing Page Association Paid ads and email campaigns drive traffic to a landing page. Associating a landing page with a campaign enables full-funnel reporting (ad CTR → landing page conversion rate) in one view.
- Add optional
landingPageUrlandlandingPageId(FK toLandingPageif one exists in the system) fields onCampaign - Performance tab: show landing page conversion rate alongside ad/email CTR if a landing page is associated
- Set in wizard Step 2 — Details
Campaign Labels / Tags
Simple string tags on Campaign for filtering and grouping.
- Add
tagsasString[]onCampaign - Multi-select tag input in the wizard and Settings tab
- Tag filter on the Campaigns Hub list and analytics page
- Suggested tags: quarter (Q1 2026), theme (Product Launch, Evergreen, Seasonal), client initiative
Lower Priority (V2)
Behaviour-based Email Sequence Triggers
CampaignSequence.triggerType supports on_subscribe | on_date | manual — no behavioural branching.
- “Re-enroll contact if they didn’t open in 14 days”
- “Exit sequence if lead converts”
- “Branch to alternate sequence if contact clicked link A but not link B”
- Requires a sequence branching model and a trigger evaluation job
Campaign-scoped Performance Report DMs should be able to generate a client-friendly PDF/rich report for a single campaign, not just a deliverable period.
- Trigger
report-writerscoped to a campaign — passesCampaignMetrics, brief KPIs, and optimisation history as context - Add
POST /tenant/v1/campaigns/:id/generate-reportendpoint - Output stored as an
Activitylinked to the campaign
Multi-Campaign Linking / Campaign Groups No concept of campaign relationships. A Google Ads campaign and a retargeting email sequence targeting the same converted leads should be linkable.
- Add
relatedCampaignIds String[]onCampaign, or aCampaignGroupmodel (name, tenantId, campaignIds[]) - Group view in the analytics page: show combined funnel across linked campaigns
- A/B path tracking: if two campaigns target the same audience with different approaches, compare conversion rates side by side
Rules-based Pause / Resume Auto-pause/resume without requiring manual HITL approval for threshold-based financial guardrails.
- “Pause this campaign if daily spend > $X” — set in Settings tab, respected by the optimizer scheduler
- “Resume when ROAS > 2.0 for 3 consecutive days”
- Only available for admin users; requires explicit opt-in per campaign
- Distinct from the existing auto-pilot (which generates recommendations but never executes automatically)