Changes:
- Use tenant-specific authority instead of 'organizations' endpoint
- Pass code parameter explicitly in acquire_token_by_authorization_code
- Fix REDIRECT_URI to include /auth/callback path
- Add ALLOWED_TENANT_IDS support for multi-tenant auth
- Improve error logging for token acquisition
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Remove collision-avoidance rename (_1, _2, etc) in FileService.save_upload;
overwrite file on disk instead, preserving original filename
- Deduplicate in SessionStore.add_file_to_session: replace existing entry
with same filename instead of appending duplicate
- Deduplicate upload results list for consistent frontend response
The rename broke Excel/import metadata lookup which matches by
Path(filename).stem.lower(). Files are already isolated per user_id
directory, so overwriting is safe.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Default model: gpt-5.2
- New models use client.responses.create() (Responses API)
- Older models (gpt-3.5-turbo) still use chat.completions.create()
- Response parsing handles both API formats
- Updated valid models list
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Upload returns immediately for AI source, processes in background
- New GET /session/{id}/files endpoint for polling AI progress
- Frontend polls every 3s, updates UI as files complete
- Shows progress: "X of Y files done..."
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Background AI processing returned before results were ready,
leaving the UI showing "AI processing..." forever. Now AI
metadata generation runs inline (awaited) so results are
returned immediately in the upload response.
Background SSE-based processing can be re-enabled later for
large batch uploads (10+ files).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
base_updater.validate_metadata() requires non-empty title.
Now uses filename stem as fallback when user leaves title blank.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Azure AD returns mixed-case usernames (VadymSamoilenko) but
superadmin was created with lowercase. Use LOWER() for matching.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- deploy.sh copies static/ to /var/www/html/solventum-image-metadata/
- Apache Alias serves CSS/JS directly from disk
- ProxyPass exclusion prevents static requests going to Docker
- Updated apache config with full working example
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Microsoft CDN URL was unreachable. Using jsdelivr with
@azure/msal-browser@3.27.0 instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Define initMsal() first, then load CDN script with onload="initMsal()".
Prevents 'msal is not defined' race condition.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MSAL.js 2.x requires await initialize() before loginPopup().
Also added openid/profile/email scopes and loading state guard.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Frontend MSAL.js handles Azure AD popup login
- Backend validates access token via Graph API
- Removed server-side MSAL redirect flow (get_auth_url, acquire_token)
- MicrosoftSSO class simplified: only needs Graph API validation
- No AZURE_CLIENT_SECRET required
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Support both ConfidentialClientApplication (with secret) and
PublicClientApplication (without secret). SSO now only requires
AZURE_CLIENT_ID and AZURE_TENANT_ID.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
git pull runs as current user (needs SSH key), docker commands
use sudo automatically if the user doesn't have docker socket access.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>