# Client API Documentation

## Overview

The Focus Set scheduler uses a simple 3-set model:

| Set | Description |
|-----|-------------|
| **New** | Problems never seen (~130 remaining) |
| **Focus** | Currently learning (20 problems) |
| **Old** | Previously mastered (grows over time) |

**Goal:** Answer 90% of Focus problems correctly to advance to the next set.

## API Endpoints

### 1. POST `/api/session` - Start a Session

Creates a new study session and initializes the Focus set if needed.

**Request:**
```json
{
  "userId": "user-id-here"
}
```

**Response:**
```json
{
  "sessionId": "cmn8qu4yk0000frnfnt33vwr5",
  "focusCount": 20,
  "focusCorrectCount": 6,
  "masteryPercent": 30,
  "newCount": 130,
  "oldCount": 0
}
```

**Client should:**
1. Store `sessionId` for subsequent requests
2. Display initial progress (e.g., "6/20 correct (30%)")
3. Call `/api/next` to get the first problem

---

### 2. POST `/api/next` - Get Next Problem

Returns the next problem to display based on the Focus Set algorithm.

**Request:**
```json
{
  "userId": "user-id-here",
  "sessionId": "session-id-here",
  "recentWrong": ["problem-id-1", "problem-id-2"],
  "recentShown": ["problem-id-3", "problem-id-4", "problem-id-5"],
  "consecutiveWrong": 0
}
```

| Field | Type | Description |
|-------|------|-------------|
| `userId` | string | Required. User identifier |
| `sessionId` | string | Optional. Current session ID |
| `recentWrong` | string[] | Problem IDs answered wrong (retry queue) |
| `recentShown` | string[] | Last ~10 problem IDs shown (avoid repeats) |
| `consecutiveWrong` | number | Count of wrong answers in a row |

**Response:**
```json
{
  "problem": {
    "problemId": "cmn8mvfuz0006a0nfapl6i54j",
    "problemText": "大化の改新",
    "groupId": "cmn8mvfut0001a0nf43v8lf7v",
    "type": "hard",
    "pCorrect": 0.35
  },
  "done": false,
  "mastered": false,
  "focusStatus": {
    "newCount": 130,
    "focusCount": 20,
    "oldCount": 0,
    "focusCorrectCount": 6,
    "masteryPercent": 30,
    "mastered": false
  }
}
```

**Problem Types:**
| Type | Description |
|------|-------------|
| `hard` | Low p_correct (< 50%), needs practice |
| `easy` | High p_correct (> 80%), confidence booster |
| `random` | Random pick from Old set |
| `retry` | Previously wrong, retrying after delay |

**Special Responses:**

When Focus set is mastered (90% correct):
```json
{
  "problem": null,
  "done": false,
  "mastered": true,
  "message": "Focus set mastered! Ready to advance.",
  "focusStatus": { "mastered": true, ... }
}
```

When no problems available:
```json
{
  "problem": null,
  "done": true,
  "mastered": false,
  "message": "No more problems available",
  "focusStatus": { ... }
}
```

**Client should:**
1. Track `recentWrong` - add problem IDs when answered wrong, remove when answered correct
2. Track `recentShown` - append each shown problem ID (keep last 10)
3. Track `consecutiveWrong` - increment on wrong, reset to 0 on correct
4. Check `mastered` flag to show celebration modal
5. Check `done` flag to end session
6. Update UI progress bar from `focusStatus`

---

### 3. POST `/api/answer` - Submit Answer

Records the user's answer and updates problem state.

