Skip to content

Mode hors ligne ​

L'application mobile doit fonctionner sans réseau : un employé qui pointe dans un sous-sol ne doit pas perdre son arrivée. Cette page explique ce que l'API garantit pour que ce soit possible. Le côté téléphone est décrit dans Mobile : mode hors ligne.

Le principe : une file d'attente ​

Sans réseau, l'application range chaque action dans une file d'attente sur le téléphone, puis la renvoie dès que le réseau revient.

Pour que ce soit fiable, l'API garantit trois choses.

1. Une intention, pas une bascule ​

Le site web dit « pointe » et l'API inverse l'état. Rejouée, la même requête inverserait l'état une seconde fois : un départ dont la réponse s'est perdue deviendrait une arrivée.

L'application dit donc ce que la personne a fait : "action": "in" ou "out" ("start" ou "end" pour une pause). Si l'action ne correspond plus à l'état, l'API répond 409 avec un code précis (already_clocked_in, not_clocked_in, already_on_break, not_on_break), et l'application sait qu'il est inutile de réessayer.

2. L'idempotence ​

Idempotent veut dire : envoyer une requête une fois ou dix fois donne le même résultat.

Chaque action reçoit, sur le téléphone, un identifiant unique (un UUID) : le client_id. Si l'API l'a déjà reçu pour cette personne, elle renvoie ce qu'elle a enregistré (200 au lieu de 201), et rien ne change. Un index unique de la base le garantit en dernier recours.

ActionChamp
Pointageclocks.client_id
Pausebreaks.start_client_id, breaks.end_client_id
Demande de correctioncorrection_requests.client_id

Le rejeu est cherché avant toute autre règle : une demande renvoyée après la validation de sa semaine reste « la demande enregistrée » (200), et non un 409 qui ferait croire au téléphone qu'elle a été refusée.

3. L'heure réelle, dans des limites ​

L'action envoie l'heure où elle a eu lieu ("time"). L'API la garde, mais accepter une heure envoyée par le client ouvrirait la porte à la triche (« je suis arrivé à 7 h »). Elle est donc vérifiée :

RègleErreur
pas dans le futur (1 minute de tolérance pour l'horloge du téléphone)422 in_future
au plus 72 heures (un week-end sans réseau)422 too_old
jamais avant le pointage ou la pause précédente422 out_of_order
jamais sur une journée qu'un manager a saisie entre-temps422 overlaps
jamais dans une semaine validée409 week_validated

Et l'API note quand elle l'a reçue : start_received_at, end_received_at sur la journée et ses pauses, vides quand l'heure est celle du serveur. Le site web affiche « Offline · sent at 11:10 » quand une heure est arrivée plus de 5 minutes après l'action. Le manager sait quelles heures viennent du téléphone, et l'employé voit la même chose.

Et la session ? ​

Une session qui expire pendant une coupure ne doit pas faire perdre la file. Les sessions mobiles survivent à une réponse perdue lors du rafraîchissement des jetons, sans affaiblir la détection d'un jeton volé : voir Authentification.

Les fichiers ​

FichierRôle
lib/timemanager/device_actions.exce qu'un téléphone peut envoyer, et les règles sans la base (futur, 72 h)
lib/timemanager/clocks.exintention, rejeu, ordre, semaine validée pour les pointages
lib/timemanager/workingtime.exla même chose pour les pauses (clock_break/2)
lib/timemanager/corrections.exrejeu des demandes (submit_request/2)