Files
tfm_ainventory/dev_docs/PHASE2_PLAN.md

6.6 KiB

Phase 2: Frontend Photo Upload UI — Implementation Plan

Status: Planning → Ready for subagent dispatch
Branch: feature/phase2-photo-ui (created from dev)
Timeline: 2-3 weeks (estimated)
Prior work: Phase 1 backend complete (commit e46777b9 on dev)


Scope

Add frontend UI for photo upload, manual crop, and display. Backend API ready at:

  • POST /api/items/{id}/photo — upload with optional crop_bounds
  • GET /api/items/{id} — returns photo URLs
  • GET /images/{category}/{filename} — static file serving

Tasks (in priority order)

Task 1: ItemPhotoUpload Component

Complexity: Medium | Files: 2-3 | Model: Standard

Create reusable React component for photo upload flow:

  • File input + camera capture (mobile)
  • Accept multipart file upload
  • Validate file size (<10MB), MIME type (image/jpeg, image/png, image/webp, image/gif)
  • Show loading state during upload
  • Return {photo: {thumbnail_url, full_url, uploaded_at}}
  • Error handling (size, MIME, network)

Files to create/modify:

  • frontend/components/photos/ItemPhotoUpload.tsx (new)
  • frontend/hooks/usePhotoUpload.ts (new)
  • Tests: frontend/tests/ItemPhotoUpload.test.tsx

Acceptance criteria:

  • Accepts file via input or camera capture
  • Validates and uploads to POST /api/items/{id}/photo
  • Shows success/error states
  • Returns photo object
  • Mobile camera works on iOS/Android

Task 2: Manual Crop UI with Drag Handles

Complexity: High | Files: 2-3 | Model: Most capable

Create interactive crop preview with drag handles:

  • Display photo with bounding box (auto-crop from backend or manual)
  • Four corner + four edge drag handles
  • Real-time crop bounds calculation (x, y, width, height)
  • "Use Full Photo" toggle
  • "Apply Crop" button passes crop_bounds to upload
  • Shows visual feedback (crosshairs, handles highlight on hover)

Files to create/modify:

  • frontend/components/photos/ManualCropUI.tsx (new)
  • frontend/hooks/useCropHandles.ts (new)
  • Tests: frontend/tests/ManualCropUI.test.tsx

Acceptance criteria:

  • Drag any handle updates bounds in real-time
  • Bounds sent as JSON: {x: 100, y: 50, width: 300, height: 300}
  • Works on touch (mobile) and mouse (desktop)
  • "Use Full Photo" clears crop_bounds
  • Visually clear which handle is being dragged

Task 3: Integrate Photo Upload into Item Creation

Complexity: Medium | Files: 2-3 | Model: Standard

Add photo upload step to item creation flow:

  • Item details form → Photo upload step
  • Auto-crop preview from backend
  • Manual crop override UI (always visible)
  • Preview thumbnail before save
  • Upload photo before/during item creation

Files to modify:

  • frontend/pages/items/create.tsx (or equivalent in app router)
  • frontend/hooks/useItemCreate.ts
  • Tests: integration test for create flow

Acceptance criteria:

  • Photo upload step appears in item creation
  • Manual crop handles visible by default
  • Users can toggle "Use Full Photo"
  • Photo uploaded successfully before item saved
  • Works on mobile camera capture

Task 4: Admin Photo Replacement Button

Complexity: Low | Files: 1-2 | Model: Fast

Add replace-photo button to admin dashboard:

  • Show current thumbnail
  • "Replace Photo" button → upload new file
  • Delete old file on backend
  • Confirm success/error
  • Update item card thumbnail

Files to modify:

  • frontend/pages/admin/inventory.tsx (or items detail view)
  • Tests: button click, API call

Acceptance criteria:

  • Button visible on item detail page
  • Clicking opens photo upload modal
  • New photo replaces old in thumbnail
  • Backend deletes old file (via replace_existing=true)

Task 5: Mobile Camera Integration & Testing

Complexity: Medium | Files: Tests | Model: Standard

Test photo flow on mobile (iOS/Android):

  • Camera capture works
  • Photo uploads successfully
  • Manual crop works on touch
  • Thumbnail displays correctly
  • No lag or dropped frames during crop

Test scenarios:

  • iPhone Safari: camera capture → crop → upload
  • Android Chrome: camera capture → crop → upload
  • Offline photo queue (Phase 5, skip for Phase 2)

Acceptance criteria:

  • Camera captures work on iOS/Android
  • Photos upload <3s on 4G
  • Manual crop responsive to touch
  • No console errors

Task 6: Inventory Card Photo Display

Complexity: Low | Files: 1-2 | Model: Fast

Update ItemCard component to show photo thumbnail:

  • Show thumbnail (200px square) if photo exists
  • Tap to open full-res modal (no carousel, just single image)
  • Fallback to text label if no photo
  • Add border/frame styling to distinguish photo

Files to modify:

  • frontend/components/ItemCard.tsx
  • frontend/components/photos/PhotoModal.tsx (new)
  • Tests: card renders photo, modal opens

Acceptance criteria:

  • Thumbnail displays in card
  • Tap opens modal with full-res photo
  • Modal closeable (X button, click outside)
  • Fallback text if no photo
  • Works on mobile and desktop

Design Reference

Backend response (from Phase 1):

{
  "status": "ok",
  "photo": {
    "thumbnail_url": "/images/networking/SFP-LR_thumb.jpg",
    "full_url": "/images/networking/SFP-LR_original.jpg",
    "uploaded_at": "2026-04-19T14:32:10Z"
  }
}

Crop bounds format:

{
  "x": 100,
  "y": 50,
  "width": 300,
  "height": 300
}

Tech Stack

  • Framework: Next.js 15+ (existing)
  • Styling: Tailwind CSS (existing)
  • Icons: Lucide Icons (existing)
  • Image handling: Canvas API (built-in, no new dependencies)
  • Form handling: React Hook Form (existing)
  • HTTP: Axios (existing)

No new dependencies required.


Success Criteria (Phase 2 Complete)

Photo upload with camera capture (mobile)
Manual crop UI with drag handles
Auto-crop preview from backend
Photo integrated into item creation
Admin replace-photo button
Inventory card shows thumbnail
Full-res photo modal viewer
Mobile testing (iOS/Android)
All components have tests
No TypeScript errors


Known Dependencies

  • Phase 1 backend — must be deployed and accessible
  • Static file serving — /images/ mount working
  • Photo API endpoints — POST/GET /api/items/{id}/photo

Out of Scope (Phase 3+)

  • Offline photo queueing (Phase 5)
  • Batch photo import (Phase 6)
  • Photo compression on slow networks (Phase 6)
  • Gallery/version history (not in scope)

Next Steps

  1. Dispatch Task 1 implementer (ItemPhotoUpload component)
  2. Review spec compliance + code quality
  3. Continue with remaining tasks
  4. Final integration review before merge

Ready to proceed.