MemPrepMate / PROFILE_SESSION_FIX.md
Christian Kniep
'switching to mmp'
d7c1993
# 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