SearchScore Agency Spec v2.2 build-ready

New in v2.2: NEW Scan cache semantics, webhook delivery requirements, entitlement re-check, report immutability, downgrade behaviour, billable vs telemetry separation, commercial control rules, white-label tightening

User Requirements & Technical Specification


Version: 2.2

Date: 2026-04-11

Author: Solution Architecture Review

Status: Build-Ready Draft

Updated: v2.2 - commercial control rules, cache semantics, webhook delivery, downgrade behaviour, report immutability




1. Executive Summary


SearchScore is an AI visibility optimisation platform. The Agency Subscription extends the core product to support marketing agencies, SEO consultants and freelancers who manage multiple client websites. Agencies need to demonstrate AI visibility gaps, deliver fixes and prove improvement over time, across all their clients from a single account.


The core product loop remains unchanged: Scan → Understand → Fix → Validate → Track. Every agency feature must support this loop. No scope expansion into social media, email marketing, CRM, campaign management, or generic SEO reporting.


Guiding Principles (non-negotiable)

1. Category focus at all costs - This is NOT an SEO tool, NOT a marketing suite, NOT a generic agency dashboard. It is a focused AI visibility system.

2. Commercially durable - Every architectural decision must support sustainable monetisation.

3. Operationally sane - Usage metering, entitlements, and cost controls are first-class requirements, not afterthoughts.

4. Platform-grade engineering - This is a platform rewrite, not a feature extension. Multi-tenancy, RBAC, queue architecture, and audit logging are structural, not optional.

5. Tool first, platform second - Build the best agency AI visibility tool in the market first. Only expose platform complexity where it increases revenue and defensibility.




2. User Personas


2.1 Primary: Agency Owner / Account Director

Role: Runs a digital marketing agency with 5-50 clients

Goal: Use AI visibility as a new service line or client retention tool

Pain: Needs to quickly show prospects why they're invisible to AI, then deliver measurable improvement

Behaviour: Wants branded reports, fast audits, and a way to manage multiple clients without switching accounts


2.2 Secondary: SEO Consultant / Freelancer

Role: Independent consultant managing 3-15 client sites

Goal: Add AI visibility audits to their service offering

Pain: Needs affordable multi-site access with professional output (reports, share links)

Behaviour: Runs audits during prospect calls, sends branded reports as follow-up


2.3 Tertiary: In-House Marketing Team

Role: Marketing manager overseeing multiple brand properties or subdomains

Goal: Monitor and improve AI visibility across the brand portfolio

Pain: Needs a single view of multiple properties with tracking over time

Behaviour: Weekly monitoring, monthly reporting to leadership




3. User Stories


3.1 Account Management

U-01 As an agency owner, I want to create a single account and manage all my clients under it, so I don't need separate logins

U-02 As an agency owner, I want to invite team members with role-based access (admin, analyst, viewer), so my team can work independently

U-03 As an agency owner, I want visibility into usage by team member, so I can understand who is consuming scans and costs


3.2 Client / Site Management

U-04 As an agency user, I want to add client domains to my workspace within my plan's allowance, so I can scale predictably

U-05 As an agency user, I want to organise clients into groups or folders (e.g. by industry, by account manager), so I can find them quickly

U-06 As an agency user, I want to see a single dashboard showing all client scores at a glance, so I can prioritise attention

U-07 As an agency user, I want to tag clients with custom labels (e.g. "at risk", "high opportunity", "onboarded"), so I can manage my pipeline

U-08 As an agency user, I want to assign a client to a specific team member, so responsibility is clear


3.3 Scanning & Auditing

U-09 As an agency user, I want to run a new scan on any client site from the dashboard, so I can get fresh data on demand

U-10 As an agency user, I want to trigger scans for multiple clients in bulk, so I don't have to do them one by one

U-11 As an agency user, I want to schedule automatic re-scans, so monitoring happens without manual effort

U-12 As an agency user, I want the scan to complete in under 60 seconds for a cached site, so I can run audits live on sales calls


3.4 AI Citation Engine

U-13 As an agency user, I want to see which AI queries mention my client and which don't, so I can identify content gaps

U-14 As an agency user, I want to add custom queries specific to my client's industry, so the citation data is relevant

U-15 As an agency user, I want to compare my client's citation rate against competitors, so I can quantify the gap

U-16 As an agency user, I want to see the actual AI response text, so I can show the client exactly what AI says about them and competitors


3.5 Fix Engine

U-17 As an agency user, I want to see a prioritised list of fixes for each client, sorted by impact, so I know what to tackle first

U-18 As an agency user, I want to mark fixes as in progress or completed, so I can track implementation status

U-19 As an agency user, I want to generate ready-to-implement assets (schema JSON-LD, llms.txt templates, robots snippets), so I can hand off to developers or implement myself

U-20 As an agency user, I want to see the estimated score improvement per fix, so I can prioritise the highest-value work


3.6 Competitor Tracking

U-21 As an agency user, I want to add 3-5 competitor domains per client, so I can benchmark performance

U-22 As an agency user, I want to see a side-by-side comparison of score, citations, and strengths/weaknesses, so I can explain the competitive landscape to clients

U-23 As an agency user, I want to see why a competitor is winning, so I can create a specific action plan


3.7 Reporting

U-24 As an agency user, I want to generate branded reports with my agency logo and colours, so the output looks professional when shared with clients

U-25 As an agency user, I want to export reports as PDF, so I can attach them to emails

U-26 As an agency user, I want to generate a shareable link for each report (with expiry and revoke), so clients can view results in a browser without logging in

U-27 As an agency user, I want before/after comparisons in reports, so I can demonstrate improvement over time

U-28 As an agency user, I want to generate a report for a prospect before they become a client, so I can use the audit as a sales tool

U-29 As an agency user, I want scheduled report delivery, so reporting can run on autopilot


3.8 White-Label

U-30 As an agency owner, I want to use a custom domain for client-facing pages, so clients see my brand

