- 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>
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>
- 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>