# Photo Analyzer Integrated, restart-safe photo analysis, duplicate review, metadata, upload, and archive workflow. Planning lives in `INTEGRATED_PIPELINE_CONCEPT.md` and `delivery_backlog/`. ## Application (`photo_pipeline`) The target application lives in `photo_pipeline/` (FastAPI + SQLAlchemy + Alembic). Run it with: ```bash python -m photo_pipeline migrate # apply database migrations python -m photo_pipeline serve # start the API + static review UI (127.0.0.1:8000) ``` Configuration comes from `PHOTO_PIPELINE_*` environment variables (see `photo_pipeline/config.py`); secrets are referenced, never logged. ## Testing One offline command runs the whole suite (unit, integration, and browser end-to-end); it needs no network and uses only deterministic synthetic fixtures: ```bash work_item/scripts/python -m pytest tests -q ``` Browser end-to-end tests require a one-time Playwright browser install: ```bash python -m playwright install chromium ``` ### Phase A acceptance gate Phase A (Epic E01: shared identity, inventory, duplicates, thumbnails, review UI) is gated by a reproducible end-to-end suite: ```bash work_item/scripts/python -m pytest tests/e2e tests/integration -q ``` - `tests/e2e/test_phase_a_pipeline.py` launches the real API process against a fresh database and a deterministic fixture library, then drives scan, `_IGNORE/` exclusion, move reconciliation, exact/fuzzy duplicate review, thumbnail orientation, canonical selection, browser reload, and a full process restart — asserting durable API and database state after the restart. - `tests/story_traceability.json` maps every delivered story to its tests; `tests/e2e/test_traceability.py` fails if a Phase A story loses coverage or a test file is left unexercised. ### Phase B acceptance gate Phase B (Epic E02: durable jobs, workflow shell, safety/analysis views) is proven through the real process and browser boundaries. One command runs the Phase B API, worker-recovery, and browser (Playwright) suites: ```bash work_item/scripts/python -m pytest tests/e2e -m phase_b -q ``` - `tests/e2e/test_phase_b_pipeline.py` launches the real server and durable worker as child processes and drives them only over HTTP/SSE: analysis start/progress, resumable SSE reconnect, the polling fallback, cancellation, per-asset error inspection, one-mutating-job rejection during read-only browsing, the NSFW→vision privacy gate, and durability across a full restart. - `tests/e2e/test_worker_kill.py` kills a worker mid-item and proves a fresh worker resumes the fenced job (the "resume" journey). - `tests/e2e/test_analysis_browser.py` starts a job from the Analyze view and watches live progress arrive over the browser's real SSE adapter. The full Phase B regression, including the unchanged Phase A gate, is the whole end-to-end suite: ```bash work_item/scripts/python -m pytest tests/e2e -q ```