AI route was reading LITELLM_URL/LITELLM_KEY but env vars are named
LITELLM_BASE_URL/LITELLM_API_KEY — causing 503 on every request.
Home page chat now creates a fresh session each time the modal opens
and resets homeSessionId on close, so conversations don't pile into
the same old session.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- h-screen with overflow-hidden so messages scroll within viewport
- Sidebar is slide-over on mobile (fixed + overlay) with translate animation
- Sidebar defaults closed; auto-selects first session on load
- Empty state when no session selected with "New Chat" CTA
- Typing indicator with animated bouncing dots
- Chat bubbles properly aligned (user right, AI left) with rounded corners
- Delete confirm moved to its own modal (not nested in session list item)
- Removed stale debug console.log
- Dark mode fixes: border, hover states, disabled button
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Added dark: variants to all cards, inputs, selects, text, and buttons
throughout the medical page. Added whitespace-nowrap + flex-shrink-0 to
all tab buttons to prevent labels like "Doctor Visit" from wrapping.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Age now shows years, months and days (e.g. "1 year, 3 months, 5 days").
Added dark: variants to all white cards, inputs, selects, and text on the
home page so dark mode no longer shows white boxes on a dark background.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All three useEffect calls were placed after an early return when childId was
null, causing React error #310 on the home page. Moved them above the
conditional returns and guarded each body with if (!childId) return.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Simple hash_ format stored by admin PATCH was incompatible with bcrypt
verification in /api/auth/signin, causing "Invalid password" on login.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Route was returning { test: "ok", count: N } instead of the expected
overview/conversions/growth/childrenByAge structure, crashing the dashboard.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
verifyAdminSession() and requireAdmin() both used expires_at but the
admin_sessions table column is named expires — causing every session
check to silently fail and always redirect to /admin-login.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root causes:
- tia_admin_session is httpOnly so document.cookie could never read it → all
client-side cookie checks always failed and redirected before any data fetched
- Sub-pages used localStorage.getItem("admin_token") which was never stored,
and passed Authorization: Bearer null headers the server ignores
Fixes:
- FamilyProvider: use usePathname() hook instead of window.location.pathname
- admin/layout.tsx: rewrite as server component using verifyAdminSession()
(new lib/admin-auth.ts helper that uses next/headers cookies()) → server-side
redirect to /admin-login if session invalid; extract sidebar to AdminSidebar.tsx
- admin/page.tsx: remove broken document.cookie guard (layout handles auth now)
- admin-login/page.tsx: replace document.cookie check with GET /api/admin/auth call
- All 7 admin sub-pages: remove localStorage guard, remove Authorization: Bearer
headers, add credentials: include to every fetch call
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix redirect from /admin/login to /admin-login
- Add DELETE endpoint for logout
- Connect logout button to API
- Remove unused admin state/localStorage
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Login page checks cookie on load via useEffect, no need for
localStorage token. More secure this way.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The API was setting the session token as a cookie but not
returning it in the JSON response. Login page expects token
in the response to store in localStorage.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Drizzle transaction generic type was causing a type mismatch error.
Since withFamilyContext and getScopedDb were not used anywhere,
simplify the file to just re-export sql and dbUnscoped.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>