ADR-002: Python + FastAPI for Backend¶
Status: Accepted Date: 2026-02-25
Context¶
We need a backend server to manage members, NFC keys, access rules, and to generate signed allow-lists for the ESP32. The hackerspace has contributors with varying experience levels.
We initially considered sharing code between the ESP32 firmware and the backend using MicroPython, but after evaluating the constraints, this was ruled out.
Options Considered¶
A) MicroPython (shared code with ESP32)¶
- Pro: Code reuse between backend and firmware (protocol parsing, crypto)
- Con: No MicroPython library for NUKI BLE (NukiBleEsp32 is C++ only)
- Con: Wiegand ISR timing requirements are difficult in MicroPython
- Con: Ed25519 verification in pure Python takes ~9 seconds on ESP32 (vs milliseconds with libsodium)
- Con: Significantly higher RAM usage, ESP32 has only 520KB SRAM
B) Rust (Axum / Actix)¶
- Pro: Excellent performance and memory safety
- Pro: Could share code with ESP32 via no_std crate
- Con: Steeper learning curve for hackerspace contributors
- Con: Slower prototyping compared to Python
C) Python + FastAPI¶
- Pro: Accessible to most hackerspace members (Python is widely known)
- Pro: FastAPI provides async support, automatic OpenAPI docs, Pydantic validation
- Pro: Rich ecosystem for crypto (PyNaCl), auth (python-jose), database (SQLAlchemy)
- Pro: Rapid development for a project where the backend is not performance-critical
- Con: No code sharing with C++ firmware (but the shared surface is small — just the binary protocol)
Decision¶
Python + FastAPI (Option C).
The primary goal is accessibility for hackerspace contributors. The backend is not performance-critical (it serves a handful of ESP32 devices, not thousands of concurrent users). The shared surface between backend and firmware is the binary allow-list format, which is well-specified and tested via cross-platform test vectors.
Consequences¶
- Backend uses Python 3.11+, FastAPI, SQLAlchemy 2.0 (async), PostgreSQL
- Auth: JWT tokens (python-jose), passwords hashed with Argon2id
- Signing: Ed25519 via PyNaCl
- Testing: pytest with async support
- The binary protocol is the integration contract — tested by generating test vectors in Python and verifying them in C++ native tests