U-31 As an agency owner, I want client-facing pages to use my branding, so the output feels native to my agency

U-32 As an agency owner, I want to control whether "Powered by SearchScore" appears on client-facing outputs


3.9 Notifications & Alerts

U-33 As an agency user, I want to be notified when a client's score changes significantly, so I can respond proactively

U-34 As an agency user, I want to be notified when a new AI citation check shows a change in mention status, so I can update the client

U-35 As an agency user, I want email or Slack notifications for scan completions and scheduled reports, so nothing falls through the cracks


3.10 API & Integrations

U-36 As an agency user, I want API access to pull scan data into my own dashboards or tools, so I can integrate SearchScore into my workflow

U-37 As an agency user, I want to trigger scans via API, so I can build automated pipelines

U-38 As an agency user, I want webhook notifications for scan completion events, so my systems can react automatically


3.11 Usage & Billing

U-39 As an agency owner, I want to see usage by category (scans, citations, reports, API) for the current billing period, so I understand where value is being consumed

U-40 As an agency owner, I want to see approaching-limit warnings before hitting hard caps, so I'm not surprised

U-41 As an agency owner, I want to understand what higher plans or add-ons unlock, so I can decide when to upgrade




4. Functional Requirements


4.1 Account & Authentication


IDRequirementPriority
F-01Email/password authentication with optional SSO (Google, Microsoft)Must
F-02Role-based access control: Owner, Admin, Analyst, ViewerMust
F-03Team member invitation via email with role assignmentMust
F-04Password reset and session managementMust
F-05Two-factor authenticationShould
F-06Enterprise SSO supportCould
F-07All role restrictions enforced server-side at API level (not frontend-only)Must

4.2 Workspace & Site Management


IDRequirementPriority
F-08Single workspace per agency account containing all client sitesMust
F-09Add/remove client domains subject to plan entitlements and usage limitsMust
F-10Client grouping/folders with custom namesShould
F-11Custom tags per client siteShould
F-12Client assignment to team membersShould
F-13Bulk import of client domains via CSVShould
F-14Client search and filter by score range, tag, statusMust

4.3 Scan Cache Semantics


A scan is classified as cached when all of the following conditions are met:

• The domain has been scanned within the **freshness window** (default: 24 hours)

• The scan configuration has not changed (same query set, same model coverage)

• The site's robots.txt or server behaviour has not changed since last scan


Freshness window rules:

• Default window: 24 hours for structural/technical analysis

• Citation check freshness: separate 7-day window (AI responses change less frequently)

• Freshness windows are configurable per plan in the entitlements table


Manual re-scan behaviour:

• A manual "Run scan" from the dashboard or API always triggers a fresh scan (bypasses cache)

• Scheduled scans respect the freshness window and may return cached results

• "Re-scan after fix" always triggers a fresh scan


Usage metering for cached scans:

• Cached scans consume 0 billable scan credits

• Cached citation checks consume 0 billable citation credits

• Fresh scans consume 1 billable scan credit

• The `fresh_scan` boolean on the scans table determines billing


Cache invalidation triggers:

• Manual re-scan request

• Freshness window expiry

• Site content change detected (via HTTP ETag/Last-Modified)

• Plan entitlement change (different model coverage)


4.4 Usage Metering & Entitlements


IDRequirementPriority
F-15Track billable events: fresh scans, citation queries, report generations, API requestsMust
F-16Track operational telemetry separately: model calls by model, cache hits, queue wait times, report views, webhook retriesMust
F-17Enforce plan entitlements and usage caps at API levelMust
F-18Expose current usage and remaining allowance in billing/settings UIMust
F-19Entitlement system configurable by plan (not hardcoded in business logic)Must
F-20Distinguish fresh scans vs cached scans in metering (only fresh scans are billable)Must
F-21Support for soft-limit warnings and hard-limit enforcementShould
F-22Support overage usage accounting for future billing integrationShould
F-23Billable events and operational telemetry must be stored in separate tables or clearly separated by a billable booleanMust
F-24Re-check org entitlements and quota at async job execution time (not just at queue time)Must

Entitlements to configure per plan:

• max_sites, max_scans_per_month, max_custom_queries_per_site, max_competitors_per_site

• max_team_members, report_generation_quota, api_enabled, webhook_enabled

• white_label_level (none / basic / advanced / full), custom_domain_enabled

• scheduling_frequency_allowed, citation_query_count, model_coverage


4.5 Scanning Engine


IDRequirementPriority
F-26On-demand scan for any client domainMust
F-27Scan completes in <60s for previously cached domainsMust
F-28Scan completes in <120s for new domainsMust
F-29Scheduled recurring scans (daily, weekly, monthly), subject to plan entitlementMust
F-30Bulk scan trigger (scan all / scan filtered group)Should
F-31Scan queue management (pause, cancel, prioritise)Could
F-32Scan history with full data retention (12 months minimum)Must
F-33Scan queue with job architecture: retries, dead-letter handling, per-org rate limitingMust
F-34Plan-based concurrency limits (one large agency must not starve others)Must
F-35Idempotent job executionMust

4.6 Scoring


IDRequirementPriority
F-36Overall AI Visibility Score 0-100 with tier labelsMust
F-37Sub-scores: Structure, Clarity, Authority, AccessibilityMust
F-38Score trend over time (line chart with selectable date range)Must
F-39Score comparison against industry averageShould
F-40Estimated improvement potential based on unresolved fixesMust

Tier Labels: Keep 5 tiers. Adopt naming: Invisible / Low Visibility / Emerging / Competitive / Dominant. Preserves existing data; "Dominant" aligns with aspirational agency positioning.


4.7 AI Citation Engine


