ae093881fa9b61c6470df96df420fb226fc877ae
- write-back: call upsert_tag inside _apply_tag's try so a tag-create failure is caught per-asset and apply_all no longer aborts mid-batch (was P1) - write-back: surface _pipeline/processed write failures in the result instead of discarding them (was reported as success) - ui: add title to the high confidence badge so approve-high-confidence's pre-action count is non-zero; confirm() before single-cluster apply - core: Store context manager; close DB connection even if a route raises; guard split_cluster against a first-member boundary (empty cluster); add writeback_log lookup index - ingest: split thumbnail download/write error handling and clean up the .tmp file on a write failure - tests: upsert/processed write-failure regression tests + split-guard test
immich-photo-flow
A monorepo of small tools that clean up and structure a large Immich
library into travel "memories". M1 ships the shared foundation
(shared/photoflow/{immich,core,ui}) and the trip-cluster app.
Layout
shared/photoflow/immich— the one Immich REST client +_pipeline/tag conventions.shared/photoflow/core— SQLite store + domain models (the only SQL).shared/photoflow/ui— base template, DaisyUI/Tailwind/Alpine/HTMX, shared grid+lightbox.apps/trip-cluster— CLI + Flask review UI (port 8084).
Dev setup
python3.12 -m venv .venv
.venv/bin/pip install -e ./shared -e ./apps/trip-cluster \
pytest==8.3.4 pytest-httpserver==1.1.0 pytest-playwright==0.6.2
.venv/bin/python -m pytest # unit + route tests
.venv/bin/python -m playwright install chromium
.venv/bin/python -m pytest apps/trip-cluster/tests/ui # Playwright UI
trip-cluster workflow
cp .env.example .env # fill IMMICH_URL + IMMICH_API_KEY
cd apps/trip-cluster
python categorize.py ingest --tag "Italy 2019" # or --from/--to/--subset
python categorize.py cluster
python categorize.py serve # review at http://localhost:8084
python categorize.py apply # write approved tags back (asks to confirm)
Immich is the source of truth; SQLite is a rebuildable working layer. Content/trip tags
are never namespaced; pipeline meta-tags live under _pipeline/.
Languages
Python
87%
JavaScript
6.6%
HTML
6.2%
Dockerfile
0.2%