● Setup Flow: Creating a Learner Profile
BrowserUser lands on / — +page.svelte renders progress indicator (Step 1 of 2)
ComponentSetupForm.svelte — Collects knowledge anchors (min 3) + reading level. Validates with $derived runes.
BrowserUser clicks "Continue" — step advances to 2, renders TopicInput
ComponentTopicInput.svelte — Collects learning topic + optional URL. Validates topic not empty.
StoreupdateLearner() — Saves {anchors, readingLevel, currentTopic} to learnerStore
StoreclearConversation() — Resets conversation history
Navigationgoto('/learn') — SvelteKit navigates to learning interface
● Learning Flow: A Single Learning Turn
Page/learn mounts — onMount checks isProfileComplete, redirects to / if missing
ComponentOptionButtons.svelte — User clicks an option (e.g., "Go deeper")
StoreaddUserTurn(choice) — Appends user turn to conversation (max 15 sliding window)
FetchPOST /api/chat — Sends {profile, history, topic, userChoice} as JSON
API+server.ts validates request — Checks profile, history, topic, userChoice fields
ProvidercreateProvider() — Factory reads AI_PROVIDER env, returns OpenAI or Anthropic instance
AI LogicbuildMessages() — Constructs system prompt (companion.md + learner context) + history + user choice
ExternalAI API call — OpenAI function calling or Anthropic tool_use with respond_to_learner tool
ParseParse tool response — Extract {explanation, checkIn?, options[]} from structured output
ResponseReturn JSON — 200 OK with AIResponse, or ErrorResponse on failure
StoreaddAssistantTurn(response) — Appends assistant turn, keeps last 15
RenderChatMessage.svelte renders markdown — OptionButtons display 2-5 new clickable options. Auto-scroll via tick().
● Content Extraction Flow
ComponentTopicInput.svelte — User pastes a URL in optional URL field
FetchPOST /api/fetch-url — Sends {url} to backend
API+server.ts validates URL — Checks url field is present and string
ExtractorvalidateUrl() — Blocks localhost, private IPs, non-HTTP(S) protocols
ExtractorfetchWithTimeout() — 10s timeout with AbortController
ExternalHTTP fetch to target URL — Uses CompassLearning/1.0 User-Agent
ParseJSDOM + Readability — Parse HTML, extract article content, generate excerpt (200 chars)
ResponseReturn ExtractedContent — {url, title, content, excerpt}
● Error Handling & Recovery
ExternalAI API call fails — Rate limit, auth error, or network failure
HandlergetErrorMessage() — Maps error types to user-friendly messages
ResponseReturn ErrorResponse — {error: true, message, code} with 400/500 status
UIError panel renders — Red box with message + "Try Again" button
RetryUser clicks "Try Again" — handleRetry() calls startLearning() again
● Start Over Flow
UIUser clicks "Start Over" in header — handleStartOver() triggered
StoreclearConversation() — Sets conversationStore to []
StoreresetLearner() — Sets learnerStore to null
Navigationgoto('/') — Returns to setup page for fresh start