AgroPulse Backend is a Spring Boot REST API organized into discrete layers that separate concerns cleanly: HTTP controllers handle incoming requests, services hold business logic, repositories mediate all database access, and JPA entities model the domain. Design patterns—Observer, Abstract Factory, and State—are applied deliberately to keep components decoupled and extensible as the number of greenhouses and sensor types grows.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/diarpicu2022-commits/backend-AgroPulse/llms.txt
Use this file to discover all available pages before exploring further.
Layered architecture
Requests flow top-to-bottom through four layers. Each layer depends only on the one below it; nothing in a lower layer reaches upward.Dual-database setup
The database driver and dialect are controlled entirely by environment variables, so the same JAR runs locally with no extra setup and in production without code changes.| Environment | Driver | Connection |
|---|---|---|
| Local / dev | org.sqlite.JDBC | jdbc:sqlite:agropulse.db (file on disk) |
| Production | org.postgresql.Driver | Set via SPRING_DATASOURCE_URL |
SPRING_DATASOURCE_URL, SPRING_DATASOURCE_DRIVER_CLASS_NAME, and SPRING_JPA_DATABASE_PLATFORM in your deployment environment (for example, Render environment variables).
Sensor auto-registration
IoT devices do not need to be manually enrolled before they start sending data. When a reading arrives for a sensor ID that does not yet exist in the database, the API creates the sensor record automatically and assigns it to the correct greenhouse. Subsequent readings updatelastValue and lastTimestamp on the existing record.
Design patterns
Observer
GreenhouseMonitor is the subject. Every time a sensor reading is saved, processSensorReading() fans the event out to all registered IGreenhouseObserver beans—such as AlertObserver—without the controller knowing which observers exist.Abstract Factory
SensorType defines the product families (TEMPERATURE, HUMIDITY, SOIL_MOISTURE, LIGHT, CO2, PH, WIND_SPEED, TEMPERATURE_INTERNAL, TEMPERATURE_EXTERNAL). The factory creates the correct sensor configuration for each type.State
Sensor anomalies move through states: detected (no
resolvedAt), notified (notified = true), and resolved (resolvedAt set). The AnomalyDetectionService drives these transitions on each 2-minute cycle.Stateless API
Spring Security is configured with
SessionCreationPolicy.STATELESS. There are no server-side sessions; every request carries its own identity context (user object or X-Admin-Email header).Data flow: device POST to anomaly detection
Device POSTs a reading
An IoT device sends a POST request to
/api/readings with sensor ID, value, and timestamp. If the sensor is not yet registered, it is created automatically at this point.ReadingController persists the data
The controller validates the payload, saves the
SensorReading record to the database, and updates the parent Sensor’s lastValue and lastTimestamp fields.GreenhouseMonitor is notified
ReadingController calls GreenhouseMonitor.processSensorReading(reading), which immediately calls onSensorReading() on every registered observer bean. This happens synchronously before the HTTP response is returned.AnomalyDetectionService runs on schedule
Independently of the reading flow,
AnomalyDetectionService.detect() runs every 2 minutes. It loads all active SensorThreshold configs and checks each sensor for OUT_OF_RANGE, NO_DATA, STUCK, and SPIKE conditions.