Skip to content

Analysis: Frontend Implementation for Item Image Upload

This document compares the current state of three repositories — api-proxy, ux-prototype, and arda-frontend-app — against the specification defined in the project goal. It identifies all gaps that must be closed before the frontend implementation for Item Image Upload is complete.

The analysis finds that api-proxy is the closest to complete: the implementation code is already written and the only remaining gap is a CHANGELOG update and a GitHub Packages publish. The ux-prototype design system requires targeted updates to five image components and the introduction of a minimal lifecycle framework; no structural changes to the package are required. arda-frontend-app has the largest gap: it needs dead-code removal, new directory structure, a new third-party dependency, four BFF route handlers, server utilities, four TanStack Query hooks, a CDN cookie lifecycle provider, grid column wiring, and form field wiring. Nothing that exists today must be moved or restructured — all new code lands in new directories.

The total work is significant but well-defined. No ambiguity remains about what needs to be built; the open question for TypeaheadCellEditor (callback vs. hook-style interface) is the only design decision still pending within scope.


Specification vs. Implementation Comparison

Section titled “Specification vs. Implementation Comparison”

Repository 1: api-proxy (@arda-cards/api-proxy)

Section titled “Repository 1: api-proxy (@arda-cards/api-proxy)”

The specification requires a new createImageUploadUrl() method on ItemProxy, the ImageUploadUrlRequest and ImageUploadUrlResponse types, and unit tests following the existing proxy test pattern.

Current state. All three deliverables are implemented and passing CI on the jmpicnic/image-upload-frontend branch. The package has not been published to GitHub Packages at the required version.

Gaps.

AreaGapNotes
CHANGELOGNo entry for the new method and typesRequired by CI gate on all PRs
GitHub Packages publishPackage not published at the version consuming repos needBlocking for arda-frontend-app BFF routes

No code changes are needed.


Repository 2: ux-prototype (@arda-cards/design-system)

Section titled “Repository 2: ux-prototype (@arda-cards/design-system)”

The specification (Phase 4a) requires: (1) a minimal lifecycle framework — ValidationResult, FieldError, EditLifecycleCallbacks<T>, EditableComponentProps<T>, and useDraft<T>; (2) updates to five image components for FD-01 compliance and production readiness; and (3) a new published version on GitHub Packages.

Current state. 19 image components are present across PR #63 and the seb/inline-card-image-upload branch. Components use raw callback props (onUpload: (file: Blob) => Promise<string> and onCheckReachability: (url: string) => Promise<boolean>). No lifecycle framework types exist anywhere in the package. The package has not been published at the version this project requires.

Gaps.

AreaGapSpec reference
ValidationResult typeNot presentFD-03
FieldError typeNot presentFD-03
EditLifecycleCallbacks<T> typeNot presentFD-03
EditableComponentProps<T> typeNot presentFD-03
useDraft<T> hookNot presentFD-03

The full framework (useComposedDraft<T>, createCellEditorFactory<T>, EditablePanel<T>) is deferred to #77 and is out of scope for this project.

AreaGapSpec reference
Progress indicatorUses a simulated 50 ms timer; spec requires an indeterminate indicatorFD-04
UploadError stateNot present; needed for production retry flowPhase 4a
Lifecycle callbacksDoes not adopt EditLifecycleCallbacks<ImageUploadResult>FD-03
AreaGapSpec reference
Factory signatureDoes not accept typed provider hooks (useImageUpload, useCheckReachability); uses raw callback propsFD-01, section 6.3
AreaGapSpec reference
Interface styleUses lookup: (string) => Promise<Option[]> callback; spec requires evaluation of whether to move to a hook-style interface consistent with FD-01FD-01 (design decision pending)

This is the one open design decision within scope. The outcome determines whether TypeaheadCellEditor requires a signature change in this project or is left as-is with a deferred ticket.

AreaGapSpec reference
ItemGridLookups interface coverageCovers only 2 of 9+ lookup fieldsPhase 4a
Image editor wiringImageCellEditor factory not wired into column definitionsPhase 4a
Image editor hook parametersColumn definitions do not thread typed provider hooks into the factoryFD-01
AreaGapSpec reference
Props typeDoes not extend EditableComponentProps<string | null>FD-03
contextErrorsDoes not accept or display contextual errors from a parentFD-03
AreaGapNotes
GitHub Packages publishPackage not published at the version arda-frontend-app needs to consumeBlocking for Phase 4 in arda-frontend-app
CHANGELOGNo entry for this project’s changesRequired by CI gate

