⚠️ Connexion perdue — données non actualisées
SG
SELOtec GNSS Monitoring Ecosystem — Live
Système opérationnel
--:--:--
Notifications
Aucune notification
Dashboard live
SELOtec GNSS · Monitoring Ecosystem complet · Actualisation 30s
🟢
Devices en ligne
— %
📡
Positions / minute
— / heure
💻
CPU / RAM
RAM —
💾
Backup nightly
📈 CPU / RAM (24h)
CPU
RAM
📡 Activité GPS (24h)
pos/min
devices actifs
🔔 Alertes système
⏱ Countdown — Jour J Migration CloudDB
06/05/2026 02h30 · Bascule HyTalkPro → CloudDB · NAT switch ~30s coupure radios
--Jours
:
--Heures
:
--Min
:
--Sec
Accès rapides
Naviguer vers les sections
Flotte GPS
Parc complet en temps réel
Devices — Parc GPS complet
800 radios · 50 groupes entreprises · données en temps réel
🟢 En ligne
⚫ Hors ligne
Total
Liste des devices
# Device ID Alias Groupe Statut
Monitoring serveur
CPU · RAM · Disque · Base de données · Alertes
CPU
utilisation processeur
RAM
Disque
Load avg 1min
charge système
Swap
utilisation swap
PostgreSQL
base traccar
📈 Historique CPU / RAM (24h)
CPU
RAM
Load
📡 Activité GPS — positions/min et devices actifs (24h)
pos/min
devices actifs
🔔 Alertes Prometheus
Sécurité & fail2ban
Protection SSH · SELOtec GNSS auth · Nginx · Actualisé 5min
🚫
IP bannies actives
Tentatives SSH détectées
🔒
Jails actives
3
🛡
Ban durée
48h
Backup & PostgreSQL FDW
Backup nightly · Sync PUC → tc_positions
Date
Taille
Rétention
positions / minute
positions (dernière heure)
devices actifs (1h)
Dernier point GPS reçu
Nginx & CI/CD GitHub
Proxy · Headers sécurité · GitHub Actions
Configuration Nginx
# /etc/nginx/sites-available/selotec server { listen 80; server_name 197.31.9.21; server_tokens off; add_header X-Frame-Options SAMEORIGIN; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header Referrer-Policy no-referrer-when-downgrade; location / { proxy_pass http://127.0.0.1:8082; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } location /grafana/ { proxy_pass http://127.0.0.1:3000/; } location /docs/ { alias /var/www/selotec-docs/; auth_basic "SELOtec GNSS"; auth_basic_user_file /etc/nginx/.htpasswd; } location /mrps/ { proxy_pass http://127.0.0.1:5000/mrps/; } location /scp/ { proxy_pass http://127.0.0.1:5000/scp/; } }
GitHub Actions CI/CD
validate-xml
Valide traccar.xml avec xmllint à chaque push
passing
validate-sql
Vérifie la syntaxe des scripts .sql via psql --dry-run
passing
📸
schema-snapshot
pg_dump --schema-only → artifact GitHub (90 jours)
passing
SCP — SELOtec Control Panel
Dashboard superadmin · Contrôle FDW · Orchestration de l'écosystème GPS
Rôle dans l'écosystème
Le SCP est l'interface de contrôle unique de l'écosystème SELOtec GNSS. Il remplace toutes les manipulations SQL/shell directes et permet de gérer le parc GPS, les organisations clientes, la synchronisation FDW et l'infrastructure serveur depuis un dashboard React sécurisé.

