Skip to content

Repository files navigation

Nexus Core

License: MIT Go Version

Headless WhatsApp backend for Nexus. Owns WhatsApp connectivity via whatsmeow, persists sessions, API keys, webhooks, and jobs in Postgres, and exposes an auth-unaware REST API over Redis streams. See docs/prd/prd-nexus-core.md in the parent workspace for product requirements.

Architecture

Hexagonal (entity <- ports <- service <- adapters), cmd/ is the composition root:

cmd/
  http/             REST API composition root (Fiber + oapi-codegen contracts)
  worker/           Redis two-queue worker — router + executor (selected via WORKER_ROLE)
internal/
  core/entity/      domain types: Session, APIKey, WebhookConfig, Job, QRCode
  core/ports/       repository + service interfaces owned by the core
  service/          business logic (use cases), depends only on ports
  adapters/
    postgresql/     pgx repositories with own dto/ + mappers
    redis/          Streams producer + ingress/provider consumers
    whatsmeow/      DeviceManager, QR handling, send/receive
    webhook/        outbound webhook forwarder
    crypto/         AES-256-GCM cipher + API key secret generator
  handlers/http/    Fiber handlers, thin with own dto/ + mappers
  config/           env + ~/.nexus/config.yaml loader (YAML takes precedence)
  contracts/        generated Fiber server from OpenAPI (api.gen.go)
migrations/         golang-migrate SQL files

Dependencies point inward; every dependency crosses the boundary through a port interface. No authentication code exists by design.

Runtime roles

Binary Role Notes
http REST API All PRD endpoints under /api/v1 (Fiber), no auth
worker Router + Executor Redis Streams two-queue pipeline, role selected via WORKER_ROLE

WORKER_ROLE controls which queues the worker drains:

Value Behavior
all Runs both router and executor (default, suitable for local dev)
router Drains nexus:queue:ingress (router group) and fans out to nexus:queue:provider:*
executor Drains nexus:queue:provider:* (executor group) and executes via whatsmeow

Executor is a singleton. Leadership is acquired via SETNX nexus:leader:executor with a 30s TTL and 10s renewal; a second executor replica fails fast. Within the leader pod, WORKER_EXECUTOR_WORKERS is kept at 1 to preserve per-number ordering for WhatsApp. The executor also runs a heartbeat loop (QUEUE_HEARTBEAT_INTERVAL_MS) that touches sessions.last_seen_at for connected clients and an inbound_listener that forwards incoming WhatsApp messages to the configured webhooks.

Quick start

cp .env.example .env
# Generate an encryption key for API key secrets
openssl rand -base64 32   # -> API_KEY_ENCRYPTION_KEY

docker compose up -d postgres redis
make migrate-up
make run-http     # or: make build && ./bin/http
make run-worker   # or: ./bin/worker  (WORKER_ROLE=all by default)

Health check:

curl http://localhost:8080/health

Environment

Configuration is loaded from ~/.nexus/config.yaml (or $NEXUS_CONFIG_PATH) with env vars as fallback. YAML takes precedence when both are present. A single cp .env.example .env covers both binaries — http reads PORT and worker reads WORKER_ROLE from the same file. nexus-core/.env.worker is supported for per-process overrides (e.g., docker run --env-file .env.worker) but is gitignored and optional; config.example.yaml at the workspace root shows the canonical YAML shape.

Key variables:

Variable Description Default
DB_DSN Postgres DSN (source of truth) postgres://nexus:nexus@localhost:5432/nexus_core?sslmode=disable
REDIS_ADDR Redis address for Streams localhost:6379
API_KEY_ENCRYPTION_KEY 32-byte base64 key for AES-256-GCM (required)
API_KEY_ENCRYPTION_KEY_PREVIOUS Previous key for rotation
WHATSMEOW_STORE_DSN WhatsApp device store DSN (separate DB, falls back to DB_DSN) postgres://nexus:nexus@localhost:5432/nexus_whatsmeow?sslmode=disable
WORKER_ROLE Worker role: all | router | executor all

Additional tuning: REDIS_INGRESS_STREAM, REDIS_PROVIDER_PREFIX, REDIS_BLOCK_MS, QUEUE_MAX_ATTEMPTS, QUEUE_SEND_TIMEOUT_MS, QUEUE_HEARTBEAT_TTL_MS, QUEUE_HEARTBEAT_INTERVAL_MS, WORKER_ROUTER_WORKERS, WORKER_EXECUTOR_WORKERS, WORKER_INGRESS_COUNT, WORKER_PROVIDER_COUNT. See .env.example and internal/config/config.go for the full list.

Development

make build          # CGO_ENABLED=0 binaries -> bin/http, bin/worker
make test           # go test ./...
make vet            # go vet ./...
make fmt            # gofmt -w .
make migrate-up     # migrate -path migrations -database $DB_DSN up
make migrate-down   # migrate down 1
make docker-build   # docker build -t nexus-core .

Contracts are defined in ../nexus-contract/nexus-core.yaml (workspace root nexus-contract/). Generated Fiber server types live in internal/contracts/api.gen.go — do not edit by hand. Regenerate from the contract repo:

# from nexus-contract/
npm run contracts:gen
# or
go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest -config oapi-codegen.yaml nexus-core.yaml

License

MIT — see LICENSE.

Copyright (c) 2026 afikrim.

About

Headless WhatsApp backend — whatsmeow + Postgres/Redis, hexagonal Go, auth-unaware Core API

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages