All projects

Offline-first app2026

Alouwato

A phone and web app that connects your long-term goals to the hours you actually spend, so you can see whether your time went where you meant it to, with no account and no internet needed.

Solo - art direction, engineering, data model and deployment

The Objectifs screen of Alouwato on desktop: a left column 'LA CHAINE' showing Vision 'Chaine YouTube', then 'JALON EN COURS 1/3 - Ecrire le script de la video 1', then 'SEMAINE - tissee depuis Chaine YouTube'; a 'NOURRIT LES VISIONS' card with three vision chips (Chaine YouTube, Certification AWS, Espagnol courant); and a right panel 'Ton jalon en cours' listing three steps with checkboxes, the first ticked and struck through, above an 'Ajouter une etape' field.
The Objectifs screen of Alouwato on desktop: a left column 'LA CHAINE' showing Vision 'Chaine YouTube', then 'JALON EN COURS 1/3 - Ecrire le script de la video 1', then 'SEMAINE - tissee depuis Chaine YouTube'; a 'NOURRIT LES VISIONS' card with three vision chips (Chaine YouTube, Certification AWS, Espagnol courant); and a right panel 'Ton jalon en cours' listing three steps with checkboxes, the first ticked and struck through, above an 'Ajouter une etape' field.

Alouwato ("time" in Kabiye, my language in Togo) is an offline-first app for planning goals and tracking where your time goes. It models a chain that most tools keep in three separate apps: a long-term vision, the milestones that move it, and the concrete work under each. Time is then counted only on the sessions you actually run, either a planned block on your weekly grid or an activity started on the spot, and every finished session is archived to a journal. The weekly review, the focus heatmap and the week/month/year long-view are all built from that journal. Everything runs on the device with no account and no server; the data stays in the browser and can be exported to a file for backup. I built it for my own use and I am its only user.

The problem

My goals lived in one place, my week's plan in another, and my daily tasks in plain notes. Nothing connected a milestone to the hours I actually put against it, so at the end of a week I had no honest picture of whether my time went where I meant it to. Keeping all of it in notes meant re-reading and rewriting everything by hand, and the plan quietly fell apart.

The approach

I modelled the missing chain, vision then milestone then task, and made time a separate thing that only counts during a session: a started block, or an on-the-fly activity. Ending a session writes a record to a journal, and every review screen is a pure read of that journal, so a reload or a re-plan never rewrites what was already lived. It is a Vue 3 PWA with all state kept in the browser, built one issue at a time with a full test suite and a visual-regression harness, and deployed on Vercel with nothing to configure.

The result

  • I keep my goals, their milestones and their tasks in one place, and I get a journal of where my time actually went.
  • The weekly review and the focus heatmap are derived from that journal, so the picture of the week is real, not re-typed.
  • It runs fully offline and installs as an app; roughly 314 commits and 44 issues over about a month, with around 305 store and component tests and 118 visual-regression reference screens.
  • Version 1 is complete and in production at alouwato.vercel.app; I am now working on version 2.

Key features

  • The goal chain: a vision, its milestones, and the tasks under each; a milestone can feed several visions at once.
  • Weekly grid: place, move and resize blocks of time for the week; an overlap with an existing block is caught as you draw it.
  • The day view answers one question, "what am I on right now", with a live focus timer and the rest of the day below it.
  • Time is counted only on a session you start (a planned block or an on-the-fly activity), and every finished session is archived to a journal with the vision it served.
  • Weekly review: hours of focus, a per-day heatmap, and time spent on each vision against what was planned.
  • Long view: the same journal aggregated by week, month and year, back to your first session.
  • Evening review and "weave my week": short guided rituals to sort what the day left behind and plan the week ahead.
  • Works offline with no account; light and dark themes; a dated file export and import for backup; an optional PIN lock.
Engineering — Architecture, decisions and trade-offs

Architecture

Alouwato is a single-page Vue 3 app with no router and no backend, ported faithfully from a Claude Design prototype and keeping that prototype's single-store shape. All logic lives in one reactive store, split by concern. A core module owns the state singleton, a React-style setState, and versioned localStorage persistence: a schema version is stamped into every payload, and hydration replays an ordered chain of idempotent migrations, added after an early change turned a vision from a bare string into an object and survived reloads in the wrong shape. A context module derives once per render everything the screens share; fifteen domain builders each assemble one slice of a single render map that mixes derived data with inline event handlers, which components read and bind directly. The domain model is the part I designed: vision, then milestone (shared across visions through a list of ids), then task, and, kept deliberately separate, the session, which is the only thing that counts time, either a started block on the weekly grid or an on-the-fly activity. Ending a session appends a record to a journal, and the weekly review, the focus heatmap and the week/month/year long-view are all pure derivations of that journal. The data model is guarded by type-checking the store with JSDoc typedefs in CI. Delivery was disciplined: one issue per branch per pull request across eight milestones, a CI gate (lint, format, type-check, tests, build), a Playwright critical-path test, and a visual-regression harness of 118 reference screens across mobile and desktop, light and dark. It ships as an installable PWA on Vercel with no environment variables.

Engineering challenges

  • Keeping persisted data safe across schema changes with no server to run a migration: every payload carries a schema version, and hydration replays an ordered chain of idempotent migration steps, so a shape change is explicit rather than a silently dropped key.
  • Making "where did my time go" trustworthy: instead of storing running totals, the app archives each finished session to a journal and derives every review from it, so a reload or a re-plan never rewrites what was already lived.
  • Not letting a faithful UI port drift as I made it functional: I froze the current app as 118 reference screenshots across mobile/desktop and light/dark and compared against them after every change, re-baselining only the intended ones.
  • A milestone that genuinely belongs to several goals: a step carries a list of vision ids, so ticking it advances every river it feeds, and cutting one vision removes just that id instead of orphaning the step.

Technical decisions

  • localStorage as the source of truth rather than a hosted database: the app had to work with no account and no network from the first launch, and the durable slice is small enough that a versioned JSON blob with file export and import covers backup.
  • One reactive store with a render map rather than Pinia or component-local state: the app is a port of a prototype built that way, and keeping the shape made the port faithful and put the logic in one place that is cheap to test (most of the roughly 305 tests hit the store directly).
  • Type-checking JavaScript with JSDoc rather than migrating to TypeScript: the real risk was shape drift in persisted data, not general type safety, so checking the store only caught what mattered without converting the whole codebase.
  • No self-hosted auth even though the prototype showed Google, email and one-time-code sign-in: for a single-user personal tool a real backend adds an account to manage and a server to run for no benefit, so authentication and the PIN lock are local only (the PIN is a salted SHA-256 hash with a progressive lockout, not a login).

Stack

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

Solo - art direction, engineering, data model and deployment — Personal project - a tool I built for my own goal-tracking and task journaling; I am its only user (2026)

Next projectAssociation CapHumain