CON-182: Campaign Goals - #105
Conversation
|
Warning Review limit reached
Next review available in: 27 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (10)
WalkthroughCampaigns now support validated publishing schedules and weekly or monthly goal cadence. Content generation uses timezone-aware scheduling and deterministic spread. Campaign overviews expose goal progress by period, including achievement, reach, percentage, and streak data. ChangesCampaign planning
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant ContentPlanGeneration
participant PersistOne
participant Scheduling
ContentPlanGeneration->>PersistOne: pass mutable DraftPost
PersistOne->>Scheduling: compose scheduled timestamp
Scheduling-->>PersistOne: UTC timestamp and effective date
PersistOne-->>ContentPlanGeneration: persist updated DraftPost
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/campaign_actions/overview/service.go`:
- Around line 170-178: The no-window fallback in the overview service must apply
the scheduled_at requirement consistently: update the total-count loop around
isCommitted to increment only when p.ScheduledAt is non-nil. Update
src/campaign_actions/overview/service_test.go lines 271-292 to expect only the
committed post with ScheduledAt; the service.go site requires the implementation
change, and the test site requires the expectation update.
In `@src/scheduling/scheduling.go`:
- Around line 181-182: Update the scheduling logic around SpreadOffset and the
returned effectiveDate so the spread-adjusted local time is clamped to the same
day’s 00:00–23:59 boundaries before converting it to UTC; ensure the returned
date remains consistent with that bounded time, and add tests covering positive
and negative spreads at both day boundaries.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: ef61975f-f599-4b11-ab40-dd8907092009
📒 Files selected for processing (18)
http-client/campaigns/campaigns.httpsrc/campaign_actions/overview/overview.gosrc/campaign_actions/overview/service.gosrc/campaign_actions/overview/service_test.gosrc/campaigngoal/campaigngoal.gosrc/campaigngoal/campaigngoal_test.gosrc/database/migrations/20260807000001_campaign_scheduling.down.sqlsrc/database/migrations/20260807000001_campaign_scheduling.up.sqlsrc/database/migrations/20260808000001_campaign_goals.down.sqlsrc/database/migrations/20260808000001_campaign_goals.up.sqlsrc/genkit/flows/content_plan/generate.gosrc/genkit/flows/content_plan/generate_test.gosrc/genkit/flows/content_plan/prompts/content_plan.tmplsrc/genkit/flows/content_plan/types.gosrc/handlers/campaigns.gosrc/models/campaign.gosrc/scheduling/scheduling.gosrc/scheduling/scheduling_test.go
Reinterpret estimated_post_count as posts PER goal_cadence period and add a goal_cadence column (week|month, default month). The full-campaign content-plan flow now generates estimated_post_count x periods-spanned posts; the targeted generate-posts path keeps its explicit count. - migration 20260808000001_campaign_goals (goal_cadence, backfill 'month') - new pure campaigngoal pkg: Normalize/Periods(ceil)/EffectiveCount/Windows - model + campaignRequest field, validated in Create/Update - overview gains a nullable goal block: per-period buckets of committed (scheduled+published, by scheduled_at) posts vs target, plus overall reached/percent and a trailing streak - unit tests for campaigngoal math and overview goal progress
Make the overview goal fallback (missing/invalid campaign dates) consistent with the windowed branch: TotalAchieved counts committed posts only when scheduled_at is set, so an undated post can't count toward a goal it can't be attributed to a period of.
cf149e4 to
6df0ce2
Compare
Adds a campaign post-rate goal (CON-182). Instead of a single absolute "estimated posts" number, a campaign now expresses a goal as a rate — N posts counted over each week / month — which:
content_planflow generates, andReuses the existing
estimated_post_countas the posts-per-period count and adds one newgoal_cadencecolumn.What changed
Data model
20260808000001_campaign_goals: addsgoal_cadence TEXT NOT NULL DEFAULT 'month'.estimated_post_countis reinterpreted as the target posts per cadence period.New pure package
src/campaigngoal/(stdlib-only, no import cycles, fully unit-tested)Normalize/ValidCadence—week|month, empty →month.Periods(cadence, start, end, loc)— number of periods, partial periods rounded up. Weeks =ceil(daysInclusive/7); months = calendar months touched. Missing/invalid dates →1. Day-counting done in UTC so DST-length days don't skew it.EffectiveCount(...)—perPeriod × Periods(0 when unset → model decides the count, unchanged behavior).Windows(...)— the[Start, End)periods (labelled "Week 1", "Jul 2026") used for progress buckets.content_plan (
generate.go)estCountnow derives fromcampaigngoal.EffectiveCount(...)(timezone resolved viasettings.ResolveTimezone). Everything downstream —planBatches, the "exactly N posts" prompt, phase/platform/date distribution — is unchanged.POST /:id/generate-postspath still uses its explicitcount(not multiplied).REST (
handlers/campaigns.go)goal_cadenceadded to the campaign request DTO, validated viacampaigngoal.Normalize(invalid →400) in both Create and Update, mirroring thenormalizeSchedulingpattern.Overview API (
GET /api/campaigns/:id/overview)goalblock. Buckets count committed posts (scheduled/scheduled_for_manual_publishing/published) by theirscheduled_at, against the per-period target, with an overall verdict and a trailing streak.nullwhen the campaign has no positiveestimated_post_count.The migration backfills
goal_cadence = 'month', so every existing campaign'sestimated_post_countnow means per month. On the next full-plan generation the effective total becomescount × months-spannedinstead ofcount.content_planis user-triggered, so nothing regenerates until a user asks.Decisions (from PRD)
week|month, defaultmonth.scheduled_at.Testing
go build ./...,go vet— clean.src/campaigngoalunit tests: periods (incl.5/weekoverJun 1→Jul 31= 9 → 45), effective count, windows tiling/labels, normalize.src/campaign_actions/overviewgoal tests: weekly buckets, streak + 100%, missing-dates degrade, nil-goal.src/handlerspackage test requires a local Postgres (pre-existing; unrelated to this change).Related
CON-181 (scheduling defaults — same field-add + content_plan-wiring pattern, base of this branch), CON-152 (summaries — future home for a goal badge), CON-113 (overview endpoint this extends).
Summary by CodeRabbit