Skip to content

feat: add per-city landing pages generated from the places dataset - #133

Merged
yakew7 merged 1 commit into
StudentSuite:mainfrom
aryansk:feat/city-pages
Aug 14, 2026
Merged

feat: add per-city landing pages generated from the places dataset#133
yakew7 merged 1 commit into
StudentSuite:mainfrom
aryansk:feat/city-pages

Conversation

@aryansk

@aryansk aryansk commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Problem

Closes #127. We hold places for hundreds of cities but only one indexable page; someone searching "SAT exam centre in Pune" finds nothing.

What this adds

  • Statically generated page per city at /city/[slug], one for every distinct city value in the dataset (217 pages), using generateStaticParams● (SSG) in the build output, no per-request rendering.
  • Slug derived from the existing city field — no second city list or slug mapping file; the dataset stays the single source of truth.
  • Grouped by category in canonical PLACE_TYPES order, with place counts.
  • City name in <title>, <h1>, and meta description (humanizeCity for display).
  • Map deep links: each place links to /map?place=<id> (the place param the map already reads) plus its Google Maps link.
  • Thin cities (≤ 3 places) get a "just getting started" card with a prompt to contribute more places.
  • Collision guard: two distinct city values that slugify identically fail the build loudly instead of silently merging (the dataset currently has zero collisions).
  • City routes added to the sitemap.

Notable detail

The dataset includes one non-ASCII city (厦门) and one with a space (new delhi). The slugifier preserves Unicode letters (so 厦门 never collapses to an empty slug) and normalizes the space case to new_delhi; the page decodes the route param before matching.

Verification

  • npm run validate passes (6 files clean).
  • 46 unit tests pass (8 new covering slugify, grouping, collision guard, type grouping); tsc --noEmit and eslint clean.
  • npm run build produces 217 prerendered /city/*.html pages; next start serves /city/%E5%8E%A6%E9%97%A8 (厦门), /city/mumbai, and /city/new_delhi with 200 and unknown slugs with 404.

Adds a statically generated page for every distinct city in the dataset, grouping that city places by category with the city name in the title, h1, and meta description. Slugs are derived from the existing city field (no second city list); Unicode city names are preserved, and two distinct cities that slugify identically fail the build loudly instead of silently merging. Thin cities get a prompt to contribute more places, each place links to its map deep link and Google Maps, and city routes are added to the sitemap.

Closes StudentSuite#127
@vercel

vercel Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

@AryanSingh is attempting to deploy a commit to the studentsuite Team on Vercel.

A member of the Team first needs to authorize it.

@yakew7
yakew7 marked this pull request as ready for review August 14, 2026 15:14
@yakew7
yakew7 merged commit 0fcbae0 into StudentSuite:main Aug 14, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add per-city landing pages generated from the places dataset

3 participants