Stokky L'application The app Ny rindranasa
Sous le capot Under the hood Ao ambanin'ny kapaoty

Hors ligne d'abord, synchronisé sans rien perdre. Offline first, synced with nothing lost. Tsy misy aterineto aloha, mifanaraka tsy manary na inona na inona.

Stokky est une application Flutter, écrite en Dart, avec Bloc pour la gestion d'état. Cette page décrit les choix techniques qui la font tenir : le stockage local comme source de vérité, une synchronisation qui traite les conflits au lieu de les écraser, et des correctifs livrés sans passer par un magasin d'applications. Stokky is a Flutter app, written in Dart, with Bloc for state management. This page covers the technical choices holding it together: local storage as the source of truth, a sync layer that resolves conflicts instead of overwriting them, and fixes shipped without going through an app store. Rindranasa Flutter i Stokky, nosoratana amin'ny Dart, miaraka amin'ny Bloc ho an'ny fitantanana ny toe-javatra. Ity pejy ity dia mamaritra ny safidy ara-teknika manohana azy: ny fitehirizana an-toerana ho loharanon'ny fahamarinana, ny fampifanarahana mandamina ny fifanoherana fa tsy manafoana azy, ary ny fanitsiana alefa tsy mandalo magazay rindranasa.

Flutter Dart Bloc / Cubit Base SQL locale Local SQL database Banky angona SQL an-toerana Temps réel Realtime An-tsehatra TDD

Hors ligne d'abord Offline first Tsy misy aterineto aloha

Le stockage local n'est pas un cache : c'est la source de vérité. L'application s'ouvre sans compte et sans réseau, et chaque lecture comme chaque écriture passe par une base SQL embarquée sur l'appareil. L'interface n'attend jamais un aller-retour serveur — le réseau, quand il existe, ne fait que rattraper ce qui a déjà été décidé localement. Local storage isn't a cache — it is the source of truth. The app opens with no account and no network, and every read and every write goes through an SQL database embedded on the device. The UI never waits on a round trip; the network, when there is one, only catches up with what was already decided locally. Tsy toeram-pitehirizana vonjimaika ny angona an-toerana: izy no loharanon'ny fahamarinana. Misokatra tsy mila kaonty na aterineto ny rindranasa, ary mandalo banky angona SQL apetraka ao anaty finday ny famakiana sy ny fanoratana rehetra. Tsy miandry valiny avy amin'ny mpizara mihitsy ny efijery — ny aterineto, rehefa misy, dia manaraka fotsiny izay efa nofidiana teo an-toerana.

  • Démarrage immédiat, sans inscription Starts instantly, no sign-up Manomboka avy hatrany, tsy mila misoratra anarana
  • Les écritures sont validées localement, puis voyagent Writes commit locally, then travel Voarakitra an-toerana aloha ny fanoratana, dia mandeha avy eo
  • Le mode purement local reste utilisable indéfiniment Local-only mode stays usable indefinitely Azo ampiasaina mandrakizay ny fomba an-toerana fotsiny

Synchronisation Synchronisation Fampifanarahana

