Skip to content

madhavcodez/SoundScoreV0.1

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

51 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SoundScore — Letterboxd for music

iOS Android Backend TypeScript PostgreSQL Redis Gemini License: MIT Open Source

Log what you listen to · rate in half-stars · follow friends · discover new sound.

Overview · Screens · Capabilities · Architecture · Spotlights · Tech · Get started · Contribute


🎯 Overview

SoundScore is a cross-platform music logging and social discovery app — think Letterboxd, but for albums.

Rate albums on a real 0–6 scale with half-star precision. Write reviews. Build curated lists. Follow friends and react to what they're spinning. Get Gemini-powered recommendations based on what you actually rate. All delivered through native iOS + Android clients backed by a single TypeScript / Fastify API and shared Zod contracts.

This is an open-source sandbox project. Built as a learning exercise and creative outlet. If you find it interesting, want to pick up where I left off, or want to contribute — go for it.

Clients Backend Database Cache AI
SwiftUI + Compose Fastify · Zod · Pino PostgreSQL 15 Redis Gemini

📱 iOS screens

Welcome Screen Feed — Trending & Collections Discover — Genre Browsing Album Detail & Rating

Search Results Social Feed — Activity from Friends

Live screenshots from the shipping SwiftUI build · emerald theme.


✨ Capabilities

Capabilities overview

# Capability What it does Status
1 Log · Rate · Review 0–6 rating with half-star precision; editable reviews with optimistic concurrency
2 Social feed Follow users, see their logs / reviews / lists, react and comment — Redis-fanned
3 Discover Genre browsing, Postgres full-text search (tsvector + GIN), trending
4 Curated lists Public or private album collections, ordered, shareable
5 Weekly recaps Auto-generated insights: albums logged, avg rating, top pick, new follows
6 Push notifications Follow alerts, reactions, comments — via push module
7 Theming 6 accent themes reskin the entire app — Emerald · Amethyst · Bonfire · Rose · Midnight · Gilt
8 GDPR tooling Full account data export + deletion
9 Gemini recs Recommendation engine wired on backend, mobile integration pending 🛠
10 Spotify OAuth Listening history import + sync, provider-agnostic canonical album mapping 🛠

🏗️ Architecture

SoundScore architecture

flowchart TB
  subgraph Clients["📱 Native Clients"]
    IOS["iOS · SwiftUI<br/>Combine · URLSession"]
    AND["Android · Jetpack Compose<br/>StateFlow · Hilt · Room"]
  end

  subgraph API["⚡ Fastify API (TypeScript)"]
    direction LR
    AUTH[auth] --- CAT[catalog] --- OPN[opinions]
    SOC[social] --- LST[lists] --- REC[recaps]
    PSH[push] --- IMP[import] --- PRV[providers]
    MAP[mapping] --- TRU[trust]
  end

  subgraph Data["💾 Data Layer"]
    PG[("PostgreSQL 15<br/>tsvector · GIN")]
    RD[("Redis<br/>sessions · fan-out · rate limit")]
  end

  subgraph Ext["🌐 External Providers"]
    SP[Spotify OAuth]
    MB[MusicBrainz]
    GM[Gemini]
  end

  IOS -- "HTTPS · /v1/*" --> API
  AND -- "HTTPS · /v1/*" --> API
  API --> PG
  API --> RD
  API --> SP
  API --> MB
  API --> GM

  classDef client fill:#061A10,stroke:#1ED760,color:#F2F5F3
  classDef api fill:#0A2A18,stroke:#1ED76088,color:#F2F5F3
  classDef data fill:#061A10,stroke:#4FC3F755,color:#F2F5F3
  classDef ext fill:#061A10,stroke:#B388FF55,color:#F2F5F3
  class IOS,AND client
  class AUTH,CAT,OPN,SOC,LST,REC,PSH,IMP,PRV,MAP,TRU api
  class PG,RD data
  class SP,MB,GM ext
Loading

Defining properties

  • 36 API routes across 11 domain modules (auth, catalog, opinions, social, lists, recaps, push, import, providers, mapping, trust)
  • Shared Zod contracts in packages/contracts/ — one source of truth for request/response shapes across Android, iOS, and backend
  • Idempotency-key enforcement on every mutating route
  • Redis-cached feed fan-out, sessions, rate limiting
  • Postgres full-text search via tsvector + GIN indexes (album/artist lookup lands in <90 ms p95)

Rating mutation · lifecycle

sequenceDiagram
  autonumber
  participant C as Client (iOS/Android)
  participant F as Fastify /v1/opinions
  participant Z as Zod validator
  participant P as Postgres
  participant R as Redis
  participant S as Social fan-out

  C->>F: POST { album, rating, idempotencyKey }
  F->>Z: validate payload
  Z-->>F: ok
  F->>P: UPSERT opinion (opinion_version++)
  P-->>F: row + version
  F->>R: cache opinion + invalidate album agg
  F->>S: enqueue feed fan-out (followers)
  F-->>C: 200 { opinion, version }
  S-->>R: push feed items for followers
Loading

Opinion state

stateDiagram-v2
  [*] --> draft
  draft --> logged: submit rating
  logged --> edited: edit review/rating
  edited --> edited: re-edit (version++)
  logged --> deleted: GDPR purge
  edited --> deleted: GDPR purge
  deleted --> [*]