IDRequirementPriority
F-41Predefined query set (10-20) per site, auto-generated from site content and industryMust
F-42Custom query addition per client site, subject to plan allowanceMust
F-43Citation check across supported models (MVP minimum 2, target 3)Must
F-44Multi-model citation checks configurable by plan or feature flagMust
F-45Per-query result: mention status, position, competitors mentioned, AI response snapshotMust
F-46Aggressive caching and reusable result windows where validMust
F-47Summary: "Mentioned in X of Y queries" with trendMust
F-48Competitor citation comparisonMust
F-49Insight generation: "Missing from queries related to [topic cluster]"Should
F-50Citation history over timeShould
F-51Optional deferred execution for less critical checksCould

4.8 Fix Engine


IDRequirementPriority
F-52Prioritised fix list sorted by impact (High/Medium/Low)Must
F-53Each fix includes: title, impact, effort, plain-English explanation, exact stepsMust
F-54Fix categories: Technical, Content, Entity/AuthorityMust
F-55Fix status tracking: Not Started / In Progress / Completed, with owner fieldMust
F-56Generated assets: schema JSON-LD, llms.txt template, robots.txt snippetsMust
F-57Estimated score gain per fix (clearly labelled as estimate, not guaranteed)Must
F-58"Re-scan after fix" button to validate improvementMust
F-59Fix history/change log per siteMust
F-60Data model must not block future: comments, client approval state, team handoffShould

4.9 Competitor Module


IDRequirementPriority
F-61Add up to 5 competitor domains per client site, subject to planMust
F-62Side-by-side score comparisonMust
F-63Citation rate comparisonMust
F-64Signal gap analysis: "Competitor has X, you don't"Must
F-65Competitive insight: "Why they're being recommended instead of you"Must
F-66Competitor score history over timeShould

4.10 Reporting


Reports are immutable point-in-time snapshots. Once generated, a report must not silently update based on newer scans or changed data. The data embedded in a report is the data as it existed at generation time.


This is critical for:

• Client trust (what they saw yesterday is what they see today)

• Sales workflows (prospect audit remains valid for the sales cycle)

• Before/after proof (baseline cannot retroactively change)

• Auditability (regulatory and internal review)


Implementation: reports store snapshot copies of all referenced data (scores, issues, citation results) rather than foreign keys to live data. PDFs are generated once and stored.


IDRequirementPriority
F-67Executive summary report (score + top issues + recommendation)Must
F-68Full diagnostic report (all sub-scores + all fixes + citation data)Must
F-69Competitor comparison reportShould
F-70Before/after progress reportMust
F-71PDF exportMust
F-72Shareable link with configurable expiry and revoke supportMust
F-73Share links must never expose internal operational metadataMust
F-74Branded reports (agency logo, colours, custom footer)Must
F-75Multiple report templates for different use casesShould
F-76Scheduled report generation and email deliveryShould
F-77Lead-gen audit report (for prospects, before they become clients)Must
F-78Prospect-safe report mode (no internal data leakage)Must
F-79Reports are immutable point-in-time snapshots (no silent updates from newer data)Must

4.11 White-Label (Tiered, Client-Facing Only)


White-label applies to client-facing surfaces only: reports, share pages, optional custom domains. Internal agency workspace UI remains SearchScore-branded unless explicitly enabled for enterprise plans.


White-label is NOT an all-or-nothing toggle. Three independent levels, enabled by plan and feature flag:


Level 1: Basic Branding

IDRequirementPriorityPlan
F-79Agency logo on reports and share pagesMustAgency
F-80Primary/secondary colour customisationMustAgency
F-81"Powered by SearchScore" footer toggleShouldAgency

Level 2: Advanced Branding

IDRequirementPriorityPlan
F-82Custom domain (CNAME) for client-facing pagesShouldAgency Plus
F-83Branded report pages with full visual controlShouldAgency Plus
F-84Removal of SearchScore attribution on external surfacesShouldAgency Plus

Level 3: Full White-Label

IDRequirementPriorityPlan
F-85Custom email sender for scheduled reportsCouldAgency Plus
F-86No SearchScore branding on client-facing surfaces other than optional legal/footer attribution controlsCouldAgency Plus

4.12 Notifications & Alerts


IDRequirementPriority
F-87Email notification on scan completion (default on, digestible)Must
F-88Alert on score change above configurable threshold (default on)Should
F-89Alert on citation status change (default off)Should
F-90Per-channel notification preferencesShould
F-91In-app notification centreShould
F-92Slack integration (lightweight, not core MVP unless trivial)Could

Principle: Do not build a spam machine. Default notifications must be limited and meaningful. Do not overinvest here before core usage is proven.


4.13 API (Premium Platform Layer)


API access must be entitlement-driven and support separate monetisation from dashboard seats.


IDRequirementPriority
F-93REST API with API key authenticationMust
F-94Separate API permissions from dashboard accessMust
F-95Separate API usage tracking and rate limitsMust
F-96Endpoints: list sites, trigger scan, get scan results, get fixes, get citationsMust
F-97Webhook registration for scan completion eventsShould
F-98API rate limiting enforced per organisation and per key (plan-based)Must
F-99API documentation (OpenAPI/Swagger)Must
F-100Architectural support for: bundled API for higher plans, standalone paid add-on laterMust

4.14 Webhook Delivery Requirements


IDRequirementPriority
F-101Signed webhook payloads using per-org HMAC-SHA256 secretMust
F-102Exponential backoff retry policy: 1s, 5s, 30s, 5m, 30m (5 attempts max)Must
F-103Dead-letter behaviour: after max retries, mark as permanently failed, alert org adminMust
F-104Unique event ID (UUID) in every payload for consumer idempotencyMust
F-105Supported event types: scan.completed, scan.failed, citation.changed, score.threshold_reached, report.generatedMust
F-106Webhook delivery status visible in org settings (last delivery, success rate, failures)Should
F-107Per-webhook secret rotation without downtimeShould

4.15 Downgrade / Over-Entitlement Behaviour


When an account downgrades below its current usage or feature footprint:


