Author: Claude Code for jmpicnic | Date: 2026-03-31 | Status: Draft
Functional and non-functional requirements for the backend implementation of
image upload. These requirements derive from the
backend specification
(BE-FR/BE-NFR), the goal, and the analysis.
| ID | Requirement | Source |
|---|
| REQ-BE-001 | The system shall generate presigned POST forms for uploading images to S3. The POST policy document shall include conditions enforcing: key (exact match), Content-Type (starts-with image/), content-length-range (1 byte to max file size), x-amz-meta-tenant-id (exact match), x-amz-meta-author (exact match), x-amz-meta-arda-key (exact match), and x-amz-server-side-encryption (AES256). Signature duration: 15 minutes (configurable). | BE-FR-001, TD-08, TD-16 |
| REQ-BE-002 | The system shall construct S3 object keys in the format <tenantId>/images/<uuid>.<ext>. The UUID shall be generated server-side using a cryptographically secure random source. The extension shall be derived from the requested content type: image/jpeg → jpg, image/png → png, image/webp → webp, image/heic → heic, image/heif → heif. | BE-FR-002, TD-16 |
| REQ-BE-003 | The system shall construct CDN URLs from object keys in the format https://<cdn-host>/<tenantId>/images/<uuid>.<ext>, where <cdn-host> is the configured CDN domain. | BE-FR-007, TD-16 |
| REQ-BE-004 | The presigned credential endpoint shall return the S3 upload URL, all form fields required for POST submission, the object key, and the CDN URL in a single response. | BE-FR-007 |
| REQ-BE-005 | The presigned credential endpoint shall construct the Arda-Key metadata value in the format operations/item/imageUrl/<uuid>.<ext>. | BE-FR-001, TD-16 |
| REQ-BE-006 | Each call to the presigned credential endpoint shall generate a new UUID and a new set of credentials. The endpoint shall be idempotent in the sense that multiple calls produce independent, valid credential sets. | BE-NFR-003 |
| ID | Requirement | Source |
|---|
| REQ-BE-007 | Before persisting a non-null imageUrl on an entity, the system shall validate that the URL matches the expected CDN host and key pattern. URLs that do not match shall be rejected with a 400 response. This validation is subject to the grandfathering rule (REQ-BE-011, TD-15): validation is skipped when the imageUrl is unchanged from the persisted value. | BE-FR-003, TD-05, TD-15 |
| REQ-BE-008 | Before persisting a non-null imageUrl, the system shall validate that the URL’s key prefix matches the requesting tenant’s ID. Cross-tenant URLs shall be rejected. | BE-FR-003 |
| REQ-BE-009 | Before persisting a non-null imageUrl, the system shall perform a HeadObject request to S3 to verify the uploaded object exists and that x-amz-meta-tenant-id matches the requesting tenant. | BE-FR-004 |
| REQ-BE-010 | The system shall accept null as a valid imageUrl value to clear an entity’s image. | BE-FR-005 |
| REQ-BE-011 | When the imageUrl value in an update request is unchanged from the currently persisted value, the system shall skip CDN pattern validation and HEAD verification (grandfathering). | TD-15 |
| REQ-BE-012 | Previous image references shall be retained in the entity’s bitemporal version history. The system shall not delete S3 objects on image replacement or removal. | BE-FR-006 |
| ID | Requirement | Source |
|---|
| REQ-BE-013 | The system shall expose POST /v1/item/<itemEId>/image-upload-url as the presigned credential endpoint, scoped under the item resource path. | TD-13 |
| REQ-BE-014 | The presigned credential endpoint shall accept a JSON body with contentType (string, required) and contentLength (integer, required). | BE-FR-001 |
| REQ-BE-015 | The presigned credential endpoint shall require the same authentication as other item endpoints: API key + tenant headers (X-Tenant-Id, X-Author, X-Request-ID). | BE-FR-001 |
| REQ-BE-016 | The presigned credential endpoint shall return 400 for invalid content types (not starting with image/) or missing required fields. | BE-FR-001 |
| ID | Requirement | Source |
|---|
| REQ-BE-017 | The operations CloudFormation shall import image infrastructure exports: ImageAssetBucketArn, ImageAssetBucketName, ImagePresignRoleArn, ImageCdnDomain. | Goal deliverable #10 |
| REQ-BE-018 | The operations IAM role shall have s3:GetObject and s3:PutObject on the image asset bucket and sts:AssumeRole on the image presigning role. IAM policies are scoped at the bucket level (${BucketArn}/*), not per-tenant prefix. Tenant isolation is enforced at the application level: presigned POST policy conditions bake in the tenant ID (server-signed, client cannot alter), and post-upload HEAD verification validates x-amz-meta-tenant-id matches the requesting tenant from ApplicationContext (TD-20). CDN tenant isolation is enforced via CloudFront signed cookies scoped to /<tenantId>/* (TD-11). | BE-NFR-002, TD-11, TD-20 |
| REQ-BE-019 | Image infrastructure values shall be wired through Helm to application configuration, following the existing uploadBucketArn pattern. | Goal deliverable #11 |
| ID | Requirement | Source |
|---|
| REQ-BE-020 | Common S3 capabilities (presigned PUT, presigned POST, HEAD verification, metadata validation) shall be consolidated in S3AssetService. CsvS3BucketDirectAccess shall delegate all S3 primitives to S3AssetService (TD-17, TD-18). | Goal, Analysis 3.x, TD-17, TD-18 |
| REQ-BE-021 | After refactoring, CsvS3BucketDirectAccess shall retain all CSV-specific behavior (GET with decompression, row/batch flow parsing) while delegating S3 primitives to S3AssetService. | Goal constraint #6, TD-18 |
| REQ-BE-022 | All existing CsvS3DirectAccessTest and S3BucketAccessTest tests shall continue to pass without modification after refactoring. | Goal constraint #6 |
| ID | Requirement | Source |
|---|
| REQ-BE-NFR-001 | Presigned POST credential generation shall complete within 1 second (P95). | BE-NFR-001 |
| REQ-BE-NFR-002 | Each new class shall have passing unit tests before any dependent class is started. New code shall achieve a minimum of 80% line and branch coverage. | Goal constraint #8 |
| REQ-BE-NFR-003 | Code coverage shall meet or exceed targets configured in Gradle build scripts for both repositories. | Goal SC #14 |
| REQ-BE-NFR-004 | Both common-module and operations shall build successfully (make clean build) at each phase gate. | Goal SC #5, #12 |
Copyright: (c) Arda Systems 2025-2026, All rights reserved