Domain · Specifications

Veritas Domain — Technical Specifications

Veritas ships 13 Nx applications under apps/veritas/.

19sections36 minread

On this page

Veritas is the autonomous AI-powered news agency for Ghana and West Africa. This document is the comprehensive technical specification of what is implemented in apps/veritas/* and libs/veritas/*. Every entity, enum, endpoint, and event below is traceable to source code; the grounding sources are listed at the end of each major section.

This document is organized as follows: §1–§2 enumerate the applications and libraries; §3–§4 cover the technology stack and infrastructure; §5 is the complete domain object model (the @veritas/core type system); §6–§9 document the running services (REST API, NLP, ingestion, AI workers); §10 covers the Prisma persistence schema; §11 covers domain events; §12–§13 document the agents system and CMS; §14 covers content authentication; §15–§16 list external integrations and configuration; §17 states acceptance criteria.

A new engineer reading this document for the first time should start with §1 (which apps exist), then §5 (what the core data model looks like), then §6 (what the API exposes), and then read §10 (how it is persisted) alongside whichever service section is most relevant to their work.


1. Application Inventory#

Veritas ships 13 Nx applications under apps/veritas/.

Application Package Type Description
API server @veritas/api Hono HTTP service REST API, API-key + JWT auth, OpenAPI/Swagger UI
NLP service veritas-nlp Hono HTTP service NLP analysis endpoints (sentiment, topics, claims, …)
Ingestion veritas-ingestion CLI worker RSS/sitemap/social collection pipeline (four modes)
AI workers veritas-ai-workers BullMQ workers AI content generation, processing, analysis, editorial
Agents veritas-agents Hono HTTP service Multi-agent orchestration service
CMS veritas-cms Hono HTTP service Editorial content-management workflow engine
Video veritas-video Worker + HTTP HeyGen video production pipeline
Audio veritas-audio Worker TTS and podcast production
Social veritas-social Worker + HTTP Multi-platform social automation
Analytics veritas-analytics Service Content, user, and revenue analytics
Notifications veritas-notifications Service Email and FCM push delivery
Web veritas-web Next.js PWA Progressive web application
Mobile veritas-mobile Expo / React Native iOS and Android application

The API server's package name is @veritas/api; its default HTTP port comes from the PORT environment variable and falls back to 3002 in apps/veritas/api/src/main.ts. The NLP service reads NLP_PORT (default 3002).

Grounding: apps/veritas/ directory listing; apps/veritas/api/package.json; apps/veritas/api/src/main.ts; apps/veritas/nlp/src/config.ts.


2. Library Inventory#

Veritas ships 64 libraries under libs/veritas/. Libraries are organized into six tiers by responsibility: Foundation (core types and infrastructure), Agents (the AI newsroom), NLP/Fact-checking/Bias, Content and Knowledge, Media Production, and Business/Monetization. The tables below list every library in each tier with its npm package name and description.

Foundation Libraries#

Package Path Description
@veritas/core libs/veritas/core Core domain types, branded primitives, error types
@veritas/models libs/veritas/models Zod validation schemas mirroring the core types
@veritas/database libs/veritas/database Prisma client, repositories, health, metrics, seed
@veritas/auth libs/veritas/auth Authentication, API keys, OAuth, middleware
@veritas/cache libs/veritas/cache Redis caching abstraction
@veritas/search libs/veritas/search Elasticsearch client, query builder, index manager
@veritas/llm libs/veritas/llm LLM client router, cost optimizer, multi-provider
@veritas/nlp-core libs/veritas/nlp-core NLP primitives and shared utilities
@veritas/events libs/veritas/events Domain event bus (publisher/subscriber)

Agent Libraries#

Package Description
@veritas/agents-core Base agent framework, LLM client, message bus, state
@veritas/agents-orchestrator Multi-agent workflow orchestration, registry, router
@veritas/agents-editorial Editor-in-Chief, Managing Editor, Content Strategist
@veritas/agents-journalism Investigative, political, breaking, business agents
@veritas/agents-fact-checking Fact-checker agent with web evidence search
@veritas/agents-social-media Social media manager agent
@veritas/agents-devops DevOps and infrastructure management agent
@veritas/agents-product Product management agent
@veritas/agents-qa QA and testing automation agent

NLP, Fact-Checking, and Bias Libraries#

Package Description
@veritas/ghana-nlp Ghana NLP (Khaya) API client
@veritas/bias-detection Political bias analysis and GPL scoring
@veritas/fact-checking Claim verification and evidence scoring
@veritas/claims Claim extraction and linking
@veritas/content-classification Topic and category classification

Content and Knowledge Libraries#

Package Description
@veritas/rag RAG pipeline (indexing, retrieval, archive)
@veritas/knowledge-graph Entity graph, profiles, relationships
@veritas/story-clustering Semantic story grouping and timeline
@veritas/recommendations Collaborative/content-based filtering
@veritas/headline-service Headline generation and A/B testing
@veritas/article-generation AI article drafting pipeline
@veritas/content-auth Content authenticity, hashing, C2PA, provenance
@veritas/cms CMS workflow engine
@veritas/ingestion-core Core ingestion pipeline primitives
@veritas/ai-next-gen Investigations, OSINT, real-time anchors
@veritas/automated-content Weather, market, fuel-price, traffic generators
@veritas/archive Content archival and retrieval
@veritas/research-assistant Research tools for journalists

Media Production Libraries#

Package Description
@veritas/video-production HeyGen video composition and rendering pipeline
@veritas/audio-production ElevenLabs/Ghana NLP TTS and mastering pipeline
@veritas/live-stream YouTube Live, RTMP, graphics, interactive Q&A
@veritas/social-automation Cross-platform social media posting

Business and Monetization Libraries#

Package Description
@veritas/analytics Content, user, revenue, social analytics
@veritas/payments Stripe, Paystack, mobile money integration
@veritas/billing Subscriptions, invoicing, pricing, usage
@veritas/notifications Push (FCM), email, SMS notification delivery
@veritas/b2b-sdk TypeScript SDK for B2B API consumers
@veritas/b2b-sdk-python Python SDK for B2B consumers
@veritas/api-client Internal/shared API client
@veritas/newsletter Email newsletter campaigns
@veritas/seo SEO optimization and sitemap generation
@veritas/business Profitability and business optimization
@veritas/expansion Pan-African geographic expansion
@veritas/developer-support AI-powered developer support chatbot for B2B API
@veritas/signup User registration flows

Regional, Access, and Infrastructure Libraries#

Package Description
@veritas/regional Region-specific content and configuration
@veritas/ussd USSD channel for telco news delivery
@veritas/platforms Platform SDKs for smartwatch, TV, enterprise
@veritas/ab-testing A/B testing for headlines and content
@veritas/community Community engagement features
@veritas/comments Article commenting system
@veritas/emergency Emergency broadcast and alert distribution
@veritas/storage File storage abstraction (S3/MinIO/GCS)
@veritas/realtime-data Real-time data feeds and streaming
@veritas/risk Risk assessment and content safety
@veritas/operations Security, compliance, QA, monitoring ops

Grounding: libs/veritas/ directory listing (64 entries).


3. Technology Stack#

Languages and Runtimes#

Technology Purpose
TypeScript All TypeScript packages (strict mode, ESM)
Node.js >= 22 — server runtime for all backend services
Python B2B Python SDK (@veritas/b2b-sdk-python)

Frameworks and Key Dependencies#

Dependency Used by Purpose
hono + @hono/node-server api, nlp, agents, cms HTTP server
@hono/swagger-ui api Swagger UI documentation page
@hono/zod-openapi api Zod-validated OpenAPI integration
zod models, api, nlp Runtime schema validation
@prisma/client + prisma database ORM and migrations
pg api, ingestion Raw PostgreSQL access
ioredis api, agents, ingestion Redis client
@elastic/elasticsearch api, search Elasticsearch client
stripe api, payments Card payments
bcryptjs api Password hashing

Grounding: apps/veritas/api/package.json; libs/veritas/core/package.json; libs/veritas/database/package.json.


4. Infrastructure Requirements#

Core Infrastructure#

Service Purpose
PostgreSQL Primary database, with pgvector and citext
Redis Caching, BullMQ job queues, sessions, agent pub/sub
Elasticsearch Full-text article search
MinIO / AWS S3 Media asset storage

PostgreSQL Extensions#

The Prisma datasource enables two extensions via previewFeatures = ["postgresqlExtensions"]:

Extension Mapped name Purpose
pgvector vector Vector embeddings for semantic deduplication / RAG
citext citext Case-insensitive text

Database Configuration#

Property Value
Connection variable VERITAS_DATABASE_URL
ORM Prisma (prisma-client-js generator)
Schema location libs/veritas/database/prisma/schema.prisma
Generated SQL libs/veritas/database/prisma/generated/schema.sql

The Prisma schema defines roughly 75 models and 50 enums (see §10 Persistence).

Grounding: libs/veritas/database/prisma/schema.prisma lines 1–17; model/enum declarations.


5. Domain Object Model (@veritas/core)#

@veritas/core is the canonical type layer — the single source of truth for every domain entity, enum, and primitive in the Veritas system. All other libraries import types from here rather than defining their own. @veritas/models provides matching Zod schemas (libs/veritas/models/src/schemas/) so that API boundaries can validate incoming and outgoing data against these types at runtime.

The sections below document each type file in libs/veritas/core/src/. The grounding note at the end of §5 lists every source file referenced.

5.1 Branded Primitives (common.ts)#

Branded primitives prevent accidental mixing of semantically distinct string values (e.g., passing a raw string where a validated URL is expected). Each primitive has a factory function and a type guard. The table below lists the four primitives and their validation rules.

Type Underlying Validation regex / rule
Uuid string isValidUuid — 8-4-4-4-12 hex UUID
UrlString string isValidUrlString^https?://.+
CountryCode string isValidCountryCode^[A-Z]{2}$ (ISO 3166-1 alpha-2)
Slug string isValidSlug^[a-z0-9]+(?:-[a-z0-9]+)*$

Factory functions: createUuid, createUrlString, createCountryCode, createSlug. Shared interfaces: Timestamped (createdAt, updatedAt), Cursor<T>, PaginatedResponse<T>, PaginationParams, WithMetadata. Result<T, E> / AsyncResult<T, E> are discriminated success/failure unions. Metadata is Record<string, unknown>.

5.2 Language (language.ts)#

The language system encodes Ghana's multilingual reality directly into the type layer. The eight BCP 47 language tags drive content routing, TTS provider selection, and search index configuration. CodeSwitchingResult models the common Ghanaian pattern of mixing English with a local language mid-sentence.

LANGUAGE_TAGS (BCP 47) — 8 values:

Tag Name Primary regions
en English Greater Accra, Ashanti, Western, Eastern, Central
tw Twi (Akan) Ashanti, Eastern, Greater Accra, Bono, Ahafo
ee Ewe Volta, Oti, Greater Accra
gaa Ga Greater Accra
ha Hausa Northern, Upper East, Upper West, North East, Savannah
dag Dagbani Northern, North East, Savannah
fr French Upper West, Upper East
und Undetermined

type Language is an alias of LanguageTag. TRANSLATION_QUALITIES = machine | human | verified. Translation carries id, languageTag, headline, summary, body, bodyHtml, quality, metadata. CodeSwitchingResult reports primaryLanguage, secondaryLanguages, confidence, hasCodeSwitching, and languageProportions. LocaleConfig and DEFAULT_LOCALE_CONFIGS define per-language date/time/number formatting; all eight default to country GH, ltr direction.

5.3 Article (article.ts)#

Article is the central entity in the domain model. It carries the full lifecycle of a piece of journalism: from raw ingestion metadata (sourceUrl, sourcePublishedAt) through editorial enrichment (claims, biasScore, perspectives) to publication and archival. The table below lists every field; fields marked null are optional or unset at ingestion time and populated progressively by the pipeline.

ARTICLE_STATUSESdraft | pending_review | published | scheduled | archived | retracted.

ARTICLE_CONTENT_TYPESnews | analysis | opinion | feature | interview | investigation | breaking | live_update | explainer | fact_check.

Article (extends Timestamped) — fields:

Field Type Notes
id Uuid required
slug Slug required
status ArticleStatus required
contentType ArticleContentType required
headline string required
summary string | null lede
body string plain text
bodyHtml string | null rendered HTML
featuredImage MediaAsset | null hero image
media MediaAsset[] all assets
audioVersion MediaAsset | null audio rendering
videoVersion MediaAsset | null video rendering
categories Category[]
tags Tag[]
entities Entity[] named entities
topics Topic[]
source ArticleSource | null originating source ref
sourceUrl UrlString | null
sourcePublishedAt Date | null
authors AuthorRef[]
attributions ArticleAttribution[] aggregated-content credits
isOriginal boolean
isAIGenerated boolean
humanReviewed boolean
reviewedBy UserRef | null
factCheckStatus FactCheckStatus | null
claims Claim[]
biasScore BiasScore | null
perspectives Perspective[] alternative perspectives
storyClusterId Uuid | null
relatedArticleIds Uuid[]
languageTag LanguageTag
translations Translation[]
publishedAt Date | null
scheduledAt Date | null
views number
shares number
readTimeSeconds number estimated read time
seo ArticleSEO | null
metadata Metadata

Supporting types: ArticleSource (id, name, domain, url), ArticleSEO (metaTitle, metaDescription, canonicalUrl, ogImage, twitterCardsummary | summary_large_image, focusKeywords, schemaTypeNewsArticle | Article | ReportageNewsArticle). ArticleListItem and ArticleDetail (extends list item) are read projections; ArticleFeedItem adds recommendationReason (trending | following | similar | breaking | personalized | editorial), score, hasInteracted, isFollowed. ArticleEngagement carries view/share/comment/save counts and a scrollDepth distribution (25% / 50% / 75% / 100%). ArticleSearchParams defines query/filter fields with sortByrelevance | recency | popularity | engagement.

Article versioningARTICLE_CHANGE_TYPES (created | updated | published | unpublished | corrected | retracted | restored | metadata_updated | media_updated | translation_added | auto_saved). ArticleVersion snapshots content per revision; ArticleVersionDiff records changed fields and TextDiff operations (equal | insert | delete); ArticleVersionComparison, ArticleVersionHistory, ArticleVersionSummary round out the revision API.

Article mediaARTICLE_MEDIA_PLACEMENTS (hero | inline | gallery | sidebar | pullquote | background | thumbnail). ArticleMedia, ArticleMediaGallery (layout grid | carousel | masonry | slideshow), and ArticleMediaSummary model in-article media placement.

DTOs: ArticleCreateInput, ArticleUpdateInput.

5.4 Source (source.ts)#

A Source represents a monitored news outlet. SourceFeed represents one polling endpoint within that outlet (an outlet may have multiple RSS feeds). SourceCredibility is the multi-signal credibility assessment that the system continuously updates as the source publishes articles that are later verified or refuted. Note that the Prisma SourceKind enum (§10) is broader than the SOURCE_KINDS in @veritas/core; both are documented below.

SOURCE_KINDS (core type) — publisher | government | ngo | blog | social | academic | wire_service | other.

SOURCE_STATUSESactive | paused | retired | pending.

OWNERSHIP_TYPESprivate | state | public | political | religious | ngo | community | academic | unknown | other.

FEED_TYPESrss | atom | sitemap | api | scrape.

Source (extends Timestamped) — id, name, kind, status, canonicalDomain, homeUrl, countryCode, region, languages, notes, ownership (SourceOwnership), bias (SourceBiasMetadata), metadata.

SourceFeed (extends Timestamped) — id, sourceId, feedType, url, isActive, fetchIntervalSeconds, priority, lastFetchedAt, lastHttpStatus, etag, lastModified, consecutiveFailures, backoffUntil, metadata.

SourceBiasMetadatapoliticalScore (−1…1), confidence (0…1), methodology, lastAssessedAt.

SourceReliabilityscore (0–100), factualAccuracy, correctionRate, transparency, factCheckedCount, lastAssessedAt.

SOURCE_CREDIBILITY_TIERShighly_credible | generally_credible | mixed_credibility | low_credibility | unreliable | unrated.

SourceCredibility is a multi-signal assessment: tier, overallScore, factualAccuracy, editorialStandards, transparency, correctionPractices, sourceAttribution, clickbaitFrequency, sensationalism, totalFactChecked, verifiedTrueCount, verifiedFalseCount, misleadingCount, correctionsIssued, retractionsIssued, externalRatings (SourceExternalRating[]), notes, redFlags (SourceCredibilityRedFlag[]), lastAssessedAt, methodologyVersion.

SourceBias (extended) adds articlesAnalyzed, topicBreakdown, historicalTrend, and indicators whose typeloaded_language | source_selection | story_selection | omission | placement | headline_framing | image_selection. SourceCredibilityRedFlag.typeknown_misinformation | undisclosed_ownership | deceptive_practices | content_farm | propaganda | satire_misrepresented | ai_generated_mass | plagiarism_pattern | state_controlled | advertising_disguised.

Other types: SourceCoverage, SourceRegistryEntry, SourcePerformanceMetrics. DTOs: SourceCreateInput, SourceUpdateInput, SourceFeedCreateInput.

Note: the Prisma SourceKind enum is broader than the core type — see §10.

5.5 Fact-Check (fact-check.ts)#

The fact-check type system models the complete verification lifecycle: claim extraction from article text (Claim), evidence retrieval and scoring (ClaimEvidence), verdict assignment (ClaimVerification), and the compiled report (FactCheckReport). Verdicts carry both a status label and a confidence score so downstream consumers can threshold on confidence as well as verdict.

FACT_CHECK_OVERALL_STATUSESverified | likely_true | disputed | misleading | mostly_false | false | unverifiable | unverified. Each status has a display label in FACT_CHECK_STATUS_LABELS and a hex color in FACT_CHECK_STATUS_COLORS.

CLAIM_TYPESfactual | opinion | prediction | quote | statistical | historical | scientific.

Claim (extends Timestamped) — id, text, normalizedText, type, articleId, speaker, context, checkworthiness (0–1), extractionConfidence (0–1), metadata.

ClaimEvidence (extends Timestamped) — id, claimId, url, sourceId, quote, title, summary, stance (supports | refutes | neutral | inconclusive), relevance (0–1), credibility (0–1), retrievedAt, metadata.

ClaimVerification (extends Timestamped) — id, claimId, status (FactCheckOverallStatus), confidence, evidenceIds, summary, notes, verifiedBy, metadata.

FactCheckStatus (article-level) — overall, a claims array of { claimId, text, status, confidence }, lastCheckedAt, checkedBy.

FactCheckReport (extends Timestamped) — id, articleId, claims, verifications, evidence, overallVerdict, summary, methodology, authorId, status (draft | review | published), publishedAt.

ClaimMatch reports similarity and matchType (exact | paraphrase | related | contradicts). CheckworthinessFactors and CheckworthinessAssessment score whether a claim is worth checking (prioritylow | medium | high | urgent).

CORRECTION_KINDScorrection | clarification | update | retraction. CORRECTION_SEVERITIESlow | medium | high. ArticleCorrection (extends Timestamped) — id, articleId, sourceId, kind, severity, summary, publicNote, publishedAt, metadata.

5.6 Bias (bias.ts)#

The bias type system models both the continuous political score (a float on −1…+1) and the discrete Ghana Political Lean (GPL) band (an integer on −3…+3 mapping to NDC vs. NPP alignment). The discrete band is used for display and editorial reporting; the continuous score is used for computation and trending. The CoverageBlindspot type models the complementary problem of what the newsroom is not covering.

BiasScorepolitical (−1…1), regional (string[]), confidence, methodology, lastAssessedAt.

Ghana Political SpectrumGHANA_POLITICAL_AXIS_VERSION = 'gh_political_axis_v1'. GHANA_POLITICAL_BIAS_BANDS is the integer set [-3, -2, -1, 0, 1, 2, 3], where −3 = Strong NDC lean … +3 = Strong NPP lean. toGhanaPoliticalBiasBand(score) clamps and rounds a continuous score; ghanaPoliticalAlignment(band) maps a band to npp | ndc | independent; ghanaPoliticalBandLabel(band) returns the human label.

BIAS_ASSESSMENT_METHODSautomated_nlp | manual_review | crowd_sourced | expert_panel | algorithmic | hybrid.

BiasAssessmentid, targetType (article | source), targetId, overallScore (BiasScore), ghanaPoliticalBand, method, linguisticIndicators (LinguisticBiasIndicators), coverageIndicators (CoverageBiasIndicators), notes, assessedAt, assessedBy.

PERSPECTIVE_STANCESsupporting | critical | neutral | analysis. Perspective carries source, url, stance, summary, metadata. BiasCorrection suggests balancing actions (biasTypepolitical | regional | source | linguistic | coverage). CoverageBlindspot (typetopic | region | perspective | source_type) and NewsDietAnalysis model under-coverage detection.

5.7 Entity (entity.ts)#

Entities are the named real-world things mentioned in articles: people, organizations, places, and events. The system links entity mentions across articles (entity linking) and maintains structured sub-types for Ghana-specific entities such as political figures with their position, party, and constituency.

ENTITY_TYPESperson | organization | place | event | product | work | concept | legislation | other.

Entityid, type, name, normalizedName, summary, externalIds (EntityExternalIds: wikidata, wikipedia, dbpedia, freebase, custom), metadata.

EntityMention records an entity occurrence in text (startOffset, endOffset, confidence, salience). Subtypes: PersonEntity, OrganizationEntity (orgTypegovernment | political_party | ngo | company | media | academic | other), PlaceEntity (placeTypecountry | region | city | district | landmark | other), EventEntity (eventTypeelection | conference | protest | disaster | ceremony | sports | other). EntityCandidate / EntityResolutionResult model entity linking.

Ghana-specificGHANA_POLITICAL_POSITIONS (president | vice_president | minister | deputy_minister | mp | mce | dce | regional_minister | chief_of_staff | speaker | chief_justice). GhanaPoliticalFigure extends PersonEntity with politicalData (position, partynpp | ndc | cpp | other, constituency, region, tenureStart, tenureEnd).

5.8 Media (media.ts)#

MediaAsset is the base type for all media attached to articles: images, videos, audio renders, embeds, and documents. Sub-types add provider-specific fields (e.g., VideoAsset carries HLS/DASH URLs; AudioAsset carries a waveform for the audio player). Storage is abstracted over multiple backends (s3, gcs, r2, minio, local, cdn).

MEDIA_KINDSimage | video | audio | embed | document | infographic. MEDIA_ROLESfeatured | inline | thumbnail | gallery | social | hero | background | other. MEDIA_STORAGE_PROVIDERSexternal | s3 | gcs | r2 | minio | local | cdn. MEDIA_SOURCESextracted | uploaded | generated | licensed.

MediaAssetid, kind, role, source, originalUrl, cdnUrl, mimeType, width, height, durationSeconds, sizeBytes, checksum, altText, caption, credit, storage (MediaStorage), metadata.

Subtypes: VideoAsset (extends MediaAsset; transcodeStatuspending | processing | completed | failed, variants, hlsUrl, dashUrl, thumbnail), AudioAsset (variants, waveform, transcript), EmbedAsset (provideryoutube | vimeo | twitter | facebook | instagram | tiktok | spotify | soundcloud | other). ResponsiveImage / ImageVariant support responsive image delivery.

5.9 Taxonomy (taxonomy.ts)#

Taxonomy organizes articles into a three-level hierarchy: broad Category (e.g., politics, sports), more specific Topic (with trending detection), and free-form Tag. The 12 seed categories (DEFAULT_CATEGORIES) and 16 Ghana administrative regions (GHANA_REGIONS) are hard-coded constants so that classification models and the UI can reference them by stable values.

Category (extends Timestamped) — hierarchical via parentId; CategoryTree adds children, depth, path. Topic (extends Timestamped) — more specific than category, carries isTrending and trendScore. Tag (extends Timestamped) — free-form, with usageCount.

DEFAULT_CATEGORIES — 12 seed categories: politics, business, sports, entertainment, technology, health, education, environment, crime, opinion, regional, international.

GHANA_REGIONS — all 16 administrative regions, each with slug, name, code (e.g. greater-accra/GA, ashanti/AS, … western-north/WN).

Helpers: buildCategoryPath, getCategoryDescendants. Statistics types: CategoryStats, TopicStats.

5.10 Story Cluster (story-cluster.ts)#

A StoryCluster groups articles from different outlets that cover the same underlying event. Clustering can be triggered by semantic similarity, entity overlap, temporal proximity, or a hybrid of all three. StoryTimeline and StoryTimelinePoint give readers a chronological view of how a story developed. StoryImportanceScore feeds the recommendation engine with a newsworthiness signal beyond recency.

CLUSTERING_METHODSsemantic_similarity | entity_overlap | temporal_proximity | topic_modeling | hybrid | manual. STORY_CLUSTER_STATUSESactive | developing | archived | merged.

StoryCluster (extends Timestamped) — id, title, summary, status, method, score, canonicalArticleId, articleIds, lastActivityAt, archivedAt, mergedIntoId, metadata.

StoryTimeline / StoryTimelinePoint (eventTypebreaking | update | analysis | reaction | follow_up) build chronological story views. StoryCoverageAnalysis reports source/regional/language distribution and a perspective balance. StoryImportanceFactors / StoryImportanceScore score newsworthiness (timeliness, impact, prominence, proximity, conflict, novelty, human interest). ClusterMergeRequest, RelatedStoryRecommendation, StorySearchParams, StorySearchResult complete the API.

5.11 Author (author.ts)#

Authors can be either external correspondents (human writers from ingested sources) or internal Veritas contributors. AuthorProfile is the public- facing profile used on the website; ArticleAttribution handles syndication credit for aggregated content.

Author (extends Timestamped) — id, name, slug, bio, avatarUrl, sourceId, socialLinks, expertise, metadata. AuthorRef and UserRef are lightweight references. ArticleAttribution records syndication credit.

CONTRIBUTOR_ROLESauthor | editor | reviewer | translator | photographer | illustrator | contributor. AUTHOR_VERIFICATION_STATUSESunverified | pending | verified | notable.

AuthorProfile (extends Author) is the public-profile entity with credentials, affiliations, beats, awards, profileStats, profileCompleteness. DTOs: AuthorCreateInput, AuthorUpdateInput, AuthorProfileUpdateInput.

5.12 Errors (errors.ts)#

All Veritas services use a shared error hierarchy so that API responses are consistent and clients can write a single error-handling path. DomainError carries a DOMAIN_ERROR_CODES code for programmatic discrimination; normalizeError and createErrorResponse are helpers used by the Hono error handler in veritas-api.

@veritas/core exports HTTP error classes (HttpError, BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, ValidationError, RateLimitError, InternalError, ServiceUnavailableError), a DomainError class with DOMAIN_ERROR_CODES, and helpers normalizeError and createErrorResponse.

Grounding: libs/veritas/core/src/{common,language,article,source,fact-check, bias,entity,media,taxonomy,story-cluster,author,errors,index}.ts.


6. REST API (@veritas/api)#

veritas-api is the single HTTP gateway for all external traffic. Web, mobile, and B2B clients speak only to this service; it proxies no other internal services directly but shares database access via the common library layer. All routes are versioned under /api/v1. The service exposes 29 route groups covering the full product surface: editorial content, analytics, payments, compliance, and B2B access.

6.1 Server Configuration#

  • Framework: Hono with @hono/node-server.
  • Route mounting: all v1 routes are mounted under /api/v1 (see registerV1Routes, which creates a sub-Hono and calls app.route('/api/v1', v1)).
  • Middleware (server.ts, applied in order): request logger (optional), timing, secureHeaders, cors (optional), Redis-backed rate limiting on /api/* (optional), sandbox detection on /api/*, API-key authentication on /api/* (optional), and a global errorHandler.
  • Auth: API-key authentication middleware (X-API-Key); a separate JWT access-token mechanism backs the /auth/* routes (infrastructure/auth/accessToken.ts).
  • Sandbox mode: requests with test API keys (sk_test_*) are detected by sandboxMiddleware; X-Sandbox-* headers tune scenario, seed, latency, and error injection. A dedicated /api/v1/sandbox route group is mounted when a Postgres pool is available.
  • OpenAPI: generateOpenApiSpec emits an OpenAPI document served at GET /openapi.json, with Swagger UI at GET /docs (and /docs/*). The spec declares a single server with base URL /api/v1.

6.2 Route Groups#

All paths below are relative to /api/v1. Methods are taken directly from the route handler source files. The tables are organized by functional area; within each area, read the route list as a contract — what the API promises to provide.

Note on the health route: the /health and /ready liveness/readiness endpoints are mounted at the app root (not under /api/v1), so they are reachable without an API key for use by load balancer health checks.

Health (routes/health.ts, mounted at app root, not under /api/v1): liveness/readiness endpoints.

Auth (auth.ts):

Method Path Purpose
POST /auth/register Register a reader account
POST /auth/login Log in, issue access token
GET /auth/me Current authenticated user
POST /auth/logout Log out

Articles (articles.ts):

Method Path Purpose
GET /articles List articles
GET /articles/trending Trending articles
GET /articles/search Search articles
GET /articles/search/suggest Search autocomplete suggestions
GET /articles/:id Article detail
GET /articles/:id/related Related articles

Sources (sources.ts):

Method Path Purpose
GET /sources List sources
GET /sources/bias-spectrum Sources arranged by bias
GET /sources/media-groups Media-group groupings
GET /sources/cross-ownership Cross-ownership relationships
GET /sources/:id Source detail
GET /sources/:id/transparency Transparency record
GET /sources/:id/corrections Source corrections
GET /sources/:id/bias Source bias assessment
GET /sources/:id/ownership Ownership detail
GET /sources/:id/regional-emphasis Regional coverage emphasis
GET /sources/:id/regional-comparison Regional comparison

Claims and fact-checking (claims.ts):

Method Path Purpose
GET /claims List claims
GET /claims/:id Claim detail
GET /claims/:id/articles Articles citing a claim
POST /fact-check Run a fact check

Bias (bias.ts):

Method Path Purpose
POST /bias/score Score text for political bias
GET /articles/:id/bias Get an article's bias score
POST /articles/:id/bias Compute/store an article's bias

The bias routes use a pluggable PoliticalBiasScorer from AppContext; when not wired, they fall back to a Ghana keyword baseline in domain/political-bias-scorer.ts.

Stories (stories.ts): GET /stories, GET /stories/:id, GET /stories/:id/articles.

Taxonomy (taxonomy.ts): GET /categories, GET /topics.

Media renders (audio.ts, video.ts): GET /audio, GET /video.

Voice / Avatar profiles (voiceProfiles.ts, avatarProfiles.ts): voice and avatar profile management.

Writing assistant (writingAssistant.ts): POST /writing-assistant.

Tips (tips.ts): POST /tips — encrypted reader tip submission.

Home-feed preferences (preferences.ts): GET / PUT / PATCH /preferences/home-feed.

Reading mode (reading-mode.ts): reading-mode preferences.

Compliance — NMC (compliance.ts): 14 endpoints under /compliance/nmc/* covering guidelines, violations, remedies, complaint stages, content checks (POST /compliance/nmc/check, .../check/batch), complaints CRUD and transitions, per-source compliance scores, statistics, and ethics references.

Data protection (data-protection.ts): DPA (Data Protection Act) consent and subject-request endpoints.

Election coverage (election-coverage.ts): 11 endpoints under /election/* — constitutional references, guidelines, offences, parties, phase detection, coverage checks (POST /election/check), active elections, configuration, and per-election violations and balance reports.

Payments — Mobile Money (payments.ts): 13 endpoints under /payments/momo/* (request, status, pre-approval, refund, validate, balance, collection/disbursement/pre-approval callbacks) plus /payments/transactions/:userId and /payments/subscriptions/:userId.

Payments — Vodafone / AirtelTigo / Stripe (vodafone-payments.ts, airteltigo-payments.ts, stripe-payments.ts): provider-specific payment routes.

Subscriptions (subscriptions.ts): ~26 endpoints — plan catalog (/subscriptions/plans, .../plans/:planId), current subscription, lifecycle (subscribe, upgrade, downgrade, cancel, resume, pause, unpause), history, usage metering (usage, usage/monthly, usage/increment), feature access checks, family-plan invitations and membership, and student verification.

Paywall (paywall.ts): paywall configuration and metering.

Subscription analytics (subscription-analytics.ts): subscription metrics.

Ads (ads.ts): 15 endpoints under /ads/* — config, eligibility, placements, impression/click tracking, ad units CRUD, campaigns CRUD, campaign status, creatives, and analytics.

Ad networks (ad-networks.ts): ad-network configuration.

B2B API (b2b-api.ts): ~27 endpoints under /b2b/* — content feed (/b2b/feed, .../feed/trending, .../feed/:id), search and suggest, fact-check claims and search, entity search/CRUD/articles/relationships and mention/relationship ingestion, media listing/search, alerts CRUD plus alert notifications, and /b2b/monitoring/stats.

API keys (api-keys.ts): 11 endpoints under /api-keys/* — create, list, detail, update, delete, rotate, per-key usage and billing, usage summary, validation, and rate-limit checks.

Grounding: apps/veritas/api/src/interfaces/http/server.ts; routes/v1/index.ts; the individual route files under routes/v1/.


7. NLP Service (veritas-nlp)#

veritas-nlp is a dedicated Hono microservice for all NLP analysis. It runs as a separate process from the API so that CPU-intensive analysis tasks do not block API response times. The NLP service exposes 23 HTTP endpoints (plus health) organized around nine capability areas: sentiment, topics, keywords, summarization, claims, language, embeddings, evidence, and Ghana-specific NLP. Most analysis endpoints have a /batch variant for processing multiple items in a single request.

The service is provider-agnostic: it routes each request to the best available provider (e.g., Cohere for embeddings, HuggingFace for sentiment, Ghana NLP Khaya for local-language tasks) and falls back gracefully if a provider is unavailable. All provider API keys are read from environment at startup:

HUGGINGFACE_API_KEY, ANTHROPIC_API_KEY, OPENAI_API_KEY, COHERE_API_KEY, SERPER_API_KEY, BRAVE_API_KEY, GHANA_NLP_API_KEY, KHAYA_API_KEY.

NLP Endpoints#

The table below lists all 23 analysis endpoints plus the three health probes. The default port is NLP_PORT (3002).

Method Path Purpose
GET /health Health check
GET /healthz Simple liveness
GET /ready Readiness probe
POST /sentiment Sentiment analysis
POST /sentiment/batch Batch sentiment analysis
POST /topics/classify Topic / category classification
POST /topics/classify/batch Batch topic classification
POST /keywords/extract Keyword extraction
POST /keywords/extract/batch Batch keyword extraction
POST /summarize/extractive Extractive summarization
POST /summarize/abstractive Abstractive (LLM) summarization
POST /claims/extract Claim extraction from text
POST /claims/extract/batch Batch claim extraction
POST /language/detect Language detection
POST /language/code-switch Code-switching detection
POST /language/normalize Ghanaian English normalization
POST /embeddings/embed Text embedding generation
POST /embeddings/embed/batch Batch embedding generation
POST /similarity/compare Semantic similarity comparison
POST /evidence/search Evidence retrieval for claim verification
POST /ghana/translate Ghana NLP cross-language translation
POST /ghana/tts Ghana NLP local-language TTS
POST /ghana/ner Named-entity recognition via Ghana NLP

Service Providers#

Each NLP capability is implemented under src/services/ as a separate module with a primary provider and optional fallbacks. The table below lists the capability, its default provider, and any secondary providers.

The NLP service organizes implementations under src/services/, each with a default provider plus fallbacks:

  • sentiment — HuggingFace + a Ghana-calibration layer.
  • topics — HuggingFace zero-shot classification.
  • keywords — RAKE algorithm.
  • summarization — extractive (statistical) and abstractive (LLM).
  • claims — heuristic extractor plus an LLM extractor.
  • embeddings — Cohere and OpenAI providers.
  • similarity — HuggingFace.
  • evidence — Serper and Brave search providers.
  • language — detection and normalization.
  • ghana — Ghana NLP / Khaya client (translate, TTS, NER).

Grounding: apps/veritas/nlp/src/server.ts; config.ts; src/services/* directory listing.


8. Ingestion Pipeline (veritas-ingestion)#

veritas-ingestion is the content discovery engine. It runs as a CLI process with four modes that together implement the full ingestion cycle. In production these modes typically run as separate containers pointing at the same database and Redis instance:

  1. Scheduler polls the source registry on configured intervals and writes raw feed items to PostgreSQL.
  2. Producer reads unprocessed feed items from PostgreSQL and pushes them onto the BullMQ queue for the Worker.
  3. Worker picks up queue jobs, scrapes the full article, normalizes it, runs SimHash deduplication, and stores it in PostgreSQL and Elasticsearch.
  4. Seed bootstraps a fresh installation with the 33 Tier-1 and government Ghana news sources.

A single CLI deployable with four modes (apps/veritas/ingestion/src/main.ts):

Mode Command Description
Scheduler node main.js scheduler Fetches feeds on schedule, queues raw items
Producer node main.js producer Enqueues unprocessed items into the BullMQ queue
Worker node main.js worker Processes the queue: scrape, normalize, deduplicate
Seed node main.js seed Seeds the database with Ghana news sources

The seed command supports --dry-run and --summary.

Collectors and Pipeline#

The ingestion pipeline is composed of four sub-systems wired together in the Worker mode. Collectors fetch raw feed data; the Scraper extracts the full article body; the Pipeline normalizes and deduplicates; the Queue manages job delivery and retry.

  • Collectors (src/collectors/): RSS collector + parser, sitemap collector, social collector, X (Twitter) collector.
  • Scraper (src/scraper/): article extraction, robots.txt handling, throttling.
  • Pipeline (src/pipeline/): language detection, media extraction, normalization, timestamp normalization, SimHash near-duplicate detection, and the processing worker.
  • Queue (src/queue/): the main processing queue is named veritas:content-processing; the per-item job type is process_feed_item.

Seeded Sources#

Running node main.js seed bootstraps the source registry with two sets of Ghana news sources. New engineers should run the seed command after the first database migration to get a working set of sources for local development.

The seed command upserts two source sets:

  • TIER1_GHANA_SOURCES (seeds/tier1-ghana-sources.ts) — 21 Tier-1 Ghana media sources (e.g. MyJoyOnline, Adom Online, Citi Newsroom, Graphic Online), grouped by media group, contributing roughly 80 feeds in total.
  • GOVERNMENT_SOURCES (seeds/government-sources.ts) — 12 Ghana government / institutional sources, contributing roughly 22 feeds.

Combined: 33 seeded sources / ~102 feeds. Helper functions (getTotalFeedCount, getMediaGroupSummary, getGovFeedSummary, getActiveGovSources) summarize the seed set; runSeed also prints a media- group breakdown and a bias-band distribution.

Grounding: apps/veritas/ingestion/src/main.ts; src/seeds/{seed, tier1-ghana-sources,government-sources,index}.ts; src/queue/constants.ts; src/collectors/, src/pipeline/, src/scraper/ directory listings.


9. AI Workers (veritas-ai-workers)#

veritas-ai-workers is the background processing engine for AI enrichment. Each worker is a BullMQ consumer that processes one specific job type — a clean separation that allows individual workers to be scaled independently based on queue depth. Workers are organized into four registries by function; ALL_WORKERS merges all four for registration at startup.

To discover workers programmatically, use listWorkers() to get all 24 worker definitions, or getWorker(name) to retrieve a specific one by its queue name.

BullMQ workers organized into four registries under apps/veritas/ai-workers/src/workers/. ALL_WORKERS merges all four; getWorker and listWorkers provide lookup. There are 24 workers in total.

Content generation (CONTENT_WORKERS, 8): weather-report, traffic-update, market-summary, fuel-price, gpl-score, ecg-load-shedding, event-calendar, trend-analysis.

Content processing (PROCESSING_WORKERS, 9): article-summarization, headline-variants, article-tagging, article-priority, claim-linking, press-release, breaking-news, entity-extraction, seo-metadata.

Analysis (ANALYSIS_WORKERS, 5): story-clustering, source-accuracy, blindspot-detection, political-bias, sentiment-analysis.

Editorial (EDITORIAL_WORKERS, 2): fact-check, original-content.

Each worker exposes a tick function and a getDefault*Options factory.

Grounding: apps/veritas/ai-workers/src/workers/{index,content/index, processing/index,analysis/index,editorial/index}.ts.


10. Persistence — Prisma Schema#

The Prisma schema at libs/veritas/database/prisma/schema.prisma (≈1,900 lines) defines roughly 75 models and 50 enums. It is the authoritative source of truth for the database structure — the domain object model in @veritas/core (§5) mirrors it in TypeScript, but the Prisma schema is what actually migrates.

The schema is large; the sections below summarize the most important enums and models organized by functional area. Engineers implementing new features should read the full schema file directly, using this section as a map.

10.1 Selected Enums#

The following enums are defined in the Prisma schema. Several have counterparts in @veritas/core but with slightly different value sets — where there is a difference, both are documented (see §5.4 for the SourceKind divergence).

SourceStatus (active | paused | retired | pending); SourceKind (newspaper | broadcaster | news_agency | digital_native | wire_service | publisher | government | ngo | blog | social | academic | other — broader than the @veritas/core SOURCE_KINDS); OwnershipType; FeedType; ArticleStatus; ArticleContentType; TranslationQuality; PerspectiveStance; EntityType; MediaKind / MediaRole / MediaSource / MediaStorageProvider; FactCheckOverallStatus; ClaimType; EvidenceStance; ClusteringMethod; StoryClusterStatus; EmbeddingProvider; VoiceProvider; SocialPlatform; ContentPriority; ScheduleRunStatus; WhatsAppSubscriberStatus / WhatsAppPostStatus; SourcePreferenceType; ContributorRole; CorrectionKind / CorrectionSeverity; AIReviewKind; the NMC enums (NmcViolationCategory, NmcComplaintStage, NmcComplaintSeverity, NmcComplainantType, NmcRemedy); the DPA enums (DpaLawfulBasis, DpaProcessingPurpose, DpaRequestType, DpaRequestStatus); the election enums (ElectionType, ElectionCoverageViolationType, CoverageComplianceLevel); and the payment enums (PaymentTransactionType, PaymentTransactionStatus, SubscriptionStatus).

10.2 Selected Models by Area#

The 75 models group naturally into the functional areas listed below. Each bullet names the Prisma models that belong to that area; the relationships between models in the same area are captured in the schema's @relation directives.

  • Sources & feedsSource, SourceFeed, FeedItem, NormalizedFeedItem, SocialMonitor, SocialPost.
  • ArticlesArticle (with priority, canonicalNormalizedFeedItemId, flags isOriginal/isAIGenerated/humanReviewed, engagement counters, and ~30 relations), Author, ArticleAuthor, ArticleAttribution, ArticleTranslation, ArticlePerspective, ArticleRelated.
  • TaxonomyCategory, Topic, Tag, ArticleCategory, ArticleTopic, ArticleTag.
  • EntitiesEntity, ArticleEntity, EntityRelationship.
  • MediaMediaAsset, ArticleMedia.
  • Story clustersStoryCluster, StoryClusterMember.
  • Fact-checkingClaim, ArticleClaim, ArticleFactCheck, ClaimVerification, ClaimEvidence.
  • EmbeddingsArticleEmbedding (pgvector).
  • Auth & usersAuthUser, AuthIdentity, PasswordReset, UserArticleRead, UserSavedArticle, UserTopicFollow, UserSourcePreference, UserAuthorFollow.
  • Media productionVoiceProfile, ArticleAudioRender, AvatarProfile, ArticleVideoRender.
  • NotificationsUserPushToken, PushNotificationOutbox, PushNotificationDelivery.
  • Social schedulingYouTubeShortsScheduleRun, TikTokScheduleRun, WhatsAppChannelSubscriber, WhatsAppChannelPost.
  • EditorialArticleCorrection, ArticleAIReview, ArticleRevision, ArticleSummaryVariant, ArticleHeadlineVariant, CalendarEvent.
  • ComplianceNmcComplaint, NmcComplaintTransition, NmcContentCheck, NmcViolationFlag; DpaConsent, DpaSubjectRequest; Election, ElectionCoverageViolation.
  • PaymentsPaymentTransaction, PaymentSubscription.

Grounding: libs/veritas/database/prisma/schema.prisma — model/enum declarations.


11. Domain Events (@veritas/events)#

The event bus enables loose coupling between Veritas services and other Oshun domains. When an article is published, the veritas.article.published event fires and any subscriber — inside or outside Veritas — can react without being called directly. This is how, for example, a notification service learns that a breaking news article has gone live without being tightly coupled to the CMS.

@veritas/events is built on @oshun/event-bus. It exposes createVeritasPublisher / createVeritasSubscriber and the VERITAS_EVENT_TYPES constant. The schema-to-payload mapping is VeritasEventPayloads.

VERITAS_EVENT_TYPES defines 41 event type strings, all veritas.*-namespaced, grouped into ten areas. The table below maps each constant name to its string value and shows which group it belongs to.

Group Event types (constant → string)
Article lifecycle ARTICLE_CREATED veritas.article.created; ARTICLE_UPDATED; ARTICLE_PUBLISHED; ARTICLE_UNPUBLISHED; ARTICLE_ARCHIVED; ARTICLE_DELETED
Content processing ARTICLE_INGESTED; ARTICLE_PROCESSED; ARTICLE_ENRICHED; ARTICLE_TRANSLATED
Fact-checking CLAIM_EXTRACTED; CLAIM_VERIFIED; FACT_CHECK_STARTED; FACT_CHECK_COMPLETED; FACT_CHECK_FAILED
Story clustering STORY_CLUSTER_CREATED veritas.story.created; STORY_CLUSTER_UPDATED; STORY_CLUSTER_MERGED; ARTICLE_CLUSTERED
Source & feed SOURCE_CREATED; SOURCE_UPDATED; SOURCE_SUSPENDED; SOURCE_ACTIVATED; FEED_FETCHED; FEED_FAILED
Media generation VIDEO_GENERATION_STARTED; VIDEO_GENERATION_COMPLETED; VIDEO_GENERATION_FAILED; AUDIO_GENERATION_STARTED; AUDIO_GENERATION_COMPLETED; AUDIO_GENERATION_FAILED; IMAGE_GENERATION_COMPLETED
Alerts BREAKING_NEWS_PUBLISHED veritas.alert.breaking; MODERATION_ALERT; BIAS_ALERT; MISINFORMATION_ALERT
Analytics TRENDING_UPDATED; ENGAGEMENT_RECORDED; READER_MILESTONE
User USER_SUBSCRIBED; USER_PREFERENCES_UPDATED; USER_SAVED_ARTICLE
NLP processing NLP_SENTIMENT_COMPLETED; NLP_TOPICS_CLASSIFIED; NLP_KEYWORDS_EXTRACTED; NLP_SUMMARY_GENERATED; NLP_ENTITIES_EXTRACTED

Representative Event Payloads#

Not all 41 event types have a dedicated payload interface — 37 do; the remaining 4 are declared as type constants only. The payloads below are the most commonly subscribed-to events and illustrate the data available to consumers.

  • ArticleCreatedPayload (extends ArticleEventBase: articleId, slug, headline, optional sourceId/sourceName/authorIds/categoryIds/ topicIds, languageTag) — adds contentType, isOriginal, isAIGenerated, optional sourceUrl, summary.
  • ClaimVerifiedPayloadclaimId, optional articleId, verdict (true | mostly_true | mixed | mostly_false | false | unverifiable), confidence, an evidence array, optional verifiedBy, verificationMethod (automated | manual | hybrid).
  • FeedFetchedPayloadfeedId, sourceId, sourceName, feedUrl, itemsFetched, newItems, fetchDurationMs, optional nextFetchAt.
  • BreakingNewsPublishedPayloadalertId, articleId, headline, optional summary, priority (critical | high | normal), optional categoryIds/topicIds, expiresAt.
  • NLPEntitiesExtractedPayloadarticleId, an entities array (text, type, confidence, positions, optional linked id/url), processingDurationMs.

Note: VeritasEventPayloads maps 37 of the 41 event types to explicit payload types; ARTICLE_ARCHIVED, ARTICLE_DELETED, SOURCE_SUSPENDED, SOURCE_ACTIVATED, FACT_CHECK_FAILED, the *_GENERATION_STARTED/*_FAILED variants, and the three USER_* events are declared as type constants without a dedicated payload interface.

Grounding: libs/veritas/events/src/types.ts; src/index.ts.


12. Agent System (veritas-agents, @veritas/agents-*)#

The agent system implements a virtual newsroom. Seven specialized agents run concurrently, each with a defined role, priority, and set of capabilities. The Orchestrator distributes incoming tasks to the appropriate agent; the Message Bus handles inter-agent communication; the State Manager persists agent state across restarts; and the Health Monitor self-heals failed agents.

For new engineers, the easiest mental model is: the 24 AI workers (§9) do fast, queue-based enrichment without judgment; the 7 agents do slower, reasoned editorial work with full editorial context and decision authority.

12.1 Agents Service#

veritas-agents (apps/veritas/agents/) is a Hono service composed of:

  • Orchestrator (orchestration/orchestrator.ts) — task distribution with distributionStrategy: 'load_balanced', auto-scaling thresholds, agent registry, and periodic state sync.
  • Message Bus (communication/message-bus.ts) — Redis pub/sub with an in-memory fallback, bounded queue, and retry policy.
  • State Manager (state/state-manager.ts) — Redis KV state with a 24-hour TTL, compression, and the veritas:state: key prefix.
  • Health Monitor (monitoring/health-monitor.ts) — self-healing with a failure threshold of 3, latency/error-rate thresholds, and a cap of 10 healing actions per hour.
  • Metrics Collector (metrics/metrics-collector.ts) — per-agent metrics.

12.2 Default Agent Roster#

getDefaultAgents() in apps/veritas/agents/src/main.ts registers the 7 default agents with the priorities and concurrency limits shown below. Higher priority agents pre-empt lower-priority ones when resources are constrained. The two journalist agents (IDs journalist-1 and journalist-2) share the same role constant but have different specializations (investigative and political respectively).

getDefaultAgents() in apps/veritas/agents/src/main.ts registers 7 agents:

Agent ID Role Priority Max concurrent tasks
editor-in-chief-1 editor_in_chief 10 5
managing-editor-1 managing_editor 9 5
fact-checker-1 fact_checker 8 3
journalist-1 journalist (investigative) 7 3
journalist-2 journalist (political) 7 3
content-strategist-1 content_strategist 6 3
social-media-manager-1 social_media_manager 5 5

AGENT_ROLES (in core/types.ts) also defines system roles orchestrator and monitor. JOURNALIST_SPECIALIZATIONS are political | business | sports | entertainment | regional | investigative | breaking_news | general. AGENT_STATUSES are initializing | idle | busy | paused | error | shutting_down | stopped. TASK_TYPES enumerates content-creation, verification, media, research, editorial, and system task kinds.

12.3 Agents HTTP API#

veritas-agents exposes an HTTP API for submitting tasks and monitoring agent health. It is an internal API — only called by veritas-api and the CMS, not exposed to external clients directly.

All routes prefixed /v1:

Method Path Purpose
GET /health, /ready Service liveness/readiness
GET /v1/agents List all agents
GET /v1/agents/:id Agent detail
GET /v1/agents/role/:role Agents filtered by role
GET /v1/agents/:id/health Agent health
GET /v1/agents/:id/issues Agent health issues
POST /v1/tasks Submit a task
GET /v1/tasks/:id Task detail
GET /v1/orchestrator/stats Orchestrator statistics
POST /v1/orchestrator/distribute Trigger task distribution
GET /v1/health/issues Active health issues
GET /v1/health/history Self-healing history
GET /v1/metrics Metrics (JSON)
GET /v1/metrics/prometheus Metrics (Prometheus format)

12.4 Specialized Agent Libraries#

@veritas/agents-editorial ships editor-in-chief, managing-editor, and content-strategist (with a Google Trends provider). @veritas/agents- journalism ships investigative-correspondent, political-, business-, and breaking-news-correspondent agents. @veritas/agents-fact- checking ships the fact-checker agent with web-evidence search. @veritas/agents-social-media, @veritas/agents-devops, @veritas/agents-product, and @veritas/agents-qa ship their respective agents. @veritas/agents-core provides the base agent, LLM client, context-window manager, message bus, state, health, metrics, and logging primitives; @veritas/agents-orchestrator provides an orchestrator with a registry, router, and conflict resolver.

Grounding: apps/veritas/agents/src/{main,server,core/types}.ts; apps/veritas/agents/src/{orchestration,communication,state,monitoring, metrics}/ directory listings; libs/veritas/agents-*/src/ listings.


