A production-grade backend API built with FastAPI, designed to demonstrate how I structure scalable, maintainable, and testable systems in a real-world engineering environment.
This repository is intentionally organized to show:
- clean architectural separation,
- async-first business logic,
- infrastructure-ready persistence,
- rigorous test coverage,
- and developer-friendly local workflows.
β Test coverage results are deployed automatically on merges to
main. View the deployed coverage report here: https://barbaraport.github.io/mars-probe-simulator/
- β‘ Async-first architecture using FastAPI and SQLAlchemy 2.0 async
- π§± Layered domain model with clear API / service / domain / repository boundaries
- π§ͺ Full testing pyramid: unit, integration, and E2E coverage
- π PostgreSQL-ready data layer with Alembic migrations and database contract safety
- π Quality tooling:
ruff, automated hooks, and environment-specific workflows - π§© Extendable design for future features and production adoption
- FastAPI β high-performance async HTTP layer
- uv β dependency and environment management
- Pydantic v2 β validation and schema contracts
- SQLAlchemy 2.0 (async) β async ORM and persistence
- PostgreSQL β production-grade relational storage
- Alembic β migrations and schema versioning
- Docker / Docker Compose β consistent local development and CI-style test environments
- pytest β deterministic, fast automated testing
- ruff β linting, formatting, and static checks
This project uses environment-specific Docker configurations to reflect real-world deployment workflows.
Each environment has different operational goals and therefore different build/runtime requirements:
| Environment | Purpose |
|---|---|
| Development | Developer productivity, hot reload, debugging, and local tooling |
| Test | Deterministic execution of automated test suites |
| Production | Lean runtime image with only the dependencies required to run the application |
This separation helps prevent development-only tooling from leaking into production images while keeping local workflows fast and reproducible.
docker/
βββ prometheus.yml # prometheus configuration
βββ docker-compose.yml # shared/base services
βββ dev/
β βββ Dockerfile
β βββ docker-compose.yml
βββ test/
β βββ Dockerfile
β βββ docker-compose.yml
βββ prod/
βββ Dockerfile
βββ docker-compose.yml
Key benefits:
- isolated environment concerns
- predictable builds
- production-safe container images
- reproducible development and testing workflows
- reduced operational risk
This application includes production-oriented observability capabilities based on modern telemetry standards.
The service emits the three fundamental observability signals:
- Logs (structured JSON logging)
- Metrics (Prometheus)
- Traces (OpenTelemetry)
All application logs are emitted as structured JSON and include request correlation metadata.
Grid setup example:
mars-probe-simulator-app-1 | {"status": "started", "grid_id": "75cf11e0-f5d5-4dd7-b895-22e7e3d66fa8", "grid_x": 10, "grid_y": 10, "probe_id": "fc5e8297-4b08-4c44-b830-f1924589fa7c", "probe_x": 0, "probe_y": 0, "probe_direction": "NORTH", "event": "PROBE_CREATED", "correlation_id": "31bef03e-4f3d-4c59-a7bb-612049c6018a", "timestamp": "2026-06-08T01:08:47.138437Z", "level": "info"}
mars-probe-simulator-app-1 | {"operation": "increment", "new_value": 1.0, "event": "PROBE_CREATED_TOTAL", "correlation_id": "31bef03e-4f3d-4c59-a7bb-612049c6018a", "timestamp": "2026-06-08T01:08:47.138494Z", "level": "info"}
mars-probe-simulator-app-1 | {"status": "finished", "grid_id": "75cf11e0-f5d5-4dd7-b895-22e7e3d66fa8", "grid_x": 10, "grid_y": 10, "probe_id": "fc5e8297-4b08-4c44-b830-f1924589fa7c", "probe_x": 0, "probe_y": 0, "probe_direction": "NORTH", "event": "PROBE_CREATED", "correlation_id": "31bef03e-4f3d-4c59-a7bb-612049c6018a", "timestamp": "2026-06-08T01:08:47.138512Z", "level": "info"}
mars-probe-simulator-app-1 | {"method": "POST", "path": "/api/v1/setup", "status_code": 200, "duration_ms": 65.18, "event": "COMPLETED_REQUEST", "correlation_id": "31bef03e-4f3d-4c59-a7bb-612049c6018a", "timestamp": "2026-06-08T01:08:47.138988Z", "level": "info"}Command example:
mars-probe-simulator-app-1 | {"status": "started", "probe_id": "fc5e8297-4b08-4c44-b830-f1924589fa7c", "command": "MMMRMMM", "from_x": 0, "from_y": 0, "from_direction": "NORTH", "to_x": 3, "to_y": 3, "to_direction": "EAST", "event": "PROBE_COMMAND_SENT", "correlation_id": "32dcb6f3-f5ee-4cc0-a841-cae6f6ae026e", "timestamp": "2026-06-08T01:09:42.239671Z", "level": "info"}
mars-probe-simulator-app-1 | {"operation": "increment", "new_value": 1.0, "event": "PROBE_COMMANDS_TOTAL", "correlation_id": "32dcb6f3-f5ee-4cc0-a841-cae6f6ae026e", "timestamp": "2026-06-08T01:09:42.239719Z", "level": "info"}
mars-probe-simulator-app-1 | {"status": "finished", "probe_id": "fc5e8297-4b08-4c44-b830-f1924589fa7c", "command": "MMMRMMM", "from_x": 0, "from_y": 0, "from_direction": "NORTH", "to_x": 3, "to_y": 3, "to_direction": "EAST", "event": "PROBE_COMMAND_SENT", "correlation_id": "32dcb6f3-f5ee-4cc0-a841-cae6f6ae026e", "timestamp": "2026-06-08T01:09:42.239736Z", "level": "info"}
mars-probe-simulator-app-1 | {"method": "PATCH", "path": "/api/v1/move", "status_code": 200, "duration_ms": 9.49, "event": "COMPLETED_REQUEST", "correlation_id": "32dcb6f3-f5ee-4cc0-a841-cae6f6ae026e", "timestamp": "2026-06-08T01:09:42.239865Z", "level": "info"}Operational endpoints are available for runtime monitoring.
| Endpoint | Purpose |
|---|---|
/api/v1/ready |
Readiness check, including database connectivity |
/metrics |
Prometheus metrics endpoint |
Metrics are exposed using Prometheus-compatible format.
Collected metrics include:
- request count
- request duration
- in-flight requests
- error rates
- endpoint-specific statistics
- domain usage statistics (grid/probe)
The application is instrumented with OpenTelemetry and automatically generates traces for:
- FastAPI requests
- service execution
- repository operations
- SQLAlchemy database interactions
Development environments include a complete local observability stack.
| Service | URL |
|---|---|
| FastAPI Docs | http://localhost:8000/docs |
| Prometheus | http://localhost:9090 |
| Grafana | http://localhost:3000 |
| Jaeger | http://localhost:16686 |
| Adminer | http://localhost:8080 |
[!NOTE]
The application is instrumented through OpenTelemetry and can export telemetry to any OTLP-compatible observability backend.
- OpenTelemetry: Vendor-neutral telemetry standard used to generate traces and metrics.
- Prometheus: Metrics collection and time-series database.
- Grafana: Dashboarding and metrics visualization.
- Jaeger: Distributed tracing backend used to inspect request execution flows.
This repo includes quality controls that reflect engineering discipline:
- Husky for Git hooks
- Commitlint for conventional commit enforcement
make checkfor linting and static checks- environment-specific runtime configuration
- modular and testable dependency wiring
Adminer is included as a lightweight tool for inspecting the database during local development.
It enables:
- browsing tables and records
- running raw SQL queries
- inspecting schema design
- validating persisted data quickly
This accelerates development without requiring an external database client.
make setupβ install dependencies, enable Git hooks, and migrate the databasemake devβ start the local development Docker stackmake testβ run the test suite inside the test Compose environmentmake checkβ run lint, formatting, and static analysismake db-upgradeβ apply database migrationsmake migration name="<message>"β create a new Alembic migration
This service uses a layered backend architecture to minimize coupling and reduce risk when shipping changes.
HTTP Layer (FastAPI routes) β Service Layer (business orchestration) β Domain Layer (probe/grid rules) β Repository Layer (data access) β Database (PostgreSQL)
Each layer is intentionally responsible for only one concern:
- Routes β translate HTTP requests into application input/output
- Services β orchestrate business rules, validation, and workflows
- Domain β encapsulate core probe/grid logic and invariants
- Repositories β isolate persistence specifics from domain behavior
- Schemas/Models β enforce contracts and data integrity
app/
βββ api/ # HTTP entrypoints, routers, dependency wiring
βββ core/ # configuration, database setup, environment bootstrapping
βββ domain/ # business rules, entities, command handling
βββ models/ # SQLAlchemy ORM models and schema mapping
βββ schemas/ # Pydantic request/response models and validation
βββ services/ # application business logic and use-case orchestration
βββ repositories/ # database persistence abstractions
βββ main.py # application startup and router mounting
This layout is designed to support team development, safe refactoring, and incremental feature growth.
This repository follows a disciplined test pyramid with clearly defined test boundaries.
To run the test suite, use the provided make commands. make setup initializes the development environment and installs dependencies, while make test executes all tests across the pyramid.
make setup
make testValidate business logic in isolation, without network or database dependencies.
- Services
- Domain rules
- Validation utilities
- Command parsing
Verify persistence and repository behavior against a real database.
- SQLAlchemy queries
- repository contracts
- transactional behavior
Validate real HTTP behavior through FastAPI endpoints.
- route contracts
- request/response validation
- business workflows
tests/
βββ unit/ # isolated business logic tests
β βββ services/ # service orchestration
β βββ domain/ # domain rules and entities
βββ integration/ # database persistence tests
β βββ repositories/ # repository contracts and queries
βββ e2e/ # HTTP endpoint tests, route contracts and workflows
This approach yields confidence for both safe refactoring and production-quality delivery.
π§ͺβ Coverage results are deployed automatically on merges to
main; inspect the latest report here: https://barbaraport.github.io/mars-probe-simulator/
The service layer isolates orchestration and enables reuse across APIs, CLI tools, or background workers.
Database access is decoupled from domain rules, making the core logic independent of persistence mechanism.
FastAPI dependencies are used to keep wiring explicit, replaceable, and testable.
The app is built around async endpoints, async sessions, and non-blocking IO for modern backend performance.
Pydantic schemas and explicit command validation ensure invalid input fails fast and clearly.
- Python
3.12or higher uvfor dependency and environment managementDockerandDocker Composefor local development and testingNode.js/npmfor package management and git hooks.envand.env.testfor environment configuration
The app loads configuration from .env in development. .env.test is used for the test environment, while .env.prod is used for the production app.
Example .env:
APP_PORT=8000
ADMINER_PORT=8080
DB_HOST=mars-probe-simulator-db
DB_PORT=5432
DB_USER=myappuser
DB_PASSWORD=password
DB_NAME=mydb
ENV=dev # dev, test, prod
GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_USER_PASSWORD=admin[!WARNING]
Each
.envfile is used for a specific purpose (development, testing, or production). For a complete experience, you should create.env,.env.test, and.env.prod. All must contain the same variables. You should change the values for each environment, avoiding conflicts.
Run both commands in sequence to prepare and launch the application:
make setup
make dev- Run
make setupto install dependencies, enable Git hooks, and migrate the database. - Run
make devto start the app and its local Docker stack. - Open
http://localhost:8000/docsto explore the automatically generated OpenAPI UI.
All endpoints are exposed under /api/v1.
POST /api/v1/setup- initialize a Mars probe on a grid
- accepts
x,y, anddirection - returns the created probe state
PATCH /api/v1/move- execute movement commands against an existing probe
- valid commands:
L,R,M - prevents invalid grid moves and invalid commands
GET /api/v1/check- returns current probe coordinates and orientation
OpenAPI docs are available at
/docswhen the app is running.
This repository demonstrates how I approach backend engineering with senior-level discipline:
- scalable backend architecture with clear service and domain boundaries
- async-first implementation aligned with modern Python best practices
- practical testing discipline across unit, integration, and E2E levels
- clean, modular code organization built for team collaboration
- production-minded infrastructure and deployment readiness
- strong focus on maintainability, validation, and long-term operability
This project was structured to demonstrate backend engineering maturity:
- predictable service boundaries
- clear domain ownership
- robust validation and error handling
- environment-specific configuration
- containerized local development
- repeatable migration workflows
- quality gates through automated tooling
This project was intentionally structured beyond the minimum requirements to reflect real-world backend engineering practices, including maintainability, scalability, and test strategy design.











