Fact Engine API Resource Gaps
Audit of missing, stubbed, and planned API resources across the fact engine pipeline. Conducted 2026-03-23 by cross-referencing existing routes, DB schema (19 tables), draft plans, and APP-CONTROL.md.
Current Coverage Summary
These resources have complete API routes in apps/web/app/api/:
| Resource | Endpoints | Notes |
|---|---|---|
| Feed / Discovery | GET /api/feed, GET /api/review | Blended ranking (recent/review/evergreen/random) |
| Card Detail | GET /api/cards/[slug] | Subscription-gated |
| Card Interactions | POST /api/cards/[slug]/interact | View, answer, bookmark, share; SRS scheduling |
| Challenge Groups | GET/POST /api/cards/[slug]/group-progress | 5-position sequential challenges |
| Score Disputes | POST /api/cards/[slug]/dispute | 10/month limit, AI adjudication |
| Entity Facts/Links | GET /api/entities/[id]/facts, /links, /paths/[b] | Entity graph traversal |
| Rewards | GET /api/user/rewards | Milestones and claims |
| Cron Dispatchers | 6 active cron routes | ingest-news, generate-evergreen, validation-retry, archive-content, topic-quotas, import-facts (stub) |
Gap 1: Admin API (Zero Fact Engine Coverage)
apps/admin/app/api/ has no fact engine endpoints. The admin dashboard currently relies on direct Supabase queries or server components with no REST API layer.
Missing Admin Endpoints
| Endpoint | Table(s) | Purpose | Priority |
|---|---|---|---|
GET /api/ingestion/runs | ingestion_runs | List recent runs with status, counts, errors | High |
GET /api/ingestion/runs/[id] | ingestion_runs | Run detail with metadata JSONB | High |
GET /api/facts | fact_records | Paginated list with filters (status, topic, date) | High |
GET /api/facts/[id] | fact_records | Full fact detail with validation JSONB | High |
PATCH /api/facts/[id] | fact_records | Edit title, notability, image, challenge fields | High |
POST /api/facts/[id]/reject | fact_records | Reject with reason (sets status=rejected) | High |
POST /api/facts/[id]/revalidate | fact_records | Re-enqueue for validation | Medium |
GET /api/topics | topic_categories | Full tree with quotas, active status | Medium |
GET /api/topics/tree | topic_categories | Hierarchical view (depth 0-3) | Medium |
PATCH /api/topics/[id] | topic_categories | Update quota, active status, icon, color | Medium |
GET /api/schemas | fact_record_schemas | List schemas with fact_keys | Medium |
PATCH /api/schemas/[id] | fact_record_schemas | Update fact_keys, card_formats | Medium |
GET /api/seeds | seed_entry_queue | Paginated seed queue with status filters | Medium |
POST /api/seeds/[id]/retry | seed_entry_queue | Reset failed seed to pending | Medium |
GET /api/ops-log | content_operations_log | Audit trail of admin operations | Low |
GET /api/unmapped-categories | unmapped_category_log | Triage unmapped provider categories | Low |
GET /api/queues/status | Upstash API | Queue depth, message counts per queue | Low |
GET /api/topics/aliases | topic_category_aliases | View external slug mappings by provider | Low |
Existing DB Query Functions (Ready to Wire)
These functions in packages/db/src/drizzle/fact-engine-queries.ts already exist and can back admin endpoints:
getActiveTopicCategories(),getTopicCategoryById(),getTopicCategoryBySlug()getRecentIngestionRunsByType(),getNewsProviderHealth()insertFactRecord(),updateFactRecordStatus(),updateFactRecordImage()getFactRecordById(),getFactRecordSchemaById()getStuckPendingValidations(),getTopicFactCountToday()
Gap 2: Web App Read APIs Missing
These resources have DB queries but no consumer-facing route:
| Endpoint | DB Function | Purpose | Priority |
|---|---|---|---|
GET /api/bookmarks | getUserBookmarks() | List user's saved facts | High |
DELETE /api/bookmarks/[factId] | removeBookmark() | Unsave a fact | High |
GET /api/topics | getActiveTopicCategories() | Browse-by-topic navigation | Medium |
GET /api/stats | getUserCumulativeScore() | Profile stats (score, streaks, mastered count) | Medium |
GET /api/search | (not implemented) | Full-text fact search | Low |
Note: Bookmark add/remove currently happens via /api/cards/[slug]/interact with interactionType: "bookmark", but there's no dedicated list endpoint.
Gap 3: Evidence Pipeline Clients (8 Planned, 0 Built)
All defined in draft plans under docs/plans/. Integration point: packages/ai/src/validation/evidence.ts (currently only Wikipedia, Wikidata, Alpha Vantage).
Tier 1 — High Priority (Core Domain Coverage)
| Client | Plan File | Target File | Domain | Key Methods |
|---|---|---|---|---|
| FRED | financial-evidence-expansion.md | packages/ai/src/fred-client.ts | US macro (GDP, CPI, unemployment) | searchSeries(), getObservations(), getGDP(), getCPI() |
| World Bank | financial-evidence-expansion.md | packages/ai/src/worldbank-client.ts | Global dev (200+ countries, 16K+ indicators) | getIndicator(), getCountryGDP(), getCountryPopulation() |
| API-Sports | api-sports-evidence-integration.md | packages/ai/src/api-sports-client.ts | Match results, player stats | getFixtures(), getPlayerStats(), getStandings() |
Tier 2 — Medium Priority (Science & Academic)
| Client | Plan File | Target File | Domain | Key Methods |
|---|---|---|---|---|
| OpenAlex | openalex-evidence-enrichment.md | packages/ai/src/openalex-client.ts | Scholarly works (286M+ records) | searchAuthor(), getAuthorWorks(), searchWork() |
| Nobel Prize | openalex-evidence-enrichment.md | packages/ai/src/nobelprize-client.ts | Laureate data | searchLaureate(), searchPrize() |
| NASA | openalex-evidence-enrichment.md | packages/ai/src/nasa-client.ts | Space/astronomy | getExoplanetCount(), getRoverInfo(), getAsteroidApproach() |
Tier 3 — Low Priority (Fallback & Backup)
| Client | Plan File | Target File | Domain |
|---|---|---|---|
| Finnhub | financial-evidence-expansion.md | packages/ai/src/finnhub-client.ts | ESG, congressional trading, patents |
| FMP | financial-evidence-expansion.md | packages/ai/src/fmp-client.ts | Company fundamentals (Alpha Vantage backup) |
Additional Planned (No Client Spec Yet)
| API | Plan File | Status |
|---|---|---|
| DBpedia | dbpedia-evidence-enrichment.md | Draft plan, no client spec |
| Wikimedia Enterprise | wikimedia-enterprise-evidence.md | Draft plan, no client spec |
Evidence Wiring Checklist (Per Client)
Each client requires:
- Client class in
packages/ai/src/ - Config getter in
packages/config/src/index.ts(API key env var) - Evidence strategy registration in
packages/ai/src/validation/evidence.ts - Topic-to-strategy mapping (which topics use which APIs)
- Unit tests in
packages/ai/src/__tests__/ - Env var added to
.env.exampleand Vercel project
Config Gaps
These env vars may be in .env.local but need verification in packages/config/:
FRED_API_KEY— Verify config getter existsFINNHUB_API_KEY— Verify config getter existsFMP_API_KEY— Verify config getter existsAPI_SPORTS_API_KEY— Confirmed in env.local, verify config getterOPENALEX_API_KEY— Optional (open API), not yet added- World Bank, Nobel Prize, NASA — Open APIs, no key needed
Gap 4: Challenge Conversation API (Planned, Not Built)
Defined in APP-CONTROL.md but no route files exist:
| Endpoint | Method | Purpose | Rate Limit |
|---|---|---|---|
/api/challenge-sessions | POST | Start conversational challenge session | 5 sessions/user/day |
/api/challenge-sessions/[id]/turn | POST | Process conversational turn | 2000 char max input |
/api/challenge-sessions/[id]/end | POST | End session early, calculate final score | — |
Blocked on: Conversational challenge UI design and implementation.
Gap 5: Stub & Deprecated Routes
| Route | Status | Action |
|---|---|---|
/api/cron/import-facts | Stub — returns no-op | Wire to evidence clients when Tier 1 clients are built |
/api/cron/daily-digest | Deprecated — v1 tables removed (migration 0118) | Delete route + remove from vercel.json |
/api/webhooks/twilio | Deprecated — SMS tables dropped | Delete route |
Gap 6: Operational Observability
No API surface for runtime pipeline health:
| Need | Current State | Suggested Endpoint |
|---|---|---|
| Queue depth per queue type | Only visible in Upstash dashboard | GET /api/admin/queues/status |
| Provider health (success rates) | getNewsProviderHealth() exists, no route | GET /api/admin/providers/health |
| Daily fact production vs quota | getTopicFactCountToday() exists, no route | GET /api/admin/quotas/status |
| Validation pass/fail rates | Computed ad-hoc from fact_records | GET /api/admin/validation/stats |
| Cost tracking (AI spend) | Stored in generation_cost_usd per record | GET /api/admin/costs/summary |
Implementation Priority
Wave 1 — Operational Visibility (Admin)
Unblocks day-to-day pipeline management:
- Ingestion runs list/detail endpoints
- Fact list with status/topic filters + reject/revalidate actions
- Queue depth endpoint (Upstash API proxy)
- Provider health endpoint
Wave 2 — Consumer UX (Web)
Low effort, high value for existing features:
- Bookmarks list endpoint
- Topics browse endpoint
- User stats endpoint
Wave 3 — Evidence Pipeline
Build clients in priority order, wire to validation:
- FRED + World Bank (economics/global)
- API-Sports (sports verification)
- OpenAlex + Nobel Prize + NASA (science/academic)
Wave 4 — Cleanup
- Delete deprecated routes (daily-digest, twilio webhook)
- Wire import-facts cron to new evidence clients
- Add challenge conversation endpoints (when UI is ready)
Related Documents
docs/APP-CONTROL.md— Operational manifest with cron schedules and API specsdocs/eko-product-bible.md— Product overview and architecturedocs/plans/financial-evidence-expansion.md— FRED, Finnhub, FMP, World Bank client specsdocs/plans/api-sports-evidence-integration.md— Sports API client specdocs/plans/openalex-evidence-enrichment.md— OpenAlex, Nobel Prize, NASA client specsdocs/plans/dbpedia-evidence-enrichment.md— DBpedia fallback plandocs/plans/wikimedia-enterprise-evidence.md— Wikimedia Enterprise plandocs/plans/alphavantage-evidence-enrichment.md— Existing Alpha Vantage integration