13. CMS (veritas-cms)#

The CMS is the final gate before publication. Articles pass through it in a Draft → Review → Schedule → Publish lifecycle. The AI review stage uses Claude to produce a structured approve/reject/request-changes decision that either progresses the article to scheduling or returns it to the journalist with written rationale. The rate limiter and quiet-hours configuration prevent feed flooding and respect Ghanaian audience patterns.

The CMS service (apps/veritas/cms/) runs the editorial workflow. Its configuration (src/config.ts) sets:

  • maxArticlesPerWindow: 6 — at most 6 articles per 30-minute window.
  • defaultQuietHours: { start: '22:00', end: '06:00' } — no scheduled publishing during quiet hours.
  • defaultTimezone: 'Africa/Accra'.
  • Optimal-time windows including a 06:00 morning slot and a 20:00–22:00 prime- time window.

Service modules: articles/, revisions/ (revision service with diffing), reviews/ (AI-assisted review service), scheduling/ (scheduler service with quiet-hours enforcement), queue/ (publication queue), and storage/ (memory storage adapter).

Grounding: apps/veritas/cms/src/{config,types,main}.ts; src/ directory listing.


14. Content Authentication (@veritas/content-auth)#

Content authentication gives Veritas's AI-generated articles and media assets a cryptographic provenance record that can be independently verified. This matters for two reasons: (1) it allows Veritas to prove an article's origin if it is later disputed or misattributed; (2) the C2PA manifests make the content interoperable with other publishers and platforms implementing the C2PA standard for AI-generated media disclosure.

