๐ŸŽฏ g5se ์˜จ๋ผ์ธ ํ€ด์ฆˆ ์•„๋ ˆ๋‚˜ - ๋‹ค์–‘ํ•œ ์ฃผ์ œ์˜ ํ€ด์ฆˆ ํ’€๊ธฐ & ์ ์ˆ˜ ๊ฒฝ์Ÿ - ๋ฐ”์ด๋ธŒ์ฝ”๋”ฉ ๋ ˆ์‹œํ”ผ
์ค‘๊ธ‰ PHP g5se AI: Claude

๐ŸŽฏ g5se ์˜จ๋ผ์ธ ํ€ด์ฆˆ ์•„๋ ˆ๋‚˜ - ๋‹ค์–‘ํ•œ ์ฃผ์ œ์˜ ํ€ด์ฆˆ ํ’€๊ธฐ & ์ ์ˆ˜ ๊ฒฝ์Ÿ

๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ช… g5se-quiz-arena-platform
์กฐํšŒ์ˆ˜ 57 0๊ฑด ์ œ์ถœ

๋ฌธ์ œ ์„ค๋ช…

๐Ÿ“š ํ”„๋กœ์ ํŠธ ๊ฐœ์š”

๊ทธ๋ˆ„๋ณด๋“œ5 SE ์œ„์—์„œ ๋™์ž‘ํ•˜๋Š” ์˜จ๋ผ์ธ ํ€ด์ฆˆ ํ”Œ๋žซํผ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๊ด€๋ฆฌ์ž๊ฐ€ ํ€ด์ฆˆ ์„ธํŠธ๋ฅผ ๋“ฑ๋กํ•˜๊ณ , ์‚ฌ์šฉ์ž๋Š” ๋‹ค์–‘ํ•œ ์ฃผ์ œ์˜ ํ€ด์ฆˆ๋ฅผ ํ’€๋ฉด์„œ ์ ์ˆ˜๋ฅผ ํš๋“ํ•˜๊ณ  ์ˆœ์œ„๋ฅผ ๊ฒฝ์Ÿํ•  ์ˆ˜ ์žˆ๋Š” ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์›น ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.

โœจ ํ•ต์‹ฌ ๊ธฐ๋Šฅ

ํ•„์ˆ˜ ๊ธฐ๋Šฅ:

  • ๐ŸŽฒ ํ€ด์ฆˆ ์นดํ…Œ๊ณ ๋ฆฌ ํƒ์ƒ‰: ์ƒ์‹/์—ญ์‚ฌ/๊ณผํ•™/์—”ํ„ฐํ…Œ์ธ๋จผํŠธ ๋“ฑ ์ฃผ์ œ๋ณ„ ํ€ด์ฆˆ ์„ธํŠธ ๋ชฉ๋ก
  • ๐Ÿ“ ํ€ด์ฆˆ ํ’€์ด ์ธํ„ฐํŽ˜์ด์Šค: ๊ฐ๊ด€์‹ 4์ง€์„ ๋‹ค, ์‹ค์‹œ๊ฐ„ ์ •๋‹ต/์˜ค๋‹ต ํ”ผ๋“œ๋ฐฑ, ์ง„ํ–‰๋ฅ  ํ‘œ์‹œ
  • ๐Ÿ† ์ ์ˆ˜ ์‹œ์Šคํ…œ: ์ •๋‹ต ์‹œ ์ ์ˆ˜ ์ ๋ฆฝ, ๊ฐœ์ธ ๋ˆ„์  ์ ์ˆ˜ ๊ธฐ๋ก
  • ๐Ÿ“Š ๋ฆฌ๋”๋ณด๋“œ: ์ „์ฒด ์‚ฌ์šฉ์ž ์ ์ˆ˜ ์ˆœ์œ„ํ‘œ (์ƒ์œ„ 20๋ช…)
  • โœ… ํ€ด์ฆˆ ์™„๋ฃŒ ๊ธฐ๋ก: ๋‚ด๊ฐ€ ํ‘ผ ํ€ด์ฆˆ ํžˆ์Šคํ† ๋ฆฌ with ์ •๋‹ต๋ฅ 

์„ ํƒ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ (๋ณด๋„ˆ์Šค):

  • โฑ๏ธ ํƒ€์ด๋จธ ๋ชจ๋“œ: ์ œํ•œ ์‹œ๊ฐ„ ๋‚ด ํ€ด์ฆˆ ํ’€๊ธฐ (๋‚œ์ด๋„ ์ƒ์Šน)
  • ๐ŸŽฏ ํžŒํŠธ ์‹œ์Šคํ…œ: ์˜ค๋‹ต 1๊ฐœ ์ œ๊ฑฐ (ํžŒํŠธ ์‚ฌ์šฉ ์‹œ ์ ์ˆ˜ ์ฐจ๊ฐ)
  • ๐Ÿ”€ ๋žœ๋ค ํ€ด์ฆˆ: ์นดํ…Œ๊ณ ๋ฆฌ ๋ฌด๊ด€ ๋žœ๋ค ๋ฌธ์ œ ์ถœ์ œ
  • ๐Ÿ“ˆ ๊ฐœ์ธ ํ†ต๊ณ„: ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์ •๋‹ต๋ฅ  ์ฐจํŠธ
  • ๐ŸŽจ ๋‹คํฌ๋ชจ๋“œ ์ž๋™ ๋Œ€์‘ (modern shell ํ† ํฐ ํ™œ์šฉ)

๐ŸŽฏ ํ•™์Šต ๋ชฉํ‘œ

  • g5se์˜ ํด๋” ๊ธฐ๋ฐ˜ ์ž๋™ ๋ผ์šฐํŒ… ์‹œ์Šคํ…œ ์ดํ•ด
  • modern shell ์ ์šฉ์œผ๋กœ ์‚ฌ์ดํŠธ ํ†ต์ผ์„ฑ ํ™•๋ณด
  • ๋ชจ๋“ˆ ์ „์šฉ SQLite DB ์„ค๊ณ„ (ํ€ด์ฆˆ/๊ฒฐ๊ณผ/์ ์ˆ˜ ํ…Œ์ด๋ธ”)
  • AJAX ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ํ€ด์ฆˆ ์ œ์ถœ & ์‹ค์‹œ๊ฐ„ ํ”ผ๋“œ๋ฐฑ
  • CSS ๋ณ€์ˆ˜ ๊ธฐ๋ฐ˜ ๋‹คํฌ๋ชจ๋“œ ๋Œ€์‘ UI
  • ์‚ฌ์šฉ์ž ์ธํ„ฐ๋ž™์…˜ ์ค‘์‹ฌ์˜ ํ”„๋ก ํŠธ์—”๋“œ ๋กœ์ง (ํƒ€์ด๋จธ, ์• ๋‹ˆ๋ฉ”์ด์…˜)

