fix: exempt /api/clubs/me from tenant validation
- Add path exemption in TenantValidationMiddleware for /api/clubs/me - Change authorization policy from RequireMember to RequireViewer - Fix KEYCLOAK_CLIENT_ID in docker-compose.yml (workclub-app not workclub-api) - Endpoint now works without X-Tenant-Id header as intended - Other endpoints still protected by tenant validation This fixes the chicken-and-egg problem where frontend needs to call /api/clubs/me to discover available clubs before selecting a tenant.
This commit is contained in:
124
.sisyphus/evidence/final-qa/phase4-frontend-scenarios-summary.md
Normal file
124
.sisyphus/evidence/final-qa/phase4-frontend-scenarios-summary.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# Phase 4: Frontend E2E Scenarios (36-41) - Results
|
||||
|
||||
## Scenario 36: Login Flow
|
||||
**Status:** ❌ FAIL (Blocker: Authentication Loop)
|
||||
**HTTP:** 302 redirect loop
|
||||
**Evidence:**
|
||||
- `.sisyphus/evidence/final-qa/s36-login-success.png`
|
||||
- `/Users/mastermito/Dev/opencode/debug-fail-s36.html`
|
||||
|
||||
**Details:**
|
||||
- Keycloak authentication succeeds (credentials accepted)
|
||||
- NextAuth callback processes successfully (302 redirect)
|
||||
- **BLOCKER:** Frontend calls `GET /api/clubs/me` which returns **404 Not Found**
|
||||
- Application logic redirects user back to `/login` due to missing clubs endpoint
|
||||
- Results in authentication loop - user cannot access dashboard
|
||||
|
||||
**Frontend Container Logs:**
|
||||
```
|
||||
POST /api/auth/signin/keycloak? 200 in 18ms
|
||||
GET /api/auth/callback/keycloak?... 302 in 34ms
|
||||
GET /login 200 in 31ms
|
||||
GET /api/auth/session 200 in 8ms
|
||||
GET /api/clubs/me 404 in 51ms <-- FAILURE POINT
|
||||
```
|
||||
|
||||
**Root Cause:**
|
||||
- Missing backend endpoint: `/api/clubs/me`
|
||||
- Frontend expects this endpoint to return user's club memberships
|
||||
- Without club data, frontend rejects authenticated session
|
||||
|
||||
## Scenario 37: Club Switching UI
|
||||
**Status:** ⏭️ SKIPPED (Blocked by S36 failure)
|
||||
**Details:** Cannot test UI interactions without successful login
|
||||
|
||||
## Scenario 38: Task List View
|
||||
**Status:** ⏭️ SKIPPED (Blocked by S36 failure)
|
||||
**Details:** Cannot access task list without successful login
|
||||
|
||||
## Scenario 39: Create Task via UI
|
||||
**Status:** ⏭️ SKIPPED (Blocked by S36 failure)
|
||||
**Details:** Cannot create tasks via UI without successful login
|
||||
|
||||
## Scenario 40: Shift List View
|
||||
**Status:** ⏭️ SKIPPED (Blocked by S36 failure)
|
||||
**Details:** Cannot access shift list without successful login
|
||||
|
||||
## Scenario 41: Shift Signup via UI
|
||||
**Status:** ⏭️ SKIPPED (Blocked by S36 failure)
|
||||
**Details:** Cannot sign up for shifts without successful login
|
||||
|
||||
---
|
||||
|
||||
## Summary Statistics
|
||||
- **Total Scenarios:** 6 (S36-S41)
|
||||
- **Pass:** 0
|
||||
- **Fail:** 1 (S36 - authentication loop blocker)
|
||||
- **Skipped:** 5 (S37-S41 - blocked by S36 failure)
|
||||
- **Pass Rate:** 0%
|
||||
|
||||
## Critical Blocker Identified
|
||||
|
||||
### Missing API Endpoint: `/api/clubs/me`
|
||||
|
||||
**Impact:** CRITICAL - Prevents all frontend functionality
|
||||
**Severity:** Blocker for Phase 4, 5, and potentially Phase 6
|
||||
|
||||
**Technical Details:**
|
||||
1. Frontend expects `GET /api/clubs/me` to return user's club memberships
|
||||
2. Backend does not implement this endpoint (returns 404)
|
||||
3. Without club data, frontend authentication guard rejects session
|
||||
4. User stuck in redirect loop: `/login` → Keycloak → callback → `/login`
|
||||
|
||||
**Required Fix:**
|
||||
```
|
||||
Backend: Implement GET /api/clubs/me endpoint
|
||||
Returns: { clubs: [ { id, name, role }, ... ] }
|
||||
Example response for admin@test.com:
|
||||
{
|
||||
"clubs": [
|
||||
{ "id": "64e05b5e-ef45-81d7-f2e8-3d14bd197383", "name": "Tennis Club", "role": "Admin" },
|
||||
{ "id": "3b4afcfa-1352-8fc7-b497-8ab52a0d5fda", "name": "Cycling Club", "role": "Member" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Alternative Workarounds (if endpoint cannot be implemented):**
|
||||
1. Modify frontend to not require `/api/clubs/me` on initial load
|
||||
2. Extract club data from JWT token `clubs` claim instead
|
||||
3. Implement fallback behavior when endpoint returns 404
|
||||
|
||||
## API vs Frontend Validation Discrepancy
|
||||
|
||||
**Observation:**
|
||||
- API CRUD operations (Phase 3) work perfectly via direct HTTP calls
|
||||
- Frontend authentication/integration completely broken
|
||||
- Suggests development was backend-focused without full-stack integration testing
|
||||
|
||||
## Next Steps
|
||||
|
||||
**CRITICAL PATH BLOCKER:** Cannot proceed with:
|
||||
- ❌ Scenarios 37-41 (Frontend E2E)
|
||||
- ❌ Scenarios 42-51 (Cross-task Integration via UI)
|
||||
|
||||
**Can Still Execute:**
|
||||
- ✅ Scenarios 42-51 (API-only integration testing via curl)
|
||||
- ✅ Scenarios 52-57 (Edge cases via API)
|
||||
- ✅ Scenario 58 (Final report)
|
||||
|
||||
**Recommendation:**
|
||||
1. Document this as a CRITICAL bug in final report
|
||||
2. Proceed with API-based integration testing (bypass UI)
|
||||
3. Mark project as "API Ready, Frontend Incomplete"
|
||||
4. Final verdict: CONDITIONAL APPROVAL (API-only usage)
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 Conclusion
|
||||
|
||||
Frontend E2E testing **BLOCKED** by missing `/api/clubs/me` endpoint.
|
||||
|
||||
**Project Status:**
|
||||
- ✅ Backend API: Fully functional
|
||||
- ❌ Frontend Integration: Non-functional (authentication loop)
|
||||
- ⚠️ Overall: Partially complete (API-only use case viable)
|
||||
Reference in New Issue
Block a user