@veritas/content-auth implements cryptographic content hashing, blockchain timestamp proofs, authenticity certificates, media-origin tracking, edit history, and device signing, plus deepfake and image-manipulation detection. It exports managers including BlockchainTimestampManager and DeviceSigningManager (with create* factory functions).

The type surface includes ContentHash / HashAlgorithm, BlockchainTimestamp / BlockchainNetwork / MerkleTreeNode / BatchTimestamp, AuthenticityCertificate / DigitalSignature / VerificationBadge / CustodyRecord, MediaOrigin / ExifData, and a full C2PA type set — C2PAManifest, C2PAAssertion, C2PACredential, C2PASignature, C2PAValidationStatus — for content-provenance manifests.

Grounding: libs/veritas/content-auth/src/index.ts; src/ listing.


15. V2 Esports Fact-Checking Bridge#

The V2 esports tooling package @v2/esports-tools (apps/v2/esports-tools/) consumes @veritas/fact-checking to verify esports outcomes and reporting after matches conclude. Veritas owns the verification primitives; V2 owns only the esports framing and the rollback isolation. Veritas itself does not depend on V2.

veritas-esports-fact-checking.ts exposes buildV2VeritasEsportsFactChecking (binding id v2.esports.veritas-fact-checking), which composes the real Veritas scoring primitives — calculateVerificationScore, calculateConsensus, and getDomainCredibility — over evidence collected for three surfaces: bracket result verification, post-match reporting, and the esports news pipeline. The output is Veritas's own FactCheckReport type, so a bracket or news claim is scored against weighted, domain-credibility-ranked evidence exactly as any other Veritas claim would be.

