# CLAUDE.md

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

## Commands

```bash
# Setup
cp .env.shadow .env
make pip_dev          # creates venv and installs all dependencies

# Development server (port 5000, or set PORT=XXXX)
make dev

# Lint
make lint             # ruff check backend/ tests/

# Auto-fix lint issues
make fmt

# Unit tests (excludes tests/integration/)
make test_unit

# Run a single unit test file
venv/bin/py.test tests/path/to/test_file.py

# Run a single test by name
venv/bin/py.test tests/ --ignore tests/integration -k "test_name"

# Integration tests
make test_integration

# Docker-based unit+lint (mirrors CI)
make docker_unit_lint
```

> Unit tests use SQLite in-memory by default. Set `TEST_DB_BACKEND=mysql` to run against a local MySQL 8.0 container (see `docker-compose.yml`).

## Architecture

**ows-track** is a Flask microservice that manages digital track metadata — ISRCs, performers, audio/rights attributes, spatial audio, and instant grats. It owns two MySQL databases (`art_relations` and `ows_track`) and a Neo4j graph for artist-role relationships.

### Request flow

```
application.py → backend/api.py (Flask app + flask_request.setup) → backend/handlers/*.py
    → backend/logic/*.py → backend/models/*.py → MySQL / Neo4j / external OWS services
```

### Key layers

**`backend/api.py`** — Creates the Flask app. Calls `flask_request.set_rules_validator(app, 'backend/access_rules.yml')` to register access rules for per-handler use (the middleware `verify_access=False`; handlers call `verify_rules_access_standalone` directly). Also sets up the Neo4j connector and uWSGI executor.

**`backend/config.py`** — Module-level singletons: `ows_client`, `pdp_authorization_backend` (a `PdpAuthorizationBackend`), DB connection strings, feature flags. Imported by handlers via `from backend import config` or `from backend.api import app`.

**`backend/handlers/`** — One file per domain. All handlers call `flask_request.verify_rules_access_standalone(request)` as their first auth gate (checked against `backend/access_rules.yml`). Six endpoints additionally accept machine-to-machine calls via a JWT identity UUID allowlist (`backend/constants/header.py:AUTHORIZED_IDENTITIES`).

**`backend/logic/`** — Business logic, one module per domain. Calls `backend/models/` for data access and external OWS service wrappers.

**`backend/models/`** — Data access layer. `ows_*.py` files are wrappers around external OWS REST APIs (e.g. `ows_product.py`, `ows_video.py`). `track.py`, `track_spatial.py`, `track_sample.py` etc. are SQLAlchemy/raw-SQL models against the local DBs. `models/sql/` holds raw SQL query strings. Neo4j queries live in `backend/cypher/`.

**`backend/connectors/mysql.py`** — SQLAlchemy session factories for both `art_relations` and `ows_track` databases.

### Auth

See `AUTH.md` for the full authorization baseline scan. In brief:
- `flask_request.setup` middleware has `verify_access=False` — access rules are **not** enforced by middleware.
- Every handler calls `flask_request.verify_rules_access_standalone(request)` to enforce `backend/access_rules.yml` at the handler level.
- `PdpAuthorizationBackend` is wired in `config.py` but no endpoint-level `is_authorized()` calls exist yet — PP migration is in progress.
- Excluded paths (no auth): `/hello/`, `/public/performer/roles`.

### Feature flags

`backend/features.py` wraps Split.io via `pythonfeatures`. Use `features.is_enabled('flag_name')` in logic/handlers. Set `SPLITIO_API_KEY` in `.env` for local testing.

### Tests

Unit tests live in `tests/` (excluding `tests/integration/`). `tests/conftest.py` patches `owsrequest.auth.get_auth0_jwks` at import time (required to prevent a live Auth0 network call). Test utilities and fixtures are in `tests/testutils/`. Integration tests in `tests/integration/` run against a real DB and external services.

@AUTH.md
