Track your trackers.
Too many habit trackers? Track them. Built 100% with vibes. Probably secure.
A small Next.js app for tracking habit tracker listings. Auth-backed, Supabase-powered, public-facing where it counts.
- Auth
- Create and manage listings
- Public listings
npm ci
cp .env.example .env.local # then set Supabase keys + site URL
npm run devOpen http://localhost:3000/.
Production-like Cloudflare runtime preview:
npm run previewnpm run lint- ESLint checknpm run lint:fix- ESLint autofixnpm run format- Prettier writenpm run format:check- Prettier checknpm run test- Vitest runnpm run build- Production build
Full verification: npm run lint && npm run test && npm run build
Pre-commit runs lint-staged on staged files only. JS/TS files get eslint --fix then prettier --write; JSON/Markdown/CSS/YAML files get prettier --write.
- Required public env vars:
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY(preferred) orNEXT_PUBLIC_SUPABASE_ANON_KEY(legacy fallback)NEXT_PUBLIC_SITE_URL
- Server-only env vars:
SUPABASE_SERVICE_ROLE_KEYfornpm run seedandnpm run import:ios
- Set
NEXT_PUBLIC_SITE_URLto the exact current app origin (http://localhost:3000in dev, deployed origin in prod). - Set Supabase Auth Site URL to your production app origin.
- Add Supabase Auth Redirect URLs for each allowed
/auth/callback/origin, including localhost, production, and any preview domains. - Seed test data with
SUPABASE_SERVICE_ROLE_KEY=... npm run seedafter setting your Supabase URL. - After schema migrations, regenerate
lib/database.types.tsso app types stay aligned with Supabase.
Main app no longer supports GitHub Pages static hosting. Auth, protected dashboard pages, and listing creation require a real runtime.
This repo targets Cloudflare Workers + OpenNext for full Next.js 16 runtime support.
open-next.config.tswrangler.jsoncnpm run previewnpm run deploynpm run cf:typegen
Use Workers, not Cloudflare Pages static hosting, for the main app.
- Framework preset: None
- Build command:
npm run deploy - Output directory: none (OpenNext writes
.open-nextand Wrangler deploys worker + assets) - Production branch: your normal deploy branch
- Node.js compatibility: enabled by
wrangler.jsoncvianodejs_compat
If you import the repo into Cloudflare Pages, do not use the Next.js static preset for the main app. Pages static output cannot support sign-in, protected routes, or create/manage listing flows in this repo.
Set these before deployment so build and runtime both receive correct values:
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEYNEXT_PUBLIC_SITE_URL
Optional / local-only:
NEXT_PUBLIC_SUPABASE_ANON_KEYif you still rely on the legacy anon key instead of a publishable keySUPABASE_SERVICE_ROLE_KEYonly if you plan to runnpm run seedfrom a trusted environment
npm ci
npm run deployFor a local production-like check before deploy:
npm run previewSet Supabase Auth Site URL to your production app origin.
Add every allowed callback origin to Supabase Auth Redirect URLs:
http://localhost:3000/auth/callback/https://<your-cloudflare-workers-domain>/auth/callback/https://<your-custom-domain>/auth/callback/https://<any-preview-domain>/auth/callback/for preview deploys
NEXT_PUBLIC_SITE_URL must match the deployed origin for each environment. For preview deploys, use preview-specific values instead of reusing the production origin.
- Server-rendered dashboard routes use Supabase cookies and require runtime execution.
- Public listing detail pages no longer depend on static export params.
- If a separate static marketing site is needed later, host it separately from the runtime app.
npm run seed- Creates or reuses
seed.listings@example.com - Adds 6 sample listings with draft/published mix for local testing
npm run import:ios -- --country=ZA --limit=10 --terms=habit tracker,streak tracker,journaling,productivity,to do- Fetches Apple iTunes Search API software results (
media=software,entity=software) - Reuses the seed user/profile bootstrap from
npm run seed - Script env loads from local Next env files (
.env.local,.env) via@next/env; global shell export not required in local dev - Maps Apple data into existing
listingsshape:name,platforms=["iOS"],urls.ios, nullablewebsite_url, nullabledescription,published,is_claimed=false - Defaults:
terms=habit tracker,streak tracker,journaling,productivity,to do,country=ZA,limit=10 - Reruns are safe for importer-owned rows: existing seed-owned iOS listings update in place by App Store URL and keep their existing slug/status/claimed state; rows owned by another user with the same iOS URL are skipped
- Requires
NEXT_PUBLIC_SUPABASE_URL(orSUPABASE_URL) plusSUPABASE_SERVICE_ROLE_KEY - Optional env overrides:
IOS_IMPORT_TERMS,IOS_IMPORT_COUNTRY,IOS_IMPORT_LIMIT - Verified schema assumptions from repo:
profiles.idownslistings.user_id;listingsusesslug,platforms,urls,website_url,description,status,is_claimed;statusenum isdraft | published; insert/update conflict handling should stay in code, not new schema columns
npm run publish:ios- Publishes seed-owned listings with
platformscontainingiOSandstatus=draft - Updates only
status; keepsuser_idand all other fields unchanged - Uses the same seed-user/profile bootstrap helpers as seed/import scripts