# CLAUDE.md

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

## Project

`ows-product-workflow` is a Flask microservice (The Orchard / Sony Music PDE) that manages the
release-approval and release-correction workflow for digital products: submitting a product for
release, approving/rejecting it, tracking correction details, and lyrics lookups. Owned by
`content-creation-management`.

See `AUTH.md` for the current authorization posture of every endpoint and the Permissions
Platform (PP) migration plan — **most endpoints currently have no authorization check at all**;
consult it before adding or changing any handler that touches access control.

## Commands

Dependency management is via Poetry; Python 3.13 required.

```bash
poetry install                 # make pip_dev — full dev environment
poetry install --only main     # make env — production deps only
```

```bash
make dev                       # run the dev server (python dev.py) on :5000, debug=True
make lint                      # ruff check product_workflow/ tests/ application.py dev.py
make fmt                       # ruff check --fix (auto-fix lint issues)
make test                      # py.test tests/ --ignore=tests/integration --cov product_workflow
make test_unit                 # same, plus junitxml + coverage xml (used in CI)
make test_integration          # py.test tests/integration (needs QA DB / grass env vars — see docker-compose.yml)
```

Run a single test file or test:

```bash
poetry run py.test tests/functional/test_release_approval_queue.py
poetry run py.test tests/functional/test_release_approval_queue.py::test_name -v
```

Docker-based flows (mirrors CI):

```bash
make docker_unit_lint          # unit tests + lint in a container
make up_dev / make down_dev    # run the dev server via docker compose
```

## Architecture

Layered, single-package Flask app: **handlers → logic → models → connectors**.

- `product_workflow/api.py` — creates the Flask `app`, wires `owslogger`/`owsrequest` middleware.
  `application.py` imports it, adds Sentry, and is the WSGI entrypoint (`uwsgi-start.sh`).
- `product_workflow/handlers.py` — **the only place routes are registered** (`@app.route(...)`).
  There are no blueprints or `add_url_rule` calls elsewhere; every endpoint lives in this one file.
  Handlers parse the request, call into `logic/`, and return via `oto.adaptors.flask.flaskify`.
- `product_workflow/logic/` — business logic per domain (`release_approval_queue`,
  `release_correction`, `rejection_notes`, `product_submission`, `metadata_queue`,
  `meta_update_queue`). Coordinates between models and, where needed, other OWS services.
- `product_workflow/models/` — two kinds of "models":
  - SQLAlchemy ORM models backed by this service's own MySQL DB (`release_correction.py`,
    `release_approval_queue.py`, `release_correction_detail.py`, `rejection_notes.py`,
    `meta_update_queue.py`), each defining CRUD-style module functions decorated with
    `mysql.wrap_db_errors` and using `mysql.db_session()` for transactional scope.
  - Thin HTTP clients to other OWS services via `owsrequest.request` (`ows_product.py`,
    `ows_account.py`, `ows_track.py`, `ows_lyrics.py`, `ows_product_review.py`) — these don't hit
    a local DB, they call out to `ows-product`, `ows-account`, etc. (see `constants/services.py`
    for endpoint bases).
- `product_workflow/connectors/mysql.py` — engine/session setup, `db_session()` context manager
  (commit/rollback/close), and the `wrap_db_errors` decorator that converts `SQLAlchemyError` into
  an `oto` fatal response. `connectors/fargate.py` / `connectors/utils.py` — AWS ECS Fargate task
  triggering (used by the metadata-queue processing flow, currently disabled — see `AUTH.md`).
- Request/response convention: every logic/model function returns an `oto.response.Response` (or
  an error variant from `oto.response`/`oto.error`), and handlers convert that to a Flask response
  via `flaskify`. Follow this convention for new logic rather than returning raw dicts or raising.
- `product_workflow/validation/json_schema.py` — validates request headers/body/query args against
  JSON schemas derived from the RAML spec (`spec/api/ows-product-workflow-1.0.0.raml`, loaded in
  `config.py` via `pyraml`). Handlers opt in per-route with the `@json_schema.validate_request_*`
  decorators — not all handlers use them (see `AUTH.md` for which ones skip validation entirely).
- Config (`product_workflow/config.py`) pulls secrets via `secrets_manager.flask_ext.FlaskSecretsManager`
  and switches DB behavior by `Environment` env var (`test` → in-memory SQLite, otherwise MySQL via
  `AR_MYSQL_*` secrets).

### Tests

- `tests/functional/` — handler-level tests exercising the Flask app end-to-end (in-process).
- `tests/logic/`, `tests/models/` — unit tests per layer.
- `tests/factories/` — `factory_boy` factories for DB-backed models.
- `tests/integration/` — hits a real QA environment (grass/DB endpoints via env vars); run only
  through `make test_integration` / `make docker_test_integration`, not part of `make test`.
