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
| Tool | Version | Notes |
|---|---|---|
| Python | 3.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.js | 20+ | npm 10+ comes with Node 20. |
| Docker Desktop | 4.30+ | Compose v2 required (docker compose ps --format json shape is v2-specific; docker-compose v1 CLI is not supported). |
| pyenv | any | Optional but recommended. pyenv install 3.13.3 then pyenv local 3.13.3 inside the repo root. |
| pip | 24+ | 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:
| Service | Container | Host port | Healthcheck |
|---|---|---|---|
| postgres | ratiba-postgres | 5434 | pg_isready — waits for accepting connections |
| redis | ratiba-redis | 6381 | redis-cli PING |
| keycloak | ratiba-keycloak | 8281 | /health/ready HTTP probe |
| livekit | ratiba-livekit | 7890 (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 inpytest,pytest-asyncio,pytest-xdist,pyright, and all test-only fixtures (testcontainers, DeepEval, etc.). alembic upgrade headmigrates both thepublicshared schema (tenant registry,payment_callbacks_unrouted) and any existingtenant_*schemas. On a fresh database it only touchespublic.- 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:
-
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 indocker-compose.yml. Remember all three Soft4U projects can run simultaneously because their ports are non-overlapping — only a non-project process should ever conflict. -
Keycloak slow to start — Keycloak's
/health/readyprobe 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):
| Service | Probe command | Interval | Retries |
|---|---|---|---|
| postgres | pg_isready -U ratiba | 5s | 5 |
| redis | redis-cli -a ratiba_redis_password ping | 5s | 5 |
| keycloak | curl -sf http://localhost:8281/health/ready | 10s | 12 |
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.