The contract is deliberately advisory and off rollback. Its rollback policy is off-rollback-post-match-journalism and it carries mayInfluenceRollback: false: a fact-check verdict can never rewrite a match that already happened, reorder a bracket, or feed back into the deterministic simulation. A verified bracket emits v2.esports.veritas.bracket-result.verified. When the reported winner, the replay winner, and the bracket winner disagree, the bridge does not silently pick one — it holds publication of the affected post-match report or news story until the conflict is resolved by an editor, so unverified esports claims never ship as fact.

This bridge is documented under V2/docs/integration/veritas-esports-fact-checking.md and is verified by V2/ue/Tools/check-v2-veritas-esports-fact-checking.py.

Grounding: apps/v2/esports-tools/src/veritas-esports-fact-checking.ts; libs/veritas/fact-checking/src/.


16. External Integrations#

The table below maps each external service to the library or application that uses it and summarizes its purpose. All provider credentials are injected as environment variables — no keys are hard-coded in source.

Service Library/App Purpose
Anthropic Claude llm, agents-core, nlp LLM orchestration, abstractive summarization
OpenAI llm, nlp Alternative LLM provider, embeddings
Cohere nlp (embeddings) Embeddings
HuggingFace nlp (sentiment, topics, similarity) Inference API
Ghana NLP (Khaya) ghana-nlp, nlp (ghana) Local-language TTS, NER, translation
Serper nlp (evidence) Search-based evidence retrieval
Brave Search nlp (evidence) Alternative evidence search
HeyGen video-production, veritas-video AI video avatar rendering
ElevenLabs audio-production, veritas-audio English text-to-speech
Stripe payments, veritas-api Card payments and subscriptions
Mobile money payments, veritas-api MTN MoMo, Vodafone Cash, AirtelTigo Money
Firebase (FCM) notifications Push notifications
Social platforms social-automation, veritas-social YouTube, TikTok, Meta, Telegram, etc.

