Files
AudiOhm/CLAUDE.md
T
root bc03225e47 docs: Improve CLAUDE.md with project documentation
Add comprehensive guidance for Claude Code working in this repository:
- Alembic config location clarification
- Docker Compose scope (database services only)
- Frontend serving explanation (FastAPI root route)
- Tailwind config location (in HTML script tag)
- Pytest async configuration details

Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-01-20 09:48:17 +00:00

12 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

AudiOhm is a music streaming application (Spotify alternative) with YouTube audio streaming. The architecture consists of:

  • Backend: FastAPI (Python 3.13+) with async SQLAlchemy, PostgreSQL, and Redis
  • Frontend: Pure HTML/JavaScript with Tailwind CSS (no framework - served directly by FastAPI)
  • Streaming: YouTube audio via yt-dlp
  • Authentication: JWT-based auth

The project uses a service-oriented architecture with clear separation between API routes, business logic (services), data models, and schemas.

File Locations

  • Backend code: /opt/audiOhm/backend/app/
  • Frontend code: /opt/audiOhm/backend/app/static/ and /opt/audiOhm/backend/app/templates/
  • Tests: /opt/audiOhm/backend/tests/
  • Migrations: /opt/audiOhm/backend/alembic/ (config at /opt/audiOhm/backend/alembic.ini)
  • Working directory for all commands: /opt/audiOhm/backend/

Development Commands

Backend Development

# Start backend with hot-reload (from /opt/audiOhm/backend)
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

# Or using the module directly
python -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

Database Operations

# From /opt/audiOhm/backend

# Run migrations
alembic upgrade head

# Create a new migration
alembic revision --autogenerate -m "description"

# Rollback one migration
alembic downgrade -1

# View migration history
alembic history

Testing

# From /opt/audiOhm/backend

# Run all tests
pytest

# Run specific test file
pytest tests/api/test_auth.py

# Run with coverage
pytest --cov=app tests/

# Run specific test function
pytest tests/api/test_library.py::test_get_liked_tracks -v

Docker Services (PostgreSQL + Redis)

Note: Docker Compose is only for database services (PostgreSQL + Redis), not the FastAPI backend.

# From /opt/audiOhm (not /opt/audiOhm/backend)
docker-compose -f docker/docker-compose.yml up -d

# Stop services
docker-compose -f docker/docker-compose.yml down

# View logs
docker-compose -f docker/docker-compose.yml logs -f postgres

Code Quality

# From /opt/audiOhm/backend

# Format code
black app/ tests/

# Lint code
ruff check app/ tests/

# Type checking
mypy app/

Frontend Development

The frontend is a single-page application (SPA) with no build process:

  • HTML: app/templates/index.html - All views in one file, served directly by FastAPI at root route /
  • JavaScript: app/static/js/app.js - All frontend logic
  • CSS: app/static/css/style.css - Minimal custom CSS (Tailwind is primary)
  • Tailwind Config: Defined in <script> tag within index.html (no separate config file)
  • No build step: Edit files directly and refresh browser

After editing frontend files:

  • Hard refresh browser: Ctrl+Shift+R (Linux/Windows) or Cmd+Shift+R (Mac)
  • Clear browser cache if needed
  • Check browser console for errors

Architecture Overview

Backend Structure

backend/app/
├── api/
│   ├── dependencies.py    # FastAPI dependencies (DB session, auth)
│   └── v1/                # API route handlers (auth, music, playlists, library)
├── core/
│   ├── config.py          # Pydantic Settings with environment variables
│   ├── database.py        # SQLAlchemy async engine and session management
│   ├── security.py        # JWT, password hashing
│   └── rate_limiter.py    # Rate limiting with slowapi
├── models/                # SQLAlchemy ORM models (user, track, artist, album, playlist, etc.)
├── schemas/               # Pydantic schemas for request/response validation
├── services/              # Business logic layer
│   ├── auth_service.py
│   ├── music_service.py
│   ├── youtube_service.py
│   ├── playlist_service.py
│   └── library_service.py
├── static/
│   ├── css/style.css      # Minimal custom CSS (Tailwind is primary)
│   └── js/app.js          # All frontend JavaScript (SPA functionality)
└── templates/
    └── index.html         # Single-page app HTML with Tailwind classes

Key Architecture Patterns

  1. Dependency Injection: FastAPI's Depends() for database sessions (DBSession) and authentication (CurrentUser)
  2. Service Layer: All business logic in /services - API routes are thin, delegating to services
  3. Repository Pattern: Services handle database operations using async SQLAlchemy
  4. Async/Await: All database operations and external API calls are async
  5. JWT Authentication: Token-based auth with get_current_user dependency

Type Aliases (from app/api/dependencies.py)

Important type aliases used throughout the codebase:

  • DBSession = Annotated[AsyncSession, Depends(get_db)] - Inject database session
  • CurrentUser = Annotated[User, Depends(get_current_user)] - Inject authenticated user
  • CurrentUserOptional = Annotated[Optional[User], Depends(get_current_user_optional)] - Inject user if authenticated
  • AuthServiceDep = Annotated[AuthService, Depends(get_auth_service)] - Inject auth service

Use these in route signatures for clean dependency injection:

async def my_endpoint(
    db: DBSession,
    current_user: CurrentUser,
) -> dict:
    # db and current_user are automatically injected

Database Models

Key relationships:

  • UserPlaylist (one-to-many)
  • UserLikedTrack (one-to-many)
  • UserListeningHistory (one-to-many)
  • PlaylistPlaylistTrackTrack (many-to-many through join table)
  • TrackArtist (many-to-one)
  • TrackAlbum (many-to-one)