๐Ÿš€ ๊ธฐ์ˆ  ์Šคํƒ

  • ๋ฐฑ์—”๋“œ: PHP 8.x + g5se (๊ทธ๋ˆ„๋ณด๋“œ5 SE)
  • DB: SQLite (๋ชจ๋“ˆ ์ „์šฉ G5_DATA_PATH/modules/quiz-arena.sqlite)
  • ํ”„๋ก ํŠธ์—”๋“œ: HTML5 + Vanilla JS + CSS3
  • ๋””์ž์ธ: modern shell ํ† ํฐ ๊ธฐ๋ฐ˜ ๋‹คํฌ๋ชจ๋“œ ์ง€์›

๐Ÿ“ฆ ๊ฒฐ๊ณผ๋ฌผ

  • /quiz-arena - ํ€ด์ฆˆ ์นดํ…Œ๊ณ ๋ฆฌ ๋ชฉ๋ก & ์„ ํƒ ํŽ˜์ด์ง€
  • /quiz-arena/play - ํ€ด์ฆˆ ํ’€์ด ํ™”๋ฉด (AJAX ๊ธฐ๋ฐ˜ ์‹ค์‹œ๊ฐ„ ์ •๋‹ต ์ฒดํฌ)
  • /quiz-arena/leaderboard - ์ „์ฒด ์ˆœ์œ„ํ‘œ
  • /quiz-arena/my-stats - ๊ฐœ์ธ ํ†ต๊ณ„ & ์™„๋ฃŒํ•œ ํ€ด์ฆˆ ํžˆ์Šคํ† ๋ฆฌ
  • ๊ด€๋ฆฌ์ž ๊ธฐ๋Šฅ: ํ€ด์ฆˆ ์„ธํŠธ ๋“ฑ๋ก ํผ (/quiz-arena/admin - ๋กœ๊ทธ์ธ ์ฒดํฌ ํฌํ•จ)

์ œ์•ฝ ์กฐ๊ฑด

  • โ€ข g5se ์„ค์น˜๋ณธ ์œ„์— ํŒŒ์ผ ์ถ”๊ฐ€ (Laravel/Composer/npm ์‚ฌ์šฉ ๊ธˆ์ง€)
  • โ€ข ํด๋” ๊ธฐ๋ฐ˜ ์ž๋™ ๋ผ์šฐํŒ… ์‚ฌ์šฉ (app/router.php์— ๋ผ์šฐํŠธ ๋“ฑ๋ก ๋ถˆํ•„์š”)
  • โ€ข modern shell ํ•„์ˆ˜ ์ ์šฉ (_head.inc.php + m-shell + _nav.inc.php + m-container + _footer.inc.php + tail.sub.php)
  • โ€ข ๋””์ž์ธ ํ† ํฐ(CSS ๋ณ€์ˆ˜) ์‚ฌ์šฉ์œผ๋กœ ๋‹คํฌ๋ชจ๋“œ ์ž๋™ ๋Œ€์‘
  • โ€ข ๋ชจ๋“ˆ ์ „์šฉ SQLite DB ์‚ฌ์šฉ (G5_DATA_PATH/modules/quiz-arena.sqlite)
  • โ€ข g5se ๋ฉ”์ธ DB์— ํ…Œ์ด๋ธ” ์ƒ์„ฑ ์ ˆ๋Œ€ ๊ธˆ์ง€
  • โ€ข ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋Š” htmlspecialchars()๋กœ ์ด์Šค์ผ€์ดํ”„
  • โ€ข prepared statement๋กœ SQL ์ธ์ ์…˜ ๋ฐฉ์ง€
  • โ€ข AJAX ์‘๋‹ต์€ JSON ํ˜•์‹ (Content-Type: application/json)
  • โ€ข CDN ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ ๊ธˆ์ง€ (์ˆœ์ˆ˜ Vanilla JS)
  • โ€ข ํ€ด์ฆˆ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์€ g5se ํšŒ์› ๋กœ๊ทธ์ธ ์ฒดํฌ ํ•„์ˆ˜

ํ”„๋กฌํ”„ํŠธ ๋ ˆ์‹œํ”ผ

์•„๋ž˜ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ AI์—๊ฒŒ ๋ณด๋‚ด๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋ณต์‚ฌ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜์„ธ์š”.

