A community-driven platform for exploring and understanding musical genres through an interactive, evolving genre tree map.
This project is built with Next.js and served by the Next.js Node server in production (e.g. in Docker). The reverse proxy (e.g. Nginx, Traefik) should route traffic to the container’s app port.
- Overview
- Pages
- Tech Stack
- Rendering Strategy
- Auth callbacks
- Project Structure
- Environment Variables
- Getting Started
- Scripts
- Docker
- CI
- Build & Hosting
- Troubleshooting
- Documentation
- License
What the application does:
GrowTheMusicTree is a web platform that allows users to explore and understand musical genres through an interactive, community-driven genre tree map. Users can visualize relationships between genres, connect their Spotify accounts to analyze their listening habits, and participate in genre classifications.
Target users:
Music enthusiasts, researchers, and the general public interested in understanding music taxonomy and discovering new genres.
High-level features:
- Interactive genre tree visualization using D3.js
- Spotify OAuth integration for music library analysis
- AI-powered genre detection for tracks
- Smart playlist generation based on musical journeys
- Community discussions and voting on genre classifications
- Rich contextual information for each genre (historical, cultural, technical)
- Home (
/) - About (
/about) - Account (
/account) - Google Auth Callback (
/auth/google/callback) - Spotify Auth Callback (
/auth/spotify/callback) - Genre Playlists (
/genre-playlists) - My Genre Tree (
/my-genre-tree) - Reference Genre Tree (
/reference-genre-tree) - Spotify Library (
/spotify-library) - Uploaded Library (
/uploaded-library)
See docs/pages/ for detailed page documentation.
- Framework: Next.js 15 with App Router
- Language: TypeScript
- Rendering: Next.js (Node server in production)
- Styling: Tailwind CSS
- Testing: Vitest
- CI: GitHub Actions
- Containerization: Docker (build and serve with Node)
- Additional libraries: React 19, D3.js, TanStack Query, React Howler, Sentry
The app is built with Next.js and served by the Node runtime in production:
next buildproduces the.next/output- The container runs
next startand serves the app onAPP_PORT - The reverse proxy (Nginx, Traefik, etc.) must proxy to the container’s port rather than to a static file root
Google and Spotify OAuth redirect the user to /auth/google/callback or /auth/spotify/callback. The layout-level component AuthCallbackHandler (src/components/auth/AuthCallbackHandler.tsx) runs in the app shell on every load, reads window.location to detect these paths, exchanges the code with the backend, shows "Connecting…" or an error popup, then redirects. With the Next.js server, the callback route is served and mounted normally.
.
├── app/ # Next.js App Router pages
├── components/ # React components
│ ├── features/ # Feature-specific components
│ └── ui/ # Reusable UI components
├── contexts/ # React contexts for state management
├── hooks/ # Custom React hooks
├── lib/ # Utility libraries and helpers
├── models/ # Data models and types
├── schemas/ # API and domain schemas
├── types/ # TypeScript type definitions
├── utils/ # Utility functions
├── public/ # Static assets
├── env/ # Environment configuration
├── scripts/ # Build and setup scripts
├── .github/workflows/ # CI/CD workflows
├── Dockerfile # Docker build configuration
├── next.config.js # Next.js configuration
├── package.json # Dependencies and scripts
├── tailwind.config.js # Tailwind CSS configuration
├── vitest.config.ts # Testing configuration
└── README.md
Environment variables are resolved at build time.
Create a local environment file:
cp env/development/example/.env.development.example .env.localExample variables:
NODE_ENV=development
PORT=3000
[email protected]
NEXT_PUBLIC_BACKEND_BASE_URL=https://api.themusictree.org/v2/
NEXT_PUBLIC_SENTRY_IS_ACTIVE=false
NEXT_PUBLIC_SPOTIFY_AUTH_URL=https://accounts.spotify.com/authorize
NEXT_PUBLIC_SPOTIFY_CLIENT_ID=your-spotify-client-id
NEXT_PUBLIC_SPOTIFY_REDIRECT_URI=/auth/spotify/callback
NEXT_PUBLIC_SPOTIFY_SCOPES=user-read-email playlist-read-private playlist-read-collaborative user-library-read user-top-read
NEXT_PUBLIC_GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
NEXT_PUBLIC_GOOGLE_REDIRECT_URI=/auth/google/callback
NEXT_PUBLIC_AUDIOMETA_URL=https://audiometa.themusictree.org
In the Spotify Developer Dashboard → your app → Settings → Redirect URIs, add the full callback URL(s), e.g. http://localhost:3000/auth/spotify/callback for local dev and your production URL for deploy. The app builds the redirect URI from your origin when you use a path like /auth/spotify/callback.
For Google sign-in, in Google Cloud Console → APIs & Services → Credentials, create an OAuth 2.0 Client ID (Web application) and add the full redirect URI(s) under "Authorized redirect URIs", e.g. http://localhost:3000/auth/google/callback.
Notes:
- Only variables prefixed with
NEXT_PUBLIC_are available in the browser NEXT_PUBLIC_AUDIOMETA_URL(required): URL of the external Audio Metadata app. Sidebar link "Audio Metadata" opens this URL in a new tab. Build fails if unset. In CI/deploy this is built from GitHub varsAUDIOMETA_SUBDOMAINandDOMAIN_NAMEashttps://<AUDIOMETA_SUBDOMAIN>.<DOMAIN_NAME>.- Changing env values requires a new build (restart
npm run devafter env changes) - Do not commit
.env.local - Preset configs: Put
.env.development.api-localand.env.development.api-remoteinenv/development/available/(seeenv/development/example/.env.development.api-*.example). Then run./scripts/setup-env-dev.sh localor./scripts/setup-env-dev.sh remoteto copy one to.env.development.local; Next.js only loads env files from the project root. Contents ofenv/development/available/are gitignored.
- Node.js >= 18
- npm / yarn / pnpm
- Docker (optional, for containerized builds)
npm install --legacy-peer-depsNote: We use --legacy-peer-deps to handle peer dependency conflicts, particularly with ESLint and its plugins.
| Command | Description |
|---|---|
npm run dev |
Start local development server |
npm run build |
Build for production |
npm run start |
Start production server (Node) |
npm run lint |
Run ESLint |
npm run verify-env |
Verify environment configuration |
npm run test |
Run unit tests |
npm run test:watch |
Run tests in watch mode |
npm run test:ui |
Run tests with UI |
npm run test:coverage |
Run tests with coverage |
Production and staging hosting use Vercel (see docs/DEPLOYMENT.md). Docker is optional for local runs or self-hosted deployment. The Dockerfile builds the app and runs the Next.js server inside the container; the entrypoint builds at startup, then runs next start on APP_PORT.
Build image:
docker build -t grow-the-music-tree-frontend --build-arg PROJECT_DIR=/home/app/ .Run container:
docker run -p 3000:3000 -e APP_PORT=3000 -e APP_VERSION=0.1.0 \
-e NEXT_PUBLIC_*="..." grow-the-music-tree-frontendContinuous Integration runs on each push to main branch and pull requests.
The CI pipeline includes:
- Dependency installation
- Linting
- Testing
- Build check
Staging builds use Vercel Git on develop. Production uses .github/workflows/vercel-deploy.yml when you push a semver release tag vX.Y.Z (must match package.json) or run the workflow manually (sets NEXT_PUBLIC_APP_VERSION, then the production deploy hook). Full NEXT_PUBLIC_* sync from GitHub is manual: .github/workflows/vercel-sync-env.yml. See docs/DEPLOYMENT.md.
GitHub Actions (simplified):
# vercel-deploy.yml — semver release tag or manual
on:
push:
tags: ['v*.*.*']
workflow_dispatch:
jobs:
deploy-production:
steps:
- checkout
- sync NEXT_PUBLIC_APP_VERSION to Vercel production
- POST production deploy hook
# vercel-sync-env.yml — manual only
on: workflow_dispatch
jobs:
sync-production / sync-preview:
steps:
- checkout
- sync all mapped NEXT_PUBLIC_* to Vercel (no hook)npm run build
npm run startBuild output: .next/. The app is served by the Next.js Node server.
Deployment: The app can be deployed to Vercel (recommended) or run in Docker. See docs/DEPLOYMENT.md for Vercel staging and production setup, including the env sync workflow from GitHub to Vercel. For Docker, the container builds once at startup then runs next start; the reverse proxy (Nginx, Traefik, etc.) should proxy to the container’s APP_PORT.
-
Auth callback shows no "Connecting with Google/Spotify...", no network request: Callbacks are handled by
AuthCallbackHandlerin the app shell (see Auth callbacks). With the Next.js server, the callback URL is served by the app; ensure the reverse proxy forwards/auth/.../callbackto the container. If the backend exchange never runs: (1) Cache — Do a hard refresh (Ctrl+Shift+R / Cmd+Shift+R) or open the callback URL in an incognito window. (2) Check the browser console for errors. -
Environment variables not applied: Rebuild required after env changes
-
Clear local cache:
rm -rf .next node_modules npm install --legacy-peer-deps
-
Ensure Node.js version compatibility: Requires Node.js >= 18
-
Peer dependency issues: Use
--legacy-peer-depsflag
For additional information about this project, please refer to:
- VISION.md - Project vision and goals
- CONTRIBUTING.md - Contribution guidelines and development setup
- CHANGELOG.md - Detailed history of changes
- CODE_OF_CONDUCT.md - Community code of conduct
- TODO.md - Current development tasks and roadmap
- docs/VERSIONING.md - Versioning strategy and guidelines
- docs/DEPLOYMENT.md - Vercel staging and production setup
- docs/REVERSE_PROXY_CONFIG.md - Nginx/reverse-proxy configuration for deployment
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.