# CLAUDE.md

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

## Overview

`ows-project-manager` is a Flask microservice in the OWS (Orchard Web Services) platform. It lets project clients create and manage releases, tracks, master recordings, marketing priorities, label-copy metadata reports, and project-transfer jobs. Dependencies are resolved from both PyPI and the internal `pde` index (`pypi.theorchard.io`).

## Commands

Dependencies are managed with Poetry; most workflows are wrapped in the `Makefile`.

- **Install dev deps**: `make pip_dev` (`poetry install`)
- **Run dev server**: `make dev` or `python dev.py` (Flask debug server on port 5000; override with `PORT=5001`)
- **Lint**: `make lint` (`ruff check project_manager tests`)
- **Unit tests** (excludes integration): `make test`
- **Integration tests**: `make test_integration` — these hit AWS/DB and are normally run in Docker (`make docker_test_integration`), requiring AWS creds in the environment.
- **Run a single test**: `poetry run py.test tests/path/to/test_file.py::test_name`
- **Docker (if you hit `SIGSEGV`/`SIGBUS` running tests locally)**: `docker compose run test`; full CI gate is `make docker_unit_lint`.

Copy `.env.shadow` to `.env` for local config before running.

## Architecture

Strict layered request flow — keep responsibilities in their layer:

1. **`project_manager/api.py`** — constructs the Flask `app`, wires `flask_request`, `OwsClient`, and the PP `PdpAuthorizationBackend`. Module-level singletons (`app`, `ows_client`, `authorization_backend`) are imported elsewhere.
2. **`project_manager/handlers.py`** — every route is registered here via `@app.route` (single file, no blueprints). Handlers parse the request, perform auth, call the logic layer, and wrap the result with `flaskify(...)`. `application.py` is the WSGI entrypoint (imports `handlers` for its side-effect route registration).
3. **`project_manager/logic/`** — business logic (`project_manager.py`, `project_transfer.py`, `label_copy_export.py`). Talks to the model layer; never to Flask request objects directly (headers are passed in).
4. **`project_manager/models/`** — `persister.py` plus per-entity modules execute **raw SQL** (SQLAlchemy Core `text()` queries defined in `models/sql/project_manager.py`), not the ORM. This service uses SQLAlchemy 1.3 in a query-string style.
5. **`project_manager/connector/`** — infrastructure: `mysql.py`, `sqs.py`, `s3.py`.

Cross-cutting conventions:

- **Responses**: handlers and logic return `oto.response.Response` / `create_error_response(...)` objects; the HTTP boundary converts them with `flaskify(...)`. Do not return raw Flask responses from the logic layer.
- **Two databases**: `mysql.py` exposes `pm_session_scope()` (the AR/project DB) and `lce_session_scope()` (the Label Copy Export DB). Pick the scope matching the data you're touching. In the `test` environment both are in-memory SQLite (`StaticPool`).
- **Config & secrets**: `config.py` reads env vars (`Environment` selects dev/qa/test/prod) and pulls credentials via `secrets_manager.FlaskSecretsManager`. Logging uses `g.log` (loggly) inside request context.
- **Feature flags**: gated through `pythonfeatures` via `project_manager/util/features.py` (e.g. account-context-aware query selection in `persister.py`).
- **Async side effects**: report generation enqueues to SQS (`{env}-label-copy-export`) and reads/writes S3 (`{env}-orcdbucket/label_copy_export`).

## Authorization

This service is mid-migration from legacy auth to the Permissions Platform (PP). **See [`AUTH.md`](AUTH.md)** for the full per-endpoint auth scan and migration plan. Key facts:

- There is **no access-rules middleware** — `flask_request.setup()` is called without a `rules_file`, so each endpoint's posture is determined entirely by its own handler.
- The **`/transfer/*` endpoints are already PP-enforced** via the `@authorize_transfer_job` decorator and helpers in `project_manager/util/authorization.py` (`PdpAuthorizationBackend` is wired in `api.py`). Follow that pattern when adding PP checks to other handlers.
- Most project/product endpoints still rely on legacy Grass headers (`Grass-Account-Type` / `Grass-Account-Id`, via `handler_util.access_check` or `flask_request.verify_grass_*`) or have no resource-level auth. `AUTH.md` prioritizes which to migrate and which template (A/B/C) to use.

## Tests

`tests/` mirrors the package layout (`logic/`, `models/`, `handlers/`, etc.); `tests/integration/` is run separately and excluded from the default `make test`. Unit tests use the in-memory SQLite config and helpers like `tests/common_assert.py` / `tests/conftest.py`.
