Skip to main content

Dev setup

Get a working Ratiba instance on your laptop. Target: ~10 minutes from clean clone to a green admin login screen at http://localhost:3010.

The stack runs four containerised services (Postgres, Redis, Keycloak, LiveKit), one FastAPI backend on :8010, and one Next.js frontend on :3010. All ports are pinned — nothing collides with the sister projects (zol-rag, trust-relay-workflow) on the same machine. See Configuration reference for the full port table.


Prerequisites

ToolVersionNotes
Python3.13+The project pins 3.13 — pyenv shims that resolve to 3.12 will break the test suite. See the pyenv troubleshooting note below.
Node.js20+npm 10+ comes with Node 20.
Docker Desktop4.30+Compose v2 required (docker compose ps --format json shape is v2-specific; docker-compose v1 CLI is not supported).
pyenvanyOptional but recommended. pyenv install 3.13.3 then pyenv local 3.13.3 inside the repo root.
pip24+Bundled with Python 3.13.

Stack topology

Only the compose services are required to boot. The five external APIs need real credentials only when you exercise those features — the rest of the system starts and serves admin UI without them.


Step 1 — Clone

git clone https://github.com/soft4u/ratiba.git
cd ratiba

All subsequent commands assume your working directory is the repo root.

Step 2 — Environment file

Ratiba reads secrets and tunables from .env at the repo root. The minimal block needed to boot and access the admin UI is:

# --- Required at boot ---
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
ADMIN_API_KEY=dev-admin-key

# --- Database (matches docker-compose defaults) ---
DATABASE_URL=postgresql+asyncpg://ratiba:ratiba_dev_password@localhost:5434/ratiba
REDIS_URL=redis://:ratiba_redis_password@localhost:6381/0

# --- Keycloak ---
KEYCLOAK_BASE_URL=http://localhost:8281
KEYCLOAK_ADMIN_REALM_USER=admin
KEYCLOAK_ADMIN_REALM_PASSWORD=keycloak_dev

# --- LiveKit (dev defaults — rotate before production) ---
LIVEKIT_URL=ws://localhost:7890
LIVEKIT_API_KEY=devkey
LIVEKIT_API_SECRET=devsecretmin32charslong0123456789

