# Branching Conversation Scenarios

## Concept

A karaoke-style guided Japanese conversation practice where users follow scripted dialogues with branching paths. Each scenario is a tree of dialogue nodes — the NPC speaks (with audio), then the user **speaks their chosen response aloud**, each leading to a different conversation branch.

**Target audience: Indonesian learners of Japanese.** All translations and UI hints are in Bahasa Indonesia.

No AI required. All content is seeded.

> **IMPORTANT — Audio is a core feature, not optional.** This is a *speaking* practice tool, not a chat app. Users must hear NPC lines and speak their responses out loud. Audio is Phase 1, not Phase 2.

---

## Example Flow

**Scenario: Ordering at a Restaurant (レストランで注文する)**

```
NPC: 🔊 いらっしゃいませ！何名様ですか？
     (Selamat datang! Berapa orang?)
         │
         ├─► User: 🎙️ 一人です。 (Satu orang.)
         │       → NPC: 🔊 カウンター席へどうぞ。 (Silakan duduk di meja bar.)
         │             ├─► User: 🎙️ ありがとうございます。 (Terima kasih.)
         │             │       → NPC: 🔊 メニューはこちらです。 (Ini menunya.)
         │             │             └─► ...lanjut
         │             └─► User: 🎙️ 窓側の席はありますか？ (Apakah ada kursi dekat jendela?)
         │                     → NPC: 🔊 申し訳ございません、カウンターのみです。
         │                            (Maaf, hanya ada meja bar.)
         │                             └─► ...lanjut
         │
         ├─► User: 🎙️ 二人です。 (Dua orang.)
         │       → NPC: 🔊 テーブル席へご案内します。 (Saya antar ke meja.)
         │             └─► ...lanjut
         │
         └─► User: 🎙️ 予約した田中です。 (Saya Tanaka, sudah reservasi.)
                 → NPC: 🔊 田中様ですね。お待ちしておりました。
                        (Tanaka-sama ya. Kami sudah menunggu Anda.)
                       └─► ...lanjut
```

---

## Data Model

### `conversation_scenarios`

| Column        | Type        | Description                                    |
|---------------|-------------|------------------------------------------------|
| id            | bigint PK   |                                                |
| title         | string      | e.g. "Ordering at a Restaurant"                |
| title_jp      | string      | e.g. "レストランで注文する"                       |
| description   | text        | Brief scenario context for the user            |
| category      | string      | restaurant, station, hospital, shopping, etc.  |
| jlpt_level    | tinyint     | 5 (easiest) → 1 (hardest)                     |
| difficulty    | enum        | beginner, intermediate, advanced               |
| image_url     | string null | Optional scene illustration                    |
| timestamps    |             |                                                |

### `scenario_nodes`

Each node is one "turn" in the conversation — either an NPC line or a user choice point.

| Column              | Type        | Description                                         |
|---------------------|-------------|-----------------------------------------------------|
| id                  | bigint PK   |                                                     |
| scenario_id         | FK          | belongs to scenario                                 |
| parent_id           | FK null     | self-referencing; null = root node                  |
| speaker             | enum        | `npc` or `user`                                     |
| japanese_text       | text        | The line in Japanese                                |
| romaji              | text null   | Romanized reading                                   |
| indonesian_translation | text        | Bahasa Indonesia translation                                     |
| hint                | text null   | Grammar/context hint shown to user                  |
| sort_order          | int         | Order among siblings (for user choices)             |
| is_endpoint         | boolean     | True if this node ends a conversation path          |
| timestamps          |             |                                                     |

