File size: 3,365 Bytes
65ba59e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# MathPulse AI — Firestore Schema (Practice Center)

## Collection: practice_sessions

### Document: practice_sessions/{session_id}

Purpose: stores the generated question set for a practice session.

Ownership: user-owned via `userId`.

Written by: backend `/api/practice/generate` endpoint.

Read by: backend `/api/practice/submit` endpoint.

Retention: kept for debugging and audit, can be cleaned up after result is stored.

| Field | Type | Description |
|-------|------|-------------|
| session_id | string | UUID |
| userId | string | Firebase UID |
| subject | string | Subject name |
| competency | string | Competency/topic |
| difficulty | string | Practice, Challenge, or Mastery |
| questions | array | Array of question objects |
| generated_at | timestamp | When generated |

```json
{
  "session_id": "uuid string",
  "userId": "firebase uid",
  "subject": "Algebra | Geometry | ...",
  "competency": "string",
  "difficulty": "Practice | Challenge | Mastery",
  "questions": [
    {
      "id": "q1",
      "question": "What is 2+2?",
      "options": ["3", "4", "5", "6"],
      "correct_index": 1,
      "explanation": "Basic addition...",
      "competency": "Basic Arithmetic",
      "difficulty": "Practice",
      "bloomsLevel": "Remember"
    }
  ],
  "generated_at": "ISO timestamp"
}
```

**Indexes needed:** None, single doc reads by `session_id`.

## Collection: practice_results/{userId}/sessions

### Document: practice_results/{userId}/sessions/{session_id}

Purpose: stores the result of a completed practice session.

Ownership: user-owned subcollection under `practice_results/{userId}`.

Written by: backend `/api/practice/submit` endpoint.

Read by: backend `/api/practice/stats` and `/api/practice/history` endpoints.

| Field | Type | Description |
|-------|------|-------------|
| session_id | string | UUID |
| userId | string | Firebase UID |
| score_percent | number | Score percentage |
| correct_count | number | Correct answers |
| total | number | Total questions |
| xp_earned | number | XP earned |
| subject | string | Subject name |
| difficulty | string | Practice, Challenge, or Mastery |
| answers | array | Selected answers per question |
| per_question_feedback | array | Per-question feedback objects |
| submitted_at | timestamp | When submitted |

```json
{
  "session_id": "uuid string",
  "userId": "firebase uid",
  "score_percent": 80,
  "correct_count": 8,
  "total": 10,
  "xp_earned": 130,
  "subject": "Algebra",
  "difficulty": "Challenge",
  "answers": [
    { "question_id": "q1", "selected_index": 1 }
  ],
  "per_question_feedback": [
    {
      "question_id": "q1",
      "selected_index": 1,
      "correct_index": 1,
      "is_correct": true,
      "explanation": "..."
    }
  ],
  "submitted_at": "ISO timestamp"
}
```

**Indexes needed:** `submitted_at DESC` for history queries.

## User Stats Updated by Practice

| Field | Update Rule |
|-------|-------------|
| totalXP | Increment by `xp_earned` |
| quizzesCompleted | Increment by 1 |
| averageScore | Rolling average: `(old_avg * old_count + new_score) / (old_count + 1)` |

## Query Patterns

- `practice_results/{userId}/sessions` ordered by `submitted_at DESC` for history
- `practice_results/{userId}/sessions` limit 10 for recent sessions used in stats
- `users/{userId}` read `totalXP`, `quizzesCompleted`, `averageScore`