Skip to content

Requirements: Frontend Implementation for Item Image Upload

These are the functional requirements and system behaviors for the Frontend Implementation for Item Image Upload project. They are grouped by subsystem: api-proxy, BFF routes, Design System, and SPA integration.

Requirements are traceable to source specifications where available. Non-functional requirements appear in a dedicated section at the end.


REQ-FE-001ItemProxy shall expose a createImageUploadUrl(request) method that calls POST /v1/item/image-upload. The request shape is { contentType: string, contentLength: number }. The response shape is { uploadUrl, formFields, objectKey, cdnUrl }.

REQ-FE-002ImageUploadRequest and ImageUploadResponse types shall be exported from @arda-cards/api-proxy/reference/item.

REQ-FE-003 — The api-proxy package shall be published to GitHub Packages at a version consumable by arda-frontend-app.


REQ-FE-010POST /api/image-upload shall proxy to the backend POST /v1/item/image-upload via @arda-cards/api-proxy ItemProxy, adding Authorization, X-Tenant-Id, X-Author, X-Request-ID, and X-oidc-subject headers derived from the authenticated session (with X-oidc-subject extracted from the session JWT claims). Source: BFF specification BFF-FR-001.

REQ-FE-011POST /api/storage/check-url shall perform a HEAD request on the supplied external HTTPS URL and return { reachable, contentType, contentLength }. Source: BFF specification BFF-FR-003.

REQ-FE-012POST /api/storage/check-url shall reject non-HTTPS URLs, private IP ranges, localhost, and managed storage host patterns with HTTP 400. Source: BFF specification BFF-FR-004, BFF-FR-007.

REQ-FE-013POST /api/storage/fetch-url shall proxy the full image content from an external URL, streaming the response, with a maximum payload of 10 MB and a timeout of 10 seconds. Source: BFF specification BFF-FR-005.

REQ-FE-014check-url and fetch-url shall enforce per-tenant rate limiting with a default of 30 requests per minute. Source: BFF specification BFF-FR-006.

REQ-FE-015 — All BFF routes shall require a valid session JWT. Requests without a valid session shall receive HTTP 401. Source: BFF specification BFF-NFR-003.

REQ-FE-016POST /api/storage/cdn-cookies shall issue CloudFront signed cookies scoped to the active tenant’s key prefix. Source: BFF specification BFF-FR-008.

REQ-FE-017 — Signed cookies shall use the attributes: Domain=.arda.cards; Path=/; Max-Age=<ttl>; Secure; HttpOnly; SameSite=Lax, where <ttl> is the configurable cookie TTL in seconds (REQ-FE-018). Source: BFF specification BFF-FR-008.

REQ-FE-018 — Cookie TTL shall be configurable, with a default of 30 minutes. Source: BFF specification BFF-FR-010.

REQ-FE-019 — Tenant ID shall be extracted from session context. It shall never be accepted as a client-supplied parameter. Source: BFF specification BFF-FR-008.

REQ-FE-020 — BFF routes shall not buffer or store image file bytes. Source: BFF specification BFF-NFR-001.

REQ-FE-021 — External URL requests made by BFF routes shall time out within 10 seconds. Source: BFF specification BFF-NFR-002.

REQ-FE-022 — BFF route handler logic shall be placed in src/server/ (FD-02). Files under src/app/api/ shall be thin re-exports only.

REQ-FE-023src/server/index.ts shall include import 'server-only' to prevent client-side bundling of server modules.

