Skip to content

chore: remove disk-upload remnants after S3 cutover#2

Draft
dosaki wants to merge 1 commit into
feat/s3-uploadsfrom
cleanup/s3-uploads
Draft

chore: remove disk-upload remnants after S3 cutover#2
dosaki wants to merge 1 commit into
feat/s3-uploadsfrom
cleanup/s3-uploads

Conversation

@dosaki

@dosaki dosaki commented May 1, 2026

Copy link
Copy Markdown
Member

⚠️ DO NOT MERGE UNTIL PR #1 IS MERGED AND VERIFIED IN PROD

This PR is the cleanup half of the disk-to-S3 cutover. The work it removes is load-bearing during the cutover and only safe to delete after the migration has actually run successfully in prod.

Merge gate checklist

  • PR feat: store book photos in S3 with presigned PUT uploads #1 (feat: store book photos in S3 with presigned PUT uploads) has been merged.
  • deploy.yml has finished and rolled out new ECS tasks.
  • The librarian-services-api task logs (CloudWatch /ecs/librarian-services/api) include a line like Done. Uploaded N object(s); updated M row(s). from the migration script.
  • At least one book cover renders in the prod UI (i.e. S3 actually serves it).

If any of those is unchecked, close this PR or wait — merging now leaves prod with the legacy shim gone and no migration to bring DB rows up to date.

What this removes

  • app/static/uploads/ (24 baked-in book covers, now living in S3 under books/).
  • scripts/migrate_uploads_to_s3.py — the one-shot data migration; nothing left to migrate.
  • The python scripts/migrate_uploads_to_s3.py line in entrypoint.sh — would now be a missing-file error on container start.
  • The legacy-filename shim from app.storage.public_url — once every row carries books/, the if "/" not in key branch is dead code that silently rewrites bad input. Removing it makes future bugs (e.g. a code path that accidentally sets photo_filename = "garbage") fail loudly instead of producing a wrong-looking S3 URL.

Test plan

  • Local: flask run boots; /library/, /library/dashboard, /borrower/dashboard, /library/add, /library/<id>/edit all render covers (resolved against MinIO or staging S3).
  • Post-merge: deploy.yml runs without the migrate_uploads_to_s3.py step (entrypoint goes straight from flask db upgrade to gunicorn).
  • Spot-check book covers in prod UI immediately after deploy.

Base-branch note

This PR's base is feat/s3-uploads, not main. If PR #1 is merged via:

  • Create a merge commitfeat/s3-uploads survives, this PR's base auto-tracks. Merge it next.
  • Squash and merge with auto-delete-branch → feat/s3-uploads is deleted; this PR's base disappears. Retarget with gh pr edit 2 --base main first.

🤖 Generated with Claude Code

Strips the legacy filesystem path now that all covers live in S3 and
all DB rows carry the books/ prefix:
- delete app/static/uploads/ (24 baked-in book covers, now in S3)
- delete scripts/migrate_uploads_to_s3.py and the entrypoint hook
  that invoked it (no work left to do)
- drop the legacy-filename branch from app.storage.public_url so
  bare filenames no longer silently get a books/ prefix

DO NOT MERGE until PR #1 has been merged AND the prod deploy has
logged "Done. Uploaded N object(s); updated M row(s)." in CloudWatch.
Merging early leaves prod with no migration ever running and the
shim gone, which 404s every existing book cover.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant