Backend¶
Introduction¶
Le backend de Diyae est développé avec Fastify, un framework Node.js performant et moderne. Il gère l'ensemble de l'API REST, la communication MQTT avec les enceintes, et la planification automatique des adhans.
Ports utilisés¶
- Port 3010 : API REST Fastify (définissable via
PORTdans.env) - Port 1883 : Broker MQTT pour la communication avec les enceintes (définissable via
MQTT_BROKER_PORT)
Architecture technique¶
Le projet est organisé selon une structure modulaire :
/config # Configuration base de données et environnement
/controllers # Logique métier des routes API
/model # Modèles Sequelize (ORM)
/mqtt # Broker et gestion MQTT
/services # Services métier (Adhan, etc.)
/utils # Utilitaires divers
/middleware # Middlewares (auth, etc.)
Sécurité et middlewares¶
Le backend utilise plusieurs couches de sécurité :
- Helmet : Protection contre les vulnérabilités web courantes
- Rate limiting : 100 requêtes par minute maximum
- CORS : Configuration pour les appels cross-origin
- JWT Authentication : Authentification par token pour les routes protégées
Routes API¶
🏥 Health Check¶
GET /health¶
Vérification de l'état du serveur.
Réponse :
{
"status": "OK",
"timestamp": "2024-01-15T10:30:00.000Z",
"uptime": 12345.67
}
📚 Gestion des contenus (Content)¶
GET /api/contents¶
Récupérer tous les contenus avec pagination et filtres.
Query Parameters :
- page (optionnel) : Numéro de page (défaut: 1)
- limit (optionnel) : Nombre d'éléments par page (défaut: 20)
- category_id (optionnel) : Filtrer par catégorie
- type (optionnel) : Filtrer par type (audio, video, pdf, live)
- search (optionnel) : Recherche textuelle
Exemple :
GET /api/contents?page=1&limit=20&category_id=1&type=audio&search=coran
GET /api/contents/:id¶
Récupérer un contenu spécifique par son ID.
POST /api/contents¶
Créer un nouveau contenu.
Body :
{
"type": "audio",
"category_id": 1,
"title": "Sourate Al-Fatiha",
"description": "Récitation de la sourate Al-Fatiha",
"language": "ar",
"author": "Sheikh Mishary",
"media_url": "https://...",
"thumbnail_url": "https://...",
"duration_ms": "180000",
"visibility": "public"
}
PUT /api/contents/:id¶
Modifier un contenu existant.
DELETE /api/contents/:id¶
Supprimer un contenu.
GET /api/contents/stats¶
Obtenir les statistiques des contenus (nombre total, par type, etc.).
📁 Gestion des catégories (Category)¶
GET /api/categories¶
Récupérer toutes les catégories avec pagination et filtres.
Query Parameters :
- page (optionnel) : Numéro de page
- limit (optionnel) : Nombre d'éléments par page
- search (optionnel) : Recherche textuelle
- with_content_count (optionnel) : Inclure le nombre de contenus
Exemple :
GET /api/categories?page=1&limit=20&search=coran&with_content_count=true
GET /api/categories/search¶
Rechercher des catégories (auto-complétion).
Query Parameters :
- q : Terme de recherche
- limit : Nombre de résultats (défaut: 5)
Exemple :
GET /api/categories/search?q=cor&limit=5
GET /api/categories/stats¶
Obtenir les statistiques des catégories.
GET /api/categories/:id¶
Récupérer une catégorie par ID.
Query Parameters :
- with_contents (optionnel) : Inclure les contenus de la catégorie
POST /api/categories¶
Créer une nouvelle catégorie.
PUT /api/categories/:id¶
Modifier une catégorie existante.
DELETE /api/categories/:id¶
Supprimer une catégorie.
Query Parameters :
- force (optionnel) : Forcer la suppression même si elle contient des contenus
📺 Gestion des séries (Series)¶
GET /api/series¶
Récupérer toutes les séries avec pagination et filtres.
Query Parameters :
- page (optionnel) : Numéro de page
- limit (optionnel) : Nombre d'éléments par page
- search (optionnel) : Recherche textuelle
- with_episode_count (optionnel) : Inclure le nombre d'épisodes
- with_latest_episode (optionnel) : Inclure le dernier épisode
Exemple :
GET /api/series?page=1&limit=20&search=prophete&with_episode_count=true
GET /api/series/search¶
Rechercher des séries (auto-complétion).
Exemple :
GET /api/series/search?q=proph&limit=5
GET /api/series/stats¶
Obtenir les statistiques des séries.
GET /api/series/:id¶
Récupérer une série par ID.
Query Parameters :
- with_episodes (optionnel) : Inclure les épisodes
- episodes_limit (optionnel) : Limiter le nombre d'épisodes retournés
POST /api/series¶
Créer une nouvelle série.
PUT /api/series/:id¶
Modifier une série existante.
DELETE /api/series/:id¶
Supprimer une série.
Query Parameters :
- force (optionnel) : Forcer la suppression même si elle contient des épisodes
PUT /api/series/:id/episodes/reorder¶
Réorganiser l'ordre des épisodes d'une série.
Body :
{
"episodes": [
{ "id": 1, "order": 1 },
{ "id": 2, "order": 2 }
]
}
🔐 Authentification et utilisateurs¶
POST /api/auth/register¶
Inscription d'un nouvel utilisateur.
Body :
{
"email": "user@example.com",
"password": "SecurePassword123",
"locale": "fr",
"timezone": "Europe/Paris"
}
POST /api/auth/login¶
Connexion utilisateur.
Body :
{
"email": "user@example.com",
"password": "SecurePassword123"
}
Réponse :
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"email": "user@example.com"
}
}
GET /api/auth/me 🔒¶
Récupérer le profil de l'utilisateur connecté.
Headers requis :
Authorization: Bearer <token>
PUT /api/auth/profile 🔒¶
Mettre à jour le profil utilisateur.
Headers requis :
Authorization: Bearer <token>
Body :
{
"locale": "en",
"timezone": "America/New_York"
}
PUT /api/auth/password 🔒¶
Changer le mot de passe.
Headers requis :
Authorization: Bearer <token>
Body :
{
"current_password": "OldPassword123",
"new_password": "NewPassword456"
}
GET /api/auth/speakers 🔒¶
Récupérer les enceintes de l'utilisateur connecté.
Headers requis :
Authorization: Bearer <token>
POST /api/auth/claim-device 🔒¶
Associer une enceinte à l'utilisateur connecté.
Headers requis :
Authorization: Bearer <token>
Body :
{
"device_id": "DY-ABC123"
}
📱 Gestion des appareils (Devices)¶
POST /api/devices/register 🔒¶
Enregistrement d'un nouveau device (appelé par l'app avec token utilisateur).
Headers requis :
Authorization: Bearer <token>
Body :
{
"device_id": "DY-ABC123",
"serial": "SN-001",
"model": "DiyaeSpeaker",
"hw_rev": "A",
"fw_version": "1.0.0",
"provision_method": "AP"
}
GET /api/devices/unclaimed¶
Liste des devices non associés à un utilisateur (admin/debug).
GET /api/devices/:device_id/state 🔒¶
Obtenir l'état temps réel d'une enceinte.
Headers requis :
Authorization: Bearer <token>
Réponse :
{
"success": true,
"device_id": "DY-ABC123",
"online": true,
"volume": 50,
"is_playing": true,
"playing_src": "https://example.com/audio.mp3",
"position_ms": 45000,
"battery_pct": 85,
"wifi_rssi": -57,
"last_seen": "2024-01-15T10:30:00.000Z",
"updated_at": "2024-01-15T10:30:00.000Z"
}
🔊 Contrôle audio des enceintes¶
Toutes ces routes nécessitent une authentification JWT.
POST /api/audio/:device_id/play 🔒¶
Lancer la lecture audio sur une enceinte.
Headers requis :
Authorization: Bearer <token>
Body :
{
"url": "https://example.com/audio.mp3",
"title": "Sourate Al-Fatiha"
}
POST /api/audio/:device_id/pause 🔒¶
Mettre en pause la lecture.
Headers requis :
Authorization: Bearer <token>
POST /api/audio/:device_id/stop 🔒¶
Arrêter la lecture.
Headers requis :
Authorization: Bearer <token>
POST /api/audio/:device_id/volume 🔒¶
Changer le volume de l'enceinte.
Headers requis :
Authorization: Bearer <token>
Body :
{
"volume": 75
}
POST /api/audio/:device_id/seek 🔒¶
Changer la position dans l'audio en cours.
Headers requis :
Authorization: Bearer <token>
Body :
{
"position_ms": 60000
}
GET /api/audio/:device_id/status 🔒¶
Obtenir le statut des commandes envoyées.
Headers requis :
Authorization: Bearer <token>
🕌 Gestion des horaires de prière (Adhan)¶
Toutes ces routes nécessitent une authentification JWT.
GET /api/adhan/:device_id 🔒¶
Récupérer la configuration Adhan d'une enceinte.
Headers requis :
Authorization: Bearer <token>
PUT /api/adhan/:device_id 🔒¶
Mettre à jour la configuration Adhan d'une enceinte.
Headers requis :
Authorization: Bearer <token>
Body :
{
"enabled": true,
"latitude": 48.8566,
"longitude": 2.3522,
"calculation_method": "MWL",
"prayers": {
"fajr": true,
"dhuhr": true,
"asr": true,
"maghrib": true,
"isha": true
}
}
DELETE /api/adhan/:device_id 🔒¶
Supprimer la configuration Adhan d'une enceinte.
Headers requis :
Authorization: Bearer <token>
GET /api/adhan 🔒¶
Lister toutes les configurations Adhan de l'utilisateur.
Headers requis :
Authorization: Bearer <token>
POST /api/adhan/update-all¶
Déclencher manuellement la mise à jour des horaires de prière pour tous les devices (admin/debug).
Réponse :
{
"success": true,
"message": "Mise à jour des horaires terminée",
"data": {
"updated": 5,
"failed": 0
}
}
🛰️ Communication MQTT¶
Le backend intègre un broker MQTT et un client MQTT pour communiquer en temps réel avec les enceintes.
Topics MQTT utilisés¶
Envoi (Server → Device)¶
diyae/{device_id}/ping: Envoi de ping pour vérifier la connexiondiyae/{device_id}/cmd: Envoi de commandes (play, pause, volume, etc.)
Réception (Device → Server)¶
diyae/{device_id}/ack: Accusé de réception des commandesdiyae/{device_id}/state: État complet de l'enceintediyae/{device_id}/register: Enregistrement automatique device-userdiyae/{device_id}/pong: Réponse au ping avec état de lecturediyae/broadcast/sync: Messages globaux (maintenance, sync, etc.)
Système Ping/Pong¶
Le backend vérifie automatiquement le statut de connexion des enceintes :
- Ping envoyé : toutes les 15 secondes
- Timeout offline : 1 minute sans réponse
- Mise à jour automatique : Statut
online/offlinedans la base de données
Lorsqu'une enceinte ne répond plus :
- Son statut passe à online: false
- L'état de lecture est vidé (is_playing: false, playing_src: null)
- Un log d'alerte est généré
📊 Architecture des commandes¶
Toutes les commandes envoyées aux enceintes suivent ce flux :
- Requête API : L'utilisateur envoie une commande via l'API REST
- Vérification : Le serveur vérifie que l'utilisateur possède l'enceinte
- Enregistrement : La commande est enregistrée dans
device_cmdavec statutsent - Publication MQTT : La commande est publiée sur
diyae/{device_id}/cmd - Accusé de réception : L'enceinte répond sur
diyae/{device_id}/ack - Mise à jour : Le statut de la commande passe à
okouerror
Cette architecture permet : - Un suivi complet de toutes les commandes - Une gestion des erreurs robuste - Un historique pour le debug
🔧 Services automatiques¶
AdhanService¶
Le service AdhanService gère automatiquement :
- Calcul des horaires de prière selon la localisation
- Planification des adhans pour chaque enceinte configurée
- Mise à jour quotidienne des horaires
- Envoi automatique de la commande de lecture à l'heure de la prière
Le service se déclenche automatiquement au démarrage du serveur.
🔐 Notes sur l'authentification¶
Le symbole 🔒 indique les routes protégées nécessitant un token JWT.
Pour utiliser ces routes :
- Obtenir un token via
/api/auth/login - Inclure le token dans le header :
Authorization: Bearer <votre_token>
Le token contient les informations de l'utilisateur (id, email) et est vérifié à chaque requête protégée.