ScenarioBehaviour
Excess sites (above new plan limit)All existing sites remain readable; no new sites can be added until under limit
Excess scans/quotaCurrent period usage stands; no new billable actions until period resets or plan upgraded
Premium automation (scheduled scans, bulk)Paused if plan no longer entitled; admin prompted to resolve
API keys above planDisabled (not deleted); admin prompted to reduce or upgrade
White-label featuresRevert gracefully for new outputs only; existing reports/PDFs are NOT broken retroactively
Historical reports and PDFsNever broken or retroactively modified by plan change
Admin notificationOrg admin receives clear summary of overages and actions required

Principle: Downgrade is graceful, not destructive. Existing data and outputs are always preserved. Only new actions are restricted.




5. Non-Functional Requirements


5.1 Performance

IDRequirement
NFR-01Dashboard loads in <2 seconds after scan
NFR-02First scan completes in <120 seconds
NFR-03Cached scan returns in <60 seconds
NFR-04PDF report generation in <10 seconds
NFR-05API response time <500ms for non-scan data endpoints

5.2 Scalability

IDRequirement
NFR-06Support 500+ client sites per agency account
NFR-07Support 50+ concurrent scan requests across the platform with per-org controls
NFR-08Score history retained for 24 months
NFR-09Citation snapshots retained for 12 months

5.3 Security

IDRequirement
NFR-10All data encrypted at rest (AES-256) and in transit (TLS 1.3)
NFR-11API keys hashed, never stored in plaintext
NFR-12Session tokens expire after 24 hours or per security policy
NFR-13Role-based access enforced at API level for every endpoint
NFR-14Audit log for administrative and sensitive actions
NFR-15Strong tenancy enforcement - org A cannot access org B's data

5.4 Availability

IDRequirement
NFR-1699.5% uptime target for dashboard
NFR-17Scan queue resilient to individual failures (retry logic, dead-letter handling)
NFR-18Graceful degradation: dashboard shows last cached data if scan service unavailable

5.5 Platform Architecture

IDRequirement
NFR-19Clear service boundaries between SaaS layer and scan engine
NFR-20Idempotent job handling for all async operations
NFR-21Entitlement checks at API level for every request
NFR-22Usage instrumentation on every billable event



6. Data Model


6.1 Entity Relationship Overview


Organisation (1) ──< (M) User
Organisation (1) ──< (M) ClientSite
Organisation (1) ──< (M) ApiKey
Organisation (1) ──< (M) WebhookDelivery
Organisation (1) ──< (1) BrandingConfig
Organisation (1) ──< (M) UsageEvent
Organisation (1) ──< (M) AuditLog
ClientSite (1) ──< (M) Scan
ClientSite (1) ──< (M) Competitor
ClientSite (1) ──< (M) CustomQuery
ClientSite (1) ──< (M) Report
Scan (1) ──< (M) CitationResult
Scan (1) ──< (M) FixItem

6.2 Core Tables


organisations

ColumnTypeNotes
idUUIDPrimary key
nameVARCHAR(255)Agency name
planENUMpro, agency, agency_plus
billing_emailVARCHAR(255)
stripe_customer_idVARCHAR(255)
created_atTIMESTAMP
settings_jsonJSONBFeature flags, overrides

users

ColumnTypeNotes
idUUIDPrimary key
org_idUUIDFK -> organisations
emailVARCHAR(255)Unique
password_hashVARCHAR(255)bcrypt
roleENUMowner, admin, analyst, viewer
nameVARCHAR(255)
avatar_urlTEXT
last_loginTIMESTAMP
created_atTIMESTAMP

client_sites

ColumnTypeNotes
idUUIDPrimary key
org_idUUIDFK -> organisations
domainVARCHAR(255)Normalised domain
nameVARCHAR(255)Client display name
industryVARCHAR(100)
assigned_user_idUUIDFK -> users (nullable)
tagsTEXT[]PostgreSQL array
folderVARCHAR(255)Grouping
scan_scheduleJSONB{"frequency": "weekly", "day": "monday"}
created_atTIMESTAMP

competitors (separate table for clean normalisation)

ColumnTypeNotes
idUUIDPrimary key
site_idUUIDFK -> client_sites
domainVARCHAR(255)
labelVARCHAR(255)Display name
created_atTIMESTAMP

custom_queries (separate table for clean normalisation)

ColumnTypeNotes
idUUIDPrimary key
site_idUUIDFK -> client_sites
queryTEXT
created_byUUIDFK -> users (nullable)
created_atTIMESTAMP

scans

ColumnTypeNotes
idUUIDPrimary key
site_idUUIDFK -> client_sites
triggered_byENUMmanual, scheduled, api, bulk
triggered_by_user_idUUIDFK -> users (nullable)
statusENUMqueued, running, completed, failed
overall_scoreINTEGER0-100
tierVARCHAR(50)
structure_scoreINTEGER0-100
clarity_scoreINTEGER
authority_scoreINTEGER
accessibility_scoreINTEGER
category_scoresJSONBFull breakdown
issues_jsonJSONBAll detected issues
improvement_potentialINTEGEREstimated max score gain
fresh_scanBOOLEANTrue if new crawl, false if cached
duration_msINTEGER
started_atTIMESTAMP
completed_atTIMESTAMP
created_atTIMESTAMP

citation_results

ColumnTypeNotes
idUUIDPrimary key
scan_idUUIDFK -> scans
queryTEXTThe AI prompt tested
modelVARCHAR(50)chatgpt, perplexity, gemini
mentionedBOOLEAN
positionINTEGER1st, 2nd, etc. (null if not mentioned)
competitors_mentionedTEXT[]
response_snapshotTEXTAI response text
cachedBOOLEANTrue if reused from prior check
created_atTIMESTAMP

fix_items

ColumnTypeNotes
idUUIDPrimary key
site_idUUIDFK -> client_sites
scan_idUUIDFK -> scans (source scan)
titleVARCHAR(255)
categoryENUMtechnical, content, entity
impactENUMhigh, medium, low
effortENUMlow, medium, high
explanationTEXTWhy it matters (plain English)
stepsJSONBArray of step objects
generated_assetTEXTCode/template to copy
estimated_gainINTEGEREstimated score points (labelled as estimate)
statusENUMnot_started, in_progress, completed
owner_user_idUUIDFK -> users (nullable)
completed_atTIMESTAMP
change_historyJSONBArray of status change events
created_atTIMESTAMP

