User Stories & Acceptance Criteria
Stories are grouped by epic, mapped to PRD Functional Requirements (FR-#), with Gherkin-style acceptance criteria. Points are rough t-shirt-to-Fibonacci estimates for planning illustration.
Epic 1: Account Connection & Setup
US-1 — Connect ad account
As a performance marketer, I want to connect my Meta Ads account via OAuth so that Ad Copilot can read my campaign data.
- Given I am on the onboarding screen, when I click “Connect Meta Ads,” then I am redirected to Meta’s OAuth consent screen.
- Given I grant permission, when I return to Ad Copilot, then my last 90 days of campaign, ad set, and ad-level performance data begins syncing.
- Given the sync is in progress, when I view the dashboard, then I see a sync-status indicator rather than an empty or misleading state.
- Given I deny permission or the OAuth flow fails, when I return to Ad Copilot, then I see a clear error message and a retry option.
US-2 — Set performance targets per campaign
As a performance marketer, I want to set a target ROAS or CPA per campaign so that the system knows when performance has drifted.
- Given I’ve connected an account, when I open a campaign’s settings, then I can input a target ROAS or target CPA (not both).
- Given no target is set, when drift monitoring runs, then that campaign is excluded from recommendations and marked “no target set.”
Epic 2: Creative Generation
US-3 — Generate ad copy variants on demand
As a performance marketer, I want to generate new ad copy variants for a specific ad set so that I can replace fatiguing creative quickly.
- Given I select an ad set and click “Generate variants,” when generation completes, then I see 3–5 headline/primary-text/CTA combinations.
- Given variants are generated, when I view them, then each displays a confidence score.
- Given the product feed is missing required fields, when I attempt generation, then I receive a specific error naming the missing field.
US-4 — Scheduled creative refresh
As a performance marketer, I want to schedule automatic variant generation for ad sets that show fatigue signals so that I don’t have to manually monitor for decay.
- Given I enable “auto-refresh” on an ad set, when fatigue is detected (e.g. CTR decline), then new variants are generated into the review queue.
- Given auto-refresh is enabled, when no fatigue signal occurs, then no unnecessary generation calls are made.
US-5 — Brand-safety filtering on generated copy
As a brand/compliance stakeholder, I want to screen generated ad copy against a wordlist so that non-compliant or off-brand copy never reaches a reviewer.
- Given a generated variant contains a blocked term, when generation completes, then that variant is suppressed and never appears in the review queue.
- Given a variant is suppressed, when an admin views generation logs, then the suppressed variant and matched term are visible for audit.
Epic 3: Monitoring & Recommendations
US-6 — Detect performance drift
As a system, I want to compare live performance against campaign targets hourly so that drift is caught before days of wasted spend.
- Given a campaign has a target CPA, when actual CPA exceeds target by more than the configured threshold for the configured duration, then a recommendation is generated.
- Given the ad platform API is rate-limited or returns stale data, when the sync job runs, then the system retries with backoff and flags data as stale rather than acting on incomplete data.
US-7 — Receive a budget/bid recommendation with reasoning
As a performance marketer, I want to see why a recommendation was made so that I can evaluate it instead of blindly trusting or distrusting it.
- Given a recommendation is generated, when I open it, then I see the triggering metric, current vs target value, and proposed action.
- Given a recommendation is generated, when I open it, then I see a confidence score and plain-language explanation — not just raw model output.
Epic 4: Review Lanes & Human-in-the-Loop
US-8 — Lane assignment for AI actions
As a system, I want to classify every AI action into Auto-apply, Suggest, or Escalate so that risk is proportional to autonomy.
- Given confidence score and blast radius are calculated, when lane assignment runs, then the action is placed in exactly one lane.
- Given an account is new (below data-volume threshold), when any action is generated, then it is placed in Suggest or Escalate — never Auto-apply.
US-9 — Review and act on a queued recommendation
As a performance marketer, I want to approve, reject, or edit a queued recommendation so that I retain control over budget-impacting actions.
- Given a Suggest-lane item, when I click Approve, then the action executes against the ad platform API and is logged.
- Given a Suggest-lane item, when I click Edit, then I can modify the proposed value before approving.
- Given I reject a recommendation, when I do so, then I can optionally provide a reason stored to improve future scoring.
US-10 — Audit log and rollback
As a performance marketer, I want to see a full history of AI actions and roll them back so that I never lose visibility or control.
- Given any AI action has been taken, when I view the audit log, then I see action, timestamp, lane, confidence, and status.
- Given an Auto-apply action was taken within the last 5 minutes, when I click Rollback, then the prior budget/bid is restored and logged.
US-11 — Configure lane thresholds per account
As a admin user, I want to adjust confidence/blast-radius thresholds so that the system’s risk tolerance matches our account’s needs.
- Given I am an admin, when I raise the Auto-apply confidence threshold, then fewer actions qualify going forward.
- Given I attempt a threshold that allows unbounded budget risk, when I save, then the system blocks the change and explains why.
Epic 5: Cost Controls
US-12 — Enforce monthly generation caps
As a business, I want to cap LLM generation calls per account per month so that AI cost doesn’t scale unpredictably against plan tier.
- Given an account has reached its monthly cap, when further generation is attempted, then the request is blocked with a clear message and upgrade option.
- Given an account crosses 80% of its cap, when this threshold is crossed, then the account owner receives a proactive notification.
US-13 — Tiered model routing
As a system, I want to use a lower-cost model for first-pass and reserve the higher-cost model for top candidates so that generation cost stays proportionate.
- Given a generation request produces an initial candidate set, when top-N are selected, then only those N are refined with the higher-cost model.
- Given refinement fails or times out, when this occurs, then first-pass candidates are still surfaced rather than failing silently.
US-14 — Cache reuse for unchanged inputs
As a system, I want to reuse prior generation outputs when product-feed input hasn’t changed so that we avoid redundant model calls.
- Given a product feed entry is unchanged within the caching window, when a new generation request is made, then cached outputs are served.
- Given cached outputs are served, when the user views them, then they carry no “stale” stigma in the UI.
Backlog summary
| Epic | Stories | P0 | Points |
|---|---|---|---|
| Account Connection & Setup | 2 | 2 | 8 |
| Creative Generation | 3 | 2 | 18 |
| Monitoring & Recommendations | 2 | 2 | 13 |
| Review Lanes & HITL | 4 | 3 | 21 |
| Cost Controls | 3 | 2 | 18 |
Suggested MVP cut: all P0 stories (13 stories, ~72 points), deferring US-4, US-11, and US-14 (P1) to Phase 2.
More in this series