Chaque action SCP impacte directement tc_device_mapping, puc_enterprise_mapping et les groupes SELOtec GNSS — les trois tables pivot de tout l'écosystème.
Version SCP
v2.4
SCP v1.0.0 release
🔗
API version
2.4.0
📦
Catégories actives
A–C
D–E roadmap
🏗
Stack
FastAPI
+ React Vite
Architecture technique
# Flux SCP /scp/React Vite (scp-frontend) → FastAPI :8090mrps_db (PostgreSQL) ← organisations, users, devices, audittraccar DB (via psycopg2) ← tc_devices, tc_groups, tc_device_mappingPUC FDW (gps_location_data_remote) ← Scan live devices non mappés # Accès production URL http://197.31.9.21/scp/ Homeid 00000 (superadmin) Dépôt vxixv/SELOtec-MRPS (privé) tag v1.1.0
Cat A — Gestion clients & onboarding
Wizard 3 étapes · Utilisateurs · JWT auth
EndpointMéthodeDescription
/api/admin/loginPOSTAuth superadmin → JWT token
/api/admin/clientsGETListe tous les clients avec KPIs (CDR, devices, dernière position)
/api/admin/clients/{homeid}GETFiche client complète
/api/admin/clients/{homeid}/devicesGET/POSTDevices SELOtec GNSS du client (GPS + CDR 30j) · Ajout device
/api/admin/onboardPOSTWizard 3 étapes : Identifier → Provisionner → Résumé
/api/admin/usersGET/POSTGestion utilisateurs MRPS (JWT, rôles client/admin/superadmin)
/api/admin/verify-passwordPOSTVérification bcrypt avant action destructive
Cat B — Organisations & groupes SELOtec GNSS
CRUD atomique · Création simultanée tc_groups + puc_enterprise_mapping + mrps_enterprises
EndpointMéthodeDescription
/api/admin/organisationsGETListe orgs avec stats (devices actifs, CDR, homeid)
/api/admin/organisationsPOSTCréation atomique : tc_groups + puc_enterprise_mapping + mrps_enterprises en une transaction
/api/admin/organisations/{homeid}PUTModification nom / homeid / mapping SELOtec GNSS
/api/admin/organisations/{homeid}DELETESuppression bloquée si devices actifs associés
/api/groupsGETGroupes SELOtec GNSS (avec parent, devices actifs)
/api/groupsPOSTCréation groupe SELOtec GNSS
/api/groups/{id}PUT/DELETERenommage / changement parent / suppression
/api/admin/organisations/{homeid}/scanGETScan devices PUC non mappés (SSE, mode fast/live, auth token)
Scanner PUC FDW — Modes fast & live
Cœur du SCP · Orchestration enregistrement devices
⚡ Mode fast (défaut)
Source : puc_known_devices local
Résultat instantané (<1s)
Données : devices connus depuis dernier scan live
Usage : consultation quotidienne
⬡ Mode live (FDW réel)
Source : gps_location_data_remote via FDW
Fenêtre 90 jours de données PUC
SSE avec messages __step__ intermédiaires
Timeout Nginx dédié 600s
Interface DOS/Matrix rain pendant le scan
Résultats : devices NEW (badge 7j) · devices avec alias à renommer (≤4 chiffres) · bouton [+ADD] / [F2] TOUT AJOUTER
Cat C — Contrôle infrastructure
Crons · Services systemd · Disque · Sans accès SSH
EndpointMéthodeDescription
/api/infra/statusGETÉtat sync PUC, purge osmand, disque, services systemd
/api/infra/sync/togglePOSTActiver / désactiver le cron sync_puc.sh (30s)
/api/infra/sync/runPOSTForce run synchronisation PUC immédiate
/api/infra/purge-osmand/togglePOSTActiver / désactiver la purge nightly osmand
/api/infra/purge-osmand/runPOSTForce run purge osmand immédiate
Audit & Synchronisation
Cohérence PUC ↔ GNSS ↔ MRPS · Journal actions
EndpointDescription
/api/admin/sync-audit?days=7|30|90Audit cohérence 3 systèmes — 100% local (<1s), 800 lignes tc_devices.lastupdate
/api/admin/auditJournal actions superadmin (filtrable par type, date, homeid)
SYNC — PUC actif + mappé GNSS + CDR MRPS
PARTIEL — actif PUC + mappé + sans CDR période
NON_MAPPE — actif PUC, non enregistré GNSS
GNSS_ONLY — mappé GNSS, inactif PUC
ORPHELIN — device GNSS sans client MRPS
Roadmap Cat D–E
Cat D — Gestion utilisateurs MRPS depuis SCP
Création/modification/suppression comptes clients depuis le panel superadmin — en attente migration clouddb
Cat E — Rapports & exports
CDR export CSV/PDF, rapports activité, heatmaps positions par client
MRPS — Relations Clients SELOtec
Interface client · CDR · GPS · Statistiques · Authentification multi-tenant
Rôle dans l'écosystème
MRPS est l'interface client finale de l'écosystème : chaque entreprise cliente accède à son espace dédié (homeid), visualise ses radios GPS sur carte, consulte l'historique CDR, et reçoit des alertes (urgences, positions anormales).

