2:I[7012,["4765","static/chunks/4765-f5afdf8061f456f3.js","9856","static/chunks/9856-3b185291364d9bef.js","6687","static/chunks/app/docs/%5B...slug%5D/page-e07536548216bee4.js"],"MarkdownRenderer"] 4:I[9856,["4765","static/chunks/4765-f5afdf8061f456f3.js","9856","static/chunks/9856-3b185291364d9bef.js","6687","static/chunks/app/docs/%5B...slug%5D/page-e07536548216bee4.js"],""] 5:I[4126,[],""] 7:I[9630,[],""] 8:I[4278,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"HeadingProvider"] 9:I[1476,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"Header"] a:I[3167,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"Sidebar"] b:I[7409,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"PageFrame"] 3:T1e33, # Admin Panel Login Fix - Complete Resolution **Date:** 2025-11-22 **Issue:** Admin panel login at https://admin.asimo.io was failing with "Unexpected token '<', '( '/api/auth/login', { method: 'POST', body: JSON.stringify({ email, password }) } ); // After: Direct fetch (handles flat response) const res = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }), }); if (!res.ok) { throw new Error(`Login failed: ${res.statusText}`); } const response = await res.json() as { access_token: string; ... }; ``` **Deployment:** ```bash cd /home/asimo/VoiceAssist/apps/admin-panel npm run build sudo cp -r dist/* /var/www/admin.asimo.io/ ``` ## Verification ### Backend API Test ```bash curl -s https://admin.asimo.io/api/auth/login \ -X POST \ -H "Content-Type: application/json" \ -d '{"email":"admin@asimo.io","password":"admin123"}' | jq . ``` **Expected Output:** ```json { "access_token": "eyJhbGc...", "refresh_token": "eyJhbGc...", "token_type": "bearer", "expires_in": 900 } ``` ### Docker Services Status ```bash docker ps | grep -E 'redis|postgres|voiceassist-server' ``` **Expected:** All three containers should show `Up` and `healthy` status. ### Apache Logs ```bash sudo tail -20 /var/log/apache2/admin-voiceassist-error.log ``` **Expected:** No new 503 errors or connection refused errors. ## Git Changes **Branch:** `fix/admin-panel-login-api-format` **Files Changed:** - `apps/admin-panel/src/contexts/AuthContext.tsx` **Commit Message:** ``` Fix admin panel login API response format mismatch The backend /api/auth/login endpoint returns a flat JSON response with access_token, refresh_token, etc., but the frontend was using fetchAPI() which expects responses wrapped in an APIEnvelope format. ``` **Push:** ```bash git checkout -b fix/admin-panel-login-api-format git add apps/admin-panel/src/contexts/AuthContext.tsx git commit -m "..." git push -u origin fix/admin-panel-login-api-format ``` **PR Link:** https://github.com/mohammednazmy/VoiceAssist/pull/new/fix/admin-panel-login-api-format ## Docker Network Configuration **Network:** `voiceassist_database-network` **Containers on Network:** - `voiceassist-server` (172.18.0.2) - Backend API - `f478d2901588_voiceassist-redis` (172.18.0.3) - Redis cache - `voiceassist-qdrant` (172.18.0.4) - Vector database - `5ec82d4fbfa9_voiceassist-postgres` (172.18.0.5) - PostgreSQL database **Network Aliases:** - `postgres` → 172.18.0.5 - `redis` → 172.18.0.3 - `qdrant` → 172.18.0.4 ## Lessons Learned 1. **Docker Port Publishing:** The `-p 8000:8000` flag doesn't always work as expected when containers are on custom bridge networks. Using container IPs directly in Apache proxy config is more reliable. 2. **Environment Variable Mismatches:** Always verify that `.env` files match the actual container configurations, especially for passwords and hostnames. 3. **API Response Formats:** Backend auth endpoints may use different response formats than standard API endpoints. Don't assume all endpoints follow the same envelope pattern. 4. **Error Diagnosis:** When seeing JSON parse errors with HTML content, check: - Apache proxy configuration - Backend service availability - Network connectivity between Apache and containers ## Future Improvements 1. **Container Management:** Consider using docker-compose to ensure all services start together with correct configurations. 2. **Health Checks:** Add monitoring to detect when Redis/Postgres containers stop unexpectedly. 3. **API Consistency:** Consider wrapping auth endpoints in the same APIEnvelope format as other endpoints, or update frontend to handle both formats gracefully. 4. **Environment Validation:** Add startup checks to verify `.env` values match container configurations. ## Related Documentation - `/home/asimo/VoiceAssist/docs/ADMIN_PANEL_LOGIN_FIX.md` - Previous troubleshooting attempts - `/etc/apache2/sites-available/admin.asimo.io.conf` - Apache configuration - `/home/asimo/VoiceAssist/.env` - Environment variables ## Testing Checklist - [x] Backend `/api/auth/login` returns valid JSON tokens - [x] Frontend builds without errors - [x] Production build deployed to `/var/www/admin.asimo.io/` - [x] Apache proxies requests to backend correctly - [x] All Docker containers running and healthy - [x] Git changes committed and pushed - [ ] **User tests login at https://admin.asimo.io/login** ← Final verification needed ## Status ✅ **FIXED** - All technical issues resolved. Awaiting user verification of login functionality in browser. 6:["slug","ADMIN_PANEL_LOGIN_FIX_COMPLETE","c"] 0:["X7oMT3VrOffzp0qvbeOas",[[["",{"children":["docs",{"children":[["slug","ADMIN_PANEL_LOGIN_FIX_COMPLETE","c"],{"children":["__PAGE__?{\"slug\":[\"ADMIN_PANEL_LOGIN_FIX_COMPLETE\"]}",{}]}]}]},"$undefined","$undefined",true],["",{"children":["docs",{"children":[["slug","ADMIN_PANEL_LOGIN_FIX_COMPLETE","c"],{"children":["__PAGE__",{},[["$L1",["$","div",null,{"children":[["$","div",null,{"className":"mb-6 flex items-center justify-between gap-4","children":[["$","div",null,{"children":[["$","p",null,{"className":"text-sm text-gray-500 dark:text-gray-400","children":"Docs / Raw"}],["$","h1",null,{"className":"text-3xl font-bold text-gray-900 dark:text-white","children":"Admin Panel Login Fix Complete"}],["$","p",null,{"className":"text-sm text-gray-600 dark:text-gray-400","children":["Sourced from"," ",["$","code",null,{"className":"font-mono text-xs","children":["docs/","ADMIN_PANEL_LOGIN_FIX_COMPLETE.md"]}]]}]]}],["$","a",null,{"href":"https://github.com/mohammednazmy/VoiceAssist/edit/main/docs/ADMIN_PANEL_LOGIN_FIX_COMPLETE.md","target":"_blank","rel":"noreferrer","className":"inline-flex items-center gap-2 rounded-md border border-gray-200 dark:border-gray-700 px-3 py-1.5 text-sm text-gray-700 dark:text-gray-200 hover:border-primary-500 dark:hover:border-primary-400 hover:text-primary-700 dark:hover:text-primary-300","children":"Edit on GitHub"}]]}],["$","div",null,{"className":"rounded-lg border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-6","children":["$","$L2",null,{"content":"$3"}]}],["$","div",null,{"className":"mt-6 flex flex-wrap gap-2 text-sm","children":[["$","$L4",null,{"href":"/reference/all-docs","className":"inline-flex items-center gap-1 rounded-md bg-gray-100 px-3 py-1 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700","children":"← All documentation"}],["$","$L4",null,{"href":"/","className":"inline-flex items-center gap-1 rounded-md bg-gray-100 px-3 py-1 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700","children":"Home"}]]}]]}],null],null],null]},[null,["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children","docs","children","$6","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[null,["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children","docs","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/7f586cdbbaa33ff7.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","className":"h-full","children":["$","body",null,{"className":"__className_f367f3 h-full bg-white dark:bg-gray-900","children":[["$","a",null,{"href":"#main-content","className":"skip-to-content","children":"Skip to main content"}],["$","$L8",null,{"children":[["$","$L9",null,{}],["$","$La",null,{}],["$","main",null,{"id":"main-content","className":"lg:pl-64","role":"main","aria-label":"Documentation content","children":["$","$Lb",null,{"children":["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]]}]]}]}]],null],null],["$Lc",null]]]] c:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Admin Panel Login Fix Complete | Docs | VoiceAssist Docs"}],["$","meta","3",{"name":"description","content":"**Date:** 2025-11-22"}],["$","meta","4",{"name":"keywords","content":"VoiceAssist,documentation,medical AI,voice assistant,healthcare,HIPAA,API"}],["$","meta","5",{"name":"robots","content":"index, follow"}],["$","meta","6",{"name":"googlebot","content":"index, follow"}],["$","link","7",{"rel":"canonical","href":"https://assistdocs.asimo.io"}],["$","meta","8",{"property":"og:title","content":"VoiceAssist Documentation"}],["$","meta","9",{"property":"og:description","content":"Comprehensive documentation for VoiceAssist - Enterprise Medical AI Assistant"}],["$","meta","10",{"property":"og:url","content":"https://assistdocs.asimo.io"}],["$","meta","11",{"property":"og:site_name","content":"VoiceAssist Docs"}],["$","meta","12",{"property":"og:type","content":"website"}],["$","meta","13",{"name":"twitter:card","content":"summary"}],["$","meta","14",{"name":"twitter:title","content":"VoiceAssist Documentation"}],["$","meta","15",{"name":"twitter:description","content":"Comprehensive documentation for VoiceAssist - Enterprise Medical AI Assistant"}],["$","meta","16",{"name":"next-size-adjust"}]] 1:null