reports

ColumnTypeNotes
idUUIDPrimary key
site_idUUIDFK -> client_sites
typeENUMexecutive, diagnostic, competitor, progress, lead_gen
from_scan_idUUIDFK -> scans
to_scan_idUUIDFK -> scans (for progress reports, nullable)
share_tokenVARCHAR(255)For shareable links
share_expires_atTIMESTAMPConfigurable expiry
share_revokedBOOLEANSupport for revocation
pdf_urlTEXTCDN URL
brandedBOOLEAN
template_idVARCHAR(50)Report template identifier
created_atTIMESTAMP

branding_configs

ColumnTypeNotes
idUUIDPrimary key
org_idUUIDFK -> organisations (1:1)
levelENUMnone, basic, advanced, full
logo_urlTEXT
primary_colourVARCHAR(7)Hex
secondary_colourVARCHAR(7)Hex
font_familyVARCHAR(100)
custom_domainVARCHAR(255)CNAME
domain_verifiedBOOLEAN
show_powered_byBOOLEANDefault true
email_senderVARCHAR(255)Custom sender (full white-label only)
created_atTIMESTAMP

api_keys

ColumnTypeNotes
idUUIDPrimary key
org_idUUIDFK -> organisations
key_hashVARCHAR(255)SHA-256 of API key
key_prefixVARCHAR(8)First 8 chars for identification
nameVARCHAR(100)User-given name
permissionsTEXT[]Scopes (separate from dashboard access)
scopesTEXT[]API-specific scopes
last_used_atTIMESTAMP
created_atTIMESTAMP

usage_events

ColumnTypeNotes
idUUIDPrimary key
org_idUUIDFK -> organisations
user_idUUIDFK -> users (nullable)
typeVARCHAR(100)scan_fresh, scan_cached, citation_query, report_gen, api_request, webhook_delivery, share_view
billableBOOLEANTrue for quota-consuming events; false for operational telemetry
quantityINTEGERUsually 1
metadata_jsonJSONB{"fresh": true, "model": "chatgpt", "site_id": "...", "cache_hit": false}
billing_periodVARCHAR(20)"2026-04" format
created_atTIMESTAMP

Billable events (consume plan quota): scan_fresh, citation_query, report_gen, api_request


Operational telemetry (do NOT consume quota): scan_cached, webhook_delivery, share_view, model_call, cache_hit, queue_wait_time


entitlements (plan limits as data, not code)

ColumnTypeNotes
planVARCHAR(50)Primary key
max_sitesINTEGER
max_scans_per_monthINTEGERFresh scans only; cached scans are free
max_citation_queries_per_siteINTEGER
max_custom_queries_per_siteINTEGER
max_competitors_per_siteINTEGER
max_team_membersINTEGER
report_quota_per_monthINTEGER
api_enabledBOOLEAN
api_rate_limit_per_hourINTEGER
webhook_enabledBOOLEAN
webhook_max_retriesINTEGERDefault 5
white_label_levelENUMnone, basic, advanced, full
custom_domain_enabledBOOLEAN
scheduling_frequenciesTEXT[]["weekly"], ["daily"], etc.
citation_modelsTEXT[]["chatgpt", "perplexity"], etc.
scan_cache_freshness_hoursINTEGERDefault 24
citation_cache_freshness_hoursINTEGERDefault 168 (7 days)

audit_logs

ColumnTypeNotes
idUUIDPrimary key
org_idUUIDFK -> organisations
actor_user_idUUIDFK -> users (nullable)
actionVARCHAR(255)
target_typeVARCHAR(100)
target_idUUIDNullable
metadata_jsonJSONB
created_atTIMESTAMP

webhook_deliveries

ColumnTypeNotes
idUUIDPrimary key
org_idUUIDFK -> organisations
webhook_idUUIDFK -> webhooks
event_idUUIDUnique event ID for consumer idempotency
event_typeVARCHAR(100)scan.completed, scan.failed, citation.changed, score.threshold_reached, report.generated
payload_hashVARCHAR(255)
signatureVARCHAR(255)HMAC-SHA256 using per-org webhook secret
statusVARCHAR(50)pending, delivered, failed, dead_letter
attemptsINTEGERMax 5 before dead_letter
last_attempt_atTIMESTAMP
response_codeINTEGERNullable
created_atTIMESTAMP



7. Commercial Control Rules


These rules are non-negotiable and apply across all implementation layers:


1. No feature with variable infrastructure cost may be implemented without entitlement hooks. Every feature that costs money to run (scans, citations, AI model calls, PDF generation, webhook delivery) must check entitlements before execution.


2. All premium capabilities must support plan-based enablement and later add-on monetisation. API access, white-label, custom domain, and advanced citation models must be architecturally prepared for standalone add-on pricing from day one, even if initially bundled.


3. Async jobs must re-check entitlement at execution time. Scheduled scans, bulk scans, report generation, and citation jobs must verify the org's current plan and quota when the job runs, not just when it was queued. This protects against downgrades, expired billing states, and queued over-usage.


4. Reports are immutable point-in-time snapshots. Generated reports store snapshot copies of all referenced data. They must not silently update based on newer scans or changed data.


5. Excess usage must be meterable even if billing is not yet enabled. Every billable event must be tracked and attributable to an org and billing period, even if Stripe metered billing is not yet connected. This ensures the accounting infrastructure is ready when billing is activated.


6. Downgrade behaviour must be graceful and deterministic. Existing data and outputs are never destroyed by plan changes. Only new actions are restricted. Admin is always notified of overages with clear resolution steps.


Protected commercial surfaces (require explicit entitlement, must not be casually bundled or left unmetered):

• Citation-heavy usage (multi-model, high query counts)

• API access (separate from dashboard)

• White-label / custom domain

