System Components

Last modified by Robert Schaub on 2026/02/08 21:46

System Components

Component Interaction

flowchart TB
    subgraph Client["🖥️ Client Layer"]
        BROWSER[Web Browser]
        ANALYZE_PAGE["/analyze page (React)"]
        JOBS_PAGE["/jobs page
Job history & status"] end subgraph NextJS["⚡ Next.js Web App (apps/web)"] direction TB subgraph API_Routes["API Routes"] ANALYZE_API["/api/fh/analyze
━━━━━━━━━━━━━
POST: Create job"] JOBS_API["/api/fh/jobs
━━━━━━━━━━━━━
GET: List jobs
POST: Create job"] JOB_API["/api/fh/jobs/[id]
━━━━━━━━━━━━━
GET: Job status"] EVENTS_API["/api/fh/jobs/[id]/events
━━━━━━━━━━━━━
GET: Job events (SSE)"] RUN_JOB["/api/internal/run-job
━━━━━━━━━━━━━
POST: Execute analysis"] end subgraph Lib["Core Libraries"] ANALYZER["analyzer.ts
━━━━━━━━━━━━━
AKEL Pipeline
~6700 lines"] RETRIEVAL["retrieval.ts
━━━━━━━━━━━━━
URL content extraction"] WEBSEARCH["web-search.ts
━━━━━━━━━━━━━
Search abstraction"] SR["source-reliability.ts
━━━━━━━━━━━━━
Source reliability (LLM+Cache)"] end end subgraph DotNet["🔧 .NET API (apps/api)"] DOTNET_API["FactHarbor.Api
ASP.NET Core"] subgraph Controllers["Controllers"] ANALYZE_CTRL["AnalyzeController"] JOBS_CTRL["JobsController"] INTERNAL_CTRL["InternalJobsController"] HEALTH_CTRL["HealthController"] end subgraph Services["Services"] JOB_SVC["JobService"] RUNNER_CLIENT["RunnerClient"] end DB[(SQLite Database
factharbor.db)] end subgraph External["🌐 External Services"] LLM["LLM Providers
Anthropic / OpenAI / Google / Mistral"] SEARCH["Search Providers
Google CSE / SerpAPI"] end %% Client connections BROWSER --> ANALYZE_PAGE BROWSER --> JOBS_PAGE ANALYZE_PAGE --> ANALYZE_API JOBS_PAGE --> JOBS_API JOBS_PAGE --> JOB_API JOBS_PAGE --> EVENTS_API %% Next.js internal ANALYZE_API --> JOBS_CTRL JOBS_API --> JOBS_CTRL JOB_API --> JOBS_CTRL EVENTS_API --> JOBS_CTRL RUN_JOB --> ANALYZER ANALYZER --> RETRIEVAL ANALYZER --> WEBSEARCH ANALYZER --> SR %% .NET internal ANALYZE_CTRL --> JOB_SVC JOBS_CTRL --> JOB_SVC INTERNAL_CTRL --> JOB_SVC ANALYZE_CTRL --> RUNNER_CLIENT JOB_SVC --> DB RUNNER_CLIENT --> RUN_JOB %% External connections ANALYZER --> LLM WEBSEARCH --> SEARCH RETRIEVAL --> External

Key Files

 File  Purpose  Size
 apps/web/src/lib/analyzer.ts  Core analysis engine (AKEL pipeline)  6700 lines
 apps/web/src/lib/retrieval.ts  URL/PDF content extraction  500 lines
 apps/web/src/lib/web-search.ts  Search provider abstraction  300 lines
 apps/web/src/lib/source-reliability.ts  Source reliability scoring  200 lines
 apps/web/src/app/jobs/[id]/page.tsx  Job results UI  800 lines
 apps/api/Controllers/JobsController.cs  Job CRUD API  200 lines
 apps/api/Data/FhDbContext.cs  Database context  100 lines
 apps/api/Services/RunnerClient.cs  Runner invocation with retry logic  150 lines

Unified Config Management (UCM)

FactHarbor uses UCM for all runtime configuration. UCM provides:

  • File-backed defaults with schema versioning
  • Admin UI for runtime configuration changes
  • Bidirectional sync between DB and files (development mode)
  • Drift detection and config validation

UCM Architecture

flowchart TB
    subgraph AdminUI [Admin UI]
        Tabs[Config Type Tabs]
        Editor[Editor/Form]
        History[Version History]
        Compare[Compare View]
    end

    subgraph ConfigTypes [Configuration Types]
        Pipeline[Pipeline]
        Search[Search]
        Calc[Calculation]
        SR[Source Reliability]
        Prompts[Prompts]
        Lexicons[Lexicons]
    end

    subgraph Storage [SQLite Storage]
        ConfigBlobs[config_blobs
immutable content] ConfigActive[config_active
activation pointers] ConfigUsage[config_usage
per-job tracking] end subgraph Validation [Validation Layer] ZodSchemas[Zod Schemas] Canonicalize[Canonicalization] end Tabs --> ConfigTypes ConfigTypes --> ZodSchemas ZodSchemas --> Canonicalize Canonicalize --> ConfigBlobs ConfigBlobs --> ConfigActive ConfigActive --> ConfigUsage

Configuration File Organization

FactHarbor uses a hybrid config storage model:

 Config Type  File Location  Format  UCM Domain
 Pipeline/Search/Calc  apps/web/configs/  JSON  Yes
 Prompts  apps/web/prompts/  Markdown  Yes
 Source Reliability  apps/web/configs/  JSON  Yes (separate)
 Lexicons  apps/web/configs/  JSON  Yes

Rationale: Prompts are version-controlled text that benefits from Markdown
formatting and line-based diffs. Structured configs benefit from JSON schema
validation and programmatic manipulation.

Source of Truth Hierarchy

  1. Runtime Authority: Database (what the app actually uses)
  2. Default Templates: JSON files in apps/web/configs/
  3. Fallback: Code constants in config-schemas.ts

See Unified_Config_Management.md (in User Guides) for details.


Navigation: Architecture Overview | Prev: Data Models | Next: Implementation Status and Quality