🧭 Compass Learning

AI-Powered Learning Companion for ADHD Learners

User Journeys

● Setup Flow: Creating a Learner Profile

Browser
User lands on / — +page.svelte renders progress indicator (Step 1 of 2)
Component
SetupForm.svelte — Collects knowledge anchors (min 3) + reading level. Validates with $derived runes.
Browser
User clicks "Continue" — step advances to 2, renders TopicInput
Component
TopicInput.svelte — Collects learning topic + optional URL. Validates topic not empty.
Store
updateLearner() — Saves {anchors, readingLevel, currentTopic} to learnerStore
Store
clearConversation() — Resets conversation history
Navigation
goto('/learn') — SvelteKit navigates to learning interface

● Learning Flow: A Single Learning Turn

Page
/learn mounts — onMount checks isProfileComplete, redirects to / if missing
Component
OptionButtons.svelte — User clicks an option (e.g., "Go deeper")
Store
addUserTurn(choice) — Appends user turn to conversation (max 15 sliding window)
Fetch
POST /api/chat — Sends {profile, history, topic, userChoice} as JSON
API
+server.ts validates request — Checks profile, history, topic, userChoice fields
Provider
createProvider() — Factory reads AI_PROVIDER env, returns OpenAI or Anthropic instance
AI Logic
buildMessages() — Constructs system prompt (companion.md + learner context) + history + user choice
External
AI API call — OpenAI function calling or Anthropic tool_use with respond_to_learner tool
Parse
Parse tool response — Extract {explanation, checkIn?, options[]} from structured output
Response
Return JSON — 200 OK with AIResponse, or ErrorResponse on failure
Store
addAssistantTurn(response) — Appends assistant turn, keeps last 15
Render
ChatMessage.svelte renders markdown — OptionButtons display 2-5 new clickable options. Auto-scroll via tick().

● Content Extraction Flow

Component
TopicInput.svelte — User pastes a URL in optional URL field
Fetch
POST /api/fetch-url — Sends {url} to backend
API
+server.ts validates URL — Checks url field is present and string
Extractor
validateUrl() — Blocks localhost, private IPs, non-HTTP(S) protocols
Extractor
fetchWithTimeout() — 10s timeout with AbortController
External
HTTP fetch to target URL — Uses CompassLearning/1.0 User-Agent
Parse
JSDOM + Readability — Parse HTML, extract article content, generate excerpt (200 chars)
Response
Return ExtractedContent — {url, title, content, excerpt}

● Error Handling & Recovery

External
AI API call fails — Rate limit, auth error, or network failure
Handler
getErrorMessage() — Maps error types to user-friendly messages
Response
Return ErrorResponse — {error: true, message, code} with 400/500 status
UI
Error panel renders — Red box with message + "Try Again" button
Retry
User clicks "Try Again" — handleRetry() calls startLearning() again

● Start Over Flow

UI
User clicks "Start Over" in header — handleStartOver() triggered
Store
clearConversation() — Sets conversationStore to []
Store
resetLearner() — Sets learnerStore to null
Navigation
goto('/') — Returns to setup page for fresh start

Technology Stack

■ Framework

SvelteKit2.49.1
Svelte5 (Runes)
Adapteradapter-node
Vite7.2.6

■ Language

TypeScript5.9.3
Strict Modeenabled
Module Resolutionbundler

■ Styling

Tailwind CSS4.1.18
PostCSS@tailwindcss/postcss
Autoprefixer10.4.23

■ AI Providers

OpenAI SDK6.16.0
Model (default)gpt-4o
Anthropic SDK0.71.2
Model (default)claude-3.5-sonnet

■ Content Processing

@mozilla/readability0.6.0
jsdom27.4.0

■ Dev Tools

ESLint9.39.2 (flat config)
Prettier3.7.4
Vitest4.0.16
svelte-check4.3.4

■ Deployment

PlatformRender
RuntimeNode.js 20+
Buildnpm run build
Startnode build

■ State Management

TypeSvelte writable stores
PersistenceNone (ephemeral)
Context Window15 turns max
DatabaseNone (POC)
🧭
Click any component in the diagram to see its details
Use layer toggles to filter. Switch views in the header.