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>
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 withinindex.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) orCmd+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
- Dependency Injection: FastAPI's
Depends()for database sessions (DBSession) and authentication (CurrentUser) - Service Layer: All business logic in
/services- API routes are thin, delegating to services - Repository Pattern: Services handle database operations using async SQLAlchemy
- Async/Await: All database operations and external API calls are async
- JWT Authentication: Token-based auth with
get_current_userdependency
Type Aliases (from app/api/dependencies.py)
Important type aliases used throughout the codebase:
DBSession=Annotated[AsyncSession, Depends(get_db)]- Inject database sessionCurrentUser=Annotated[User, Depends(get_current_user)]- Inject authenticated userCurrentUserOptional=Annotated[Optional[User], Depends(get_current_user_optional)]- Inject user if authenticatedAuthServiceDep=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:
User→Playlist(one-to-many)User→LikedTrack(one-to-many)User→ListeningHistory(one-to-many)Playlist→PlaylistTrack→Track(many-to-many through join table)Track→Artist(many-to-one)Track→Album(many-to-one)
Frontend Architecture
- Single Page Application: All views are in
index.html, shown/hidden via JavaScript - State Management:
AppStateobject inapp.jsholds current state (track, queue, user, etc.) - DOM Elements:
DOMobject 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>inindex.html) - No Framework: Pure vanilla JavaScript with DOM manipulation
- Window Assignment: All functions called from HTML
onclickhandlers must be assigned towindowobject
Key frontend functions:
showPage(pageId)- Switch between views (home, search, library, etc.)updatePlayerUI()- Update player displayshowToast(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
- User receives JWT token on login (
/api/v1/auth/login) - Token stored in
localStorage(authToken) - All API requests include
Authorization: Bearer <token>header get_current_userdependency validates token and injects user
YouTube Integration
YouTubeServicehandles YouTube search and stream URL extraction- Audio streamed via
/api/v1/music/youtube/{video_id}/streamendpoint - 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
- Add Pydantic schemas in
app/schemas/ - Add business logic in
app/services/ - Add route handler in
app/api/v1/ - 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
- Update model in
app/models/ - Create migration:
alembic revision --autogenerate -m "description" - Review generated migration in
alembic/versions/ - Apply migration:
alembic upgrade head - Update Pydantic schemas
Important: Always review auto-generated migrations before applying!
Frontend State Updates
When modifying frontend behavior:
- Modify
AppStateobject for state changes - Update DOM elements cached in
DOMobject - Call
updatePlayerUI()orrenderTracks()as needed - Use
showToast(message, type)for user feedback - CRITICAL: Assign new functions to
windowif called from HTMLonclick
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.pyprovides 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 functionsasyncio_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
.envmatches Docker config - Run migrations:
alembic upgrade head
Authentication Errors (401)
- Check
SECRET_KEYis 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.jsfunctions are assigned towindowobject (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