The specification covers: legacy dead-code removal (FD-07, first commit), new directory structure (FD-02), @tanstack/react-query adoption, four BFF route handlers, server-side utilities, four TanStack Query hooks, a CDN cookie lifecycle provider, QueryClientProvider in the provider stack, grid column integration, ImageFormField wiring in ItemFormPanel, and dependency updates.

Current state. The app is a Next.js 16 BFF-architecture application using Redux for all state. @tanstack/react-table is present as a dead dependency (ItemTable.tsx is superseded by ItemTableAGGrid but not removed). No @tanstack/react-query. No src/server/, src/api/, or src/providers/ directories. src/lib/ mixes server and client code without boundary enforcement. ItemFormPanel has imageUrl in the type system with a disabled dropzone placeholder. The item grid uses ItemTableAGGrid (AG Grid) but has no image cell renderers or editors wired.

Gaps.

AreaGapSpec reference
ItemTable.tsxDead code; not removedFD-07
src/tests/itemTable.test.tsxDead test file; not removedFD-07
@tanstack/react-table dependencyPresent in package.json; no other consumers verifiedFD-07

This commit must be isolated, pass all CI checks independently, and land before any new code is added.

AreaGapSpec reference
@tanstack/react-queryNot presentFD-01, Phase 4a
@tanstack/react-query-devtoolsNot presentPhase 4a
@arda-cards/design-systemVersion bump needed to consume lifecycle framework and updated componentsPhase 4a
@arda-cards/api-proxyNot a direct dependency of arda-frontend-app; BFF routes need itPhase 3a

Note: react-easy-crop, react-dropzone, browser-image-compression, and heic2any are design system dependencies and are not added to arda-frontend-app directly.

DirectoryGapSpec reference
src/server/Does not exist; needed for BFF route handlers and server utilitiesFD-02
src/api/Does not exist; needed for SPA API functions layerFD-02
src/hooks/image-upload/Does not exist; needed for TanStack mutation hooksFD-02
src/hooks/cdn/Does not exist; needed for useCdnCookiesFD-02
src/providers/Does not exist; needed for QueryClientProvider and CdnCookieProviderFD-02
RouteGapSpec reference
POST /api/image-uploadNot present; proxies to Backend via api-proxy, adds auth and tenant headersPhase 3a
POST /api/storage/check-urlNot present; SSRF-protected URL reachability checkPhase 3a
POST /api/storage/fetch-urlNot present; SSRF-protected image fetch proxy, max 10 MB, 10s timeoutPhase 3a
POST /api/storage/cdn-cookiesNot present; generates CloudFront custom-policy cookies scoped to tenantPhase 3b
UtilityGapSpec reference
cloudfront-signer.tsNot present; signs CloudFront custom policy with RSA key from Secrets Manager or envPhase 3b
ssrf-validator.tsNot present; HTTPS-only, private IP rejection, managed storage host rejectionPhase 3a
rate-limiter.tsNot present; in-memory per-instance, per-tenant sliding-window counterPhase 3a

TanStack Query hooks (Phase 4a — FD-01 wiring layer)

