# Kenya Eats — Backend
FastAPI backend for a multi-vendor food delivery platform, hardened
for production use: real payment reconciliation, an explicit order
state machine, RBAC enforced server-side, and a financial ledger that
doesn't rely on floating-point arithmetic.
## Quick start (development)
```bash
cd backend
python3 -m venv venv && source venv/bin/activate
pip install -r requirements-dev.txt # includes requirements.txt + test tooling
cp .env.example .env # defaults are safe for local dev as-is
alembic upgrade head # create schema via migrations
python -m app.seed # ~100 demo hotels across 10 towns (dev/test only)
uvicorn app.main:app --reload --port 8000
```
Docs at `
localhost` (disabled automatically when `ENV=production`).
Demo accounts (seed script, refuses to run when `ENV=production`):
| Role | Email | Password |
|---|---|---|
| Admin | admin@kenyaeats.co.ke | admin123 |
| Customer | customer@kenyaeats.co.ke | customer123 |
| Vendor | vendor0@kenyaeats.co.ke (also vendor1, vendor2, ...) | vendor123 |
## Architecture
```
app/
config.py Centralized, validated settings. Production
FAILS FAST on missing/weak secrets, missing
CORS origins, missing M-Pesa creds.
database.py SQLAlchemy engine/session; explicit rollback
on exception (not just implicit close-rollback).
models.py ORM models. Money is Numeric(12,2) + Decimal
everywhere, never float. See PaymentTransaction,
LedgerEntry, OrderStatusHistory, RefreshToken,
AuditLog for the financial/audit layer.
money.py Decimal rounding helper (ROUND_HALF_UP, 2dp).
order_state_machine.py Single source of truth for legal order status
transitions and which role may perform each.
auth.py Short-lived JWT access tokens + revocable,
rotating refresh tokens. Login lockout.
mpesa.py Daraja STK Push integration. Strict Kenyan
phone validation. Mock mode only ou …