MVP web app to discover 1300+ Brazilian Jiu-Jitsu gyms worldwide.
- Next.js (App Router, TypeScript)
- Tailwind CSS v4
- Supabase (PostgreSQL + PostGIS)
- Leaflet + react-leaflet + marker clusters
- CARTO basemaps (API key required since 2026-09-23)
- Vercel for deployment + Vercel Web Analytics
Project status and TODO: see ../STATUS.md.
npm install- Create a Supabase project at https://supabase.com
- Copy
.env.local.exampleto.env.localand fill in your credentials:
cp .env.local.example .env.local- Run the schema in Supabase SQL editor — copy the contents of
supabase/schema.sqland execute it.
npm install -D tsx dotenv
npx tsx src/data/import-clubs.tsAfter import, run this SQL in Supabase to populate the PostGIS location column:
UPDATE clubs
SET location = ST_MakePoint(lng, lat)::geography
WHERE lat IS NOT NULL AND lng IS NOT NULL AND location IS NULL;npm run devsrc/
app/
layout.tsx -- Global layout (dark theme, Inter font)
page.tsx -- Landing page (search + world map)
LandingMap.tsx -- Client component for landing map
search/
page.tsx -- Search results wrapper (Suspense)
SearchContent.tsx -- Search results (list + map + filters)
club/
[id]/
page.tsx -- Club detail page (SSR, SEO)
components/
Map.tsx -- Leaflet map (client only)
MapDynamic.tsx -- Dynamic import wrapper (no SSR)
ClubCard.tsx -- Club card in list
SearchBar.tsx -- Search input
FilterBar.tsx -- Gi/No-Gi/Open Mat/Drop-in filters
ClubDetail.tsx -- Full club detail view
lib/
supabase.ts -- Supabase client
types.ts -- TypeScript types
data/
import-clubs.ts -- Import script (JSON -> Supabase)
supabase/
schema.sql -- Database schema (PostGIS)
- Dark theme (#0f1117 bg, #22d3a7 accent)
- Inter font
- Colored badges: Gi (blue), No-Gi (purple), Open Mat (amber), Drop-in (green)
- Dark Carto basemap tiles
- Marker clustering
npx vercelSet environment variables in Vercel dashboard:
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYNEXT_PUBLIC_CARTO_API_KEY(map tiles are watermarked without it)
.env.local also needs NEXT_PUBLIC_CARTO_API_KEY, and SUPABASE_SERVICE_ROLE_KEY for admin scripts.
- Sources (column
source):ibjjf(~89 %),cfjjb(France, with emails), affiliation networks,bjj_globetrotters,club_request(added on a gym's request). curated_v2was AI-generated during prototyping and is not verified (drop-in flags removed on 2026-09-30).verified = truemeans the gym confirmed its info directly.- Bulk data fixes live in
supabase/fix-data-*.sqland are run manually in the Supabase SQL editor after a backup.
- Club pages with no contact/info signal are
noindexand excluded from the sitemap. - City slugs map spaces to
-; the city page matches-against space or hyphen (ILIKE_). /city/lisboaand/city/warszawaredirect (308) to/city/lisbonand/city/warsaw.