← App|Global Music Trendsdocs

Architecture

Tech Stack

LayerChoiceReason
FrameworkNext.js 16 (App Router)ISR, Suspense streaming, edge middleware
DeploymentVercelEdge network, x-vercel-ip-country header, ISR support
DataLast.fm Public APIFree, no auth for read endpoints, supports lang param
i18nnext-intl 4.xLocale-in-URL routing, server + client component support
LanguageTypeScriptType-safe API responses and component props
StylingTailwind CSS v4Utility-first, dark theme, zero runtime

System Diagram

File Structure

/
├── proxy.ts                          # Edge: country + locale detection, rewrite
├── i18n/
│   ├── routing.ts                    # Supported locales + default
│   ├── request.ts                    # Server-side locale/message resolution
│   └── navigation.ts                 # Locale-aware Link, useRouter
├── messages/
│   ├── en.json                       # English UI strings
│   ├── es.json                       # Spanish
│   ├── no.json                       # Norwegian
│   └── it.json                       # Italian
├── lib/
│   ├── lastfm.ts                     # Last.fm API wrapper (typed, ISR fetch)
│   └── countries.ts                  # ISO → slug, display names, flag emojis
├── app/
│   ├── layout.tsx                    # Root layout (html, body, fonts)
│   ├── docs/                         # MDX documentation (this site)
│   └── [locale]/
│       ├── layout.tsx                # NextIntlClientProvider per locale
│       ├── trends/[country]/page.tsx # ISR chart page
│       └── artist/[name]/page.tsx    # ISR artist detail page
└── components/
    ├── NowTrendingHero.tsx
    ├── CountrySelector.tsx
    ├── TrackList.tsx
    └── ArtistGrid.tsx

i18n Strategy

Locale is determined once at the edge in proxy.ts and embedded in the URL path:

/en/trends/united-states
/es/trends/spain
/no/artist/Kygo
/it/artist/Måneskin

Supported locales: en (default), es, no, it, fr

Locale detection order for root /:

  1. Accept-Language request header matched against supported locales
  2. Falls back to en

Server components call getTranslations(namespace) from next-intl/server.
Client components call useTranslations(namespace) — messages are injected by NextIntlClientProvider in the locale layout.

Caching Strategy

RouteMethodTTLCache Key
/[locale]/trends/[country]ISR3600slocale + country
/[locale]/artist/[name]ISR3600slocale + artist name
Last.fm fetch (tracks)next: { revalidate: 3600 }3600sfull URL
Last.fm fetch (artists)next: { revalidate: 3600 }3600sfull URL
Last.fm fetch (artist info)next: { revalidate: 3600 }3600sfull URL + lang

ISR means Vercel serves the cached page immediately and regenerates it in the background when the TTL expires.

Rendering Strategy

ConcernApproachWhy
Country detectionEdge (proxy.ts)Zero latency, runs before any server code
Locale detectionEdge (proxy.ts)Same pass as country, no extra round-trip
Chart dataISR + fetch revalidateCharts change hourly; caching saves API quota
Loading statesReact Suspense + loading.tsxStreams shell instantly, content fills in
Country switchClient-side navigationInstant UX, no full reload