Skip to content

Specification: Frontend Implementation for Item Image Upload

Driving document for implementing the frontend image upload feature across 5 repositories in 9 sequential phases. References goal.md, analysis.md, requirements.md, and verification.md.

This project delivers the BFF proxy layer, design system component updates, TanStack Query integration, SPA wiring, and backend strict validation that enable image upload, display, and management for the Item entity. It spans api-proxy, ux-prototype, arda-frontend-app, operations, and documentation.

The work is organized into 8 phases with review gates between each. Phases execute sequentially — each phase must pass its exit criteria and review before the next begins. The dependency chain is:

[component-preparation project] ← prerequisite (separate project/PR)
└─→ 3.1 API Proxy Publish (api-proxy)
└─→ 3.2 Lifecycle Framework (ux-prototype)
└─→ 3.3 Component Updates (ux-prototype)
└─→ 3.4 Design System Publish (ux-prototype)
└─→ 3.5 BFF Routes (arda-frontend-app)
└─→ 3.6 SPA Integration (arda-frontend-app)
└─→ 3.6b Backend Strict Validation (operations)
└─→ 3.7 Release (all repos)

Prerequisite: The component-preparation project must be completed and merged before this project begins. It removes the legacy @tanstack/react-table code and adds the dev:local tooling.

Note: Phases 3.1 (api-proxy) and 3.2–3.4 (ux-prototype) operate on different repositories. They could execute in parallel if needed, but sequential execution is recommended to keep the review cadence predictable.


  • Goal — scope, constraints, deliverables, success criteria
  • Analysis — gap analysis: current state vs. specification
  • Requirements — 61 functional + non-functional requirements
  • Verification — traceability matrix (requirement → test → phase)
  • Decision Log — FD-01 through FD-07
DecisionSummaryImpact
FD-01Typed data providers in design systemComponents never import TanStack Query; app provides hooks
FD-02Hybrid code organizationNew code in src/server/, src/api/, src/hooks/<feature>/, src/providers/
FD-03Minimal lifecycle frameworkOnly types + useDraft<T> in this project; full framework deferred to #77
FD-04Indeterminate upload progressReplace simulated timer with spinner; optional onProgress added later
FD-05Entity persist stays in ReduxupdateItem() via existing Redux thunk, not TanStack mutation
FD-06ItemCardEditor out of scopePrototype-only; no production wiring
FD-07Legacy cleanup first commitRemove @tanstack/react-table before adding new code

Worktrees already created at project start:

projects/image-upload-frontend-worktrees/
├── api-proxy/ # branch: jmpicnic/image-upload-frontend
├── ux-prototype/ # branch: jmpicnic/image-upload-frontend (rebased onto seb/inline-card-image-upload)
├── arda-frontend-app/ # branch: jmpicnic/image-upload-frontend
├── operations/ # branch: jmpicnic/image-upload-frontend (from jmpicnic/multi-pdf-print-and-bugs)
└── documentation/ # branch: jmpicnic/image-upload-frontend

Single agent, sequential phases — no integration branch needed. Each repository gets one PR to its target branch.

Local development across repos uses npm run dev:local in arda-frontend-app (see tools/dev-local.sh).


component-preparation project (separate project/PR)

Section titled “component-preparation project (separate project/PR)”
AttributeValue
Projectcomponent-preparation
Repositoriesarda-frontend-app
DeliverablesLegacy @tanstack/react-table removed, dev:local tooling added
StatusMust be merged before this project begins

AttributeValue
Repositoryapi-proxy
Specification3.1-api-proxy-publish/specification.md
Tasks4
Entry criteriaCode already implemented (preparation phase)
Exit criteriaPackage published to GitHub Packages
Deliverable@arda-cards/api-proxy at new version

REVIEW GATE: Verify package is consumable. Test install in a scratch directory.


AttributeValue
Repositoryux-prototype
Specification32-lifecycle-framework/specification.md
Tasks4
RequirementsREQ-FE-030 through REQ-FE-033
Entry criteriaux-prototype branch, existing checks pass
Exit criteriaTypes + useDraft<T> exported, all tests pass
DeliverableLifecycle framework types in canary entry point

REVIEW GATE: Review type design and useDraft<T> implementation before applying to components.


AttributeValue
Repositoryux-prototype
Specification33-component-updates/specification.md
Tasks7
RequirementsREQ-FE-040 through REQ-FE-047
Entry criteriaPhase 3.2 complete, infrastructure#439 deployed
Exit criteria5 components updated, all tests + Storybook pass
DeliverableUpdated image components with FD-01 compliance

REVIEW GATE: Review component changes. Verify Storybook stories render with default handlers. Verify no TanStack import in design system.


AttributeValue
Repositoryux-prototype
Specification34-design-system-publish/specification.md
Tasks6
Entry criteriaPhases 3.2 + 3.3 complete
Exit criteriaPackage published to GitHub Packages at new version
Deliverable@arda-cards/design-system with lifecycle types + updated components

REVIEW GATE: Verify package is consumable. Test import of lifecycle types and updated components.


AttributeValue
Repositoryarda-frontend-app
Specification3.5-bff-routes/specification.md
Tasks8
RequirementsREQ-FE-010 through REQ-FE-023
Entry criteriaPhase 3.1 (api-proxy published), component-preparation project merged
Exit criteria4 BFF routes + 3 utilities, all tests pass
Deliverablesrc/server/ directory with BFF routes and utilities