Grounding: apps/veritas/nlp/src/config.ts; route files under apps/veritas/api/src/interfaces/http/routes/v1/; library directory names.


17. Configuration Reference#

The table below lists the environment variables required by the main Veritas services. Variables not listed here (e.g., social platform API keys, HeyGen credentials) follow the same pattern: read from environment, no defaults in source code.

Variable Consumed by Purpose
VERITAS_DATABASE_URL database, api, ingestion PostgreSQL connection string
PORT api, video, social HTTP port (api default 3002)
NLP_PORT nlp NLP service port (default 3002)
HUGGINGFACE_API_KEY nlp HuggingFace inference
ANTHROPIC_API_KEY nlp, agents, ai-workers Claude API access
OPENAI_API_KEY nlp, agents OpenAI access
COHERE_API_KEY nlp Cohere embeddings
SERPER_API_KEY nlp Serper evidence search
BRAVE_API_KEY nlp Brave evidence search
GHANA_NLP_API_KEY nlp Ghana NLP / Khaya API
KHAYA_API_KEY nlp Khaya API (alternate key)

Grounding: apps/veritas/api/src/main.ts; apps/veritas/nlp/src/config.ts.


18. Acceptance Criteria#

The acceptance criteria below define the minimum observable behaviors that confirm a Veritas deployment is correctly wired. They can be used as a post-deployment smoke test checklist and as the reference for what a CI integration test suite should verify.