Frontend Architecture

  • Single Page Application: All views are in index.html, shown/hidden via JavaScript
  • State Management: AppState object in app.js holds current state (track, queue, user, etc.)
  • DOM Elements: DOM object caches all DOM references for performance
  • API Communication: fetch() calls to /api/v1/* endpoints
  • Styling: Tailwind CSS utility classes with custom theme extension (defined in <script> in index.html)
  • No Framework: Pure vanilla JavaScript with DOM manipulation
  • Window Assignment: All functions called from HTML onclick handlers must be assigned to window object

Key frontend functions:

  • showPage(pageId) - Switch between views (home, search, library, etc.)
  • updatePlayerUI() - Update player display
  • showToast(message, type) - Show notification to user
  • All functions that interact with AppState

Important Implementation Details

Database Session Management

All database sessions are async and automatically committed/rolled back:

# In API routes
async def my_endpoint(db: DBSession):
    result = await db.execute(select(User))
    return result.scalars().all()
    # Session auto-commits after successful handler

Authentication Flow

  1. User receives JWT token on login (/api/v1/auth/login)
  2. Token stored in localStorage (authToken)
  3. All API requests include Authorization: Bearer <token> header
  4. get_current_user dependency validates token and injects user

YouTube Integration

  • YouTubeService handles YouTube search and stream URL extraction
  • Audio streamed via /api/v1/music/youtube/{video_id}/stream endpoint
  • Uses yt-dlp for URL extraction (not downloading)

Frontend Routing

Client-side routing in app.js:

  • showPage(pageId) function switches between views (home, search, library, etc.)
  • No server-side routing for pages (only API endpoints)
  • State persists across navigation

How the SPA is served: FastAPI's root route / (in app/main.py) serves index.html, which contains the entire single-page application. All other routes are API endpoints under /api/v1/.


Configuration

Environment Variables (.env in backend/)

Key variables (see app/core/config.py for full list):

# Database
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USER=spotify
POSTGRES_PASSWORD=spotify_password
POSTGRES_DB=spotify_le_2

# Redis
REDIS_HOST=localhost
REDIS_PORT=6379

# JWT
SECRET_KEY=change-this-in-production
ACCESS_TOKEN_EXPIRE_MINUTES=15

# Application
DEBUG=true
LOG_LEVEL=INFO

Tailwind CSS Configuration

Defined in <script> tag in index.html:

  • Primary colors: Cyan/blue (#0ea5e9)
  • Accent colors: Pink/magenta (#ec4899)
  • Dark mode enabled by default (class="dark" on <html>)

Common Patterns

Creating a New API Endpoint

  1. Add Pydantic schemas in app/schemas/
  2. Add business logic in app/services/
  3. Add route handler in app/api/v1/
  4. Register router in app/main.py

Example:

# app/api/v1/my_feature.py
from fastapi import APIRouter, Depends
from app.api.dependencies import DBSession, CurrentUser

router = APIRouter()

@router.get("/my-endpoint")
async def get_my_data(
    db: DBSession,
    current_user: CurrentUser,
) -> dict:
    # Your logic here - typically delegate to a service
    return {"data": "response"}

Adding Database Fields

  1. Update model in app/models/
  2. Create migration: alembic revision --autogenerate -m "description"
  3. Review generated migration in alembic/versions/
  4. Apply migration: alembic upgrade head
  5. Update Pydantic schemas

Important: Always review auto-generated migrations before applying!

Frontend State Updates

When modifying frontend behavior:

  1. Modify AppState object for state changes
  2. Update DOM elements cached in DOM object
  3. Call updatePlayerUI() or renderTracks() as needed
  4. Use showToast(message, type) for user feedback
  5. CRITICAL: Assign new functions to window if called from HTML onclick

Example:

// Define function
function myNewFunction() {
    // Your logic
}

// MUST assign to window if called from HTML
window.myNewFunction = myNewFunction;

Testing Strategy

  • Unit tests: Test services and business logic
  • API tests: Test endpoints with test database
  • Fixtures: conftest.py provides test DB and auth setup
  • Test files in backend/tests/api/ mirror API structure

Pytest Configuration (pytest.ini):

  • asyncio_mode = auto - Required for async test functions
  • asyncio_default_fixture_loop_scope = function - Isolated event loop per test

Common Issues

Database Connection Issues

  • Ensure Docker services are running: docker-compose -f docker/docker-compose.yml ps
  • Check connection string in .env matches Docker config
  • Run migrations: alembic upgrade head

Authentication Errors (401)

  • Check SECRET_KEY is set in .env
  • Verify token format: Authorization: Bearer <token>
  • Frontend: Check localStorage.getItem('authToken')

YouTube Streaming Issues

  • yt-dlp may need updates: pip install --upgrade yt-dlp
  • Some videos may be region-restricted or unavailable

Frontend Not Updating

  • Hard refresh browser: Ctrl+Shift+R
  • Check browser console for JavaScript errors
  • Verify app.js functions are assigned to window object (for HTML onclick handlers)

Default Credentials

Admin user (created on first run):

  • Email: admin@example.com
  • Password: admin123

Documentation References

  • Tailwind refactor info: /opt/audiOhm/TAILWIND_REFACTOR.md
  • Quick styling reference: /opt/audiOhm/QUICK_REFERENCE.md
  • Installation guide: /opt/audiOhm/INSTALLATION.md
  • API docs: Available at http://localhost:8000/api/docs (Swagger UI) when backend is running