Chaque modification entre dans une file d'attente durable qui survit à la fermeture de l'application. La récupération est incrémentale : un curseur retient l'endroit où la dernière passe s'est arrêtée, donc seules les lignes réellement modifiées circulent. Les échecs sont réessayés avec un délai croissant, et l'état reste visible — un compteur de changements en attente, un bandeau quand la synchronisation est bloquée. Les photos suivent leur propre chemin, séparé du texte, parce qu'elles n'ont ni la même taille ni la même urgence. Every change enters a durable queue that survives the app being closed. Pulling is incremental: a cursor remembers where the last pass stopped, so only rows that actually changed travel. Failures retry on a growing delay, and the state stays visible — a pending-change counter, a banner when sync is blocked. Photos take their own path, separate from text, because they share neither its size nor its urgency. Miditra amin'ny laharana maharitra, tsy levona rehefa hidiana ny rindranasa, ny fanovana rehetra. Miakatra tsikelikely ny fakana: misy famantarana mitadidy ny toerana nijanonan'ny fandalovana farany, ka izay andalana niova tokoa ihany no mandeha. Averina amin'ny fe-potoana mitombo ny tsy fahombiazana, ary hita maso foana ny toe-javatra — misy isan'ny fanovana miandry, sy fampandrenesana rehefa voasakana ny fampifanarahana. Manana ny lalany manokana, misaraka amin'ny lahatsoratra, ny sary, satria tsy mitovy habe na hamehana aminy.

  • File d'attente persistée, rejouée au redémarrage Queue persisted, replayed on restart Laharana voatahiry, averina rehefa misokatra indray
  • Récupération incrémentale par curseur, jamais de rechargement complet Cursor-based incremental pull, never a full reload Fakana tsikelikely amin'ny famantarana, tsy misy famerenana feno
  • Réessais espacés, aucune perte silencieuse Backed-off retries, no silent loss Andrana miverina misy elanelana, tsy misy very mangina
  • Les photos se synchronisent sur leur propre voie Photos sync on a path of their own Mifanaraka amin'ny lalany manokana ny sary

Gestion des conflits Conflict handling Fitantanana ny fifanoherana

Une écriture ne remplace jamais une ligne à l'aveugle. Elle porte la version qu'elle croit corriger ; si la ligne a bougé ailleurs entre-temps, le serveur refuse, l'application capture les deux états et met un conflit en file. Un écran de résolution montre la différence champ par champ — ma version, la version distante — en séparant ce qui a changé de ce qui n'a pas bougé. Là où aucune fusion n'aurait de sens, comme les zones dessinées sur la photo d'un meuble, la dernière écriture l'emporte automatiquement : arbitrer aurait coûté à l'utilisateur plus que ça ne lui aurait rapporté. A write never blindly replaces a row. It carries the version it believes it is amending; if the row moved elsewhere in the meantime, the server refuses, the app captures both states and files a conflict. A resolution screen shows the difference field by field — mine, remote — separating what changed from what didn't. Where no merge would mean anything, such as the zones drawn on a photo of a piece of furniture, the last write simply wins: asking would have cost the user more than it gave them. Tsy misolo andalana an-jamba mihitsy ny fanoratana. Mitondra ny kinova heveriny hovana izy; raha niova any an-kafa ilay andalana nandritra izany, dia mandà ny mpizara, ka raisin'ny rindranasa ny toe-javatra roa ary alahany ny fifanoherana. Misy efijery famahana mampiseho ny fahasamihafana isaky ny saha — ny ahy sy ny lavitra — sady manavaka izay niova amin'izay tsy nihetsika. Any amin'izay tsy misy dikany ny fampifangaroana, toy ny faritra voasoritra amin'ny sarim-panaka, dia ny fanoratana farany no mandresy ho azy: ny fanontaniana dia handany ny mpampiasa mihoatra noho izay omeny azy.

  • Écriture conditionnelle : contrôle de version ligne par ligne Conditional write: a per-row version check Fanoratana misy fepetra: fanamarinana kinova isaky ny andalana
  • Le conflit est mis de côté, l'application continue The conflict is set aside; the app keeps working Atokana ny fifanoherana, mitohy ny rindranasa
  • Résolution champ par champ, choix explicite Field-level resolution, an explicit choice Famahana isaky ny saha, safidy mazava
  • Dernière écriture gagnante là où arbitrer serait absurde Last write wins where arbitration would be absurd Ny fanoratana farany no mandresy raha tsy misy dikany ny misafidy
Le reste de la mécanique The rest of the machinery Ny sisa amin'ny mekanika

Ce qui rend les trois premiers points tenables. What makes the first three sustainable. Izay mahatonga ireo telo voalohany ho azo tanterahina.

Temps réel Realtime An-tsehatra

