feat: auth, persistence, and AI integration

- Cookie-based auth via backend proxy (httpOnly JWTs)
- Supabase Postgres persistence for sessions/messages/profiles + RLS
- Fix cross-user session leak (token cache keyed by full token, not 50-char prefix)
- Fix missing table grants (42501) via migration; auto-provision profiles on user creation
- Chat validation, ownership checks, rate limiting, /api/chat/sessions route ordering
- Frontend auth-state reset + credentials include
- OpenRouter AI provider (OpenAI-compatible base URL, reasoning disabled)
- Tests: chatValidation, appState
This commit is contained in:
2026-08-19 09:41:40 -04:00
parent 93a35a7343
commit ff9da4d324
43 changed files with 4174 additions and 249 deletions
@@ -8,13 +8,16 @@ import "./ChatHistory.css";
const ChatHistory = ({
messages,
activeSubject,
activeGrade,
activeChapter,
onPromptClick,
isTyping,
showSelectorFlow,
onGradeChange,
selectorStep,
selectorData,
}) => {
const hasMessages = messages.length > 0;
const isSelector = selectorStep !== "chat";
const suggestions = [
{
@@ -63,6 +66,7 @@ const ChatHistory = ({
const streamingMsg = messages.find((m) => m.streaming);
/* ─── Messages mode ─── */
if (hasMessages) {
return (
<div className="chat-history">
@@ -79,14 +83,23 @@ const ChatHistory = ({
);
}
if (showSelectorFlow) {
/* ─── Selector mode (grade → subject → chapter) ─── */
if (isSelector && selectorData) {
return (
<div className="chat-history">
<SelectorFlow grade={activeGrade} onGradeChange={onGradeChange} />
<SelectorFlow
title={selectorData.title}
subtitle={selectorData.subtitle}
selected={selectorData.selected}
items={selectorData.items}
onSelect={selectorData.onSelect}
step={selectorStep}
/>
</div>
);
}
/* ─── Welcome / suggestions mode ─── */
return (
<div className="chat-history">
<div className="chat-history__focus">