Files
GearBox/.planning/phases/17-object-storage/17-CONTEXT.md

4.8 KiB

Phase 17: Object Storage - Context

Gathered: 2026-04-05 Status: Ready for planning

## Phase Boundary

Move image storage from local filesystem (uploads/ directory) to MinIO (S3-compatible object storage). All image uploads go to MinIO. Existing images are migrated. Image URLs are served via presigned URLs or a proxy. Docker Compose includes MinIO for local development.

## Implementation Decisions

S3 Client

  • D-01: Use @aws-sdk/client-s3 (AWS SDK v3) for MinIO communication. Works with any S3-compatible service. Tree-shakeable, well-maintained.
  • D-02: Use @aws-sdk/s3-request-presigner for generating presigned URLs.

Storage Service

  • D-03: Create src/server/services/storage.service.ts — thin wrapper around S3 SDK with functions: uploadImage(buffer, filename, contentType), deleteImage(filename), getImageUrl(filename).
  • D-04: getImageUrl() returns a presigned URL with configurable expiry (default 1 hour). No proxy — client fetches directly from MinIO.
  • D-05: Environment variables: S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET (default: gearbox-images), S3_REGION (default: us-east-1).

Image Upload Changes

  • D-06: POST /api/images and POST /api/images/from-url upload to MinIO instead of local filesystem. Same filename pattern (UUID-based).
  • D-07: fetchImageFromUrl() in image.service.ts uploads the fetched buffer to MinIO instead of writing to disk.
  • D-08: Remove the static file serving for /uploads/* from the server — images are served via presigned URLs from MinIO.

Image URL Serving

  • D-09: When returning item/candidate data with imageFilename, the API resolves it to a presigned MinIO URL. Add a imageUrl field to API responses (or replace imageFilename with the URL).
  • D-10: Client components use the presigned URL directly. No changes to image display components beyond using the URL field.

Migration

  • D-11: One-time migration script (scripts/migrate-images-to-minio.ts) reads all files from uploads/, uploads each to MinIO bucket, verifies upload, logs progress.
  • D-12: No filename changes during migration — existing imageFilename values in the database remain valid as MinIO object keys.

Docker Compose

  • D-13: MinIO service in docker-compose.yml (both dev and prod) with automatic bucket creation on startup.
  • D-14: Dev compose uses fixed credentials for simplicity. Prod compose uses env vars.

Claude's Discretion

  • Presigned URL expiry duration (1h default, configurable)
  • Whether to add a GET /api/images/:filename proxy endpoint as fallback
  • MinIO Docker image version
  • Bucket policy (private with presigned URLs vs public-read)
  • Whether to delete local files after successful migration
  • Error handling strategy for upload failures

<canonical_refs>

Canonical References

Downstream agents MUST read these before planning or implementing.

Image Handling (to be refactored)

  • src/server/services/image.service.ts — Current local file storage logic
  • src/server/routes/images.ts — Upload endpoints (file + URL)
  • src/server/index.ts — Static file serving for uploads/

Schema (imageFilename columns)

  • src/db/schema.tsimageFilename on items and threadCandidates tables

Docker

  • docker-compose.yml — Production compose (add MinIO)
  • docker-compose.dev.yml — Dev compose (add MinIO)
  • .env.example — Add S3 env vars

Client (image display)

  • src/client/lib/api.ts — API wrapper
  • src/client/components/ — Components that display images

Requirements

  • .planning/REQUIREMENTS.md — IMG-01 through IMG-04

</canonical_refs>

<code_context>

Existing Code Insights

Reusable Assets

  • image.service.ts — refactor to use storage service instead of local fs
  • UUID filename generation pattern — keep as-is for MinIO object keys
  • Content type validation — keep in image routes

Established Patterns

  • Service DI pattern (db, userId params) — storage service is stateless, no db needed
  • Async operations — all storage ops will be async (already async pattern)
  • Environment config via process.env — same for S3 config

Integration Points

  • src/server/routes/images.ts — Replace Bun.write with storage.upload
  • src/server/services/image.service.ts — Replace Bun.write with storage.upload
  • src/server/index.ts — Remove static file serving for uploads/
  • API response serialization — add imageUrl field from presigned URL

</code_context>

## Specific Ideas

No specific requirements — open to standard approaches for S3-compatible object storage with MinIO.

## Deferred Ideas

None — discussion stayed within phase scope


Phase: 17-object-storage Context gathered: 2026-04-05