The Sensor Data Management System is a full-stack application designed to ingest, store, manage, and visualize generic sensor data. It is built with a focus on flexibility, allowing it to handle various sensor types and hierarchical location structures without schema changes. The system utilizes a modern GraphQL API for efficient data retrieval and a React-based frontend for user interaction.
The system follows a standard three-tier architecture:
- Presentation Layer (Frontend): A Single Page Application (SPA) built with React and TypeScript.
- Application Layer (Backend): A Python-based REST and GraphQL API built with FastAPI.
- Data Layer (Database): A PostgreSQL relational database optimized for time-series data.
graph TD
Client[Client Browser] <-->|GraphQL / HTTP| API[FastAPI Backend]
API <-->|SQLAlchemy ORM| DB[(PostgreSQL Database)]
API -->|Alembic| DB_Migration[Database Migrations]
- FastAPI: Serves as the web framework, providing high performance, automatic OpenAPI documentation, and easy integration with async Python features.
- Strawberry GraphQL: Implements the GraphQL schema, allowing clients to request exactly the data they need.
- SQLAlchemy: The Object-Relational Mapper (ORM) used to interact with the database.
- Alembic: Handles database schema migrations.
The database schema is designed to be generic and extensible. Key entities include:
- SensorType: Defines the category of a sensor (e.g., "Temperature", "Humidity") including units and valid ranges.
- Location: A hierarchical entity (Self-referencing adjacency list) allowing for structures like Building -> Floor -> Room.
- Sensor: Represents a physical device, linked to a
SensorTypeand aLocation. It includes metadata like manufacturer, model, and calibration data. - SensorReading: The core time-series entity. It stores the actual measurement (
value), timestamp, and quality indicators. It is optimized for high-volume writes. - Alert: Stores threshold-based or anomaly-based alerts generated from sensor readings.
- GraphQL Endpoint (
/graphql): The primary interface for the frontend.- Queries: Fetch sensors, locations, readings (with time-range filtering), and alerts.
- Mutations: Create/Update sensors, locations, sensor types, and record new readings.
- REST Endpoints:
/health: System health check./docs: Auto-generated API documentation.
- React 19: The core UI library.
- TypeScript: Ensures type safety across the application.
- Vite: The build tool and development server, offering fast hot module replacement (HMR).
- Apollo Client: Manages GraphQL state, caching, and network requests.
- Routing:
react-router-domhandles client-side routing for Dashboard, Sensor Lists, and Detail views. - Visualization:
chart.jsandreact-chartjs-2are used to render time-series charts of sensor data. - UI Components: Modular components (Layout, LoadingSpinner, Modal) ensure a consistent user interface.
- Icons:
lucide-reactprovides a consistent icon set.
PostgreSQL was chosen for its robustness, support for complex queries, and reliability.
- Indexing:
SensorReadingtables are heavily indexed ontimestampandsensor_idto ensure fast retrieval of historical data. - UUIDs: All primary keys use UUIDs to support distributed generation and prevent ID collisions in potential multi-master setups.
- JSONB:
device_metadataandalert_metadatacolumns use JSON types to allow for flexible, schema-less storage of device-specific attributes.
- Containerization: Dockerfiles are provided for both frontend and backend services, enabling consistent deployment across environments.
- Database Hosting: Configured to work with managed PostgreSQL services (e.g., Aiven).
- Configuration: The application uses
python-dotenvto load configuration from.envfiles, adhering to the 12-factor app methodology.
- CORS: Configured via FastAPI middleware to control access from the frontend application.
- Environment Variables: Sensitive credentials (database URLs, secret keys) are strictly managed via environment variables and never committed to code.