What It Does
- Unifies projects, goals, journals, debugging task lists, and collaborative sessions under one identity and data layer
- Provides offline-ready flows with Supabase sync for seamless cross-device productivity
- Offers realtime collaboration channels for shared sessions and clipboard sync
- Features a journal engine with 12+ question types, calendar/history views, and full-text search
- Includes template versioning that keeps answers stable across updates while detecting breaking changes
- Supports exports to JSON/CSV for backup and data portability
- Works as an installable PWA with responsive design and notification hooks
Why I Built This
I was juggling multiple productivity tools—separate apps for backlogs, journals, timers, and collaboration. Each had its own login, data silo, and UI patterns. The friction of context-switching was killing my flow. I wanted one cohesive, installable web app that could replace this fragmented workflow.
After retiring a legacy .NET API, I chose Supabase as the single backend. It gave me unified auth, storage, and realtime channels without maintaining a bespoke server. The challenge became building a modular frontend that could scale from personal use to small team collaboration while keeping data integrity and offline capabilities.
How It Works
The frontend is built with React 19, Vite 7, and TypeScript, styled with Tailwind utilities and CSS modules. Framer Motion powers the animations. Supabase handles PostgreSQL database, authentication, realtime channels, and Edge Functions on the backend.
A custom SupabaseGateway + BaseRepository + Command pattern encapsulates all data access, providing type safety, dependency injection, and consistent error handling. This architecture makes the codebase testable with Vitest unit tests and enables deterministic mocking for E2E scenarios.
Recent architectural improvements included a question identity migration that decouples template versions from user answers, ensuring historical journal entries never break when templates evolve. Row-level security policies protect data while still allowing public share links for the collaborative clipboard feature.
Impact
By the numbers:
- 4-person development team (based on git shortlog)
- 21+ Playwright E2E test specs covering journals, clipboard sharing, debug workflows, and goal persistence
- 433/434 Vitest unit tests passing
- 8 E2E tests validating question identity stability and version uniqueness
- 40+ Supabase database tables with generated TypeScript types
What changed:
- Eliminated the need for multiple separate productivity tools
- Goal data now persists on every interaction, fixing user-reported data loss
- RLS policy cleanup restored public share links without compromising security
- Data layer refactor improved testability and consistency across all services
- Template versioning protects historical journal entries from breaking changes
Challenges & Solutions
The biggest challenge was fixing goal persistence. Users were losing progress when using +/- controls because saves only triggered on input blur events. I had to centralize save logic and invoke saves on every interaction instead. This revealed that our E2E tests weren't matching real user behavior—synthetic blur events had been hiding the bug.
Another challenge was the question identity migration. Journal templates needed to version without breaking historical entries. I solved this by making identity_id stable across versions, decoupling read/write paths, and regenerating Supabase types. Then I added E2E coverage to guard against regressions.
Realtime collaboration introduced RLS policy complexity. Some policies were recursive and blocked public Clippy share links. I had to carefully refactor the policies to enforce ownership validation while still allowing public read access for shared items.
What I Learned
I learned that E2E test flows must align with real user behavior. Our tests used programmatic blur events that masked the persistence bug for months. Now I write tests that mimic actual click patterns and state transitions.
I also learned that centralized data layers (gateway + repositories) dramatically reduce drift in error handling and simplify test stubbing. The initial setup took time, but it paid dividends in code maintainability and test reliability.
Most importantly: selection-based or date-based "current entry" detection is safer than timestamp heuristics when dealing with concurrent data. Our original logic assumed the most recent entry by timestamp was always "current," but that broke when users had multiple goals active simultaneously.
Future improvements:
- Add mobile-native apps for iOS and Android using React Native
- Implement advanced analytics dashboard for goal trends and journal insights
- Build team workspace features with permission controls and shared templates
- Add AI-powered suggestions for journal prompts based on usage patterns
- Create webhook integrations for popular productivity tools (Notion, Todoist, etc.)
Links
- Live App: app.tooldobox.com
- Code: Private repository
- Tech Stack: React 19, TypeScript 5.8, Vite 7, Tailwind CSS, Supabase, Playwright, Vitest
- Related: Goal Bar, Productivity Bar, ToDo Runner