Evoke
Evoke is a spaced-repetition app built around free recall instead of flashcards. I have a terrible memory and have always loved Anki, but I wanted something that pushed me to answer in my own words, which research suggests is more effective for deeper understanding.
So I built Evoke: you create questions or topics (‘recalls’), answer them from memory, and get AI feedback and a score. The app then reschedules each item based on how you did, so you spend more time on what you’re still getting wrong and less on what you’ve already memorised.
It’s the first full web app I’ve built that I’d call genuinely usable, and it was my way of pulling together everything I’ve been learning about design, HTML, CSS, JavaScript and modern frameworks into one thing that actually solves a problem for me.
The stack is Next.js (App Router), Supabase for the DB and auth, and Tailwind for styling. Attempt evaluations also run in a Supabase Edge Function that calls the OpenAI API, so the API key never touches the client.
One of the trickier parts was keeping the UI in sync with that async flow: you submit an answer, get sent to the attempt page and see ‘Processing’ until the AI result comes back. I used Supabase Realtime so the page subscribes to changes on that attempt and updates as soon as the Edge Function writes the score and feedback, avoiding polling or a manual refresh. I also put time into custom searchable/sortable tables for recalls and attempts (e.g. sorted by due date, score, title), as well as validation and sanitisation so user and AI-generated content are safe to render.
I worked hard to make the codebase more maintainable, as I intend to improve on it over time. Core logic lives in app/lib with clear separation from the UI and Zod for validation. I also added Vitest tests and mocks for shared utilities so that I could refactor with more confidence. I know I’ve still got a lot to learn about setting up a sensible architecture and tests, but this is something I hope to develop over time with more experience.
There were plenty of other bumps on the road - auth and RLS, the spaced-repetition math, form and error handling - but I managed to gradually research and fix issues as they came up. Honestly, I also never fully warmed to server actions - the pattern didn’t quite click for me. I’ll try to learn more, but if I were to refactor today, I’d likely pivot to standard API routes and client-side calls, which feels more intuitive for this specific use case.
Overall, Evoke is still something I use myself. It’s not perfect, but it’s my first full stack app that does something I care about and that reflects the design and engineering skills I’ve been building.
View project