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
- Runtime Authority: Database (what the app actually uses)
- Default Templates: JSON files in apps/web/configs/
- 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