REQ-FE-024check-url and fetch-url shall validate that the response Content-Type matches image/*. Non-image content types shall be rejected with HTTP 422. Source: audit-1 finding #8.

REQ-FE-025 — The secrets utility (getSecret) shall cache fetched secrets with a configurable TTL (default 8 hours). Expired cache entries shall be re-fetched from AWS Secrets Manager. Source: audit-1 finding #10, FD-10.

REQ-FE-026 — CDN cookies shall include a Max-Age attribute matching the CloudFront policy TTL (default 1800 seconds). Source: audit-1 finding #7.

REQ-FE-027 — The check-url GET fallback shall discard the response body after inspecting headers. The body shall not be read, buffered, or returned. Source: audit-1 findings #13, #27.

REQ-FE-028 — BFF route handlers shall use RequestContext from @arda-cards/api-proxy (Phase 3.1) to pass user identity headers to the Backend proxy, rather than manually injecting headers. Source: audit-2 finding #9.


REQ-FE-030 — The design system shall export ValidationResult, FieldError, EditLifecycleCallbacks<T>, and EditableComponentProps<T> types from @arda-cards/design-system/types/canary.

REQ-FE-031 — The design system shall export a useDraft<T> hook that manages draft state, runs intrinsic validation on every update, and exposes the following interface: value, dirty, isValid, phase, allErrors, errorsFor(field), update(), confirm(), cancel(), reset().

REQ-FE-032useDraft<T> shall reset the draft when initialValue changes (for example, when a parent confirmation or data refresh occurs).

REQ-FE-033useDraft<T> shall merge contextErrors (supplied by the parent) with intrinsic validation errors for unified display via allErrors and errorsFor(field).


REQ-FE-040ImageUploadDialog shall display an indeterminate progress indicator during the Uploading phase (FD-04). Any simulated timer (e.g., a 50 ms stub) shall be removed.

REQ-FE-041ImageUploadDialog shall support an UploadError phase that displays error information and provides retry capability.

REQ-FE-042ImageUploadDialog shall adopt EditLifecycleCallbacks<ImageUploadResult> for its onConfirm / onCancel contract.

REQ-FE-043 — The ImageCellEditor factory shall accept typed provider hooks (useImageUpload, useCheckReachability) closed over at column-definition time (FD-01).

REQ-FE-044ImageFormField shall adopt EditableComponentProps<string | null> and accept contextErrors for parent-supplied validation.

REQ-FE-045 — The ItemGridColumns / ItemGridLookups interface shall cover all lookup fields used by item grid columns.

REQ-FE-046 — Design system components shall not import @tanstack/react-query (FD-01).

REQ-FE-047 — All updated design system components shall continue to work with default stub handlers in Storybook.


REQ-FE-060arda-frontend-app shall add @tanstack/react-query as a dependency and configure QueryClientProvider in the component tree.

REQ-FE-061 — The SPA shall provide TanStack-backed implementations of useImageUpload (mutation), useCheckReachability (mutation), and useFetchExternalImage (mutation) as FD-01 typed provider hooks.

REQ-FE-062 — The SPA shall provide useCdnCookies as a TanStack query with refetchInterval set to approximately 50% of the cookie TTL and refetchIntervalInBackground: true.

REQ-FE-063 — SPA API functions shall be placed in src/api/ (FD-02) and shall call BFF routes via plain fetch().

REQ-FE-064 — TanStack hooks shall be placed in src/hooks/image-upload/ and src/hooks/cdn/ (FD-02).

REQ-FE-065useImageUpload shall orchestrate: obtain presigned credentials from the BFF, upload to S3 via presigned POST, and return the CDN URL. Entity persistence shall use the existing Redux updateItem() thunk (FD-05).

REQ-FE-066useCheckReachability shall attempt a SPA-side HEAD request first, and fall back to the BFF check-url route on CORS failure.

REQ-FE-067 — The CDN cookie manager shall refresh cookies at session start, proactively before expiry, on tenant switch, and on 403 recovery (maximum one retry per image request). Source: SPA specification SPA-FR-018, SPA-FR-019.

REQ-FE-068 — Image grid thumbnails shall load from CDN using signed cookies. A shimmer shall display during load; a placeholder with an error badge shall display on failure. Source: SPA specification SPA-FR-014.

REQ-FE-069 — The ImageHoverPreview popover shall appear after approximately 500 ms of hover. Source: SPA specification SPA-FR-015.

REQ-FE-070 — Double-click or Enter on an image cell shall open the editor modal via factory-injected typed provider hooks. Source: SPA specification SPA-FR-016.

REQ-FE-071 — The Add Item form shall include an optional image field via ImageFormField. Source: SPA specification SPA-FR-022.

REQ-FE-072 — The Edit Item form shall support changing and removing the item image. Source: SPA specification SPA-FR-023.

REQ-FE-073 — Only one upload shall be active per browser tab (per application instance) at any time. Source: SPA specification SPA-FR-020.

REQ-FE-074 — The image editor shall always produce JPEG output. Source: SPA specification SPA-FR-021.

REQ-FE-075 — Copyright text shall be displayed inline in the confirm dialog footer. Source: TD-04.

REQ-FE-076 — Upload shall use presigned POST, not presigned PUT. Source: TD-08.

REQ-FE-077 — Upload progress shall be displayed as an indeterminate indicator during the Uploading state. Source: FD-04.

REQ-FE-078 — The SPA shall provide a shared useImageWithCdnRecovery hook that handles CDN 403 recovery for all image display contexts (grid, form, inspector). The hook shall detect CDN URLs, trigger cookie refresh on error, and retry with cache-busting. Maximum one retry per URL per mount. Source: FD-16, audit-1 finding #11.

REQ-FE-079 — When editing an existing CDN-hosted image on canvas, the <img> element shall set crossOrigin="use-credentials" to enable canvas export. This attribute shall only be set for CDN URLs, not for local blobs or object URLs. Source: FD-17, infrastructure#439.

REQ-FE-080 — The CDN host pattern shall be derived from NEXT_PUBLIC_INFRASTRUCTURE and NEXT_PUBLIC_PARTITION environment variables using the naming convention ${partition}.${infrastructure}.assets.arda.cards (lowercased). Source: audit-2 finding #4.

REQ-FE-081 — The cookie TTL and refresh interval shall be derived from a shared source (AwsNaming). The SPA useCdnCookies refetchInterval shall equal 50% of the configured cookie TTL. Source: audit-2 finding #8.


REQ-FE-NF-001 — Image thumbnails shall not cause layout reflow. Source: SPA specification SPA-NFR-001.

REQ-FE-NF-002 — Upload retry shall not require the user to re-enter or re-select the image. Source: SPA specification SPA-NFR-002.

REQ-FE-NF-003 — HEIC/HEIF images shall degrade gracefully when the format is unsupported by the runtime. Source: SPA specification SPA-NFR-003.

REQ-FE-NF-004 — CDN cookies shall be tested using mocks. Mock setup shall not interfere with future integration testing. Source: FD constraint.

REQ-FE-NF-005 — All new code in arda-frontend-app shall follow the FD-02 hybrid directory structure. Source: FD-02.



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