DEALData regroupe les services Django qui portent les donnees metier de la plateforme DEAL.
| Couche | Port local | Role |
|---|---|---|
core_layer |
7000 |
Projets, membres, objets observes et experiences. |
gps_layer |
7001 |
Capteurs GPS, donnees GPS brutes, positions traitees et evenements WildFi raw.gps. |
sensor_layer |
7002 |
Capteurs generiques, mesures associees et evenements WildFi raw.sensor. |
Le depot est prevu comme fournisseur de donnees pour Smartappli/DEALIoT et
comme ensemble de modules deployables derriere Smartappli/DEALHost.
Le depot contient trois services Django deployables separement. Chaque couche utilise sa propre base PostgreSQL en Docker:
core-dbpourcore_layer.gps-dbpourgps_layer.sensor-dbpoursensor_layer.
Les couches GPS et Sensor ne declarent pas de foreign keys SQL vers la base
Core. Les liens vers les objets observes sont conserves sous forme d'UUID
(observed_object_id) geres par core_layer.
Les donnees WildFi arrivent via les contrats DEALIoT suivants:
raw.gpsversgps_data.WildFiGPSFix.raw.sensorverssensor_data.WildFiDecodedSensorEvent.
Ces tables conservent l'enveloppe DEALIoT (device_id, timestamp,
source, mqtt_topic, ingested_at) avec le payload decode, les metadonnees
de transport et les champs utiles a l'idempotence (event_id, payload_hash).
Deux modes d'integration sont supportes:
- Push HTTP depuis un service externe vers les endpoints
/api/ingest/wildfi/.... - Consommation Kafka directe des topics DEALIoT
raw.gpsetraw.sensorvia les workers Djangoconsume_dealiot_kafka.
Le mode Kafka constitue le chainon direct DEALIoT -> DEALData: les workers
lisent les messages JSON produits par DEALIoT et les persistent dans les memes
chemins d'ingestion idempotents que l'API HTTP.
- Python
>=3.14. - Docker et Docker Compose pour l'environnement PostgreSQL local.
- PowerShell pour les commandes ci-dessous.
Depuis la racine du depot:
py -3.14 -m venv .venv
.\.venv\Scripts\python.exe -m pip install --upgrade pip
.\.venv\Scripts\python.exe -m pip install -r core_layer\requirements.txt
.\.venv\Scripts\python.exe -m pip install -r gps_layer\requirements.txt
.\.venv\Scripts\python.exe -m pip install -r sensor_layer\requirements.txt
.\.venv\Scripts\python.exe -m pip install pytest pytest-django pytest-covLe fichier pyproject.toml centralise aussi les versions ciblees, mais
l'installation editable du depot n'est pas active tant que le packaging
multi-couches n'est pas configure explicitement.
Depuis la racine du depot, avec les dependances installees dans .venv:
.\.venv\Scripts\python.exe -m compileall -q core_layer gps_layer sensor_layer
cd core_layer; ..\.venv\Scripts\python.exe manage.py check; ..\.venv\Scripts\python.exe -m pytest . --ds=core.settings -q
cd ..\gps_layer; ..\.venv\Scripts\python.exe manage.py check; ..\.venv\Scripts\python.exe -m pytest . --ds=gps.settings -q
cd ..\sensor_layer; ..\.venv\Scripts\python.exe manage.py check; ..\.venv\Scripts\python.exe -m pytest . --ds=sensor.settings -q
cd ..Pour appliquer les migrations localement dans une couche:
cd core_layer
..\.venv\Scripts\python.exe manage.py migrate
..\.venv\Scripts\python.exe manage.py createsuperuser
cd ..Adapter le dossier et le module settings pour gps_layer ou sensor_layer si
necessaire.
L'environnement Docker local demarre les trois services avec une base PostgreSQL dediee par couche:
Copy-Item .env.example .env
# Renseigner les cles Django, mots de passe PostgreSQL et DEALDATA_INGEST_TOKEN.
docker compose up --buildEndpoints de sante et d'observabilite:
GET http://localhost:7000/health/live/GET http://localhost:7000/health/ready/GET http://localhost:7000/metrics/GET http://localhost:7001/health/live/GET http://localhost:7001/health/ready/GET http://localhost:7001/metrics/GET http://localhost:7002/health/live/GET http://localhost:7002/health/ready/GET http://localhost:7002/metrics/
Endpoints WildFi:
GET http://localhost:7001/api/wildfi/gps/POST http://localhost:7001/api/ingest/wildfi/gps/POST http://localhost:7001/api/ingest/wildfi/gps/batch/GET http://localhost:7002/api/wildfi/sensor/POST http://localhost:7002/api/ingest/wildfi/sensor/POST http://localhost:7002/api/ingest/wildfi/sensor/batch/
Les endpoints d'ingestion acceptent le header
X-DEALDATA-INGEST-TOKEN quand DEALDATA_INGEST_TOKEN est defini.
En Docker local, cette variable doit etre renseignee dans .env.
Pour connecter directement DEALData aux topics Kafka DEALIoT:
docker compose --profile dealiot up --buildCe profil demarre deux workers supplementaires:
gps-dealiot-consumer: consommeraw.gpset alimenteWildFiGPSFix.sensor-dealiot-consumer: consommeraw.sensoret alimenteWildFiDecodedSensorEvent.
Par defaut, les workers cherchent Kafka sur
kafka1:9092,kafka2:9092,kafka3:9092. Adapter
DEALDATA_KAFKA_BOOTSTRAP_SERVERS si DEALIoT expose d'autres endpoints.
Exemple minimal raw.gps:
{
"event_id": "gps-event-1",
"device_id": "wildfi-17",
"timestamp": "2026-05-24T12:30:00Z",
"source": "wildfi-mqtt",
"mqtt_topic": "wildfi/wildfi-17/gps",
"latitude": 50.6333,
"longitude": 5.5667,
"altitude_m": 121.5,
"speed_m_s": 1.8,
"heading_deg": 84.5,
"payload": {
"fix": 3,
"hdop": 0.9
}
}Exemple minimal raw.sensor:
{
"event_id": "sensor-event-1",
"device_id": "wildfi-17",
"timestamp": "2026-05-24T12:30:00Z",
"source": "wildfi-mqtt",
"mqtt_topic": "wildfi/wildfi-17/sensor",
"payload": {
"sensor_type": "temperature",
"value": 18.5,
"unit": "C"
}
}Les endpoints batch acceptent soit un tableau JSON, soit un objet
{"events": [...]}.
Compatibilite champs DEALIoT:
altitude_m,speed_m_setheading_degsont acceptes et normalises vers les colonnesaltitude,speedetheading.- Les anciens alias
alt,course,lat,lonetlngrestent acceptes. - Pour
raw.sensor,sensor_typeest determine dans cet ordre: champ explicite top-level,payload.sensor_type,payload.type, suffixemqtt_topicconnu (imu,environment,proximity,movement,metadata, etc.), puis heuristiques sur les cles du payload.
Codes HTTP attendus:
201 Created: evenement insere.200 OK: evenement deja connu ou batch traite.400 Bad Request: payload invalide.403 Forbidden: token d'ingestion invalide.
L'ingestion est idempotente. Si event_id est fourni, l'unicite est controlee
par couple source + event_id. Sinon, un payload_hash stable est calcule
sur le contenu de l'evenement.
Les endpoints de lecture acceptent des filtres par device et intervalle temporel:
Invoke-RestMethod "http://localhost:7001/api/wildfi/gps/?device_id=wildfi-17&from=2026-05-24T12:00:00Z&to=2026-05-24T13:00:00Z&limit=10"
Invoke-RestMethod "http://localhost:7002/api/wildfi/sensor/?device_id=wildfi-17&sensor_type=temperature&from=2026-05-24T12:00:00Z&to=2026-05-24T13:00:00Z&limit=10"Renseigner les variables de .env.example, puis lancer avec l'override:
docker compose -f docker-compose.yml -f docker-compose.prod.yml up --buildAvec la consommation Kafka DEALIoT:
docker compose -f docker-compose.yml -f docker-compose.prod.yml --profile dealiot up --buildVariables obligatoires en production:
CORE_DJANGO_SECRET_KEY,GPS_DJANGO_SECRET_KEY,SENSOR_DJANGO_SECRET_KEY.CORE_DJANGO_ALLOWED_HOSTS,GPS_DJANGO_ALLOWED_HOSTS,SENSOR_DJANGO_ALLOWED_HOSTS.CORE_DATABASE_HOST,GPS_DATABASE_HOST,SENSOR_DATABASE_HOST.CORE_DATABASE_USER,GPS_DATABASE_USER,SENSOR_DATABASE_USER.CORE_DATABASE_PASSWORD,GPS_DATABASE_PASSWORD,SENSOR_DATABASE_PASSWORD.DEALDATA_INGEST_TOKENpour les endpoints d'ingestion GPS et Sensor.
Variables optionnelles ou avec valeur par defaut:
CORE_DATABASE_NAME,GPS_DATABASE_NAME,SENSOR_DATABASE_NAME.DEALDATA_KAFKA_BOOTSTRAP_SERVERS,DEALDATA_KAFKA_AUTO_OFFSET_RESET,DEALDATA_KAFKA_MAX_RECORDS,DEALDATA_KAFKA_POLL_TIMEOUT_MS.DEALDATA_GPS_KAFKA_TOPIC,DEALDATA_GPS_KAFKA_GROUP_ID,DEALDATA_SENSOR_KAFKA_TOPIC,DEALDATA_SENSOR_KAFKA_GROUP_ID.SENTRY_DSN,SENTRY_ENVIRONMENT,SENTRY_TRACES_SAMPLE_RATE,SENTRY_SEND_DEFAULT_PII.
En production, DJANGO_DEBUG=false est impose par docker-compose.prod.yml.
- Les metriques exposees par
/metrics/utilisent un format compatible Prometheus. - Les migrations doivent etre appliquees par couche avant ouverture du trafic.
.env.examplecontient les variables attendues avec des valeurs vides. Renseigner.envlocalement ou via le gestionnaire de secrets de l'environnement cible.docker-compose.dev.ymletdocker-compose.staging.ymlsont actuellement vides. Ils ne modifient donc pas le comportement tant qu'ils ne sont pas completes.