Listo
Local-first task manager with reactive state and browser persistence
Context
I created Listo as an Angular exercise: a local-first task manager. In it, I explored how to structure a frontend application with persistent data, multiple filters, and an accessible interface without relying on authentication or a backend.
Listo's visual identity.
Technical problem
The interface needs to keep pending and completed tasks synchronized with the search term and selected date. The initial implementation applied each new filter to an already filtered result, causing items to disappear after successive search or date changes.
To solve the problem, I combined the persisted collection, search term, and selected date with RxJS. Every event recalculates the result from the original source, preserving a single source of truth. Pending and completed lists are derived from the same shared stream.
Architecture and data
I used standalone Angular components and separated models, persistence, services, and features. Dexie provides a typed layer over IndexedDB, while liveQuery publishes local changes reactively. Services encapsulate task and tag operations, and combineLatest with shareReplay coordinates the state rendered by the interface.
Data remains on the user's device. This decision reduces infrastructure requirements and supports privacy and local use, with the deliberate limitation that tasks are not synchronized across devices.
Interface and accessibility
The layout adapts from a centered desktop window to a full-screen experience on smaller devices. Controls have accessible names, visible focus, and suitable interaction areas. Actions do not rely exclusively on hover, and transitions respect the reduced-motion preference.
Main interface with date navigation, search, and separate pending and completed task views.
Quality and evolution
I migrated the project incrementally from Angular 19 to Angular 22, including Angular Material, the modern build system, SSR, and prerendering. I also migrated the test suite from Karma and Jasmine to Vitest, removing the requirement for an installed browser in continuous integration.
Tests cover the services, search and date state publication, and regressions in the filter combination. The production build generates browser bundles, the SSR server, and the prerendered initial route.
Project boundaries
I present Listo as an engineering study rather than a commercial product. Authentication, collaboration, notifications, and remote synchronization are outside its scope. Possible next steps include end-to-end tests and an optional synchronization strategy that preserves its local-first approach.