• PDF report generation

• Webhook delivery




8. Data Ownership Boundaries


Explicit split between systems. No dual ownership.


SaaS Database (PostgreSQL) owns:

• Organisations, users, permissions, RBAC

• Client sites, tags, folders, assignments

• Competitors, custom queries

• Branding configs, API keys, webhooks

• Reports, share tokens

• Fix status, fix history, fix owners

• Usage events, entitlements, billing state

• Audit logs, notification settings

• Webhook delivery records


Scan System (existing sites.db) owns:

• Raw scan execution, timing, duration

• Raw analysis output (scores, issues, category data)

• Citation run results and AI response snapshots

• Scan artifacts (cached pages, extracted text)

• Scan queue state


Interface: Scan outputs are normalised and persisted into the SaaS layer via a defined write boundary. Scan system produces results; SaaS system consumes and stores them. No shared mutable state.




9. API Structure


9.1 Authentication

POST   /api/auth/login
POST   /api/auth/register
POST   /api/auth/refresh
POST   /api/auth/forgot-password
POST   /api/auth/reset-password

9.2 Organisation & Users

GET    /api/org
PATCH  /api/org
GET    /api/org/users
POST   /api/org/users/invite
PATCH  /api/org/users/:id
DELETE /api/org/users/:id

9.3 Usage & Billing

GET    /api/org/usage                     # Current period usage summary
GET    /api/org/usage/summary             # Aggregated usage stats
GET    /api/org/usage/by-category         # Breakdown by type
GET    /api/org/usage/history             # Historical usage by period
GET    /api/org/entitlements              # Current plan limits

9.4 Client Sites

GET    /api/sites                         # List all client sites (paginated, filterable)
POST   /api/sites                         # Add client site (entitlement check)
GET    /api/sites/:id                     # Get site details
PATCH  /api/sites/:id                     # Update site
DELETE /api/sites/:id                     # Remove site
POST   /api/sites/import                  # Bulk CSV import
GET    /api/sites/:id/summary             # Quick summary (latest scan, score, tier)

9.5 Scans

POST   /api/sites/:id/scans               # Trigger scan (usage metered)
POST   /api/scans/bulk                    # Trigger bulk scan
GET    /api/sites/:id/scans               # Scan history
GET    /api/scans/:id                     # Full scan results
GET    /api/scans/:id/compare             # Compare two scans

9.6 Citations

GET    /api/sites/:id/citations           # Latest citation results
POST   /api/sites/:id/queries             # Add custom query (metered)
DELETE /api/sites/:id/queries/:qid        # Remove custom query
GET    /api/citations/:id/response        # Full AI response snapshot

9.7 Fixes

GET    /api/sites/:id/fixes               # List fixes (filterable by status, category)
PATCH  /api/fixes/:id                     # Update fix status/owner
GET    /api/fixes/:id/asset               # Get generated asset (schema, llms.txt etc)
POST   /api/fixes/:id/rescan              # Re-scan after fix

9.8 Competitors

GET    /api/sites/:id/competitors         # List competitors
POST   /api/sites/:id/competitors         # Add competitor (entitlement check)
DELETE /api/sites/:id/competitors/:cid
GET    /api/sites/:id/comparison          # Side-by-side comparison data

9.9 Reports

POST   /api/sites/:id/reports             # Generate report (usage metered)
GET    /api/sites/:id/reports             # List reports
GET    /api/reports/:id                   # View report
GET    /api/reports/:id/pdf               # Download PDF
POST   /api/reports/:id/share             # Create share link (with expiry)
DELETE /api/reports/:id/share             # Revoke share link
GET    /api/shared/:token                 # Public share page (no auth)

9.10 Branding

GET    /api/org/branding                  # Get branding config
PATCH  /api/org/branding                  # Update branding (level-gated)
POST   /api/org/branding/verify-domain    # Verify custom domain

9.11 API Keys

GET    /api/org/api-keys                  # List API keys
POST   /api/org/api-keys                  # Create key
DELETE /api/org/api-keys/:id              # Revoke key

9.12 Webhooks

GET    /api/org/webhooks                  # List webhooks
POST   /api/org/webhooks                  # Register webhook
DELETE /api/org/webhooks/:id              # Remove webhook

9.13 Notifications

GET    /api/notifications                 # List notifications
PATCH  /api/notifications/:id             # Mark read
GET    /api/org/notification-settings     # Get notification preferences
PATCH  /api/org/notification-settings     # Update preferences



10. UI Screen Specification


10.1 Navigation (Agency Mode)


Left sidebar:

Overview - Agency-wide dashboard

Clients - Client site list and management

[Client Name] - Expanded client submenu (when a client is selected):

- Dashboard

- Visibility Score

- AI Mentions

- Fixes

- Competitors

- Reports

Settings - Account, team, branding, API, billing


10.2 Agency Overview Dashboard


Purpose: Single view of all client health. Must answer: What's happening? Why? What do I do next?


Layout:

• Row 1: Agency summary stats

- Total clients, Average score across all clients

- Clients needing attention (score dropped >5 pts or below Emerging)

- Scans run this month / allowance remaining (with approaching-limit visual)

• Row 2: Client score table (sortable, filterable)

- Columns: Client name, Domain, Score, Tier, Trend (delta), Last scan, Status tags

- Click row -> navigate to client dashboard

- Inline "Run scan" button per row

• Row 3: High-priority alerts

- Score drops >5 points, New issues detected, Citation status changes

• Row 4: Usage summary

- Scans used/remaining, Citation usage, Reports generated, API calls


10.3 Client Dashboard (per-site)

• Hero score card

• Recommendation status card

• Opportunity card

• Top 3 fixes

• Competitor snapshot

• Recent scan changes

• AI mentions snapshot


10.4 Client Visibility Score Screen

• Overall score with trend

• 4 sub-score cards: Structure, Clarity, Authority, Accessibility

• Accordion detail per category: score, what's wrong, why it matters, related fixes


10.5 Client AI Mentions Screen

