Development Guide¶
This guide helps you set up a development environment for OpenLatch. Target audience: junior to mid-level developers on Linux, macOS, or Windows.
Prerequisites¶
You need the following tools installed:
| Tool | Version | Purpose |
|---|---|---|
| Python | 3.12+ | Backend server, tooling |
| pip | latest | Python package manager |
| Docker + Docker Compose | latest | Local PostgreSQL database |
| PlatformIO CLI | 6.x | ESP32 firmware build + test |
| Git | 2.x+ | Version control |
| A C++ compiler | gcc/clang | Native firmware tests (runs on your machine) |
Install Python 3.12+¶
Download from python.org or use winget:
Make sure to check "Add Python to PATH" during installation.
Install Docker¶
Download Docker Desktop for Windows or:
Requires WSL 2 enabled. Docker Desktop will guide you through this.
Install PlatformIO CLI¶
PlatformIO is used to build and test the ESP32 firmware. The CLI is sufficient — you don't need the IDE.
Verify:
Note: PlatformIO downloads the ESP32 toolchain automatically on first build. The native test environment (which runs on your computer, no hardware needed) requires only a C++ compiler.
Install a C++ Compiler¶
This is needed for running firmware tests on your development machine (native tests — no ESP32 required).
Install MSYS2 and then from the MSYS2 terminal:
Or install Visual Studio Build Tools with the "Desktop development with C++" workload.
Project Setup¶
1. Clone the Repository¶
2. Start PostgreSQL¶
This starts a PostgreSQL 16 instance on localhost:5432 with:
- Database: openlatch
- User: postgres
- Password: postgres
3. Set Up the Backend¶
cd backend
# Create a virtual environment
python3 -m venv .venv
# Activate it
source .venv/bin/activate # Linux/macOS
# .venv\Scripts\activate # Windows (cmd)
# .venv\Scripts\Activate.ps1 # Windows (PowerShell)
# Install dependencies (including dev tools)
pip install -e ".[dev]"
4. Verify Backend Tests Pass¶
You should see:
5. Verify Firmware Native Tests Pass¶
You should see:
Note: This runs on your computer — no ESP32 hardware needed. The
nativetest environment compiles the firmware logic as a regular C++ program and runs the tests locally.
6. (Optional) Generate Ed25519 Keypair¶
For local development, you can generate a signing keypair:
This prints the keys to stdout. Use --write to save them to files.
Development Workflow¶
TDD (Test-Driven Development)¶
We follow TDD. For every new feature:
- Write a failing test first
- Write the minimal code to make the test pass
- Refactor if needed, keeping tests green
- Commit with a meaningful message
Running Tests¶
# Backend
cd backend && source .venv/bin/activate && pytest -v
# Firmware (native tests, no hardware needed)
cd firmware && pio test -e native
# Firmware (on real ESP32, requires hardware)
cd firmware && pio test -e esp32dev
Code Style & Linting¶
Backend (Python):
cd backend && source .venv/bin/activate
# Check formatting
ruff format --check .
# Check lint rules
ruff check .
# Auto-fix
ruff format .
ruff check --fix .
Firmware (C++):
Git Commit Messages¶
Write clear, descriptive commit messages. Format:
Short summary of what changed (imperative mood)
Optional longer description explaining why the change was made,
any important design decisions, or context for reviewers.
Good examples:
- Add time slot evaluation for overnight events
- Fix grace period calculation crossing midnight
- Implement Ed25519 signature verification in firmware
Bad examples:
- fix stuff
- WIP
- update
Branching¶
main— stable, CI must pass- Feature branches:
feature/add-member-api,feature/wiegand-decoder - Bug fixes:
fix/overnight-time-slot
Project Structure¶
openlatch/
├── backend/ Python FastAPI backend
│ ├── app/ Application code
│ │ ├── auth/ Authentication (JWT, passwords)
│ │ ├── models/ SQLAlchemy models + Pydantic schemas
│ │ ├── routes/ API endpoints
│ │ ├── services/ Business logic (rules engine, signing)
│ │ └── crypto/ Ed25519 key management
│ └── tests/ pytest tests
├── firmware/ ESP32 PlatformIO project
│ ├── include/ C++ header files
│ ├── src/ C++ source files
│ └── test/
│ ├── test_native_*/ Tests that run on your computer (one dir per suite)
│ └── test_embedded/ Tests that run on real ESP32
├── proto/ Allow-list protocol specification
├── tools/ Keygen, docker-compose
└── docs/ Architecture, diagrams, this file
Where to Start¶
| "I want to..." | Start here |
|---|---|
| Understand the system | docs/diagrams.md |
| Work on the backend API | backend/app/routes/ |
| Work on access rules | backend/app/services/rules_engine.py |
| Work on firmware logic | firmware/src/ + firmware/test/test_native_*/ |
| Understand the binary protocol | proto/allowlist.md |
| Change the database schema | backend/alembic/versions/ |
CI/CD Pipeline¶
GitLab CI runs automatically on every push. The pipeline has 4 stages:
| Job | Stage | What it does |
|---|---|---|
backend:lint |
lint | ruff format + ruff check |
firmware:lint |
lint | pio check (C++ static analysis) |
backend:test |
test | pytest with PostgreSQL |
firmware:test:native |
test | pio test -e native |
cross:test |
test | Python signs → C++ verifies |
backend:build |
build | Docker image (main branch only) |
firmware:build |
build | ESP32 binary (main branch only) |
security:backend |
security-scan | pip-audit |
security:firmware |
security-scan | pio check |
Your merge request must pass at least lint and test stages.
Common Tasks¶
Add a New API Endpoint¶
- Create a test in
backend/tests/test_<feature>.py - Add the route in
backend/app/routes/<feature>.py - Register the router in
backend/app/main.py - Run
pytest -vto verify
Add a New Firmware Module¶
- Create header in
firmware/include/<module>.h - Create source in
firmware/src/<module>.cpp - Add native tests in
firmware/test/test_native_<module>/test_<module>.cpp - Run
pio test -e nativeto verify
Update the Database Schema¶
- Modify the SQLAlchemy model in
backend/app/models/ - Create a migration:
- Apply it:
Flash Firmware to ESP32¶
Monitor serial output:
Troubleshooting¶
pio test -e native fails with linker errors¶
Make sure you have a C++ compiler installed (see prerequisites). On macOS, run xcode-select --install.
PostgreSQL connection refused¶
Make sure Docker is running and the database container is up:
Python ModuleNotFoundError¶
Make sure you activated the virtual environment:
PlatformIO downloads take forever on first run¶
This is normal. PlatformIO downloads the ESP32 toolchain (~500MB) on first build. Subsequent builds are fast.