diff --git a/AGENTS.md b/AGENTS.md index 29a4ecf..459366f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,3 +11,33 @@ Mapbox does **not** work with SSR. Importing `mapbox-gl` in a code path that run **Required pattern:** load the map UI only on the client with `next/dynamic` and **`{ ssr: false }`**. Never add a Server Component that imports `mapbox-gl` or a module that imports it at top level without this guard. **In this repo:** `components/HomePage.tsx` wraps `MapCanvas` in `dynamic(() => import("@/components/map/MapCanvas"), { ssr: false, ... })`. Keep new Mapbox code behind that boundary (or another `dynamic(..., { ssr: false })`). + +## Cursor Cloud specific instructions + +### Services overview + +**pgtruth** is a Next.js 16 (App Router) crowdsourced PG-review app with a Mapbox map. The backend is Supabase (PostgreSQL + service role key). There is no Docker setup or local database — all persistence goes through the Supabase REST API. + +### Running the app + +- `npm run dev` — starts the dev server on port 3000 (uses `--webpack` flag). +- `npm run build` — production build; also validates TypeScript. +- `npm run lint` — ESLint 9 with `eslint-config-next`. Pre-existing warnings/errors exist in the repo; 4 errors and 13 warnings as of initial setup — do not treat those as regressions. +- `npm test` — Vitest, runs 10 test files (53 tests) in `lib/**/*.test.ts`. Pure unit tests, no external services needed. + +### Required secrets (set via Cursor Secrets) + +| Secret | Required for | +|---|---| +| `NEXT_PUBLIC_SUPABASE_URL` | All data loading / API routes | +| `SUPABASE_SERVICE_ROLE_KEY` | Server-side writes (review submission) | +| `NEXT_PUBLIC_MAPBOX_TOKEN` | Map rendering | + +Without real Supabase + Mapbox tokens the app starts but shows fallback UI (gray map, "Can't load reviews" banner). Lint and tests work without any secrets. + +### Gotchas + +- The lockfile is `package-lock.json` — use **npm**, not pnpm/yarn. +- `next dev` uses `--webpack` (not Turbopack); the build script does too. +- The `middleware.ts` file triggers a deprecation warning ("use proxy instead") — this is expected with Next.js 16 and can be ignored. +- `.env.local` is gitignored; create it from `env.example` and fill in real keys. diff --git a/lib/place-rent-label.test.ts b/lib/place-rent-label.test.ts index f46b8f0..3bbf570 100644 --- a/lib/place-rent-label.test.ts +++ b/lib/place-rent-label.test.ts @@ -21,4 +21,9 @@ describe("formatMapPinRentLine", () => { const s = formatMapPinRentLine([row(8000), row(28000)]); expect(s).toContain("–"); }); + + it("rev count reflects total reviews, not just those with rent data", () => { + const s = formatMapPinRentLine([row(10000), row(0), row(15000)]); + expect(s).toContain("3 rev"); + }); }); diff --git a/lib/place-rent-label.ts b/lib/place-rent-label.ts index b4b6834..424a633 100644 --- a/lib/place-rent-label.ts +++ b/lib/place-rent-label.ts @@ -24,9 +24,8 @@ export function formatMapPinRentLine(reps: ReportRow[]): string { const med = Math.round(medianSorted(sorted)); const min = sorted[0]!; const max = sorted[sorted.length - 1]!; - const n = rents.length; - const medPart = `Med ${ruShort(med)}/mo · ${n} rev`; + const medPart = `Med ${ruShort(med)}/mo · ${reps.length} rev`; const spread = max - min; const wide = spread > Math.max(4000, med * 0.12) && min !== max;