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:T129d, # Dev Frontend CORS Fix Summary **Date:** 2025-11-24 **Issue:** Dev frontend (dev.asimo.io) was calling `/conversations` without `/api` prefix, causing 404s and CORS errors ## Root Cause The dev.asimo.io Apache vhost was proxying **all requests** (including `/api/*`) to the Vite dev server on port 5173, instead of proxying API requests to the backend on port 8000. ## Changes Made ### 1. Fixed Double `/api` Bug in Frontend (apps/web-app/src/hooks/useAuth.ts) **Before:** ```typescript baseURL: `${import.meta.env.VITE_API_URL || "http://localhost:8000"}/api`; ``` **After:** ```typescript baseURL: import.meta.env.VITE_API_URL || "http://localhost:8000/api"; ``` **Why:** `VITE_API_URL` already includes `/api`: - Dev: `VITE_API_URL=https://dev.asimo.io/api` - Prod: `VITE_API_URL=https://assist.asimo.io/api` Appending `/api` was creating URLs like `https://dev.asimo.io/api/api/conversations` (404). ### 2. Updated Apache Vhost for dev.asimo.io (/etc/apache2/sites-available/dev.asimo.io-le-ssl.conf) **Changes:** - Added `ProxyPass /api http://localhost:8000/api` to route API requests to backend - Added WebSocket support for API routes: `RewriteRule` for `/api/` with `ws://localhost:8000/` - Added `DocumentRoot /var/www/dev.asimo.io` to serve static test files - Added `RewriteCond` to check if file exists before proxying to Vite - Everything else still proxies to Vite dev server (port 5173) for HMR **Result:** - `https://dev.asimo.io/api/*` → proxied to backend (localhost:8000) - `https://dev.asimo.io/*` → proxied to Vite dev server (localhost:5173) - Static files in `/var/www/dev.asimo.io/` served directly ### 3. Restarted Services - Restarted Vite dev server to pick up useAuth.ts changes - Reloaded Apache with `sudo systemctl reload apache2` - Backend already had correct CORS (`ALLOWED_ORIGINS` includes `https://dev.asimo.io`) ## Verification ### CORS Test Results ```bash # OPTIONS preflight curl -i -X OPTIONS "https://dev.asimo.io/api/conversations" \ -H "Origin: https://dev.asimo.io" \ -H "Access-Control-Request-Method: GET" \ -H "Access-Control-Request-Headers: authorization" # Response includes: # access-control-allow-origin: https://dev.asimo.io # access-control-allow-credentials: true # access-control-allow-methods: GET, POST, PUT, DELETE, PATCH ``` ### API Endpoint Tests ```bash # Login works curl -s https://dev.asimo.io/api/auth/login -X POST \ -H "Content-Type: application/json" \ -d '{"email":"admin@asimo.io","password":"admin123"}' # Returns: {"access_token": "eyJ..."} # Conversations endpoint accessible (auth issue is separate) curl -s "https://dev.asimo.io/api/conversations?page=1&pageSize=3" \ -H "Authorization: Bearer " # Returns proper response or auth error (not 404/CORS error) ``` ### Test Page Created test page at `/var/www/dev.asimo.io/test-cors.html` to verify from browser: ``` https://dev.asimo.io/test-cors.html ``` ## Remaining Issues ### Redis Connection / Auth The backend logs show: ``` Cannot check token revocation - Redis not connected, assuming valid ``` This causes 401 "Could not validate credentials" errors even with valid tokens. However, this is a **separate issue** from the CORS/routing problem that has been fixed. **Note:** Login endpoint works fine (returns tokens), but protected endpoints like `/api/conversations` fail auth validation. ## Git Commit ``` commit 18a084c fix(dev): fix API base URL to prevent double /api prefix - Remove extra /api suffix from baseURL in useAuth.ts - VITE_API_URL already includes /api, so no need to append it - This fixes 404 errors and CORS issues on both dev and prod - Also implement register method properly (was TODO) ``` ## Manual Verification Steps 1. **Open browser and visit:** https://dev.asimo.io 2. **Check Network tab:** API calls should go to `https://dev.asimo.io/api/*` (not 404) 3. **Check CORS headers:** Responses should include `Access-Control-Allow-Origin: https://dev.asimo.io` 4. **WebSocket:** Should connect to `wss://dev.asimo.io/api/realtime/ws` when creating conversation 5. **No CORS errors:** Browser console should not show "blocked by CORS policy" ## Configuration Files Changed 1. `/home/asimo/VoiceAssist/apps/web-app/src/hooks/useAuth.ts` (committed) 2. `/etc/apache2/sites-available/dev.asimo.io-le-ssl.conf` (not in repo) ## Environment Variables Verified - `/home/asimo/VoiceAssist/apps/web-app/.env.development`: ``` VITE_API_URL=https://dev.asimo.io/api VITE_WS_URL=wss://dev.asimo.io/api/realtime/ws ``` - `/home/asimo/VoiceAssist/services/api-gateway/.env`: ``` ALLOWED_ORIGINS=https://assist1.asimo.io,https://assist.asimo.io,http://localhost:5173,https://dev.asimo.io ``` Both were already correct before this fix. 6:["slug","archive/DEV_CORS_FIX_SUMMARY","c"] 0:["X7oMT3VrOffzp0qvbeOas",[[["",{"children":["docs",{"children":[["slug","archive/DEV_CORS_FIX_SUMMARY","c"],{"children":["__PAGE__?{\"slug\":[\"archive\",\"DEV_CORS_FIX_SUMMARY\"]}",{}]}]}]},"$undefined","$undefined",true],["",{"children":["docs",{"children":[["slug","archive/DEV_CORS_FIX_SUMMARY","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":"Dev Cors Fix Summary"}],["$","p",null,{"className":"text-sm text-gray-600 dark:text-gray-400","children":["Sourced from"," ",["$","code",null,{"className":"font-mono text-xs","children":["docs/","archive/DEV_CORS_FIX_SUMMARY.md"]}]]}]]}],["$","a",null,{"href":"https://github.com/mohammednazmy/VoiceAssist/edit/main/docs/archive/DEV_CORS_FIX_SUMMARY.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":"Dev Cors Fix Summary | Docs | VoiceAssist Docs"}],["$","meta","3",{"name":"description","content":"**Date:** 2025-11-24"}],["$","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