MRPS consomme les données produites par le FDW (positions GPS), enrichies par Nominatim (géocodage), et injectées via ingest.py + enrich_gps.py.
Devices enregistrés
7j
Nouveaux (7 jours)
24h
Nouveaux (24h)
🏢
Clients actifs
38
sur 50 entreprises
📞
CDR total
214K+
📍
Positions géolocalisées
151K+
🚨
Urgences détectées
21
📦
Version API
2.3.0
Architecture technique
# Flux MRPS /mrps/React Vite (frontend) → FastAPI :8090mrps_db (PostgreSQL) ├── mrps_enterprises ← 50 entreprises (homeid, nom, actif) ├── mrps_users ← comptes JWT (client/admin/superadmin) ├── mrps_call_records ← 214K CDR (device_id, durée, coords, priorité) └── mrps_audit_log ← journal actions superadmin (JSONB) # Pipeline données GPS tc_positionsingest.pymrps_call_recordsenrich_gps.pyNominatimcoordonnées nommées # Accès production URL http://197.31.9.21/mrps/ Homeid 00004 (admin client démo) Dépôt vxixv/SELOtec-MRPS (privé) tag v1.1.0
API endpoints clients
EndpointMéthodeDescription
/api/loginPOSTAuth client → JWT (homeid, username, rôle)
/api/devicesGETDevices du client (GPS live, statut, dernière position)
/api/cdrGETJournal d'appels (durée, coordonnées, priorité, urgence)
/api/statsGETStatistiques : appels/jour, durée moyenne, urgences, couverture GPS
/api/positionsGETHistorique positions GPS (filtre device, période)
/api/mapGETDonnées carte : positions actuelles + tracé trajet
Derniers devices enregistrés
Les plus récents en premier
Workflow Hytera complet
# Flux Hytera → SELOtec SOP Interface → org_id 5 chiffres (= homeid MRPS) → Radio alluméeHytalk app → Internet → Hytalk Pro (serveur) ├── PUC (GPS) : device_id 7 chiffres → FDW → tc_positions → MRPS └── clouddb (CDR) : enterprise_id interne ⚠ ≠ homeid (lien non résolu) # État 98 devices Hytalk incompatibles state=10 → PTT OK mais GPS non transmis Cause : version app Hytalk incompatible serveur PUC Correction : upgrade serveur PUC (prévu migration clouddb)
Architecture — Migration CloudDB
Philosophie SQL · Architecture · Infrastructure · Données · Séquence · Jour J — 06/05/2026 02h30
⏰ Jour J : 06/05/2026 02h30
Du relationnel au dimensionnel — un changement de paradigme
Le PUC Hytera fonctionnait sur un modèle relationnel classique (OLTP) : 1 table plate, toutes les radios mélangées, aucun partitionnement. CloudDB adopte un modèle dimensionnel orienté time-series (OLAP) : hypertable TimescaleDB partitionnée sur l'axe temporel, isolation par realm (dimension client), distribution Citus. Ce n'est pas qu'un changement de serveur — c'est un changement de paradigme de stockage.
PUC — Modèle Relationnel (OLTP)
Modèle de stockage
1 table plate dbo.gps_location_data
Toutes les radios mélangées — aucune isolation client
Identifiant device
device_id 12 chars — encodage composite
org(5) + device(7) — pas une vraie dimension
Partitionnement
Aucun — 1 bloc de données, croissance linéaire
Index btree sur device_id + gps_datetime
Indicateur GPS valide
gps_av = 'A' → valide · 'V' → invalide
Convention NMEA inversée propre à HyTalkPro
Timezone
UTC+2 Brussels → décalage +1h vs Tunis
Correction obligatoire à chaque sync
CloudDB — Dimensionnel / Time-Series (OLAP)
Modèle de stockage
51 schémas isolés — 1 par client (realm)
Chaque realm = dimension organisation indépendante
Dimensions
device_id 7 chars — dimension device pure
realm — dimension client (clé de routage inter-schéma)
Axe temporel — TimescaleDB
Hypertable sur gps_datetime
Chunks automatiques 7j · Compression chunks froids · Rétention · Range scans ultra-rapides
Indicateur GPS valide
gps_av = 'V' → valide (inversé vs PUC)
Notre sync gère les deux conventions simultanément
Distribution — Citus
Données réparties sur nœuds workers · Scalabilité horizontale
Africa/Tunis — offset 0 vs notre serveur
Adaptation SELOtec — pont entre les deux modèles
Concept SQLPUC (relationnel)CloudDB (dimensionnel)Adaptation sync
Identifiant device12 chars 0000410000537 chars 1000053RIGHT(remote_uniqueid, 7)
Validité GPSgps_av = 'A'gps_av = 'V'Condition OR dans sync
Namespace clientAbsent (1 schéma dbo)db_[client].selotec.compuc_enterprise_mapping.clouddb_realm
Accès données1 foreign table FDW51 foreign tablesVue UNION ALL gps_location_data_clouddb
Décalage horaireUTC+2 → correction -1hAfrica/Tunis → offset 0Aucune correction dans sync clouddb
PartitionnementAucun (table plate)Hypertable chunks 7jTransparent pour la sync (SELECT standard)
Stack logicielle complète — SELOtec GNSS
6 couches · Terrain → PTT → DB → Sync → Services → UI
COUCHE 1 — TERRAIN · ~800 RADIOS PTT PNC360S×47 P30 / P30L×38 MNC360×29 PNC380×26 PNC460×22 SmartphonesGNSS Client · · · ~800 devices total GPS TCP 46000-48005 · Status TCP 8063-8064 COUCHE 2 — HYTALKPRO PTT SERVER · 197.13.20.164:14005 · AlmaLinux 51 Realms (schémas) db_[client].selotec.com TimescaleDB Hypertable · Chunks 7j · Rétention Citus Distribution horizontale device_info (par schéma) device_id · device_alias · terminal_model · realm FDW PostgreSQL · sync_all_positions_clouddb() · toutes les 2s · UNION ALL 51 tables COUCHE 3 — SELOTEC GNSS SERVER · Ubuntu 22.04 · PostgreSQL local tc_positions ~9GB · 24 mois rétention (contractuel) tc_device_mapping local_id ↔ remote_uniqueid · realm Nominatim local Tunisia PBF · 372K places · :7070 Backup + Monitoring ionice GPG 02h00 · Prometheus/Grafana COUCHE 4 — SERVICES & APPLICATIONS SELOtec GNSS 6.11 :8082 · online/offline JVM OsmAnd heartbeat + filter.zero Geocodage Nominatim onRequest SCP v2.4 API :8091 · JWT · Nginx /scp/ Scanner FDW · CRUD devices Organisations · Cat A-C MRPS v1.5.0 Flask :5000 · Nginx /mrps/ 38 clients · 214K CDR 151K géolocalisés · 24 mois OsmAnd heartbeat filter.zero online/offline Docs site Nginx /docs/ ce dashboard status.json live
Architecture infrastructure — avant / après migration
Réseau · NAT · Serveurs · Ports · Jour J
ANCIEN SERVEUR PUC — DÉCOMMISSIONNÉ 197.13.35.2 · port 5432 NAT interne : 10.0.1.3 OSWindows Server Basepuc · PostgreSQL standard ExtensionsAucune (vanilla PostgreSQL) Structure1 schéma dbo · table plate device_id12 chars (org5+device7) TimezoneUTC+2 Brussels → +1h Tunis gps_av valide'A' (NMEA inversé HyTalk) FDW SELOtecpuc_server → gps_location_data_remote DÉCOMMISSIONNÉ NAT switch 06/05/2026 02h30 197.13.35.3 10.0.1.3 → 10.0.1.4 NOUVEAU SERVEUR CLOUDDB — ACTIF ✅ 197.13.20.164 · port 14005 NAT interne : 10.0.1.4 OSAlmaLinux Baseclouddb · TimescaleDB + Citus ExtensionsTimescaleDB + Citus (distribué) Structure51 schémas db_[client].selotec.com device_id7 chars · RIGHT(remote_uniqueid,7) TimezoneAfrica/Tunis → offset 0 ✓ gps_av valide'V' (les deux gérés par sync) Ports GPSTCP 46000-48005 · Status 8063-8064 ACTIF SELOTEC GNSS SERVER — Ubuntu 22.04 · selotec.codeclub.tn:80 PostgreSQL + SELOtec GNSS FDW clouddb_server (actif post-J) tc_positions · tc_devices · mapping Nominatim :7070 · backup GPG 02h fail2ban · Prometheus/Grafana Nginx Reverse Proxy /docs/ → :8090 (dashboard live) /scp/ → :8091 · /mrps/ → :5000 /nominatim-proxy/ → :7070 Headers CSP · HSTS · X-Frame FDW actif (post-J)
Architecture des données — modèle entité-relation
Tables · Clés · JOIN · FDW · Relations inter-systèmes
CLOUDDB — 197.13.20.164:14005 [realm].gps_location_data HYPERTABLE TS PKguidUUID auto-généré DIMdevice_idVARCHAR(7) ← dimension device TIMEgps_datetimeTIMESTAMPTZ ← axe temporel chunk latitude · longitudeNUMERIC(10,6) speedNUMERIC(5,2) km/h gps_av'V'=valide (≠ PUC où 'A'=valide) stateINTEGER (statut radio PTT) position_errorINTEGER (nouveau champ clouddb) Chunks automatiques 7j · Compression chunks froids · Rétention policy INDEX: (device_id, gps_datetime DESC) — optimisé range scan temporel [realm].device_info PKdevice_id VARCHAR(7)device_alias · terminal_model realm · has_gpsenable_gps ← non fiable firmware puc_enterprise_mapping · traccar_group_id ↔ clouddb_realm · 20/51 mappés SELOTEC GNSS DB (traccar) clouddb.[realm_slug] — 51 foreign tables (FDW) server: clouddb_server · user: selotec_gps_user · miroir gps_location_data FDW link VIEW public.gps_location_data_clouddb UNION ALL 51 foreign tables → source unique sync tc_positions PKid BIGSERIAL~9 GB · 24 mois (contractuel) FKdeviceid → tc_devices.id fixtime · latitude · longitude · speed protocol · address · attributes protocol = 'osmand' ou 'clouddb' sync_all_positions_clouddb() tc_device_mapping local_device_id ↔ remote_uniqueid clouddb_realm · alias tc_devices id · name · groupId lastUpdate · positionId CLÉ JOIN inter-systèmes RIGHT(tc_device_mapping.remote_uniqueid, 7) = clouddb.gps_location_data.device_id LÉGENDE PK Clé primaire FK Clé étrangère DIM Dimension TIME Axe temporel hypertable FDW (Foreign Data Wrapper) TimescaleDB hypertable : partitionnement automatique sur gps_datetime, index BRIN optimisé, compress cold chunks Citus : sharding horizontal des données par device_id sur workers — transparent pour nos SELECT standards
Diagramme de séquence — flux GPS complet
Radio → HyTalkPro → FDW → GNSS → Applications · 13 étapes
Radio PTT HyTalkPro CloudDB FDW/Cron sync 2s SELOtec GNSS DB tc_positions GNSS UI Server OsmAnd heartbeat SCP / MRPS applications GPS data (TCP 46000-48005) INSERT [realm].gps_location_data · gps_av='V' · device_id 7ch · chunk auto Status online/offline (TCP 8063-8064) cron 2s sync_all_positions_clouddb() déclenché par crontab SELECT gps_location_data_clouddb (UNION ALL 51) rows nouvelles positions (batch ~2s) JOIN RIGHT(remote_uniqueid,7)=device_id INSERT tc_positions (fixtime, lat, lon, speed, protocol='clouddb') heartbeat (filter.zero · lat=0,lon=0 · 60s) UPDATE statut online/offline · lastUpdate en mémoire JVM Traccar geocode Nominatim local onRequest · reuseDistance 100m · :7070 SCP: SELECT tc_device_mapping · tc_groups · tc_devices MRPS: SELECT tc_positions WHERE deviceid IN (…) 24 mois LÉGENDE Push terrain Sync FDW/SQL GNSS interne Lecture applicative Réponse callback TIMING GLOBAL Radio → CloudDB : <1s (push direct TCP) · CloudDB → tc_positions : ~2s (cron batch) · OsmAnd heartbeat : 60s Latence totale Radio → GNSS UI : 2-4s · Nominatim geocodage : onRequest, pas de délai sync SÉQUENCE JOUR J — 06/05/2026 02h30 ① pg_dump backup · ② Arrêt cron sync · ③ Hytera switch NAT 10.0.1.3→10.0.1.4 (~30s coupure radios) ④ sudo -u postgres psql -d traccar -f migration_hytalkpro_clouddb_jourj.sql · ⑤ Test device 1000053 · ⑥ Réactivation cron
Rapport & Documentation
Architecture · Chronologie · Problèmes · Changelog · Roadmap · Synthèse
Paramètres du projet
ParamètreValeur
Flux de données
Objets SQL
Chronologie du projet
Composants installés
Mises à jour techniques
État opérationnel des composants
🇫🇷 Synthèse finale

🇬🇧 Executive Summary

Réalisations
🏗 Architecture CloudDB
Architecture PUC → CloudDB · Jour J — 06/05/2026 02h30

Documentation complète de la migration vers CloudDB (51 schémas, Citus + TimescaleDB) :

  • Architecture PUC (ancien) vs CloudDB (nouveau)
  • Concept Realm : identification du schéma client dans clouddb
  • Adaptation FDW : foreign server + 51 tables + vue UNION ALL
  • Ports : 8063/8064/46000-48005/14005
  • Séquence Jour J — bascule automatique en 5 étapes