Section titled “TanStack Query hooks (Phase 4a — FD-01 wiring layer)”
HookGapSpec reference
useImageUploadNot present; TanStack mutation over BFF image-upload routeFD-01, Phase 4a
useCheckReachabilityNot present; TanStack mutation over BFF check-url routeFD-01, Phase 4a
useFetchExternalImageNot present; TanStack mutation over BFF fetch-url routeFD-01, Phase 4a
useCdnCookiesNot present; TanStack query with proactive background refresh at ~50% TTLPhase 4b
ProviderGapSpec reference
QueryClientProviderNot present in provider stackPhase 4a
CdnCookieProviderNot present; CDN cookie lifecycle managerPhase 4b
FileGapSpec reference
src/api/image-upload.tsNot present; plain fetch() wrappers over BFF routesFD-02, Phase 4a
AreaGapSpec reference
ImageCellDisplay in column defsNot wired; no image thumbnail in item gridPhase 4b
ImageCellEditor factory in column defsNot wired; no inline image editor on double-click / EnterPhase 4b
ImageHoverPreviewNot wired; no hover preview with ~500ms delayPhase 4b
Typed provider hooks threaded into column defsNo hook wiring exists at column definition assembly pointFD-01, Phase 4b
AreaGapSpec reference
ImageFormField in ItemFormPanelPresent in type system, disabled placeholder; not wired to ImageFormField componentPhase 4c
ITEM_IMAGE_CONFIG constantNot present; entity-specific configuration (1:1 aspect ratio, formats, 10 MB max, 200px min)Phase 4a
AreaGapSpec reference
BFF route handler testsNot present (routes do not exist yet)Phase 3a, 3b
CloudFrontSignerTestNot presentPhase 3b
CdnCookiesRouteTestNot presentPhase 3b
AreaGapNotes
CHANGELOG entriesNo entries for any of the above changesRequired by CI gate

Specification RequirementRepositoryStatusPhaseNotes
createImageUploadUrl() method on ItemProxyapi-proxyokPrepImplemented on branch
ImageUploadUrlRequest / ImageUploadUrlResponse typesapi-proxyokPrepImplemented on branch
Proxy unit testsapi-proxyokPrepImplemented on branch
api-proxy CHANGELOG entryapi-proxygapPrepRequired before publish
api-proxy publish to GitHub Packagesapi-proxygapPrepBlocking for app BFF routes
ValidationResult, FieldError typesux-prototypegap4aLifecycle framework does not exist
EditLifecycleCallbacks<T>, EditableComponentProps<T> typesux-prototypegap4aLifecycle framework does not exist
useDraft<T> hookux-prototypegap4aLifecycle framework does not exist
ImageUploadDialog — indeterminate progress indicatorux-prototypegap4aCurrently simulated 50 ms timer
ImageUploadDialogUploadError stateux-prototypegap4aNot present
ImageUploadDialogEditLifecycleCallbacks adoptionux-prototypegap4aStill uses raw callbacks
ImageCellEditor — typed provider hook factory signatureux-prototypegap4aCurrently raw callback props
TypeaheadCellEditor — hook-style interface evaluationux-prototypepartial4aDesign decision pending
ItemGridLookups — full lookup field coverageux-prototypegap4aOnly 2 of 9+ fields covered
ItemGridColumns — image editor hook wiringux-prototypegap4aNot wired
ImageFormFieldEditableComponentProps and contextErrorsux-prototypegap4aNot adopted
ux-prototype CHANGELOG entryux-prototypegap4aRequired before publish
@arda-cards/design-system publish to GitHub Packagesux-prototypegap4aBlocking for app Phase 4
ItemTable.tsx removal (dead code)arda-frontend-appgapFD-07Must be first commit
itemTable.test.tsx removalarda-frontend-appgapFD-07Must be first commit
@tanstack/react-table dependency removalarda-frontend-appgapFD-07Must be first commit
@tanstack/react-query dependencyarda-frontend-appgap4aNot present
@tanstack/react-query-devtools dependencyarda-frontend-appgap4aNot present
@arda-cards/design-system version bumparda-frontend-appgap4aAfter design system publish
@arda-cards/api-proxy dependencyarda-frontend-appgap3aNeeded by BFF routes
src/server/ directoryarda-frontend-appgapFD-02Does not exist
src/api/ directoryarda-frontend-appgapFD-02Does not exist
src/hooks/image-upload/ directoryarda-frontend-appgapFD-02Does not exist
src/hooks/cdn/ directoryarda-frontend-appgapFD-02Does not exist
src/providers/ directoryarda-frontend-appgapFD-02Does not exist
POST /api/image-upload BFF routearda-frontend-appgap3aNot present
POST /api/storage/check-url BFF routearda-frontend-appgap3aNot present
POST /api/storage/fetch-url BFF routearda-frontend-appgap3aNot present
POST /api/storage/cdn-cookies BFF routearda-frontend-appgap3bNot present
cloudfront-signer.ts utilityarda-frontend-appgap3bNot present
ssrf-validator.ts utilityarda-frontend-appgap3aNot present
rate-limiter.ts utilityarda-frontend-appgap3aNot present
src/api/image-upload.ts SPA API functionsarda-frontend-appgap4aNot present
useImageUpload hookarda-frontend-appgap4aNot present
useCheckReachability hookarda-frontend-appgap4aNot present
useFetchExternalImage hookarda-frontend-appgap4aNot present
useCdnCookies hookarda-frontend-appgap4bNot present
QueryClientProvider in provider stackarda-frontend-appgap4aNot present
CdnCookieProvider in provider stackarda-frontend-appgap4bNot present
ITEM_IMAGE_CONFIG constantarda-frontend-appgap4aNot present
ImageCellDisplay in grid column defsarda-frontend-appgap4bNot wired
ImageCellEditor factory in grid column defsarda-frontend-appgap4bNot wired
ImageHoverPreview in gridarda-frontend-appgap4bNot wired
ImageFormField wiring in ItemFormPanelarda-frontend-appgap4cPlaceholder disabled
BFF route handler testsarda-frontend-appgap3a/3bRoutes do not exist yet
arda-frontend-app CHANGELOG entriesarda-frontend-appgapAllRequired by CI gate

