V0.2.0 — API Site, auth et Caméras
Publiée le 01/10/2026.
Documentation fonctionnelle
Ce que change la version pour les collaborateurs
Pourquoi
Après la 0.1.0, les Flux simulés existaient mais le Site ne connaissait aucune Caméra : rien pour en déclarer, savoir lesquelles répondent, ni protéger cet accès. Il manquait aussi une API sur laquelle brancher l'UI de la 0.3.0.
Ce qu'on peut faire maintenant
- Lancer l'API du Site (FastAPI + PostgreSQL) avec le même
docker compose up -d --wait; le schéma s'applique tout seul au démarrage, la base n'est pas exposée. - Se connecter en tant qu'Administrateur (compte local défini dans
.env), consulter/api/moi, se déconnecter. Les sessions survivent à un redémarrage, expirent après 24 h, tombent si le mot de passe change ; 5 échecs en 15 min bloquent la connexion (429). - Créer, lire, modifier, désactiver puis supprimer des Caméras (nom, URL RTSP, emplacement), avec le mot de passe RTSP masqué dans toutes les réponses.
- Voir l'état de chaque Caméra active (
unknown/online/offline), déterminé par une sonde RTSP de fond toutes les 10 s. - Suivre le protocole de lancement pas à pas du README ; les limites de sécurité sont décrites dans
docs/securite.md.
Documentation technique
Spec versionnée : docs/specs/v0.2.0-api-site-auth-cameras.md
Issue parente : #6
V0.2.0 — API Site, auth et Caméras
Problem Statement
Le Site ne connaît encore aucune Caméra : les Flux simulés de la 0.1.0 existent, mais rien ne permet de déclarer des Caméras, de savoir lesquelles répondent, ni de protéger cet accès. L'Administrateur n'a pas d'API sur laquelle brancher l'UI de la 0.3.0, et rien ne lui dit qu'une Caméra a décroché.
Solution
Une API du Site (FastAPI + PostgreSQL), lancée par le même docker compose, protégée par le compte local de l'Administrateur défini dans .env. L'Administrateur se connecte, crée, lit, modifie, désactive puis supprime des Caméras (nom, URL RTSP, emplacement). L'API sonde en tâche de fond chaque Caméra active et expose son état unknown / online / offline. Les choix de sécurité et leurs limites sont écrits dans un document dédié pour ne pas être oubliés avant de brancher de vraies caméras.
User Stories
Stack
- En tant que développeur, je veux que
docker compose up -d --waitlance aussi l'API et sa base, pour tout démarrer d'une commande. - En tant que développeur, je veux que l'image PostgreSQL soit épinglée, pour que la stack ne change pas toute seule.
- En tant que développeur, je veux que le schéma de base soit appliqué automatiquement au démarrage de l'API (migrations), pour qu'un clone neuf fonctionne sans étape manuelle.
- En tant que développeur, je veux que les données survivent à un
docker compose down/up, pour ne pas ressaisir mes Caméras. - En tant qu'Administrateur, je veux que PostgreSQL ne soit pas joignable depuis le réseau local, pour qu'une machine du réseau (ou une caméra compromise) ne puisse pas lire la base.
- En tant que développeur, je veux la documentation OpenAPI sur
/api/docs, pour explorer l'API sans lire le code.
Administrateur et connexion
- En tant qu'Administrateur, je veux définir mon identifiant et mon mot de passe dans
.env(ARGOS_IDENTIFIANT,ARGOS_MOT_DE_PASSE), pour qu'aucun secret ne soit dans git. - En tant qu'Administrateur, je veux que l'API refuse de démarrer si l'une de ces variables manque, avec un message clair, pour qu'il n'existe jamais de compte par défaut.
- En tant qu'Administrateur, je veux me connecter avec mon identifiant et mon mot de passe et recevoir un cookie de session
HttpOnly, pour accéder à l'API. - En tant qu'Administrateur, je veux qu'un mauvais identifiant ou mot de passe renvoie
401sans dire lequel est faux, pour ne pas aider un attaquant. - En tant qu'Administrateur, je veux consulter qui est connecté (
GET /api/moi), pour que l'UI sache si la session est valide. - En tant qu'Administrateur, je veux me déconnecter, pour que la session soit révoquée côté serveur.
- En tant qu'Administrateur, je veux qu'une session expire 24 h après la connexion, sans prolongation, pour limiter la durée d'un cookie volé.
- En tant qu'Administrateur, je veux que toutes les sessions ouvertes soient invalidées quand je change le mot de passe dans
.envpuis redémarre, pour couper un accès compromis. - En tant qu'Administrateur, je veux que toute route des Caméras renvoie
401sans session valide, pour que rien ne fuite sans connexion. - En tant qu'Administrateur, je veux qu'après 5 échecs de connexion en 15 min la connexion réponde
429pendant 15 min, pour freiner la force brute depuis le réseau local. - En tant qu'Administrateur, je veux que les sessions survivent à un redémarrage de l'API (hors changement de mot de passe), pour ne pas être déconnecté à chaque mise à jour.
Caméras
- En tant qu'Administrateur, je veux créer une Caméra avec un nom, une URL RTSP et un emplacement facultatif, pour que le Site la connaisse.
- En tant qu'Administrateur, je veux que le nom soit obligatoire et unique, pour distinguer les Caméras.
- En tant qu'Administrateur, je veux que l'URL soit obligatoire, unique et en
rtsp://, pour ne pas déclarer deux fois la même Caméra ni une URL invalide. - En tant qu'Administrateur, je veux un
409en cas de doublon de nom ou d'URL, et un422pour une URL invalide, pour comprendre le refus. - En tant qu'Administrateur, je veux lister toutes les Caméras (actives et désactivées), pour avoir la vue d'ensemble du Site.
- En tant qu'Administrateur, je veux lire une Caméra, pour voir ses informations et son état.
- En tant qu'Administrateur, je veux voir l'hôte et le port dérivés de l'URL, pour connaître ses infos réseau sans les ressaisir.
- En tant qu'Administrateur, je veux pouvoir écrire les identifiants RTSP dans l'URL (
rtsp://user:motdepasse@ip/...), parce que la plupart des vraies caméras l'exigent. - En tant qu'Administrateur, je veux que l'API masque le mot de passe RTSP dans toutes ses réponses (
rtsp://user:***@ip/...), pour qu'il ne s'affiche pas à l'écran ni dans les logs du navigateur. - En tant qu'Administrateur, je veux que renvoyer l'URL masquée telle quelle lors d'une modification conserve le mot de passe stocké, pour modifier le nom ou l'emplacement sans ressaisir le mot de passe.
- En tant qu'Administrateur, je veux modifier le nom, l'URL ou l'emplacement d'une Caméra, pour corriger une erreur.
- En tant qu'Administrateur, je veux qu'un changement d'URL remette l'état à
unknown, pour ne pas afficher l'état de l'ancienne adresse. - En tant qu'Administrateur, je veux désactiver une Caméra, pour que le Site la connaisse encore mais ne la surveille plus.
- En tant qu'Administrateur, je veux réactiver une Caméra désactivée, pour reprendre sa surveillance.
- En tant qu'Administrateur, je veux qu'une Caméra désactivée garde son nom et son URL réservés, pour éviter un doublon à sa réactivation.
- En tant qu'Administrateur, je veux supprimer définitivement une Caméra désactivée (
204), pour nettoyer le Site. - En tant qu'Administrateur, je veux que la suppression d'une Caméra active soit refusée (
409), pour éviter une suppression accidentelle. - En tant qu'Administrateur, je veux un
404sur une Caméra inexistante, pour distinguer « absente » de « refusée ».
État
- En tant qu'Administrateur, je veux voir l'état
unknown/online/offlinede chaque Caméra, pour savoir d'un coup d'œil laquelle a décroché. - En tant qu'Administrateur, je veux voir quand l'état a été vérifié pour la dernière fois (
etat_verifie_le), pour savoir si l'information est fraîche. - En tant qu'Administrateur, je veux qu'une Caméra soit
onlineseulement si au moins un paquet vidéo a été reçu d'elle, parce que « on reçoit du flux » est la définition d'une Caméra active. - En tant qu'Administrateur, je veux qu'une Caméra qui ne livre aucun paquet vidéo en 5 s passe
offlinedès la première sonde ratée, pour être prévenu sans délai. - En tant qu'Administrateur, je veux que chaque Caméra active soit sondée toutes les 10 s, pour que l'état suive la réalité.
- En tant qu'Administrateur, je veux régler l'intervalle et le délai de sonde dans
.env, pour les adapter à mon réseau. - En tant qu'Administrateur, je veux qu'une Caméra nouvelle soit
unknowntant qu'elle n'a pas été sondée, pour ne pas afficher un état inventé. - En tant qu'Administrateur, je veux qu'une Caméra désactivée ne soit plus sondée et soit
unknown, pour ne pas consommer une connexion sur une caméra qu'on ne surveille plus. - En tant que développeur, je veux qu'une Caméra simulée déclarée avec
rtsp://mediamtx:8554/cam1passeonline, pour vérifier la sonde sans matériel.
Documentation
- En tant que développeur, je veux que le glossaire définisse Site, Administrateur et Caméra désactivée, pour parler le même langage.
- En tant que développeur, je veux un document de sécurité (
docs/securite.md, rôlesecurity) qui explique ce que prouve l'état d'une Caméra (et le scénario de rejeu de flux), l'exposition réseau dans une installation type et les dettes connues, pour ne pas oublier ces limites avant de brancher de vraies caméras. - En tant que développeur, je veux que la feuille de route dise que les identifiants RTSP sont stockés en clair pour l'instant, et liste en « Plus tard » : chiffrement des identifiants RTSP, HTTPS, authentification des Flux MediaMTX, accès distant par VPN, détection de Flux figé ou rejoué.
- En tant que développeur, je veux une contrainte transverse dans la feuille de route : pas d'installation sur de vraies caméras avant HTTPS et authentification des Flux.
- En tant que nouveau venu, je veux que le README explique
.env(identifiants), comment lancer l'API, comment ajouter les trois Caméras simulées aveccurl(URLrtsp://mediamtx:8554/camNet pourquoi), comment tester, et la nouvelle structure.
Implementation Decisions
- Site : une installation d'ArgOS. Un seul Site par installation ; ce n'est pas une ressource de l'API.
- Stack : deux services rejoignent la stack Compose existante :
api(Python ≥ 3.12, FastAPI, uv) etdb(PostgreSQL, image épinglée, aucun port publié, volume nommé). Migrations Alembic appliquées au démarrage deapi.apipublie le port 8000 sur toutes les interfaces. MediaMTX inchangé. - Administrateur : compte unique, identifiant et mot de passe lus dans l'environnement (
.env). Absence de l'une des variables → l'API ne démarre pas. Comparaison du mot de passe à temps constant ; rien n'est haché ni stocké, puisque la source est.env..env.exampledocumente les clés et recommande un mot de passe long. - Sessions : jeton aléatoire opaque dans un cookie
HttpOnly,SameSite=Lax(pasSecuretant qu'il n'y a pas de HTTPS). Session stockée en base, durée absolue de 24 h, sans prolongation. Chaque session garde une empreinte du mot de passe en vigueur à sa création : si le mot de passe de.envchange, toutes les sessions existantes sont refusées. Déconnexion = suppression de la session. - Frein à la force brute : compteur global en mémoire (un seul compte). 5 échecs dans une fenêtre de 15 min →
429sur la connexion pendant 15 min. Remis à zéro au redémarrage. - Horloge et configuration injectables dans l'application, pour que les règles temporelles (expiration, fenêtre du
429) et de configuration (changement de mot de passe) soient testables sans attendre. - Contrat HTTP (JSON, erreurs FastAPI standard
\{"detail": ...\}) :POST /api/session\{identifiant, mot_de_passe\}→204+ cookie ;401;429.DELETE /api/session→204.GET /api/moi→\{identifiant\};401.GET /api/cameras→ liste ;POST /api/cameras\{nom, url_rtsp, emplacement?\}→201.GET /api/cameras/\{id\};PATCH /api/cameras/\{id\}(champs partiels, dontactive) ;DELETE /api/cameras/\{id\}→204,409si active.- Représentation d'une Caméra :
id,nom,url_rtsp(mot de passe masqué),emplacement,hote,port,active,etat,etat_verifie_le.
- Règles Caméra : nom et URL uniques (y compris parmi les désactivées) →
409. URL enrtsp://avec hôte → sinon422. Port par défaut 554 si absent de l'URL. URL renvoyée masquée inchangée enPATCH→ mot de passe stocké conservé. Changement d'URL →etat = unknown,etat_verifie_le = null. Désactivation →etat = unknown, plus de sonde. Suppression définitive. - Identifiants RTSP stockés en clair dans la base pour la 0.2.0 ; masqués dans toutes les réponses. Dette consignée (feuille de route + document de sécurité).
- Sonde d'état : boucle de fond dans le processus
api, toutes les 10 s (.env), sondes en parallèle. Une sonde = session RTSPDESCRIBE/SETUP/PLAY(identifiants de l'URL pris en charge), réception d'au moins un paquet RTP vidéo dans le délai (5 s,.env), puisTEARDOWN. Succès →online, sinon →offline, horodaté. Pas d'hystérésis. Pas de ffmpeg dans l'imageapi. Un module de sonde à interface étroite (une URL et un délai en entrée, vrai/faux en sortie). - MediaMTX : pas de pilotage par l'API en 0.2.0. Le choix MediaMTX pont / simulateur est reporté à la 0.3.0. Depuis le conteneur
api, les Caméras simulées se déclarent avecrtsp://mediamtx:8554/camN. - Base vide au démarrage : aucune Caméra pré-enregistrée.
- Glossaire (
CONTEXT.md) :- Site : une installation d'ArgOS : les Caméras qu'elle connaît et l'Administrateur qui la gère.
- Administrateur : personne qui se connecte au Site avec le compte local pour gérer les Caméras. Avoid : admin, utilisateur, opérateur. (« Administrateur système » n'entre au glossaire que lorsque ce rôle existera dans le produit.)
- Caméra désactivée : Caméra que le Site connaît encore mais ne surveille plus.
- Document de sécurité
docs/securite.md, nouveau rôlesecuritydansagents/roles.yml: (1) ce que prouve l'état d'une Caméra : un paquet vidéo reçu, pas l'authenticité ; scénario de rejeu / injection de flux et défenses (VLAN, auth RTSP / RTSPS, détection d'image figée ou en boucle, événements ONVIF de sabotage) ; (2) exposition réseau dans l'installation type (serveur sur site, caméras, Wi-Fi, accès internet futur) : pourquoi PostgreSQL n'est pas exposé, Docker qui contourne le pare-feu de l'hôte, caméras comme maillon faible, Flux MediaMTX sans auth, API en HTTP, VPN plutôt que redirection de port / UPnP ; (3) dettes connues : identifiants RTSP en clair, pas de HTTPS, Flux sans auth. Le README y renvoie. - Feuille de route : section 0.2.0 complétée (identifiants RTSP en clair, masqués en sortie) ; contrainte transverse « pas d'installation sur de vraies caméras avant HTTPS et authentification des Flux » ; entrées « Plus tard » : chiffrement des identifiants RTSP, HTTPS, authentification des Flux MediaMTX, accès distant par VPN, détection de Flux figé ou rejoué.
- Rôle
test-roots: ajout des deux nouvelles racines de tests (HTTP et en processus). - Pas d'ADR : aucune décision ne remplit à la fois « difficile à défaire », « surprenante » et « vrai compromis ».
Testing Decisions
- Seam principal : HTTP contre la stack lancée, comme les tests de Flux de la 0.1.0 (prior art : la racine de tests des Flux, fixture de session qui lance
docker compose up -d --wait). Couvre : refus sans session (401), connexion /moi/ déconnexion, mauvais identifiants, CRUD complet,409doublons,422URL invalide, masquage du mot de passe et conservation enPATCH, hôte / port dérivés, désactivation / réactivation, suppression refusée si active,404,unknownà la création,onlinepourrtsp://mediamtx:8554/cam1,offlinepour une URL injoignable,429après 5 échecs. - Second seam, étroit : l'application en processus (FastAPI monté en mémoire, horloge et configuration injectées, base PostgreSQL de test). Uniquement pour les règles impossibles à tester vite en HTTP : expiration à 24 h, fin du
429après 15 min, invalidation des sessions au changement de mot de passe, refus de démarrer sans identifiants. - Les tests HTTP n'effacent jamais la base : chaque test crée ses Caméras avec des noms uniques puis les désactive et les supprime. Le test du
429remet l'API dans un état propre (redémarrage deapiou ordre d'exécution, à trancher au ticket). - Identifiants des tests lus dans
.env; s'ils manquent, échec immédiat avec un message qui dit quoi ajouter. Pas de compte de test caché. - Un bon test vérifie un comportement observable (réponse HTTP, état d'une Caméra), pas la forme des tables ni la commande RTSP envoyée.
/tlance toutes les racines detest-roots.
Out of Scope
- UI (0.3.0), pilotage de MediaMTX par l'API, choix MediaMTX pont / simulateur, WebRTC vs HLS.
- Plusieurs comptes, rôles, gestion des comptes par l'API, Administrateur système.
- HTTPS, cookie
Secure, chiffrement des identifiants RTSP, authentification des Flux MediaMTX, accès distant / VPN. - Hystérésis de l'état, historique des états, événements, alertes, détection de Flux figé ou rejoué.
- Archivage des Caméras supprimées.
- Enregistrement, IA, ONVIF, PTZ, codecs autres que H.264.
- CI GitHub Actions ; analyse SonarCloud par Automatic Analysis (comme BBASS), pas de scanner CI.
Further Notes
onlinesignifie « un paquet vidéo a été reçu », pas « c'est la vraie caméra » : voir le document de sécurité.- Sur Mac / Docker Desktop, la sonde vers MediaMTX passe par le réseau Compose interne (
mediamtx), pas parlocalhost. - Contexte : feuille de route de dev (section 0.2.0), spec 0.1.0, contexte initial.