All work

Case study 01 · EAV Labs

EAV Insight

A FastAPI backend for document intake, operational reporting and searchable business records.

Role
Backend engineering and system design
Period
2026
Stack
Python 3.12 · FastAPI · PostgreSQL · SQLAlchemy · Alembic · Docker · Caddy · OCI
Links
Live API (opens in a new tab)API docs (opens in a new tab)Repository (opens in a new tab)
Swagger/OpenAPI documentation for EAV Insight API at insight.env.pm, showing the health, authentication and report endpoint groups.
The live OpenAPI documentation at insight.env.pm/docs.
01 · Context

Built like a team depends on it

Built in EAV Labs as a production-style backend service: typed Python, environment-based configuration, Dockerised development, automated testing, CI and documentation discipline.

I built Insight in EAV Labs to practise the parts of backend work that tutorials tend to skip: configuration, migrations, tests, CI and deployment, done properly on a small but real service.

02 · Problem

Records scattered across too many places

Business teams often store reports, documents, invoices and field records in scattered systems.

Searching, categorising and tracking those records gets harder as the organisation grows.

The service is for:

  • Operations managers
  • Analysts
  • Field teams
  • SMEs
  • Document-heavy teams
03 · My role

What I did

I designed and built the service end to end: the data model and migrations, the versioned API, authentication and organisation scoping, the error and pagination conventions, the tests and CI, and the deployment to Oracle Cloud. There is no frontend; Insight is an API with its documentation.

04 · Approach

Small modules, explicit contracts

A modular FastAPI service with versioned routes, Pydantic schemas, SQLAlchemy models and Alembic migrations, deployed from main through GitHub Actions to an OCI ARM64 VM.

I kept the service deliberately plain: clear module boundaries, schemas at every edge and a migration for every schema change, so each part can be tested and changed on its own.

Deployment architecture, from the project documentation.
05 · Key decisions

Decisions that shaped it

Decision 01

Records are scoped to the caller’s organisation

Report and document endpoints require a bearer token and resolve the organisation from it, so clients never send organization_id.

Why: Taking the organisation from the token means no client can reach another organisation’s records by changing an ID. The trade-off is that every query has to carry that scope.

Decision 02

One error envelope for every failure

Every error returns code, message and details, with field-level details when validation fails.

Why: Clients handle one shape for every failure, and validation errors point at the exact field. The cost is a little mapping work for each new kind of error.

Decision 03

Pagination clients can build on

List responses carry total, count, has_next, has_previous and the next and previous offsets.

Why: Clients can build paging without guessing or counting rows themselves. The trade-off is a count query on every list request.

Decision 04

Production runs only what the code uses

Redis stays in local development but is left out of production, because the application does not consume it yet.

Why: Running only what the code uses keeps production simpler and cheaper to operate. Redis comes back when a feature actually needs it.

Requestbash
curl -H "Authorization: Bearer <access_token>" \
  http://localhost:8000/api/v1/reports
Validation errorjson
{
  "error": {
    "code": "validation_error",
    "message": "Request validation failed.",
    "details": [
      {
        "field": "body.title",
        "message": "String should have at least 2 characters",
        "type": "string_too_short"
      }
    ]
  }
}
06 · Result

Live, documented and deployable from main

The MVP deploys from main to Oracle Cloud through GitHub Actions and is live at insight.env.pm, with OpenAPI docs and a health endpoint.

It is small, but I can change it with confidence: every push runs the checks, and a merge to main reaches production through the pipeline rather than by hand.

GitHub Actions workflow runs for EAV Insight API, including CI and Deploy to OCI.
CI on every push and pull request: lint, tests, migration check, Docker build.
The live health endpoint of EAV Insight API returning status ok for the production environment.
The live health endpoint, /api/v1/health.