A production-grade IoT data platform with three decoupled components: FastAPI backend, Flutter client, and ESP32 device integration.
┌─────────────┐ HTTP/WS ┌─────────────────┐ PostgreSQL ┌────────────┐
│ ESP32 │ ───────────────▶ │ FastAPI │ ◀───────────────▶ │ PostgreSQL │
│ Devices │ │ Backend │ │ Database │
└─────────────┘ └────────┬────────┘ └────────────┘
│
HTTP/WS
│
┌────────▼────────┐
│ Flutter │
│ Client │
└─────────────────┘
- Framework: FastAPI with async SQLAlchemy 2.x
- Database: SQLite (development) / PostgreSQL (production) with Alembic migrations
- Architecture: Clean Architecture with layered separation
- Features:
- REST API for device management and data queries
- WebSocket real-time streaming
- Async database operations with connection pooling
- Pydantic v2 validation
- Structured logging (JSON/console)
- Migration-based schema management
- Framework: Flutter 3.2+
- State Management: Riverpod
- Architecture: Clean Architecture with feature-based organization
- Features:
- Device monitoring dashboard
- Real-time sensor data visualization
- Historical data charts
- WebSocket live streaming
- ESP32 BLE Provisioning (Security 2 with SRP6a)
- See: Flutter Client README
- ESP32 Provisioning: Provisioning Guide
- Protocol: HTTP POST for data ingestion
- Authentication: API key-based
- Provisioning: BLE with Security 2 (SRP6a)
- See:
- Docker & Docker Compose
- Python 3.12+ (for local development)
- Flutter SDK 3.2+ (for client development)
-
Clone the repository:
git clone <repository-url> cd telemetry_app
-
Copy environment configuration:
cp .env.example .env # Edit .env with your settings -
Start all services:
docker-compose up -d
-
⚠️ CRITICAL: Run database migrations (creates tables):docker-compose exec backend alembic upgrade headNote: Skipping this step will cause "no such table" errors!
-
Access the API:
- API: http://localhost:8000
- API Docs: http://localhost:8000/docs
- Health: http://localhost:8000/api/v1/health
cd backend
# Create virtual environment
python -m venv .venv
source .venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Set up environment
cp .env.example .env
# Edit .env with your database settings
# For local dev: DATABASE_URL=sqlite+aiosqlite:///./dev.db
# For production: DATABASE_URL=postgresql+asyncpg://user:pass@host/db
# ⚠️ CRITICAL: Run migrations to create database tables
alembic upgrade head
# Verify tables exist
sqlite3 dev.db ".tables" # For SQLite
# Expected output: alembic_version devices readings
# Start development server
uvicorn app.main:app --reload
# API available at: http://localhost:8000/docsTroubleshooting: If you see "no such table: devices" error, run
alembic upgrade headSee backend/README.md for detailed setup guide
See backend/MIGRATIONS.md for migration workflow
cd flutter_client
# Get dependencies
flutter pub get
# Run the app
flutter run -d chrome # Web
flutter run -d macos # macOS
flutter run # Default devicetelemetry_app/
├── backend/
│ ├── app/
│ │ ├── api/ # REST endpoints & dependencies
│ │ ├── config/ # Settings & logging
│ │ ├── db/ # Database layer (NEW)
│ │ │ ├── base.py # Declarative Base
│ │ │ ├── models.py # ORM models
│ │ │ └── session.py # Connection management
│ │ ├── domain/ # Entities, value objects
│ │ ├── infrastructure/ # WebSocket & external services
│ │ ├── repositories/ # Data access layer
│ │ └── services/ # Business logic
│ ├── alembic/ # Database migrations
│ │ ├── versions/ # Migration scripts
│ │ └── env.py # Alembic configuration
│ ├── tests/ # Unit & integration tests
│ ├── README.md # Backend quick start
│ ├── MIGRATIONS.md # Migration workflow guide
│ ├── init-db.sh # Database initialization script
│ ├── Dockerfile
│ └── requirements.txt
├── flutter_client/
│ ├── lib/
│ │ ├── core/ # Shared utilities
│ │ └── features/ # Feature modules
│ │ ├── dashboard/
│ │ ├── devices/
│ │ └── live_stream/
│ ├── test/
│ └── pubspec.yaml
├── docs/
│ └── ESP32_PROTOCOL.md # ESP32 integration guide
├── docker-compose.yml
└── README.md
All endpoints are prefixed with /api/v1
GET /api/v1/health- System health check (returns status, timestamp, websocket connections)
POST /api/v1/ingest- Submit sensor readingPOST /api/v1/ingest/batch- Submit multiple readings
POST /api/v1/devices- Register new deviceGET /api/v1/devices- List all active devicesGET /api/v1/devices/{device_id}- Get device detailsGET /api/v1/devices/{device_id}/history- Query historical readingsGET /api/v1/devices/{device_id}/aggregate- Get aggregated statistics (min/max/avg)
WS /api/v1/realtime/subscribe/{device_id}- Subscribe to live device updates
- Admin endpoints require:
X-API-Key: <admin-secret> - Device endpoints require:
X-API-Key: <device-key>
See API Documentation when running locally.
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
required | Database connection string SQLite: sqlite+aiosqlite:///./dev.dbPostgreSQL: postgresql+asyncpg://user:pass@host/db |
APP_ENV |
development |
Environment (development/staging/production) |
API_SECRET_KEY |
required | Admin API secret key (min 16 chars) |
DEVICE_API_KEYS |
`` | Comma-separated device API keys |
LOG_LEVEL |
info |
Logging level (DEBUG/INFO/WARNING/ERROR/CRITICAL) |
LOG_FORMAT |
json |
Log format (json/console) |
DEBUG |
false |
Enable debug mode (SQL logging) |
HOST |
0.0.0.0 |
Server bind host |
PORT |
8000 |
Server port |
DB_POOL_SIZE |
5 |
Database connection pool size |
WS_HEARTBEAT_INTERVAL |
30 |
WebSocket heartbeat interval (seconds) |
See backend .env.example for complete configuration template.
Edit lib/core/config/app_config.dart to set:
- API base URL
- WebSocket URL
- Default settings
cd backend
pytest
pytest --cov=app # With coveragecd flutter_client
flutter test
flutter test --coverage- Run database migrations BEFORE starting app:
alembic upgrade head - Set strong
API_SECRET_KEY(min 32 characters, usesecrets.token_urlsafe(32)) - Configure
DATABASE_URLfor production PostgreSQL - Generate unique
DEVICE_API_KEYSfor each device - Set
APP_ENV=production - Set
DEBUG=false - Set
LOG_FORMAT=json - Configure connection pool settings (
DB_POOL_SIZE,DB_MAX_OVERFLOW) - Enable HTTPS/TLS
- Set up monitoring and alerting
- Configure automated backups for PostgreSQL
- Test migration rollback procedure
# Build images
docker-compose -f docker-compose.yml build
# Start database first
docker-compose up -d postgres
# Run migrations (CRITICAL!)
docker-compose run backend alembic upgrade head
# Start all services
docker-compose up -dFor schema changes:
# 1. Modify models in app/db/models.py
# 2. Generate migration
alembic revision --autogenerate -m "description"
# 3. Review migration in alembic/versions/
# 4. Test locally
alembic upgrade head
# 5. Commit migration files to git
# 6. Deploy: run migrations before starting appSee backend/MIGRATIONS.md for detailed migration guide.
Cause: Database migrations haven't been run.
Solution:
cd backend
alembic upgrade headCause: App can't connect to database.
Solution: Check DATABASE_URL in .env file is correct.
Cause: Missing or incorrect X-API-Key header.
Solution:
- Admin endpoints: Use value from
API_SECRET_KEY - Device endpoints: Use one of
DEVICE_API_KEYS
cd backend
rm dev.db # Remove old database
alembic upgrade head # Recreate tables
uvicorn app.main:app --reloadSee component-specific READMEs for more troubleshooting:
- Fork the repository
- Create a feature branch
- Make your changes
- Add/update tests
- If schema changed: Generate migration with
alembic revision --autogenerate - Run tests:
pytest(backend) orflutter test(client) - Update documentation
- Submit a pull request
MIT License - see LICENSE file for details