Campaign is the tenancy boundary
A campaign represents one tracked brand. Nearly every other record hangs off it, and the dashboard is always scoped to the campaign currently selected in the session.GoogleAccount records — ga4_google_account_id and
gsc_google_account_id — so Analytics and Search Console can be connected under different
Google identities. isDomainFullyVerified() is true only when both ga4_domain_verified
and gsc_domain_verified are set.
Prompts
Prompt is the unit of tracking. Its lifecycle is driven by three status constants:
Useful scopes:
active(), suggested(), approved(), status($status) and
forCampaign($campaignId). updateLastRun() stamps the prompt after a batch.
PROMPTS_ACTIVE_LIMIT (default 10) caps how many prompts a campaign may have active at
once, which is what bounds the per-campaign provider spend. PROMPTS_AUTO_SEED controls
whether a new campaign gets a starter set automatically.Prompt runs
PromptRun is one execution of one prompt against one provider. Runs are grouped by
batch_id — scopeByBatchId() is how a whole scheduled batch is retrieved.
Visibility lives on the run:
hasVisibility()— whether the brand was detected in the answergetVisibilityType()— how it appearedscopeWithVisibility()/scopeWithoutVisibility()— filtering for analyticsscreenshot_urlaccessor — resolves the stored SERP screenshot, captured byTakeSearchScreenshotJobvia ScreenshotOne
Sentiment
SentimentRecord holds a scored topic result, with SentimentMention rows for the
individual brand mentions behind the score. The BrandSentiment model namespace holds the
supporting value objects used by the scoring pipeline.
Competitors
Three models cover the competitor flow:DiscoveredCompetitor— domains found in answers, before classificationCompetitorAppearance— per-run appearances used for benchmarkingCompetitorSubdomain— subdomain grouping soblog.example.comandexample.comcount as one competitor
CompetitorClassifier decides which discovered domains are direct competitors. That
verdict feeds non_competitor_penalty in the scoring formula, so misclassification directly
moves visibility scores.