A deployment of the Veritas domain is correct when:

  1. Type integrity@veritas/core exports the documented branded primitives, entities, enums, and error classes; @veritas/models Zod schemas validate them.
  2. API surfaceveritas-api mounts all v1 route groups under /api/v1, serves OpenAPI at /openapi.json and Swagger UI at /docs, and applies the middleware chain (timing, security headers, rate limiting, sandbox detection, API-key auth) in order.
  3. NLP serviceveritas-nlp exposes the documented analysis endpoints and reports readiness via /ready.
  4. Ingestionveritas-ingestion runs in scheduler, producer, worker, and seed modes; seed upserts the 33 Tier-1 and government Ghana sources.
  5. AI workers — the 24 workers across the four registries are discoverable via listWorkers and getWorker.
  6. Persistence — the Prisma schema migrates against PostgreSQL with the pgvector and citext extensions.
  7. Events@veritas/events publishes and subscribes the 41 veritas.* event types via @oshun/event-bus.
  8. Agentsveritas-agents registers the 7-agent roster with the documented priorities and exposes the /v1/* orchestration API.
  9. CMSveritas-cms enforces the 6-articles-per-30-minutes rate limit and the 22:00–06:00 Africa/Accra quiet hours.

Grounding Statement#

Every entity, field, enum value, endpoint, event, and count in this document was read directly from source in libs/veritas/* and apps/veritas/* — principally libs/veritas/core/src/, libs/veritas/events/src/types.ts, libs/veritas/database/prisma/schema.prisma, and the route, worker, seed, agent, and config files cited under each section's grounding note. No counts, schemas, or integrations were inferred. Where the codebase and an earlier draft of these docs disagreed (source counts, the API route prefix, the language-tag set, the worker roster), the code was treated as authoritative.