Quand plusieurs personnes partagent un foyer, les changements arrivent sans rafraîchir. Un abonnement temps réel réveille la synchronisation dès qu'une ligne bouge côté serveur, au lieu d'interroger en boucle. When several people share a household, changes arrive without a refresh. A realtime subscription wakes the sync layer as soon as a row moves on the server, instead of polling in a loop. Rehefa olona maromaro no miara-monina, dia tonga ho azy ny fanovana, tsy mila fanavaozana. Misy fisoratana an-tsehatra mamoha ny fampifanarahana raha vao misy andalana miova any amin'ny mpizara, fa tsy manontany tsy an-kijanona.

Mises à jour à distance Over-the-air updates Fanavaozana avy lavitra

Un correctif atteint les appareils déjà installés sans passer par la revue d'un magasin d'applications, en quelques heures plutôt qu'en quelques jours. Chaque correctif est validé sur un canal de préproduction avant d'être diffusé. A fix reaches already-installed devices without going through app store review — hours instead of days. Every patch is validated on a pre-production channel before it ships. Tonga amin'ny finday efa nametrahana azy ny fanitsiana, tsy mandalo ny fandinihan'ny magazay rindranasa: ora vitsivitsy fa tsy andro maromaro. Hamarinina amin'ny lalana fitsapana aloha ny fanitsiana tsirairay vao alefa.

Architecture Architecture Rafitra

MVVM par fonctionnalité, avec des dépôts abstraits pour seule couture. Les dépendances vont dans un seul sens : vue → cubit → dépôt. C'est cette couture qui permet au web de tourner sans base locale, et à chaque test de cubit de tourner sans base du tout. Feature-first MVVM, with abstract repositories as the only seam. Dependencies point one way: view → cubit → repository. That seam is what lets the web build run without a local database, and every cubit test run without one at all. MVVM isaky ny endri-javatra, ny tahiry mizotra ihany no zaitra. Lalana tokana no alehan'ny fiankinana: efijery → cubit → tahiry. Io zaitra io no ahafahan'ny web mandeha tsy misy banky angona an-toerana, sy ny fitsapana cubit rehetra mandeha tsy misy izany mihitsy.

État prévisible Predictable state Toe-javatra azo vinaniana

L'état vit dans des Cubits, sous forme d'états immuables plutôt que de booléens de chargement éparpillés. Ce qui ne survivrait pas à la reconstruction d'un écran reste un simple setState : la frontière est écrite quelque part, pas devinée à chaque écran. State lives in Cubits, as immutable state classes rather than loading booleans scattered about. Anything that wouldn't survive a screen rebuild stays a plain setState: the boundary is written down somewhere, not guessed at each screen. Mipetraka anaty Cubit ny toe-javatra, amin'ny endrika kilasy tsy miova fa tsy boolean fampidirana miparitaka. Izay tsy ho tafavoaka rehefa amboarina indray ny efijery dia mijanona ho setState tsotra: voasoratra any ny fetra, fa tsy vinaniana isaky ny efijery.

Tests sur quatre niveaux Tests on four layers Fitsapana ambaratonga efatra

Cubit, dépôt, widget, intégration. Le cycle est rouge-vert-refactor : le test échoue d'abord, sinon il ne prouve rien. Les captures d'écran de la page d'accueil sont produites par ces mêmes tests — elles ne peuvent pas mentir sur l'application. Cubit, repository, widget, integration. The cycle is red-green-refactor: the test fails first, or it proves nothing. The phone screenshots on the landing page are produced by those same tests — they cannot lie about the app. Cubit, tahiry, widget, fampidirana. Mena-maitso-refactor ny fizotra: tsy maintsy tsy mandeha aloha ny fitsapana, raha tsy izany tsy manaporofo na inona na inona. Ireo fitsapana ireo ihany no mamokatra ny sarin'ny efijery eo amin'ny pejy fandraisana — tsy afaka mandainga momba ny rindranasa izy ireo.

Schéma additif Additive schema Rafitra angona fanampiana