REVIEW GATE: Security review of SSRF protection. Review CDN cookie signing. Verify server-only enforcement.


AttributeValue
Repositoryarda-frontend-app
Specification3.6-spa-integration/specification.md
Tasks12
RequirementsREQ-FE-060 through REQ-FE-077, REQ-FE-NF-001 through REQ-FE-NF-005
Entry criteriaPhases 3.4 (design system published) + 3.5 (BFF routes) complete
Exit criteriaTanStack hooks wired, grid + form integration, all checks pass
DeliverableFull SPA image upload functionality in mock mode

REVIEW GATE: Full integration review. Verify upload flow end-to-end in mock mode. Review FD-01 wiring (no TanStack leaks into design system components). Review FD-02 directory structure.


AttributeValue
Repositoryoperations
Specification36b-backend-validation/specification.md
Tasks8
Entry criteriaPhase 3.6 complete (frontend sends CDN URLs only), CDN infrastructure deployed
Exit criteriaStrict CDN URL validation enforced, make build passes
Deliverableoperations branch with backward-compat relaxations reverted

REVIEW GATE: Verify make build passes. Confirm no nullable CDN dependencies remain. Confirm backward-compat tests removed and original test URLs restored.


AttributeValue
RepositoriesAll
Specification37-release/specification.md
Tasks6
Entry criteriaAll phases 3.0–3.6b reviewed and approved
Exit criteriaAll PRs merged, worktrees cleaned up
DeliverableFeature merged to target branches in all repos

RepositoryCommands
arda-frontend-appnpm run lint, npx tsc --noEmit, npx jest --no-coverage --watchAll=false --forceExit, npm run build
operationsmake build (Gradle build including tests)
api-proxynpm run lint, npm run typecheck, npm run test, npm run build
ux-prototypemake check (lint + typecheck), make test, make build
documentationmake pr-checks (lint + preview build + link check + smoke tests)

All project artifacts (specifications, session logs, byproducts, decision log updates) live in the documentation worktree. After each phase:

  1. Run make pr-checks in the documentation worktree to verify all checks pass (CHANGELOG validation, broken link detection, smoke tests).
  2. Commit the documentation changes with a message referencing the phase.
  3. The documentation worktree accumulates commits across all phases; a single PR is created in Phase 3.7.

After creating or pushing to any PR, run /pr-steward <pr-url> to monitor CI checks, surface reviewer comments, implement fixes, reply to threads, and resolve conversations. This applies to all PRs across all repositories (Phases 3.1, 3.4, 3.7).

Every PR to a protected branch must include a CHANGELOG update per the release-lifecycle skill conventions. The release phase (3.7) consolidates entries.

New BFF routes in src/server/ import env and jwt from src/lib/ (legacy location). Annotate with // TODO #734: move to src/server/lib/. This is cleaned up when #734 executes.

  • ux-prototype publishes → arda-frontend-app bumps dependency
  • Use npm run dev:local for local development (see tools/dev-local.sh)
  • Never copy design system components into arda-frontend-app

Each phase specification references the skills relevant to its tasks. The following skills apply across the project:

SkillWhen to use
implementation-taskEach phase follows the implementation task workflow (analysis, planning, byproducts, session logging)
typescript-codingAll TypeScript code (api-proxy, BFF routes, SPA hooks)
ui-componentComponent updates in ux-prototype, component wiring in arda-frontend-app
unit-tests-frontendAll Jest/Vitest tests (ux-prototype and arda-frontend-app)
document-writingAll documentation artifacts (architecture docs, session logs, byproducts)
plantuml-diagramsAll PlantUML diagrams in documentation
release-lifecycleCHANGELOG updates, PR creation, merge ordering
pr-stewardPR monitoring after creation or push
path-conventionsAll Markdown links across repos
cdk-infrastructureCloudFront signer context (signing key construct)

Collected from all phase specifications. Resolve before or during the relevant phase.

#PhaseQuestionOptionsRecommendationDecision
13.2useDraft location: utilities/ vs. hooks/A: alongside types, B: dedicated hooks dirA (colocate)Decided: A
23.2updateField deep clone strategyA: shallow spread, B: structuredClone, C: immerA (lightweight)Decided: A — shallow spread per level, React best practice
33.3ImageFormField prop namingA: rename to initialValue, B: alias, C: keep imageUrlB (backward compat)Decided: B (alias + deprecation)
43.3TypeaheadCellEditor interface styleA: convert to hook, B: keep promise callbackB (already FD-01)Decided: B (keep promise callback)
53.5CloudFront key loadingA: env var only, B: Secrets Manager with fallbackA (simpler for now)Decided: B (Secrets Manager) — FD-10
63.6403 recovery wiring levelA: component-level, B: grid wrapperB (keeps ImageDisplay pure)Decided: B + shared hook — FD-16
73.6QueryClient in test-utilsA: shared wrapper, B: per-testA (consistent)Decided: A

Before declaring the project complete (end of Phase 3.7), verify:

  • All 61 requirements in verification.md have status Pass
  • All phase exit criteria met
  • All review gates passed
  • No regressions in existing functionality across all repos
  • CHANGELOGs updated for api-proxy, ux-prototype, arda-frontend-app, operations
  • All PRs merged (merge ordering: documentation → operations → arda-frontend-app)
  • Worktrees removed, local branches cleaned up
  • Open questions table above: all resolved or deferred with ticket

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