Skip to content

feat: GCS multi-image support for products - #10

Merged
rezadrian01 merged 3 commits into
mainfrom
feat/gcs-product-images
May 30, 2026
Merged

feat: GCS multi-image support for products#10
rezadrian01 merged 3 commits into
mainfrom
feat/gcs-product-images

Conversation

@rezadrian01

Copy link
Copy Markdown
Owner

Summary

  • Replaces the single image_url field with a product_images table supporting multiple ordered images per product
  • Position 0 is the primary image; image_url in all product responses is now computed from images[0].url for backward compatibility
  • Adds Google Cloud Storage integration via a StorageService interface with a NoopStorage fallback — service starts cleanly without GCS credentials, upload returns 503
  • Deleting a product now also deletes all its GCS objects

New endpoints (admin only)

Method Path Description
POST /api/products/:id/images Upload file to GCS, create DB record
DELETE /api/products/:id/images/:image_id Remove from GCS and DB
PUT /api/products/:id/images/reorder Set display order; position 0 = primary

Breaking change

image_url is removed from POST /api/products and PUT /api/products/:id request bodies. Images are managed exclusively via the new image endpoints after the product is created.

What changed

  • product-service — new product_images table (raw SQL migration, idempotent), StorageService interface + GCS implementation, 3 new handlers, image cleanup on product delete
  • api-gateway — 3 new image routes registered under admin-protected products group
  • docker-compose.yml + .env.exampleGCS_BUCKET_NAME and GCS_CREDENTIALS_JSON documented
  • docs/API_DOCS.md + docs/API_CURL_TESTS.md — updated product response shape and new image endpoint docs

Test plan

  • Upload JPEG → GCS URL returned, position auto-assigned
  • Upload second image → appended at next position
  • GET product → images[] populated, image_url equals images[0].url
  • Reorder → image_url updates to reflect new primary
  • Delete image → removed from GCS and DB
  • Wrong MIME type → 400
  • Wrong image count in reorder → 400
  • Non-existent image → 404
  • Non-existent product → 404
  • Service starts without GCS_BUCKET_NAME set (NoopStorage fallback)

🤖 Generated with Claude Code

rezadrian01 and others added 3 commits May 30, 2026 13:01
Replaces the single image_url field with a product_images table supporting
multiple ordered images per product. Position 0 is the primary display image;
image_url in ProductResponse is computed from it for backward compatibility.

New endpoints (admin only, enforced by gateway):
  POST   /api/products/:id/images          — upload file to GCS, create DB record
  DELETE /api/products/:id/images/:id      — remove from GCS and DB
  PUT    /api/products/:id/images/reorder  — reorder by position (0 = primary)

StorageService interface with NoopStorage fallback means the service starts
cleanly when GCS_BUCKET_NAME is unset — upload returns 503, all other
product endpoints are unaffected.

DeleteProduct now cleans up all GCS objects before removing the DB row.
ProductImage table is auto-migrated alongside existing tables.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gateway was missing the three image management routes, causing 404s.
Added POST/DELETE/PUT for /:id/images and /:id/images/reorder under
the admin-protected products group.

Migration was trying to call db.AutoMigrate(&ProductImage{}) in isolation,
which caused GORM to traverse relationships and generate invalid SQL
("insufficient arguments"). Replaced with idempotent raw SQL in
applySearchIndex so product_images is always created safely regardless
of whether the products table already existed.

Also updated API_DOCS.md and API_CURL_TESTS.md with the new image
endpoints, updated product response shape (images array + computed
image_url), and removed image_url from the create/update request body.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 30, 2026 06:28
@rezadrian01
rezadrian01 merged commit 8033d7c into main May 30, 2026
1 of 2 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

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.

2 participants