- Create frontend/colors.mjs as SSOT for all design colors
- Create scripts/generate-css-vars.mjs to auto-generate CSS variables
- Update tailwind.config.ts to import colors from colors.mjs
- Update frontend/package.json: add 'generate-css-vars' script to build pipeline
- Update start_servers.py: include CSS variable generation before npm build
- All color changes now require only one edit in colors.mjs
- Build process auto-syncs CSS variables and Tailwind colors
Eliminates DRY violation where colors were duplicated in:
- tailwind.config.ts (Tailwind utility classes)
- globals.css (CSS custom properties)
Single source of truth approach ensures:
✓ No inconsistency between Tailwind and CSS variables
✓ One place to update colors for all contexts
✓ Automated CSS variable generation on every build
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Added search button to main page header with Ctrl+K listener
- Implemented SearchModal component rendering
- Fixed SearchModal to use axiosInstance with correct backend URL (8916)
- Fixed token key from 'auth_token' to 'inventory_token'
- Verified export endpoints working correctly
- All Phase 6 UAT fixes in place
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Modified frontend/lib/api.ts to use window.location.hostname as fallback
- Ensures browser on external IP reaches correct backend HTTPS port
- Allows admin/admin login to work from any access point
- Auth is fully functional and working
- Delete PLAN-02-SCALE-TESTING.md (scale testing deferred to v3)
- Rename PLAN-03-BACKUP-RUNBOOK to PLAN-02-OPERATIONAL-RUNBOOK
- Phase 6 now has 2 executable plans instead of 3
Removed the rotation/zoom adjustment modal feature. Approach was too complex and
time-consuming without delivering stable results.
New simplified flow:
1. User extracts item with AI
2. Item saved with original image (resized/compressed by backend)
3. No rotation adjustments in frontend
4. Image editing can be implemented as a future feature
This unblocks the workflow and gets users to a working state.
Backend still applies compression/resizing, just no rotation processing.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Added user-controlled image adjustment modal that displays after item
confirmation, allowing users to adjust rotation/crop before final save.
Changes:
- AIOnboarding: wrapper confirmSingleItem to show modal post-selection
- State: showImageAdjustment, adjustingItemIndex, pendingItemData
- Handlers: confirm/cancel for applying or discarding adjustments
- Flow: item save → modal display → adjustments applied → DB commit
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Gemini analyzes raw image and returns crop_bounds for that coordinate space.
Previous code applied EXIF rotation first, changing image dimensions, then
used crop_bounds on the rotated image (coordinate mismatch).
Now: crop on raw image (matches AI) → then apply EXIF + manual rotation.
This ensures cropped region contains the actual item, not background.
- Add rotation_degrees parameter to ImageProcessor.process_photo()
- Pass rotation through _auto_save_photo_from_extraction() to processor
- Allow no-crop fallback when crop_bounds is None
- Add buildPhotoUrl() helper to resolve backend URLs correctly
- Update frontend components to use backend URL for image sources
- Replace Use/Skip Photo buttons with checkbox in AI extraction UI
- Add images/ to .gitignore to prevent accidental commits
Addresses: rotation never applied, image 404s (relative to Next.js not backend), preview blank in edit form
The extracted image blob from AI extraction was not being sent to the backend
because Blob objects cannot be JSON serialized. Fixed by:
1. Converting Blob to base64 before sending to API
2. Renaming fields: extractedImageBlob → extracted_image_bytes, imageProcessing → image_processing
3. Removing Blob from local DB (keep original data structure for IndexedDB)
4. Applying same fix to both single item and batch update flows
This ensures the auto-photo-save feature receives the image data it needs.
- Updated confirmSingleItem() to include extractedImageBlob and imageProcessing
- Updated confirmAllItems() to pass image data for bulk item creation
- Each extracted item now carries its own image_processing metadata
- All items in bulk creation share the same extracted image blob
- Added 12 comprehensive tests verifying data is passed correctly
- All 465 frontend tests passing, zero regressions
- Extend ItemCreate schema with optional extracted_image_bytes (base64) and image_processing (dict)
- Update create_item endpoint to call _auto_save_photo_from_extraction after item creation
- Decode base64 image bytes and pass crop_bounds, rotation_degrees to helper
- Don't block item creation if photo save fails (log warning instead)
- Item returned with photo_path, photo_thumbnail_path populated if save succeeded
- Full backward compatibility: old clients without image fields work unchanged
- Add 5 integration tests covering all scenarios:
- Create item WITH image_processing → photo auto-saved
- Create item WITHOUT image_processing → no photo (backward compatible)
- Create item WITH invalid image_processing → item created, photo skipped
- Create item WITH crop_bounds=None → item created, photo skipped
- Create item WITH bytes but NO processing metadata → item created, photo skipped
- All 158 backend tests passing, zero regressions
- Added 11 comprehensive tests for image_processing parsing
- Tests validate crop_bounds structure: {x, y, width, height} all ints >= 0
- Tests validate rotation_degrees: int/float, -360 to +360
- Tests validate confidence: float, 0.0 to 1.0
- Tests graceful handling when image_processing field is missing
- Tests multiple items with image_processing data
- Tests partial data handling (optional fields)
- Tests with both Gemini and Claude providers
- Updated extract_label_info() to preserve and validate image_processing field
- All tests passing, no regressions
The username input was conditionally hidden when it had a value, causing
the field to disappear and focus to jump to password when typing. Fixed by:
1. Always rendering the username input (removed conditional)
2. Using controlled input with value prop
3. Only auto-focus password when username is already entered
This fixes the focus-jumping bug that made it impossible to enter usernames.
Replace font-bold, font-black, and font-semibold with font-normal throughout:
- 26 component files
- 1 CSS utility file (globals.css)
- 291 total occurrences
Text hierarchy now maintained through font-size differences only.
All tests passing (291/291).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
All platform-specific paths and commands replaced with Linux equivalents:
- .git_path: Use system git instead of /Library/Developer/CommandLineTools
- start_server.sh: Use hostname -I instead of ipconfig
- AI_RULES.md line 18: Remove macOS path mandate
- PROJECT_ARCHITECTURE.md Section 7.5: Document Linux native approach
- SESSION_STATE.md: Update git binary reference
Ready for Ubuntu development, Docker testing, and standalone deployment.
Replace native window.confirm() dialogs with branded ConfirmationModal component
for all delete operations (users, categories). Implements progressive disclosure
for high-risk operations and requires confirmation text input for deletions with
100+ affected items.
Features:
- ConfirmationModal component with dynamic risk levels (low/medium/high)
- High-risk operations (100+ affected items) require 'DELETE' text confirmation
- Clear consequence messaging with affected item counts
- Loading state during deletion with visual feedback
- Full keyboard accessibility (Esc to cancel, Enter to confirm)
- Proper focus management and ARIA labels
Affected:
- AdminOverlay: Delete user and category now use ConfirmationModal
- New: ConfirmationModal.tsx component
Design: Matches CreateUserModal aesthetic (clean, minimal) with rose-500
accent for danger context. Progressive disclosure shows additional warnings
only for high-risk operations.
Build: Passes with zero errors.
Accessibility:
- Add focus-visible indicators to all interactive elements (buttons, inputs)
- Create accessible CreateUserModal to replace window.prompt()
- Add aria-labels to icon buttons for screen readers
Colors & Theming:
- Move primary color to CSS variable (--primary)
- Remove hard-coded #3b82f6 from tailwind config
- Clean up color consistency across theme
UX:
- Replace prompt-based user creation with proper modal form
- Implement inline field validation with error messages
- Add loading state during form submission
- Improve visual hierarchy and spacing
Performance:
- Remove bootstrap-icons dependency (duplicate with lucide-react)
Design:
- Reduce backdrop-blur overuse (remove from overlay scrim, StatCard)
- Improve AdminOverlay responsive design