The album diary for people with real opinions.
Music4You is a Letterboxd-style music web app where you rate albums, pin favourite records to your public profile, and follow a daily editorial pick. Built as a full-stack Next.js project with a clean provider/database architecture ready for Spotify and Supabase at scale.
- π Rate albums 1β10 and have your score contribute to a community average.
- β€οΈ Pick four favourite albums directly from album pages, with replacement flow when your profile is already full.
- π€ Build a public music identity β custom display name, bio, avatar, and a shareable
/u/[username]profile showing your four favourite albums and four most recent ratings. - π Album of the Day β one record gets the spotlight for the full day, then moves to an archive that never repeats until the catalog runs out.
- π Discovery feed β a curated grid of albums to explore, backed by a swappable provider interface.
- π Authentication β sign up, sign in, sign out via Supabase Auth with route-level middleware that keeps auth pages clean for signed-in users.
- βοΈ Settings page β view and edit your profile, including avatar randomization.
| Layer | Technology |
|---|---|
| Framework | Next.js 15 (App Router) |
| UI | MUI v7 + Tailwind CSS v4 |
| Language | TypeScript |
| Auth + DB | Supabase (Auth, Postgres, RLS) |
| Notifications | react-hot-toast |
| Runtime | React 19 (Server + Client Components) |
Two core interfaces keep the app decoupled from any specific vendor:
MusicProvider β search albums, fetch album details, get featured albums
AlbumDatabase β persist albums, manage featured lists, drive the daily rotation
Swapping from mock data to Spotify, or from Supabase to another database, means writing a new adapter β not touching UI code.
Page (Server Component)
βββ MusicService cache-first orchestrator
βββ MusicProvider fetch from external API (Spotify / mock)
βββ AlbumDatabase read/write Supabase (Supabase.ts)
Middleware (proxy.ts) redirect signed-in users away from /signin, /signup
βββ getUser() server-only Supabase session check
βββ Server pages redirect to /signin if not authenticated
βββ Server actions validate session before any mutation
src/
βββ app/ # Next.js App Router routes
β βββ page.tsx # Landing page
β βββ layout.tsx # Root layout (Nav + Footer)
β βββ providers.tsx # MUI theme + toast provider (client boundary)
β βββ feed/ # Discovery album grid
β βββ album/[id]/ # Dynamic album detail + rating page
β βββ album-of-the-day/ # Daily editorial page
β βββ profile/ # Authenticated user profile (editable)
β βββ u/[username]/ # Public profile by username
β βββ settings/ # Account settings
β βββ signin/ # Sign-in form + server action
β βββ signup/ # Sign-up form + server action
β
βββ components/ # Shared UI components
β βββ daily/ # Daily album page sub-components
β β βββ DailyAlbumHero.tsx # Cover, title, stats, CTAs
β β βββ DailyTrackSpotlight.tsx # Track listing panel
β β βββ DailyArchive.tsx # Previous picks grid
β β βββ DailyRightColumn.tsx # Scoreboard + ritual info
β βββ Nav.tsx # Server nav shell with streaming auth slot
β βββ NavClient.tsx # Client nav with logo + links
β βββ PageFooter.tsx # Sitewide footer with links + contact
β βββ AlbumCard.tsx # Album cover card
β βββ AlbumGrid.tsx # Responsive album grid layout
β βββ AlbumView.tsx # Full album detail view
β βββ AlbumFavoriteSection.tsx # Favourite toggle + replacement flow
β βββ AlbumRatingSection.tsx # Rating form + community score display
β βββ FavoriteReplaceDialog.tsx # Choose which favourite album to swap out
β βββ SongView.tsx # Individual track row
β βββ DailyAlbumPageView.tsx # Orchestrator for daily page sections
β βββ ProfilePageView.tsx # User profile layout
β βββ ProfileAvatar.tsx # Avatar with initials fallback
β βββ ProfileEditDialog.tsx # Edit profile dialog
β
βββ actions/ # Next.js Server Actions
β βββ users.ts # Sign up, sign in, sign out
β βββ favorites.ts # Add/remove/replace profile favourites
β βββ profiles.ts # Update profile
β βββ reviews.ts # Submit album rating
β
βββ auth/ # Supabase client factories
β βββ server.ts # SSR-aware server client + session helpers
β βββ client.ts # Browser client
β βββ admin.ts # Service-role admin client (server-only)
β βββ env.ts # Environment variable validation
β
βββ lib/
β βββ db/
β β βββ errors.ts # Shared DB error utilities (unique violation, etc.)
β βββ favorites/
β β βββ types.ts # Favourite album domain types
β β βββ server.ts # Favourite fetch + mutation helpers
β βββ music/
β β βββ types.ts # Core contracts: AlbumData, MusicProvider, AlbumDatabase
β β βββ Music.ts # MusicService factory (singleton)
β β βββ MusicService.ts # Cache-first orchestrator for all music data
β β βββ Supabase.ts # AlbumDatabase implementation
β β βββ server.ts # Shared album-row persistence helpers for mutations
β β βββ mappers.ts # DB row β domain type transformations
β β βββ supabaseQueries.ts # Low-level Supabase query builders
β β βββ dailyAlbum.ts # Date/time utilities for daily rotation
β β βββ discovery.ts # Cached discovery feed helpers
β β βββ constants.ts # Shared slug/limit constants
β β βββ Spotify.ts # Spotify provider stub (in progress)
β β βββ testing/ # Mock provider + seeded album data
β βββ profiles/
β β βββ types.ts # Profile domain types
β β βββ server.ts # Profile fetch, create, update (server-only)
β β βββ format.ts # Date/display formatting for profiles
β β βββ avatar.ts # DiceBear avatar URL generation
β β βββ validation.ts # Username rules + profile input validation
β βββ reviews/
β βββ types.ts # Rating domain types
β βββ server.ts # Rating fetch + upsert (server-only)
β
βββ proxy.ts # Middleware: auth redirects
| Table | Purpose |
|---|---|
profiles |
User profile data (username, display name, bio, avatar) |
albums |
Persisted album records with provider metadata |
reviews |
User ratings (1β10) per album |
profile_favorite_albums |
Up to four public favourite albums per user |
featured_lists |
Named curated lists (feed, daily rotation) |
featured_list_items |
Albums assigned to a list with rank |
npm installcp .env.example .env.localRequired:
NEXT_PUBLIC_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY
SUPABASE_SERVICE_ROLE_KEY
npm run supabase:startReset to a clean database from migrations:
npm run supabase:db:resetIf you are connected to a hosted Supabase project, push new migrations after schema changes:
npm run supabase:db:pushnpm run devOpen http://localhost:3000.
| Command | Description |
|---|---|
npm run dev |
Start local dev server |
npm run build |
Production build |
npm run start |
Run production build |
npm run lint |
Lint project |
npm run supabase:start |
Start local Supabase stack |
npm run supabase:stop |
Stop local Supabase stack |
npm run supabase:status |
Print local Supabase URLs and keys |
npm run supabase:db:reset |
Rebuild local DB from repo migrations |
npm run supabase:db:push |
Push local migrations to hosted Supabase |
npm run supabase:migration:new -- <name> |
Create a new migration file |
Migrations live in supabase/migrations β the repo is the source of truth, not the dashboard. Use the dashboard for logs, data inspection, and auth settings only.
When you pull code that adds a new schema-backed feature, make sure the matching migration has been applied before testing the UI. For this favourites feature, that means 20260412000000_profile_favorite_albums.sql must exist in the target database or the app will fail when it queries profile_favorite_albums.
# Create a new migration
npm run supabase:migration:new -- add_playlists
# Apply full history locally
npm run supabase:db:reset
# Link to hosted project once
npx supabase link --project-ref <your-project-ref>
# Push to hosted project
npm run supabase:db:push- π Wire nav search to
MusicService.searchAlbums - π§ Complete Spotify provider implementation
- π€ Friends / social graph
- π Album lists and year-in-review summaries
- π Ratings connected to daily scoreboard
Music4You demonstrates product-quality full-stack engineering:
- π§± Server/client boundary discipline β data fetching and mutations stay on the server; the client only handles interactivity.
- π Interface-driven architecture β
MusicProviderandAlbumDatabaseare contracts, not implementations. Spotify and any future database are drop-in replacements. - π§© Modular codebase β domain logic (music, profiles, reviews) is isolated in
lib/, shared utilities (db/errors,music/mappers) prevent duplication, and large components are split into focused sub-components. - π Auth done right β SSR-aware Supabase clients, service-role admin isolation, and middleware-level redirect guards.
- π― Product thinking β discovery feed, shareable profiles, and a daily editorial feature that creates a reason to return every day.
Built by Raihan Carder πΆ