1241 lines
59 KiB
Markdown
1241 lines
59 KiB
Markdown
# Daily Practice System
|
||
|
||
> Architecture and implementation plan for the structured daily practice system.
|
||
|
||
## Overview
|
||
|
||
This document outlines the plan to implement a structured daily practice system following the traditional Japanese soroban teaching methodology. The curriculum follows the order used in physical abacus workbooks.
|
||
|
||
## Book's Teaching Order
|
||
|
||
The workbooks teach in this specific order:
|
||
|
||
### Level 1: No Regrouping (Single Column Operations)
|
||
|
||
Operations that don't require carrying/borrowing across columns.
|
||
|
||
**Addition (+1 through +9)**
|
||
For each number, practice in this order:
|
||
|
||
1. **Without friends of 5**: Direct bead movements only
|
||
- e.g., `2 + 1 = 3` (just move earth beads)
|
||
2. **With friends of 5**: Using the 5-complement technique
|
||
- e.g., `3 + 4 = 7` → needs `+5, -1`
|
||
|
||
**Subtraction (-9 through -1)**
|
||
For each number, practice in this order:
|
||
|
||
1. **Without friends of 5**: Direct bead movements only
|
||
- e.g., `7 - 2 = 5` (just remove earth beads)
|
||
2. **With friends of 5**: Using the 5-complement technique
|
||
- e.g., `6 - 4 = 2` → needs `-5, +1`
|
||
|
||
### Level 2: Addition with Regrouping (Friends of 10)
|
||
|
||
Addition that requires carrying to the next column.
|
||
|
||
**Addition (+1 through +9)**
|
||
For each number:
|
||
|
||
1. **Without friends of 5**: Pure 10-complement
|
||
- e.g., `5 + 7 = 12` → needs `-3, +10` (no 5-bead manipulation in ones)
|
||
2. **With friends of 5**: Combined 10-complement and 5-complement
|
||
- e.g., `9 + 6 = 15` → needs `+10, -5, +1`
|
||
|
||
### Level 3: Subtraction with Regrouping (Friends of 10)
|
||
|
||
Subtraction that requires borrowing from the next column.
|
||
|
||
**Subtraction (-9 through -1)**
|
||
For each number:
|
||
|
||
1. **Without friends of 5**: Pure 10-complement
|
||
- e.g., `12 - 7 = 5` → needs `+3, -10`
|
||
2. **With friends of 5**: Combined 10-complement and 5-complement
|
||
- e.g., `15 - 6 = 9` → needs `-10, +5, -1`
|
||
|
||
## Problem Format
|
||
|
||
- **Multi-term sequences** (3-7 terms): `12 + 45 + 23 + 67 + 8 = ?`
|
||
- **Double-digit from the start**: The books don't start with single-digit only
|
||
- **Visualization starts Level 1**: Once mechanics are familiar, practice without abacus visible
|
||
|
||
## Existing Infrastructure
|
||
|
||
### What We Have
|
||
|
||
| Component | Location | Can Leverage |
|
||
| ----------------- | --------------------------------------------------- | ----------------------- |
|
||
| Problem generator | `src/utils/problemGenerator.ts` | ✅ Core logic exists |
|
||
| Skill analysis | `analyzeColumnAddition()` | ✅ Pattern to follow |
|
||
| SkillSet types | `src/types/tutorial.ts` | ✅ Has 5/10 complements |
|
||
| Practice player | `src/components/tutorial/PracticeProblemPlayer.tsx` | ✅ UI exists |
|
||
| Constraint system | `allowedSkills`, `targetSkills`, `forbiddenSkills` | ✅ Ready to use |
|
||
|
||
### What We Need to Add
|
||
|
||
| Feature | Description | File(s) to Modify | Status |
|
||
| -------------------------- | --------------------------------------- | ------------------------------- | ---------- |
|
||
| Subtraction skill analysis | `analyzeColumnSubtraction()` | `src/utils/problemGenerator.ts` | ✅ Done |
|
||
| Subtraction in SkillSet | Add subtraction-specific skills | `src/types/tutorial.ts` | ✅ Done |
|
||
| Curriculum definitions | Level 1/2/3 PracticeStep configs | New: `src/curriculum/` | ⏳ Pending |
|
||
| Visualization mode | Hide abacus option | `PracticeProblemPlayer.tsx` | ⏳ Pending |
|
||
| Adaptive mastery | Continue until N consecutive correct | New logic | ⏳ Pending |
|
||
| Progress persistence | Track technique mastery | Database/localStorage | ⏳ Pending |
|
||
| **Student profiles** | Extend players with curriculum progress | New DB tables | ✅ Done |
|
||
| **Student selection UI** | Pick student before practice | `src/components/practice/` | ✅ Done |
|
||
|
||
## Student Progress Architecture
|
||
|
||
### Design Decision: Players ARE Students
|
||
|
||
Rather than creating a separate "student" concept, we extend the existing **arcade player system**:
|
||
|
||
- **Players already have identity** - name, emoji, color (kid-friendly!)
|
||
- **Players are scoped to users** - supports multiple kids per parent account
|
||
- **Active/inactive concept** - can select which student is practicing
|
||
- **Guest-friendly** - works without auth via `guestId`
|
||
- **Stats infrastructure exists** - `player_stats` with per-game JSON breakdown
|
||
|
||
This means a child's avatar in arcade games is the same avatar they use for practice - unified experience.
|
||
|
||
### Database Schema Extension
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ EXISTING │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ players │ player_stats │
|
||
│ ├── id │ ├── playerId (PK, FK) │
|
||
│ ├── userId (FK) │ ├── gamesPlayed │
|
||
│ ├── name │ ├── gameStats (JSON) │
|
||
│ ├── emoji │ └── ... │
|
||
│ ├── color │ │
|
||
│ └── isActive │ │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ NEW TABLES │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ player_curriculum │ player_skill_mastery │
|
||
│ ├── playerId (PK, FK) │ ├── id (PK) │
|
||
│ ├── currentLevel (1,2,3) │ ├── playerId (FK) │
|
||
│ ├── currentPhaseId │ ├── skillId │
|
||
│ ├── worksheetPreset │ ├── attempts │
|
||
│ ├── visualizationMode │ ├── correct │
|
||
│ └── updatedAt │ ├── consecutiveCorrect │
|
||
│ │ ├── masteryLevel │
|
||
│ practice_sessions │ └── lastPracticedAt │
|
||
│ ├── id (PK) │ │
|
||
│ ├── playerId (FK) │ UNIQUE(playerId, skillId) │
|
||
│ ├── phaseId │ │
|
||
│ ├── problemsAttempted │ │
|
||
│ ├── problemsCorrect │ │
|
||
│ ├── skillsUsed (JSON) │ │
|
||
│ └── completedAt │ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Data Models
|
||
|
||
```typescript
|
||
// player_curriculum - Overall curriculum position for a player
|
||
interface PlayerCurriculum {
|
||
playerId: string; // FK to players, PRIMARY KEY
|
||
currentLevel: 1 | 2 | 3; // Which level they're on
|
||
currentPhaseId: string; // e.g., "L1.add.+3.withFive"
|
||
worksheetPreset: string; // Saved worksheet difficulty profile
|
||
visualizationMode: boolean; // Practice without visible abacus
|
||
updatedAt: Date;
|
||
}
|
||
|
||
// player_skill_mastery - Per-skill progress tracking
|
||
interface PlayerSkillMastery {
|
||
id: string;
|
||
playerId: string; // FK to players
|
||
skillId: string; // e.g., "fiveComplements.4=5-1"
|
||
attempts: number; // Total attempts using this skill
|
||
correct: number; // Successful uses
|
||
consecutiveCorrect: number; // Current streak (resets on error)
|
||
masteryLevel: "learning" | "practicing" | "mastered";
|
||
lastPracticedAt: Date;
|
||
// UNIQUE constraint on (playerId, skillId)
|
||
}
|
||
|
||
// practice_sessions - Historical session data
|
||
interface PracticeSession {
|
||
id: string;
|
||
playerId: string;
|
||
phaseId: string; // Which curriculum phase
|
||
problemsAttempted: number;
|
||
problemsCorrect: number;
|
||
averageTimeMs: number;
|
||
skillsUsed: string[]; // Skills exercised this session
|
||
startedAt: Date;
|
||
completedAt: Date;
|
||
}
|
||
```
|
||
|
||
### Mastery Logic
|
||
|
||
```typescript
|
||
const MASTERY_CONFIG = {
|
||
consecutiveForMastery: 5, // 5 correct in a row = mastered
|
||
minimumAttempts: 10, // Need at least 10 attempts
|
||
accuracyThreshold: 0.85, // 85% accuracy for practicing → mastered
|
||
};
|
||
|
||
function updateMasteryLevel(skill: PlayerSkillMastery): MasteryLevel {
|
||
if (
|
||
skill.consecutiveCorrect >= MASTERY_CONFIG.consecutiveForMastery &&
|
||
skill.attempts >= MASTERY_CONFIG.minimumAttempts &&
|
||
skill.correct / skill.attempts >= MASTERY_CONFIG.accuracyThreshold
|
||
) {
|
||
return "mastered";
|
||
}
|
||
if (skill.attempts >= 5) {
|
||
return "practicing";
|
||
}
|
||
return "learning";
|
||
}
|
||
```
|
||
|
||
### UX Flow
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ PARENT/TEACHER VIEW │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ "Who is practicing today?" │
|
||
│ │
|
||
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────────┐ │
|
||
│ │ 😊 │ │ 🦊 │ │ 🚀 │ │ ➕ │ │
|
||
│ │ Sonia│ │Carlos│ │ Maya │ │ Add New │ │
|
||
│ │ Lv.2 │ │ Lv.1 │ │ Lv.1 │ │ Student │ │
|
||
│ └──────┘ └──────┘ └──────┘ └──────────┘ │
|
||
│ │
|
||
│ [Select student, hand computer to child] │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
↓
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ STUDENT VIEW (after selection) │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ Hi Sonia! 😊 │
|
||
│ │
|
||
│ ┌─────────────────────────────────────────┐ │
|
||
│ │ Level 2: Addition with Regrouping │ │
|
||
│ │ Current: +6 with Friends of 5 │ │
|
||
│ │ ████████████░░░░░░░░ 60% mastered │ │
|
||
│ │ │ │
|
||
│ │ [Continue Practice] [View Progress] │ │
|
||
│ └─────────────────────────────────────────┘ │
|
||
│ │
|
||
│ [Generate Worksheet for My Level] │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Worksheet Integration
|
||
|
||
When generating worksheets:
|
||
|
||
1. **No student selected**: Manual difficulty selection (current behavior)
|
||
2. **Student selected**:
|
||
- Pre-populate settings based on their curriculum position
|
||
- "Generate for Sonia's level" button
|
||
- Still allow manual override
|
||
|
||
## Practice Session Planning
|
||
|
||
### Overview
|
||
|
||
A "session plan" is the system's recommendation for what a student should practice, generated based on:
|
||
|
||
- Available time (specified by teacher)
|
||
- Student's current curriculum position
|
||
- Skill mastery levels (what needs work vs. what's mastered)
|
||
- Spaced repetition needs (when were skills last practiced)
|
||
|
||
The teacher drives the process: select student → specify time → review plan → start session.
|
||
|
||
### Session Flow
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ 1. SETUP (Teacher) │
|
||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||
│ │ Select │ → │ Set Time │ → │ Generate │ │
|
||
│ │ Student │ │ Available │ │ Plan │ │
|
||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ 2. REVIEW PLAN (Teacher + Student) │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ "Today's Practice for Emma" [Config] │ │
|
||
│ │ ⚙️ │ │
|
||
│ │ Time: ~15 minutes (20 problems) │ │
|
||
│ │ │ │
|
||
│ │ Focus: Adding +3 using five-complement (12 problems) │ │
|
||
│ │ Review: +1, +2 direct addition (6 problems) │ │
|
||
│ │ Challenge: Mixed +1 to +3 (2 problems) │ │
|
||
│ │ │ │
|
||
│ │ [Adjust Plan] [Let's Go! ✓] │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ 3. ACTIVE SESSION (Student, Teacher monitors) │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ Problem 7 of 20 ⏱️ 8:32 remaining │ │
|
||
│ │ ████████░░░░░░░░░░░░ 35% [Config] │ │
|
||
│ │ ⚙️ │ │
|
||
│ │ Session Health: 🟢 On Track │ │
|
||
│ │ Accuracy: 85% (6/7) | Avg: 42s/problem │ │
|
||
│ │ │ │
|
||
│ │ [Teacher: Pause] [Teacher: Adjust] [Teacher: End Early] │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ 4. SESSION SUMMARY │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ Great job, Emma! 🎉 │ │
|
||
│ │ │ │
|
||
│ │ Completed: 18/20 problems in 14 minutes │ │
|
||
│ │ Accuracy: 83% │ │
|
||
│ │ │ │
|
||
│ │ Mastery Progress: │ │
|
||
│ │ +3 five-comp: Learning → Practicing ⬆️ │ │
|
||
│ │ +1 direct: Mastered ✓ (reviewed) │ │
|
||
│ │ │ │
|
||
│ │ [Done] [Generate Worksheet] [Start Another Session] │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Configuration Inspector (Debug/Fine-tune Mode)
|
||
|
||
Both the **Plan Review** and **Active Session** screens include a "Config" button (⚙️) that opens a panel showing the exact configuration being applied. This is useful for:
|
||
|
||
- **Teachers**: Understanding why certain problems appear
|
||
- **Developers**: Debugging the plan generation algorithm
|
||
- **Fine-tuning**: Adjusting parameters before starting
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────────────┐
|
||
│ Session Configuration [×] │
|
||
├──────────────────────────────────────────────────────────────────┤
|
||
│ PLAN PARAMETERS │
|
||
│ ├── targetDuration: 15 minutes │
|
||
│ ├── estimatedProblems: 20 │
|
||
│ ├── avgTimePerProblem: 45s (based on student history) │
|
||
│ └── planGeneratedAt: 2024-01-15T10:30:00Z │
|
||
│ │
|
||
│ DISTRIBUTION │
|
||
│ ├── focus: 60% (12 problems) │
|
||
│ │ └── targetSkills: ["fiveComplements.3=5-2"] │
|
||
│ ├── reinforce: 20% (4 problems) │
|
||
│ │ └── targetSkills: ["basic.directAddition"] │
|
||
│ ├── review: 15% (3 problems) │
|
||
│ │ └── targetSkills: ["fiveComplements.1=5-4"] │
|
||
│ └── challenge: 5% (1 problem) │
|
||
│ └── targetSkills: ["mixed"] │
|
||
│ │
|
||
│ PROBLEM CONSTRAINTS (Current Slot) │
|
||
│ ├── slotIndex: 7 │
|
||
│ ├── purpose: "focus" │
|
||
│ ├── allowedSkills: { fiveComplements: { "3=5-2": true } } │
|
||
│ ├── forbiddenSkills: { tenComplements: true } │
|
||
│ ├── digitRange: { min: 1, max: 2 } │
|
||
│ └── termCount: { min: 3, max: 5 } │
|
||
│ │
|
||
│ STUDENT STATE SNAPSHOT │
|
||
│ ├── currentPhase: "L1.add.+3.five" │
|
||
│ ├── phaseProgress: 4/10 skills at 'practicing' or better │
|
||
│ └── skillMastery: │
|
||
│ ├── fiveComplements.3=5-2: { attempts: 23, accuracy: 74% } │
|
||
│ ├── fiveComplements.2=5-3: { attempts: 18, accuracy: 89% } │
|
||
│ └── basic.directAddition: { attempts: 45, accuracy: 96% } │
|
||
│ │
|
||
│ [Copy to Clipboard] [Export JSON] │
|
||
└──────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Session Health Indicators
|
||
|
||
Real-time metrics visible to the teacher during the active session:
|
||
|
||
| Indicator | 🟢 Good | 🟡 Warning | 🔴 Struggling |
|
||
| -------------- | ---------------------- | ------------------ | -------------------- |
|
||
| **Accuracy** | >80% | 60-80% | <60% |
|
||
| **Pace** | On track or ahead | 10-30% behind | >30% behind |
|
||
| **Streak** | 3+ consecutive correct | Mixed results | 3+ consecutive wrong |
|
||
| **Engagement** | <60s per problem | 60-90s per problem | >90s or long pauses |
|
||
|
||
Overall session health is the worst of the four indicators.
|
||
|
||
### Teacher Adjustments Mid-Session
|
||
|
||
When the session isn't going well, the teacher can:
|
||
|
||
| Adjustment | Effect | When to Use |
|
||
| ---------------------- | -------------------------------------------------- | ----------------------------------- |
|
||
| **Reduce Difficulty** | Switch remaining slots to easier problems | Accuracy < 60%, frustration visible |
|
||
| **Enable Scaffolding** | Turn on visualization mode (show abacus) | Conceptual confusion |
|
||
| **Narrow Focus** | Drop review/challenge, focus only on current skill | Overwhelmed by variety |
|
||
| **Take a Break** | Pause timer, allow discussion | Long pauses, emotional state |
|
||
| **Extend Session** | Add more problems | Going well, student wants more |
|
||
| **End Gracefully** | Complete current problem, show summary | Time constraint, fatigue |
|
||
|
||
All adjustments are logged in `SessionPlan.adjustments[]` for later analysis.
|
||
|
||
### Data Model
|
||
|
||
```typescript
|
||
interface SessionPlan {
|
||
id: string;
|
||
playerId: string;
|
||
|
||
// Setup parameters
|
||
targetDurationMinutes: number;
|
||
estimatedProblemCount: number;
|
||
avgTimePerProblemSeconds: number; // Calculated from student history
|
||
|
||
// Problem slots (generated upfront, can be modified)
|
||
slots: ProblemSlot[];
|
||
|
||
// Human-readable summary for plan review screen
|
||
summary: SessionSummary;
|
||
|
||
// State machine
|
||
status: "draft" | "approved" | "in_progress" | "completed" | "abandoned";
|
||
|
||
// Timestamps
|
||
createdAt: Date;
|
||
approvedAt?: Date; // When teacher/student clicked "Let's Go"
|
||
startedAt?: Date; // When first problem displayed
|
||
completedAt?: Date;
|
||
|
||
// Live tracking
|
||
currentSlotIndex: number;
|
||
sessionHealth: SessionHealth;
|
||
adjustments: SessionAdjustment[];
|
||
|
||
// Results (filled in as session progresses)
|
||
results: SlotResult[];
|
||
}
|
||
|
||
interface ProblemSlot {
|
||
index: number;
|
||
purpose: "focus" | "reinforce" | "review" | "challenge";
|
||
|
||
// Constraints passed to problem generator
|
||
constraints: {
|
||
allowedSkills?: Partial<SkillSet>;
|
||
targetSkills?: Partial<SkillSet>;
|
||
forbiddenSkills?: Partial<SkillSet>;
|
||
digitRange?: { min: number; max: number };
|
||
termCount?: { min: number; max: number };
|
||
operator?: "addition" | "subtraction" | "mixed";
|
||
};
|
||
|
||
// Generated problem (filled when slot is reached)
|
||
problem?: GeneratedProblem;
|
||
}
|
||
|
||
interface SessionSummary {
|
||
focusDescription: string; // "Adding +3 using five-complement"
|
||
focusCount: number;
|
||
reviewSkills: string[]; // Human-readable skill names
|
||
reviewCount: number;
|
||
challengeCount: number;
|
||
estimatedMinutes: number;
|
||
}
|
||
|
||
interface SessionHealth {
|
||
overall: "good" | "warning" | "struggling";
|
||
accuracy: number; // 0-1
|
||
pacePercent: number; // 100 = on track, <100 = behind
|
||
currentStreak: number; // Positive = correct streak, negative = wrong streak
|
||
avgResponseTimeMs: number;
|
||
}
|
||
|
||
interface SessionAdjustment {
|
||
timestamp: Date;
|
||
type:
|
||
| "difficulty_reduced"
|
||
| "scaffolding_enabled"
|
||
| "focus_narrowed"
|
||
| "paused"
|
||
| "resumed"
|
||
| "extended"
|
||
| "ended_early";
|
||
reason?: string; // Optional teacher note
|
||
previousHealth: SessionHealth;
|
||
}
|
||
|
||
interface SlotResult {
|
||
slotIndex: number;
|
||
problem: GeneratedProblem;
|
||
studentAnswer: number;
|
||
isCorrect: boolean;
|
||
responseTimeMs: number;
|
||
skillsExercised: string[]; // Which skills this problem tested
|
||
timestamp: Date;
|
||
}
|
||
```
|
||
|
||
### Plan Generation Algorithm
|
||
|
||
```typescript
|
||
interface PlanGenerationConfig {
|
||
// Distribution weights (should sum to 1.0)
|
||
focusWeight: number; // Default: 0.60
|
||
reinforceWeight: number; // Default: 0.20
|
||
reviewWeight: number; // Default: 0.15
|
||
challengeWeight: number; // Default: 0.05
|
||
|
||
// Timing
|
||
defaultSecondsPerProblem: number; // Default: 45
|
||
|
||
// Spaced repetition
|
||
reviewIntervalDays: {
|
||
mastered: number; // Default: 7 (review mastered skills weekly)
|
||
practicing: number; // Default: 3 (review practicing skills every 3 days)
|
||
};
|
||
}
|
||
|
||
function generateSessionPlan(
|
||
playerId: string,
|
||
durationMinutes: number,
|
||
config: PlanGenerationConfig = DEFAULT_CONFIG,
|
||
): SessionPlan {
|
||
// 1. Load student state
|
||
const curriculum = await getPlayerCurriculum(playerId);
|
||
const skillMastery = await getAllSkillMastery(playerId);
|
||
const recentSessions = await getRecentSessions(playerId, 10);
|
||
|
||
// 2. Calculate personalized timing
|
||
const avgTime =
|
||
calculateAvgTimePerProblem(recentSessions) ??
|
||
config.defaultSecondsPerProblem;
|
||
const problemCount = Math.floor((durationMinutes * 60) / avgTime);
|
||
|
||
// 3. Categorize skills by need
|
||
const currentPhaseSkills = getSkillsForPhase(curriculum.currentPhaseId);
|
||
const struggling = skillMastery.filter(
|
||
(s) =>
|
||
currentPhaseSkills.includes(s.skillId) && s.correct / s.attempts < 0.7,
|
||
);
|
||
const needsReview = skillMastery.filter(
|
||
(s) =>
|
||
s.masteryLevel === "mastered" &&
|
||
daysSince(s.lastPracticedAt) > config.reviewIntervalDays.mastered,
|
||
);
|
||
|
||
// 4. Calculate slot distribution
|
||
const focusCount = Math.round(problemCount * config.focusWeight);
|
||
const reinforceCount = Math.round(problemCount * config.reinforceWeight);
|
||
const reviewCount = Math.round(problemCount * config.reviewWeight);
|
||
const challengeCount =
|
||
problemCount - focusCount - reinforceCount - reviewCount;
|
||
|
||
// 5. Build slots with constraints
|
||
const slots: ProblemSlot[] = [];
|
||
|
||
// Focus slots: current phase, primary skill
|
||
for (let i = 0; i < focusCount; i++) {
|
||
slots.push({
|
||
index: slots.length,
|
||
purpose: "focus",
|
||
constraints: buildConstraintsForPhase(curriculum.currentPhaseId),
|
||
});
|
||
}
|
||
|
||
// Reinforce slots: struggling skills get extra practice
|
||
for (let i = 0; i < reinforceCount; i++) {
|
||
const skill = struggling[i % struggling.length];
|
||
slots.push({
|
||
index: slots.length,
|
||
purpose: "reinforce",
|
||
constraints: buildConstraintsForSkill(skill?.skillId),
|
||
});
|
||
}
|
||
|
||
// Review slots: spaced repetition of mastered skills
|
||
for (let i = 0; i < reviewCount; i++) {
|
||
const skill = needsReview[i % needsReview.length];
|
||
slots.push({
|
||
index: slots.length,
|
||
purpose: "review",
|
||
constraints: buildConstraintsForSkill(skill?.skillId),
|
||
});
|
||
}
|
||
|
||
// Challenge slots: slightly harder or mixed
|
||
for (let i = 0; i < challengeCount; i++) {
|
||
slots.push({
|
||
index: slots.length,
|
||
purpose: "challenge",
|
||
constraints: buildChallengeConstraints(curriculum),
|
||
});
|
||
}
|
||
|
||
// 6. Shuffle to interleave purposes (but keep some focus problems together)
|
||
const shuffledSlots = intelligentShuffle(slots);
|
||
|
||
// 7. Build summary
|
||
const summary = buildHumanReadableSummary(shuffledSlots, curriculum);
|
||
|
||
return {
|
||
id: generateId(),
|
||
playerId,
|
||
targetDurationMinutes: durationMinutes,
|
||
estimatedProblemCount: problemCount,
|
||
avgTimePerProblemSeconds: avgTime,
|
||
slots: shuffledSlots,
|
||
summary,
|
||
status: "draft",
|
||
createdAt: new Date(),
|
||
currentSlotIndex: 0,
|
||
sessionHealth: {
|
||
overall: "good",
|
||
accuracy: 1,
|
||
pacePercent: 100,
|
||
currentStreak: 0,
|
||
avgResponseTimeMs: 0,
|
||
},
|
||
adjustments: [],
|
||
results: [],
|
||
};
|
||
}
|
||
```
|
||
|
||
### Database Schema Addition
|
||
|
||
```sql
|
||
-- Add to existing schema
|
||
CREATE TABLE session_plans (
|
||
id TEXT PRIMARY KEY,
|
||
player_id TEXT NOT NULL REFERENCES players(id) ON DELETE CASCADE,
|
||
|
||
-- Setup
|
||
target_duration_minutes INTEGER NOT NULL,
|
||
estimated_problem_count INTEGER NOT NULL,
|
||
avg_time_per_problem_seconds INTEGER NOT NULL,
|
||
|
||
-- Slots and summary stored as JSON
|
||
slots TEXT NOT NULL, -- JSON array of ProblemSlot
|
||
summary TEXT NOT NULL, -- JSON SessionSummary
|
||
|
||
-- State
|
||
status TEXT NOT NULL DEFAULT 'draft',
|
||
current_slot_index INTEGER NOT NULL DEFAULT 0,
|
||
session_health TEXT, -- JSON SessionHealth
|
||
adjustments TEXT, -- JSON array of SessionAdjustment
|
||
results TEXT, -- JSON array of SlotResult
|
||
|
||
-- Timestamps
|
||
created_at INTEGER NOT NULL,
|
||
approved_at INTEGER,
|
||
started_at INTEGER,
|
||
completed_at INTEGER
|
||
);
|
||
|
||
CREATE INDEX idx_session_plans_player ON session_plans(player_id);
|
||
CREATE INDEX idx_session_plans_status ON session_plans(status);
|
||
```
|
||
|
||
### API Endpoints
|
||
|
||
```
|
||
POST /api/curriculum/{playerId}/sessions/plan
|
||
Body: { durationMinutes: number, config?: PlanGenerationConfig }
|
||
Returns: SessionPlan (status: 'draft')
|
||
|
||
GET /api/curriculum/{playerId}/sessions/plan/{planId}
|
||
Returns: SessionPlan with full slot details
|
||
|
||
PATCH /api/curriculum/{playerId}/sessions/plan/{planId}
|
||
Body: { status: 'approved' } or adjustment data
|
||
Returns: Updated SessionPlan
|
||
|
||
POST /api/curriculum/{playerId}/sessions/plan/{planId}/slot/{index}/result
|
||
Body: { studentAnswer: number, responseTimeMs: number }
|
||
Returns: { isCorrect, updatedHealth, nextSlot? }
|
||
|
||
POST /api/curriculum/{playerId}/sessions/plan/{planId}/adjust
|
||
Body: { type: AdjustmentType, reason?: string }
|
||
Returns: Updated SessionPlan with modified remaining slots
|
||
```
|
||
|
||
## Practice Experience
|
||
|
||
### Overview
|
||
|
||
The practice experience is the actual problem-solving interface where the student works through their session plan. The computer/phone serves as the primary proctoring device - displaying problems, collecting answers, and tracking progress.
|
||
|
||
### Design Principles
|
||
|
||
1. **One problem at a time** - Clean, focused display without distraction
|
||
2. **Physical abacus preferred** - On-screen abacus is a "last resort"
|
||
3. **Device-appropriate input** - Native keyboard on desktop, simplified keypad on phone
|
||
4. **Visualization mode** - Encourages mental math by hiding abacus aids
|
||
5. **Skill-appropriate problems** - Never ask for skills not yet learned
|
||
|
||
### Hardware Recommendations
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ RECOMMENDED SETUP │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ ┌─────────────┐ ┌───────────────────────┐ │
|
||
│ │ SCREEN │ │ PHYSICAL ABACUS │ │
|
||
│ │ (problems) │ │ (3D printed STL) │ │
|
||
│ │ │ │ │ │
|
||
│ │ 45 + 23 │ │ ☐ ☐ ☐ ☐ ☐ ☐ ☐ ☐ ☐ │ │
|
||
│ │ │ │ ─────────────────── │ │
|
||
│ │ [ 68 ] │ │ ● ● ● ● ○ ○ ○ ○ ○ │ │
|
||
│ │ │ │ ● ● ● ● ○ ○ ○ ○ ○ │ │
|
||
│ └─────────────┘ │ ● ● ● ● ○ ○ ○ ○ ○ │ │
|
||
│ │ ● ● ● ● ○ ○ ○ ○ ○ │ │
|
||
│ └───────────────────────┘ │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Problem Formats
|
||
|
||
The curriculum uses two distinct problem formats:
|
||
|
||
#### 1. Vertical (Columnar) Format - Primary
|
||
|
||
This is the main format from the workbooks. Numbers are stacked vertically:
|
||
|
||
- **Plus sign omitted** - Addition is implicit
|
||
- **Minus sign shown** - Only subtraction is marked
|
||
- **Answer box at bottom** - Student fills in the result
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ VERTICAL FORMAT (Primary - Parts 1 & 2) │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ Problem 7 of 20 ⏱️ 8:32 remaining │
|
||
│ ████████░░░░░░░░░░░░ 35% │
|
||
│ │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ │ 88 │ │
|
||
│ │ 61 │ │
|
||
│ │ 33 │ │
|
||
│ │ - 55 │ │
|
||
│ │ 47 │ │
|
||
│ │ - 28 │ │
|
||
│ │ ────── │ │
|
||
│ │ ┌───────┐ │ │
|
||
│ │ │ 146 │ ← Student input │ │
|
||
│ │ └───────┘ │ │
|
||
│ │ │ │
|
||
│ │ [Submit] │ │
|
||
│ │ │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ [Need Help?] [Show Abacus] │
|
||
│ (last resort) │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
#### 2. Linear Format - Mental Math (Part 3)
|
||
|
||
After visualization practice, students progress to linear problems - sequences presented as a math sentence for mental calculation:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ LINEAR FORMAT (Part 3 - Mental Math) │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ Problem 4 of 10 🧠 Mental Math Practice │
|
||
│ ████████████░░░░░░░░ 40% │
|
||
│ │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ │ 88 + 61 + 33 - 55 + 47 - 28 = ? │ │
|
||
│ │ │ │
|
||
│ │ ┌───────────┐ │ │
|
||
│ │ │ 146 │ │ │
|
||
│ │ └───────────┘ │ │
|
||
│ │ │ │
|
||
│ │ [Submit] │ │
|
||
│ │ │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ 💭 "Visualize the beads as you work through each number" │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Daily Practice Structure
|
||
|
||
Based on the workbook format, a typical daily practice session has three parts:
|
||
|
||
| Part | Format | Abacus | Purpose |
|
||
| -------------------------- | -------- | --------------- | -------------------------------------- |
|
||
| **Part 1: Skill Building** | Vertical | Physical abacus | Build muscle memory, learn techniques |
|
||
| **Part 2: Visualization** | Vertical | Hidden/mental | Internalize bead movements mentally |
|
||
| **Part 3: Mental Math** | Linear | None | Pure mental calculation, no visual aid |
|
||
|
||
### Input Methods
|
||
|
||
| Device | Primary Input | Implementation |
|
||
| ------------------------ | --------------- | --------------------------------------- |
|
||
| **Desktop/Laptop** | Native keyboard | `<input type="number">` with auto-focus |
|
||
| **Tablet with keyboard** | Native keyboard | Same as desktop |
|
||
| **Phone/Touch tablet** | Virtual keypad | `react-simple-keyboard` numeric layout |
|
||
|
||
#### Phone Keypad Implementation
|
||
|
||
Reference existing implementations:
|
||
|
||
- **Know Your World**: `src/arcade-games/know-your-world/components/SimpleLetterKeyboard.tsx`
|
||
- Uses `react-simple-keyboard` v3.8.139
|
||
- Configured for letter input in learning mode
|
||
- **Memory Quiz**: `src/arcade-games/memory-quiz/components/InputPhase.tsx`
|
||
- Custom numeric keypad implementation
|
||
- Device detection logic for keyboard vs touch
|
||
|
||
```typescript
|
||
// Simplified numeric keypad for practice
|
||
const numericLayout = {
|
||
default: ["7 8 9", "4 5 6", "1 2 3", "{bksp} 0 {enter}"],
|
||
};
|
||
|
||
// Use device detection from memory quiz
|
||
const useDeviceType = () => {
|
||
// Returns 'desktop' | 'tablet' | 'phone'
|
||
// Based on screen size and touch capability
|
||
};
|
||
```
|
||
|
||
### Abacus Access
|
||
|
||
The on-screen abacus is available as a **last resort**, not a primary tool:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ ABACUS ACCESS (when clicked) │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ 💡 Tip: Using a physical abacus helps build muscle │ │
|
||
│ │ memory! We have a 3D-printable model available. │ │
|
||
│ │ │ │
|
||
│ │ [Download STL] [Show On-Screen Abacus Anyway] │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
If the student insists, show the `AbacusReact` component from `@soroban/abacus-react`.
|
||
|
||
**Tracking**: Log when students use the on-screen abacus to identify those who may need a physical one.
|
||
|
||
### Visualization Mode
|
||
|
||
When `visualizationMode: true` in the student's curriculum settings:
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ VISUALIZATION MODE │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ │
|
||
│ Problem 7 of 20 🧠 Visualization Practice │
|
||
│ │
|
||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ │ 45 + 23 + 12 + 8 = ? │ │
|
||
│ │ │ │
|
||
│ │ 💭 "Picture the beads in your mind" │ │
|
||
│ │ │ │
|
||
│ │ ┌───────────┐ │ │
|
||
│ │ │ │ │ │
|
||
│ │ └───────────┘ │ │
|
||
│ │ │ │
|
||
│ └──────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ [Having Trouble?] ← Opens hints, NOT the abacus │
|
||
│ │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
**Visualization mode behaviors**:
|
||
|
||
- Hide "Show Abacus" button entirely
|
||
- Add gentle reminder: "Picture the beads in your mind"
|
||
- If student struggles (2+ wrong in a row):
|
||
- Offer guided visualization hints
|
||
- Suggest stepping back to physical abacus practice
|
||
- Do NOT automatically show abacus
|
||
- Track accuracy separately for visualization vs. abacus-assisted
|
||
|
||
### Skill Constraint Enforcement
|
||
|
||
**CRITICAL**: Never present problems requiring skills the student hasn't learned yet.
|
||
|
||
The problem generator (`src/utils/problemGenerator.ts`) already supports:
|
||
|
||
- `allowedSkills` - Skills the problem MUST use
|
||
- `targetSkills` - Skills we're trying to practice
|
||
- `forbiddenSkills` - Skills the problem must NOT use
|
||
|
||
```typescript
|
||
// For a Level 1 student who has only learned +1, +2, +3 direct addition:
|
||
const constraints = {
|
||
forbiddenSkills: {
|
||
fiveComplements: true, // No five-complement techniques
|
||
tenComplements: true, // No ten-complement techniques
|
||
tenComplementsSub: true, // No subtraction borrowing
|
||
fiveComplementsSub: true, // No subtraction with fives
|
||
},
|
||
allowedSkills: {
|
||
basic: { directAddition: true },
|
||
},
|
||
};
|
||
```
|
||
|
||
**Audit checklist for problem generation**:
|
||
|
||
1. ✅ `analyzeRequiredSkills()` accurately categorizes all techniques needed
|
||
2. ✅ `problemMatchesSkills()` correctly validates against constraints
|
||
3. ⏳ Create curriculum phase → constraints mapping
|
||
4. ⏳ Validate no "skill leak" (problems requiring unlearned techniques)
|
||
|
||
### Existing Components to Leverage
|
||
|
||
| Component | Location | Purpose |
|
||
| ----------------------- | ---------------------------------------------------------------------- | ----------------------------------------- |
|
||
| `PracticeProblemPlayer` | `src/components/tutorial/PracticeProblemPlayer.tsx` | Existing practice UI (abacus-based input) |
|
||
| `SimpleLetterKeyboard` | `src/arcade-games/know-your-world/components/SimpleLetterKeyboard.tsx` | `react-simple-keyboard` integration |
|
||
| `InputPhase` | `src/arcade-games/memory-quiz/components/InputPhase.tsx` | Custom numeric keypad + device detection |
|
||
| `problemGenerator` | `src/utils/problemGenerator.ts` | Skill-constrained problem generation |
|
||
| `AbacusReact` | `@soroban/abacus-react` | On-screen abacus (last resort) |
|
||
|
||
### Data Model Extensions
|
||
|
||
```typescript
|
||
interface PracticeAnswer {
|
||
slotIndex: number;
|
||
studentAnswer: number;
|
||
isCorrect: boolean;
|
||
responseTimeMs: number;
|
||
inputMethod: "keyboard" | "virtual_keypad" | "touch";
|
||
usedOnScreenAbacus: boolean; // Track abacus usage
|
||
visualizationMode: boolean; // Was this in visualization mode?
|
||
}
|
||
|
||
// For identifying students who may need a physical abacus
|
||
interface StudentAbacusUsage {
|
||
onScreenAbacusUsed: number; // Count of problems using on-screen
|
||
totalProblems: number;
|
||
usageRate: number; // Percentage
|
||
suggestPhysicalAbacus: boolean; // true if usage rate > 30%
|
||
}
|
||
```
|
||
|
||
### Mobile Responsiveness
|
||
|
||
```
|
||
┌────────────────────┐
|
||
│ PHONE - VERTICAL │
|
||
├────────────────────┤
|
||
│ │
|
||
│ Problem 7/20 │
|
||
│ ████░░░░░ 35% │
|
||
│ │
|
||
│ 88 │
|
||
│ 61 │
|
||
│ 33 │
|
||
│ - 55 │
|
||
│ 47 │
|
||
│ - 28 │
|
||
│ ────── │
|
||
│ ┌────────┐ │
|
||
│ │ 146 │ │
|
||
│ └────────┘ │
|
||
│ │
|
||
│ ┌──┬──┬──┐ │
|
||
│ │ 7│ 8│ 9│ │
|
||
│ ├──┼──┼──┤ │
|
||
│ │ 4│ 5│ 6│ │
|
||
│ ├──┼──┼──┤ │
|
||
│ │ 1│ 2│ 3│ │
|
||
│ ├──┼──┼──┤ │
|
||
│ │ ⌫│ 0│ ⏎│ │
|
||
│ └──┴──┴──┘ │
|
||
│ │
|
||
└────────────────────┘
|
||
```
|
||
|
||
```
|
||
┌────────────────────┐
|
||
│ PHONE - LINEAR │
|
||
│ (Mental Math) │
|
||
├────────────────────┤
|
||
│ │
|
||
│ Problem 4/10 │
|
||
│ 🧠 Mental Math │
|
||
│ │
|
||
│ 88 + 61 + 33 │
|
||
│ - 55 + 47 - 28 │
|
||
│ = ? │
|
||
│ │
|
||
│ ┌────────┐ │
|
||
│ │ 146 │ │
|
||
│ └────────┘ │
|
||
│ │
|
||
│ ┌──┬──┬──┐ │
|
||
│ │ 7│ 8│ 9│ │
|
||
│ ├──┼──┼──┤ │
|
||
│ │ 4│ 5│ 6│ │
|
||
│ ├──┼──┼──┤ │
|
||
│ │ 1│ 2│ 3│ │
|
||
│ ├──┼──┼──┤ │
|
||
│ │ ⌫│ 0│ ⏎│ │
|
||
│ └──┴──┴──┘ │
|
||
│ │
|
||
└────────────────────┘
|
||
```
|
||
|
||
## Implementation Phases
|
||
|
||
### Phase 0: Student Progress Infrastructure ✅ COMPLETE
|
||
|
||
**Goal**: Create database tables and basic UI for tracking student progress through the curriculum.
|
||
|
||
**Tasks**:
|
||
|
||
1. ✅ Create `player_curriculum` table schema - `src/db/schema/player-curriculum.ts`
|
||
2. ✅ Create `player_skill_mastery` table schema - `src/db/schema/player-skill-mastery.ts`
|
||
3. ✅ Create `practice_sessions` table schema - `src/db/schema/practice-sessions.ts`
|
||
4. ✅ Migrations run automatically on app start
|
||
5. ✅ Create student selection UI component - `src/components/practice/StudentSelector.tsx`
|
||
6. ✅ Create progress dashboard component - `src/components/practice/ProgressDashboard.tsx`
|
||
7. ✅ Create API routes for curriculum progress CRUD - `src/app/api/curriculum/[playerId]/`
|
||
8. ✅ Create `src/lib/curriculum/progress-manager.ts`
|
||
9. ✅ Create `src/hooks/usePlayerCurriculum.ts`
|
||
10. ✅ Create `/practice` page - `src/app/practice/page.tsx`
|
||
|
||
**Files Created**:
|
||
|
||
- ✅ `src/db/schema/player-curriculum.ts` - Curriculum position tracking
|
||
- ✅ `src/db/schema/player-skill-mastery.ts` - Per-skill mastery tracking with `MASTERY_CONFIG` and `calculateMasteryLevel()`
|
||
- ✅ `src/db/schema/practice-sessions.ts` - Practice session history
|
||
- ✅ `src/components/practice/StudentSelector.tsx` - Student selection UI
|
||
- ✅ `src/components/practice/ProgressDashboard.tsx` - Progress display and actions
|
||
- ✅ `src/components/practice/index.ts` - Component exports
|
||
- ✅ `src/lib/curriculum/progress-manager.ts` - CRUD operations for curriculum data
|
||
- ✅ `src/hooks/usePlayerCurriculum.ts` - Client-side curriculum state management
|
||
- ✅ `src/app/api/curriculum/[playerId]/route.ts` - GET/PATCH curriculum
|
||
- ✅ `src/app/api/curriculum/[playerId]/advance/route.ts` - POST advance phase
|
||
- ✅ `src/app/api/curriculum/[playerId]/skills/route.ts` - POST record skill attempt
|
||
- ✅ `src/app/api/curriculum/[playerId]/skills/batch/route.ts` - POST batch record
|
||
- ✅ `src/app/api/curriculum/[playerId]/sessions/route.ts` - POST start session
|
||
- ✅ `src/app/api/curriculum/[playerId]/sessions/[sessionId]/complete/route.ts` - POST complete
|
||
- ✅ `src/app/practice/page.tsx` - Practice entry point page
|
||
|
||
### Phase 1: Problem Generator Extension ✅ COMPLETE
|
||
|
||
**Goal**: Enable the problem generator to handle subtraction and properly categorize "with/without friends of 5".
|
||
|
||
**Tasks**:
|
||
|
||
1. ✅ Add `analyzeColumnSubtraction()` function - `src/utils/problemGenerator.ts:148`
|
||
2. ✅ Add subtraction skills to `SkillSet` type - `src/types/tutorial.ts:36`
|
||
- `fiveComplementsSub`: `-4=-5+1`, `-3=-5+2`, `-2=-5+3`, `-1=-5+4`
|
||
- `tenComplementsSub`: `-9=+1-10`, `-8=+2-10`, ... `-1=+9-10`
|
||
- `basic.directSubtraction`, `basic.heavenBeadSubtraction`, `basic.simpleCombinationsSub`
|
||
3. ✅ Add `analyzeSubtractionStepSkills()` function - `src/utils/problemGenerator.ts:225`
|
||
4. ✅ Refactor `problemMatchesSkills()` and `findValidNextTerm()` to support new skill categories
|
||
5. ⏳ Test with Storybook stories (pending)
|
||
6. ⏳ Add `generateSubtractionSequence()` for mixed operation problems (pending)
|
||
|
||
### Phase 2: Curriculum Definitions
|
||
|
||
**Goal**: Define the Level 1/2/3 structure as data that drives practice.
|
||
|
||
**Tasks**:
|
||
|
||
1. Create curriculum data structure:
|
||
|
||
```typescript
|
||
interface CurriculumLevel {
|
||
id: string;
|
||
name: string;
|
||
description: string;
|
||
phases: CurriculumPhase[];
|
||
}
|
||
|
||
interface CurriculumPhase {
|
||
targetNumber: number; // +1, +2, ... +9 or -9, -8, ... -1
|
||
operation: "addition" | "subtraction";
|
||
useFiveComplement: boolean;
|
||
usesTenComplement: boolean;
|
||
practiceStep: PracticeStep; // Existing type
|
||
}
|
||
```
|
||
|
||
2. Define all phases for Level 1, 2, 3
|
||
3. Create helper to convert curriculum phase to PracticeStep constraints
|
||
|
||
### Phase 3: Daily Practice Mode ⏳ NEXT UP
|
||
|
||
**Goal**: A `/practice` page that guides students through the curriculum with intelligent session planning.
|
||
|
||
**Tasks**:
|
||
|
||
1. ✅ Create `/app/practice/page.tsx` - Basic structure done
|
||
2. ✅ Track current position in curriculum - Database schema done
|
||
3. ⏳ Create session plan generator (`src/lib/curriculum/session-planner.ts`)
|
||
4. ⏳ Create `session_plans` database table
|
||
5. ⏳ Create Plan Review screen component
|
||
6. ⏳ Create Active Session screen component
|
||
7. ⏳ Create Configuration Inspector component
|
||
8. ⏳ Create Session Summary screen component
|
||
9. ⏳ Implement session health tracking and indicators
|
||
10. ⏳ Implement teacher adjustment controls
|
||
11. ⏳ Visualization toggle (show/hide abacus)
|
||
12. ⏳ API routes for session plan CRUD
|
||
|
||
**Sub-phases**:
|
||
|
||
#### Phase 3a: Session Plan Generation
|
||
|
||
- Create `SessionPlan` type definitions
|
||
- Implement `generateSessionPlan()` algorithm
|
||
- Create `session_plans` table schema
|
||
- API: POST `/api/curriculum/{playerId}/sessions/plan`
|
||
|
||
#### Phase 3b: Plan Review UI
|
||
|
||
- Plan summary display
|
||
- Configuration inspector (debug panel)
|
||
- "Adjust Plan" controls
|
||
- "Let's Go" approval flow
|
||
|
||
#### Phase 3c: Active Session UI (Practice Experience)
|
||
|
||
- One-problem-at-a-time display with progress bar
|
||
- Timer and pace tracking
|
||
- Device-appropriate input:
|
||
- Desktop: native keyboard with auto-focus
|
||
- Phone: `react-simple-keyboard` numeric keypad (reference: `SimpleLetterKeyboard.tsx`)
|
||
- Device detection logic (reference: `InputPhase.tsx`)
|
||
- On-screen abacus access (last resort):
|
||
- Prompt suggesting physical abacus first
|
||
- Track on-screen abacus usage
|
||
- `AbacusReact` from `@soroban/abacus-react`
|
||
- Visualization mode:
|
||
- Hide abacus button entirely
|
||
- "Picture the beads" reminder
|
||
- Guided hints for struggling students
|
||
- Session health indicators (accuracy, pace, streak, engagement)
|
||
- Teacher controls (pause, adjust, end early)
|
||
- Configuration inspector (current slot details)
|
||
|
||
#### Phase 3d: Session Completion
|
||
|
||
- Summary display with results
|
||
- Mastery level changes
|
||
- Skill update and persistence
|
||
- Next steps (worksheet, another session, done)
|
||
|
||
### Phase 4: Worksheet Integration
|
||
|
||
**Goal**: Generate printable worksheets targeting specific techniques.
|
||
|
||
**Tasks**:
|
||
|
||
1. Add "technique mode" to worksheet config
|
||
2. Allow selecting specific curriculum phase for worksheet
|
||
3. Generate problems using same constraints as online practice
|
||
|
||
## Technical Details
|
||
|
||
### Skill Analysis Logic
|
||
|
||
**Current addition analysis** (from `analyzeColumnAddition`):
|
||
|
||
- Checks if adding `termDigit` to `currentDigit` requires:
|
||
- Direct addition (result ≤ 4)
|
||
- Heaven bead (involves 5)
|
||
- Five complement (needs +5-n)
|
||
- Ten complement (needs -n+10)
|
||
|
||
**Subtraction analysis** (to implement):
|
||
|
||
- Check if subtracting `termDigit` from `currentDigit` requires:
|
||
- Direct subtraction (have enough earth beads)
|
||
- Heaven bead removal (have 5-bead to remove)
|
||
- Five complement (needs -5+n)
|
||
- Ten complement (needs +n-10)
|
||
|
||
### "With/Without Friends of 5" Implementation
|
||
|
||
Use `forbiddenSkills` to exclude five-complement techniques:
|
||
|
||
```typescript
|
||
// Level 1, +3, WITHOUT friends of 5
|
||
const practiceStep: PracticeStep = {
|
||
allowedSkills: { basic: { directAddition: true, heavenBead: true } },
|
||
targetSkills: {
|
||
/* target +3 specifically */
|
||
},
|
||
forbiddenSkills: {
|
||
fiveComplements: {
|
||
"3=5-2": true,
|
||
"2=5-3": true,
|
||
"1=5-4": true,
|
||
"4=5-1": true,
|
||
},
|
||
},
|
||
};
|
||
|
||
// Level 1, +3, WITH friends of 5
|
||
const practiceStep: PracticeStep = {
|
||
allowedSkills: {
|
||
basic: { directAddition: true, heavenBead: true },
|
||
fiveComplements: { "2=5-3": true },
|
||
},
|
||
targetSkills: { fiveComplements: { "2=5-3": true } }, // Specifically target +3 via +5-2
|
||
};
|
||
```
|
||
|
||
## Assessment Data to Track
|
||
|
||
- **Per technique**:
|
||
- Total attempts
|
||
- Correct count
|
||
- Consecutive correct streak
|
||
- Average time per problem
|
||
- Error patterns (which complement pairs are weak)
|
||
|
||
- **Per session**:
|
||
- Date/time
|
||
- Problems completed
|
||
- Accuracy
|
||
- Techniques practiced
|
||
|
||
## Questions Resolved
|
||
|
||
| Question | Answer |
|
||
| ------------------- | --------------------------------------------------- |
|
||
| Problem format? | Multi-term sequences (3-7 terms), like the books |
|
||
| Single-digit first? | No, double-digit from the start |
|
||
| Visualization mode? | No abacus visible - that's the point of mental math |
|
||
| Adaptive mastery? | Yes, continue until demonstrated proficiency |
|
||
|
||
## Sources
|
||
|
||
- [Fine Motor Math - 5-Complement Addition](https://finemotormath.com/abacus-lesson7/)
|
||
- [Fine Motor Math - 10-Complement Addition](https://finemotormath.com/abacus-lesson9/)
|
||
- [Fine Motor Math - Subtraction with Borrowing](https://finemotormath.com/abacus-lesson10/)
|
||
- [Learn Abacus At Home - Curriculum](https://learnabacusathome.com/curriculum/)
|
||
- [Soroban Exam - Basics](https://www.sorobanexam.org/basics/add.html)
|