Status: Accepted
Date: 2025-12-21
Deciders: Engineering Team
Context: The app needed shareable, bookmarkable URLs for festival drinks, breweries, and styles. Two approaches were considered: hash-based URLs (/#/drink/123) and path-based URLs (/drink/123). The app was pre-release with no existing shared URLs or search engine indexing, so there were no backward-compatibility constraints.
We adopted festival-scoped, path-based URLs with GoRouter and usePathUrlStrategy().
/{festivalId} → Festival home (drinks list)
/{festivalId}/favorites → Favorites for this festival
/{festivalId}/drink/{drinkId} → Drink detail
/{festivalId}/brewery/{id} → Brewery detail
/{festivalId}/style/{styleName} → Style detail (lowercase canonical)
/{festivalId}/info → Festival info
/about → About (global, not festival-scoped)
- Festival ID as URL root -- every drink/brewery/style URL is scoped to a festival, enabling cross-festival deep links
- Lowercase canonical style URLs --
buildStylePath()lowercases style names for consistent URLs - URL encoding -- all user-provided IDs are encoded via
Uri.encodeComponent() - Pre-release advantage -- no redirect logic or legacy URL support needed
- Simpler: no server-side SPA routing config needed
- Rejected because: poor SEO, unprofessional appearance, not shareable on social media
- Simpler routing, fewer path segments
- Rejected because: can't distinguish same drink ID across different festivals; can't share a link to "this year's festival"
- Clean, shareable URLs that work on social media
- Festival context is always visible in the URL
- Browser back/forward works correctly
- Bookmarks and shared links are self-contained
- Requires SPA fallback routing on the server (Cloudflare Pages
_redirectsor--proxyflag on http-server) - Detail routes currently lack festival ID validation (documented as known limitation, see todos.md H3)
- Festival selector UI doesn't update the URL when switching festivals (see todos.md C3)
- Router:
lib/router.dart(GoRouter configuration) - URL builders:
lib/utils/navigation_helpers.dart - E2E tests:
test-e2e/routing.spec.ts(Playwright URL smoke tests) - Server config:
--proxyflag on http-server for SPA fallback
docs/code/routing.md-- current routing implementation detailsdocs/code/navigation.md-- navigation helper API reference