
My Role
End-to-end ownership—product, design system, full-stack Next.js, AI integration with Anthropic Claude, Paystack subscriptions, Cloudinary uploads, VAPID web push, service worker, and production docs.
Tech Stack
Engineering Decisions
- Local-first architecture—Zustand with persist middleware as single source of truth across pages. Every mutation runs synchronously; no network round-trips block the UI. The action API is shaped so a future DB swap (MongoDB / Postgres) replaces only the action bodies, not component contracts.
- Custom design system instead of a UI library—five themes via CSS variables (OKLCH), zero borders / blur / glass / colored shadows. Includes hand-built DatePicker, TimePicker, Select, Modal, Popover, and a ~80 LOC markdown renderer to keep the bundle tight.
- Streaming AI with classified errors—every AI surface (chat, plan my day, goal diagnose, task breakdown, note assistant) streams Claude responses via ReadableStream. Errors are mapped to typed kinds (no_credit / rate_limit / auth / overloaded) and rendered as markdown inside the same stream, so the UI never has to handle a separate error path.
- Keyboard-first interaction—⌘K command palette with fuzzy matching, chord nav (g t for Today, g j for journal), quick add (N), cheatsheet (?), and per-modal focus traps. Every native form control replaced with custom primitives so the experience is identical across browsers and themes.
- Paystack billing in GHS—Pro at GH₵70/mo or GH₵640/yr (saves GH₵200). HMAC SHA512 webhook signature verification with timing-safe compare; invoice list pulled live from the Paystack API.
Hard Problem
Challenge: A local-first store powered by Zustand persist creates a server/client hydration mismatch on every authed page: the server has no localStorage, so it renders the seed; the client rehydrates and renders the user's real data. React flags this as a hydration error and discards the tree.
Solution: Built a 30-line Hydrated wrapper at the layout level that renders a structural skeleton on both the server and the first client paint, then swaps to children after the store rehydrates. No mismatch, no flash, one render. The same primitive removes a whole class of bugs across every store-backed page.
In Production
Pre-launch beta—actively used for personal daily planning. Service worker initially intercepted /api/* during PWA install, briefly breaking the streaming AI responses. Fixed by adding an explicit URL path check in the SW fetch handler and version-prefixing every cache so old caches purge cleanly on each new deploy.
What's Next
Wire MongoDB for cross-device sync and persistent push subscriptions. Ship Google Calendar / ICS sync. Add a Vercel Cron job for goal-at-risk nudges (the endpoint is already wired). Add MFA. Move soft-delete retention enforcement from client-side to a server-side cron once the DB lands.



