Commit graph

80 commits

Author SHA1 Message Date
SamoilenkoVadym
77494488d5 feat(deploy): add auto git pull and cleanup to deployment script
- 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>
2026-02-09 15:40:11 +00:00
SamoilenkoVadym
1bac1b6994 feat(config): commit .env files to git for deployment
- 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>
2026-02-09 15:17:26 +00:00
SamoilenkoVadym
75202abe44 fix(config): use OPENAI_MODEL and gpt-5.2
- 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>
2026-02-09 15:12:19 +00:00
SamoilenkoVadym
917d1ed9f0 fix(frontend): correct API URL with full path
- Change VITE_API_URL from /api to /solventum-image-metadata/api
- Matches Apache ProxyPass configuration
- Fixes 404 errors on API calls

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-09 14:58:58 +00:00
SamoilenkoVadym
ed8e0abe35 fix(docker): mount frontend directory for serving from FastAPI
- 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>
2026-02-09 14:57:10 +00:00
SamoilenkoVadym
0fbef069a8 fix(backend): serve React frontend from FastAPI
- 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>
2026-02-09 14:47:11 +00:00
SamoilenkoVadym
114f5af81c fix(backend): add missing image_updater.py
- Copy image_updater.py from src/updaters/
- Required by metadata_service

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-09 14:43:41 +00:00
SamoilenkoVadym
d5aaec5d37 fix(backend): rename import.py to import_api.py (reserved keyword)
- 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>
2026-02-09 14:41:41 +00:00
SamoilenkoVadym
0afd7a628e fix(frontend): add complete .env with Azure AD configuration
- 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>
2026-02-09 14:36:05 +00:00
SamoilenkoVadym
f44dcc1388 fix(config): correct FRONTEND_URL to include path
- 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>
2026-02-09 14:31:38 +00:00
SamoilenkoVadym
b03ff91e4e docs(deploy): add complete deployment checklist and env files
- 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>
2026-02-09 14:29:45 +00:00
SamoilenkoVadym
3585aaff0b fix(sso): add OAuth callback handler with correct redirect URI
- 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>
2026-02-09 14:28:07 +00:00
SamoilenkoVadym
ea914dcf69 feat(frontend): add Microsoft SSO button to login page
- 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>
2026-02-09 14:19:09 +00:00
SamoilenkoVadym
16aa4f6b49 style(frontend): match Flask design with gold gradients and glass morphism
- 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>
2026-02-09 14:15:23 +00:00
SamoilenkoVadym
632272f6b6 fix(backend): add import API endpoints
- Create /import/file endpoint for CSV/Excel/JSON upload
- Create /import/excel/preview for sheet preview
- Create /import/configure for column mapping
- Add import router to main.py

Fixes 404 errors on import functionality.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-09 14:11:56 +00:00
SamoilenkoVadym
901d4d9a21 feat(frontend): complete metadata editor with all fields and sources
- Add all metadata sources: manual, AI, Excel, import, template
- Add all metadata fields: title, subject, keywords, author, copyright, comments
- Add custom fields editor with add/remove functionality
- Add character counters for all fields
- Add import file upload with session handling
- Add template selection dropdown
- Add common components: Modal, Button, Input

Full feature parity with Flask version achieved.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-09 14:04:10 +00:00
SamoilenkoVadym
b51a4a9216 fix(backend): add missing utils.py module
- 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>
2026-02-09 14:00:07 +00:00
SamoilenkoVadym
6c01941b3e docs(apache): add simplified Apache configuration guide
- Add simple ProxyPass configuration matching existing patterns
- Provide two variants: backend-only vs frontend/backend split
- Recommend variant 2 for better performance

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-09 13:54:36 +00:00
SamoilenkoVadym
c986470543 fix(deploy): return to script directory before docker-compose commands
- 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>
2026-02-09 13:52:33 +00:00
SamoilenkoVadym
24e57f2d99 feat(frontend): add file components (missing from previous commit)
- 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>
2026-02-09 13:49:51 +00:00
SamoilenkoVadym
227472ca02 fix(frontend): add .tsx extensions to component imports
- Fix Vite build error for component resolution
- Add explicit .tsx extensions to imports

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-09 13:44:25 +00:00
SamoilenkoVadym
3dd0149235 chore(frontend): add package-lock.json for reproducible builds
- Generate package-lock.json with npm install
- Required for npm ci in deployment script
- Ensures consistent dependency versions

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-09 13:40:31 +00:00
SamoilenkoVadym
34594b64b4 fix(docker): isolate Redis within Docker network
- 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>
2026-02-09 13:39:19 +00:00
SamoilenkoVadym
a591765c28 fix(docker): use existing Redis server instead of container
- Remove redis container (port 6379 conflict)
- Use host Redis at 172.17.0.1:6379 (Docker bridge gateway)
- Remove redis depends_on from backend
- Remove redis-data volume

