feat: full feature buildout — streaming, i18n, mastery map, admin, jobs
Progressive lesson streaming via onSegment callback (fixes SSE for non-English users — locale was shadowed in lesson-reader useEffect). Adds: BullMQ workers, Redis stream buffer, token budget enforcement, Langfuse tracing, golden-eval runner, Playwright e2e scaffolding, lesson depth/locale/preferences schema, mastery map UI, admin panel (blueprints/users/reports/quality/misconceptions), image queries, source citations, view transitions, reading animations, i18n (next-intl), PDF export, surprise endpoint, and 402 passing unit tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,586 @@
|
||||
{
|
||||
"lesson": {
|
||||
"ariaLesson": "Lesson",
|
||||
"ariaProgress": "Lesson progress",
|
||||
"reading": "Reading",
|
||||
"segments": "{count, plural, one {# segment} other {# segments}}",
|
||||
"segmentLocked": "Complete the previous checkpoint to continue.",
|
||||
"checkpoint": {
|
||||
"predict": "Predict",
|
||||
"explain": "Explain",
|
||||
"solve": "Solve",
|
||||
"placeholder": "Write your answer here…",
|
||||
"checking": "Checking…",
|
||||
"submitted": "Submitted",
|
||||
"confidenceLegend": "Before you submit — how sure are you?",
|
||||
"notSure": "Not sure",
|
||||
"thinkSo": "Think so",
|
||||
"confident": "Confident",
|
||||
"notSureAria": "Not sure about my answer",
|
||||
"thinkSoAria": "I think my answer is right",
|
||||
"confidentAria": "I am confident in my answer"
|
||||
},
|
||||
"print": "Export PDF",
|
||||
"considering": "Considering…",
|
||||
"empty": "This lesson has no segments yet. Check back shortly — content is still being prepared.",
|
||||
"outline": {
|
||||
"intro": "What you'll explore",
|
||||
"preparing": "Generating your lesson…",
|
||||
"streaming": "Writing your lesson…",
|
||||
"streamingLabel": "Lesson content loading"
|
||||
},
|
||||
"tangent": {
|
||||
"placeholder": "Curious about something?",
|
||||
"ariaInput": "Curiosity question",
|
||||
"ariaAsk": "Ask",
|
||||
"considering": "Looking into it…"
|
||||
},
|
||||
"journeyProgress": "Lesson {current} of {total}",
|
||||
"complete": {
|
||||
"ariaLabel": "Lesson complete",
|
||||
"heading": "Lesson complete.",
|
||||
"saved": "Progress saved.",
|
||||
"saving": "Saving…",
|
||||
"markComplete": "Mark complete",
|
||||
"nextLesson": "Next lesson →",
|
||||
"deepen": "Go deeper →",
|
||||
"journeyDone": "Journey complete.",
|
||||
"journeyDoneNote": "You've finished all lessons in this journey."
|
||||
}
|
||||
},
|
||||
"review": {
|
||||
"title": "Daily Review",
|
||||
"aria": "Daily review session",
|
||||
"loading": "Loading your review…",
|
||||
"empty": "Nothing due for review. Check back tomorrow.",
|
||||
"progress": "{current} of {total}",
|
||||
"considering": "Considering…",
|
||||
"next": "Next →",
|
||||
"finish": "Finish",
|
||||
"complete": {
|
||||
"heading": "Session complete",
|
||||
"reviewed": "{count, plural, one {# concept reviewed} other {# concepts reviewed}}",
|
||||
"netDelta": "Net mastery: {delta}",
|
||||
"nothingDue": "You're all caught up.",
|
||||
"backHome": "Back to learning"
|
||||
},
|
||||
"delta": {
|
||||
"up": "↑ {pct}%",
|
||||
"down": "↓ {pct}%",
|
||||
"same": "unchanged"
|
||||
},
|
||||
"emptyUntil": "All caught up. Your next review is on {date}.",
|
||||
"emptyNoHistory": "No reviews yet. Complete a lesson to start building your review queue."
|
||||
},
|
||||
"nav": {
|
||||
"learn": "Learn",
|
||||
"review": "Review",
|
||||
"mastery": "Mastery",
|
||||
"map": "Map",
|
||||
"signIn": "Sign in",
|
||||
"signOut": "Sign out",
|
||||
"profile": "Profile",
|
||||
"admin": "Admin"
|
||||
},
|
||||
"home": {
|
||||
"eyebrow": "Curiosity-led mastery",
|
||||
"title": "What do you want to understand?",
|
||||
"lede": "Tell us what you're curious about.",
|
||||
"fieldLabel": "Your learning intent",
|
||||
"placeholder": "e.g. how vaccines work",
|
||||
"examplesLabel": "Or try one of these",
|
||||
"submit": "Start learning",
|
||||
"submitting": "Finding your lesson…",
|
||||
"error": "Something went wrong. Try again.",
|
||||
"examples": [
|
||||
"Why ice is slippery",
|
||||
"How a gyroscope stays upright",
|
||||
"Why the sky is blue",
|
||||
"What temperature really is",
|
||||
"How noise-cancelling headphones work",
|
||||
"Why light speed is a limit",
|
||||
"How lasers work",
|
||||
"Why magnets attract",
|
||||
"What causes friction",
|
||||
"How a microwave heats food",
|
||||
"Why glass is transparent",
|
||||
"How superconductors work",
|
||||
"What quantum entanglement is",
|
||||
"Why mirrors flip left and right",
|
||||
"How sound travels",
|
||||
"What makes a rainbow",
|
||||
"Why hot air rises",
|
||||
"How a nuclear reactor works",
|
||||
"What dark matter might be",
|
||||
"Why time slows near light speed",
|
||||
"How black holes form",
|
||||
"Why the moon causes tides",
|
||||
"What a neutron star is",
|
||||
"How stars make elements",
|
||||
"Why Mars is red",
|
||||
"How rockets reach orbit",
|
||||
"What the Big Bang was",
|
||||
"Why Pluto isn't a planet",
|
||||
"How GPS uses relativity",
|
||||
"What causes solar eclipses",
|
||||
"How telescopes see the past",
|
||||
"Why galaxies spiral",
|
||||
"What a light-year measures",
|
||||
"How the sun produces energy",
|
||||
"Why space is cold but sunlight burns",
|
||||
"What causes the seasons",
|
||||
"How comets get their tails",
|
||||
"Why the universe is expanding",
|
||||
"What exoplanets are",
|
||||
"How auroras form",
|
||||
"How vaccines work",
|
||||
"Why onions make you cry",
|
||||
"How memory is stored",
|
||||
"Why we dream",
|
||||
"How muscles grow",
|
||||
"What causes aging",
|
||||
"How antibiotics kill bacteria",
|
||||
"Why we get fevers",
|
||||
"How the immune system learns",
|
||||
"What DNA actually does",
|
||||
"How nerves send signals",
|
||||
"Why we yawn",
|
||||
"How the heart keeps rhythm",
|
||||
"What gut bacteria do",
|
||||
"How wounds heal",
|
||||
"Why we need sleep",
|
||||
"How eyes detect color",
|
||||
"What causes allergies",
|
||||
"How cells divide",
|
||||
"Why exercise builds endurance",
|
||||
"Why soap cleans",
|
||||
"How batteries store energy",
|
||||
"What makes something acidic",
|
||||
"How glass is made",
|
||||
"Why metals conduct electricity",
|
||||
"How fireworks get their colors",
|
||||
"What rust really is",
|
||||
"How catalysts speed reactions",
|
||||
"Why oil and water don't mix",
|
||||
"How plastic is made",
|
||||
"What pH measures",
|
||||
"How fermentation works",
|
||||
"Why diamonds are hard",
|
||||
"How soap bubbles form",
|
||||
"What makes chili peppers hot",
|
||||
"How dry ice works",
|
||||
"Why bread rises",
|
||||
"How perfume spreads",
|
||||
"What alloys are",
|
||||
"How carbon dating works",
|
||||
"TCP congestion control",
|
||||
"How encryption keeps secrets",
|
||||
"What a database index does",
|
||||
"How neural networks learn",
|
||||
"Why passwords get hashed",
|
||||
"How the internet routes data",
|
||||
"What a compiler does",
|
||||
"How GPS finds your location",
|
||||
"Why computers use binary",
|
||||
"How a CPU executes code",
|
||||
"What caching really solves",
|
||||
"How Wi-Fi carries data",
|
||||
"What blockchain actually is",
|
||||
"How search engines rank pages",
|
||||
"Why RAM is faster than disk",
|
||||
"How image compression works",
|
||||
"What an API is",
|
||||
"How public-key crypto works",
|
||||
"Why software has bugs",
|
||||
"How machine translation works",
|
||||
"Why prime numbers matter",
|
||||
"What calculus measures",
|
||||
"How probability works",
|
||||
"Why pi is everywhere",
|
||||
"What infinity really means",
|
||||
"What a derivative tells you",
|
||||
"Why zero was revolutionary",
|
||||
"How statistics can mislead",
|
||||
"What exponential growth means",
|
||||
"Why some problems are unsolvable",
|
||||
"How compound interest grows",
|
||||
"What a logarithm is",
|
||||
"Why the bell curve appears",
|
||||
"How fractals are made",
|
||||
"What Bayes' theorem does",
|
||||
"Why we can't divide by zero",
|
||||
"How GPS triangulates position",
|
||||
"What a matrix represents",
|
||||
"Why randomness is hard",
|
||||
"How central banks set rates",
|
||||
"What causes inflation",
|
||||
"How stock markets work",
|
||||
"Why money has value",
|
||||
"What a recession is",
|
||||
"How taxes shape behavior",
|
||||
"Why prices rise and fall",
|
||||
"What supply and demand means",
|
||||
"How insurance spreads risk",
|
||||
"Why trade benefits both sides",
|
||||
"What GDP measures",
|
||||
"How credit scores work",
|
||||
"Why bubbles form and burst",
|
||||
"How exchange rates move",
|
||||
"Why monopolies are risky",
|
||||
"What a bond is",
|
||||
"How venture capital works",
|
||||
"Why diversification matters",
|
||||
"What game theory explains",
|
||||
"How the printing press changed Europe",
|
||||
"Why empires collapse",
|
||||
"How writing was invented",
|
||||
"What caused the Industrial Revolution",
|
||||
"Why the Roman Empire fell",
|
||||
"How money replaced barter",
|
||||
"What sparked the Renaissance",
|
||||
"How democracy began",
|
||||
"Why the Silk Road mattered",
|
||||
"What the Enlightenment changed",
|
||||
"How plagues reshaped society",
|
||||
"Why borders are where they are",
|
||||
"How language families spread",
|
||||
"What caused the Cold War",
|
||||
"How cities first formed",
|
||||
"Why revolutions happen",
|
||||
"How navigation opened the world",
|
||||
"What feudalism really was",
|
||||
"How the calendar was set",
|
||||
"Why some civilizations vanished",
|
||||
"How earthquakes happen",
|
||||
"Why volcanoes erupt",
|
||||
"What causes weather",
|
||||
"How mountains form",
|
||||
"Why the ocean is salty",
|
||||
"How rivers shape land",
|
||||
"What drives ocean currents",
|
||||
"Why deserts form where they do",
|
||||
"How fossils are made",
|
||||
"How clouds form rain",
|
||||
"Why the climate is changing",
|
||||
"How coral reefs grow",
|
||||
"What plate tectonics explains",
|
||||
"How caves form",
|
||||
"Why leaves change color",
|
||||
"How lightning forms",
|
||||
"What soil is made of",
|
||||
"How glaciers move",
|
||||
"Why some places get monsoons",
|
||||
"Why we procrastinate",
|
||||
"How habits form",
|
||||
"Why music moves us",
|
||||
"How we learn languages",
|
||||
"What makes things go viral",
|
||||
"Why optical illusions fool us",
|
||||
"How memory tricks work",
|
||||
"Why we feel déjà vu",
|
||||
"How persuasion works",
|
||||
"What makes a melody catchy",
|
||||
"Why crowds behave irrationally",
|
||||
"How accents develop",
|
||||
"Why we see faces everywhere",
|
||||
"How the placebo effect works",
|
||||
"Why deadlines boost focus",
|
||||
"How color affects mood",
|
||||
"Why stories stick with us",
|
||||
"How bilingual brains switch",
|
||||
"Why we forget names",
|
||||
"How attention actually works"
|
||||
],
|
||||
"spark": "Spark something",
|
||||
"sparking": "Finding something…",
|
||||
"or": "or",
|
||||
"depthLabel": "Lesson depth",
|
||||
"depth": {
|
||||
"quick": "Quick",
|
||||
"quickMeta": "~5 min",
|
||||
"standard": "Standard",
|
||||
"standardMeta": "~10 min",
|
||||
"deep": "Deep",
|
||||
"deepMeta": "~20 min"
|
||||
},
|
||||
"modeLabel": "Format",
|
||||
"mode": {
|
||||
"practice": "Practice",
|
||||
"read": "Just read"
|
||||
},
|
||||
"continue": {
|
||||
"heading": "Continue learning",
|
||||
"lessonProgress": "Lesson {position} of {total}",
|
||||
"resume": "Resume →"
|
||||
},
|
||||
"dueReviews": "{count} due for review →"
|
||||
},
|
||||
"auth": {
|
||||
"login": {
|
||||
"title": "Sign in",
|
||||
"email": "Email",
|
||||
"password": "Password",
|
||||
"submit": "Sign in",
|
||||
"submitting": "Signing in…",
|
||||
"error": "Invalid email or password.",
|
||||
"forgotPassword": "Forgot password?",
|
||||
"noAccount": "No account?",
|
||||
"register": "Register",
|
||||
"resetSuccess": "Password updated. Sign in with your new password.",
|
||||
"or": "or",
|
||||
"continueWithGoogle": "Continue with Google",
|
||||
"continueWithGitHub": "Continue with GitHub",
|
||||
"continueWith": "Continue with {provider}"
|
||||
},
|
||||
"register": {
|
||||
"title": "Create account",
|
||||
"name": "Name",
|
||||
"email": "Email",
|
||||
"password": "Password",
|
||||
"confirmPassword": "Confirm password",
|
||||
"passwordMismatch": "Passwords do not match.",
|
||||
"submit": "Create account",
|
||||
"submitting": "Creating account…",
|
||||
"signInFailed": "Account created but sign-in failed. Try signing in manually.",
|
||||
"hasAccount": "Already have an account?",
|
||||
"signIn": "Sign in"
|
||||
},
|
||||
"forgotPassword": {
|
||||
"title": "Reset password",
|
||||
"email": "Email",
|
||||
"submit": "Send reset link",
|
||||
"submitting": "Sending…",
|
||||
"sentTitle": "Check your inbox",
|
||||
"sentBody": "If an account exists for that email, we sent a reset link. It expires in 1 hour.",
|
||||
"backToSignIn": "Back to sign in",
|
||||
"error": "Something went wrong. Try again."
|
||||
},
|
||||
"resetPassword": {
|
||||
"title": "Set new password",
|
||||
"newPassword": "New password",
|
||||
"confirmPassword": "Confirm password",
|
||||
"passwordMismatch": "Passwords do not match.",
|
||||
"submit": "Set password",
|
||||
"submitting": "Saving…",
|
||||
"error": "Failed to reset password.",
|
||||
"invalidLink": "Invalid reset link.",
|
||||
"requestNew": "Request a new one"
|
||||
},
|
||||
"acceptInvite": {
|
||||
"title": "Accept your invitation",
|
||||
"subtitle": "Set up your account to get started.",
|
||||
"email": "Email",
|
||||
"name": "Your name",
|
||||
"password": "Password",
|
||||
"confirmPassword": "Confirm password",
|
||||
"passwordMismatch": "Passwords do not match.",
|
||||
"submit": "Create account",
|
||||
"submitting": "Creating…",
|
||||
"error": "Could not accept this invite.",
|
||||
"invalidLink": "This invite link is invalid, expired, or already used.",
|
||||
"goToLogin": "Go to sign in"
|
||||
},
|
||||
"verifyEmail": {
|
||||
"title": "Verify your email",
|
||||
"body": "We sent a verification link to your email address. Click it to activate your account.",
|
||||
"subtext": "Didn't receive it? Check your spam folder."
|
||||
},
|
||||
"error": {
|
||||
"title": "Authentication error",
|
||||
"default": "Something went wrong during sign in.",
|
||||
"Configuration": "Server configuration error. Contact support.",
|
||||
"AccessDenied": "Access denied.",
|
||||
"Verification": "The verification link has expired or already been used.",
|
||||
"backToSignIn": "Back to sign in"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"title": "Settings",
|
||||
"profile": {
|
||||
"title": "Profile",
|
||||
"name": "Display name",
|
||||
"save": "Save",
|
||||
"saving": "Saving…",
|
||||
"saved": "Saved.",
|
||||
"saveFailed": "Failed to save."
|
||||
},
|
||||
"language": {
|
||||
"title": "Language",
|
||||
"label": "Interface language",
|
||||
"description": "Choose the language used throughout the app.",
|
||||
"en": "English",
|
||||
"fr": "Français"
|
||||
},
|
||||
"security": {
|
||||
"title": "Security",
|
||||
"currentPassword": "Current password",
|
||||
"newPassword": "New password",
|
||||
"confirmPassword": "Confirm new password",
|
||||
"changePassword": "Change password",
|
||||
"changing": "Changing…",
|
||||
"changed": "Password changed.",
|
||||
"failed": "Failed.",
|
||||
"oauthNote": "Password change is not available for accounts using social sign-in.",
|
||||
"linked": "Linked via: {providers}",
|
||||
"passwordMismatch": "New passwords do not match."
|
||||
},
|
||||
"appearance": {
|
||||
"title": "Appearance",
|
||||
"theme": {
|
||||
"label": "Theme",
|
||||
"system": "System",
|
||||
"light": "Light",
|
||||
"dark": "Dark"
|
||||
}
|
||||
},
|
||||
"danger": {
|
||||
"title": "Danger zone",
|
||||
"deleteAccount": "Delete account",
|
||||
"deleteConfirm": "Delete my account",
|
||||
"deleteWarning": "This will permanently delete your account and all your learning data. This cannot be undone.",
|
||||
"deleting": "Deleting…"
|
||||
},
|
||||
"learning": {
|
||||
"title": "Learning",
|
||||
"description": "Shape how lessons are written for you.",
|
||||
"ageGroup": {
|
||||
"label": "Who is learning?",
|
||||
"child": "Child (8–12)",
|
||||
"teen": "Teen (13–17)",
|
||||
"adult": "Adult"
|
||||
},
|
||||
"difficulty": {
|
||||
"label": "Default difficulty",
|
||||
"1": "Beginner",
|
||||
"2": "Intermediate",
|
||||
"3": "Advanced"
|
||||
},
|
||||
"depth": {
|
||||
"label": "Default lesson length",
|
||||
"quick": "Quick (~5 min)",
|
||||
"standard": "Standard (~10 min)",
|
||||
"deep": "Deep (~20 min)"
|
||||
},
|
||||
"hint": {
|
||||
"label": "About you (optional)",
|
||||
"placeholder": "e.g. I'm a nurse, I like analogies with cooking…",
|
||||
"description": "A short note helps tailor explanations to your background."
|
||||
},
|
||||
"save": "Save",
|
||||
"saving": "Saving…",
|
||||
"saved": "Saved.",
|
||||
"saveFailed": "Failed to save."
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notifications",
|
||||
"description": "Control how Curio contacts you.",
|
||||
"emailDigest": "Send me a daily email when reviews are due"
|
||||
}
|
||||
},
|
||||
"onboarding": {
|
||||
"title": "Welcome to Curio",
|
||||
"subtitle": "Let's set up your learning profile. You can always change this later.",
|
||||
"ageGroup": {
|
||||
"label": "Who is learning?",
|
||||
"child": "Child (8–12)",
|
||||
"teen": "Teen (13–17)",
|
||||
"adult": "Adult"
|
||||
},
|
||||
"difficulty": {
|
||||
"label": "How familiar are you with most topics?",
|
||||
"1": "Beginner — build from first principles",
|
||||
"2": "Intermediate — assume basic familiarity",
|
||||
"3": "Advanced — go deep, explore edge cases"
|
||||
},
|
||||
"depth": {
|
||||
"label": "Preferred lesson length",
|
||||
"quick": "Quick (~5 min)",
|
||||
"standard": "Standard (~10 min)",
|
||||
"deep": "Deep (~20 min)"
|
||||
},
|
||||
"hint": {
|
||||
"label": "Tell us a bit about yourself (optional)",
|
||||
"placeholder": "e.g. I'm a nurse, I like analogies with cooking…",
|
||||
"description": "Helps tailor explanations to your background."
|
||||
},
|
||||
"submit": "Get started",
|
||||
"submitting": "Saving…",
|
||||
"skip": "Skip for now"
|
||||
},
|
||||
"masteryMap": {
|
||||
"title": "Mastery Map",
|
||||
"loading": "Loading…",
|
||||
"empty": "No mastery data yet.",
|
||||
"emptyLink": "Start learning",
|
||||
"due": "due",
|
||||
"dueZone": {
|
||||
"heading": "Due for review",
|
||||
"startReview": "Start review →",
|
||||
"none": "Nothing due right now."
|
||||
},
|
||||
"overview": {
|
||||
"mastered": "Mastered",
|
||||
"learning": "Learning",
|
||||
"needsWork": "Needs work",
|
||||
"progress": "{mastered} of {total} concepts mastered"
|
||||
},
|
||||
"status": {
|
||||
"mastered": "Mastered",
|
||||
"learning": "Learning",
|
||||
"needsWork": "Needs work",
|
||||
"notStarted": "Not started"
|
||||
},
|
||||
"filter": {
|
||||
"all": "All",
|
||||
"due": "Due",
|
||||
"needsWork": "Needs work"
|
||||
},
|
||||
"remove": "Remove",
|
||||
"removeBlueprint": "Remove {title} from mastery map"
|
||||
},
|
||||
"profile": {
|
||||
"title": "Your profile",
|
||||
"masteryTitle": "Mastery overview",
|
||||
"noMastery": "No mastery data yet. Start learning to see progress here."
|
||||
},
|
||||
"grade": {
|
||||
"verdict": {
|
||||
"mastered": "Understood",
|
||||
"partial": "Partial",
|
||||
"misconception": "Misconception",
|
||||
"uncertain": "Unclear"
|
||||
},
|
||||
"calibration": {
|
||||
"confidentFailed": "You rated yourself confident — worth pausing on what tripped you.",
|
||||
"unsurePassed": "You rated yourself unsure, but your answer was solid. Trust your understanding."
|
||||
},
|
||||
"referenceHeading": "Full answer",
|
||||
"ariaFeedback": "Tutor feedback",
|
||||
"ariaCalibration": "Calibration note",
|
||||
"socratic": {
|
||||
"ariaLabel": "Socratic follow-up",
|
||||
"placeholder": "Go ahead…",
|
||||
"ariaInput": "Follow-up answer",
|
||||
"submit": "Reply",
|
||||
"considering": "Considering…"
|
||||
},
|
||||
"reexplain": {
|
||||
"loading": "Preparing another explanation…",
|
||||
"trigger": "Try another explanation →"
|
||||
},
|
||||
"retry": "Try again →",
|
||||
"report": {
|
||||
"toggle": "Flag an issue",
|
||||
"ariaLabel": "Report an issue",
|
||||
"thanks": "Thanks — we'll look into it.",
|
||||
"reasonGradeWrong": "Grade seems wrong",
|
||||
"reasonContentError": "Content error",
|
||||
"reasonOther": "Other",
|
||||
"notesPlaceholder": "Optional details…",
|
||||
"ariaReason": "Reason",
|
||||
"ariaDetails": "Details",
|
||||
"submit": "Send",
|
||||
"cancel": "Cancel"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user