# shadow-0602/serp-scout architecture

> Architecture diagram of the GitHub repository shadow-0602/serp-scout, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-25). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/shadow-0602/serp-scout
- Repository: https://github.com/shadow-0602/serp-scout

## Overview

Serp-Scout is a multi-tenant competitive-intelligence and local SEO action platform. A business owner uses the web app to manage a business and request research; background analysis extracts its profile, gathers local search evidence, and supports competitor and keyword opportunity analysis. Ranking changes and market shifts feed prioritized recommendations and reports, delivered in dashboards, PDFs, and email. The README documents additional audits, sharing, scheduling, and outcome tracking. Unsampled route and agent implementations are represented by their existing paths; their internal wiring is not inferred.

Main entry points: [`apps/api/src/routes/analysis.ts`](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/routes/analysis.ts) (REST routes), [`packages/db/src/schema/index.ts`](https://github.com/shadow-0602/serp-scout/blob/main/packages/db/src/schema/index.ts) (Postgres data), [`apps/api/src/services/search-run.service.ts`](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/services/search-run.service.ts) (Search runs), [`apps/api/src/jobs/queues.ts`](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/jobs/queues.ts) (Job queues)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_client["Web experience"]
  node_web["Business dashboards<br/>[page.tsx]"]
  node_sharing["Shared reports<br/>[page.tsx]"]
end

subgraph group_api["API and analysis"]
  node_routes["REST routes<br/>[analysis.ts]"]
  node_search["Search runs"]
  node_ranking["Ranking deltas<br/>[ranking.service.ts]"]
  node_market["Market alerts"]
  node_pdf["PDF rendering<br/>[pdf.service.ts]"]
  node_notify["Email notifications"]
end

subgraph group_agents["Intelligence agents"]
  node_website["Website analysis<br/>[index.ts]"]
  node_parser["Page extraction<br/>[parser.ts]"]
  node_competitors["Competitor discovery<br/>[index.ts]"]
  node_keywords["Keyword opportunities<br/>[index.ts]"]
  node_gaps["Content gaps<br/>[index.ts]"]
  node_recommendations["Action recommendations<br/>[index.ts]"]
  node_reports["Report generation<br/>[index.ts]"]
end

subgraph group_jobs["Background work"]
  node_queues["Job queues<br/>[queues.ts]"]
  node_research["Research worker<br/>[research.worker.ts]"]
  node_reportworker["Report worker<br/>[report.worker.ts]"]
  node_stale["Stale checks"]
end

subgraph group_state["State and integrations"]
  node_db[("Postgres data<br/>[index.ts]")]
  node_serp["SerpApi search<br/>[index.ts]"]
  node_tavily["Tavily search<br/>[tavily.service.ts]"]
  node_redis[("Redis queue state<br/>[queues.ts]")]
end

node_owner(("Business owner"))
node_serpservice(("Search provider"))
node_mail(("Email delivery"))

node_owner -->|"uses"| node_web
node_web -->|"API requests"| node_routes
node_sharing -->|"public access"| node_routes
node_routes -->|"starts searches"| node_search
node_search -->|"reads and writes"| node_db
node_search -->|"searches"| node_serp
node_search -.->|"searches"| node_tavily
node_serp -->|"queries"| node_serpservice
node_research -->|"analyzes sites"| node_website
node_website -->|"extracts pages"| node_parser
node_research -->|"refreshes rankings"| node_ranking
node_research -->|"reads and updates"| node_db
node_routes -->|"enqueues work"| node_queues
node_queues -->|"dispatches jobs"| node_research
node_queues -->|"dispatches jobs"| node_reportworker
node_queues -->|"dispatches jobs"| node_stale
node_queues -->|"stores queue state"| node_redis
node_search -->|"triggers analysis"| node_market
node_reportworker -->|"generates report"| node_reports
node_reportworker -->|"reads and saves"| node_db
node_reportworker -->|"renders report"| node_pdf
node_reportworker -->|"requests delivery"| node_notify
node_notify -->|"records notifications"| node_db
node_notify -->|"sends email"| node_mail
node_routes -.->|"supports discovery"| node_competitors
node_routes -.->|"supports discovery"| node_keywords
node_routes -.->|"supports analysis"| node_gaps
node_routes -.->|"supports actions"| node_recommendations
node_ranking -->|"reads observations"| node_db
node_stale -->|"checks freshness"| node_db

click node_web "https://github.com/shadow-0602/serp-scout/blob/main/apps/web/src/app/(app)/app/page.tsx"
click node_sharing "https://github.com/shadow-0602/serp-scout/blob/main/apps/web/src/app/shared/%5Btoken%5D/page.tsx"
click node_routes "https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/routes/analysis.ts"
click node_search "https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/services/search-run.service.ts"
click node_ranking "https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/services/ranking.service.ts"
click node_market "https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/services/market-shift.service.ts"
click node_website "https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/website-analyzer/index.ts"
click node_parser "https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/website-analyzer/parser.ts"
click node_competitors "https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/competitor-discovery/index.ts"
click node_keywords "https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/keyword-discovery/index.ts"
click node_gaps "https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/content-gap/index.ts"
click node_recommendations "https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/recommendation-engine/index.ts"
click node_reports "https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/report-generator/index.ts"
click node_queues "https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/jobs/queues.ts"
click node_research "https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/jobs/workers/research.worker.ts"
click node_reportworker "https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/jobs/workers/report.worker.ts"
click node_stale "https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/jobs/workers/stale-check.worker.ts"
click node_db "https://github.com/shadow-0602/serp-scout/blob/main/packages/db/src/schema/index.ts"
click node_serp "https://github.com/shadow-0602/serp-scout/blob/main/packages/serpapi/src/index.ts"
click node_tavily "https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/services/tavily.service.ts"
click node_redis "https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/jobs/queues.ts"
click node_pdf "https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/services/pdf.service.ts"
click node_notify "https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/services/notification.service.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_web,node_sharing toneBlue
class node_routes,node_search,node_ranking,node_market,node_pdf,node_notify toneAmber
class node_website,node_parser,node_competitors,node_keywords,node_gaps,node_recommendations,node_reports toneMint
class node_queues,node_research,node_reportworker,node_stale toneRose
class node_db,node_serp,node_tavily,node_redis,node_owner,node_serpservice,node_mail toneIndigo
```

## Components

### Web experience

- [Business dashboards](https://github.com/shadow-0602/serp-scout/blob/main/apps/web/src/app/(app)/app/page.tsx): `apps/web/src/app/(app)/app/page.tsx`
- [Shared reports](https://github.com/shadow-0602/serp-scout/blob/main/apps/web/src/app/shared/%5Btoken%5D/page.tsx): `apps/web/src/app/shared/[token]/page.tsx`

### API and analysis

- [REST routes](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/routes/analysis.ts): `apps/api/src/routes/analysis.ts`
- [Search runs](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/services/search-run.service.ts): `apps/api/src/services/search-run.service.ts`
- [Ranking deltas](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/services/ranking.service.ts): `apps/api/src/services/ranking.service.ts`
- [Market alerts](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/services/market-shift.service.ts): `apps/api/src/services/market-shift.service.ts`
- [PDF rendering](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/services/pdf.service.ts): `apps/api/src/services/pdf.service.ts`
- [Email notifications](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/services/notification.service.ts): `apps/api/src/services/notification.service.ts`

### Intelligence agents

- [Website analysis](https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/website-analyzer/index.ts): `packages/agents/src/website-analyzer/index.ts`
- [Page extraction](https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/website-analyzer/parser.ts): `packages/agents/src/website-analyzer/parser.ts`
- [Competitor discovery](https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/competitor-discovery/index.ts): `packages/agents/src/competitor-discovery/index.ts`
- [Keyword opportunities](https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/keyword-discovery/index.ts): `packages/agents/src/keyword-discovery/index.ts`
- [Content gaps](https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/content-gap/index.ts): `packages/agents/src/content-gap/index.ts`
- [Action recommendations](https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/recommendation-engine/index.ts): `packages/agents/src/recommendation-engine/index.ts`
- [Report generation](https://github.com/shadow-0602/serp-scout/blob/main/packages/agents/src/report-generator/index.ts): `packages/agents/src/report-generator/index.ts`

### Background work

- [Job queues](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/jobs/queues.ts): `apps/api/src/jobs/queues.ts`
- [Research worker](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/jobs/workers/research.worker.ts): `apps/api/src/jobs/workers/research.worker.ts`
- [Report worker](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/jobs/workers/report.worker.ts): `apps/api/src/jobs/workers/report.worker.ts`
- [Stale checks](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/jobs/workers/stale-check.worker.ts): `apps/api/src/jobs/workers/stale-check.worker.ts`

### State and integrations

- [Postgres data](https://github.com/shadow-0602/serp-scout/blob/main/packages/db/src/schema/index.ts): `packages/db/src/schema/index.ts`
- [SerpApi search](https://github.com/shadow-0602/serp-scout/blob/main/packages/serpapi/src/index.ts): `packages/serpapi/src/index.ts`
- [Tavily search](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/services/tavily.service.ts): `apps/api/src/services/tavily.service.ts`
- [Redis queue state](https://github.com/shadow-0602/serp-scout/blob/main/apps/api/src/jobs/queues.ts): `apps/api/src/jobs/queues.ts`

### Other components

- **Business owner**
- **Search provider**
- **Email delivery**

## Connections

- Business owner → Business dashboards: uses
- Business dashboards → REST routes: API requests
- Shared reports → REST routes: public access
- REST routes → Search runs: starts searches
- Search runs → Postgres data: reads and writes
- Search runs → SerpApi search: searches
- Search runs → Tavily search: searches
- SerpApi search → Search provider: queries
- Research worker → Website analysis: analyzes sites
- Website analysis → Page extraction: extracts pages
- Research worker → Ranking deltas: refreshes rankings
- Research worker → Postgres data: reads and updates
- REST routes → Job queues: enqueues work
- Job queues → Research worker: dispatches jobs
- Job queues → Report worker: dispatches jobs
- Job queues → Stale checks: dispatches jobs
- Job queues → Redis queue state: stores queue state
- Search runs → Market alerts: triggers analysis
- Report worker → Report generation: generates report
- Report worker → Postgres data: reads and saves
- Report worker → PDF rendering: renders report
- Report worker → Email notifications: requests delivery
- Email notifications → Postgres data: records notifications
- Email notifications → Email delivery: sends email
- REST routes → Competitor discovery: supports discovery
- REST routes → Keyword opportunities: supports discovery
- REST routes → Content gaps: supports analysis
- REST routes → Action recommendations: supports actions
- Ranking deltas → Postgres data: reads observations
- Stale checks → Postgres data: checks freshness