The remaining variables (WhatsApp WHATSAPP_APP_SECRET, Africa's Talking AFRICASTALKING_SMS_API_KEY, Daraja credentials, ElevenLabs, Deepgram) are only needed when testing those specific channels. The pre-flight script scripts/pilot-preflight.sh will warn about any that are unset.

For the full variable reference — every var, its default, whether it is required at boot, and which subsystem owns it — see Configuration reference.

Step 3 — Boot dependencies

docker compose up -d

Four services come up:

ServiceContainerHost portHealthcheck
postgresratiba-postgres5434pg_isready — waits for accepting connections
redisratiba-redis6381redis-cli PING
keycloakratiba-keycloak8281/health/ready HTTP probe
livekitratiba-livekit7890 (signal), 7891 (TCP RTC), 52000-52050 (UDP RTC)None — shows running

Wait until Postgres, Redis, and Keycloak all read (healthy):

docker compose ps

Typical cold-start times: Postgres ~5s, Redis ~2s, Keycloak ~20-30s. LiveKit has no healthcheck; it is ready when running appears.

Step 4 — Backend

cd backend
python -m venv .venv
.venv/bin/python -m pip install -e ".[dev]"
.venv/bin/alembic upgrade head

Notes:

  • The [dev] extras bring in pytest, pytest-asyncio, pytest-xdist, pyright, and all test-only fixtures (testcontainers, DeepEval, etc.).
  • alembic upgrade head migrates both the public shared schema (tenant registry, payment_callbacks_unrouted) and any existing tenant_* schemas. On a fresh database it only touches public.
  • Always run subsequent pytest invocations through .venv/bin/python -m pytest — see pyenv and Python 3.13 below and the detailed guide at Testing.

Step 5 — Frontend

cd ../frontend
npm install

Next.js 14 App Router + Tailwind v4 + shadcn/ui. First install pulls ~600 MB of node_modules; subsequent installs are cache-hot and finish in under 30s.

Step 6 — Start services

Open two terminal tabs from the repo root:

# Terminal A — backend (FastAPI + worker)
./start-server.sh
# Terminal B — frontend
./start-client.sh

Both scripts auto-kill any stale process on their port (8010, 3010) before starting, so re-running them is always safe.

Step 7 — Verify

Run the pre-flight as a sanity check before doing real work:

./scripts/pilot-preflight.sh

It validates required env vars, every docker container's health, and GET http://localhost:8010/healthz. Green output = you are clear to proceed.

Open http://localhost:3010 — you should land on the Ratiba admin login screen (NextAuth → Keycloak redirect).

Backend health check from the CLI:

curl http://localhost:8010/healthz
# {"status":"ok"}

Troubleshooting

Container shows (unhealthy)

Run docker compose logs <service> to see the boot error. The two most common causes:

  1. Port conflict — a pre-existing process is squatting the host port. Run lsof -i :<port> to find the process, then kill it or change the port mapping in docker-compose.yml. Remember all three Soft4U projects can run simultaneously because their ports are non-overlapping — only a non-project process should ever conflict.

  2. Keycloak slow to start — Keycloak's /health/ready probe can take 30-45s on slow disks or after a Docker Desktop restart. If Keycloak shows (starting) for longer than a minute: docker compose restart keycloak.

pyenv and Python 3.13

The project pins Python 3.13 via pyproject.toml requires-python = ">=3.13". macOS pyenv shims default to whatever pyenv global reports — often 3.12. Running python -m pytest through the wrong interpreter produces confusing errors (ModuleNotFoundError, SyntaxError on 3.13-only syntax, or keycloak-admin import failures).

Fix: always invoke pytest through the explicit venv path:

# This is the canonical invocation — use it every time
/Users/soft4u/Development/ratiba/backend/.venv/bin/python -m pytest

Or set pyenv local to 3.13 inside the repo:

# In the repo root
pyenv install 3.13.3 # if not already installed
pyenv local 3.13.3

For full pytest guidance — xdist cap, testcontainers per worker, the seeded_tenant fixture, the DeepEval eval gate — see Testing.

alembic upgrade head fails

Almost always a DATABASE_URL mismatch. The host port is 5434 (not 5432 which is the in-container port). Verify Postgres reports (healthy) in docker compose ps before running Alembic.

./start-server.sh exits immediately with ImportError

You are hitting a pyenv shim — see pyenv and Python 3.13 above. Activate the venv explicitly: source backend/.venv/bin/activate then re-run, or use the full path: backend/.venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8010 --reload.

Frontend boots but http://localhost:3010 returns 404

Next.js compiles routes lazily on the first request; initial hit can take 5-15s on a cold cache. If still 404 after 30s, check the start-client.sh terminal for the actual compile error.

Pre-flight is green but /healthz returns 500

The backend booted but database migrations are stale. Run cd backend && .venv/bin/alembic upgrade head and restart the server.

Docker healthcheck timings

The three healthchecked services use these probe settings (defined in docker-compose.yml):

ServiceProbe commandIntervalRetries
postgrespg_isready -U ratiba5s5
redisredis-cli -a ratiba_redis_password ping5s5
keycloakcurl -sf http://localhost:8281/health/ready10s12

Keycloak allows up to 120s of start-up time (12 retries × 10s interval). If it transitions directly to (unhealthy) before reaching that count, the JVM ran out of memory — increase Docker Desktop's memory allocation to at least 4 GB.


What next

  • Seed test data — populate a freshly-booted tenant with knowledge snippets and sample catalog entries so the agent has something to offer.
  • Onboard a tenant — provision your first tenant (Postgres schema + Keycloak realm + catalog) before any booking will work.
  • First booking — walk a haircut through WhatsApp end-to-end including STK push.
  • Architecture overview — the bigger picture behind the stack.