• Summary bar: mentioned in X/Y queries, best/worst topic clusters

• Table: Query, Model, Mention status (chip), Competitors, View response button

• Right-side drawer for AI response snapshot with highlighted mentions

• Insight panel: topic gaps, competitor dominance patterns


10.6 Client Fixes Screen

• Top summary: total issues, high-impact count, estimated score gain (labelled as estimate)

• Two-pane layout:

- Left: prioritised fix queue with status badges and owner

- Right: fix detail panel (title, why it matters, what to do, generated asset, action buttons)


10.7 Client Competitors Screen

• Score comparison table (you vs competitors)

• Citation rate comparison

• Insight panel: "Competitor A is winning because..."

• CTA: "View detailed comparison report"


10.8 Client Reports Screen

• Generate report button (select type + date range)

• Report list with type, date, status

• Actions: View, Export PDF, Share link (with expiry control), Delete


10.9 Client Management (List)

• Search bar

• Filters: tag, score range, folder, assigned user

• Bulk actions: scan selected, add tag, assign to user

• Each row: name, domain, score chip, tags, last scan, actions


10.10 Settings

• Account settings (org name, billing email)

• Team management (invite, roles, remove)

• Branding (logo upload, colour picker, custom domain - level-gated)

• API keys (create, view prefix, revoke)

• Webhooks (register URL, select events)

• Notification preferences

• Billing (plan, usage, Stripe portal link)

• Usage dashboard (scans, citations, reports, API by category)


10.11 Monetisation Visibility

The product should tastefully show economic value:

• Usage remaining indicators

• What higher plans unlock (inline, not pushy)

• When bulk scanning or API would be valuable

• Report branding locked behind plan

• Custom domain as premium feature

• This is not dark-pattern upselling - it's helping agencies understand upgrade value




11. Pricing Model (Backend Support)


11.1 Three-Layer Pricing Structure


The backend must support this structure, even if initial launch uses flat tiers:


Layer 1: Core Subscription

• Workspace, team, included sites, included scans, included reporting


Layer 2: Usage Layer

• Overage scans, citation expansions, high-volume API usage

• Metered and visible


Layer 3: Premium Add-ons

• API / MCP access

• Advanced white-label

• Custom domain


11.2 Reference Tiers


FeaturePro (£49/mo)Agency (£149/mo)Agency Plus (£299/mo)
Sites325100 included
Scans/month505002,000 included
Competitors/site255
Team members1525
Reports/month10100500 included
Branded reportsNoYesYes
White-label domainNoNoYes
API accessNoOptional add-onYes or add-on
WebhooksNoOptional add-onYes or add-on
Scheduled scansWeeklyDailyDaily
Citation queries/site102050
Custom queries/site520100 included
PDF exportYesYesYes
Share links/month10100500 included
Priority supportNoYesYes

Note: Public pricing can use "fair use" language if desired, but internal entitlement architecture must not depend on true unlimited usage. Every "included" tier has an internal hard cap with overage accounting.




12. Implementation Layers


Implementation is split into four product layers. Each layer is a coherent deliverable. Do not start a layer until the previous one is validated.


Layer A: Agency Workspace Core (Weeks 1-3)

The foundation. Multi-tenant data model, auth, client management.


• Multi-tenant SaaS database (PostgreSQL)

• Organisations, users, RBAC (server-side enforced)

• Client site CRUD (add, edit, remove, list, group)

• Entitlement system with plan-defined limits

• Usage metering foundation on every billable event

• Agency overview dashboard (all-clients view)

• Team member invitation with role assignment

• Basic scan scheduling

• JWT authentication, session management


Layer B: Core Product Experience (Weeks 4-6)

The value engine. Scores, fixes, citations, competitors.


• Client dashboard (per-site overview)

• AI Visibility Score breakdown

• AI Citation Engine (predefined queries, 2-model MVP, response snapshots)

• Fix Engine (prioritised list, status tracking, owner, generated assets, change history)

• Competitor module (add competitors, side-by-side comparison, gap analysis)


Layer C: Agency Tooling (Weeks 7-9)

The commercial output. Reports, branding, notifications, bulk operations.


• Report generation (executive, diagnostic, progress, lead-gen)

• PDF export

• Share links with expiry and revoke

• Branded reports (Level 1 white-label)

• Lead-gen prospect audit reports

• Bulk scan triggers

• Notification system (email alerts for score changes, scan completions)

• Usage dashboard in settings

• Monetisation visibility (approaching limits, plan upgrade hints)


Layer D: Platform Layer (Weeks 10-12)

The extensibility. API, webhooks, advanced white-label. Only after demand is proven.


• Custom domain support (CNAME verification)

• Advanced white-label (Level 2-3)

• REST API with key authentication (separate permissions, separate metering)

• API documentation (Swagger/OpenAPI)

• Webhook registration and delivery

• Scheduled report email delivery

• 3-model citation expansion

• Custom query metering as premium resource

• Slack notification integration

• Overage billing support




13. Technical Architecture


13.1 Current Stack (What Exists)

Backend: Node.js / Express on port 3470

Database: SQLite (`sites.db`) via better-sqlite3

Frontend: Static HTML served via Cloudflare Pages (`searchscore/landing/`)

Auth: None (public audit tool with admin panel behind password)

Payments: Stripe (price IDs configured, webhook live)


13.2 Required Architecture Changes


This is a platform rewrite, not a feature extension. Architectural decisions must reflect that.


Authentication Layer:

• JWT-based auth with refresh tokens

• Server-side RBAC enforcement on every endpoint

• Audit logging for admin actions


Database:

• PostgreSQL for SaaS data (users, orgs, clients, reports, fixes, usage, entitlements)

• Keep existing `sites.db` for raw scan data with explicit ownership boundary

• Turso/libSQL acceptable only if concurrency and migration strategy are explicit

• No dual ownership of scan results


Frontend:

• React/Next.js SPA for authenticated agency app

• Public landing page stays on Cloudflare Pages