**Tree structure:** A node with `speaker = npc` is followed by one or more child nodes with `speaker = user` (the choices). Each user choice node then has one child `npc` node (the NPC's response to that choice), and so on alternating.

```
npc (root, parent_id=null)
├── user (choice A, parent_id=root)
│   └── npc (response to A)
│       ├── user (choice A1)
│       │   └── npc (response to A1) [is_endpoint=true]
│       └── user (choice A2)
│           └── npc (response to A2)
│               └── ...
├── user (choice B, parent_id=root)
│   └── npc (response to B)
│       └── ...
└── user (choice C, parent_id=root)
    └── npc (response to C)
        └── ...
```

### `user_scenario_progress`

Tracks which scenarios a user has attempted and which paths they've explored.

| Column        | Type        | Description                                    |
|---------------|-------------|------------------------------------------------|
| id            | bigint PK   |                                                |
| user_id       | FK          |                                                |
| scenario_id   | FK          |                                                |
| current_node_id | FK null   | Where the user currently is (null = completed) |
| path_taken    | JSON        | Array of node IDs the user chose               |
| is_completed  | boolean     | At least one endpoint reached                  |
| times_played  | int         | How many times replayed                        |
| timestamps    |             |                                                |

---

## User Flow

1. **Browse scenarios** — list page filtered by JLPT level / category
2. **Select a scenario** — see title, description, scene image, difficulty
3. **Start conversation** — NPC speaks first (root node), audio plays automatically 🔊
4. **User picks a response** — shown 2-3 Japanese options with optional romaji/Indonesian hints (togglable)
5. **User speaks the line** — user reads the chosen response aloud 🎙️ (can replay their own audio to self-check)
6. **NPC responds** — audio plays for NPC's next line based on chosen branch 🔊
7. **Repeat** until an endpoint node is reached
8. **Summary screen** — show the full path taken, highlight new vocab, option to replay and explore other branches. User can replay all audio from the conversation.

### Replay & Exploration

- After completing a path, user can restart and pick different branches
- Progress tracking shows which branches have been explored (e.g. "3/7 paths explored")
- Visual tree map (optional) showing explored vs unexplored branches

---

## API Endpoints

```
GET    /api/v1/scenarios                    — list all (filterable by category, jlpt_level)
GET    /api/v1/scenarios/{id}               — scenario detail + full node tree
POST   /api/v1/scenarios/{id}/start         — begin or resume a scenario
POST   /api/v1/scenarios/{id}/choose/{nodeId} — pick a user choice, returns next NPC node + new choices
GET    /api/v1/scenarios/{id}/progress      — user's progress for this scenario
```

---

## Seeder Structure

Each scenario is a self-contained seeder file defining the full tree:

```php
// database/seeders/Scenarios/RestaurantOrderingSeeder.php

$scenario = ConversationScenario::create([
    'title' => 'Ordering at a Restaurant',
    'title_jp' => 'レストランで注文する',
    'category' => 'restaurant',
    'jlpt_level' => 5,
    'difficulty' => 'beginner',
]);

$root = $scenario->nodes()->create([
    'speaker' => 'npc',
    'japanese_text' => 'いらっしゃいませ！何名様ですか？',
    'romaji' => 'Irasshaimase! Nanmei-sama desu ka?',
    'indonesian_translation' => 'Selamat datang! Berapa orang?',
]);

$choiceA = $root->children()->create([
    'scenario_id' => $scenario->id,
    'speaker' => 'user',
    'japanese_text' => '一人です。',
    'romaji' => 'Hitori desu.',
    'indonesian_translation' => 'Satu orang.',
    'sort_order' => 1,
]);

// ... continue building tree
```

---

## Scenario Categories (Initial)

| Category     | Example Scenarios                         | JLPT |
|-------------|-------------------------------------------|------|
| restaurant  | Ordering food, asking for the bill        | N5   |
| shopping    | Buying clothes, asking for sizes          | N5   |
| station     | Buying a ticket, asking for directions    | N5   |
| hospital    | Describing symptoms, making appointments  | N4   |
| workplace   | Self-introduction, asking for help        | N4   |
| phone       | Making a reservation, calling in sick     | N3   |
| bank        | Opening an account, currency exchange     | N3   |

---

## Open Questions

### 1. Should user choices show Japanese only or Japanese + Bahasa Indonesia?

**Recommendation: Togglable, default based on JLPT level.**
- N5–N4 scenarios default to showing Japanese + romaji + terjemahan Bahasa Indonesia
- N3+ scenarios default to Japanese only
- User can override via a toggle button in the conversation UI at any time

This way beginners aren't overwhelmed, advanced learners get immersion, and everyone can adjust to their comfort level.

### 2. ~~Audio/TTS~~ — RESOLVED: Audio is Phase 1 Core

**Audio is essential, not optional.** This is a speaking practice tool.

#### NPC Audio (listening)
- Use browser Web Speech API (`speechSynthesis` with `ja-JP` voice) to play NPC lines automatically
- Add `audio_url` nullable column to `scenario_nodes` for future pre-recorded/high-quality TTS override
- When `audio_url` is set, use that instead of browser TTS

#### User Audio (speaking)
- After picking a response, the UI shows the Japanese text as a "read aloud" prompt
- User clicks a 🎙️ mic button → browser records via MediaRecorder API
- User can replay their own recording to self-check pronunciation
- No speech-to-text grading in Phase 1 — the goal is to practice speaking out loud, self-assessment
- Phase 2 (optional): Web Speech Recognition API for basic pronunciation feedback

#### Audio Controls
- 🔊 Replay NPC line button on each NPC bubble
- 🎙️ Record / 🔁 Re-record on each user bubble
- ▶️ Play back own recording
- Global speed control (0.75x / 1x / 1.25x) for NPC audio

### 3. Scoring / XP?

**Recommendation: Yes, keep it simple.**
- Award XP on completing a path (reaching an endpoint node)
- Bonus XP for exploring all branches of a scenario (encourages replay)
- No per-choice scoring — avoid punishing users for picking "wrong" branches since all paths are valid learning
- Tie into the existing user XP/level system if one exists

### 4. Should some choices be marked as "more natural" or "more polite"?

**Recommendation: Yes, add a `tone` enum to user choice nodes.**
- Values: `casual`, `polite`, `formal`, `humorous`
- Show a small label/badge next to choices after the user picks (not before, to avoid biasing)
- On the summary screen, explain the register differences: "Kamu memilih bentuk kasual — dalam situasi ini, bentuk sopan lebih umum digunakan karena..."
- This is one of the hardest things to learn in Japanese, and guided scenarios are the perfect place to teach it

### 5. Free-text input mode?

**Recommendation: No for Phase 1, optional Phase 2.**
- Multiple-choice is the core experience — it keeps things achievable and fun
- Free-text adds complexity (fuzzy matching, typo tolerance, multiple valid answers) with little benefit at beginner levels
- If added later: only for N3+ scenarios, with lenient matching (ignore particles, accept synonym kanji, kana-only input OK)

### 6. Time limit per response?

**Recommendation: No, but add an optional "challenge mode".**
- Default: no time limit. Language learning should be low-pressure, users need time to read and think
- Optional "challenge mode" toggle: 15-second timer per choice, awards bonus XP. For users who want to simulate real conversation speed
- Never force time limits — always opt-in
