The product web app for BetterPomo — a shared Pomodoro timer you can run with your whole team. Start a session, share a 6-character code, and everyone in the room sees the same countdown in real time, with chat, participants, friends, session history, and an ambient sound mixer built in. Served at app.betterpomo.com.
Built by Luciano Menezes.
This is a client-side Next.js app — there are no server components that query data and no API routes (except the OAuth callback). Every data read and write goes through the BetterPomo API. Supabase is used directly only for authentication and the realtime subscription layer (live timers, chat, and presence). So to run the app you need both this app and the API running.
Web app ──HTTPS (Bearer JWT)──▶ betterpomo-api ──▶ Supabase (Postgres)
└────────────── Supabase Auth + Realtime (directly) ──────────────┘
- Shared timer — one countdown, synced in real time across every participant
- Pomodoro & running-timer modes — focus/break cycles or an open stopwatch with laps
- Live chat & participants — message the room; owners can promote admins or remove members
- Friends & DMs — add friends, see who's in a session, message them directly
- Session history & stats — total/active time per session and a GitHub-style activity calendar
- Ambient sound mixer — layer looping sounds, set each level, pause-all, and save one-tap presets
- Background sessions — sessions keep running when you navigate away; a floating banner brings you back
- End-session summary — a recap of your stats when a session ends
- Emoji avatars & profiles — pick an emoji, write a bio, set your name, toggle privacy
- Dark / light / system theme and a fully responsive, mobile-friendly layout
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router, React 19) |
| Data | BetterPomo API via typed SWR hooks |
| Auth & Realtime | Supabase (used directly for auth + postgres_changes) |
| Styling | Tailwind CSS v4 |
| UI components | shadcn/ui + Base UI |
| Icons | Lucide React |
| Theming | next-themes |
| Language | TypeScript |
- Node.js 18+
- A Supabase project
- The BetterPomo API running on
:4000
npm installCreate a .env.local file:
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
NEXT_PUBLIC_API_URL=http://localhost:4000The Supabase values are under Settings → API in your Supabase project.
Run supabase/migration_apply_all.sql in the Supabase SQL Editor — it creates
every table, RLS policy, and RPC in one shot. Individual migration files also live
in supabase/.
In Supabase → Authentication → Providers, enable Google and add your OAuth credentials. The app works without it — email/password auth is always available.
npm run dev # → http://localhost:3000 (API must be running on :4000)
npm run buildapp/
(main)/ authenticated shell
dashboard/ active sessions + history
create/ join/ start / join a session
search/ settings/ user search · profile & legal
u/[username]/ public user profile
session/[code]/ live session (full-screen)
auth/callback/ OAuth code exchange (do not remove)
components/
session/ SessionClient, ChatPanel, ParticipantList, TimerDisplay,
SoundPanel, StopwatchView, …
lib/
backend-api.ts api.get / post / patch / delete
hooks.ts typed SWR data hooks + cache invalidators
supabase/ browser client (auth) + server client (OAuth callback)
supabase/ SQL migrations (shared with the API)
Licensed under the BetterPomo Non-Commercial License — see LICENSE.
You may read, learn from, and modify the code, but any use or modification must credit Luciano Menezes, and you may not use it commercially (no selling, no paid SaaS, no ad revenue). Want a commercial license? Reach out.