Backend connects to existing Redis on host machine.

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-09 13:36:11 +00:00
SamoilenkoVadym
536400fa6f fix(docker): remove PostgreSQL service (using SQLite)
- 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>
2026-02-09 13:35:13 +00:00
SamoilenkoVadym
5b06af283f fix(docker): make Excel lookup file optional in docker-compose
- 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>
2026-02-09 13:34:03 +00:00
SamoilenkoVadym
9fd8581dd4 fix(config): use port 5001 for Azure AD compatibility
- 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>
2026-02-09 13:29:45 +00:00
SamoilenkoVadym
0d706fe79b fix(config): change backend port to 8001 (port 8000 occupied on server)
- 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>
2026-02-09 13:26:51 +00:00
SamoilenkoVadym
856dacb7ab fix(config): correct Azure AD redirect URI and add Apache migration guide
- 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>
2026-02-09 13:21:41 +00:00
SamoilenkoVadym
e5bcfcb674 docs: add comprehensive deployment and migration documentation
- Add DEPLOYMENT.md with production deployment guide
- Add README-FASTAPI.md with backend API documentation
- Add README-FULLSTACK.md with complete migration guide
- Add Apache configuration in docs/apache/ for reference

Documentation includes:
- Quick start guide for Docker Compose
- Environment variable configuration
- API endpoint documentation
- Troubleshooting guide
- Backup and maintenance procedures
- Migration statistics and improvements

Apache configuration (reference only):
- SSL/HTTPS setup
- Reverse proxy for FastAPI backend
- Static file serving for React frontend
- Security headers and caching

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-09 13:16:17 +00:00
SamoilenkoVadym
a95f7be047 feat(deploy): add production deployment for Ubuntu with Docker
- 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>
2026-02-09 13:15:04 +00:00
SamoilenkoVadym
4eaeaf998f feat(frontend): add React SPA with TypeScript
- Create React 18 + TypeScript + Vite application
- Implement Zustand state management (auth, files)
- Add Axios API client with JWT auth interceptors
- Create drag-drop file upload with react-dropzone
- Create metadata editor with validation
- Add login page with SSO support
- Configure Tailwind CSS for styling
- Setup routing with React Router

Components created:
- LoginPage - Authentication UI
- DashboardPage - Main application
- FileUploadZone - Drag-drop upload
- FileList - File list with batch operations
- FileItem - File card with metadata editor

Features:
- JWT token auto-refresh on 401
- Character counters for metadata fields
- Toast notifications for user feedback
- Responsive design with Tailwind

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-09 13:14:46 +00:00
SamoilenkoVadym
563d476a94 feat(backend): migrate from Flask to FastAPI with Redis sessions
- Create FastAPI application with async I/O
- Implement Redis session storage (fixes session loss on restart)
- Add JWT authentication with refresh tokens
- Add Microsoft SSO support via MSAL
- Copy all processors from src/ (100% reused, no changes)
- Create file upload/download endpoints
- Create metadata update endpoints
- Create template CRUD endpoints
- Add SQLAlchemy async database models
- Add Docker Compose configuration with Redis

Solves critical issues:
- Session management: Redis replaces in-memory dicts
- Scalability: Async FastAPI + microservices architecture
- File handling: Persistent storage with auto-cleanup

