cosmicmicra commited on
Commit
3bc409d
Β·
verified Β·
1 Parent(s): 6ecd5b7

Add system architecture document

Browse files
Files changed (1) hide show
  1. system_architecture.md +925 -0
system_architecture.md ADDED
@@ -0,0 +1,925 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MathLingua β€” System Architecture Document
2
+
3
+ ## 1. System Overview
4
+
5
+ MathLingua is a bilingual adaptive math tutoring application for Spanish-speaking students (grades 6–8) transitioning to English-medium mathematics education. The system presents math word problems with 4 scaffolded hint levels and uses a hybrid adaptive algorithm to personalize difficulty progression.
6
+
7
+ ```
8
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
9
+ β”‚ MathLingua System β”‚
10
+ β”‚ β”‚
11
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
12
+ β”‚ β”‚ Frontend β”‚ β”‚ Backend β”‚ β”‚ External Services β”‚ β”‚
13
+ β”‚ β”‚ (Next.js) │◄─►│ (Firebase) │◄─►│ (LLM / SLM) β”‚ β”‚
14
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
15
+ β”‚ β”‚ β”‚ β”‚ β”‚
16
+ β”‚ β–Ό β–Ό β–Ό β”‚
17
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
18
+ β”‚ β”‚ Adaptive β”‚ β”‚ Firestore β”‚ β”‚ V1: Gemini API β”‚ β”‚
19
+ β”‚ β”‚ Engine β”‚ β”‚ Database β”‚ β”‚ V2: Qwen2.5-3B SLM β”‚ β”‚
20
+ β”‚ β”‚ (Client JS) β”‚ β”‚ β”‚ β”‚ (HF Inference EP) β”‚ β”‚
21
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
22
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
23
+ ```
24
+
25
+ ---
26
+
27
+ ## 2. Component Architecture
28
+
29
+ ### 2.1 Frontend β€” React / Next.js Application
30
+
31
+ **Technology**: Next.js 14+ (App Router), TypeScript, Tailwind CSS
32
+ **Hosting**: Firebase Hosting or Vercel
33
+
34
+ #### Key Pages/Routes
35
+
36
+ | Route | Component | Purpose |
37
+ |---|---|---|
38
+ | `/` | `LandingPage` | Login/signup, language preference |
39
+ | `/dashboard` | `StudentDashboard` | Progress overview, session history, MCS/LDS charts |
40
+ | `/practice` | `PracticeSession` | Adaptive practice from question database |
41
+ | `/solve` | `CustomProblem` | "Input your question" β€” Gemini/SLM processes user-submitted problems |
42
+ | `/session-report` | `SessionReport` | End-of-session summary with performance analytics |
43
+
44
+ #### Core Frontend Components
45
+
46
+ ```
47
+ src/
48
+ β”œβ”€β”€ components/
49
+ β”‚ β”œβ”€β”€ ProblemDisplay/
50
+ β”‚ β”‚ β”œβ”€β”€ MathProblem.tsx # Renders word problem text
51
+ β”‚ β”‚ β”œβ”€β”€ HintScaffold.tsx # L1/L2/L3/L4 progressive hint UI
52
+ β”‚ β”‚ β”œβ”€β”€ AnswerInput.tsx # Numeric/expression answer entry
53
+ β”‚ β”‚ └── SolutionReveal.tsx # L4 step-by-step solution display
54
+ β”‚ β”œβ”€β”€ Adaptive/
55
+ β”‚ β”‚ β”œβ”€β”€ DifficultyIndicator.tsx # Visual current-level indicator
56
+ β”‚ β”‚ β”œβ”€β”€ ProgressBar.tsx # Session progress (e.g., 7/20)
57
+ β”‚ β”‚ └── SessionTimer.tsx # Time tracking per problem
58
+ β”‚ β”œβ”€β”€ Dashboard/
59
+ β”‚ β”‚ β”œβ”€β”€ EloChart.tsx # Elo rating over time (Recharts)
60
+ β”‚ β”‚ β”œβ”€β”€ TopicHeatmap.tsx # Performance by math topic
61
+ β”‚ β”‚ β”œβ”€β”€ LDSMCSPanel.tsx # Language Dependency & Math Confidence
62
+ β”‚ β”‚ └── StreakBadge.tsx # Gamification elements
63
+ β”‚ └── Shared/
64
+ β”‚ β”œβ”€β”€ BilingualToggle.tsx # EN/ES interface language switch
65
+ β”‚ β”œβ”€β”€ MathRenderer.tsx # KaTeX for math expressions
66
+ β”‚ └── LoadingSkeleton.tsx
67
+ β”œβ”€β”€ lib/
68
+ β”‚ β”œβ”€β”€ adaptive-engine.ts # Elo + BKT + Thompson Sampling (client-side)
69
+ β”‚ β”œβ”€β”€ feature-engineer.ts # LDS & MCS computation
70
+ β”‚ β”œβ”€β”€ firebase.ts # Firebase SDK initialization
71
+ β”‚ └── llm-client.ts # Gemini/SLM API abstraction
72
+ β”œβ”€β”€ hooks/
73
+ β”‚ β”œβ”€β”€ useAdaptiveSession.ts # Manages session state + engine calls
74
+ β”‚ β”œβ”€β”€ useStudentProfile.ts # Reads/writes Firestore student state
75
+ β”‚ └── useQuestionQueue.ts # Pre-fetches next batch of questions
76
+ └── types/
77
+ └── index.ts # TypeScript interfaces for all data structures
78
+ ```
79
+
80
+ #### Hint Scaffold UI Flow
81
+
82
+ ```
83
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€οΏ½οΏ½οΏ½β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
84
+ β”‚ Problem displayed in original β”‚
85
+ β”‚ English at student's current level β”‚
86
+ β”‚ β”‚
87
+ β”‚ [Try to solve] [I need a hint β†’] β”‚
88
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
89
+ β”‚ click
90
+ β–Ό
91
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
92
+ β”‚ L1: Simplified English β”‚
93
+ β”‚ "A store has 24 apples..." β”‚
94
+ β”‚ β”‚
95
+ β”‚ [Got it!] [Still stuck β†’] β”‚
96
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
97
+ β”‚ click
98
+ β–Ό
99
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
100
+ β”‚ L2: Bilingual Keywords Inline β”‚
101
+ β”‚ "A store has 24 apples (manzanas)" β”‚
102
+ β”‚ "divided equally (dividido β”‚
103
+ β”‚ igualmente) among 6 boxes" β”‚
104
+ β”‚ β”‚
105
+ β”‚ [Got it!] [Still stuck β†’] β”‚
106
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
107
+ β”‚ click
108
+ β–Ό
109
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
110
+ β”‚ L3: Full Spanish Translation β”‚
111
+ β”‚ "Una tienda tiene 24 manzanas β”‚
112
+ β”‚ divididas igualmente entre 6 β”‚
113
+ β”‚ cajas. ΒΏCuΓ‘ntas manzanas hay β”‚
114
+ β”‚ en cada caja?" β”‚
115
+ β”‚ β”‚
116
+ β”‚ [Got it!] [Show me the answer β†’] β”‚
117
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
118
+ β”‚ click
119
+ β–Ό
120
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
121
+ β”‚ L4: Step-by-Step Solution β”‚
122
+ β”‚ Step 1: Identify β€” 24 Γ· 6 β”‚
123
+ β”‚ Step 2: Calculate β€” 24 Γ· 6 = 4 β”‚
124
+ β”‚ Step 3: Answer β€” 4 apples per box β”‚
125
+ β”‚ β”‚
126
+ β”‚ [Next Problem β†’] β”‚
127
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
128
+ ```
129
+
130
+ Each hint interaction is logged with timestamp to compute `escalation_speed` and `scaffold_time_ratio` for the LDS formula.
131
+
132
+ ---
133
+
134
+ ### 2.2 Adaptive Engine (Client-Side JavaScript)
135
+
136
+ The adaptive engine runs **entirely in the browser** β€” no server round-trip needed for difficulty decisions. This ensures instant feedback and works offline after initial question batch load.
137
+
138
+ #### Engine Components
139
+
140
+ ```
141
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
142
+ β”‚ Adaptive Engine (client-side) β”‚
143
+ β”‚ β”‚
144
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
145
+ β”‚ β”‚ Elo Rating β”‚ β”‚ BKT β”‚ β”‚ Thompson β”‚ β”‚
146
+ β”‚ β”‚ System β”‚ β”‚ Engine β”‚ β”‚ Sampler β”‚ β”‚
147
+ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
148
+ β”‚ β”‚ Updates β”‚ β”‚ P(know) β”‚ β”‚ Beta prior β”‚ β”‚
149
+ β”‚ β”‚ student & β”‚ β”‚ per β”‚ β”‚ per level, β”‚ β”‚
150
+ β”‚ β”‚ question β”‚ β”‚ topic β”‚ β”‚ ZPD window β”‚ β”‚
151
+ β”‚ β”‚ ratings β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
152
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚
153
+ β”‚ β”‚ β”‚ β”‚ β”‚
154
+ β”‚ β–Ό β–Ό β–Ό β”‚
155
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
156
+ β”‚ β”‚ Decision Orchestrator β”‚ β”‚
157
+ β”‚ β”‚ β”‚ β”‚
158
+ β”‚ β”‚ Input: weighted_outcome, features β”‚ β”‚
159
+ β”‚ β”‚ Output: next_level, decision_type β”‚ β”‚
160
+ β”‚ β”‚ (increase/maintain/decrease) β”‚ β”‚
161
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
162
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
163
+ ```
164
+
165
+ #### Elo Update Formula
166
+
167
+ ```
168
+ weighted_outcome = {
169
+ no_hint: 1.00 (solved without any scaffold)
170
+ L1_only: 0.75 (needed simplified English)
171
+ L2_used: 0.50 (needed bilingual keywords)
172
+ L3_used: 0.25 (needed full translation)
173
+ L4_used: 0.00 (needed answer reveal)
174
+ }
175
+
176
+ E_student = 1 / (1 + 10^((R_question - R_student) / 400))
177
+ R_student_new = R_student + K Γ— (weighted_outcome - E_student)
178
+
179
+ K = 32 (default), increased to 48 for first 10 interactions (cold-start acceleration)
180
+ ```
181
+
182
+ #### BKT Parameters (per topic)
183
+
184
+ | Parameter | Symbol | Default | Description |
185
+ |---|---|---|---|
186
+ | Prior knowledge | P(Lβ‚€) | 0.10 | Initial probability student knows topic |
187
+ | Learn rate | P(T) | 0.15 | Probability of learning per opportunity |
188
+ | Slip | P(S) | 0.10 | Probability of incorrect despite knowing |
189
+ | Guess | P(G) | 0.25 | Probability of correct despite not knowing |
190
+
191
+ Slip is adjusted based on hint usage:
192
+ ```
193
+ P(S)_adjusted = P(S) Γ— (1 + 0.5 Γ— hint_depth_normalized)
194
+ ```
195
+ This models the intuition that using more scaffolds means apparent "correctness" is less certain.
196
+
197
+ #### Thompson Sampling with ZPD Windowing
198
+
199
+ ```
200
+ For each candidate level l in ZPD window [current - 2, current + 3]:
201
+ sample ΞΈ_l ~ Beta(Ξ±_l, Ξ²_l)
202
+ score_l = ΞΈ_l Γ— proximity_bonus(l, target_elo)
203
+
204
+ Select level = argmax(score_l)
205
+
206
+ proximity_bonus(l, target) = exp(-0.5 Γ— ((elo_l - target) / 100)Β²)
207
+ ```
208
+
209
+ ZPD window is asymmetric (+3 upward, -2 downward) to encourage upward progression while preventing catastrophic failure.
210
+
211
+ #### Progression Decision Rules
212
+
213
+ | Condition | Decision | Action |
214
+ |---|---|---|
215
+ | weighted_outcome β‰₯ 0.75 AND P(know) β‰₯ 0.70 | **Increase** | Move up 1 sub-level |
216
+ | weighted_outcome β‰₯ 0.85 AND streak β‰₯ 3 | **Skip** | Move up 2 sub-levels |
217
+ | 0.40 ≀ weighted_outcome < 0.75 | **Maintain** | Stay at current level |
218
+ | weighted_outcome < 0.40 OR streak_wrong β‰₯ 2 | **Decrease** | Move down 1 sub-level |
219
+ | weighted_outcome < 0.25 AND P(know) < 0.30 | **Rapid Decrease** | Move down 2 sub-levels |
220
+
221
+ ---
222
+
223
+ ### 2.3 Firebase Backend
224
+
225
+ **Services Used**:
226
+ - Firebase Authentication (Google Sign-In, Email/Password)
227
+ - Cloud Firestore (student state, question database, session logs)
228
+ - Cloud Functions (LLM API calls, batch question generation, session reports)
229
+ - Firebase Hosting (static frontend assets)
230
+
231
+ #### Firestore Data Model
232
+
233
+ ```
234
+ firestore/
235
+ β”œβ”€β”€ users/
236
+ β”‚ └── {uid}/
237
+ β”‚ β”œβ”€β”€ profile: {
238
+ β”‚ β”‚ displayName, email, gradeLevel, preferredLanguage,
239
+ β”‚ β”‚ createdAt, lastActive
240
+ β”‚ β”‚ }
241
+ β”‚ β”œβ”€β”€ adaptiveState: {
242
+ β”‚ β”‚ currentElo: number, // e.g., 1050
243
+ β”‚ β”‚ currentLevel: string, // e.g., "2.1"
244
+ β”‚ β”‚ totalInteractions: number,
245
+ β”‚ β”‚ topicMastery: { // BKT P(know) per topic
246
+ β”‚ β”‚ "arithmetic": 0.72,
247
+ β”‚ β”‚ "fractions": 0.45,
248
+ β”‚ β”‚ "algebra_basic": 0.31,
249
+ β”‚ β”‚ ...
250
+ β”‚ β”‚ },
251
+ β”‚ β”‚ thompsonPriors: { // Beta(Ξ±,Ξ²) per level
252
+ β”‚ β”‚ "1.1": { alpha: 12, beta: 3 },
253
+ β”‚ β”‚ "1.2": { alpha: 8, beta: 5 },
254
+ β”‚ β”‚ ...
255
+ β”‚ β”‚ },
256
+ β”‚ β”‚ featureAverages: {
257
+ β”‚ β”‚ avgLDS: 0.42,
258
+ β”‚ β”‚ avgMCS: 0.61,
259
+ β”‚ β”‚ recentLDS_5: [0.3, 0.4, 0.5, 0.35, 0.45],
260
+ β”‚ β”‚ recentMCS_5: [0.6, 0.65, 0.58, 0.62, 0.7]
261
+ β”‚ β”‚ },
262
+ β”‚ β”‚ streakCount: number,
263
+ β”‚ β”‚ lastUpdated: timestamp
264
+ β”‚ β”‚ }
265
+ β”‚ └── sessions/
266
+ β”‚ └── {sessionId}/
267
+ β”‚ β”œβ”€β”€ metadata: {
268
+ β”‚ β”‚ startTime, endTime, questionsAttempted,
269
+ β”‚ β”‚ questionsCorrect, avgWeightedOutcome,
270
+ β”‚ β”‚ startElo, endElo, sessionLDS, sessionMCS
271
+ β”‚ β”‚ }
272
+ β”‚ └── interactions/
273
+ β”‚ └── {interactionId}: {
274
+ β”‚ questionId, level, topic,
275
+ β”‚ startTime, endTime, timeSpentMs,
276
+ β”‚ hintsUsed: [0,1,2,3,4], // which levels accessed
277
+ β”‚ hintTimestamps: { L1: ts, L2: ts, ... },
278
+ β”‚ maxHintLevel: number,
279
+ β”‚ answer: string,
280
+ β”‚ isCorrect: boolean,
281
+ β”‚ attempts: number,
282
+ β”‚ weightedOutcome: number,
283
+ β”‚ lds: number,
284
+ β”‚ mcs: number,
285
+ β”‚ eloBeforeUpdate: number,
286
+ β”‚ eloAfterUpdate: number,
287
+ β”‚ adaptiveDecision: string
288
+ β”‚ }
289
+ β”‚
290
+ β”œβ”€β”€ questions/
291
+ β”‚ └── {questionId}: {
292
+ β”‚ id, level, topic, subtopic,
293
+ β”‚ problemText, answer, answerNumeric,
294
+ β”‚ solutionSteps: [...],
295
+ β”‚ scaffolds: {
296
+ β”‚ L1_simplified: string,
297
+ β”‚ L2_bilingual: string,
298
+ β”‚ L3_spanish: string,
299
+ β”‚ L4_solution: string
300
+ β”‚ },
301
+ β”‚ readability: {
302
+ β”‚ fleschKincaid: number,
303
+ β”‚ wordCount: number,
304
+ β”‚ difficultWords: number,
305
+ β”‚ avgSyllables: number
306
+ β”‚ },
307
+ β”‚ eloRating: number,
308
+ β”‚ timesServed: number,
309
+ β”‚ avgOutcome: number,
310
+ β”‚ metadata: {
311
+ β”‚ source: "curated" | "generated",
312
+ β”‚ generatedBy: "gemini-2.0" | "qwen2.5-3b" | null,
313
+ β”‚ reviewedBy: string | null,
314
+ β”‚ createdAt: timestamp
315
+ β”‚ }
316
+ β”‚ }
317
+ β”‚
318
+ β”œβ”€β”€ questionIndex/ // Denormalized for fast queries
319
+ β”‚ └── byLevel/
320
+ β”‚ └── {level}: {
321
+ β”‚ questionIds: [...],
322
+ β”‚ count: number
323
+ β”‚ }
324
+ β”‚
325
+ └── analytics/ // Aggregated (Cloud Functions)
326
+ β”œβ”€β”€ dailyStats/
327
+ β”‚ └── {date}: { activeUsers, sessionsCompleted, ... }
328
+ └── cohortProgress/
329
+ └── {cohortId}: { avgElo, avgLDS, avgMCS, ... }
330
+ ```
331
+
332
+ #### Firestore Security Rules
333
+
334
+ ```javascript
335
+ rules_version = '2';
336
+ service cloud.firestore {
337
+ match /databases/{database}/documents {
338
+ // Users can only read/write their own data
339
+ match /users/{uid}/{document=**} {
340
+ allow read, write: if request.auth != null && request.auth.uid == uid;
341
+ }
342
+ // Questions are readable by all authenticated users
343
+ match /questions/{questionId} {
344
+ allow read: if request.auth != null;
345
+ allow write: if false; // Only admin/Cloud Functions
346
+ }
347
+ // Question index readable by all authenticated users
348
+ match /questionIndex/{document=**} {
349
+ allow read: if request.auth != null;
350
+ allow write: if false;
351
+ }
352
+ // Analytics only accessible by admin
353
+ match /analytics/{document=**} {
354
+ allow read, write: if false; // Cloud Functions only
355
+ }
356
+ }
357
+ }
358
+ ```
359
+
360
+ ---
361
+
362
+ ### 2.4 Cloud Functions (Serverless Backend)
363
+
364
+ ```
365
+ functions/
366
+ β”œβ”€β”€ onUserCreate.ts # Initialize adaptive state for new user
367
+ β”œβ”€β”€ generateScaffolds.ts # Call Gemini/SLM to create L1-L4 for a problem
368
+ β”œβ”€β”€ batchGenerateQuestions.ts # Generate next 20 questions for session queue
369
+ β”œβ”€β”€ processCustomProblem.ts # "Input your question" flow
370
+ β”œβ”€β”€ generateSessionReport.ts # End-of-session analytics
371
+ β”œβ”€β”€ updateQuestionStats.ts # Update question difficulty from outcomes
372
+ └── scheduledAnalytics.ts # Daily aggregation (cron-triggered)
373
+ ```
374
+
375
+ #### Key Cloud Function: `generateScaffolds`
376
+
377
+ ```typescript
378
+ // Triggered when student submits a custom problem or when
379
+ // pre-generating scaffolds for database questions
380
+
381
+ interface ScaffoldRequest {
382
+ problemText: string;
383
+ studentGradeLevel: number;
384
+ currentLDS: number; // Informs simplification level
385
+ }
386
+
387
+ interface ScaffoldResponse {
388
+ L1_simplified: string; // Simplified English
389
+ L2_bilingual: string; // English with inline Spanish keywords
390
+ L3_spanish: string; // Full Spanish translation
391
+ L4_solution: string; // Step-by-step solution
392
+ answer: string;
393
+ answerNumeric: number;
394
+ }
395
+
396
+ // Prompt template for LLM
397
+ const SCAFFOLD_PROMPT = `
398
+ You are a bilingual math tutor helping Spanish-speaking students
399
+ (grades 6-8) learn math in English.
400
+
401
+ Given this math word problem:
402
+ "{problemText}"
403
+
404
+ Generate 4 scaffold levels:
405
+
406
+ **L1 (Simplified English):** Rewrite using shorter sentences,
407
+ simpler vocabulary (grade {adjustedGrade} reading level).
408
+ Keep all math content identical.
409
+
410
+ **L2 (Bilingual Keywords):** Take the original problem and add
411
+ Spanish translations in parentheses for key math and context
412
+ vocabulary. Format: "English word (palabra en espaΓ±ol)".
413
+
414
+ **L3 (Full Spanish Translation):** Translate the complete problem
415
+ to natural, grade-appropriate Spanish. Ensure mathematical
416
+ precision is maintained.
417
+
418
+ **L4 (Step-by-Step Solution):** Provide a clear, numbered
419
+ step-by-step solution in English with the final numerical answer.
420
+
421
+ Return as JSON with keys: L1_simplified, L2_bilingual, L3_spanish,
422
+ L4_solution, answer, answerNumeric.
423
+ `;
424
+ ```
425
+
426
+ #### Key Cloud Function: `batchGenerateQuestions`
427
+
428
+ ```typescript
429
+ // Called when student reaches question 17 of 20 (prefetch trigger)
430
+ // Selects next 20 questions from database based on adaptive state
431
+
432
+ export const batchGenerateQuestions = onCall(async (request) => {
433
+ const { uid } = request.auth;
434
+ const state = await getAdaptiveState(uid);
435
+
436
+ // Thompson Sampling selects level distribution for next batch
437
+ const levelDistribution = thompsonSampleBatch(
438
+ state.thompsonPriors,
439
+ state.currentLevel,
440
+ batchSize: 20
441
+ );
442
+ // e.g., { "2.1": 5, "2.2": 8, "2.3": 5, "2.4": 2 }
443
+
444
+ // Select questions avoiding recently served ones
445
+ const recentIds = await getRecentQuestionIds(uid, lookback: 100);
446
+ const questions = await selectQuestions(
447
+ levelDistribution,
448
+ excludeIds: recentIds,
449
+ topicBalance: state.topicMastery // Favor weaker topics
450
+ );
451
+
452
+ // Ensure all questions have scaffolds generated
453
+ const withScaffolds = await ensureScaffoldsGenerated(questions);
454
+
455
+ return { questions: withScaffolds, sessionBatchId: generateId() };
456
+ });
457
+ ```
458
+
459
+ ---
460
+
461
+ ### 2.5 LLM Service Layer
462
+
463
+ #### V1: Gemini API (Current)
464
+
465
+ ```
466
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” HTTPS/REST β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
467
+ β”‚ Cloud β”‚ ──────────────────►│ Google Gemini β”‚
468
+ β”‚ Function β”‚ ◄──────────────────│ 2.0 Flash API β”‚
469
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
470
+
471
+ Cost: ~$0.075 per 1M input tokens, ~$0.30 per 1M output tokens
472
+ Latency: 200-800ms per scaffold generation
473
+ Rate limit: 60 RPM (free tier), 1000 RPM (paid)
474
+ ```
475
+
476
+ #### V2: Qwen2.5-3B SLM (Planned)
477
+
478
+ ```
479
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” HTTPS/REST β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
480
+ β”‚ Cloud β”‚ ──────────────────►│ HF Inference Endpoint β”‚
481
+ β”‚ Function β”‚ ◄──────────────────│ Qwen2.5-3B-Instruct β”‚
482
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ (QLoRA fine-tuned) β”‚
483
+ β”‚ GPU: T4 or L4 β”‚
484
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
485
+
486
+ Cost: ~$0.60/hr (T4) or ~$1.04/hr (L4)
487
+ Latency: 100-400ms per scaffold generation
488
+ Rate limit: Unlimited (dedicated endpoint)
489
+ ```
490
+
491
+ #### LLM Client Abstraction
492
+
493
+ ```typescript
494
+ // lib/llm-client.ts β€” Provider-agnostic interface
495
+
496
+ interface LLMProvider {
497
+ generateScaffolds(problem: string, context: ScaffoldContext): Promise<ScaffoldResponse>;
498
+ generateQuestion(level: string, topic: string): Promise<QuestionWithScaffolds>;
499
+ validateAnswer(problem: string, studentAnswer: string, correctAnswer: string): Promise<AnswerValidation>;
500
+ }
501
+
502
+ class GeminiProvider implements LLMProvider { ... }
503
+ class QwenSLMProvider implements LLMProvider { ... }
504
+
505
+ // Factory with fallback
506
+ function createLLMClient(): LLMProvider {
507
+ if (config.useSLM && config.slmEndpointAvailable) {
508
+ return new QwenSLMProvider(config.slmEndpoint);
509
+ }
510
+ return new GeminiProvider(config.geminiApiKey);
511
+ }
512
+ ```
513
+
514
+ ---
515
+
516
+ ### 2.6 SLM Fine-Tuning Pipeline
517
+
518
+ ```
519
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
520
+ β”‚ Training β”‚ β”‚ Fine-Tune β”‚ β”‚ Deploy β”‚
521
+ β”‚ Data Prep │───►│ QLoRA SFT │───►│ HF Inference EP β”‚
522
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
523
+
524
+ Step 1: Collect 2,000-5,000 scaffold examples from Gemini V1 usage
525
+ Step 2: Human review + quality filter β†’ ~1,500 gold examples
526
+ Step 3: QLoRA fine-tune Qwen2.5-3B-Instruct
527
+ Step 4: Evaluate on held-out test set (BLEU, math accuracy, readability)
528
+ Step 5: Deploy to HF Inference Endpoint
529
+ Step 6: Shadow-test alongside Gemini (serve both, compare quality)
530
+ Step 7: Full cutover when SLM matches Gemini quality
531
+ ```
532
+
533
+ **Fine-tuning Configuration:**
534
+
535
+ | Parameter | Value | Rationale |
536
+ |---|---|---|
537
+ | Base model | Qwen2.5-3B-Instruct | Best math+Spanish at 3B scale |
538
+ | Method | QLoRA (4-bit NF4) | Fits single 16GB GPU |
539
+ | LoRA rank (r) | 32 | Balance quality/efficiency for small dataset |
540
+ | LoRA alpha | 64 | Standard 2Γ— rank |
541
+ | Target modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj | Full attention + MLP |
542
+ | Learning rate | 2e-4 | Standard for QLoRA |
543
+ | Epochs | 3-5 | Small dataset, monitor val loss |
544
+ | Batch size | 4 (effective 16 with grad accum) | Memory constraint |
545
+ | Max sequence length | 1024 | Sufficient for problem + all 4 scaffolds |
546
+ | Warmup ratio | 0.05 | Short warmup for small dataset |
547
+
548
+ ---
549
+
550
+ ## 3. Data Flow Diagrams
551
+
552
+ ### 3.1 Flow A: "Practice Problems" Mode
553
+
554
+ ```
555
+ Student clicks "Start Practice"
556
+ β”‚
557
+ β–Ό
558
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
559
+ β”‚ 1. Load adaptive state from β”‚
560
+ β”‚ Firestore (Elo, BKT, priors) β”‚
561
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
562
+ β”‚
563
+ β–Ό
564
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
565
+ β”‚ 2. Thompson Sampling selects β”‚
566
+ β”‚ next question level β”‚
567
+ β”‚ (ZPD window: current Β±2/+3) β”‚
568
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
569
+ β”‚
570
+ β–Ό
571
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
572
+ β”‚ 3. Fetch question from Firestoreβ”‚
573
+ β”‚ by level + topic balancing β”‚
574
+ β”‚ (avoid recently served) β”‚
575
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
576
+ β”‚
577
+ β–Ό
578
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
579
+ β”‚ 4. Display problem, start timer β”‚
580
+ β”‚ Student reads and attempts β”‚
581
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
582
+ β”‚
583
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
584
+ β”‚ Needs hints? β”‚
585
+ β–Ό No β–Ό Yes
586
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
587
+ β”‚ Submit β”‚ β”‚ L1 β†’ L2 β†’ L3 β†’ L4β”‚
588
+ β”‚ answer β”‚ β”‚ (each click logged β”‚
589
+ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β”‚ with timestamp) β”‚
590
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
591
+ β”‚ β”‚
592
+ β–Ό β–Ό
593
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
594
+ β”‚ 5. Compute weighted_outcome β”‚
595
+ β”‚ based on correctness + hints β”‚
596
+ β”‚ Compute LDS and MCS β”‚
597
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
598
+ β”‚
599
+ β–Ό
600
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
601
+ β”‚ 6. Update Elo (student + Q) β”‚
602
+ β”‚ Update BKT P(know) for topic β”‚
603
+ β”‚ Update Thompson Beta priors β”‚
604
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
605
+ β”‚
606
+ β–Ό
607
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
608
+ β”‚ 7. Progression decision: β”‚
609
+ β”‚ increase / maintain / decreaseβ”‚
610
+ β”‚ Select next level β”‚
611
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
612
+ β”‚
613
+ β–Ό
614
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
615
+ β”‚ 8. Save interaction to Firestoreβ”‚
616
+ β”‚ Display "Next Problem" β”‚
617
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
618
+ β”‚
619
+ β–Ό
620
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
621
+ β”‚ Q17 of 20? β”‚
622
+ β–Ό Yes β–Ό No
623
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
624
+ β”‚ Prefetch β”‚ β”‚ Loop to β”‚
625
+ β”‚ next batch β”‚ β”‚ step 2 β”‚
626
+ β”‚ (Cloud Fn) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
627
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
628
+ β”‚
629
+ At Q20: β–Ό
630
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
631
+ β”‚ 9. Generate session report β”‚
632
+ β”‚ (Cloud Function) β”‚
633
+ β”‚ Show summary to student β”‚
634
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
635
+ ```
636
+
637
+ ### 3.2 Flow B: "Input Your Question" Mode
638
+
639
+ ```
640
+ Student types/pastes a math word problem
641
+ β”‚
642
+ β–Ό
643
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
644
+ β”‚ 1. Cloud Function: β”‚
645
+ β”‚ processCustomProblem β”‚
646
+ β”‚ - Validate it's a math β”‚
647
+ β”‚ word problem β”‚
648
+ β”‚ - Extract answer/solution β”‚
649
+ β”‚ - Call Gemini/SLM to generateβ”‚
650
+ β”‚ L1, L2, L3, L4 scaffolds β”‚
651
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
652
+ β”‚
653
+ β–Ό
654
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
655
+ β”‚ 2. Estimate difficulty level β”‚
656
+ β”‚ using readability metrics β”‚
657
+ β”‚ (FK grade, word count, etc.) β”‚
658
+ β”‚ Map to nearest Elo rating β”‚
659
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
660
+ β”‚
661
+ β–Ό
662
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
663
+ β”‚ 3. Display problem with β”‚
664
+ β”‚ scaffold buttons active β”‚
665
+ β”‚ (same UI as Practice mode) β”‚
666
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
667
+ β”‚
668
+ β–Ό
669
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
670
+ β”‚ 4. Student interacts, solves β”‚
671
+ β”‚ Same hint tracking as β”‚
672
+ β”‚ Practice mode β”‚
673
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
674
+ β”‚
675
+ β–Ό
676
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
677
+ β”‚ 5. Update adaptive state β”‚
678
+ β”‚ (Elo, BKT, Thompson) β”‚
679
+ β”‚ Log interaction β”‚
680
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
681
+ β”‚
682
+ β–Ό
683
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
684
+ β”‚ 6. Offer: "Try another?" or β”‚
685
+ β”‚ "Switch to Practice Mode" β”‚
686
+ β”‚ (where engine auto-selects) β”‚
687
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
688
+ ```
689
+
690
+ ---
691
+
692
+ ## 4. API Contracts
693
+
694
+ ### 4.1 Client β†’ Cloud Functions
695
+
696
+ ```typescript
697
+ // POST /generateScaffolds
698
+ interface GenerateScaffoldsRequest {
699
+ problemText: string;
700
+ gradeLevel: number; // 6, 7, or 8
701
+ currentLDS: number; // 0.0-1.0, informs simplification
702
+ }
703
+ interface GenerateScaffoldsResponse {
704
+ scaffolds: {
705
+ L1_simplified: string;
706
+ L2_bilingual: string;
707
+ L3_spanish: string;
708
+ L4_solution: string;
709
+ };
710
+ answer: string;
711
+ answerNumeric: number;
712
+ estimatedLevel: string; // e.g., "2.3"
713
+ estimatedElo: number; // e.g., 1100
714
+ processingTimeMs: number;
715
+ }
716
+
717
+ // POST /batchGenerateQuestions
718
+ interface BatchRequest {
719
+ batchSize: number; // default 20
720
+ // Auth token provides uid β†’ adaptive state looked up server-side
721
+ }
722
+ interface BatchResponse {
723
+ questions: QuestionWithScaffolds[];
724
+ sessionBatchId: string;
725
+ }
726
+
727
+ // POST /submitInteraction
728
+ interface InteractionSubmission {
729
+ sessionId: string;
730
+ questionId: string;
731
+ answer: string;
732
+ isCorrect: boolean;
733
+ timeSpentMs: number;
734
+ hintsUsed: number[]; // [0], [0,1], [0,1,2], etc.
735
+ hintTimestamps: Record<string, number>;
736
+ attempts: number;
737
+ }
738
+ interface InteractionResponse {
739
+ weightedOutcome: number;
740
+ lds: number;
741
+ mcs: number;
742
+ newElo: number;
743
+ newLevel: string;
744
+ decision: "increase" | "maintain" | "decrease" | "skip" | "rapid_decrease";
745
+ nextQuestion: QuestionWithScaffolds; // Pre-selected
746
+ }
747
+
748
+ // POST /generateSessionReport
749
+ interface SessionReportRequest {
750
+ sessionId: string;
751
+ }
752
+ interface SessionReportResponse {
753
+ summary: {
754
+ questionsAttempted: number;
755
+ questionsCorrect: number;
756
+ avgWeightedOutcome: number;
757
+ eloChange: number;
758
+ topicsStrong: string[];
759
+ topicsWeak: string[];
760
+ avgLDS: number;
761
+ avgMCS: number;
762
+ languageProgressNote: string; // Generated text about L2 progress
763
+ };
764
+ recommendations: string[]; // e.g., "Focus on fractions vocabulary"
765
+ }
766
+ ```
767
+
768
+ ---
769
+
770
+ ## 5. Deployment Architecture
771
+
772
+ ### 5.1 V1 Deployment (MVP)
773
+
774
+ ```
775
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
776
+ β”‚ Firebase Project β”‚
777
+ β”‚ β”‚
778
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
779
+ β”‚ β”‚ Firebase β”‚ β”‚ Cloud β”‚ β”‚ Cloud β”‚ β”‚
780
+ β”‚ β”‚ Hosting β”‚ β”‚ Firestore β”‚ β”‚ Functions β”‚ β”‚
781
+ β”‚ β”‚ (Next.js) β”‚ β”‚ (Database) β”‚ β”‚ (Node.js 20) β”‚ β”‚
782
+ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
783
+ β”‚ β”‚ Static + β”‚ β”‚ Student β”‚ β”‚ LLM calls β”‚ β”‚
784
+ β”‚ β”‚ SSR pages β”‚ β”‚ state, β”‚ β”‚ Batch gen β”‚ β”‚
785
+ β”‚ β”‚ β”‚ β”‚ questions, β”‚ β”‚ Reports β”‚ β”‚
786
+ β”‚ β”‚ β”‚ β”‚ sessions β”‚ β”‚ β”‚ β”‚
787
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
788
+ β”‚ β”‚ β”‚
789
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
790
+ β”‚
791
+ HTTPS β”‚
792
+ β–Ό
793
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
794
+ β”‚ Google Gemini β”‚
795
+ β”‚ 2.0 Flash API β”‚
796
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
797
+
798
+ Estimated monthly cost (100 students, 5 sessions/week):
799
+ - Firebase Hosting: Free tier (~$0)
800
+ - Firestore: ~$5/mo (reads/writes within free tier mostly)
801
+ - Cloud Functions: ~$10/mo (invocations + compute)
802
+ - Gemini API: ~$15-25/mo (scaffold generation)
803
+ - Total: ~$30-40/mo
804
+ ```
805
+
806
+ ### 5.2 V2 Deployment (SLM)
807
+
808
+ ```
809
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
810
+ β”‚ Firebase Project β”‚
811
+ β”‚ β”‚
812
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
813
+ β”‚ β”‚ Firebase β”‚ β”‚ Cloud β”‚ β”‚ Cloud β”‚ β”‚
814
+ β”‚ β”‚ Hosting β”‚ β”‚ Firestore β”‚ β”‚ Functions β”‚ β”‚
815
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
816
+ β”‚ β”‚ β”‚
817
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
818
+ β”‚
819
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
820
+ β”‚ β”‚ β”‚
821
+ β–Ό β–Ό β”‚
822
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
823
+ β”‚ HF Inference β”‚ β”‚ Gemini API β”‚ β”‚
824
+ β”‚ Endpoint β”‚ β”‚ (fallback) β”‚ β”‚
825
+ β”‚ Qwen2.5-3B β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
826
+ β”‚ QLoRA FT β”‚ β”‚
827
+ β”‚ (T4 GPU) β”‚ Shadow testing: β”‚
828
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Both called, SLM β”‚
829
+ response served, β”‚
830
+ Gemini response β”‚
831
+ logged for QA β”‚
832
+ β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
833
+
834
+ Estimated monthly cost (100 students):
835
+ - Firebase: ~$15/mo (same as V1)
836
+ - HF Inference Endpoint (T4, scale-to-zero): ~$50-100/mo
837
+ (active only during school hours, ~8hrs/day Γ— 20 days)
838
+ - Gemini fallback: ~$5/mo (only when SLM is cold)
839
+ - Total: ~$70-120/mo (but no per-token costs at scale)
840
+ ```
841
+
842
+ ### 5.3 V3 Deployment (Scale)
843
+
844
+ ```
845
+ When student count exceeds 500+, migrate to:
846
+
847
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
848
+ β”‚ β”‚
849
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
850
+ β”‚ β”‚ Vercel β”‚ β”‚ Firebase β”‚ β”‚ Cloud Run β”‚ β”‚
851
+ β”‚ β”‚ (Next.js) β”‚ β”‚ Firestore β”‚ β”‚ (API server) β”‚ β”‚
852
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
853
+ β”‚ β”‚ β”‚
854
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β” β”‚
855
+ β”‚ β”‚ β”‚ β”‚ β”‚
856
+ β”‚ β–Ό β–Ό β”‚ β”‚
857
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
858
+ β”‚ β”‚ HF Inference EP β”‚ β”‚ IRT/DKT Model β”‚ β”‚ β”‚
859
+ β”‚ β”‚ Qwen2.5-3B β”‚ β”‚ Server β”‚ β”‚ β”‚
860
+ β”‚ β”‚ (Auto-scaling) β”‚ β”‚ (Python/FastAPI)β”‚ β”‚ β”‚
861
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
862
+ β”‚ β”‚ β”‚
863
+ β”‚ + Deep Knowledge Tracing (DKT) replaces BKT β”‚ β”‚
864
+ β”‚ + IRT item calibration from pooled student data β”‚ β”‚
865
+ β”‚ + A/B testing framework for algorithm improvements β”‚ β”‚
866
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
867
+ ```
868
+
869
+ ---
870
+
871
+ ## 6. Technology Stack Summary
872
+
873
+ | Layer | Technology | Justification |
874
+ |---|---|---|
875
+ | Frontend Framework | Next.js 14+ (App Router) | SSR for SEO, React ecosystem, TypeScript |
876
+ | UI Styling | Tailwind CSS + shadcn/ui | Rapid prototyping, consistent design |
877
+ | Math Rendering | KaTeX | Fast client-side LaTeX rendering |
878
+ | Charts | Recharts | React-native charting for dashboards |
879
+ | Authentication | Firebase Auth | Google Sign-In, simple integration |
880
+ | Database | Cloud Firestore | Real-time sync, offline support, serverless |
881
+ | Serverless Functions | Firebase Cloud Functions (Node.js 20) | Low latency, Firebase integration |
882
+ | LLM (V1) | Google Gemini 2.0 Flash | Low cost, fast, good multilingual |
883
+ | SLM (V2) | Qwen2.5-3B-Instruct (QLoRA fine-tuned) | Best math+Spanish at 3B, Apache 2.0 |
884
+ | SLM Hosting | HF Inference Endpoints (T4, scale-to-zero) | Cost-effective, no infra management |
885
+ | Adaptive Engine | Client-side TypeScript | Zero-latency decisions, works offline |
886
+ | State Management | Zustand + Firestore sync | Lightweight, persists across sessions |
887
+ | Testing | Vitest + Playwright | Unit + E2E testing |
888
+ | CI/CD | GitHub Actions | Automated testing + Firebase deploy |
889
+ | Monitoring | Firebase Analytics + Crashlytics | User behavior + error tracking |
890
+
891
+ ---
892
+
893
+ ## 7. Security & Privacy Considerations
894
+
895
+ ### 7.1 Data Protection
896
+ - **COPPA Compliance**: Students are minors (ages 11-14). No personally identifiable information stored beyond email/display name. No third-party tracking.
897
+ - **FERPA Alignment**: Performance data (Elo, LDS, MCS) is associated with uid only. Teachers/admins see aggregate data, never individual student identifiers.
898
+ - **Data Encryption**: Firestore encrypts at rest (AES-256). All API calls over HTTPS/TLS 1.3.
899
+
900
+ ### 7.2 API Security
901
+ - Firebase Auth tokens required for all Cloud Function calls
902
+ - Gemini/SLM API keys stored in Firebase environment secrets (never client-side)
903
+ - Rate limiting on Cloud Functions to prevent abuse (max 10 scaffold generations per minute per user)
904
+
905
+ ### 7.3 Content Safety
906
+ - All LLM-generated scaffolds pass through a validation function checking:
907
+ - Mathematical accuracy (answer matches expected)
908
+ - Appropriate content (no adult/violent themes)
909
+ - Language accuracy (Spanish translation verified against expected pattern)
910
+ - Questions from the curated database are pre-reviewed; generated questions flagged for human review
911
+
912
+ ---
913
+
914
+ ## 8. Performance Targets
915
+
916
+ | Metric | Target | Measurement |
917
+ |---|---|---|
918
+ | Time to first problem display | < 2 seconds | Lighthouse / Firebase Performance |
919
+ | Adaptive decision latency | < 50ms | Client-side (no network) |
920
+ | Scaffold generation (Gemini) | < 1.5 seconds | Cloud Function logs |
921
+ | Scaffold generation (SLM) | < 800ms | HF Inference EP metrics |
922
+ | Batch prefetch trigger β†’ ready | < 5 seconds | 20 questions fetched at Q17 |
923
+ | Offline capability | Full session | After initial batch load |
924
+ | Concurrent users (V1) | 50 | Firebase free/Blaze tier |
925
+ | Concurrent users (V2) | 500+ | HF auto-scaling endpoint |