Skip to content

Decision Log: Upload Product Images and Managed File Assets

Goal: Resolve large design questions before deciding on Phasing, initial scope and detailed design.

Source: design-session-01.md

#QuestionStatusDecision
DQ-001S3 bucket organizationDecidedOption B (two buckets: http-assets durable + ephemeral-uploads short TTL). Key format: ${tenantId}/${owning-module}/${entity-type}/${property-name}/${asset-uuid}.${ext}
DQ-002Read-path access control modelDecidedPhased: Option A (unguessable keys) initially, then Option B (signed cookies). Two separate CloudFront distributions. Secrets Manager for key pair. BFF scope extension.
DQ-003FileStore as Lambda vs. componentDecidedOption C (shared library in common-module). Strongly typed Storage Access class parametrized at bootstrap. Re-evaluate Option A (Lambda) later.
DQ-004Object key structureDecidedResolved by DQ-001. Key format is a more granular variant of tenant-first (Option A).
DQ-005Upload workflow (write path)DecidedOption A (Decoupled Upload + Entity Update) with mandatory HEAD check on entity update. Presigned POST with S3-enforced policy (Content-Type, content-length-range, metadata). See design-session-02.md.
DQ-006CDN integration approachDecidedOption B (separate distribution). URL: ${partition}.${infrastructure}.assets.arda.cards. Three-phase rollout: no CDN, CDN without auth, CDN with signed cookies.
DQ-007S3 abstraction placementDecidedOption A (new abstraction in common-module). Nice-to-have: extract common elements from CsvS3BucketDirectAccess.
DQ-008Object immutability and versioningPending ReviewOption A (immutable, no versioning) initially. Orphan cleanup per Option C or on entity retirement. Pending human team review with Denis.

Goal: Deep-dive into DQ-005 (Upload Workflow). Evaluate three workflow options, decide on upload protocol (PUT vs POST), define presigned POST policy specification, and produce detailed requirements.

Source: design-session-02.md

#QuestionStatusDecision
DQ-005Upload workflow (write path)DecidedOption A with mandatory HEAD check. Three steps: (1) request presigned POST credentials, (2) upload to S3, (3) entity update with HEAD validation. Details.
Upload protocol (PUT vs POST)DecidedPresigned POST. Required for S3-edge enforcement of Content-Type and Content-Length. Rationale.
Accepted image formatsDecidedimage/jpeg, image/png, image/webp. GIF, SVG, TIFF rejected. starts-with "image/" in POST policy + server-side allow-list.
File size limitsDecided50 KB minimum, 10 MB maximum. Based on 300 DPI / 3.5x5” print target (1050x1500 min pixels).
HEAD check behaviorDecidedMandatory rejection. Entity update returns 422 if S3 object not found or metadata mismatch. No best-effort mode.
Option C (generic upload endpoint)DecidedDiscarded. Violates DDD principle of domain-specific API endpoints.

  • Object Eviction Requirements and scenarios.

Copyright: (c) Arda Systems 2025-2026, All rights reserved