Loading

🔥 Feature spotlights

A real rating system · not five stars

Rating spotlight

Thirteen increments from 0.0 to 6.0. Every half-star matters. Every edit bumps opinion_version so concurrent edits can't clobber each other — the server resolves with optimistic concurrency and returns the authoritative version.

Social feed that's actually fast

The social module writes to per-user feed keys in Redis when a followed user logs an album, reacts, or publishes a list. Clients read a prebuilt feed instead of querying the graph — no N+1 fan-out at read time. Expiry is capped so cold followers don't blow up memory.

6 themes · whole-app reskin

The iOS ThemeManager publishes an AccentTheme (Emerald · Bonfire · Rose · Amethyst · Midnight · Gilt). Every screen binds to ThemeManager.shared.primary / secondary / colors.darkBase. Picking a theme in Settings re-renders the entire app — backdrop glows, album gradient overlays, tab bar accents, everything.

Gemini-powered recommendations

The backend exposes a recommendation endpoint that takes a user's rating history, sends a compact prompt to Gemini, and returns a structured list of album recs with a "because you rated X" explanation. Mobile surfacing is in progress; the API is live.


🛠️ Tech stack

Layer Stack
iOS Swift · SwiftUI · Combine · URLSession
Android Kotlin · Jetpack Compose · StateFlow · Hilt · OkHttp · Room
Backend TypeScript · Fastify 4.x · Pino · Zod
Contracts packages/contracts/ — shared Zod schemas consumed by backend + type-gen for clients
Database PostgreSQL 15 (tsvector + GIN full-text search)
Cache Redis — sessions, feed fan-out, rate limit buckets
AI Google Gemini (recommendation engine)
Infra Docker Compose (local Postgres + Redis) · Railway (prod)
Tooling Node 20 · Xcode 16+ · Android Studio · Gradle Kotlin DSL

🚀 Getting started

Prerequisites

  • Node.js 20+
  • Docker (for local Postgres + Redis)
  • Xcode 16+ (for iOS)
  • Android Studio (for Android)

Backend

docker compose up -d
npm install
npm run migrate --workspace backend
npm run dev --workspace backend

Server runs at http://localhost:8080.

iOS

Open ios/SoundScore/SoundScore.xcodeproj in Xcode, pick a simulator, hit Run. The app auto-authenticates against the local backend in debug mode.

Android

./gradlew installDebug

Or open the project in Android Studio and run on a device / emulator.


🗂️ Project structure

SoundScoreV0.1/
├── app/                    # 📱 Android app (Kotlin + Jetpack Compose)
│   └── src/main/java/
│       ├── data/           #   Repository · API client · DTOs
│       └── ui/             #   Screens · ViewModels · theme
│
├── ios/                    # 🍎 iOS app (Swift + SwiftUI)
│   └── SoundScore/
│       ├── Screens/        #   10 screens + ViewModels
│       ├── Components/     #   Reusable UI (glass cards, rating bar, etc.)
│       └── Theme/          #   6 accent themes + typography
│
├── backend/                # ⚡ Fastify API
│   └── src/
│       ├── modules/        #   11 domain modules
│       ├── lib/            #   18 shared utilities
│       └── db/             #   Schema migrations
│
├── packages/contracts/     # 📦 Shared Zod schemas
├── docs/                   # 📖 Architecture, audit logs, screenshots
└── docker-compose.yml      # 🐳 Local Postgres + Redis

📊 Stats

Android iOS Backend
Source files 33 67 45
Lines of code ~4,900 ~8,300 ~5,500
API routes wired 18 22 36
Domain modules 11
Themes 6
Tests ~96

🎨 Design tokens

Token Value Used for
darkBase #020A04#0A0802 (per-theme) App background
darkSurface #061A10 → theme variant Card / list surface
darkElevated #0A2A18 → theme variant Modals, sheets
glassBg rgba(255,255,255,0.07) Glass morphism cards
glassBorder rgba(255,255,255,0.18) Glass edges
accentEmerald #1ED760 Primary (default theme)
accentAmethyst #B388FF Purple theme / violet semantic
accentBonfire #FF8C42 Orange theme
accentRose #FF6B8A Pink theme
accentMidnight #4FC3F7 Blue theme
accentGilt #FFD54F Gold theme

🤝 Contributing

This started as a solo sandbox project. If you want to pick it up, extend it, or fork it as a foundation — go for it.

Areas that could use work:

  • Android parity with iOS (5 screens still missing)
  • Phase 2 Spotify integration on mobile clients
  • Surface Gemini recs in the UI
  • Test coverage (currently backend-only, ~96 tests)
  • CI / CD pipeline hardening

Branch strategy

Branch prefix Purpose
main Stable
feat/<description> New features
fix/<description> Bug fixes

Commit format

<type>: <description>

Types: feat · fix · refactor · docs · test · chore · perf · ci


🔗 Related

  • SoundScore Web (Legacy) — the original 2025 web prototype (React + Express + MongoDB). Archived as a reference.

📄 License

MIT · Built by @madhavcodez

Log what you listen to. Share what you love.

About

Open-source sandbox — cross-platform music logging app (Android + iOS + TypeScript backend). Letterboxd for music.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors