Single-project Next.js application that serves both:
- Web frontend (App Router)
- API endpoints (
/healthz,/readyz,/v1/...)
Backend domain/DB/ingestion code remains in src/ and is reused by Next route handlers.
- Node 22 runtime
- npm package manager
- TypeScript + Next.js 16 (App Router)
- PostgreSQL + Drizzle ORM/migrations
- Cron-driven ingestion pipelines
- Install dependencies:
npm install- Copy env file and adjust values as needed:
cp .env.example .envCORS_ORIGINcontrols API CORS allowlist (*for open, or comma-separated origins).PREDICTION_API_URLis optional; defaults tohttp://127.0.0.1:${PORT}(or3000).
- Create DB, run migrations, seed providers:
npm run db:prepareLocal dev (web + API in one process):
npm run devProduction web service:
npm run build
npm run startCron pipelines:
npm run cron:topn-live
npm run cron:full-catalog
npm run cron:full-catalog:resumeRecommended Coolify cron entries:
*/5 * * * * npm run cron:topn-live
*/15 * * * * npm run cron:full-catalog:resumecron:full-catalog remains available as a monolithic/manual run. For environments with strict timeout caps, prefer cron:full-catalog:resume.
Manual ingestion (direct execution, no queue):
npm run ingest:metadata
npm run ingest:metadata:backfill
npm run ingest:prices
npm run ingest:orderbook
npm run ingest:trades
npm run ingest:oi
npm run ingest:kalshi:metadata
npm run ingest:kalshi:prices
npm run ingest:kalshi:orderbook
npm run ingest:kalshi:trades
npm run ingest:kalshi:oi
npm run ingest:categories
npm run ingest:categories:backfill
npm run ingest:rollups
npm run ingest:allVerification and tests:
npm run verify:summary
npm run verify:summary:strict
npm run typecheck
npm testRun as a single web service:
- Build command:
npm ci && npm run build - Start command:
npm run start - Port:
3000 - Health check path:
/healthz
Use separate Coolify cron jobs from this same repository for ingestion:
npm run cron:topn-livenpm run cron:full-catalog:resume
topN_live:core.market_scope-based prioritized ingestion, designed for 5-minute cadence with seed top-N event-expanded scope selection.full_catalog: active-market full-universe ingestion using batched selectors fromcore.market/core.instrument, designed for low-frequency cadence.full_catalog_resume: full-catalog state machine that checkpoints provider/step progress (ops.ingest_checkpoint) and resumes from the latest step on the next invocation.
GET /healthzGET /readyzGET /v1/meta/providersGET /v1/meta/coverageGET /v1/meta/ingest-healthGET /v1/meta/data-freshnessGET /v1/meta/category-qualityGET /v1/markets?provider=polymarket|kalshi&limit=&offset=GET /v1/markets/:marketUidGET /v1/events/:eventUidGET /v1/events/:eventUid/trades?limit=50GET /v1/events/:eventUid/price-history?from=&to=&interval=1hGET /v1/markets/:marketUid/price-history?from=&to=&interval=1hGET /v1/dashboard/main?provider=polymarket|kalshiGET /v1/dashboard/treemap?provider=polymarket|kalshi&coverage=all|scopeGET /v1/trades/top?window=24h|7d|30d&provider=polymarket|kalshi&limit=&offset=
- Public market IDs are
provider:marketRef. - Public event IDs are
provider:eventRef. - Canonical probability scale in storage is
0..1. ops.job_run_logis the canonical run history (step-level + cron skip outcomes).ops.ingest_checkpointstores incremental windows and full-catalog cursor state./v1/dashboard/mainreturns provider KPIs plus event-level rows with nested markets/instruments sourced fromcore.market_scope.