Key files:
- backend/app/main.py - FastAPI entry point
- backend/app/core/redis_client.py - Session store
- backend/app/core/auth.py - JWT authentication
- backend/app/api/* - All REST endpoints
- backend/app/processors/ - Reused from src/

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-09 13:14:37 +00:00
SamoilenkoVadym
0b136bac6c Fix session expiration issues and improve error handling
Fixed two critical session-related issues:

1. Session expiration during file processing
   - Added proper error message when session expires mid-process
   - Prevents silent failure and missing download buttons
   - Shows clear "Session expired" message to user

2. Session lifetime and cookie configuration
   - Increased session lifetime from 24 hours to 7 days (configurable)
   - Made sessions permanent (session.permanent = True) in all login flows
   - Improved cookie security settings with environment variable control
   - Added SESSION_COOKIE_SECURE and SESSION_LIFETIME_DAYS env vars
   - Fixed cookie configuration for HTTPS reverse proxy

Changes:
- web_app.py: Enhanced session configuration and made sessions permanent
- templates/index.html: Better error handling for session expiration

This fixes:
- "Unexpected token '<'" errors appearing intermittently
- Missing download buttons after metadata update
- Sessions expiring too quickly requiring frequent re-login

Environment variables (optional):
- SESSION_COOKIE_SECURE=true (default for HTTPS)
- SESSION_LIFETIME_DAYS=7 (default 7 days)

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-09 11:46:51 +00:00
SamoilenkoVadym
2ea4673bf0 Fix session persistence and improve AJAX detection for file uploads
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>
2026-02-09 11:24:49 +00:00
SamoilenkoVadym
53ab780758 Fix AJAX authentication errors - return JSON for API requests
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>
2026-02-09 11:07:49 +00:00
SamoilenkoVadym
f5aa512629 Handle redirect on login page and clear stuck MSAL state 2026-02-06 23:55:12 +00:00
SamoilenkoVadym
60b9329da2 Fix MSAL initialization and interaction_in_progress error 2026-02-06 23:53:00 +00:00
SamoilenkoVadym
25c5d1ba11 Complete SPA OAuth flow - login button uses MSAL.js
- Login button now uses MSAL.js loginRedirect() for PKCE
- oauth_callback uses MSAL.js handleRedirectPromise() to complete token exchange
- PKCE flow is now entirely in browser (SPA compatible)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 23:50:23 +00:00
SamoilenkoVadym
1fb5072a19 Simplify OAuth callback with direct token exchange and debug output 2026-02-06 23:45:34 +00:00
SamoilenkoVadym
2e64ae9d15 Add SPA-compatible OAuth flow with MSAL.js
- Render oauth_callback.html with MSAL.js for browser token exchange
- Add /auth/token endpoint to receive token from JavaScript
- Token exchange happens in browser (cross-origin) for SPA compatibility

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 23:40:42 +00:00
SamoilenkoVadym
497ab446ad Handle OAuth callback on root path /
- Check for OAuth code in query params on main page
- Process SSO login without requiring /auth/callback route
- Redirect to clean URL after successful login

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 23:27:55 +00:00
SamoilenkoVadym
992787bef1 Add debug logging to auth callback 2026-02-06 23:25:42 +00:00
SamoilenkoVadym
14ea29c5cb Add PKCE support for Azure AD public client SSO
- Use initiate_auth_code_flow for PKCE (required by Azure AD for public clients)
- Store auth flow in session for token exchange
- Fix AADSTS9002325 error

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 23:21:20 +00:00
SamoilenkoVadym
614322e135 Fix URL prefix to use single path /solventum-image-metadata
- Remove -back suffix, use single path for monolithic Flask app
- All routes now use /solventum-image-metadata/ prefix

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 23:12:10 +00:00
SamoilenkoVadym
1da1cd6220 Add gunicorn for production WSGI server
- Replace Flask development server with gunicorn
- 2 workers, 120s timeout for file processing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 22:55:46 +00:00
SamoilenkoVadym
a1ddf28108 Fix redirect URLs for reverse proxy
- Add URL_PREFIX for all redirect URLs
- Redirects now go to /solventum-image-metadata-back/login instead of /login

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 22:32:54 +00:00
SamoilenkoVadym
26095be769 Remove git pull from deploy script
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 22:26:12 +00:00
SamoilenkoVadym
189cb3dab3 Add deployment script and configure reverse proxy with Azure SSO
- Add deploy.sh for idempotent Docker deployments
- Configure API_BASE for /solventum-image-metadata-back/ reverse proxy
- Enable Azure AD SSO with public client flow (no secret required)
- Remove hardcoded tester user for production security
- Add ProxyFix middleware for reverse proxy header handling

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 16:37:19 +00:00
SamoilenkoVadym
e6e3037459 Add GPT-5 model support with enhanced API logging
- Add GPT-5, GPT-5-mini, and GPT-5-nano to valid models list

- Add model validation with automatic fallback to gpt-4o-mini

- Update _is_new_model() to recognize GPT-5 as new generation

- Add detailed API response logging (model used, tokens, content preview)

- Add empty content detection with helpful error messages

- Fix API parameter selection for GPT-5 models

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-26 14:33:55 +00:00