Tous les projets

App offline-first2026

Alouwato

Une application mobile et web qui relie tes objectifs de long terme aux heures que tu passes vraiment, pour voir si ton temps est allé là où tu le voulais, sans compte et sans connexion.

Seul - direction artistique, ingénierie, modèle de données et déploiement

L'écran Objectifs d'Alouwato sur desktop : une colonne de gauche « LA CHAINE » montrant Vision « Chaine YouTube », puis « JALON EN COURS 1/3 - Ecrire le script de la video 1 », puis « SEMAINE - tissee depuis Chaine YouTube » ; une carte « NOURRIT LES VISIONS » avec trois pastilles de vision (Chaine YouTube, Certification AWS, Espagnol courant) ; et un panneau de droite « Ton jalon en cours » listant trois étapes à cocher, la première cochée et barrée, au-dessus d'un champ « Ajouter une etape ».
L'écran Objectifs d'Alouwato sur desktop : une colonne de gauche « LA CHAINE » montrant Vision « Chaine YouTube », puis « JALON EN COURS 1/3 - Ecrire le script de la video 1 », puis « SEMAINE - tissee depuis Chaine YouTube » ; une carte « NOURRIT LES VISIONS » avec trois pastilles de vision (Chaine YouTube, Certification AWS, Espagnol courant) ; et un panneau de droite « Ton jalon en cours » listant trois étapes à cocher, la première cochée et barrée, au-dessus d'un champ « Ajouter une etape ».

Alouwato (« temps » en kabiyè, ma langue au Togo) est une application hors-ligne d'abord pour planifier ses objectifs et suivre où passe son temps. Elle modélise une chaîne que la plupart des outils gardent dans trois applications séparées : une vision de long terme, les jalons qui la font avancer, et le travail concret sous chacun. Le temps n'est ensuite compté que sur les sessions qu'on lance vraiment, soit un bloc planifié sur la grille de la semaine, soit une activité démarrée sur le moment, et chaque session terminée est archivée dans un journal. La revue de la semaine, la heatmap de focus et la vue longue (semaine / mois / année) sont toutes construites à partir de ce journal. Tout tourne sur l'appareil, sans compte et sans serveur ; les données restent dans le navigateur et peuvent être exportées dans un fichier pour la sauvegarde. Je l'ai construite pour mon usage et j'en suis le seul utilisateur.

Le problème

Mes objectifs vivaient à un endroit, le plan de ma semaine à un autre, et mes tâches du jour dans des notes. Rien ne reliait un jalon aux heures que je passais vraiment dessus, donc à la fin d'une semaine je n'avais aucune vision honnête de savoir si mon temps était allé là où je le voulais. Tout garder dans des notes voulait dire tout relire et tout réécrire à la main, et le plan se défaisait doucement.

L’approche

J'ai modélisé la chaîne qui manquait, vision puis jalon puis tâche, et fait du temps une chose à part qui ne compte que pendant une session : un bloc démarré, ou une activité à la volée. Terminer une session écrit une entrée dans un journal, et chaque écran de bilan est une simple lecture de ce journal, donc un rechargement ou une re-planification ne réécrit jamais ce qui a déjà été vécu. C'est une PWA Vue 3 avec tout l'état gardé dans le navigateur, construite une issue à la fois avec une suite de tests complète et un harnais de non-régression visuelle, et déployée sur Vercel sans rien à configurer.

Le résultat

  • Je garde mes objectifs, leurs jalons et leurs tâches au même endroit, et j'obtiens un journal de là où mon temps est vraiment passé.
  • La revue de la semaine et la heatmap de focus sont dérivées de ce journal, donc la vision de la semaine est réelle, pas ressaisie.
  • L'application fonctionne entièrement hors-ligne et s'installe comme une app ; environ 314 commits et 44 issues sur à peu près un mois, avec autour de 305 tests de store et de composants et 118 écrans de référence de non-régression visuelle.
  • La version 1 est terminée et en production sur alouwato.vercel.app ; je travaille maintenant sur la version 2.

Fonctionnalités clés

  • La chaîne d'objectifs : une vision, ses jalons, et les tâches sous chacun ; un jalon peut nourrir plusieurs visions à la fois.
  • Grille de la semaine : poser, déplacer et redimensionner des blocs de temps ; un chevauchement avec un bloc déjà posé est détecté pendant qu'on le trace.
  • La vue du jour répond à une seule question, « sur quoi je suis là, maintenant », avec un minuteur de focus en direct et le reste de la journée en dessous.
  • Le temps n'est compté que sur une session qu'on lance (un bloc planifié ou une activité à la volée), et chaque session terminée est archivée dans un journal avec la vision qu'elle a servie.
  • Revue de la semaine : les heures de focus, une heatmap par jour, et le temps passé sur chaque vision face à ce qui était prévu.
  • Vue longue : le même journal agrégé par semaine, mois et année, jusqu'à ta première session.
  • Revue du soir et « tisser ma semaine » : de courts rituels guidés pour trier ce que la journée a laissé et préparer la semaine.
  • Fonctionne hors-ligne sans compte ; thèmes clair et sombre ; export et import de sauvegarde dans un fichier daté ; verrouillage par code PIN optionnel.
