Mode hors ligne
API prête, mobile à faire Cette page décrit le fonctionnement prévu côté mobile. L'API a déjà tout ce qu'il faut (voir plus bas).
Le sujet demande deux choses :
- un mode hors ligne avec synchronisation automatique (stockage local ou SQLite) ;
- une explication de comment fonctionne le pointage hors ligne.
Aujourd'hui
| Situation | Comportement actuel |
|---|---|
| Ouvrir un écran sans réseau | « Serveur injoignable ». Si l'écran avait déjà chargé ses données, useQuery les garde affichées. |
| Pointer sans réseau | Le pointage échoue, rien n'est enregistré. |
| Session | Gardée : une erreur réseau ne déconnecte jamais. |
Le principe
Le téléphone ne refuse jamais un pointage. Sans réseau, il l'enregistre localement avec l'heure du geste, puis l'envoie dès que le réseau revient.
Étape par étape
1. Détecter le réseau
Avec @react-native-community/netinfo, l'app sait à tout moment si elle est connectée. Un bandeau « Hors ligne » s'affiche en haut de l'écran.
2. Garder les données lues
Chaque réponse de lecture est enregistrée localement. Sans réseau, useQuery affiche la dernière version connue au lieu d'une erreur. L'historique, l'équipe et le tableau de bord restent lisibles.
3. Mettre les pointages en file d'attente
Sans réseau, un pointage (arrivée, départ, début ou fin de pause) est enregistré dans une file locale avec :
- l'utilisateur ;
- l'action ;
- l'heure exacte du téléphone ;
- un identifiant unique (pour ne jamais l'envoyer deux fois).
L'écran réagit tout de suite comme si le pointage était parti : statut, chrono, frise. Le bandeau indique « 1 pointage en attente ».
4. Synchroniser
Dès que le réseau revient (et à chaque ouverture de l'app) :
- les pointages sont envoyés dans l'ordre où ils ont été faits ;
- chaque pointage accepté est retiré de la file ;
- un pointage qui échoue reste dans la file, et l'app réessaie plus tard ;
- une fois la file vide, tout est rechargé depuis le serveur et le bandeau disparaît.
Ce que l'API sait faire maintenant
L'équipe backend a ajouté tout ce qu'il faut au mode hors ligne (pull requests #162 à #166, fusionnées dans main). Il ne reste qu'à l'utiliser côté mobile.
| Besoin | Ce que l'API propose | Commit |
|---|---|---|
| Garder l'heure réelle du geste | POST /clocks/:id et /break acceptent un champ time (ISO 8601) : jamais dans le futur (1 minute de tolérance), au plus 72 h en arrière, jamais avant le dernier pointage, jamais dans une semaine validée. Le serveur note aussi quand il l'a reçu (received_at). | a789c7e |
| Ne jamais inverser un pointage renvoyé | Une action explicite (in / out, start / end) et un client_id (un UUID créé par le téléphone). Le même client_id renvoyé ne change rien et rend ce qui a été enregistré. Une action qui ne correspond pas à l'état répond 409 avec un code (already_clocked_in, not_clocked_in...). | 41acb76 |
| Ne pas créer deux fois une demande de correction | POST /corrections accepte aussi un client_id | 5e4f03b |
| Rester connecté sur un mauvais réseau | POST /auth/login avec "client": "mobile" renvoie les jetons dans la réponse (Bearer, sans cookie ni CSRF). Une réponse de renouvellement perdue ne déconnecte plus. | 365c63d |
Sans corps de requête, rien ne change : l'app actuelle et le site web continuent de fonctionner pendant la transition.
Le problème de l'heure, décrit dans les versions précédentes de cette page, est donc réglé par l'option A : le champ time côté API, sans passer par une demande de correction.
Les cas particuliers
| Cas | Ce qui se passe |
|---|---|
| L'app est fermée avant le retour du réseau | La file est sur le téléphone, rien n'est perdu. L'envoi se fait à la prochaine ouverture. |
| Double appui ou file renvoyée | Chaque pointage a son client_id : le serveur reconnaît un renvoi et ne l'enregistre qu'une fois. |
| Heure du téléphone trafiquée | L'API limite l'écart : 72 h au maximum, jamais dans le futur, jamais avant le dernier pointage. |
| Session expirée pendant la coupure | La file attend la reconnexion, puis elle est envoyée. |
| Le serveur refuse un pointage (409 : semaine validée, ordre impossible, chevauchement) | Il est retiré de la file et l'utilisateur est prévenu, avec la possibilité de demander une correction. |
| Deux téléphones | Chaque téléphone a sa file. L'API garde l'ordre grâce aux heures. |
Les dépendances prévues
| Paquet | Rôle | Dans Expo Go |
|---|---|---|
@react-native-community/netinfo | Savoir si on est connecté | Oui |
expo-sqlite | Stocker le cache et la file | Oui |
Les deux s'installent avec npx expo install et fonctionnent sans « development build ».