# Signal-Learn PRD — Product Requirements Document
**Version:** 1.1 (with Teacher-Generated Join Codes)  
**Status:** ✅ Production-Ready for Development  
**Date:** August 2026  
**Timeline:** 5 weeks to launch

---

## TABLE OF CONTENTS

1. [Executive Summary](#1-executive-summary)
2. [Problem Statement](#2-problem-statement)
3. [Product Vision & Goals](#3-product-vision--goals)
4. [Target Users](#4-target-users)
5. [Feature Set (MVP 1.1)](#5-feature-set-mvp-11)
6. [User Flows](#6-user-flows)
7. [Data Model & Database Design](#7-data-model--database-design)
8. [Technical Architecture](#8-technical-architecture)
9. [UI/UX & Wireframes](#9-uiux--wireframes)
10. [API Endpoints](#10-api-endpoints)
11. [Success Metrics](#11-success-metrics)
12. [Scope & Constraints](#12-scope--constraints)
13. [Development Roadmap](#13-development-roadmap)
14. [Launch & Rollout Plan](#14-launch--rollout-plan)
15. [Appendix: Join Codes Deep-Dive](#15-appendix-join-codes-deep-dive)

---

## 1. EXECUTIVE SUMMARY

### Product Overview
**Signal-Learn** adalah aplikasi web real-time untuk guru/fasilitator memantau status pembelajaran murid menggunakan sistem traffic light (Red/Yellow/Green). Guru membuat sesi pembelajaran, berbagi link atau **generate join codes** unik ke murid, dan melihat dashboard real-time yang menunjukkan berapa banyak murid dalam setiap status.

**Key Innovation (MVP 1.1):** Teacher-generated join codes—guru dapat membuat, customize, dan revoke codes kapan saja untuk memberikan fleksibilitas akses kepada murid.

### Key Value Proposition
- **Guru:** Insight real-time tentang kesehatan kelas tanpa menanyakan satu-satu → lebih efisien mengalokasikan bantuan
- **Murid:** Cara sederhana signal kebutuhan mereka (tap tombol) tanpa harus bicara di depan kelas
- **Scalable:** Bekerja untuk 5 murid hingga 100+ murid; multi-teacher multi-session support

### Target Users
1. **Primary:** Guru/Educator (sekolah K-12, higher ed, kursus)
2. **Secondary:** Fasilitator workshop/training korporat, tutor online, trainer komunitas
3. **Tertiary:** Superadmin (untuk analytics & usage monitoring)

### Core Metrics
- Status update latency: **< 2 seconds**
- Uptime: **99.5%** during school hours
- Session support: **5 to 1000+ students** per session
- Timeline: **5 weeks** to production launch

---

## 2. PROBLEM STATEMENT

### Current Pain Points

1. **Guru kesulitan mengetahui siapa yang struggling** 
   - Harus berkeliling kelas, menanyakan satu-satu, atau menunggu murid minta bantuan
   - Tidak ada signal yang jelas dari murid yang merasa malu/ragu

2. **Murid malu/ragu untuk signal kebutuhan**
   - Banyak yang diam ketimbang ngangkat tangan/berbicara di depan kelas
   - Social anxiety mencegah mereka minta bantuan

3. **Sulit track progress sesi pembelajaran**
   - Tidak tahu berapa lama sesi berlangsung dengan akurat
   - Tidak ada history siapa saja yang perlu follow-up

4. **Tidak ada data historis**
   - Guru tidak bisa review atau analisa pola masalah pembelajaran
   - Sulit identify topik yang consistently problematic

### Opportunity
Dengan sistem visual yang sederhana (tap tombol warna, bukan text) + **flexible join codes**, murid akan lebih nyaman signal status → guru bisa proaktif membantu, bukan reaktif.

---

## 3. PRODUCT VISION & GOALS

### Objective 1: Enable Real-Time Visibility
- Guru bisa lihat dalam 1 dashboard berapa murid Red/Yellow/Green saat ini
- Update live tanpa perlu refresh halaman (polling/WebSocket)
- Status berubah dalam < 2 detik setelah murid tap tombol

### Objective 2: Lower Barrier to Entry for Students
- Murid tidak perlu login atau input kompleks
- Cukup tap tombol, automatic reset setelah 5 menit
- Mobile-first responsive UI
- **Flexible join via code OR link** (murid pilih cara)

### Objective 3: Persist Historical Data
- Setiap sesi disimpan dengan timestamp, durasi, dan state changes
- Guru bisa review sesi lalu untuk pattern recognition

### Objective 4: Support Multi-Instructor Multi-Session
- Guru bisa manage banyak course/sesi sekaligus
- Setiap sesi punya join method yang fleksibel (code + link)
- Dashboard guru menunjukkan semua sesi yang active & past

### Objective 5: Enable Teacher Flexibility with Join Codes
- Guru dapat **generate codes kapan saja** (pre-session atau live)
- **Auto-generated atau custom codes** (guru pilih)
- **Revoke codes anytime** (bahkan mid-session)
- **Track code usage** (siapa pakai kode apa)

---

## 4. TARGET USERS

### Persona 1: K-12 Teacher
- **Context:** Mengajar 25-30 siswa di kelas
- **Pain:** Tidak tahu siapa yang struggling, students takut raise hand
- **Usage:** Generate code "MATH-101", announce verbally, monitor real-time

### Persona 2: Corporate Facilitator
- **Context:** Memfasilitasi workshop/training untuk 20-50 peserta
- **Pain:** Q&A tidak produktif, banyak yang silent
- **Usage:** Generate multiple codes untuk group-based activity

### Persona 3: Online Tutor
- **Context:** 1-on-1 atau small group tutoring
- **Pain:** Tidak bisa observe non-verbal cues online
- **Usage:** Share code/link via Zoom chat, monitor student engagement

### Persona 4: Superadmin/Organization
- **Context:** Tracking app usage across multiple teachers/schools
- **Pain:** No visibility into which courses are working, adoption metrics
- **Usage:** View analytics dashboard, identify problem topics

---

## 5. FEATURE SET (MVP 1.1)

### 5.1 TEACHER FEATURES

#### A. Authentication
- **Google OAuth Login**
  - Click "Login with Google" → OAuth flow → redirect ke dashboard
  - Auto-create user profile (name, email, Google ID)
  - No passwords, no account creation friction

#### B. Course Management
- **Create Course**
  - Form: Title, Description, Date, Time, Duration (30-120 menit)
  - Auto-generate unique session code (e.g., "SIGNAL-ABC-123")
  - Save to database with metadata
  
- **Edit Course** (sebelum sesi start)
  - Modify: title, description, date, time
  - Locked after session starts
  
- **Delete Course**
  - Soft delete (archive) untuk historical retention
  
- **List/View Courses**
  - Table: Title, Date, Duration, Status (Draft/Active/Completed)
  - Filter: Active, Past, All
  - Sort: Date (newest first)

#### C. Join Code Management (NEW - MVP 1.1)
- **Generate Join Codes**
  - Dapat generate **sebelum OR saat session berjalan**
  - Opsi: **Auto-generated** (e.g., "SIGNAL-ABC-123") atau **Custom** (guru input, e.g., "MATH-101")
  - Format validation: 3-50 alphanumeric + hyphens, case-insensitive
  
- **View & Manage Codes**
  - Dashboard menunjukkan: list all codes, status (active/revoked), participant count per code
  - Buttons: [Copy], [Revoke], [Reactivate]
  
- **Revoke & Reactivate Codes**
  - **Revoke:** Code menjadi invalid untuk new joins
    - Students already joined tetap stay (not kicked)
    - Can revoke anytime (even mid-session)
  - **Reactivate:** Re-enable code (optional, phase 2)

#### D. Session Control (During Live Session)
- **Start Session**
  - Button "Start Learning" → Activate session, start timer
  - Display shareable link: `signal-learn.web.id/session/SIGNAL-ABC-123`
  - Show all active codes with usage counts
  - Copy buttons for both link + codes
  
- **Live Dashboard**
  - **Status Summary Card:**
    - 🟢 Green: X murid (lancar)
    - 🟡 Yellow: X murid (pertanyaan)
    - 🔴 Red: X murid (butuh bantuan)
    - Total participants: X
    - Elapsed time: HH:MM (real-time)
  
  - **Active Codes Display:**
    - Code name, status, how many students joined via this code
    - Real-time update as students join
  
  - **Real-time Updates:**
    - Auto-refresh setiap 1-2 detik (polling atau WebSocket)
    - No manual refresh needed

- **End Session**
  - Button "End Learning" → Stop accepting new participants, freeze session
  - Store session data to database
  - Show summary: total participants, codes used, final status breakdown

#### E. Alerts
- **In-App Alert:**
  - Alert card: "⚠️ 5+ students now in Red status"
  - Dismissible
  - Threshold configurable (default = 5 Red)

#### F. Session History & Review
- **View Past Sessions**
  - List all completed sessions
  - Click to view: duration, participant count, codes used, final status distribution
  
- **Export** (Phase 2)
  - CSV export untuk raw data

---

### 5.2 STUDENT FEATURES (No Login Required)

#### A. Join Session
**Access:** Student opens link or enters code

**Method 1: Join via Code (NEW)**
- Open app → "Enter Join Code" field
- Type code (e.g., "MATH-101")
- System validates:
  - ✓ Code format valid
  - ✓ Code is active (not revoked)
  - ✓ Session is open
- Proceed to course info if valid
- Error message if invalid: "Code not found or expired"

**Method 2: Join via Link (Original)**
- Open direct link → `signal-learn.web.id/session/SIGNAL-ABC-123`
- Skip to course info directly

**Join Flow (Both Methods):**
- Show course title, instructor name
- Prompt: "What's your name?" (optional, teacher configurable)
- If anonymous mode → go straight to status board
- If name required → input name → then go to status board
- Can join/rejoin throughout session

#### B. Status Indicator UI
- **Large Tap Buttons (3 colors):**
  - 🟢 **Green** — "I'm doing well, keep going"
  - 🟡 **Yellow** — "I have a question, but can keep working"
  - 🔴 **Red** — "I need help urgently"
  
- **Behavior:**
  - Tap color → button animates (slight scale/glow)
  - Status updates immediately (visible to teacher within 2 sec)
  - Auto-reset to neutral after 5 minutes if no new tap
  - Display: "Your status: [Color] — will reset in 5 min" (countdown)
  - Student dapat re-tap anytime untuk change status atau refresh timer

#### C. Session Info Display
- Show course title, instructor name, elapsed time, duration remaining
- Display "Connection: ✓ Connected" indicator

---

### 5.3 SUPERADMIN FEATURES

#### A. Dashboard Overview
- **Aggregate Stats:**
  - Total teachers, total sessions, total participants this month
  - Top 5 courses by participation
  
- **Course Analytics:**
  - Per-course: session count, avg participants, avg Red/Yellow/Green distribution
  - Identify problem courses (high Red percentage)

#### B. User Management (Minimal MVP)
- View all teachers (name, email, created date)
- View all sessions (date, participants, status distribution)

---

## 6. USER FLOWS

### 6.1 Teacher Creates & Runs a Session

```
1. Teacher logs in with Google OAuth
2. Dashboard shows: "Create New Course" button + list of past courses
3. Click "Create" → Form (Title, Description, Date, Time, Duration)
4. Submit → System generates unique session code (e.g., "SIGNAL-ABC-123")
5. Course saved as Draft, shown in list
6. Click course → Detail page
7. See option: Generate Join Codes
   a. Click "Generate Code"
   b. Choose: Auto-generate or Enter Custom
   c. Auto-generated: "SIGNAL-ABC-123"
   d. Or type custom: "MATH-101"
   e. Submit → Code created, shown in list
8. Can generate multiple codes: "MATH-101", "LATE-JOIN", etc.
9. Click "Start Learning" → Activate session, generate shareable link
10. Dashboard shows:
    - Live Red/Yellow/Green counts
    - Active codes + usage counts
    - Copy buttons for all codes + link
11. Teacher shares codes/link (copy, WhatsApp, verbal announcement, etc.)
12. Students start joining (via code or link)
13. Teacher sees live dashboard updating in real-time
14. Can generate NEW code anytime (e.g., "LATE-JOIN" for latecomers)
15. Can REVOKE old codes if needed
16. Teacher clicks "End Learning" → Session frozen
17. Summary shown: total time, participants, codes used, final status
18. Session archived in "Past Sessions"
```

### 6.2 Student Joins & Signals Status

```
1. Student receives code from teacher (verbally, WhatsApp, or direct link)
2. Opens app
3. OPTION A: Enter Code
   - Type "MATH-101" in code field
   - System validates → shows course name "Math 101 - Algebra"
   - Asks for name (optional)
   - Proceeds to status board
4. OPTION B: Use Direct Link
   - Clicks link → auto-redirects to session
   - Shows course name
   - Asks for name (optional)
   - Proceeds to status board
5. Sees 3 large buttons: 🟢 🟡 🔴
6. Taps status (e.g., Green)
   - Button highlights
   - Timer starts (5 minutes)
   - Countdown displayed: "Will reset in 4:59"
   - Teacher sees updated count instantly
7. During session, student can:
   - Re-tap if status changes
   - Refresh timer by tapping same status again
8. After 5 minutes with no tap:
   - Auto-reset to neutral (Gray)
   - Teacher count updates
9. Session ends (teacher clicks End)
   - Student UI shows "Session ended, thank you!"
   - Can no longer tap or rejoin
```

### 6.3 Superadmin Monitors Usage

```
1. Superadmin logs in
2. Sees aggregate dashboard:
   - Total sessions this month, avg participants, etc.
3. Clicks "Courses" → Table of all courses
   - Identifies: "Advanced Math" has 60% Red status rate
   - Flag as problem course
4. Can drill into: specific session data, participants, code breakdown
```

---

## 7. DATA MODEL & DATABASE DESIGN

### 7.1 Database Entities (8 Total)

#### Entity 1: User (Teachers)
```
Table: users
├─ id: BIGINT PRIMARY KEY AUTO_INCREMENT
├─ google_id: VARCHAR(255) UNIQUE NOT NULL
├─ email: VARCHAR(255) UNIQUE NOT NULL
├─ name: VARCHAR(255)
├─ profile_picture_url: VARCHAR(500) NULLABLE
├─ created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
├─ updated_at: TIMESTAMP
└─ is_active: BOOLEAN DEFAULT TRUE

Indexes: PRIMARY (id), UNIQUE (google_id, email), INDEX (created_at)
```

#### Entity 2: Course (Learning Session Metadata)
```
Table: courses
├─ id: BIGINT PRIMARY KEY AUTO_INCREMENT
├─ instructor_id: BIGINT NOT NULL (FK → users.id)
├─ title: VARCHAR(255) NOT NULL
├─ description: TEXT NULLABLE
├─ date: DATE NOT NULL
├─ start_time: TIME NOT NULL
├─ duration_minutes: INT NOT NULL (30-120)
├─ session_code: VARCHAR(20) UNIQUE NOT NULL (e.g., "SIGNAL-ABC-123")
├─ allow_anonymous: BOOLEAN DEFAULT FALSE
├─ status: ENUM('draft', 'active', 'completed') DEFAULT 'draft'
├─ created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
├─ updated_at: TIMESTAMP
└─ deleted_at: TIMESTAMP NULLABLE (soft delete)

Indexes: PRIMARY (id), FK (instructor_id), UNIQUE (session_code), INDEX (status)
```

#### Entity 3: CourseSession (Active Session Instance)
```
Table: course_sessions
├─ id: BIGINT PRIMARY KEY AUTO_INCREMENT
├─ course_id: BIGINT NOT NULL (FK → courses.id)
├─ session_start_time: TIMESTAMP NOT NULL
├─ session_end_time: TIMESTAMP NULLABLE
├─ is_active: BOOLEAN DEFAULT TRUE
├─ created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
└─ updated_at: TIMESTAMP

Indexes: PRIMARY (id), FK (course_id), INDEX (is_active, session_start_time)
```

#### Entity 4: JoinCode (Teacher-Generated Codes) [NEW MVP 1.1]
```
Table: join_codes
├─ id: BIGINT PRIMARY KEY AUTO_INCREMENT
├─ session_id: BIGINT NOT NULL (FK → course_sessions.id)
├─ code: VARCHAR(50) NOT NULL (e.g., "MATH-101")
├─ is_custom: BOOLEAN DEFAULT FALSE (auto-gen vs manual)
├─ status: ENUM('active', 'revoked') DEFAULT 'active'
├─ generated_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
├─ revoked_at: TIMESTAMP NULLABLE
├─ created_by: BIGINT NOT NULL (FK → users.id)
├─ updated_at: TIMESTAMP
└─ usage_count: INT DEFAULT 0 (how many students joined via this code)

Indexes: 
  - PRIMARY (id)
  - FK (session_id), FK (created_by)
  - UNIQUE (session_id, code) — Unique per session
  - INDEX (status, revoked_at)
```

#### Entity 5: Participant (Students)
```
Table: participants
├─ id: BIGINT PRIMARY KEY AUTO_INCREMENT
├─ session_id: BIGINT NOT NULL (FK → course_sessions.id)
├─ join_code_id: BIGINT NULLABLE (FK → join_codes.id)
├─ join_method: ENUM('code', 'link') NOT NULL
├─ name: VARCHAR(255) NULLABLE (anonymous if NULL)
├─ join_timestamp: TIMESTAMP NOT NULL
├─ leave_timestamp: TIMESTAMP NULLABLE
├─ is_active: BOOLEAN DEFAULT TRUE
├─ created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
└─ updated_at: TIMESTAMP

Indexes:
  - PRIMARY (id)
  - FK (session_id), FK (join_code_id)
  - INDEX (join_method, join_timestamp)
  - INDEX (is_active)
```

#### Entity 6: StatusEvent (Status Change Log)
```
Table: status_events
├─ id: BIGINT PRIMARY KEY AUTO_INCREMENT
├─ participant_id: BIGINT NOT NULL (FK → participants.id)
├─ status: ENUM('red', 'yellow', 'green') NOT NULL
├─ triggered_at: TIMESTAMP NOT NULL (when student tapped)
├─ auto_reset_at: TIMESTAMP NOT NULL (5 min from triggered_at)
├─ is_reset: BOOLEAN DEFAULT FALSE
├─ created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
└─ updated_at: TIMESTAMP

Indexes:
  - PRIMARY (id)
  - FK (participant_id) ON DELETE CASCADE
  - INDEX (status, triggered_at)
  - INDEX (is_reset)

Note: Append-only log (immutable after creation)
```

#### Entity 7: SessionSummary (End-of-Session Aggregate)
```
Table: session_summaries
├─ id: BIGINT PRIMARY KEY AUTO_INCREMENT
├─ session_id: BIGINT UNIQUE NOT NULL (FK → course_sessions.id)
├─ total_participants: INT NOT NULL
├─ participants_via_link: INT DEFAULT 0
├─ participants_via_code: INT DEFAULT 0
├─ codes_generated_count: INT DEFAULT 0
├─ codes_revoked_count: INT DEFAULT 0
├─ final_red_count: INT DEFAULT 0
├─ final_yellow_count: INT DEFAULT 0
├─ final_green_count: INT DEFAULT 0
├─ duration_seconds: INT NOT NULL
├─ created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
└─ updated_at: TIMESTAMP

Indexes:
  - PRIMARY (id)
  - FK (session_id)
  - UNIQUE (session_id)

Note: Computed at session end (not real-time)
```

#### Entity 8: AdminUser (Superadmin)
```
Table: admin_users
├─ id: BIGINT PRIMARY KEY AUTO_INCREMENT
├─ email: VARCHAR(255) UNIQUE NOT NULL
├─ role: ENUM('admin', 'superadmin') DEFAULT 'admin'
├─ created_at: TIMESTAMP DEFAULT CURRENT_TIMESTAMP
├─ updated_at: TIMESTAMP
└─ is_active: BOOLEAN DEFAULT TRUE

Indexes: PRIMARY (id), UNIQUE (email), INDEX (role)
```

### 7.2 Relationships

| From | To | Type | Cardinality | Notes |
|------|----|----|---|---|
| User | Course | 1:Many | 1 teacher : Many courses | Created by |
| Course | CourseSession | 1:Many | 1 course : Many sessions | Multiple instances |
| CourseSession | Participant | 1:Many | 1 session : Many students | Join session |
| CourseSession | JoinCode | 1:Many | 1 session : Many codes | Multiple codes per session |
| JoinCode | Participant | 1:Many | 1 code : Many students | Track usage |
| Participant | StatusEvent | 1:Many | 1 student : Many taps | Event log |
| CourseSession | SessionSummary | 1:1 | 1 session : 1 summary | Computed at end |

---

## 8. TECHNICAL ARCHITECTURE

### 8.1 Technology Stack

**Frontend:**
- React 19+ (TypeScript)
- TanStack Router (file-based routing)
- TanStack Query (server state)
- TanStack Form (form management)
- Tailwind CSS (styling)

**Backend:**
- Full-stack: Tanstack Start (Node.js runtime)
- OR Separate: Hono + separate frontend

**Database:**
- MySQL 8.0+ (managed service: my.php.id)
- Drizzle ORM (type-safe, zero-runtime)

**Authentication:**
- Google OAuth 2.0
- Session management via JWT or cookies

**Deployment:**
- Cloudflare Workers (serverless, global edge)
- Database: my.php.id (MySQL compatible)

**Real-time:**
- MVP: HTTP polling (1-2 sec interval)
- Phase 2: WebSocket upgrade

### 8.2 Architecture Diagram

```
┌──────────────────────────────────────┐
│   Browser (React Frontend)           │
│  ├─ Teacher Dashboard                │
│  ├─ Student Status Board             │
│  └─ Superadmin Analytics             │
└────────────────┬─────────────────────┘
                 │ HTTPS
                 ↓
┌──────────────────────────────────────┐
│   Cloudflare Workers (Serverless)    │
│  ├─ API Routes (REST)                │
│  ├─ Google OAuth Handler             │
│  ├─ Request Validation               │
│  └─ Polling/WebSocket Handler        │
└────────────────┬─────────────────────┘
                 │ SQL
                 ↓
┌──────────────────────────────────────┐
│   MySQL Database (PlanetScale)       │
│  ├─ 8 tables (user, course, etc.)    │
│  ├─ Indices optimized                │
│  └─ Automated backups                │
└──────────────────────────────────────┘
```

### 8.3 API Endpoints

#### Authentication
```
POST /auth/google
  Purpose: Google OAuth callback
  Returns: { accessToken, user }

POST /auth/logout
  Purpose: Logout and clear session
```

#### Course Management
```
POST /api/courses
  Purpose: Create new course
  Body: { title, description, date, start_time, duration_minutes, allow_anonymous }
  Returns: { id, session_code, ... }

GET /api/courses
  Purpose: List all courses for logged-in teacher
  Returns: [ { id, title, status, ... } ]

PATCH /api/courses/:id
  Purpose: Update course (before start)
  Body: { title?, description?, ... }

DELETE /api/courses/:id
  Purpose: Delete (soft delete) course
```

#### Join Codes (NEW)
```
POST /api/sessions/:sessionId/codes
  Purpose: Generate new join code
  Body: { code?: "CUSTOM-CODE", auto_generate?: true }
  Returns: { id, code, status, generated_at }

GET /api/sessions/:sessionId/codes
  Purpose: List all codes for session
  Returns: [ { id, code, status, usage_count, ... } ]

PATCH /api/sessions/:sessionId/codes/:codeId
  Purpose: Revoke/reactivate code
  Body: { status: "revoked" | "active" }
  Returns: { id, code, status, revoked_at }

DELETE /api/sessions/:sessionId/codes/:codeId
  Purpose: Delete code entirely (before usage)
```

#### Session Management
```
POST /api/sessions/:sessionId/start
  Purpose: Start session (activate)
  Returns: { sessionId, is_active, started_at }

POST /api/sessions/:sessionId/end
  Purpose: End session, compute summary
  Returns: { sessionId, summary: {...} }

GET /api/sessions/:sessionId/status-summary
  Purpose: Real-time Red/Yellow/Green counts
  Returns: { red: 3, yellow: 5, green: 12, total: 20, elapsed_seconds: 945 }
```

#### Student Join
```
POST /api/join-by-code
  Purpose: Student joins via code
  Body: { code: "MATH-101", name?: "Andi" }
  Returns: { participantId, sessionInfo }

POST /api/join-by-link
  Purpose: Student joins via link
  Body: { sessionCode: "SIGNAL-ABC", name?: "Andi" }
  Returns: { participantId, sessionInfo }
```

#### Status Updates
```
POST /api/status-events
  Purpose: Student taps status (Red/Yellow/Green)
  Body: { participant_id, status: "red"|"yellow"|"green" }
  Returns: { eventId, auto_reset_at }

GET /api/participants/:sessionId
  Purpose: Get all participants in session (for dashboard)
  Returns: [ { id, name, current_status, join_timestamp, ... } ]
```

#### Analytics
```
GET /api/sessions/:sessionId/summary
  Purpose: Get completed session summary
  Returns: { total_participants, final_counts, duration, codes_used }

GET /api/admin/courses
  Purpose: Superadmin—all courses with stats
  Returns: [ { course, sessions, participants, red_rate, ... } ]

GET /api/admin/stats
  Purpose: Superadmin—aggregate stats
  Returns: { total_teachers, total_sessions, total_participants, ... }
```

---

## 9. UI/UX & WIREFRAMES

### 9.1 Teacher Dashboard (Main View)

```
┌─────────────────────────────────────────────────┐
│ SignalLearn  [Profile] [Logout]                 │
├─────────────────────────────────────────────────┤
│                                                 │
│ 📚 My Courses                                   │
│ [+ Create New Course]                           │
│                                                 │
│ ┌──────────────────────────────────────────┐   │
│ │ ACTIVE SESSION                           │   │
│ │ Math 101 - Algebra Basics                │   │
│ │ Started 2 min ago • Duration: 60 min     │   │
│ │                                          │   │
│ │ 🟢 12 Green    🟡 5 Yellow    🔴 3 Red  │   │
│ │ Total: 20 students • Elapsed: 2:15      │   │
│ │                                          │   │
│ │ 📋 Active Codes:                         │   │
│ │ MATH-101 (5 joined) [Copy] [Revoke]     │   │
│ │ MATH-LATE (2 joined) [Copy] [Revoke]    │   │
│ │ [+ Generate Code]                        │   │
│ │                                          │   │
│ │ [End Session]  [Share Link]             │   │
│ └──────────────────────────────────────────┘   │
│                                                 │
│ ┌──────────────────────────────────────────┐   │
│ │ PAST SESSIONS                            │   │
│ ├──────────────────────────────────────────┤   │
│ │ Physics 101 - Motion      45 min • 25 p │   │
│ │ [View Details]                           │   │
│ │                                          │   │
│ │ Chemistry 102 - Reactions 50 min • 18 p │   │
│ │ [View Details]                           │   │
│ └──────────────────────────────────────────┘   │
│                                                 │
└─────────────────────────────────────────────────┘
```

### 9.2 Student Join Screen

```
┌──────────────────────────────────┐
│                                  │
│     SignalLearn                  │
│                                  │
│ Have a code? Enter it below:     │
│                                  │
│ ┌──────────────────────────────┐ │
│ │ Enter join code...           │ │
│ └──────────────────────────────┘ │
│ [Continue]                       │
│                                  │
│ ─────────────────────────────     │
│                                  │
│ Or paste link:                   │
│ ┌──────────────────────────────┐ │
│ │ app.com/session/SIGNAL-ABC   │ │
│ └──────────────────────────────┘ │
│ [Go]                             │
│                                  │
└──────────────────────────────────┘
```

### 9.3 Student Status Board

```
┌──────────────────────────────────┐
│                                  │
│ 📚 Math 101 - Algebra Basics     │
│ Teacher: Jaki Wijaya            │
│ Time left: 45:23                │
│ ✓ Connected                      │
│                                  │
│ ─────────────────────────────     │
│                                  │
│ How are you doing?               │
│                                  │
│    [🟢]    [🟡]    [🔴]         │
│                                  │
│    Green   Yellow   Red          │
│     I'm OK Have Q  Need Help     │
│                                  │
│ ─────────────────────────────     │
│                                  │
│ Your status: 🟢 Green            │
│ Reset in: 4:32                   │
│                                  │
└──────────────────────────────────┘
```

---

## 10. API ENDPOINTS (COMPLETE)

### 10.1 Core Endpoints

| Method | Endpoint | Purpose | Auth |
|--------|----------|---------|------|
| **POST** | `/auth/google` | Google OAuth | Public |
| **POST** | `/auth/logout` | Logout | Required |
| **POST** | `/api/courses` | Create course | Required |
| **GET** | `/api/courses` | List courses | Required |
| **PATCH** | `/api/courses/:id` | Update course | Required |
| **DELETE** | `/api/courses/:id` | Delete course | Required |
| **POST** | `/api/sessions/:id/codes` | Generate code | Required |
| **GET** | `/api/sessions/:id/codes` | List codes | Required |
| **PATCH** | `/api/sessions/:id/codes/:codeId` | Revoke/activate | Required |
| **POST** | `/api/sessions/:id/start` | Start session | Required |
| **POST** | `/api/sessions/:id/end` | End session | Required |
| **GET** | `/api/sessions/:id/status-summary` | Live counts | Required |
| **POST** | `/api/join-by-code` | Join via code | Public |
| **POST** | `/api/join-by-link` | Join via link | Public |
| **POST** | `/api/status-events` | Update status | Public |
| **GET** | `/api/sessions/:id/summary` | Session summary | Required |
| **GET** | `/api/admin/courses` | Admin course list | Admin |
| **GET** | `/api/admin/stats` | Admin stats | Admin |

---

## 11. SUCCESS METRICS

### Technical Metrics (MVP Launch)
- ✅ Status update latency: < 2 seconds (visible to teacher)
- ✅ Uptime: 99.5% during school hours
- ✅ Zero critical bugs at launch
- ✅ Session timer accuracy: ±5 seconds
- ✅ Mobile responsiveness: Works on iPhone + Android

### Product Metrics (Week 1-2)
- ✅ 10+ beta teachers sign up
- ✅ 80%+ students tap status at least once per session
- ✅ 95%+ session completion rate (not abandoned)
- ✅ Positive feedback on join codes feature

### Growth Metrics (Month 2+)
- 50+ teachers active
- 5000+ total students participated
- 20+ daily active sessions
- Join code adoption: % of sessions using codes vs links
- NPS baseline: Net Promoter Score > 50

---

## 12. SCOPE & CONSTRAINTS

### In Scope (MVP 1.1)
✅ Google OAuth teacher login  
✅ Course creation (CRUD)  
✅ Unique session codes + shareable links  
✅ **Teacher-generated join codes (auto/custom)**  
✅ **Code revoke/reactivate capability**  
✅ **Code usage tracking**  
✅ Real-time Red/Yellow/Green counts  
✅ Student join (no login, code OR link)  
✅ Status buttons + auto-reset (5 min)  
✅ Session timer (auto-track elapsed)  
✅ Alerts (high Red count)  
✅ Past session review (summary)  
✅ Superadmin basic dashboard  

### Out of Scope (Phase 2+)
❌ QR code generation/scanning  
❌ Detailed analytics (export CSV, charts)  
❌ Custom status labels (Red/Yellow/Green only)  
❌ SMS/Email notifications (dashboard alert only)  
❌ Mobile native apps (web responsive only)  
❌ Integrations (Slack, Teams, LMS)  
❌ SSO/Enterprise authentication  
❌ Participant-level detailed history  

### Constraints
- **Timeline:** 5 weeks development (MVP launch)
- **Team:** 1-2 developers (full-stack)
- **Infrastructure:** Cloudflare Workers (serverless, low cost)
- **Database:** MySQL managed (my.php.id)

---

## 13. DEVELOPMENT ROADMAP

### Week 1-2: Foundation
**Database Setup**
- [ ] Create Drizzle ORM schema (8 entities)
- [ ] Migrations + indices
- [ ] Test fixtures

**Authentication**
- [ ] Google OAuth configuration
- [ ] Login flow implementation
- [ ] Session management

**Project Structure**
- [ ] Tanstack Start scaffolding
- [ ] File-based routing
- [ ] API structure
- [ ] Component organization

**Testing Setup**
- [ ] Unit test framework
- [ ] Mock data generators

### Week 2-3: Core Features
**Teacher Features**
- [ ] Course CRUD endpoints
- [ ] Start/end session logic
- [ ] Session timer
- [ ] Real-time status dashboard

**Student Features**
- [ ] Student join page (code + link)
- [ ] Status buttons UI
- [ ] Auto-reset logic (5 min timer)

**Join Codes Feature (NEW)**
- [ ] JoinCode table + migrations
- [ ] Generate endpoint (auto + custom)
- [ ] Code validation logic
- [ ] Revoke/reactivate endpoint
- [ ] Code management UI
- [ ] Join-by-code endpoint
- [ ] Usage tracking

**Real-time**
- [ ] Polling implementation (1-2 sec)
- [ ] Dashboard auto-refresh
- [ ] Performance optimization

### Week 3-4: Polish & QA
**Alerts & Notifications**
- [ ] Alert card component
- [ ] High Red threshold logic
- [ ] Dismissible alerts

**Session Summary**
- [ ] Compute summary at end
- [ ] Display summary page
- [ ] Code usage breakdown

**Superadmin**
- [ ] Superadmin dashboard
- [ ] Course list + stats
- [ ] Problem course identification

**Quality Assurance**
- [ ] Functional testing (all features)
- [ ] Performance testing (< 2 sec latency)
- [ ] Mobile responsiveness testing
- [ ] Security audit (OWASP)
- [ ] Accessibility audit (WCAG 2.1)

### Week 4-5: Launch
**Deployment**
- [ ] Deploy to staging environment
- [ ] Staging smoke test
- [ ] Deploy to production
- [ ] Production smoke test

**Beta Testing**
- [ ] Invite 5-10 beta teachers
- [ ] Provide feedback form
- [ ] Monitor error logs
- [ ] Rapid bug fixes

**Public Launch**
- [ ] Update landing page
- [ ] Social media announcement
- [ ] Email campaign
- [ ] Monitor server health
- [ ] Track signup metrics

---

## 14. LAUNCH & ROLLOUT PLAN

### Phase 1: Beta Launch (Week 4)
1. Deploy to staging environment
2. Internal testing (product + QA team)
3. Fix critical bugs
4. Invite 5-10 beta teachers (seed users)
5. Collect feedback (in-app form)
6. 48-hour monitoring

### Phase 2: Public Launch (Week 5)
1. Deploy to production
2. Publish landing page: signallearn.app
3. Social media announcement (LinkedIn, Twitter, Instagram)
4. Email outreach to education networks
5. Start signup tracking

### Phase 3: Post-Launch (Week 6+)
- Monitor uptime (99.5% target)
- Track signup rate + adoption
- Respond to support requests (same-day)
- Gather product feedback for Phase 2
- Plan enhancements based on user feedback

---

## 15. APPENDIX: JOIN CODES DEEP-DIVE

### 15.1 Join Code Feature Overview

**Why This Matters:**
Without join codes, all students must share one link or individually type the session code. Join codes give teachers flexibility to:
- Announce code verbally (natural classroom interaction)
- Create separate codes for different groups
- Revoke access if needed
- Track which students used which code

### 15.2 Use Cases

#### Use Case 1: Verbal Classroom Share
```
Teacher setup:
1. Start session → Auto-generates "SIGNAL-ABC-123"
2. Announces: "Kode: SIGNAL-ABC-123"
3. Students type code → join
4. Teacher monitors dashboard
```

#### Use Case 2: Multiple Groups
```
Teacher has 3 simultaneous groups:
1. Pre-generate: "GROUP-A", "GROUP-B", "GROUP-C"
2. Share each code to respective group
3. Dashboard shows breakdown per code
4. Later: Analyze which group had most Red status
```

#### Use Case 3: Late Arrivals
```
Session running, some students late:
1. Generate new code: "LATE-JOIN"
2. Share to late students via WhatsApp
3. They join with separate code
4. Dashboard shows: original (12 students), LATE-JOIN (3)
```

#### Use Case 4: Access Control
```
Small secure workshop:
1. Pre-generate code only for invited students
2. Share code privately
3. Anyone else trying to join: "Code not found"
4. Prevents random access
```

### 15.3 Code Management Rules

**Generation:**
- Auto-generated: System creates readable code (e.g., "SIGNAL-ABC-123")
- Custom: Teacher enters code (3-50 chars, alphanumeric + hyphens)
- Timing: Anytime (pre-session or live)

**Uniqueness:**
- Per session (code "MATH-101" can be used in Session 1 AND Session 2, just not twice in same session)

**Revoke Logic:**
- Revoked code: New students CANNOT join
- Already-joined students: Remain in session (not kicked)
- Anytime revoke: Can revoke mid-session

**Usage Tracking:**
- Count students joined via each code
- Show in dashboard
- Include in SessionSummary

### 15.4 Code Validation

```
Format Rules:
- 3-50 characters
- Alphanumeric (A-Z, 0-9) + hyphens (-) only
- Case-insensitive (MATH-101 = math-101)
- No spaces, no special characters

Examples (Valid):
✓ MATH-101
✓ CLASS-2026-AUG
✓ LATE-JOIN
✓ ABC123
✓ math101

Examples (Invalid):
✗ @#$%
✗ "code with spaces"
✗ MATH-101!! (special chars)
✗ M (too short)
```

---

## APPENDIX: FILE LOCATIONS & DEPLOYMENT

### Development
- **Source Code:** GitHub repository (with this PRD in /docs/)
- **Database:** my.php.id MySQL (staging + production)
- **Frontend Hosting:** Cloudflare Workers
- **Environment:** Node.js 18+ with Bun runtime

### Production
- **Domain:** signal-learn.web.id
- **CDN:** Cloudflare (global edge)
- **Database:** my.php.id (MySQL)
- **Monitoring:** Cloudflare Analytics + Error tracking (e.g., Sentry)

---

## DOCUMENT SIGN-OFF

| Role | Name | Approval | Date |
|------|------|----------|------|
| **Product Owner** | Jaki | ✅ | Aug 2026 |
| **Dev Lead** | [To be assigned] | ⏳ | - |
| **Designer** | [To be assigned] | ⏳ | - |
| **QA Lead** | [To be assigned] | ⏳ | - |

---

## VERSION HISTORY

| Version | Date | Changes |
|---------|------|---------|
| 1.0 | Aug 2026 | Initial PRD (MVP minimal) |
| 1.1 | Aug 2026 | Added join codes feature (MVP 1.1) |

---

## NEXT STEPS

1. ✅ **Review & Approve** this PRD
2. ⏳ **Brief development team** (share this document)
3. ⏳ **Design detailed ERD** from data model (Section 7)
4. ⏳ **Create technical spec** (API details, data flow)
5. ⏳ **Kickoff meeting** (all leads, 90 min)
6. ⏳ **Development starts** (Week 1)

---

**Status:** ✅ **READY FOR DEVELOPMENT KICKOFF**

**All information provided. No ambiguity. Let's build!**

---

**Document prepared by:** Claude + Jaki Product Discovery  
**Date:** August 2026  
**App Name:** Signal-Learn  
**Timeline:** 5 weeks to launch  

*This PRD is production-ready. Share with your development team to begin work immediately.*

---

**🚀 Let's launch Signal-Learn!**
