Upload files are now stored in session-specific subdirectories instead of
a shared flat folder. Within a session, re-uploading the same file replaces
the existing entry without renaming. Session IDs use secure random tokens.
Added auto-cleanup of ZIP archives and improved old file cleanup.
Updated README to v3.1.1 with changelog and futures log.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add COPY templates/ ./templates/ to Dockerfile
- Fixes TemplateNotFound error for Flask HTML templates
- Required for serving Jinja2 templates from FastAPI
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Copy Flask v3.1 HTML templates (index.html, login.html) to backend/templates/
- Add Jinja2 support to FastAPI main.py
- Update all JavaScript fetch() calls to use /api/* endpoints
- Add JWT authentication to all requests (Authorization: Bearer token)
- Implement automatic token refresh on 401 errors
- Store JWT tokens in localStorage
Benefits:
- 100% identical UI to Flask v3.1 (proven, working design)
- Gold gradient, Montserrat font, all animations preserved
- FastAPI backend (Redis sessions, JWT auth, async)
- No React rewrite needed
- All features work immediately
UI now matches Flask exactly while using modern FastAPI backend.
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Replace NaN and Inf float values with None before JSON serialization
- Fixes 500 error: 'Out of range float values are not JSON compliant'
- Clean sample data in both /file and /excel/preview endpoints
- Pandas returns NaN for empty cells, JSON cannot serialize them
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Add fallback to 0 for undefined stats values
- Prevents toLocaleString() error on undefined
- Safe rendering when API returns incomplete data
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
Import & Excel Mapping:
- Add ImportMappingModal with column mapping and preview
- Integrate modal into FileUploadZone
- Add Excel lookup metadata source with file upload
- Create excelService for API calls
- Show success indicators after configuration
Registration & Auth:
- Create RegisterPage with form validation
- Add /register route in App.tsx
- Add registration link in LoginPage
- Password strength validation (min 8 chars)
AI Generation:
- Integrate MetadataAnalyzer in backend files upload
- Add AI generation case in metadata_service
- Error handling for missing OPENAI_API_KEY
- Test script for AI integration
Stats & UI Polish:
- Add storage stats cards to Dashboard (files, storage, users)
- Fix vite.svg 404 by replacing with emoji favicon
- Enhanced loading states with spinner
- Improved drag-drop visual feedback
- Fix TypeScript errors with vite-env.d.ts
All features now match Flask v3.1 functionality:
✅ Import from CSV/Excel/JSON with column mapping
✅ Excel lookup table
✅ AI metadata generation
✅ Template system
✅ User registration
✅ Statistics dashboard
✅ All builds successfully, TypeScript clean
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
Backend changes:
- Add PyJWT for Azure AD id_token validation
- Add validate_azure_id_token() function in core/auth.py
- Replace /microsoft/login and /microsoft/callback with /microsoft/login POST
- New endpoint validates id_token from frontend (no Graph API calls)
- Support PublicClientApplication (no client secret needed)
Frontend changes:
- Add @azure/msal-browser and @azure/msal-react dependencies
- Create msalConfig.ts with MSAL configuration
- Wrap App with MsalProvider
- Update LoginPage to use useMsal hook and loginPopup
- Remove OAuthCallback handler (MSAL handles redirect)
- Frontend gets id_token from Microsoft, sends to backend
Benefits:
- ✅ Works without AZURE_CLIENT_SECRET (matches apac-ops-bot)
- ✅ More secure (no secret in backend)
- ✅ Simpler backend (just JWT validation)
- ✅ Better UX (MSAL handles popups, silent refresh)
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Use PublicClientApplication when AZURE_CLIENT_SECRET not set
- Allows SPA-style auth flow without backend secret
- Falls back to ConfidentialClientApplication when secret provided
- Matches configuration from other Oliver apps
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Document new FastAPI backend and React frontend
- Add quick start guide for production deployment
- Update architecture section with Redis and JWT
- Add comprehensive troubleshooting section
- Link to new deployment documentation files
- Update changelog for v4.0 release
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Don't fail if git pull doesn't work (SSH keys not configured)
- Show warning but continue with deployment
- Useful for first-time deployment
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Auto pull latest code before deployment
- Clean old Docker images before building new ones
- Add comprehensive cleanup commands documentation
- Add production deployment guide
- Fix frontend serving from /var/www/html for production
- Preserve build cache for faster deployments
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Remove .env from .gitignore
- Add backend/.env with all configuration
- Add frontend/.env with Vite variables
- Match APAC Ops Bot pattern
Environment files now tracked in git for easier deployment.
Update SECRET_KEY, OPENAI_API_KEY, AZURE_CLIENT_SECRET on server.
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Change to OPENAI_MODEL (original variable name)
- Add OPENAI_API_BASE
- Use gpt-5.2 model as specified
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Add volume mount for /var/www/html/solventum-image-metadata
- Read-only mount (ro) for security
- Allows FastAPI to serve React static files
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Serve index.html on root /
- Mount /assets for React static files
- Backend now serves both frontend and API
- Works with simple ProxyPass config
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Rename app/api/import.py to import_api.py
- Update imports in main.py
- Fixes SyntaxError: 'import' is a reserved keyword in Python
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Add VITE_AZURE_* variables for SSO
- Use relative /api URL for Apache proxy
- Match APAC Ops Bot env pattern
- Production and development configs
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Change FRONTEND_URL to full URL with /solventum-image-metadata path
- Ensures CORS allows requests from correct origin
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Add DEPLOYMENT-CHECKLIST.md with step-by-step guide
- Add frontend/.env.production for build
- Update .env.fastapi.example with correct REDIRECT_URI
- Include all verification steps and troubleshooting
Ready for production deployment!
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Update .env: REDIRECT_URI without /api/ prefix
- Add OAuth handler in App.tsx for SSO callback
- Add basename to BrowserRouter: /solventum-image-metadata
- Add .env.production for server deployment
Matches Azure AD config:
https://ai-sandbox.oliver.solutions/solventum-image-metadata/
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Add prominent "Login with Microsoft" button
- Match original Flask design with Microsoft icon
- Add divider between SSO and local login
- Update styling to match gold theme
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Add Montserrat font from Google Fonts
- Use original color scheme (gold #FFC407, dark gradients)
- Add glass morphism effect with backdrop blur
- Add shimmer animation on header
- Style upload zone with hover/drag states
- Match all original design elements from Flask version
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Copy utils.py from src/ (required by extractors)
- Fixes ModuleNotFoundError: No module named 'app.processors.utils'
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- cd back to SCRIPT_DIR before running docker-compose logs/ps
- Fixes "no such file" error when running from frontend/ directory
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- FileUploadZone: Drag-drop with metadata source selector
- FileList: Batch operations (select, download, process more)
- FileItem: File card with expandable metadata editor
These were created but not committed previously.
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Add Redis container back (no external port exposure)
- Redis only accessible within Docker network
- Backend connects via redis://redis:6379/0
- Simplify Redis health check in deploy.sh
This avoids port conflicts while keeping Redis in Docker.
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Remove postgres service (port 5432 conflict)
- Using SQLite by default (simpler for single-server deployment)
- Remove postgres-data volume
- PostgreSQL can be added later if needed
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Comment out Excel file volume mount by default
- Excel lookup will be disabled if file not present
- Prevents deployment error when file doesn't exist
- Users can uncomment the line if they have the Excel file
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Change BACKEND_PORT from 8001 to 5001 (same as Flask)
- Keeps existing Azure AD redirect URI working
- No need to update Azure AD app registration
- Apache proxy can use same port configuration
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Make BACKEND_PORT configurable via .env
- Update docker-compose to use ${BACKEND_PORT:-8001}
- Update deploy.sh to read port from .env
- Update Apache config examples to use port 8001
- Update all documentation with correct port
Apache config must proxy:
/solventum-image-metadata/api → http://localhost:8001
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Update REDIRECT_URI to include /api/auth/microsoft/callback path
- Add production Azure AD credentials to .env.fastapi.example
- Create Apache migration guide with correct configuration
BREAKING CHANGE: Apache proxy must change from port 5001 to 8000
- Old: ProxyPass /solventum-image-metadata/ http://localhost:5001/
- New: ProxyPass /solventum-image-metadata/api http://localhost:8000
Frontend now served as static files, not proxied.
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Create idempotent deploy.sh for production deployment
- Add docker-compose.fastapi.yml with Redis + Backend
- Configure health checks for all services
- Add .env.fastapi.example with all configuration
- Remove old Flask deployment script (docker-run.sh)
Deployment features:
- Pre-flight checks (Docker, Node, permissions)
- Frontend build with Vite
- Deploy to /var/www/html/solventum-image-metadata
- Graceful container restart
- Health checks (backend + Redis)
- Auto-cleanup old Docker images
Usage:
cd /opt/solventum-image-metadata
git pull origin main
sudo ./deploy.sh
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
Fixed three critical issues:
1. Session persistence - Cookies not saved after page refresh
- Replaced APPLICATION_ROOT with SESSION_COOKIE_PATH
- Added proper cookie settings for reverse proxy (HttpOnly, SameSite)
- Set correct cookie path matching URL_PREFIX
2. AJAX detection for FormData uploads (JPG, etc.)
- Enhanced @login_required to detect POST/PUT/DELETE as AJAX
- Added Content-Type check for JSON requests
- Added path prefix check for API endpoints
3. JavaScript AJAX identification
- Updated fetchWithAuth() to add X-Requested-With header
- Properly handles both JSON and FormData requests using Headers API
- Ensures all fetch calls are identified as AJAX by server
Changes:
- web_app.py: Fixed Flask session cookie configuration
- src/auth.py: Improved AJAX detection logic in login_required decorator
- templates/index.html: Enhanced fetchWithAuth() with proper headers
This fixes:
- Users having to re-login on every page refresh
- "Unexpected token '<'" errors when uploading JPG files
- Session cookies not persisting through reverse proxy
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
Fixed two critical issues with API authentication on production server:
1. Modified @login_required decorator to detect AJAX/API requests and return
JSON error with 401 status instead of HTML redirect. This prevents
"Unexpected token '<'" errors when session expires.
2. Created fetchWithAuth() helper function in JavaScript that automatically
handles 401 responses by redirecting to login page. Updated all 11 API
fetch calls to use this wrapper.
Changes:
- src/auth.py: Added AJAX detection and JSON error responses to login_required
- templates/index.html: Added fetchWithAuth() and updated all fetch() calls
This fixes the console errors:
- "Failed to load templates: SyntaxError: Unexpected token '<'"
- 502 Bad Gateway errors now properly handled with session checks
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>