Architecture & Codebase Overview
Welcome to the Roja developer documentation. Roja is a Nigerian peer-to-peer (P2P) lending fintech platform connecting borrowers and lenders through structured tickets (loan requests and offers), backed by multi-tier KYC verification, direct-debit repayment mandates, automated collections/dunning, credit scoring (the Roja Score), and optional credit insurance.
All platform interfaces—mobile, customer web, staff back-office, and developer portals—are powered by the unified Go backend API documented across this knowledge base.
System Topology
Roja is architected as an OpenAPI-first, container-free in local dev, GitOps-deployed in production system.
┌─────────────────────────────────────────────────────────────────────────────┐
│ CLIENT SURFACES │
│ │
│ Mobile App Customer Web App Staff Dashboard │
│ (Expo / React Native) (Next.js App Router / R19) (Next.js Pages) │
└──────────┬────────────────────────┬────────────────────────────┬────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ SHARED CLIENT LAYER │
│ │
│ @roja/client ─── Generated OpenAPI TypeScript SDK (Strictly Typed) │
│ @roja/common ─── Axios client factory, CSRF, Token Refresh, React Query │
└─────────────────────────────────────┬───────────────────────────────────────┘
│ HTTPS / JSON API (/v1/...)
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ BACKEND API │
│ │
│ Go 1.27 + net/http + oapi-codegen (Strict-Server Interface) │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ CORE DOMAIN SERVICES │ │
│ │ • tickets • directpay • collections • score (Markov) │ │
│ │ • kyc • banking • wallet • insurance │ │
│ │ • support • superlender • staff • featureflags │ │
│ └──────────────────────────────────┬──────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────┴──────────────────────┐ │
│ ▼ ▼ │
│ PostgreSQL 18 (sqlc + pgx) Redis 8 │
│ • Double-Entry Audit Mirror • Asynq Queues │
│ • Transactional Outbox • Distributed Caching │
│ • Declarative Atlas Migrations • Session Keyspaces │
└──────────────────────────────────────┬──────────────────────────────────────┘
│
┌──────────────────────────┴──────────────────────────┐
▼ ▼
┌──────────────────────────────────────┐ ┌───────────────────────────────────┐
│ ASYNC WORKERS │ │ EXTERNAL RAILS │
│ │ │ │
│ • asynq-worker (Task Consumers) │ │ • Banking / Mandates: │
│ • asynq-scheduler (Periodic Cron) │ │ Mono, Monnify, Providus │
│ • asynq-monitor (Prometheus/API) │ │ • Identity / KYC: │
│ • agent-worker (Liquidity Bots) │ │ Dojah, QoreID, Monnify │
│ │ │ • Insurance: Curacel, MyCover │
└──────────────────────────────────────┘ └───────────────────────────────────┘
Monorepo Layout
The repository is managed as a Bun workspace monorepo (bun@1.3.14).
| Workspace / Directory | Tech Stack | Responsibility |
|---|---|---|
backend/ | Go 1.27, net/http, sqlc, pgx/v5, Asynq, Atlas | Core REST API, background workers, scheduled jobs, and platform liquidity bot agents. |
apps/web/ | Next.js (App Router), React 19, Tailwind CSS v4 | Customer-facing web application for loan requests, marketplace browsing, offers, and KYC. |
apps/staff/ | Next.js (Pages Router), React 19, Tailwind CSS v4 | Back-office dashboard for operations, risk reviews, manual disbursement approvals, and collections. |
apps/docs/ | Docusaurus 3, MDX, TypeScript | This documentation site (docs.roja.dev / docs.getroja.com), served via Cloudflare Workers. |
apps/files/ | Cloudflare Worker | Document attachment handler and media proxy. |
apps/cdn/ | Cloudflare Worker | Asset caching and static delivery rail. |
mobile/ | React Native, Expo SDK, expo-router, NativeWind | iOS and Android mobile app distributed via Google Play Store and Apple App Store. |
packages/common/ | TypeScript, @tanstack/react-query, Axios | Shared frontend runtime: auth interceptors, CSRF handling, date/money formatters, and custom hooks. |
packages/js-client/ | TypeScript (Auto-generated) | Type-safe API client generated directly from backend/spec/gen/openapi.yaml. |
tools/storybook-web/ | Storybook, Vite, Tailwind v4 | UI component preview for apps/web and apps/staff with Vitest smoke tests (storybook.roja.dev). |
tools/storybook-mobile/ | Storybook, React Native Web | UI component preview for mobile/ components (storybook-mobile.roja.dev). |
tools/duckdb/ | DuckDB, dbt, Python | Synthetic, scrubbed OLAP data mart for financial analytics without exposing real customer PII. |
devops/ | Nix, Cloudflare, Terraform, Ansible | Infrastructure configurations, Cloudflare tunnels, deployment pipelines, and Grafana dashboards. |
service-registry/ | Kubernetes, Flux GitOps, Kustomize | Kubernetes manifests and GitOps deployment configs for cluster environments. |
Technology Stack & Core Choices
Built on the Go standard library net/http router wrapped by oapi-codegen strict-server interfaces. Zero heavyweight web framework overhead; high concurrency and deterministic memory management.
Declarative SQL schema in backend/db/schema/ managed by Atlas. sqlc compiles type-safe Go structs and queries from plain SQL in backend/db/query/.
Distributed background task queue backed by Redis with priority queues, exponential retries, and transactional outbox event dispatching.
Customer web app built with React 19, React Compiler, and Tailwind CSS v4. Staff back-office runs Pages Router with role-based view gating.
Cross-platform mobile application with typed routing (expo-router), biometrics, passkeys, and NativeWind styling.
Container-free local development via Nix flakes; frontend static sites and OpenNext instances deployed as Cloudflare Workers.
The OpenAPI-First Contract
Roja operates strictly on an OpenAPI-first contract. The OpenAPI specification is the single authoritative source of truth for the entire platform.
The API specification is broken into modular YAML files under backend/spec/:
paths/— Every route definition, request method, parameters, and response links.schemas/— Domain entity schemas, input payloads, and error objects.parameters/— Reusable query, header, and path parameters.
Running task backend:generate (or make generate) compiles modular specs into a single bundled file at backend/spec/gen/openapi.yaml.
oapi-codegen generates:
- Go request/response structs.
- Strict server interfaces (
StrictServerInterface) inbackend/internal/apiserver/router.go. - RBAC permissions and user role mappings in
backend/spec/roles.gen.go.
scripts/generate-js-client.sh consumes the bundled YAML and emits a fully typed TypeScript client into packages/js-client/. All web, staff, and mobile components consume this client through @roja/common.
CI Contract Gate: Continuous integration validates that all generated Go and TypeScript files match the OpenAPI specification. If a pull request modifies an API route without running task generate and committing the output, CI fails.
Regulatory & Compliance Principles
Roja operates in the Nigerian financial technology ecosystem under the jurisdiction of the Federal Competition and Consumer Protection Commission (FCCPC) and the Central Bank of Nigeria (CBN).
FCCPC Compliance Guardrail: Customer personally identifiable information (PII)—including National Identification Numbers (NIN), Bank Verification Numbers (BVN), home addresses, bank account credentials, and phone numbers—must never leave developer machines in plaintext logs, test fixtures, terminal outputs, or AI prompts.
Key Compliance Rules:
- PII Encryption at Rest: BVN and NIN fields stored on customer records are encrypted using AES-256-GCM (
backend/internal/crypto) before database persistence. - Deterministic Pseudonymization in Fixtures: All analytics and development fixtures in
tools/duckdbuse synthetic, scrubbed test data. Real production dumps are prohibited in local environments. - Audit Trails & Evidence Durability: Financial operations require immutable audit evidence. Deleting financial transactions, settlement sagas, or outbox events before their retention window is prohibited by database foreign keys and trigger locks.
- App Store Lending Policy Compliance: Mobile app permissions on Android are strictly restricted to Camera and Microphone (for KYC verification). Requesting contacts, SMS, or precise location is banned to conform to Google Play's Personal Loans policy.
Money Discipline
Financial operations require absolute numerical accuracy. Floating-point math (float32, float64, or JavaScript number) is strictly forbidden across the codebase for monetary values.
- Wire Representation: All monetary figures cross network boundaries as exact decimal strings formatted to two decimal places (e.g.
{"amount": "50000.00", "currency": "NGN"}). - Backend Arithmetic: Handled exclusively using
shopspring/decimal. Direct arithmetic using floating-point types fails static checks (backend/scripts/decimal-containment-check.sh). - Database Storage: Stored as PostgreSQL
numeric(18,2)with check constraints prohibiting negative balances. - Frontend Formatting: Consumed only through
@roja/common/moneyutilities which perform string-based normalization and formatting without loss of precision.
Next Steps
Set up your machine with Nix flakes, run native services, and learn common dev tasks.
Financial Engine & LedgerUnderstand the double-entry audit mirror, chart of accounts, and reconciliation loops.
Domain Models & LifecyclesExplore the lifecycles of tickets, loans, KYC verification, scoring, and collections.
Frontends & MobileLearn how Next.js, Expo, @roja/common, and Storybook interact.