Une migration ajoute une colonne ; elle n'en renomme ni n'en supprime jamais. Une version ancienne de l'application continue donc de fonctionner contre un serveur récent — condition indispensable dès lors que tout le monde ne met pas à jour le même jour. A migration adds a column; it never renames or drops one. An older build therefore keeps working against a newer server — a hard requirement once you accept that not everyone updates on the same day. Manampy tsanganana ny fiovan'ny rafitra angona; tsy manova anarana na manala mihitsy. Mbola mandeha amin'ny mpizara vaovao noho izany ny kinova taloha — tsy maintsy izany, satria tsy mandray ny fanavaozana amin'ny andro iray ny olona rehetra.

Design system Design system Rafitra famolavolana

Couleurs, espacements, rayons et typographie sont des jetons, jamais des valeurs écrites à la main dans un widget. Un catalogue de composants partagés les montre isolés, en clair et en sombre. Cette page utilise les mêmes jetons que l'application. Colours, spacing, radii and type are tokens, never values hand-written into a widget. A catalogue of shared components shows them in isolation, in light and dark. This page uses the same tokens as the app. Marika ny loko, ny elanelana, ny boribory ary ny endri-tsoratra, fa tsy sanda soratana an-tanana anaty widget. Misy katalaogy singa iombonana mampiseho azy ireo mitokana, amin'ny mazava sy ny maizina. Mitovy marika amin'ny rindranasa ity pejy ity.

Une base, six cibles One codebase, six targets Fango iray, kendrena enina

Android, iOS, le web et les trois systèmes de bureau partent du même code. Le widget d'écran d'accueil est de l'interface de l'application rendue en image : en changer la mise en page reste du Dart, pas du code natif à écrire deux fois. Android, iOS, the web and the three desktops all come from the same code. The home-screen widget is app UI rasterised to an image, so changing its layout stays Dart, not native code written twice. Miainga amin'ny fango iray ihany i Android, iOS, ny web ary ny rafitra birao telo. Ny widget eo amin'ny efijery fandraisana dia efijery rindranasa novana sary: ka Dart ihany, fa tsy kaody natif soratana indroa, no anovana ny endriny.

Trois langues, aucune en dur Three languages, none hardcoded Fiteny telo, tsy misy voafatotra

Français, anglais et malgache, sans une seule chaîne écrite en dur dans un widget. Le framework ne fournit aucune traduction malgache pour ses propres libellés : ils retombent sur le français plutôt que sur l'anglais, ce qui est le repli utile ici. French, English and Malagasy, without a single string hardcoded into a widget. The framework ships no Malagasy for its own built-in labels, so those fall back to French rather than English — the useful fallback here. Frantsay, anglisy ary malagasy, tsy misy soratra na iray voafatotra anaty widget. Tsy manome dikanteny malagasy ho an'ny lahateniny manokana ny framework: mianjera amin'ny frantsay izy ireo fa tsy amin'ny anglisy, izay no fialana mahasoa eto.

Livraison Shipping Fandefasana

Trois environnements s'installent côte à côte sur le même téléphone, chacun avec sa propre base locale, ce qui permet de tester une version sans toucher à ses vraies données. Rien n'atteint la production sans être passé par la préproduction d'abord. Three environments install side by side on the same phone, each with its own local database, so a build can be tested without touching real data. Nothing reaches production without going through staging first. Tontolo telo no azo apetraka miaraka amin'ny finday iray ihany, samy manana ny banky angonany an-toerana, ka azo andramana ny kinova iray nefa tsy voakitika ny tena angona. Tsy misy tonga amin'ny famokarana raha tsy nandalo ny fitsapana aloha.

0 Plateformes Platforms Sehatra
0 Langues Languages Fiteny
0 Niveaux de tests Test layers Ambaratonga fitsapana
0 Traceurs Trackers Mpanaraka

Rien de tout cela ne se voit. C'est le but. None of this is visible. That is the point. Tsy hita izany rehetra izany. Izay indrindra no tanjona.

L'utilisateur ouvre l'application, ajoute un article, ferme le téléphone. Le reste est notre problème. You open the app, add an item, put the phone away. The rest is our problem. Sokafan'ny mpampiasa ny rindranasa, manampy entana izy, dia atsahatra ny finday. Anjaranay ny sisa.

Revenir à l'application Back to the app Hiverina amin'ny rindranasa