Backend API for [EduFurther](
edufurther.org) . A mentorship platform connecting African students pursuing international graduate school with mentors at institutions worldwide.
# EduFurther Backend
Backend API for EduFurther — a mentorship platform
connecting African students pursuing international graduate school with mentors
at institutions worldwide.
This service is replacing a Bubble low-code application. The frontend is a
separate Next.js app that consumes this API.
## Quickstart
```bash
uv sync --all-extras --dev # install
uv run pre-commit install # install the git hooks (pre-commit + commit-msg)
cp .env.example .env # local settings, including the database URL
docker compose up -d # PostgreSQL 17 on port 55432
uv run alembic upgrade head # apply the migration chain
make check # the full local gate — run before every commit
```
On Windows, where `make` is usually absent, run the gate directly:
```bash
uv run python scripts/check.py
```
Run the API:
```bash
uv run uvicorn app.main:app --reload --app-dir src
```
Then `GET
127.0.0.1` returns `{"status": "ok"}`, and the
generated OpenAPI schema is at `/docs`.
## Layout
```
src/app/api/ transport only — no business logic
src/app/domain/ the product — pure Python, no I/O, no framework
src/app/infra/ adapters — DB, cache, outbound clients
src/app/core/ configuration and the base error taxonomy
tests/{unit,integration,e2e}/
docs/adr/ decision records — read before proposing a rewrite
docs/edufurther-migration/ the target schema, field mapping and runbook —
received from the migration work, never edited here
migrations/ the Alembic chain — outside src/ so it is neither packaged
into the wheel nor scanned by the layer check
alembic.ini migration config; carries no database URL, by design
scripts/ the layer check, the local gate, and the reference-data
generator whose output is committed as a migration
```
`api/deps.py` and `main.py` are the only sanctioned wiring points.
## The rule that matters most
`domain/` imports no framework and no other layer e …