Ingénierie — Architecture, décisions et compromis

Architecture

Alouwato est une application monopage Vue 3 sans router et sans backend, portée fidèlement depuis un prototype Claude Design dont elle a gardé la forme à store unique. Toute la logique vit dans un seul store réactif, découpé par domaine. Un module de base porte le singleton d'état, un setState façon React, et une persistance localStorage versionnée : un numéro de schéma est estampillé dans chaque payload, et l'hydratation rejoue une suite ordonnée de migrations idempotentes, ajoutée après qu'un changement précoce a fait passer une vision d'une simple chaîne à un objet et a survécu aux rechargements dans la mauvaise forme. Un module de contexte dérive une fois par rendu tout ce que les écrans partagent ; quinze builders de domaine assemblent chacun une tranche d'une unique carte de rendu qui mêle données dérivées et handlers d'événements inline, que les composants lisent et bindent directement. Le modèle de données est la partie que j'ai conçue : vision, puis jalon (partagé entre visions par une liste d'ids), puis tâche, et, gardée volontairement à part, la session, seule chose qui compte le temps, soit un bloc démarré sur la grille de la semaine, soit une activité à la volée. Terminer une session ajoute une entrée à un journal, et la revue de la semaine, la heatmap de focus et la vue longue (semaine / mois / année) sont toutes de pures dérivations de ce journal. Le modèle de données est protégé par un type-check du store en JSDoc dans la CI. La livraison a été disciplinée : une issue par branche par pull request sur huit milestones, une porte de CI (lint, format, type-check, tests, build), un test Playwright du parcours critique, et un harnais de non-régression visuelle de 118 écrans de référence en mobile et desktop, clair et sombre. Le tout est livré en PWA installable sur Vercel, sans variable d'environnement.

Défis d’ingénierie

  • Garder les données persistées en sécurité à travers les changements de schéma sans serveur pour lancer une migration : chaque payload porte un numéro de schéma, et l'hydratation rejoue une suite ordonnée d'étapes de migration idempotentes, donc un changement de forme est explicite plutôt qu'une clé perdue en silence.
  • Rendre « où est passé mon temps » digne de confiance : au lieu de stocker des totaux, l'application archive chaque session terminée dans un journal et en dérive chaque bilan, donc un rechargement ou une re-planification ne réécrit jamais ce qui a déjà été vécu.
  • Empêcher un portage d'interface fidèle de dériver pendant que je le rendais fonctionnel : j'ai figé l'application courante en 118 captures de référence, mobile/desktop et clair/sombre, et je les ai comparées après chaque changement, en re-figeant seulement les écarts voulus.
  • Un jalon qui appartient vraiment à plusieurs objectifs : une étape porte une liste d'ids de vision, donc la cocher fait avancer chaque rivière qu'elle nourrit, et couper une vision retire seulement cet id au lieu d'orpheliner l'étape.

Décisions techniques

  • localStorage comme source de vérité plutôt qu'une base hébergée : l'application devait fonctionner sans compte et sans réseau dès le premier lancement, et la part durable est assez petite pour qu'un blob JSON versionné avec export et import de fichier suffise à la sauvegarde.
  • Un seul store réactif avec une carte de rendu plutôt que Pinia ou de l'état local aux composants : l'application est un portage d'un prototype construit ainsi, et garder la forme a rendu le portage fidèle et mis la logique à un seul endroit peu coûteux à tester (la plupart des ~305 tests visent le store directement).
  • Type-check du JavaScript en JSDoc plutôt que migration vers TypeScript : le vrai risque était la dérive de forme des données persistées, pas la sûreté de type en général, donc ne vérifier que le store a attrapé ce qui comptait sans convertir toute la base de code.
  • Pas d'auth auto-hébergée alors que le prototype montrait une connexion Google, email et code à usage unique : pour un outil personnel mono-utilisateur, un vrai backend ajoute un compte à gérer et un serveur à faire tourner sans bénéfice, donc l'authentification et le verrou PIN sont locaux uniquement (le PIN est un hash SHA-256 salé avec blocage progressif, pas une connexion).

Stack

  • Vue 3
  • Vite
  • JavaScript (checkJs + JSDoc)
  • Vitest
  • Playwright
  • ESLint
  • Prettier
  • vite-plugin-pwa / Workbox
  • Web Crypto (SHA-256)
  • localStorage
  • GitHub Actions
  • Vercel

Seul - direction artistique, ingénierie, modèle de données et déploiement — Projet personnel - un outil que je me suis construit pour suivre mes objectifs et journaliser mes tâches ; j'en suis le seul utilisateur (2026)

Projet suivantAssociation CapHumain