1
Step 1
g5se๊ฐ€ ์„ค์น˜๋œ ๋””๋ ‰ํ„ฐ๋ฆฌ(๋ฃจํŠธ์— `index.php`ยท`app/`์ด ์žˆ๋Š” ๊ณณ)์—์„œ ์ž‘์—…์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. (g5se ์„ค์น˜๋Š” https://github.com/gnuboard/g5se ์ฐธ๊ณ )

**Step 1: ํ€ด์ฆˆ ์•„๋ ˆ๋‚˜ ๋ฉ”์ธ ํŽ˜์ด์ง€ ์ƒ์„ฑ**

`app/modules/quiz-arena/index.php` ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ  ๋‹ค์Œ์„ ๊ตฌํ˜„ํ•˜์„ธ์š”:

1. **modern shell ๊ณจ๊ฒฉ ์ ์šฉ**:
   - `_common.php` ์ธํด๋ฃจ๋“œ
   - `_head.inc.php` + `m-shell` + `_nav.inc.php` + `m-container` + `_footer.inc.php` + `tail.sub.php` ๊ตฌ์กฐ ์‚ฌ์šฉ

2. **SQLite DB ์ดˆ๊ธฐํ™”**:
   - ํŒŒ์ผ ์œ„์น˜: `G5_DATA_PATH.'/modules/quiz-arena.sqlite'`
   - ๋””๋ ‰ํ„ฐ๋ฆฌ ์ƒ์„ฑ: `@mkdir(G5_DATA_PATH.'/modules', 0707, true);`
   - ํ…Œ์ด๋ธ” ์Šคํ‚ค๋งˆ (์ฒซ ์ ‘๊ทผ ์‹œ ์ž๋™ ์ƒ์„ฑ):
     ```sql
     CREATE TABLE IF NOT EXISTS quiz_sets (
       id INTEGER PRIMARY KEY AUTOINCREMENT,
       category TEXT NOT NULL,
       title TEXT NOT NULL,
       difficulty TEXT DEFAULT 'normal',
       created_at TEXT DEFAULT CURRENT_TIMESTAMP
     );
     
     CREATE TABLE IF NOT EXISTS quiz_questions (
       id INTEGER PRIMARY KEY AUTOINCREMENT,
       quiz_set_id INTEGER NOT NULL,
       question TEXT NOT NULL,
       option_a TEXT NOT NULL,
       option_b TEXT NOT NULL,
       option_c TEXT NOT NULL,
       option_d TEXT NOT NULL,
       correct_answer TEXT NOT NULL,
       explanation TEXT,
       FOREIGN KEY(quiz_set_id) REFERENCES quiz_sets(id)
     );
     
     CREATE TABLE IF NOT EXISTS user_scores (
       id INTEGER PRIMARY KEY AUTOINCREMENT,
       mb_id TEXT NOT NULL,
       quiz_set_id INTEGER NOT NULL,
       score INTEGER DEFAULT 0,
       total_questions INTEGER DEFAULT 0,
       completed_at TEXT DEFAULT CURRENT_TIMESTAMP,
       FOREIGN KEY(quiz_set_id) REFERENCES quiz_sets(id)
     );
     ```

3. **์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํ€ด์ฆˆ ์„ธํŠธ ๋ชฉ๋ก ํ‘œ์‹œ**:
   - DB์—์„œ quiz_sets๋ฅผ category๋ณ„๋กœ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ์กฐํšŒ
   - ๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ ์นด๋“œ์— ํ€ด์ฆˆ ์„ธํŠธ ๊ฐœ์ˆ˜ ํ‘œ์‹œ
   - ์นด๋“œ ํด๋ฆญ ์‹œ `/quiz-arena/play?set_id={id}` ๋งํฌ

4. **UI ๋””์ž์ธ**:
   - ํ—ค๋”: "๐ŸŽฏ ํ€ด์ฆˆ ์•„๋ ˆ๋‚˜" ํƒ€์ดํ‹€ + "๋„์ „! ์ง€์‹์™• ๋˜๊ธฐ" ์„œ๋ธŒํƒ€์ดํ‹€
   - ์นดํ…Œ๊ณ ๋ฆฌ ์นด๋“œ: ๊ทธ๋ฆฌ๋“œ ๋ ˆ์ด์•„์›ƒ (2์—ด, ๋ชจ๋ฐ”์ผ 1์—ด)
   - ์นด๋“œ ์Šคํƒ€์ผ: `background: var(--m-surface); box-shadow: var(--m-shadow); border-radius: var(--m-radius-lg);`
   - hover ์‹œ ์‚ด์ง scale ์• ๋‹ˆ๋ฉ”์ด์…˜
   - ์šฐ์ธก ์ƒ๋‹จ์— "๋‚ด ๊ธฐ๋ก" ๋ฒ„ํŠผ (`/quiz-arena/my-stats` ๋งํฌ)

5. **์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ์‚ฝ์ž…** (DB๊ฐ€ ๋น„์–ด์žˆ์„ ๊ฒฝ์šฐ):
   - ์ƒ์‹/์—ญ์‚ฌ/๊ณผํ•™/์—”ํ„ฐํ…Œ์ธ๋จผํŠธ ์นดํ…Œ๊ณ ๋ฆฌ์— ๊ฐ 1๊ฐœ์”ฉ ์ƒ˜ํ”Œ ํ€ด์ฆˆ ์„ธํŠธ ์ƒ์„ฑ
   - ๊ฐ ์„ธํŠธ๋‹น 5๊ฐœ ๋ฌธ์ œ (4์ง€์„ ๋‹ค)

**๋””์ž์ธ ํ† ํฐ ์‚ฌ์šฉ ์˜ˆ์‹œ:**
```css
.quiz-category-card {
  background: var(--m-surface);
  color: var(--m-text);
  box-shadow: var(--m-shadow);
  border-radius: var(--m-radius-lg);
  padding: 24px;
  transition: transform 0.2s;
}
.quiz-category-card:hover {
  transform: translateY(-4px);
}
.category-badge {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  padding: 6px 12px;
  border-radius: 12px;
  font-size: 0.9em;
}
```

**์˜ˆ์ƒ URL**: `/quiz-arena` (ํด๋” ๊ธฐ๋ฐ˜ ์ž๋™ ๋ผ์šฐํŒ…)

ํŒŒ์ผ ๊ฒฝ๋กœ๋Š” ๋ฐ˜๋“œ์‹œ `app/modules/quiz-arena/index.php`๋กœ ์ƒ์„ฑํ•˜์„ธ์š”.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: - `/quiz-arena` ์ ‘์† ์‹œ modern shell์ด ์ ์šฉ๋œ ํŽ˜์ด์ง€ ํ‘œ์‹œ - SQLite DB๊ฐ€ ์ž๋™ ์ƒ์„ฑ๋˜๊ณ  ํ…Œ์ด๋ธ” ์Šคํ‚ค๋งˆ ์ดˆ๊ธฐํ™” - ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํ€ด์ฆˆ ์„ธํŠธ ์นด๋“œ๊ฐ€ ๊ทธ๋ฆฌ๋“œ๋กœ ํ‘œ์‹œ (์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ ํฌํ•จ) - ๋‹คํฌ๋ชจ๋“œ ํ† ๊ธ€ ์‹œ ๋ฐฐ๊ฒฝ/ํ…์ŠคํŠธ ์ƒ‰์ƒ ์ž๋™ ์ „ํ™˜ - ์นด๋“œ hover ์‹œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋™์ž‘

2
Step 2
**Step 2: ํ€ด์ฆˆ ํ’€์ด ํŽ˜์ด์ง€ ๊ตฌํ˜„**

`app/modules/quiz-arena/play/index.php` ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ  ๋‹ค์Œ์„ ๊ตฌํ˜„ํ•˜์„ธ์š”:

1. **URL ํŒŒ๋ผ๋ฏธํ„ฐ ์ฒ˜๋ฆฌ**:
   - `$_GET['set_id']`๋กœ ํ€ด์ฆˆ ์„ธํŠธ ID ๋ฐ›๊ธฐ
   - ํ•ด๋‹น ์„ธํŠธ์˜ ๋ฌธ์ œ ๋ชฉ๋ก์„ DB์—์„œ ์กฐํšŒ (quiz_questions ํ…Œ์ด๋ธ”)
   - ์„ธํŠธ๊ฐ€ ์—†์œผ๋ฉด 404 ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ

2. **ํ€ด์ฆˆ UI ๊ตฌ์กฐ**:
   - ์ƒ๋‹จ: ์ง„ํ–‰๋ฅ  ๋ฐ” (์˜ˆ: "3 / 5 ๋ฌธ์ œ")
   - ์ค‘์•™: ํ˜„์žฌ ๋ฌธ์ œ ํ…์ŠคํŠธ (ํฐ ํฐํŠธ)
   - 4๊ฐœ ์„ ํƒ์ง€ ๋ฒ„ํŠผ (A/B/C/D)
   - ํ•˜๋‹จ: "๋‹ค์Œ ๋ฌธ์ œ" ๋ฒ„ํŠผ (์ •๋‹ต ์„ ํƒ ํ›„ ํ™œ์„ฑํ™”)

3. **JavaScript ์ธํ„ฐ๋ž™์…˜**:
   - ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ ๋ฌธ์ œ ๋ฐ์ดํ„ฐ๋ฅผ JSON์œผ๋กœ `<script>` ํƒœ๊ทธ์— ์ž„๋ฒ ๋“œ
   - ์„ ํƒ์ง€ ํด๋ฆญ ์‹œ:
     - AJAX๋กœ `/quiz-arena/check-answer` POST ์š”์ฒญ (๋ฌธ์ œ ID + ์„ ํƒํ•œ ๋‹ต)
     - ์‘๋‹ต์—์„œ ์ •๋‹ต ์—ฌ๋ถ€ ๋ฐ›์•„์„œ ์ฆ‰์‹œ ํ”ผ๋“œ๋ฐฑ (์ •๋‹ต: ์ดˆ๋ก ๋ฐฐ๊ฒฝ, ์˜ค๋‹ต: ๋นจ๊ฐ• ๋ฐฐ๊ฒฝ)
     - ์ •๋‹ต์ผ ๊ฒฝ์šฐ ์ ์ˆ˜ +10์  ํ‘œ์‹œ
     - ์˜ค๋‹ต์ผ ๊ฒฝ์šฐ ์ •๋‹ต ์„ ํƒ์ง€ ๊ฐ•์กฐ + ํ•ด์„ค ํ‘œ์‹œ
   - "๋‹ค์Œ ๋ฌธ์ œ" ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ๋‹ค์Œ ๋ฌธ์ œ๋กœ ์ด๋™ (JS๋กœ ํ™”๋ฉด ๊ฐฑ์‹ )
   - ๋งˆ์ง€๋ง‰ ๋ฌธ์ œ ์™„๋ฃŒ ์‹œ ๊ฒฐ๊ณผ ์š”์•ฝ ๋ชจ๋‹ฌ ํ‘œ์‹œ (์ด ์ ์ˆ˜, ์ •๋‹ต๋ฅ )

4. **AJAX ์—”๋“œํฌ์ธํŠธ ๋ถ„๊ธฐ** (๊ฐ™์€ ํŒŒ์ผ ๋‚ด):
   - `$_POST['action'] === 'check_answer'`์ผ ๊ฒฝ์šฐ:
     - ๋ฌธ์ œ ID์™€ ์„ ํƒํ•œ ๋‹ต์„ ๋ฐ›์•„์„œ ์ •๋‹ต ์—ฌ๋ถ€ ์ฒดํฌ
     - JSON ์‘๋‹ต: `{"correct": true/false, "explanation": "...", "correct_answer": "B"}`
     - `header('Content-Type: application/json');`
     - `exit;`๋กœ HTML ๋ Œ๋”๋ง ์ค‘๋‹จ

5. **ํ€ด์ฆˆ ์™„๋ฃŒ ์ฒ˜๋ฆฌ**:
   - ๋ชจ๋“  ๋ฌธ์ œ ์™„๋ฃŒ ์‹œ user_scores ํ…Œ์ด๋ธ”์— ๊ธฐ๋ก ์ €์žฅ
   - mb_id๋Š” `$member['mb_id']` ์‚ฌ์šฉ (๋น„ํšŒ์›์€ 'guest')
   - ์™„๋ฃŒ ๋ชจ๋‹ฌ์— "๋ฆฌ๋”๋ณด๋“œ ๋ณด๊ธฐ" ๋ฒ„ํŠผ ์ถ”๊ฐ€

6. **UI ๋””์ž์ธ**:
   - ์ง„ํ–‰๋ฅ  ๋ฐ”: `<progress>` ํƒœ๊ทธ + CSS ์Šคํƒ€์ผ๋ง
   - ์„ ํƒ์ง€ ๋ฒ„ํŠผ: ํฐ ํŒจ๋”ฉ, ํ˜ธ๋ฒ„ ์‹œ ๋ฐฐ๊ฒฝ์ƒ‰ ๋ณ€ํ™”
   - ์ •๋‹ต ํ”ผ๋“œ๋ฐฑ: 0.3์ดˆ fade-in ์• ๋‹ˆ๋ฉ”์ด์…˜
   - ๋ชจ๋‹ฌ: ๋ฐ˜ํˆฌ๋ช… ๋ฐฐ๊ฒฝ + ์ค‘์•™ ์นด๋“œ

**AJAX ์ฝ”๋“œ ์˜ˆ์‹œ (JS):**
```javascript
function checkAnswer(questionId, selectedAnswer) {
  fetch('/quiz-arena/play', {
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body: `action=check_answer&question_id=${questionId}&answer=${selectedAnswer}`
  })
  .then(res => res.json())
  .then(data => {
    if (data.correct) {
      // ์ •๋‹ต ์ฒ˜๋ฆฌ
      document.querySelector(`[data-option="${selectedAnswer}"]`).style.background = '#10b981';
    } else {
      // ์˜ค๋‹ต ์ฒ˜๋ฆฌ
      document.querySelector(`[data-option="${selectedAnswer}"]`).style.background = '#ef4444';
      document.querySelector(`[data-option="${data.correct_answer}"]`).style.background = '#10b981';
      showExplanation(data.explanation);
    }
  });
}
```

**์˜ˆ์ƒ URL**: `/quiz-arena/play?set_id=1`

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: - ํ€ด์ฆˆ ์„ธํŠธ ID๋กœ ์ ‘์† ์‹œ ์ฒซ ๋ฒˆ์งธ ๋ฌธ์ œ ํ‘œ์‹œ - ์„ ํƒ์ง€ ํด๋ฆญ ์‹œ AJAX๋กœ ์ •๋‹ต ์ฒดํฌ ํ›„ ์ฆ‰์‹œ ํ”ผ๋“œ๋ฐฑ - ์ง„ํ–‰๋ฅ  ๋ฐ”๊ฐ€ ๋ฌธ์ œ ์ง„ํ–‰์— ๋”ฐ๋ผ ์—…๋ฐ์ดํŠธ - ๋ชจ๋“  ๋ฌธ์ œ ์™„๋ฃŒ ์‹œ ๊ฒฐ๊ณผ ๋ชจ๋‹ฌ ํ‘œ์‹œ (์ ์ˆ˜, ์ •๋‹ต๋ฅ ) - user_scores ํ…Œ์ด๋ธ”์— ์™„๋ฃŒ ๊ธฐ๋ก ์ €์žฅ

3
Step 3
**Step 3: ๋ฆฌ๋”๋ณด๋“œ ํŽ˜์ด์ง€ ๊ตฌํ˜„**

`app/modules/quiz-arena/leaderboard/index.php` ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ  ๋‹ค์Œ์„ ๊ตฌํ˜„ํ•˜์„ธ์š”:

1. **์ „์ฒด ์ˆœ์œ„ ์กฐํšŒ**:
   - user_scores ํ…Œ์ด๋ธ”์—์„œ mb_id๋ณ„ ์ด์  ์ง‘๊ณ„ (SUM)
   - ์ ์ˆ˜ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ, ์ƒ์œ„ 20๋ช…๋งŒ ํ‘œ์‹œ
   - ๋น„ํšŒ์›('guest')์€ ์ œ์™ธ

2. **์ˆœ์œ„ํ‘œ UI**:
   - ํ…Œ์ด๋ธ” ํ˜•์‹: ์ˆœ์œ„ | ์‚ฌ์šฉ์ž๋ช… | ์ด์  | ์™„๋ฃŒํ•œ ํ€ด์ฆˆ ์ˆ˜
   - 1~3์œ„๋Š” ๊ธˆ/์€/๋™ ๋ฉ”๋‹ฌ ์•„์ด์ฝ˜ ํ‘œ์‹œ
   - ๋ณธ์ธ ์ˆœ์œ„๋Š” ํ•˜์ด๋ผ์ดํŠธ (๋ฐฐ๊ฒฝ์ƒ‰ ๋ณ€๊ฒฝ)

3. **ํ•„ํ„ฐ ๊ธฐ๋Šฅ**:
   - ์ƒ๋‹จ์— ํƒญ: "์ „์ฒด" / "์˜ค๋Š˜" / "์ด๋ฒˆ ์ฃผ"
   - ํƒญ ํด๋ฆญ ์‹œ ๊ธฐ๊ฐ„ ํ•„ํ„ฐ๋ง (completed_at ๊ธฐ์ค€)
   - AJAX ์—†์ด ํŽ˜์ด์ง€ ์ƒˆ๋กœ๊ณ ์นจ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ (`?period=today` ํŒŒ๋ผ๋ฏธํ„ฐ)

4. **๋นˆ ์ƒํƒœ ์ฒ˜๋ฆฌ**:
   - ์ˆœ์œ„ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์„ ๊ฒฝ์šฐ "์•„์ง ๊ธฐ๋ก์ด ์—†์Šต๋‹ˆ๋‹ค" ๋ฉ”์‹œ์ง€ + ํ€ด์ฆˆ ํ’€๋Ÿฌ ๊ฐ€๊ธฐ ๋ฒ„ํŠผ

5. **๋””์ž์ธ**:
   - ํ…Œ์ด๋ธ” ํ—ค๋”: ์–ด๋‘์šด ๋ฐฐ๊ฒฝ (`var(--m-surface)` + ํˆฌ๋ช…๋„)
   - ์ˆœ์œ„ ์…€: ํฐ ํฐํŠธ, ๋ณผ๋“œ
   - ๋ฉ”๋‹ฌ ์•„์ด์ฝ˜: ๐Ÿฅ‡๐Ÿฅˆ๐Ÿฅ‰ ์ด๋ชจ์ง€ ์‚ฌ์šฉ
   - ๋ณธ์ธ ํ–‰: `background: rgba(102, 126, 234, 0.1);`

**SQL ์˜ˆ์‹œ:**
```sql
SELECT 
  mb_id,
  SUM(score) as total_score,
  COUNT(*) as quiz_count
FROM user_scores
WHERE mb_id != 'guest'
GROUP BY mb_id
ORDER BY total_score DESC
LIMIT 20
```

**๊ธฐ๊ฐ„ ํ•„ํ„ฐ SQL (์˜ค๋Š˜ ๊ธฐ์ค€):**
```sql
WHERE mb_id != 'guest' 
  AND DATE(completed_at) = DATE('now')
```

**์˜ˆ์ƒ URL**: `/quiz-arena/leaderboard?period=all`

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: - ์ „์ฒด ์‚ฌ์šฉ์ž ์ ์ˆ˜ ์ˆœ์œ„ํ‘œ ํ‘œ์‹œ (์ƒ์œ„ 20๋ช…) - 1~3์œ„์— ๋ฉ”๋‹ฌ ์•„์ด์ฝ˜ ํ‘œ์‹œ - ๋ณธ์ธ ์ˆœ์œ„ ํ•˜์ด๋ผ์ดํŠธ (๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž) - ํƒญ ํด๋ฆญ์œผ๋กœ ๊ธฐ๊ฐ„ ํ•„ํ„ฐ๋ง ๋™์ž‘ - ๋ฐ์ดํ„ฐ ์—†์„ ์‹œ ๋นˆ ์ƒํƒœ ๋ฉ”์‹œ์ง€

4
Step 4
**Step 4: ๊ฐœ์ธ ํ†ต๊ณ„ ํŽ˜์ด์ง€ ๊ตฌํ˜„**

`app/modules/quiz-arena/my-stats/index.php` ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ  ๋‹ค์Œ์„ ๊ตฌํ˜„ํ•˜์„ธ์š”:

1. **๋กœ๊ทธ์ธ ์ฒดํฌ**:
   - `$is_member`๊ฐ€ false๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
   - ๋น„ํšŒ์›์€ ์ ‘๊ทผ ๋ถˆ๊ฐ€ ๋ฉ”์‹œ์ง€

2. **๊ฐœ์ธ ํ†ต๊ณ„ ๋ฐ์ดํ„ฐ ์กฐํšŒ**:
   - ์ด ํ’€์ดํ•œ ํ€ด์ฆˆ ์ˆ˜
   - ํ‰๊ท  ์ •๋‹ต๋ฅ  (์ •๋‹ต ์ˆ˜ / ์ด ๋ฌธ์ œ ์ˆ˜ * 100)
   - ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์™„๋ฃŒ ํšŸ์ˆ˜ (quiz_sets ์กฐ์ธ)
   - ์ตœ๊ทผ ์™„๋ฃŒํ•œ ํ€ด์ฆˆ 5๊ฐœ (completed_at ๋‚ด๋ฆผ์ฐจ์ˆœ)

3. **ํ†ต๊ณ„ ์นด๋“œ UI**:
   - ์ƒ๋‹จ: ํฐ ์ˆซ์ž๋กœ "์ด ํ’€์ด ํ€ด์ฆˆ: 12๊ฐœ" / "ํ‰๊ท  ์ •๋‹ต๋ฅ : 85%"
   - ์ค‘๊ฐ„: ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์™„๋ฃŒ ํšŸ์ˆ˜ ๋ฐ” ์ฐจํŠธ (CSS `width` ํผ์„ผํŠธ๋กœ ์‹œ๊ฐํ™”)
   - ํ•˜๋‹จ: ์ตœ๊ทผ ์™„๋ฃŒ ํ€ด์ฆˆ ๋ชฉ๋ก (์ œ๋ชฉ, ์ ์ˆ˜, ๋‚ ์งœ)

4. **๋ฐ” ์ฐจํŠธ ๊ตฌํ˜„** (์ˆœ์ˆ˜ CSS):
   ```html
   <div class="stat-bar">
     <div class="stat-label">์ƒ์‹</div>
     <div class="stat-progress" style="width: 70%;">7ํšŒ</div>
   </div>
   ```
   - ๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์™„๋ฃŒ ํšŸ์ˆ˜๋ฅผ ์ตœ๋Œ€๊ฐ’ ๋Œ€๋น„ ๋น„์œจ๋กœ ๊ณ„์‚ฐ
   - ๋ฐ” ์ƒ‰์ƒ: ์นดํ…Œ๊ณ ๋ฆฌ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ทธ๋ผ๋””์–ธํŠธ

5. **๋นˆ ์ƒํƒœ ์ฒ˜๋ฆฌ**:
   - ์•„์ง ํ€ด์ฆˆ๋ฅผ ํ’€์ง€ ์•Š์€ ๊ฒฝ์šฐ "์ฒซ ํ€ด์ฆˆ๋ฅผ ํ’€์–ด๋ณด์„ธ์š”!" ๋ฉ”์‹œ์ง€ + ํ€ด์ฆˆ ๋ชฉ๋ก ๋ฒ„ํŠผ

6. **๋””์ž์ธ**:
   - ํ†ต๊ณ„ ์นด๋“œ: `background: var(--m-surface); padding: 32px;`
   - ์ˆซ์ž๋Š” ํฐ ํฐํŠธ (48px) + ๋ณผ๋“œ
   - ๋ฐ” ์ฐจํŠธ: ์• ๋‹ˆ๋ฉ”์ด์…˜ (ํŽ˜์ด์ง€ ๋กœ๋“œ ์‹œ 0%์—์„œ ์‹ค์ œ ๊ฐ’๊นŒ์ง€ 0.5์ดˆ transition)

**SQL ์˜ˆ์‹œ (์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์ง‘๊ณ„):**
```sql
SELECT 
  qs.category,
  COUNT(*) as count
FROM user_scores us
JOIN quiz_sets qs ON us.quiz_set_id = qs.id
WHERE us.mb_id = :mb_id
GROUP BY qs.category
```

**์˜ˆ์ƒ URL**: `/quiz-arena/my-stats`

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: - ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ - ๊ฐœ์ธ ํ†ต๊ณ„ ์š”์•ฝ ์นด๋“œ ํ‘œ์‹œ (์ด ํ€ด์ฆˆ ์ˆ˜, ํ‰๊ท  ์ •๋‹ต๋ฅ ) - ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์™„๋ฃŒ ํšŸ์ˆ˜ ๋ฐ” ์ฐจํŠธ ํ‘œ์‹œ - ์ตœ๊ทผ ์™„๋ฃŒ ํ€ด์ฆˆ 5๊ฐœ ๋ชฉ๋ก - ํ€ด์ฆˆ ๊ธฐ๋ก ์—†์„ ์‹œ ๋นˆ ์ƒํƒœ ๋ฉ”์‹œ์ง€

5
Step 5
**Step 5: ๊ด€๋ฆฌ์ž ํ€ด์ฆˆ ๋“ฑ๋ก ํผ ๊ตฌํ˜„**

`app/modules/quiz-arena/admin/index.php` ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ  ๋‹ค์Œ์„ ๊ตฌํ˜„ํ•˜์„ธ์š”:

1. **๊ด€๋ฆฌ์ž ๊ถŒํ•œ ์ฒดํฌ**:
   - `$member['mb_level']`์ด 10 ์ด์ƒ์ธ์ง€ ํ™•์ธ (g5se ์ตœ๊ณ ๊ด€๋ฆฌ์ž)
   - ๊ถŒํ•œ ์—†์œผ๋ฉด "์ ‘๊ทผ ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค" ๋ฉ”์‹œ์ง€ + ํ™ˆ์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ ๋ฒ„ํŠผ

2. **ํ€ด์ฆˆ ์„ธํŠธ ๋“ฑ๋ก ํผ**:
   - ์ž…๋ ฅ ํ•„๋“œ:
     - ์นดํ…Œ๊ณ ๋ฆฌ (select: ์ƒ์‹/์—ญ์‚ฌ/๊ณผํ•™/์—”ํ„ฐํ…Œ์ธ๋จผํŠธ/๊ธฐํƒ€)
     - ํ€ด์ฆˆ ์„ธํŠธ ์ œ๋ชฉ (text)
     - ๋‚œ์ด๋„ (select: ์‰ฌ์›€/๋ณดํ†ต/์–ด๋ ค์›€)
   - "๋ฌธ์ œ ์ถ”๊ฐ€" ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ๋ฌธ์ œ ์ž…๋ ฅ ํ•„๋“œ ๋™์  ์ถ”๊ฐ€ (JS)

3. **๋ฌธ์ œ ์ž…๋ ฅ ํ•„๋“œ** (๋™์  ์ถ”๊ฐ€):
   - ๋ฌธ์ œ ํ…์ŠคํŠธ (textarea)
   - ์„ ํƒ์ง€ A/B/C/D (text input 4๊ฐœ)
   - ์ •๋‹ต ์„ ํƒ (radio button)
   - ํ•ด์„ค (textarea, ์„ ํƒ์‚ฌํ•ญ)
   - "์ด ๋ฌธ์ œ ์‚ญ์ œ" ๋ฒ„ํŠผ

4. **ํผ ์ œ์ถœ ์ฒ˜๋ฆฌ**:
   - POST ์š”์ฒญ ์‹œ:
     - quiz_sets ํ…Œ์ด๋ธ”์— ์„ธํŠธ ์ •๋ณด INSERT
     - ๋ฐ˜ํ™˜๋œ set_id๋กœ ๊ฐ ๋ฌธ์ œ๋ฅผ quiz_questions ํ…Œ์ด๋ธ”์— INSERT
     - ํŠธ๋žœ์žญ์…˜ ์‚ฌ์šฉ (SQLite `BEGIN`/`COMMIT`)
   - ์„ฑ๊ณต ์‹œ "ํ€ด์ฆˆ ์„ธํŠธ๊ฐ€ ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค" ๋ฉ”์‹œ์ง€ + ๋ชฉ๋ก์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ

5. **๊ธฐ์กด ํ€ด์ฆˆ ์„ธํŠธ ๋ชฉ๋ก ํ‘œ์‹œ**:
   - ํผ ํ•˜๋‹จ์— ๋“ฑ๋ก๋œ ํ€ด์ฆˆ ์„ธํŠธ ํ…Œ์ด๋ธ”
   - ๊ฐ ํ–‰: ์ œ๋ชฉ | ์นดํ…Œ๊ณ ๋ฆฌ | ๋ฌธ์ œ ์ˆ˜ | ์‚ญ์ œ ๋ฒ„ํŠผ
   - ์‚ญ์ œ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ™•์ธ ๋ชจ๋‹ฌ + AJAX DELETE ์š”์ฒญ

6. **UI ๋””์ž์ธ**:
   - ํผ ๋ ˆ์ด์•„์›ƒ: 2์—ด ๊ทธ๋ฆฌ๋“œ (๋ ˆ์ด๋ธ” ์ขŒ์ธก, ์ž…๋ ฅ ์šฐ์ธก)
   - ๋ฌธ์ œ ์นด๋“œ: ์ ์„  ํ…Œ๋‘๋ฆฌ + ๋ฐฐ๊ฒฝ์ƒ‰ ๊ตฌ๋ถ„
   - "๋ฌธ์ œ ์ถ”๊ฐ€" ๋ฒ„ํŠผ: ์ ์„  ์Šคํƒ€์ผ + hover ์‹œ ๋ฐฐ๊ฒฝ ๋ณ€ํ™”

**JavaScript ๋™์  ํ•„๋“œ ์ถ”๊ฐ€ ์˜ˆ์‹œ:**
```javascript
let questionCount = 1;
document.getElementById('add-question-btn').addEventListener('click', () => {
  const container = document.getElementById('questions-container');
  const questionHtml = `
    <div class="question-card" data-index="${questionCount}">
      <h4>๋ฌธ์ œ ${questionCount}</h4>
      <textarea name="questions[${questionCount}][text]" placeholder="๋ฌธ์ œ ํ…์ŠคํŠธ" required></textarea>
      <input type="text" name="questions[${questionCount}][option_a]" placeholder="A" required>
      <input type="text" name="questions[${questionCount}][option_b]" placeholder="B" required>
      <input type="text" name="questions[${questionCount}][option_c]" placeholder="C" required>
      <input type="text" name="questions[${questionCount}][option_d]" placeholder="D" required>
      <label><input type="radio" name="questions[${questionCount}][correct]" value="A" required> ์ •๋‹ต: A</label>
      <textarea name="questions[${questionCount}][explanation]" placeholder="ํ•ด์„ค (์„ ํƒ)"></textarea>
      <button type="button" onclick="this.parentElement.remove()">์‚ญ์ œ</button>
    </div>
  `;
  container.insertAdjacentHTML('beforeend', questionHtml);
  questionCount++;
});
```

**์˜ˆ์ƒ URL**: `/quiz-arena/admin`

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: - ๊ด€๋ฆฌ์ž๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ (๊ถŒํ•œ ์ฒดํฌ) - ํ€ด์ฆˆ ์„ธํŠธ ๋“ฑ๋ก ํผ ํ‘œ์‹œ - "๋ฌธ์ œ ์ถ”๊ฐ€" ๋ฒ„ํŠผ์œผ๋กœ ๋ฌธ์ œ ํ•„๋“œ ๋™์  ์ถ”๊ฐ€ - ํผ ์ œ์ถœ ์‹œ quiz_sets + quiz_questions ํ…Œ์ด๋ธ”์— ๋ฐ์ดํ„ฐ ์ €์žฅ - ๊ธฐ์กด ํ€ด์ฆˆ ์„ธํŠธ ๋ชฉ๋ก ํ‘œ์‹œ + ์‚ญ์ œ ๊ธฐ๋Šฅ

6
Step 6
**Step 6: ํƒ€์ด๋จธ ๋ชจ๋“œ & ํžŒํŠธ ์‹œ์Šคํ…œ (๋ณด๋„ˆ์Šค ๊ธฐ๋Šฅ)**

`app/modules/quiz-arena/play/index.php` ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜์—ฌ ๋‹ค์Œ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”:

1. **ํƒ€์ด๋จธ ๋ชจ๋“œ ํ™œ์„ฑํ™”**:
   - URL ํŒŒ๋ผ๋ฏธํ„ฐ `?mode=timer` ๊ฐ์ง€
   - ๊ฐ ๋ฌธ์ œ๋‹น 30์ดˆ ์ œํ•œ ์‹œ๊ฐ„
   - ํ™”๋ฉด ์ƒ๋‹จ์— ์นด์šดํŠธ๋‹ค์šด ํƒ€์ด๋จธ ํ‘œ์‹œ (ํฐ ํฐํŠธ)
   - ์‹œ๊ฐ„ ์ดˆ๊ณผ ์‹œ ์ž๋™์œผ๋กœ ์˜ค๋‹ต ์ฒ˜๋ฆฌ + ๋‹ค์Œ ๋ฌธ์ œ๋กœ ์ด๋™

2. **ํƒ€์ด๋จธ UI**:
   - ์›ํ˜• ํ”„๋กœ๊ทธ๋ ˆ์Šค ๋ฐ” (SVG `<circle>` ์‚ฌ์šฉ)
   - ๋‚จ์€ ์‹œ๊ฐ„์ด 10์ดˆ ์ดํ•˜์ผ ๋•Œ ๋นจ๊ฐ„์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝ + ๊นœ๋นก์ž„ ์• ๋‹ˆ๋ฉ”์ด์…˜
   - ์‹œ๊ฐ„ ์ดˆ๊ณผ ์‹œ "์‹œ๊ฐ„ ์ดˆ๊ณผ!" ๋ฉ”์‹œ์ง€ + ์ •๋‹ต ํ‘œ์‹œ

3. **ํžŒํŠธ ์‹œ์Šคํ…œ**:
   - ํ™”๋ฉด ์šฐ์ธก ์ƒ๋‹จ์— "๐Ÿ’ก ํžŒํŠธ ์‚ฌ์šฉ" ๋ฒ„ํŠผ
   - ํด๋ฆญ ์‹œ:
     - ์˜ค๋‹ต ์„ ํƒ์ง€ 1๊ฐœ๋ฅผ ๋žœ๋ค์œผ๋กœ ๋น„ํ™œ์„ฑํ™” (ํ๋ฆฌ๊ฒŒ ํ‘œ์‹œ)
     - ํžŒํŠธ ์‚ฌ์šฉ ํšŸ์ˆ˜ ์ œํ•œ (ํ€ด์ฆˆ๋‹น 3ํšŒ)
     - ํžŒํŠธ ์‚ฌ์šฉ ์‹œ ์ ์ˆ˜ -5์  ์ฐจ๊ฐ
   - ํžŒํŠธ ์‚ฌ์šฉ ํšŸ์ˆ˜ ํ‘œ์‹œ ("ํžŒํŠธ ๋‚จ์Œ: 2/3")

4. **์ ์ˆ˜ ๊ณ„์‚ฐ ๋กœ์ง ์ˆ˜์ •**:
   - ๊ธฐ๋ณธ ์ ์ˆ˜: ์ •๋‹ต ์‹œ +10์ 
   - ํƒ€์ด๋จธ ๋ชจ๋“œ: ๋‚จ์€ ์‹œ๊ฐ„์— ๋น„๋ก€ํ•œ ๋ณด๋„ˆ์Šค ์ ์ˆ˜ (์ตœ๋Œ€ +5์ )
   - ํžŒํŠธ ์‚ฌ์šฉ: -5์  ์ฐจ๊ฐ
   - ์ตœ์ข… ์ ์ˆ˜ = ๊ธฐ๋ณธ ์ ์ˆ˜ + ์‹œ๊ฐ„ ๋ณด๋„ˆ์Šค - ํžŒํŠธ ํŽ˜๋„ํ‹ฐ

5. **ํƒ€์ด๋จธ JavaScript ๊ตฌํ˜„**:
```javascript
let timeLeft = 30;
const timerInterval = setInterval(() => {
  timeLeft--;
  document.getElementById('timer-display').textContent = timeLeft;
  updateTimerProgress(timeLeft / 30 * 100);
  
  if (timeLeft <= 10) {
    document.getElementById('timer-display').classList.add('warning');
  }
  
  if (timeLeft <= 0) {
    clearInterval(timerInterval);
    handleTimeout();
  }
}, 1000);

function handleTimeout() {
  // ์˜ค๋‹ต ์ฒ˜๋ฆฌ ๋กœ์ง
  showMessage('์‹œ๊ฐ„ ์ดˆ๊ณผ!');
  setTimeout(() => nextQuestion(), 2000);
}
```

6. **ํžŒํŠธ ๊ธฐ๋Šฅ JavaScript**:
```javascript
let hintsRemaining = 3;
function useHint() {
  if (hintsRemaining <= 0) {
    alert('ํžŒํŠธ๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค');
    return;
  }
  
  const wrongOptions = ['A', 'B', 'C', 'D'].filter(opt => opt !== correctAnswer);
  const randomWrong = wrongOptions[Math.floor(Math.random() * wrongOptions.length)];
  document.querySelector(`[data-option="${randomWrong}"]`).style.opacity = '0.3';
  document.querySelector(`[data-option="${randomWrong}"]`).disabled = true;
  
  hintsRemaining--;
  currentScore -= 5;
  updateHintDisplay();
}
```

7. **UI ๊ฐœ์„ **:
   - ํƒ€์ด๋จธ ๋ชจ๋“œ ์„ ํƒ ํ† ๊ธ€ ์Šค์œ„์น˜ (๋ฉ”์ธ ํŽ˜์ด์ง€์— ์ถ”๊ฐ€)
   - ํžŒํŠธ ๋ฒ„ํŠผ: ๋ฐ˜ํˆฌ๋ช… ๋ฐฐ๊ฒฝ + ์•„์ด์ฝ˜
   - ์‹œ๊ฐ„ ์ดˆ๊ณผ ์‹œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ (shake)

**์˜ˆ์ƒ URL**: `/quiz-arena/play?set_id=1&mode=timer`

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: - ํƒ€์ด๋จธ ๋ชจ๋“œ ํ™œ์„ฑํ™” ์‹œ ๊ฐ ๋ฌธ์ œ๋‹น 30์ดˆ ์นด์šดํŠธ๋‹ค์šด - ์‹œ๊ฐ„ ์ดˆ๊ณผ ์‹œ ์ž๋™ ์˜ค๋‹ต ์ฒ˜๋ฆฌ + ๋‹ค์Œ ๋ฌธ์ œ ์ด๋™ - ํžŒํŠธ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์˜ค๋‹ต 1๊ฐœ ๋น„ํ™œ์„ฑํ™” (์ ์ˆ˜ ์ฐจ๊ฐ) - ํƒ€์ด๋จธ ์ง„ํ–‰์— ๋”ฐ๋ผ UI ์ƒ‰์ƒ ๋ณ€๊ฒฝ (10์ดˆ ์ดํ•˜ ๋นจ๊ฐ•) - ์ตœ์ข… ์ ์ˆ˜์— ์‹œ๊ฐ„ ๋ณด๋„ˆ์Šค + ํžŒํŠธ ํŽ˜๋„ํ‹ฐ ๋ฐ˜์˜

์ œ์ถœ๋œ ์ž‘ํ’ˆ (0)

๋กœ๊ทธ์ธ ํ›„ ์ œ์ถœ

์•„์ง ์ œ์ถœ๋œ ์ž‘ํ’ˆ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋„์ „์ž๊ฐ€ ๋˜์–ด๋ณด์„ธ์š”!

๋Œ“๊ธ€ (0)

๋กœ๊ทธ์ธ ํ›„ ๋Œ“๊ธ€์„ ๋‚จ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋Œ“๊ธ€์„ ๋‚จ๊ฒจ๋ณด์„ธ์š”!