Spaces:
Sleeping
Sleeping
| # Profile Session Restoration Fix | |
| ## Problem Summary | |
| When loading the webapp, users encountered the error: | |
| ``` | |
| Error: Profile session not found. Please log in again. | |
| ``` | |
| ### Root Cause | |
| The Flask session cache (`session["profile_session_id"]`) would expire, but the user's profile session still existed in the backend API. The webapp had no fallback mechanism to restore the session from the backend. | |
| ## Solution | |
| Implemented a session restoration mechanism that automatically queries the backend API when the Flask session cache expires. | |
| ### Files Changed | |
| 1. **`webapp/src/services/session_helper.py`** (new file) | |
| - `ensure_profile_session(user_id)`: Queries backend API for existing profile session or creates new one | |
| - `get_or_restore_profile_session(user_id, cached_session_id)`: Returns cached ID or restores from backend | |
| 2. **`webapp/src/routes/contacts.py`** (2 locations updated) | |
| - Line ~414: In `send_message()` - replaced simple cache check with restoration logic | |
| - Line ~537: In `add_fact()` - replaced simple cache check with restoration logic | |
| ### How It Works | |
| **Before (would fail):** | |
| ```python | |
| profile_session_id = session.get("profile_session_id") | |
| if not profile_session_id: | |
| flash("Error: Profile session not found. Please log in again.", "warning") | |
| return redirect(...) | |
| ``` | |
| **After (auto-restores):** | |
| ```python | |
| try: | |
| profile_session_id = get_or_restore_profile_session( | |
| user_id=user_id, | |
| cached_session_id=session.get("profile_session_id") | |
| ) | |
| # Update Flask session cache | |
| session["profile_session_id"] = profile_session_id | |
| except Exception as e: | |
| flash("Error: Unable to initialize profile session. Please log in again.", "warning") | |
| logger.error(f"Failed to restore profile_session_id for user {user_id}: {e}") | |
| return redirect(...) | |
| ``` | |
| ### Restoration Flow | |
| 1. **Cache Hit**: If `profile_session_id` exists in Flask session β return immediately (fast path) | |
| 2. **Cache Miss**: If Flask session expired: | |
| - Call `backend_api.list_sessions(user_id=user_id)` | |
| - Search for session with `contact_id="user-profile"` | |
| - If found β return existing `session_id` and update Flask cache | |
| - If not found β create new profile session and return `session_id` | |
| ### Benefits | |
| - **Seamless UX**: Users no longer need to log out/in when Flask session expires | |
| - **Resilient**: Handles backend session persistence correctly | |
| - **Performant**: Only queries backend on cache miss (lazy restoration) | |
| - **Logged**: All restoration attempts are logged for monitoring | |
| ## Testing | |
| ### Manual Test Steps | |
| 1. **Start the backend API:** | |
| ```bash | |
| cd /Users/christian.kniep/src/gitlab.com/qnib-memverge/streamlit/prepmate | |
| docker compose up -d api | |
| ``` | |
| 2. **Start the webapp:** | |
| ```bash | |
| cd webapp | |
| # Set required environment variables | |
| export FLASK_SECRET_KEY="your-secret-key" | |
| export HUGGINGFACE_CLIENT_ID="your-client-id" | |
| export HUGGINGFACE_CLIENT_SECRET="your-client-secret" | |
| export BACKEND_API_URL="http://localhost:4004" | |
| # Run webapp | |
| python -m flask run --port 5001 | |
| ``` | |
| 3. **Test restoration scenario:** | |
| - Log in via OAuth (creates profile session) | |
| - Create a contact | |
| - Clear Flask session cache (delete cookies or `session.pop("profile_session_id")`) | |
| - Send a message to the contact | |
| - **Expected**: Message sends successfully (profile session restored automatically) | |
| - **Check logs**: Should see `[SESSION_RESTORE]` or `[SESSION_CREATE]` log entries | |
| ### Expected Log Output | |
| **Cache Miss β Existing Session Found:** | |
| ``` | |
| [SESSION_RESTORE] Found existing profile session for user test-user: session_id=abc-123 | |
| ``` | |
| **Cache Miss β New Session Created:** | |
| ``` | |
| [SESSION_CREATE] Creating new profile session for user test-user | |
| [SESSION_CREATE] Created new profile session for user test-user: session_id=def-456 | |
| ``` | |
| ### Verify Fix | |
| 1. Check that messages/facts can be sent even after Flask session expires | |
| 2. Check logs for restoration attempts | |
| 3. Verify no more "Profile session not found" errors in normal operation | |
| 4. Confirm profile session is reused (not creating duplicates) | |
| ## Related Files | |
| - Backend API: [api/internal/services/session_manager.go](../api/internal/services/session_manager.go) - GetSession method (line 194-341) | |
| - Profile Handler: [api/internal/handlers/profile.go](../api/internal/handlers/profile.go) - GetProfile endpoint | |
| - Auth Route: [webapp/src/routes/auth.py](auth.py) - OAuth callback creates initial profile session (line 112) | |
| ## Notes | |
| - The backend API's `GetSession` method only retrieves sessions, it does not auto-create | |
| - Profile sessions are identified by `contact_id="user-profile"` in the backend | |
| - The fix maintains backward compatibility - existing profile sessions are reused | |
| - Flask session cache is updated after successful restoration for performance | |