# jelger1/focus-keyword-tool architecture

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

- Interactive diagram: https://gitdiagram.com/jelger1/focus-keyword-tool
- Repository: https://github.com/jelger1/focus-keyword-tool

## Overview

Keyword Focus & Intent Check is an internal SEO analysis tool: a marketer submits a page URL and focus keyword, receives an intent assessment, and—if it matches—a content-gap and optimization report. If it does not match, the tool proposes a better keyword and automatically re-analyzes. The README documents region/language selection, Search Console imports and API data, live progress, Markdown and PDF exports, and a status check. The graph follows those documented capabilities; some subsystem wiring is based on the README because its source was not sampled.

Main entry points: [`api/analyze.js`](https://github.com/jelger1/focus-keyword-tool/blob/main/api/analyze.js) (Analyze endpoint), [`api/refocus.js`](https://github.com/jelger1/focus-keyword-tool/blob/main/api/refocus.js) (Refocus endpoint), [`app.js`](https://github.com/jelger1/focus-keyword-tool/blob/main/app.js) (Browser flow), [`api/status.js`](https://github.com/jelger1/focus-keyword-tool/blob/main/api/status.js) (Status endpoint)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_user_flow["User workflow"]
  node_browser_app["Browser flow<br/>[app.js]"]
  node_report_view["Report cards<br/>[report.js]"]
  node_pdf_export["PDF export<br/>[pdf.js]"]
end

subgraph group_api_flow["Analysis and refocus"]
  node_analyze_api["Analyze endpoint<br/>[analyze.js]"]
  node_refocus_api["Refocus endpoint<br/>[refocus.js]"]
  node_status_api["Status endpoint<br/>[status.js]"]
end

subgraph group_analysis["SEO analysis"]
  node_page_reader["Page extraction<br/>[page.js]"]
  node_serp_router["SERP provider<br/>[serp.js]"]
  node_intent_check["Intent assessment<br/>[intent.js]"]
  node_competitor_compare["Competitor comparison<br/>[compare.js]"]
  node_gap_analysis["Content gap<br/>[gap.js]"]
  node_refocus_logic["Refocus logic<br/>[refocus.js]"]
  node_keyword_sources["Keyword candidates<br/>[keywordsources.js]"]
  node_fact_checks["Claim checks<br/>[facts.js]"]
  node_progress_stream["Progress stream<br/>[progress.js]"]
end

subgraph group_sources["Data sources"]
  node_ahrefs_client["Ahrefs data<br/>[ahrefs.js]"]
  node_searchconsole_client["Search Console API<br/>[searchconsole.js]"]
  node_searchconsole_import["Search Console export<br/>[gsc.js]"]
  node_hybrid_sources["Source merging<br/>[hybrid.js]"]
  node_claude_client["Claude client<br/>[claude.js]"]
end

subgraph group_reporting["Report and controls"]
  node_auth_control["Password and rate limit<br/>[auth.js]"]
  node_rate_limit["Request throttling<br/>[ratelimit.js]"]
end

node_marketer(("Marketer"))
node_target_site(("Target website"))
node_serp_provider(("SERP services"))
node_anthropic(("Anthropic Claude"))
node_google_searchconsole(("Google Search Console"))
node_ahrefs_service(("Ahrefs"))

node_marketer -->|"submits URL and keyword"| node_browser_app
node_browser_app -->|"requests analysis"| node_analyze_api
node_browser_app -->|"requests refocus"| node_refocus_api
node_analyze_api -->|"fetches target page"| node_page_reader
node_page_reader -->|"reads HTML"| node_target_site
node_analyze_api -->|"fetches SERP"| node_serp_router
node_serp_router -->|"queries rankings"| node_serp_provider
node_serp_router -->|"uses Ahrefs provider"| node_ahrefs_client
node_analyze_api -->|"fetches keyword metrics"| node_ahrefs_client
node_ahrefs_client -->|"queries metrics and ideas"| node_ahrefs_service
node_analyze_api -->|"requests page data"| node_searchconsole_client
node_searchconsole_client -->|"queries performance"| node_google_searchconsole
node_analyze_api -->|"compares SERP pages"| node_competitor_compare
node_competitor_compare -->|"extracts competitor pages"| node_page_reader
node_analyze_api -->|"builds intent assessment"| node_intent_check
node_analyze_api -->|"requests assessment"| node_claude_client
node_claude_client -->|"sends prompts"| node_anthropic
node_analyze_api -->|"builds gap recommendations"| node_gap_analysis
node_analyze_api -->|"requests gap recommendations"| node_claude_client
node_analyze_api -->|"validates model claims"| node_fact_checks
node_analyze_api -->|"sets source flags"| node_hybrid_sources
node_browser_app -->|"uploads export"| node_searchconsole_import
node_browser_app -->|"sends export rows"| node_refocus_api
node_refocus_api -->|"re-fetches target"| node_page_reader
node_refocus_api -->|"builds candidate list"| node_keyword_sources
node_keyword_sources -->|"requests query data"| node_searchconsole_client
node_keyword_sources -->|"reads uploaded export"| node_searchconsole_import
node_keyword_sources -->|"combines source data"| node_hybrid_sources
node_refocus_api -->|"enriches and checks keywords"| node_ahrefs_client
node_refocus_api -->|"chooses better keyword"| node_claude_client
node_refocus_api -->|"validates choice"| node_refocus_logic
node_refocus_api -->|"checks proposed data"| node_fact_checks
node_browser_app -->|"re-analyzes chosen keyword"| node_analyze_api
node_analyze_api -->|"streams phase updates"| node_progress_stream
node_refocus_api -->|"streams phase updates"| node_progress_stream
node_analyze_api -->|"returns report"| node_browser_app
node_refocus_api -->|"returns keyword choices"| node_browser_app
node_browser_app -->|"renders report"| node_report_view
node_report_view -->|"prepares printing"| node_pdf_export
node_browser_app -->|"checks configuration"| node_status_api
node_status_api -->|"checks connection"| node_searchconsole_client
node_status_api -->|"checks password"| node_auth_control
node_status_api -->|"limits checks"| node_rate_limit
node_analyze_api -.->|"checks password"| node_auth_control
node_refocus_api -.->|"checks password"| node_auth_control

click node_browser_app "https://github.com/jelger1/focus-keyword-tool/blob/main/app.js"
click node_report_view "https://github.com/jelger1/focus-keyword-tool/blob/main/report.js"
click node_pdf_export "https://github.com/jelger1/focus-keyword-tool/blob/main/pdf.js"
click node_analyze_api "https://github.com/jelger1/focus-keyword-tool/blob/main/api/analyze.js"
click node_refocus_api "https://github.com/jelger1/focus-keyword-tool/blob/main/api/refocus.js"
click node_status_api "https://github.com/jelger1/focus-keyword-tool/blob/main/api/status.js"
click node_page_reader "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/page.js"
click node_serp_router "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/serp.js"
click node_intent_check "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/intent.js"
click node_competitor_compare "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/compare.js"
click node_gap_analysis "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/gap.js"
click node_refocus_logic "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/refocus.js"
click node_keyword_sources "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/keywordsources.js"
click node_fact_checks "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/facts.js"
click node_progress_stream "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/progress.js"
click node_ahrefs_client "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/ahrefs.js"
click node_searchconsole_client "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/searchconsole.js"
click node_searchconsole_import "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/gsc.js"
click node_hybrid_sources "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/hybrid.js"
click node_claude_client "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/claude.js"
click node_auth_control "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/auth.js"
click node_rate_limit "https://github.com/jelger1/focus-keyword-tool/blob/main/lib/ratelimit.js"

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_browser_app,node_report_view,node_pdf_export toneBlue
class node_analyze_api,node_refocus_api,node_status_api toneAmber
class node_page_reader,node_serp_router,node_intent_check,node_competitor_compare,node_gap_analysis,node_refocus_logic,node_keyword_sources,node_fact_checks,node_progress_stream toneMint
class node_ahrefs_client,node_searchconsole_client,node_searchconsole_import,node_hybrid_sources,node_claude_client toneRose
class node_auth_control,node_rate_limit,node_marketer,node_target_site,node_serp_provider,node_anthropic,node_google_searchconsole,node_ahrefs_service toneIndigo
```

## Components

### User workflow

- [Browser flow](https://github.com/jelger1/focus-keyword-tool/blob/main/app.js): `app.js`
- [Report cards](https://github.com/jelger1/focus-keyword-tool/blob/main/report.js): `report.js`
- [PDF export](https://github.com/jelger1/focus-keyword-tool/blob/main/pdf.js): `pdf.js`

### Analysis and refocus

- [Analyze endpoint](https://github.com/jelger1/focus-keyword-tool/blob/main/api/analyze.js): `api/analyze.js`
- [Refocus endpoint](https://github.com/jelger1/focus-keyword-tool/blob/main/api/refocus.js): `api/refocus.js`
- [Status endpoint](https://github.com/jelger1/focus-keyword-tool/blob/main/api/status.js): `api/status.js`

### SEO analysis

- [Page extraction](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/page.js): `lib/page.js`
- [SERP provider](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/serp.js): `lib/serp.js`
- [Intent assessment](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/intent.js): `lib/intent.js`
- [Competitor comparison](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/compare.js): `lib/compare.js`
- [Content gap](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/gap.js): `lib/gap.js`
- [Refocus logic](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/refocus.js): `lib/refocus.js`
- [Keyword candidates](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/keywordsources.js): `lib/keywordsources.js`
- [Claim checks](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/facts.js): `lib/facts.js`
- [Progress stream](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/progress.js): `lib/progress.js`

### Data sources

- [Ahrefs data](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/ahrefs.js): `lib/ahrefs.js`
- [Search Console API](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/searchconsole.js): `lib/searchconsole.js`
- [Search Console export](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/gsc.js): `lib/gsc.js`
- [Source merging](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/hybrid.js): `lib/hybrid.js`
- [Claude client](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/claude.js): `lib/claude.js`

### Report and controls

- [Password and rate limit](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/auth.js): `lib/auth.js`
- [Request throttling](https://github.com/jelger1/focus-keyword-tool/blob/main/lib/ratelimit.js): `lib/ratelimit.js`

### Other components

- **Marketer**
- **Target website**
- **SERP services**
- **Anthropic Claude**
- **Google Search Console**
- **Ahrefs**

## Connections

- Marketer → Browser flow: submits URL and keyword
- Browser flow → Analyze endpoint: requests analysis
- Browser flow → Refocus endpoint: requests refocus
- Analyze endpoint → Page extraction: fetches target page
- Page extraction → Target website: reads HTML
- Analyze endpoint → SERP provider: fetches SERP
- SERP provider → SERP services: queries rankings
- SERP provider → Ahrefs data: uses Ahrefs provider
- Analyze endpoint → Ahrefs data: fetches keyword metrics
- Ahrefs data → Ahrefs: queries metrics and ideas
- Analyze endpoint → Search Console API: requests page data
- Search Console API → Google Search Console: queries performance
- Analyze endpoint → Competitor comparison: compares SERP pages
- Competitor comparison → Page extraction: extracts competitor pages
- Analyze endpoint → Intent assessment: builds intent assessment
- Analyze endpoint → Claude client: requests assessment
- Claude client → Anthropic Claude: sends prompts
- Analyze endpoint → Content gap: builds gap recommendations
- Analyze endpoint → Claude client: requests gap recommendations
- Analyze endpoint → Claim checks: validates model claims
- Analyze endpoint → Source merging: sets source flags
- Browser flow → Search Console export: uploads export
- Browser flow → Refocus endpoint: sends export rows
- Refocus endpoint → Page extraction: re-fetches target
- Refocus endpoint → Keyword candidates: builds candidate list
- Keyword candidates → Search Console API: requests query data
- Keyword candidates → Search Console export: reads uploaded export
- Keyword candidates → Source merging: combines source data
- Refocus endpoint → Ahrefs data: enriches and checks keywords
- Refocus endpoint → Claude client: chooses better keyword
- Refocus endpoint → Refocus logic: validates choice
- Refocus endpoint → Claim checks: checks proposed data
- Browser flow → Analyze endpoint: re-analyzes chosen keyword
- Analyze endpoint → Progress stream: streams phase updates
- Refocus endpoint → Progress stream: streams phase updates
- Analyze endpoint → Browser flow: returns report
- Refocus endpoint → Browser flow: returns keyword choices
- Browser flow → Report cards: renders report
- Report cards → PDF export: prepares printing
- Browser flow → Status endpoint: checks configuration
- Status endpoint → Search Console API: checks connection
- Status endpoint → Password and rate limit: checks password
- Status endpoint → Request throttling: limits checks
- Analyze endpoint → Password and rate limit: checks password
- Refocus endpoint → Password and rate limit: checks password