**Request:**
```json
{
  "userId": "user-id-here",
  "problemId": "problem-id-here",
  "sessionId": "session-id-here",
  "userInput": "645",
  "responseMs": 2500,
  "presentedType": "hard"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `userId` | string | Required. User identifier |
| `problemId` | string | Required. Problem being answered |
| `sessionId` | string | Required. Current session ID |
| `userInput` | string | Required. User's answer |
| `responseMs` | number | Required. Time taken in milliseconds |
| `presentedType` | string | Required. How problem was presented: `easy`, `hard`, `random`, `retry` |

**Response:**
```json
{
  "wasCorrect": true,
  "correctAnswer": "645",
  "answerDescription": "蒸しご（645）ろし、蘇我氏を倒す",
  "focusStatus": {
    "newCount": 130,
    "focusCount": 20,
    "oldCount": 0,
    "focusCorrectCount": 7,
    "masteryPercent": 35,
    "mastered": false
  },
  "justMastered": false,
  "newFocusCount": 0
}
```

**When mastery is reached:**
```json
{
  "wasCorrect": true,
  "correctAnswer": "645",
  "answerDescription": "...",
  "focusStatus": {
    "masteryPercent": 90,
    "mastered": true,
    ...
  },
  "justMastered": true,
  "newFocusCount": 20
}
```

**Client should:**
1. Display correct/incorrect feedback with `wasCorrect`
2. Show correct answer and description if wrong
3. Update progress bar from `focusStatus`
4. If `wasCorrect`: remove from `recentWrong`, reset `consecutiveWrong` to 0
5. If `!wasCorrect`: add to `recentWrong`, increment `consecutiveWrong`
6. If `justMastered`: show celebration modal

---

### 4. POST `/api/promote` - Advance to Next Focus Set

Manually promotes the Focus set after mastery celebration.

**Request:**
```json
{
  "userId": "user-id-here"
}
```

**Response:**
```json
{
  "success": true,
  "newFocusCount": 20,
  "focusCount": 20,
  "focusCorrectCount": 0,
  "masteryPercent": 0,
  "newCount": 110,
  "oldCount": 20
}
```

**Client should:**
1. Call this when user clicks "Continue" after mastery celebration
2. Reset local state (`recentWrong`, `recentShown`, `consecutiveWrong`)
3. Update UI with new counts
4. Call `/api/next` to get first problem of new Focus set

---

### 5. GET `/api/stats` - Get User Statistics

Returns overall progress statistics.

**Request:**
```
GET /api/stats?userId=user-id-here
```

**Response:**
```json
{
  "totalProblems": 150,
  "newCount": 110,
  "focusCount": 20,
  "focusCorrectCount": 18,
  "oldCount": 20,
  "masteryPercent": 90,
  "todayStats": {
    "answered": 45,
    "correct": 38,
    "accuracy": 0.844
  }
}
```

**Client should:**
1. Call on app load to show initial state
2. Call after session ends to refresh stats

---

## Client State Management

The client must track these values locally:

```typescript
interface ClientState {
  // Session
  sessionId: string | null;

  // Current problem
  currentProblem: Problem | null;

  // Retry queue - problems answered wrong that need retry
  recentWrong: string[];  // max 5 items

  // Recently shown - to avoid immediate repeats
  recentShown: string[];  // max 10 items

  // Consecutive wrong counter - for easy problem selection
  consecutiveWrong: number;

  // Session stats
  sessionCorrect: number;
  sessionTotal: number;

  // Focus status (from API responses)
  focusStatus: FocusStatus;
}
```

---

## Typical Flow

```
┌─────────────────────────────────────────────────────────┐
│  1. POST /api/session                                   │
│     └─► Store sessionId, display initial progress       │
└─────────────────────────────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│  2. POST /api/next                                      │
│     └─► Display problem, start timer                    │
└─────────────────────────────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│  3. User submits answer                                 │
│                                                         │
│  4. POST /api/answer                                    │
│     ├─► If correct: show ✓, remove from recentWrong    │
│     └─► If wrong: show ✗, add to recentWrong           │
└─────────────────────────────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│  5. Check response flags                                │
│     ├─► If justMastered: show celebration modal        │
│     │   └─► User clicks Continue → POST /api/promote   │
│     └─► Else: goto step 2 (next problem)               │
└─────────────────────────────────────────────────────────┘
```

---

## Algorithm Notes

### Problem Selection Priority

1. **Retry queue** - Wrong answers come back after 1-2 other problems
2. **Easy problem** - If 2+ consecutive wrong, serve an easy one
3. **Session queue** - Built with:
   - 3 Easy (p > 80%) from Focus + Old
   - 7 Hard (p < 50%, fallback to < 70%) from Focus
   - 2 Random from Old

### p_correct Calculation

Exponential decay over last 10 attempts:
```
weight(i) = e^(-0.1 * hours_since_attempt_i)
p_correct = Σ(weight_i * correct_i) / Σ(weight_i)
```

New items (never answered): `p_correct = 0.35`

### Mastery Rules

- Focus set: 20 problems
- Mastery threshold: 90% (18/20 must have `lastResult = correct`)
- Once a problem is correct, it won't be re-served in the Focus set
- This prevents accidental mastery loss from re-answering correct problems wrong

---

## Error Handling

All endpoints return errors in this format:
```json
{
  "error": "Error message here"
}
```

HTTP status codes:
- `400` - Bad request (missing required fields)
- `500` - Server error

**Client should:**
1. Check for `error` field in response
2. Display user-friendly error message
3. Allow retry or return to safe state
