6.0 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Development Commands
Building
# Build the application
go build -o naviwatcher
# Build with race detector
go build -race -o naviwatcher
# Cross-platform build examples
GOOS=linux GOARCH=amd64 go build -o naviwatcher-linux
GOOS=darwin GOARCH=amd64 go build -o naviwatcher-mac
GOOS=windows GOARCH=amd64 go build -o naviwatcher.exe
Running
# Run the application
./naviwatcher
# Run with specific config file
./naviwatcher -config=/path/to/config.yaml
# Run in development mode (if implemented)
go run main.go
Testing
# Run all tests
go test ./...
# Run tests with coverage
go test ./... -cover
# Run a specific test package
go test ./internal/scanner
# Run tests verbose
go test ./... -v
Dependency Management
# Add a new dependency
go get github.com/example/package@v1.2.3
# Update dependencies
go get -u ./...
# Tidy up dependencies
go mod tidy
# Vendor dependencies (if needed)
go mod vendor
Linting and Formatting
# Format code
go fmt ./...
# Vet for potential issues
go vet ./...
# Static analysis (if golangci-lint is installed)
golangci-lint run
Docker
# Build Docker image
docker build -t naviwatcher .
# Run with docker compose
docker compose up
# Run in background
docker compose up -d
# View logs
docker compose logs -f
Code Architecture
Based on the specification (docs/Specification.md), the application follows a modular architecture:
Core Modules
-
Navidrome Client (
internal/navidrome/or similar)- Handles Subsonic API communication
- Fetches artist and album data from Navidrome instance
- Implements authentication and error handling
-
MusicBrainz Provider (
internal/musicbrainz/or similar)- Interfaces with MusicBrainz API
- Implements rate limiting (1 request/second)
- Manages caching of artist discographies (24-hour TTL)
- Works with Release Group (RG) entities to minimize duplicates
-
Scanner Engine (
internal/scanner/or similar)- Normalizes string comparisons for fuzzy matching
- Implements the comparison algorithm (0.85 similarity threshold)
- Handles removal of special characters, years, and bracketed keywords
- Compares local albums vs. external discographies
Shared normalization lives in
internal/normalize(NormalizeString,NormalizeArtistName) — this is the single source of truth for string normalization, reused by bothinternal/musicbrainzandinternal/scanner. Do NOT add local copies of normalization logic elsewhere. -
Database Layer (
internal/database/or similar)- SQLite 3 integration via github.com/mattn/go-sqlite3
- Subsonic API client via github.com/delucks/go-subsonic
- Manages schema migrations
- Handles tables:
artist_settings: Artist monitoring configurationlocal_albums: Navidrome albums synced via Subsonic API (id, artist_id, title)external_releases: Cached MusicBrainz datanotifications_sent: Sent notification tracking
-
Notifier (
internal/notifier/or similar)- Telegram bot integration
- Scheduled task execution (cron-based)
- Batch notification sending
- Message formatting with Web UI links
-
Web UI (
internal/web/or similar)- Go standard library net/http + html/template
- Embedded templates using //go:embed
- Basic authentication protection
- Dashboard for viewing missing albums
- Artist detail views with ignore functionality
- Archive view for previously ignored releases
Key Technical Requirements
- Concurrency: Separate goroutines for external API calls to keep web UI responsive
- Rate Limiting: Strict adherence to MusicBrainz 1 request/second limit
- Graceful Shutdown: Proper SIGTERM handling to close database connections
- Configuration: YAML-based config (config.yaml) with environment-specific overrides
- Static Assets: HTML templates embedded via //go:embed for single-binary deployment
- Data Modeling: Focus on Release Group entities rather than specific releases
Common Development Patterns
- Use context.Context for cancellation and timeouts
- Implement proper error handling with logging
- Follow Go idioms and conventions
- Write table-driven tests for complex logic
- Use dependency injection for testability
- Apply the specified fuzzy matching algorithm consistently
- Centralize shared logic: Place reusable filtering, validation, or utility functions in dedicated files (e.g., internal/musicbrainz/filter.go) and import them across packages to ensure consistent behavior across cache-hit, cache-miss, and real-time paths
Execution Flow
The application follows a sequential data pipeline:
- Sync artists from Navidrome (populate artist_settings)
- Sync discographies from MusicBrainz (populate external_releases with filtering)
- Sync albums from Navidrome (populate local_albums)
- Scan for missing releases using fuzzy matching (produces MissingRelease results)
This flow is implemented in the syncAndScan() function in cmd/naviwatcher/main.go, which is called by the periodic sync loop and on startup.
Configuration Reference
See docs/Specification.md Section 7 for full config.yaml structure including:
- Server settings (host, port, basic auth)
- Navidrome connection details
- MusicBrainz API configuration
- Telegram notification settings
- Scanner parameters (fuzzy threshold, filters)
Database Schema
See docs/Specification.md Section 5 for complete SQLite schema including:
- artist_settings table columns and defaults
- external_releases table structure
- notifications_sent table for tracking
Getting Started
- Copy config.yaml.example to config.yaml and fill in your values
- Ensure Navidrome instance is running and accessible
- Set up Telegram bot and obtain token/chat ID
- Initialize database: ./naviwatcher (will create tables on first run)
- Start the service: ./naviwatcher
- Access Web UI at http://localhost:8080 (or configured host/port)