Priority 1 — Blocking (must complete before any other work proceeds)

Section titled “Priority 1 — Blocking (must complete before any other work proceeds)”
  1. Legacy cleanup in arda-frontend-app (FD-07, first commit). Remove ItemTable.tsx, itemTable.test.tsx, and the @tanstack/react-table dependency. This commit must be isolated and pass all checks before any new code is added. It unblocks a clean baseline for all subsequent work.

  2. Publish api-proxy to GitHub Packages. Add a CHANGELOG entry and publish the existing jmpicnic/image-upload-frontend branch content. This unblocks BFF route development in arda-frontend-app, which imports api-proxy as a runtime dependency.

  3. Introduce lifecycle framework types in ux-prototype. Add ValidationResult, FieldError, EditLifecycleCallbacks<T>, EditableComponentProps<T>, and useDraft<T>. These types must exist before any component updates in this project or any downstream consumer can reference them.

  4. Update the five image components in ux-prototype. With the lifecycle framework in place, apply the FD-01 and FD-03 changes to ImageUploadDialog, ImageCellEditor, ImageFormField, ItemGridColumns / ItemGridLookups, and (after the design decision is resolved) TypeaheadCellEditor. This is prerequisite to resolving the TypeaheadCellEditor interface question — that decision should be made before component work begins.

  5. Publish @arda-cards/design-system to GitHub Packages. After component updates pass CI (lint, typecheck, unit tests, Storybook build, VRT). This unblocks all Phase 4 work in arda-frontend-app.

Priority 2 — Core functionality (after Priority 1 is complete)

Section titled “Priority 2 — Core functionality (after Priority 1 is complete)”
  1. Create src/server/ directory structure and BFF route handlers (Phase 3a/3b). Add @arda-cards/api-proxy dependency, create src/server/, implement ssrf-validator.ts, rate-limiter.ts, cloudfront-signer.ts, and all four route handlers. Write route handler tests.

  2. Add @tanstack/react-query and create src/hooks/ and src/providers/ (Phase 4a). Install the dependency, add QueryClientProvider to the provider stack, create src/api/image-upload.ts, and implement useImageUpload, useCheckReachability, useFetchExternalImage, and useCdnCookies hooks. Add ITEM_IMAGE_CONFIG.

  3. Bump @arda-cards/design-system and wire grid and form (Phase 4b/4c). Update the design system dependency, add CdnCookieProvider, wire ImageCellDisplay, ImageCellEditor, and ImageHoverPreview into item grid column definitions with typed provider hooks, and wire ImageFormField into ItemFormPanel.

  1. CHANGELOG entries for all three repositories. Each repository requires a CHANGELOG entry covering its changes before CI will allow a PR to merge. Draft these entries in parallel with implementation; finalize before raising PRs.

  2. PRs and merge ordering. Follow the merge sequence defined in the release-lifecycle conventions: api-proxy PR merges first (already publish-ready), ux-prototype PR second (design system publish gates app), arda-frontend-app PR last. The documentation PR for project completion artifacts can be merged independently once the implementation PRs are merged.



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