Skip to main content

Services Overview

GospeLib is composed of eight backend services, each owning a distinct domain. All external traffic enters through the Gateway — no other service is exposed directly to clients.

Service Catalog

ServicePortLanguageFrameworkResponsibility
Gateway8080GoChi v5API gateway — JWT validation, rate limiting, reverse proxy
Content8100Python 3.12FastAPIScripture graph queries (FalkorDB)
Auth8200GoChi v5Clerk wrapper, user sync, JWT middleware
Billing8300GoChi v5Stripe subscriptions, entitlements
AI8400Python 3.12FastAPILLM passage explanation, study questions
Notifications8500GoChi v5Push (APNs/FCM), email (Resend), Redis Streams
Plugin Registry8500Python 3.12FastAPIPlugin manifest registry, discovery, versioning
IngestPython 3.12Click CLI14-stage data pipeline (corpus → FalkorDB)
info

The Ingest service is a CLI tool, not an HTTP service — it has no port.

Request Flow

Browser / Mobile App


Gateway (:8080)
├── JWT validation
├── Rate limiting
├── Entitlement check
└── Reverse proxy ──► Content (:8100)
──► Auth (:8200)
──► Billing (:8300)
──► AI (:8400)
──► Notifications (:8500)

All inter-service communication uses direct HTTP. The gateway injects X-Request-ID and X-User-Id headers into every proxied request.

Middleware Stack

Every request through the gateway passes through an ordered middleware chain:

RequestID → RealIP → OpenTelemetry → Logger → Recoverer → CORS → RateLimiter
└── Auth group: ValidateJWT → InjectUserClaims → Entitlement

See Gateway > Middleware Stack for details.

Dependency Rules

  • Apps (web, admin, mobile) import all @gospelib/* packages
  • @gospelib/sdk imports only @gospelib/types
  • Services never import TypeScript packages at runtime — they are standalone processes

Response Envelope

All services follow a shared response envelope format:

// Success
{ "data": T, "meta": { "next_cursor": "...", "total": 42 } }

// Error
{ "error": { "code": "PASSAGE_NOT_FOUND", "message": "...", "request_id": "..." } }

Pagination is cursor-based via next_cursor in meta.

Async Communication

Services communicate asynchronously via Redis Streams with consumer groups:

StreamProducerConsumer
gl:events:notificationsAny serviceNotifications
gl:events:usersAuthBilling, Notifications
gl:events:ingestIngestContent

Service Directory Structures

Go Services (Gateway, Auth, Billing, Notifications)

services/<name>/
├── cmd/server/main.go # Entry point
├── internal/
│ ├── config/config.go # Env-var config with defaults
│ ├── handler/<resource>.go # HTTP handlers (+ _test.go)
│ ├── middleware/ # HTTP middleware
│ ├── service/<resource>.go # Business logic
│ ├── repository/<resource>.go # Data access
│ └── model/<resource>.go # Domain types
├── api/openapi.yaml
├── go.mod / go.sum
└── Dockerfile

Python Services (Content, AI)

services/<name>/src/gospelib_<name>/
├── __init__.py
├── main.py # create_app() → FastAPI
├── config.py # pydantic-settings BaseSettings
├── routes/ # APIRouter per resource
├── models/ # Pydantic models
├── services/ # Business logic
├── db/ # Database clients
└── utils/