• Agency app on `app.searchscore.io`


Job Queue:

• Redis/BullMQ with: retries, dead-letter handling, per-org concurrency limits

• Plan-based queue priority

• Idempotent job execution

• Cancellation support


Report Generation:

• Server-side PDF via Playwright

• Template engine for branded reports

• CDN-backed storage (R2)


Billing/Usage Layer:

• Entitlement service (reads from entitlements table, not hardcoded)

• Usage tracking on every billable event

• Quota enforcement at API level

• Plan-aware access checks


13.3 Infrastructure


Cloudflare CDN
  +-- searchscore.io (landing page, static)
  +-- app.searchscore.io (agency SPA)
        |
API Gateway (Express)
  +-- /api/auth/*   (authentication, RBAC enforcement)
  +-- /api/sites/*  (client management, entitlement checks)
  +-- /api/scans/*  (scan orchestration, usage metering)
  +-- /api/reports/* (report generation, usage metering)
  +-- /api/v1/*     (public API, separate auth, separate metering)
        |
   +----------+----------+
   |                     |
SaaS DB (PostgreSQL)  Scan Engine (existing)
Users, Orgs,          sites.db
Clients, Reports,     Raw scan execution
Fixes, Usage,         Citation runs
Entitlements          Scan artifacts
BrandConfig           Queue state
   |                     |
   +----------+----------+
              |
Job Queue (Redis/BullMQ)
  +-- Scan jobs (on-demand, scheduled, bulk)
  +-- Report generation jobs
  +-- Citation check jobs
  +-- Webhook delivery jobs
  +-- Per-org rate limiting & concurrency



14. Risks & Open Questions


14.1 Open Questions

1. Final tier naming model - Adopt Competitive/Dominant or keep Strong/AI-Ready?

2. Database strategy: PostgreSQL now (recommended), or Turso/libSQL for faster initial delivery?

3. Existing users: How do current Stripe subscribers (Full Report, Monitor) map to new plan structure?

4. Scan cost per model: Citation checks across 3 AI models x 20 queries = 60 API calls per scan. Cost model?

5. Custom domain support burden: DNS verification via CNAME requires agency IT cooperation. Start in Layer D only.

6. White-label leak prevention: What audit process ensures SearchScore identity never leaks on full white-label?

7. API pricing: Should API be bundled into Agency Plus or sold as a standalone add-on?

8. White-label split: Should white-label be split into branding, branded share pages, and custom domain as separate entitlements?

9. Usage pooling: Should scheduled scans and high-volume citation checks consume pooled usage credits?

10. Overage billing: Stripe metered billing integration - implement in Layer D or defer?


14.2 Risks

RiskImpactMitigation
Scan queue overload from bulk scansHighPer-org rate limiting, plan-based concurrency, staggered queue
AI API costs at scaleHighAggressive caching, plan-based query/model limits, usage metering
SQLite concurrency in multi-user SaaSHighLayer A must migrate to PostgreSQL
API cannibalises dashboard valueMediumEntitlement-based API, separate usage metering, possible add-on pricing
Scope creep into SEO/marketingMediumStrict backlog grooming against core loop
One agency degrading others' performanceHighQueue isolation, plan-based priority
White-label identity leakageMediumAudit checklist for every external surface
White-label support burdenMediumFeature-tiered white-label, self-serve docs, premium pricing
"Unlimited" marketing vs actual costsMediumInternal controls always enforce caps; marketing is separate concern



15. Acceptance Criteria


15.1 MVP Acceptance Criteria (Layer A + B)

1. An agency owner can sign up, add 5 clients, invite 2 team members, and run scans on all clients

2. A team member with "analyst" role can view clients and run scans but cannot change billing or manage team

3. Every API endpoint enforces RBAC server-side; role leakage is not possible

4. The agency overview dashboard shows all clients sorted by score with trend indicators

5. Citation checks run against minimum 2 AI models and show mention status

6. Fix engine shows prioritised fixes with generated assets, status tracking, and owner

7. Competitor comparison shows side-by-side scores with gap analysis

8. Usage is tracked per organisation and exposed in the billing/settings area

9. Entitlements are enforced via entitlements table, not scattered business logic

10. An agency can show before/after improvement clearly enough for a client to understand it in under 2 minutes


15.2 Phase 2 Acceptance Criteria (Layer C + D)

1. A user can generate a branded PDF report for any client and share it via link with configurable expiry and revoke

2. A user can view before/after score comparison between any two scans

3. An agency can generate a prospect audit and use it in a sales workflow

4. Scheduled weekly scans run automatically and send email notification on completion

5. API allows triggering a scan and retrieving results programmatically

6. Webhooks can be registered and delivered reliably

7. White-label branding works correctly on client-facing outputs without leaking SearchScore identity

8. One large agency cannot degrade platform performance for others (queue isolation verified)

9. API usage is correctly metered and visible in billing usage

10. Share links support expiry and revoke; reports never expose internal metadata

11. Estimated score gains on fixes are clearly labelled as estimates




16. Strategic Direction: Tool First, Platform Second


This is the most important strategic instruction for the build.


SearchScore must first succeed as:

• A high-value agency tool

• A client reporting and audit engine

• A retention and sales support system


Only then expand into:

• Infrastructure

• Programmatic access

• Deeper automation


Optimise the build for:

• Strongest agency UI

• Fastest time to value

• Best reporting experience

• Strongest fix workflow


NOT for:

• Maximum platform complexity on day one

• Generic dashboard bloat

• Feature completeness over commercial clarity


Non-negotiable guardrails:

• No accidental margin traps

• No fake unlimited plans

• No underpriced white-label

• No casual API giveaway

• No generic dashboard bloat

• No loss of category focus


The final product should feel like:

"The clearest, most commercially useful way for an agency to show why a client is not being recommended by AI, fix it, and prove the result."

Not:

• a generic SEO dashboard

• a broad marketing platform

• a raw analytics console

• a cheap white-label data utility




*End of specification.*