๐ŸŽฏ g5se ์˜ค๋Š˜์˜ ํƒ€๋กœ ์Šคํ”„๋ ˆ๋“œ ํ•ด์„๊ธฐ - 3์žฅ ์นด๋“œ ๋ฆฌ๋”ฉ & ์šด์„ธ ์ €์žฅ - ๋ฐ”์ด๋ธŒ์ฝ”๋”ฉ ๋ ˆ์‹œํ”ผ
์ค‘๊ธ‰ PHP g5se AI: Claude

๐ŸŽฏ g5se ์˜ค๋Š˜์˜ ํƒ€๋กœ ์Šคํ”„๋ ˆ๋“œ ํ•ด์„๊ธฐ - 3์žฅ ์นด๋“œ ๋ฆฌ๋”ฉ & ์šด์„ธ ์ €์žฅ

๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ช… g5se-tarot-spread-interpreter
์กฐํšŒ์ˆ˜ 50 0๊ฑด ์ œ์ถœ

๋ฌธ์ œ ์„ค๋ช…

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

ํƒ€๋กœ ์นด๋“œ 3์žฅ ์Šคํ”„๋ ˆ๋“œ(๊ณผ๊ฑฐ-ํ˜„์žฌ-๋ฏธ๋ž˜)๋ฅผ ๋ฝ‘๊ณ , ๊ฐ ์นด๋“œ์˜ ์˜๋ฏธ์™€ ์ „์ฒด ํ•ด์„์„ ์ œ๊ณตํ•˜๋Š” ํƒ€๋กœ ๋ฆฌ๋”ฉ ํŽ˜์ด์ง€์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๋Š” ๋ฆฌ๋”ฉ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ณผ๊ฑฐ ๊ธฐ๋ก์„ ๋˜๋Œ์•„๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โœจ ํ•„์ˆ˜ ๊ธฐ๋Šฅ

1. ํƒ€๋กœ ์นด๋“œ ๋ฑ & ์Šคํ”„๋ ˆ๋“œ

  • ๋ฉ”์ด์ € ์•„๋ฅด์นด๋‚˜ 22์žฅ ์นด๋“œ ๋ฐ์ดํ„ฐ (์นด๋“œ๋ช…, ์ •๋ฐฉํ–ฅ/์—ญ๋ฐฉํ–ฅ ํ‚ค์›Œ๋“œ, ์ด๋ฏธ์ง€)
  • "๊ณผ๊ฑฐ-ํ˜„์žฌ-๋ฏธ๋ž˜" 3์žฅ ์Šคํ”„๋ ˆ๋“œ ๋ฌด์ž‘์œ„ ๋ฝ‘๊ธฐ
  • ๊ฐ ์นด๋“œ๋งˆ๋‹ค ์ •๋ฐฉํ–ฅ/์—ญ๋ฐฉํ–ฅ ๋žœ๋ค ๊ฒฐ์ •
  • ์นด๋“œ ๋ฝ‘๊ธฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ (๋’ค์ง‘ํžˆ๋Š” ํšจ๊ณผ)

2. ์นด๋“œ ํ•ด์„ ํ‘œ์‹œ

  • ๊ฐ ์นด๋“œ๋ณ„ ์œ„์น˜(๊ณผ๊ฑฐ/ํ˜„์žฌ/๋ฏธ๋ž˜) ๋ผ๋ฒจ๋ง
  • ์นด๋“œ ์ด๋ฏธ์ง€ + ์ •์—ญ๋ฐฉํ–ฅ ํ‘œ์‹œ
  • ํ•ด๋‹น ์นด๋“œ์˜ ํ‚ค์›Œ๋“œ & ๊ฐ„๋‹จํ•œ ์˜๋ฏธ ์„ค๋ช…
  • 3์žฅ ์ „์ฒด๋ฅผ ์ข…ํ•ฉํ•œ "์˜ค๋Š˜์˜ ์šด์„ธ ํ•ด์„" ๋ฌธ๊ตฌ ์ž๋™ ์ƒ์„ฑ

3. ๋ฆฌ๋”ฉ ๊ธฐ๋ก ์ €์žฅ (SQLite)

  • ๋ฆฌ๋”ฉ ๋‚ ์งœ, 3์žฅ ์นด๋“œ ์ •๋ณด(์นด๋“œ๋ช…, ์ •์—ญ๋ฐฉํ–ฅ), ์ข…ํ•ฉ ํ•ด์„ ์ €์žฅ
  • ์ €์žฅ ์‹œ ํšŒ์› ID ์—ฐ๋™ (๋น„ํšŒ์›์€ ์„ธ์…˜ ID๋กœ ์ž„์‹œ ์ €์žฅ)
  • ๊ณผ๊ฑฐ ๋ฆฌ๋”ฉ ๋ชฉ๋ก ํŽ˜์ด์ง€: ๋‚ ์งœ๋ณ„ ์นด๋“œ ์กฐํ•ฉ & ํ•ด์„ ์š”์•ฝ
  • ์ƒ์„ธ ๋ณด๊ธฐ: ์ €์žฅ๋œ ๋ฆฌ๋”ฉ ๋‹ค์‹œ ๋ณด๊ธฐ

4. ๋ฐ˜์‘ํ˜• UI & ๋‹คํฌ๋ชจ๋“œ

  • modern shell ์ ์šฉ์œผ๋กœ ์‚ฌ์ดํŠธ ์ „์ฒด nav/footer/๋‹คํฌ๋ชจ๋“œ ํ† ๊ธ€ ์ž๋™ ์—ฐ๋™
  • ์นด๋“œ ์ด๋ฏธ์ง€๋Š” CDN ๋˜๋Š” public asset์œผ๋กœ ์ œ๊ณต (์˜ˆ: Rider-Waite ๋ฑ ์ด๋ฏธ์ง€)
  • ๋ชจ๋ฐ”์ผ์—์„œ๋„ ์นด๋“œ 3์žฅ์ด ์„ธ๋กœ ์Šคํƒ์œผ๋กœ ๊น”๋”ํ•˜๊ฒŒ ํ‘œ์‹œ

๐ŸŽ ๋ณด๋„ˆ์Šค ๊ธฐ๋Šฅ

  • ์นด๋“œ ๋ฝ‘๊ธฐ ์ „ "์งˆ๋ฌธ ์ž…๋ ฅ" ํผ (๋ฆฌ๋”ฉ ์ฃผ์ œ ๊ธฐ๋ก)
  • ๋ฆฌ๋”ฉ ๊ฒฐ๊ณผ ๊ณต์œ  ๋งํฌ ์ƒ์„ฑ (๊ณ ์œ  URL๋กœ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋„ ๋ณผ ์ˆ˜ ์žˆ๊ฒŒ)
  • ์นด๋“œ ์ƒ์„ธ ์„ค๋ช… ๋ชจ๋‹ฌ (๊ฐ ์นด๋“œ ํด๋ฆญ ์‹œ ํ’€ ๋””์Šคํฌ๋ฆฝ์…˜ ํŒ์—…)
  • ๋ฆฌ๋”ฉ ํ†ต๊ณ„: ๊ฐ€์žฅ ๋งŽ์ด ๋‚˜์˜จ ์นด๋“œ TOP 3

๐ŸŽจ ๋””์ž์ธ ๊ฐ€์ด๋“œ

  • ํƒ€๋กœ ๋ถ„์œ„๊ธฐ์— ๋งž๋Š” ๋ฏธ์Šคํ‹ฑํ•œ ์ƒ‰์ƒ (๋ณด๋ผ/๋‚จ์ƒ‰ ๊ณ„์—ด)
  • ์นด๋“œ ๋’ท๋ฉด ๋””์ž์ธ์€ CSS๋กœ ํŒจํ„ด ๊ตฌํ˜„ (๋˜๋Š” placeholder ์ด๋ฏธ์ง€)
  • ๋ฆฌ๋”ฉ ๊ฒฐ๊ณผ๋Š” ์นด๋“œ๋ณ„๋กœ ๊ตฌ๋ถ„๋œ ์„น์…˜ ๋ ˆ์ด์•„์›ƒ
  • ์ €์žฅ ๋ฒ„ํŠผ์€ ๋ˆˆ์— ๋„๋Š” ์œ„์น˜์— ๋ฐฐ์น˜

๐Ÿ“š ํ•™์Šต ํฌ์ธํŠธ

  • g5se ํด๋” ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ… ํ™œ์šฉ (app/modules/tarot-spread/index.php)
  • ๋ชจ๋“ˆ ์ „์šฉ SQLite DB ์„ค๊ณ„ (๋ฆฌ๋”ฉ ๊ธฐ๋ก CRUD)
  • ๋žœ๋ค ๋กœ์ง (์นด๋“œ ์…”ํ”Œ, ์ •์—ญ๋ฐฉํ–ฅ ๊ฒฐ์ •)
  • AJAX ์—†์ด ํผ ์ œ์ถœ๋กœ ๋ฆฌ๋”ฉ ์ €์žฅ & ํŽ˜์ด์ง€ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
  • modern shell๋กœ ์‚ฌ์ดํŠธ ์ผ๊ด€์„ฑ ์œ ์ง€

์ œ์•ฝ ์กฐ๊ฑด

  • โ€ข g5se ํด๋” ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ… ์‚ฌ์šฉ (๋ผ์šฐํŠธ ๋“ฑ๋ก ๋ถˆํ•„์š”)
  • โ€ข modern shell (_head.inc.php + m-shell + _nav.inc.php + m-container + _footer.inc.php) ํ•„์ˆ˜ ์ ์šฉ
  • โ€ข ๋””์ž์ธ ํ† ํฐ (--m-surface, --m-text ๋“ฑ) ํ™œ์šฉ์œผ๋กœ ๋‹คํฌ๋ชจ๋“œ ์ž๋™ ๋Œ€์‘
  • โ€ข ๋ชจ๋“ˆ ์ „์šฉ SQLite (G5_DATA_PATH/modules/tarot-spread.sqlite) ์‚ฌ์šฉ
  • โ€ข g5se ๋ฉ”์ธ DB์— ํ…Œ์ด๋ธ” ์ƒ์„ฑ ๊ธˆ์ง€
  • โ€ข ์™ธ๋ถ€ ๋นŒ๋“œ ๋„๊ตฌ(npm/webpack) ์‚ฌ์šฉ ๊ธˆ์ง€
  • โ€ข CDN ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ตœ์†Œํ™” (์ˆœ์ˆ˜ HTML/CSS/JS ๊ถŒ์žฅ)
  • โ€ข prepared statement๋กœ SQL ์ธ์ ์…˜ ๋ฐฉ์ง€
  • โ€ข htmlspecialchars()๋กœ XSS ๋ฐฉ์ง€
  • โ€ข ํšŒ์›/๋น„ํšŒ์› ๋ชจ๋‘ ์ด์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค๊ณ„

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

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

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

## Step 1: ํƒ€๋กœ ์Šคํ”„๋ ˆ๋“œ ํŽ˜์ด์ง€ ๊ณจ๊ฒฉ ์ƒ์„ฑ

`app/modules/tarot-spread/index.php` ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”. ์ด ํŒŒ์ผ์€ ์ž๋™์œผ๋กœ `/tarot-spread` URL์— ๋งคํ•‘๋ฉ๋‹ˆ๋‹ค.

### ํŒŒ์ผ ๋‚ด์šฉ:

```php
<?php
include_once('./_common.php');

// ํƒ€๋กœ ์นด๋“œ ๋ฑ ๋ฐ์ดํ„ฐ (๋ฉ”์ด์ € ์•„๋ฅด์นด๋‚˜ 22์žฅ)
$tarot_deck = [
    ['name' => 'The Fool', 'upright' => '์ƒˆ๋กœ์šด ์‹œ์ž‘, ์ˆœ์ˆ˜ํ•จ, ์ž์œ ', 'reversed' => '๋ฌด๋ชจํ•จ, ๊ฒฝ์†”ํ•จ, ๋ฆฌ์Šคํฌ'],
    ['name' => 'The Magician', 'upright' => '์ฐฝ์กฐ๋ ฅ, ์˜์ง€, ๊ธฐ์ˆ ', 'reversed' => '์กฐ์ž‘, ์†์ž„์ˆ˜, ์žฌ๋Šฅ ๋‚ญ๋น„'],
    ['name' => 'The High Priestess', 'upright' => '์ง๊ด€, ์‹ ๋น„, ์ž ์žฌ์˜์‹', 'reversed' => '๋น„๋ฐ€, ๋‹จ์ ˆ, ์นจ๋ฌต'],
    ['name' => 'The Empress', 'upright' => 'ํ’์š”, ๋ชจ์„ฑ, ์ž์—ฐ', 'reversed' => '์˜์กด, ์งˆ์‹, ๊ณตํ—ˆํ•จ'],
    ['name' => 'The Emperor', 'upright' => '๊ถŒ์œ„, ๊ตฌ์กฐ, ํ†ต์ œ', 'reversed' => '๋…์žฌ, ๊ฒฝ์ง, ๋ฏธ์„ฑ์ˆ™'],
    ['name' => 'The Hierophant', 'upright' => '์ „ํ†ต, ๊ต์œก, ์‹ ๋…', 'reversed' => '๋ฐ˜ํ•ญ, ์ž์œ ์‚ฌ์ƒ, ๋น„์ •ํ†ต'],
    ['name' => 'The Lovers', 'upright' => '์‚ฌ๋ž‘, ์กฐํ™”, ์„ ํƒ', 'reversed' => '๋ถˆ๊ท ํ˜•, ๊ฐˆ๋“ฑ, ์ž˜๋ชป๋œ ์„ ํƒ'],
    ['name' => 'The Chariot', 'upright' => '์˜์ง€, ์Šน๋ฆฌ, ๊ฒฐ๋‹จ', 'reversed' => '๋ฐฉํ–ฅ ์ƒ์‹ค, ์ขŒ์ ˆ, ๊ณต๊ฒฉ์„ฑ'],
    ['name' => 'Strength', 'upright' => '์šฉ๊ธฐ, ์ธ๋‚ด, ์ž์ œ๋ ฅ', 'reversed' => '์ž๊ธฐ ์˜์‹ฌ, ์•ฝํ•จ, ์ž์ œ๋ ฅ ๋ถ€์กฑ'],
    ['name' => 'The Hermit', 'upright' => '๋‚ด๋ฉด ํƒ๊ตฌ, ๊ณ ๋…, ์ง€ํ˜œ', 'reversed' => '๊ณ ๋ฆฝ, ์™ธ๋กœ์›€, ์ฒ ํšŒ'],
    ['name' => 'Wheel of Fortune', 'upright' => '์šด๋ช…, ๋ณ€ํ™”, ์ˆœํ™˜', 'reversed' => '๋ถˆ์šด, ์ €ํ•ญ, ์ •์ฒด'],
    ['name' => 'Justice', 'upright' => '๊ณต์ •, ์ง„์‹ค, ๋ฒ•', 'reversed' => '๋ถˆ๊ณต์ •, ๊ฑฐ์ง“, ์ฑ…์ž„ ํšŒํ”ผ'],
    ['name' => 'The Hanged Man', 'upright' => 'ํฌ์ƒ, ์ƒˆ๋กœ์šด ๊ด€์ , ๋Œ€๊ธฐ', 'reversed' => '์ง€์—ฐ, ์ €ํ•ญ, ํ—›๋œ ํฌ์ƒ'],
    ['name' => 'Death', 'upright' => '์ข…๊ฒฐ, ๋ณ€ํ™”, ์žฌํƒ„์ƒ', 'reversed' => '์ €ํ•ญ, ์ •์ฒด, ๋‚ด๋ฉด์˜ ์ •ํ™”'],
    ['name' => 'Temperance', 'upright' => '๊ท ํ˜•, ์ ˆ์ œ, ์น˜์œ ', 'reversed' => '๋ถˆ๊ท ํ˜•, ๊ณผ์ž‰, ๋ถ€์กฐํ™”'],
    ['name' => 'The Devil', 'upright' => '์†๋ฐ•, ์ค‘๋…, ๋ฌผ์งˆ์ฃผ์˜', 'reversed' => 'ํ•ด๋ฐฉ, ์ž๊ฐ, ํƒˆ์ถœ'],
    ['name' => 'The Tower', 'upright' => 'ํŒŒ๊ดด, ํ˜ผ๋ˆ, ๊ณ„์‹œ', 'reversed' => '์žฌ๋‚œ ํšŒํ”ผ, ๋‘๋ ค์›€, ์ง€์—ฐ๋œ ๋ณ€ํ™”'],
    ['name' => 'The Star', 'upright' => 'ํฌ๋ง, ์˜๊ฐ, ํ‰์˜จ', 'reversed' => '์ ˆ๋ง, ์‹ ๋ขฐ ์ƒ์‹ค, ๋‹จ์ ˆ'],
    ['name' => 'The Moon', 'upright' => 'ํ™˜์ƒ, ๋‘๋ ค์›€, ์ž ์žฌ์˜์‹', 'reversed' => 'ํ˜ผ๋ž€ ํ•ด์†Œ, ์ง„์‹ค, ๋ถˆ์•ˆ ๊ทน๋ณต'],
    ['name' => 'The Sun', 'upright' => '๊ธฐ์จ, ์„ฑ๊ณต, ํ™œ๋ ฅ', 'reversed' => '๋น„๊ด€, ์šฐ์šธ, ์ง€์—ฐ๋œ ํ–‰๋ณต'],
    ['name' => 'Judgement', 'upright' => '๊ฐ์„ฑ, ๊ฒฐ๋‹จ, ์žฌ์ƒ', 'reversed' => '์ž๊ธฐ ์˜์‹ฌ, ํ›„ํšŒ, ํŒ๋‹จ ์œ ๋ณด'],
    ['name' => 'The World', 'upright' => '์™„์„ฑ, ์„ฑ์ทจ, ์—ฌํ–‰', 'reversed' => '๋ฏธ์™„์„ฑ, ์ง€์—ฐ, ๋ถ€์กฑํ•จ']
];

require_once(G5_THEME_PATH.'/modern/_head.inc.php');
include_once('./head.sub.php');
?>

<style>
.tarot-hero {
    text-align: center;
    padding: 48px 20px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    border-radius: var(--m-radius-lg);
    margin-bottom: 32px;
}
.tarot-hero h1 {
    font-size: 2rem;
    font-weight: 700;
    margin: 0 0 12px;
}
.tarot-hero p {
    font-size: 1.1rem;
    opacity: 0.95;
    margin: 0;
}
.draw-section {
    text-align: center;
    padding: 32px 20px;
    background: var(--m-surface);
    border-radius: var(--m-radius-lg);
    box-shadow: var(--m-shadow);
    margin-bottom: 32px;
}
.draw-btn {
    display: inline-block;
    padding: 16px 48px;
    font-size: 1.2rem;
    font-weight: 600;
    color: white;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border: none;
    border-radius: var(--m-radius-lg);
    cursor: pointer;
    transition: transform 0.2s, box-shadow 0.2s;
}
.draw-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
}
.info-box {
    background: var(--m-surface);
    padding: 24px;
    border-radius: var(--m-radius-lg);
    box-shadow: var(--m-shadow);
    margin-bottom: 32px;
}
.info-box h3 {
    color: var(--m-text);
    font-size: 1.3rem;
    font-weight: 600;
    margin: 0 0 16px;
}
.info-box ul {
    color: var(--m-text-muted);
    line-height: 1.8;
    margin: 0;
    padding-left: 20px;
}
</style>

<div class="m-shell">
    <?php require G5_THEME_PATH.'/modern/_nav.inc.php'; ?>
    
    <main class="m-container" style="padding: 32px 20px 48px; max-width: 800px; margin: 0 auto;">
        <div class="tarot-hero">
            <h1>๐Ÿ”ฎ ์˜ค๋Š˜์˜ ํƒ€๋กœ ์Šคํ”„๋ ˆ๋“œ</h1>
            <p>๊ณผ๊ฑฐ-ํ˜„์žฌ-๋ฏธ๋ž˜ 3์žฅ ์นด๋“œ๋กœ ๋‹น์‹ ์˜ ์šด์„ธ๋ฅผ ํ™•์ธํ•˜์„ธ์š”</p>
        </div>

        <div class="draw-section">
            <form method="post" action="">
                <button type="submit" name="draw" class="draw-btn">๐ŸŽด ์นด๋“œ ๋ฝ‘๊ธฐ</button>
            </form>
        </div>

        <div class="info-box">
            <h3>๐Ÿ“– ํƒ€๋กœ ๋ฆฌ๋”ฉ์ด๋ž€?</h3>
            <ul>
                <li><strong>๊ณผ๊ฑฐ ์นด๋“œ:</strong> ํ˜„์žฌ ์ƒํ™ฉ์˜ ์›์ธ์ด ๋œ ๊ณผ๊ฑฐ ์‚ฌ๊ฑด์ด๋‚˜ ์˜ํ–ฅ</li>
                <li><strong>ํ˜„์žฌ ์นด๋“œ:</strong> ์ง€๊ธˆ ๋‹น์‹ ์ด ์ฒ˜ํ•œ ์ƒํ™ฉ๊ณผ ์—๋„ˆ์ง€</li>
                <li><strong>๋ฏธ๋ž˜ ์นด๋“œ:</strong> ํ˜„์žฌ ํ๋ฆ„์ด ์ด์–ด์งˆ ๋•Œ ๋‹ค๊ฐ€์˜ฌ ๊ฒฐ๊ณผ</li>
            </ul>
        </div>

        <div class="info-box">
            <h3>โœจ ์ด์šฉ ๋ฐฉ๋ฒ•</h3>
            <ul>
                <li>๋งˆ์Œ์„ ๊ฐ€๋ผ์•‰ํžˆ๊ณ  ์งˆ๋ฌธ์ด๋‚˜ ๊ณ ๋ฏผ์„ ๋– ์˜ฌ๋ ค๋ณด์„ธ์š”</li>
                <li>"์นด๋“œ ๋ฝ‘๊ธฐ" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ 3์žฅ์˜ ์นด๋“œ๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค</li>
                <li>๊ฐ ์นด๋“œ์˜ ์˜๋ฏธ๋ฅผ ์ฝ๊ณ  ์ „์ฒด ํ•ด์„์„ ํ™•์ธํ•˜์„ธ์š”</li>
                <li>๋ฆฌ๋”ฉ ๊ฒฐ๊ณผ๋Š” ์ €์žฅํ•˜์—ฌ ๋‚˜์ค‘์— ๋‹ค์‹œ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค</li>
            </ul>
        </div>
    </main>
    
    <?php require G5_THEME_PATH.'/modern/_footer.inc.php'; ?>
</div>

<?php include_once('./tail.sub.php'); ?>
```

### ์ฃผ์š” ํฌ์ธํŠธ:

1. **modern shell ๊ณจ๊ฒฉ ์ ์šฉ**: `_head.inc.php` โ†’ `m-shell` โ†’ `_nav.inc.php` โ†’ `m-container` โ†’ `_footer.inc.php` โ†’ `tail.sub.php` ์ˆœ์„œ๋กœ ์‚ฌ์ดํŠธ ์ „์ฒด chrome ํ†ต์ผ
2. **ํƒ€๋กœ ๋ฑ ๋ฐ์ดํ„ฐ**: ๋ฉ”์ด์ € ์•„๋ฅด์นด๋‚˜ 22์žฅ ๋ฐฐ์—ด (์นด๋“œ๋ช…, ์ •๋ฐฉํ–ฅ/์—ญ๋ฐฉํ–ฅ ํ‚ค์›Œ๋“œ)
3. **ํžˆ์–ด๋กœ ์„น์…˜**: ๊ทธ๋ผ๋””์–ธํŠธ ๋ฐฐ๊ฒฝ์œผ๋กœ ํƒ€๋กœ ๋ถ„์œ„๊ธฐ ์—ฐ์ถœ
4. **์นด๋“œ ๋ฝ‘๊ธฐ ๋ฒ„ํŠผ**: ํผ ์ œ์ถœ ๋ฐฉ์‹ (๋‹ค์Œ ๋‹จ๊ณ„์—์„œ POST ์ฒ˜๋ฆฌ)
5. **์•ˆ๋‚ด ๋ฐ•์Šค**: ํƒ€๋กœ ๋ฆฌ๋”ฉ ์„ค๋ช… & ์ด์šฉ ๋ฐฉ๋ฒ•

ํŒŒ์ผ์„ ์ €์žฅํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ €์—์„œ `/tarot-spread`์— ์ ‘์†ํ•˜์—ฌ ํŽ˜์ด์ง€๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ํ‘œ์‹œ๋˜๋Š”์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: `/tarot-spread` URL๋กœ ์ ‘๊ทผ ์‹œ ํžˆ์–ด๋กœ ์„น์…˜, ์นด๋“œ ๋ฝ‘๊ธฐ ๋ฒ„ํŠผ, ์•ˆ๋‚ด ๋ฐ•์Šค๊ฐ€ ํ‘œ์‹œ๋˜๋Š” ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. modern shell์ด ์ ์šฉ๋˜์–ด ์ƒ๋‹จ nav์™€ ํ•˜๋‹จ footer๊ฐ€ ์ž๋™์œผ๋กœ ํ‘œ์‹œ๋˜๋ฉฐ, ๋‹คํฌ๋ชจ๋“œ ํ† ๊ธ€๋„ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

2
Step 2
## Step 2: ์นด๋“œ ๋ฝ‘๊ธฐ ๋กœ์ง & ๋ฆฌ๋”ฉ ๊ฒฐ๊ณผ ํ‘œ์‹œ

`app/modules/tarot-spread/index.php` ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜์—ฌ ์นด๋“œ ๋ฝ‘๊ธฐ POST ์ฒ˜๋ฆฌ์™€ ๊ฒฐ๊ณผ ํ™”๋ฉด์„ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.

### ์ˆ˜์ • ๋‚ด์šฉ:

1. **POST ์ฒ˜๋ฆฌ ๋กœ์ง** (ํŒŒ์ผ ์ƒ๋‹จ, `require_once` ์ „์— ์ถ”๊ฐ€):

```php
<?php
include_once('./_common.php');

// ํƒ€๋กœ ์นด๋“œ ๋ฑ ๋ฐ์ดํ„ฐ
$tarot_deck = [
    ['name' => 'The Fool', 'upright' => '์ƒˆ๋กœ์šด ์‹œ์ž‘, ์ˆœ์ˆ˜ํ•จ, ์ž์œ ', 'reversed' => '๋ฌด๋ชจํ•จ, ๊ฒฝ์†”ํ•จ, ๋ฆฌ์Šคํฌ'],
    ['name' => 'The Magician', 'upright' => '์ฐฝ์กฐ๋ ฅ, ์˜์ง€, ๊ธฐ์ˆ ', 'reversed' => '์กฐ์ž‘, ์†์ž„์ˆ˜, ์žฌ๋Šฅ ๋‚ญ๋น„'],
    ['name' => 'The High Priestess', 'upright' => '์ง๊ด€, ์‹ ๋น„, ์ž ์žฌ์˜์‹', 'reversed' => '๋น„๋ฐ€, ๋‹จ์ ˆ, ์นจ๋ฌต'],
    ['name' => 'The Empress', 'upright' => 'ํ’์š”, ๋ชจ์„ฑ, ์ž์—ฐ', 'reversed' => '์˜์กด, ์งˆ์‹, ๊ณตํ—ˆํ•จ'],
    ['name' => 'The Emperor', 'upright' => '๊ถŒ์œ„, ๊ตฌ์กฐ, ํ†ต์ œ', 'reversed' => '๋…์žฌ, ๊ฒฝ์ง, ๋ฏธ์„ฑ์ˆ™'],
    ['name' => 'The Hierophant', 'upright' => '์ „ํ†ต, ๊ต์œก, ์‹ ๋…', 'reversed' => '๋ฐ˜ํ•ญ, ์ž์œ ์‚ฌ์ƒ, ๋น„์ •ํ†ต'],
    ['name' => 'The Lovers', 'upright' => '์‚ฌ๋ž‘, ์กฐํ™”, ์„ ํƒ', 'reversed' => '๋ถˆ๊ท ํ˜•, ๊ฐˆ๋“ฑ, ์ž˜๋ชป๋œ ์„ ํƒ'],
    ['name' => 'The Chariot', 'upright' => '์˜์ง€, ์Šน๋ฆฌ, ๊ฒฐ๋‹จ', 'reversed' => '๋ฐฉํ–ฅ ์ƒ์‹ค, ์ขŒ์ ˆ, ๊ณต๊ฒฉ์„ฑ'],
    ['name' => 'Strength', 'upright' => '์šฉ๊ธฐ, ์ธ๋‚ด, ์ž์ œ๋ ฅ', 'reversed' => '์ž๊ธฐ ์˜์‹ฌ, ์•ฝํ•จ, ์ž์ œ๋ ฅ ๋ถ€์กฑ'],
    ['name' => 'The Hermit', 'upright' => '๋‚ด๋ฉด ํƒ๊ตฌ, ๊ณ ๋…, ์ง€ํ˜œ', 'reversed' => '๊ณ ๋ฆฝ, ์™ธ๋กœ์›€, ์ฒ ํšŒ'],
    ['name' => 'Wheel of Fortune', 'upright' => '์šด๋ช…, ๋ณ€ํ™”, ์ˆœํ™˜', 'reversed' => '๋ถˆ์šด, ์ €ํ•ญ, ์ •์ฒด'],
    ['name' => 'Justice', 'upright' => '๊ณต์ •, ์ง„์‹ค, ๋ฒ•', 'reversed' => '๋ถˆ๊ณต์ •, ๊ฑฐ์ง“, ์ฑ…์ž„ ํšŒํ”ผ'],
    ['name' => 'The Hanged Man', 'upright' => 'ํฌ์ƒ, ์ƒˆ๋กœ์šด ๊ด€์ , ๋Œ€๊ธฐ', 'reversed' => '์ง€์—ฐ, ์ €ํ•ญ, ํ—›๋œ ํฌ์ƒ'],
    ['name' => 'Death', 'upright' => '์ข…๊ฒฐ, ๋ณ€ํ™”, ์žฌํƒ„์ƒ', 'reversed' => '์ €ํ•ญ, ์ •์ฒด, ๋‚ด๋ฉด์˜ ์ •ํ™”'],
    ['name' => 'Temperance', 'upright' => '๊ท ํ˜•, ์ ˆ์ œ, ์น˜์œ ', 'reversed' => '๋ถˆ๊ท ํ˜•, ๊ณผ์ž‰, ๋ถ€์กฐํ™”'],
    ['name' => 'The Devil', 'upright' => '์†๋ฐ•, ์ค‘๋…, ๋ฌผ์งˆ์ฃผ์˜', 'reversed' => 'ํ•ด๋ฐฉ, ์ž๊ฐ, ํƒˆ์ถœ'],
    ['name' => 'The Tower', 'upright' => 'ํŒŒ๊ดด, ํ˜ผ๋ˆ, ๊ณ„์‹œ', 'reversed' => '์žฌ๋‚œ ํšŒํ”ผ, ๋‘๋ ค์›€, ์ง€์—ฐ๋œ ๋ณ€ํ™”'],
    ['name' => 'The Star', 'upright' => 'ํฌ๋ง, ์˜๊ฐ, ํ‰์˜จ', 'reversed' => '์ ˆ๋ง, ์‹ ๋ขฐ ์ƒ์‹ค, ๋‹จ์ ˆ'],
    ['name' => 'The Moon', 'upright' => 'ํ™˜์ƒ, ๋‘๋ ค์›€, ์ž ์žฌ์˜์‹', 'reversed' => 'ํ˜ผ๋ž€ ํ•ด์†Œ, ์ง„์‹ค, ๋ถˆ์•ˆ ๊ทน๋ณต'],
    ['name' => 'The Sun', 'upright' => '๊ธฐ์จ, ์„ฑ๊ณต, ํ™œ๋ ฅ', 'reversed' => '๋น„๊ด€, ์šฐ์šธ, ์ง€์—ฐ๋œ ํ–‰๋ณต'],
    ['name' => 'Judgement', 'upright' => '๊ฐ์„ฑ, ๊ฒฐ๋‹จ, ์žฌ์ƒ', 'reversed' => '์ž๊ธฐ ์˜์‹ฌ, ํ›„ํšŒ, ํŒ๋‹จ ์œ ๋ณด'],
    ['name' => 'The World', 'upright' => '์™„์„ฑ, ์„ฑ์ทจ, ์—ฌํ–‰', 'reversed' => '๋ฏธ์™„์„ฑ, ์ง€์—ฐ, ๋ถ€์กฑํ•จ']
];

$spread = null;
$interpretation = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['draw'])) {
    // ์นด๋“œ ์…”ํ”Œ & 3์žฅ ๋ฝ‘๊ธฐ
    $shuffled = $tarot_deck;
    shuffle($shuffled);
    $selected = array_slice($shuffled, 0, 3);
    
    // ๊ฐ ์นด๋“œ๋งˆ๋‹ค ์ •๋ฐฉํ–ฅ/์—ญ๋ฐฉํ–ฅ ๋žœ๋ค ๊ฒฐ์ •
    $spread = [
        [
            'position' => '๊ณผ๊ฑฐ',
            'card' => $selected[0],
            'reversed' => rand(0, 1) === 1,
            'emoji' => 'โณ'
        ],
        [
            'position' => 'ํ˜„์žฌ',
            'card' => $selected[1],
            'reversed' => rand(0, 1) === 1,
            'emoji' => 'โœจ'
        ],
        [
            'position' => '๋ฏธ๋ž˜',
            'card' => $selected[2],
            'reversed' => rand(0, 1) === 1,
            'emoji' => '๐Ÿ”ฎ'
        ]
    ];
    
    // ์ข…ํ•ฉ ํ•ด์„ ์ƒ์„ฑ (๊ฐ„๋‹จํ•œ ํ…œํ”Œ๋ฆฟ)
    $past_msg = $spread[0]['reversed'] ? '์–ด๋ ค์›€' : '๊ธ์ •์  ์˜ํ–ฅ';
    $present_msg = $spread[1]['reversed'] ? '๋„์ „์ ์ธ ์ƒํ™ฉ' : '์ข‹์€ ํ๋ฆ„';
    $future_msg = $spread[2]['reversed'] ? '์ฃผ์˜๊ฐ€ ํ•„์š”ํ•œ ์‹œ๊ธฐ' : '๋ฐ์€ ์ „๋ง';
    
    $interpretation = "๊ณผ๊ฑฐ์—๋Š” {$past_msg}์ด ์žˆ์—ˆ๊ณ , ํ˜„์žฌ๋Š” {$present_msg}์ž…๋‹ˆ๋‹ค. ์ด ํ๋ฆ„์ด ๊ณ„์†๋˜๋ฉด ๋ฏธ๋ž˜์—๋Š” {$future_msg}์ด ์˜ˆ์ƒ๋ฉ๋‹ˆ๋‹ค. ๊ฐ ์นด๋“œ์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ํ˜„๋ช…ํ•œ ์„ ํƒ์„ ํ•˜์„ธ์š”.";
}

require_once(G5_THEME_PATH.'/modern/_head.inc.php');
include_once('./head.sub.php');
?>
```

2. **์Šคํƒ€์ผ ์ถ”๊ฐ€** (๊ธฐ์กด `<style>` ๋ธ”๋ก ํ•˜๋‹จ์— ์ถ”๊ฐ€):

```css
.spread-result {
    margin-bottom: 32px;
}
.cards-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 20px;
    margin-bottom: 32px;
}
.card-item {
    background: var(--m-surface);
    border-radius: var(--m-radius-lg);
    box-shadow: var(--m-shadow);
    padding: 24px;
    text-align: center;
    transition: transform 0.3s;
}
.card-item:hover {
    transform: translateY(-4px);
}
.card-position {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-size: 1.1rem;
    font-weight: 600;
    color: #667eea;
    margin-bottom: 12px;
}
.card-name {
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--m-text);
    margin: 12px 0;
}
.card-orientation {
    display: inline-block;
    padding: 4px 12px;
    border-radius: 12px;
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 12px;
}
.card-orientation.upright {
    background: #d4edda;
    color: #155724;
}
.card-orientation.reversed {
    background: #f8d7da;
    color: #721c24;
}
.card-meaning {
    color: var(--m-text-muted);
    line-height: 1.6;
    font-size: 0.95rem;
}
.interpretation-box {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    padding: 32px;
    border-radius: var(--m-radius-lg);
    margin-bottom: 32px;
}
.interpretation-box h3 {
    font-size: 1.5rem;
    font-weight: 700;
    margin: 0 0 16px;
}
.interpretation-box p {
    font-size: 1.1rem;
    line-height: 1.8;
    margin: 0;
}
.action-buttons {
    display: flex;
    gap: 12px;
    justify-content: center;
    flex-wrap: wrap;
}
.btn {
    padding: 12px 32px;
    font-size: 1rem;
    font-weight: 600;
    border-radius: var(--m-radius-lg);
    border: none;
    cursor: pointer;
    transition: transform 0.2s, box-shadow 0.2s;
}
.btn-primary {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
}
.btn-secondary {
    background: var(--m-surface);
    color: var(--m-text);
    box-shadow: var(--m-shadow);
}
.btn:hover {
    transform: translateY(-2px);
}
```

3. **๊ฒฐ๊ณผ ํ™”๋ฉด HTML** (`<main>` ํƒœ๊ทธ ์•ˆ, draw-section ์•„๋ž˜์— ์ถ”๊ฐ€):

```php
<?php if ($spread): ?>
<div class="spread-result">
    <div class="cards-grid">
        <?php foreach ($spread as $item): ?>
            <div class="card-item">
                <div class="card-position">
                    <span><?php echo $item['emoji']; ?></span>
                    <span><?php echo htmlspecialchars($item['position']); ?></span>
                </div>
                <div class="card-name"><?php echo htmlspecialchars($item['card']['name']); ?></div>
                <span class="card-orientation <?php echo $item['reversed'] ? 'reversed' : 'upright'; ?>">
                    <?php echo $item['reversed'] ? '์—ญ๋ฐฉํ–ฅ โ†“' : '์ •๋ฐฉํ–ฅ โ†‘'; ?>
                </span>
                <div class="card-meaning">
                    <?php 
                    $meaning = $item['reversed'] ? $item['card']['reversed'] : $item['card']['upright'];
                    echo htmlspecialchars($meaning);
                    ?>
                </div>
            </div>
        <?php endforeach; ?>
    </div>
    
    <div class="interpretation-box">
        <h3>๐Ÿ”ฎ ์ข…ํ•ฉ ํ•ด์„</h3>
        <p><?php echo htmlspecialchars($interpretation); ?></p>
    </div>
    
    <div class="action-buttons">
        <form method="post" action="">
            <button type="submit" name="draw" class="btn btn-primary">๐Ÿ”„ ๋‹ค์‹œ ๋ฝ‘๊ธฐ</button>
        </form>
        <button type="button" class="btn btn-secondary" onclick="alert('์ €์žฅ ๊ธฐ๋Šฅ์€ ๋‹ค์Œ ๋‹จ๊ณ„์—์„œ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค!')">๐Ÿ’พ ๊ฒฐ๊ณผ ์ €์žฅ</button>
    </div>
</div>
<?php endif; ?>
```

### ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ:

1. **์นด๋“œ ๋ฝ‘๊ธฐ ๋กœ์ง**: POST ์š”์ฒญ ์‹œ ๋ฑ์„ ์…”ํ”Œํ•˜๊ณ  3์žฅ ์„ ํƒ, ๊ฐ ์นด๋“œ๋งˆ๋‹ค ์ •์—ญ๋ฐฉํ–ฅ ๋žœ๋ค ๊ฒฐ์ •
2. **์ข…ํ•ฉ ํ•ด์„**: 3์žฅ ์นด๋“œ์˜ ์ •์—ญ๋ฐฉํ–ฅ ์กฐํ•ฉ์— ๋”ฐ๋ผ ๊ฐ„๋‹จํ•œ ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ
3. **๊ทธ๋ฆฌ๋“œ ๋ ˆ์ด์•„์›ƒ**: ์นด๋“œ 3์žฅ์„ ๋ฐ˜์‘ํ˜• ๊ทธ๋ฆฌ๋“œ๋กœ ํ‘œ์‹œ (๋ชจ๋ฐ”์ผ์—์„œ๋Š” ์„ธ๋กœ ์Šคํƒ)
4. **์นด๋“œ๋ณ„ ์ •๋ณด**: ์œ„์น˜(๊ณผ๊ฑฐ/ํ˜„์žฌ/๋ฏธ๋ž˜), ์นด๋“œ๋ช…, ์ •์—ญ๋ฐฉํ–ฅ, ํ‚ค์›Œ๋“œ ํ‘œ์‹œ
5. **์•ก์…˜ ๋ฒ„ํŠผ**: ๋‹ค์‹œ ๋ฝ‘๊ธฐ & ์ €์žฅ ๋ฒ„ํŠผ (์ €์žฅ์€ ๋‹ค์Œ ๋‹จ๊ณ„์—์„œ ๊ตฌํ˜„)

ํŒŒ์ผ์„ ์ €์žฅํ•˜๊ณ  "์นด๋“œ ๋ฝ‘๊ธฐ" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ๋ฆฌ๋”ฉ ๊ฒฐ๊ณผ๊ฐ€ ํ‘œ์‹œ๋˜๋Š”์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: ์นด๋“œ ๋ฝ‘๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํŽ˜์ด์ง€๊ฐ€ ์ƒˆ๋กœ๊ณ ์นจ๋˜๋ฉฐ 3์žฅ์˜ ํƒ€๋กœ ์นด๋“œ๊ฐ€ ๊ทธ๋ฆฌ๋“œ ํ˜•ํƒœ๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๊ฐ ์นด๋“œ๋งˆ๋‹ค ์œ„์น˜(๊ณผ๊ฑฐ/ํ˜„์žฌ/๋ฏธ๋ž˜), ์นด๋“œ๋ช…, ์ •์—ญ๋ฐฉํ–ฅ, ํ‚ค์›Œ๋“œ๊ฐ€ ํ‘œ์‹œ๋˜๊ณ , ํ•˜๋‹จ์— ์ข…ํ•ฉ ํ•ด์„ ๋ฐ•์Šค๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋ฝ‘๊ธฐ ๋ฒ„ํŠผ์œผ๋กœ ์ƒˆ๋กœ์šด ๋ฆฌ๋”ฉ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3
Step 3
## Step 3: SQLite DB ์„ค์ • & ๋ฆฌ๋”ฉ ์ €์žฅ ๊ธฐ๋Šฅ

`app/modules/tarot-spread/index.php` ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜์—ฌ ๋ฆฌ๋”ฉ ๊ฒฐ๊ณผ๋ฅผ SQLite DB์— ์ €์žฅํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”.

### ์ˆ˜์ • ๋‚ด์šฉ:

1. **DB ์—ฐ๊ฒฐ & ํ…Œ์ด๋ธ” ์ƒ์„ฑ ํ•จ์ˆ˜** (ํŒŒ์ผ ์ƒ๋‹จ, ํƒ€๋กœ ๋ฑ ๋ฐ์ดํ„ฐ ์•„๋ž˜์— ์ถ”๊ฐ€):

```php
// SQLite DB ์—ฐ๊ฒฐ & ํ…Œ์ด๋ธ” ์ƒ์„ฑ
function getTarotDB() {
    @mkdir(G5_DATA_PATH.'/modules', 0707, true);
    $db_path = G5_DATA_PATH.'/modules/tarot-spread.sqlite';
    $db = new PDO('sqlite:'.$db_path);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    // ๋ฆฌ๋”ฉ ๊ธฐ๋ก ํ…Œ์ด๋ธ”
    $db->exec("
        CREATE TABLE IF NOT EXISTS readings (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            user_id TEXT NOT NULL,
            reading_date DATETIME DEFAULT CURRENT_TIMESTAMP,
            card1_name TEXT NOT NULL,
            card1_reversed INTEGER NOT NULL,
            card2_name TEXT NOT NULL,
            card2_reversed INTEGER NOT NULL,
            card3_name TEXT NOT NULL,
            card3_reversed INTEGER NOT NULL,
            interpretation TEXT NOT NULL
        )
    ");
    
    return $db;
}
```

2. **์ €์žฅ ์ฒ˜๋ฆฌ ๋กœ์ง** (์นด๋“œ ๋ฝ‘๊ธฐ ๋กœ์ง ์•„๋ž˜, `require_once` ์ „์— ์ถ”๊ฐ€):

```php
// ๋ฆฌ๋”ฉ ์ €์žฅ ์ฒ˜๋ฆฌ
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_reading'])) {
    $db = getTarotDB();
    
    // ํšŒ์›์ด๋ฉด ํšŒ์› ID, ๋น„ํšŒ์›์ด๋ฉด ์„ธ์…˜ ID
    $user_id = $is_member ? $member['mb_id'] : session_id();
    
    $stmt = $db->prepare("
        INSERT INTO readings (
            user_id, card1_name, card1_reversed, card2_name, card2_reversed,
            card3_name, card3_reversed, interpretation
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
    ");
    
    $stmt->execute([
        $user_id,
        $_POST['card1_name'],
        (int)$_POST['card1_reversed'],
        $_POST['card2_name'],
        (int)$_POST['card2_reversed'],
        $_POST['card3_name'],
        (int)$_POST['card3_reversed'],
        $_POST['interpretation']
    ]);
    
    // ์ €์žฅ ํ›„ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
    header('Location: /tarot-spread?saved=1');
    exit;
}

// ์ €์žฅ ์„ฑ๊ณต ๋ฉ”์‹œ์ง€
$saved_message = '';
if (isset($_GET['saved']) && $_GET['saved'] === '1') {
    $saved_message = '๋ฆฌ๋”ฉ ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!';
}
```

3. **์ €์žฅ ํผ ์ˆ˜์ •** (๊ฒฐ๊ณผ ํ™”๋ฉด์˜ ์ €์žฅ ๋ฒ„ํŠผ ๋ถ€๋ถ„์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝ):

```php
<div class="action-buttons">
    <form method="post" action="" style="display: inline;">
        <button type="submit" name="draw" class="btn btn-primary">๐Ÿ”„ ๋‹ค์‹œ ๋ฝ‘๊ธฐ</button>
    </form>
    <form method="post" action="" style="display: inline;">
        <input type="hidden" name="card1_name" value="<?php echo htmlspecialchars($spread[0]['card']['name']); ?>">
        <input type="hidden" name="card1_reversed" value="<?php echo $spread[0]['reversed'] ? '1' : '0'; ?>">
        <input type="hidden" name="card2_name" value="<?php echo htmlspecialchars($spread[1]['card']['name']); ?>">
        <input type="hidden" name="card2_reversed" value="<?php echo $spread[1]['reversed'] ? '1' : '0'; ?>">
        <input type="hidden" name="card3_name" value="<?php echo htmlspecialchars($spread[2]['card']['name']); ?>">
        <input type="hidden" name="card3_reversed" value="<?php echo $spread[2]['reversed'] ? '1' : '0'; ?>">
        <input type="hidden" name="interpretation" value="<?php echo htmlspecialchars($interpretation); ?>">
        <button type="submit" name="save_reading" class="btn btn-secondary">๐Ÿ’พ ๊ฒฐ๊ณผ ์ €์žฅ</button>
    </form>
</div>
```

4. **์ €์žฅ ์„ฑ๊ณต ์•Œ๋ฆผ** (ํžˆ์–ด๋กœ ์„น์…˜ ๋ฐ”๋กœ ์•„๋ž˜์— ์ถ”๊ฐ€):

```php
<?php if ($saved_message): ?>
<div style="background: #d4edda; color: #155724; padding: 16px 24px; border-radius: var(--m-radius-lg); margin-bottom: 24px; text-align: center; font-weight: 600;">
    โœ… <?php echo htmlspecialchars($saved_message); ?>
</div>
<?php endif; ?>
```

### ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ:

1. **SQLite DB ํ•จ์ˆ˜**: `G5_DATA_PATH/modules/tarot-spread.sqlite` ํŒŒ์ผ์— DB ์ƒ์„ฑ, ์ฒซ ์ ‘๊ทผ ์‹œ ํ…Œ์ด๋ธ” ์ž๋™ ์ƒ์„ฑ
2. **๋ฆฌ๋”ฉ ์ €์žฅ**: ์นด๋“œ 3์žฅ ์ •๋ณด(์ด๋ฆ„, ์ •์—ญ๋ฐฉํ–ฅ)์™€ ์ข…ํ•ฉ ํ•ด์„์„ DB์— INSERT
3. **์‚ฌ์šฉ์ž ์‹๋ณ„**: ํšŒ์›์€ `mb_id`, ๋น„ํšŒ์›์€ `session_id()`๋กœ ๊ตฌ๋ถ„
4. **์ €์žฅ ํ›„ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ**: PRG ํŒจํ„ด์œผ๋กœ ์ค‘๋ณต ์ œ์ถœ ๋ฐฉ์ง€
5. **์„ฑ๊ณต ๋ฉ”์‹œ์ง€**: URL ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ €์žฅ ์„ฑ๊ณต ์•Œ๋ฆผ ํ‘œ์‹œ

ํŒŒ์ผ์„ ์ €์žฅํ•˜๊ณ  ์นด๋“œ๋ฅผ ๋ฝ‘์€ ๋’ค "๊ฒฐ๊ณผ ์ €์žฅ" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ DB์— ์ €์žฅ๋˜๋Š”์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: ๋ฆฌ๋”ฉ ๊ฒฐ๊ณผ ํ™”๋ฉด์—์„œ "๊ฒฐ๊ณผ ์ €์žฅ" ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ SQLite DB์— ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋˜๊ณ , ํŽ˜์ด์ง€๊ฐ€ ์ƒˆ๋กœ๊ณ ์นจ๋˜๋ฉฐ ์ƒ๋‹จ์— "๋ฆฌ๋”ฉ ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!" ์„ฑ๊ณต ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. `data/modules/tarot-spread.sqlite` ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๊ณ  readings ํ…Œ์ด๋ธ”์— ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.

4
Step 4
## Step 4: ๊ณผ๊ฑฐ ๋ฆฌ๋”ฉ ๋ชฉ๋ก ํŽ˜์ด์ง€

`app/modules/tarot-spread/history/index.php` ํŒŒ์ผ์„ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด ์ €์žฅ๋œ ๋ฆฌ๋”ฉ ๊ธฐ๋ก์„ ๋ชฉ๋ก์œผ๋กœ ๋ณด์—ฌ์ฃผ๋Š” ํŽ˜์ด์ง€๋ฅผ ๊ตฌํ˜„ํ•ด์ฃผ์„ธ์š”.

### ํŒŒ์ผ ์ƒ์„ฑ:

`app/modules/tarot-spread/history/index.php`:

```php
<?php
include_once('./_common.php');

// SQLite DB ์—ฐ๊ฒฐ ํ•จ์ˆ˜ (๋ฉ”์ธ ํŽ˜์ด์ง€์™€ ๋™์ผ)
function getTarotDB() {
    @mkdir(G5_DATA_PATH.'/modules', 0707, true);
    $db_path = G5_DATA_PATH.'/modules/tarot-spread.sqlite';
    $db = new PDO('sqlite:'.$db_path);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $db->exec("
        CREATE TABLE IF NOT EXISTS readings (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            user_id TEXT NOT NULL,
            reading_date DATETIME DEFAULT CURRENT_TIMESTAMP,
            card1_name TEXT NOT NULL,
            card1_reversed INTEGER NOT NULL,
            card2_name TEXT NOT NULL,
            card2_reversed INTEGER NOT NULL,
            card3_name TEXT NOT NULL,
            card3_reversed INTEGER NOT NULL,
            interpretation TEXT NOT NULL
        )
    ");
    
    return $db;
}

// ํ˜„์žฌ ์‚ฌ์šฉ์ž ID
$user_id = $is_member ? $member['mb_id'] : session_id();

// ๋ฆฌ๋”ฉ ๊ธฐ๋ก ์กฐํšŒ (์ตœ์‹ ์ˆœ)
$db = getTarotDB();
$stmt = $db->prepare("SELECT * FROM readings WHERE user_id = ? ORDER BY reading_date DESC");
$stmt->execute([$user_id]);
$readings = $stmt->fetchAll(PDO::FETCH_ASSOC);

require_once(G5_THEME_PATH.'/modern/_head.inc.php');
include_once('./head.sub.php');
?>

<style>
.history-hero {
    text-align: center;
    padding: 48px 20px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    border-radius: var(--m-radius-lg);
    margin-bottom: 32px;
}
.history-hero h1 {
    font-size: 2rem;
    font-weight: 700;
    margin: 0 0 12px;
}
.history-hero p {
    font-size: 1.1rem;
    opacity: 0.95;
    margin: 0 0 16px;
}
.back-btn {
    display: inline-block;
    padding: 10px 24px;
    background: rgba(255, 255, 255, 0.2);
    color: white;
    border-radius: var(--m-radius-lg);
    text-decoration: none;
    font-weight: 600;
    transition: background 0.2s;
}
.back-btn:hover {
    background: rgba(255, 255, 255, 0.3);
}
.readings-list {
    display: flex;
    flex-direction: column;
    gap: 20px;
}
.reading-card {
    background: var(--m-surface);
    border-radius: var(--m-radius-lg);
    box-shadow: var(--m-shadow);
    padding: 24px;
    transition: transform 0.2s;
}
.reading-card:hover {
    transform: translateY(-2px);
}
.reading-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;
    flex-wrap: wrap;
    gap: 12px;
}
.reading-date {
    font-size: 0.95rem;
    color: var(--m-text-muted);
}
.reading-id {
    font-size: 0.85rem;
    color: var(--m-text-muted);
    background: rgba(102, 126, 234, 0.1);
    padding: 4px 12px;
    border-radius: 12px;
}
.cards-summary {
    display: flex;
    gap: 12px;
    margin-bottom: 16px;
    flex-wrap: wrap;
}
.card-badge {
    background: rgba(102, 126, 234, 0.1);
    padding: 8px 16px;
    border-radius: var(--m-radius-lg);
    font-size: 0.9rem;
}
.card-badge strong {
    color: #667eea;
    font-weight: 600;
}
.card-badge .orientation {
    font-size: 0.8rem;
    color: var(--m-text-muted);
    margin-left: 4px;
}
.interpretation-preview {
    color: var(--m-text-muted);
    line-height: 1.6;
    font-size: 0.95rem;
    margin-bottom: 16px;
}
.view-detail-btn {
    display: inline-block;
    padding: 8px 20px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    border-radius: var(--m-radius-lg);
    text-decoration: none;
    font-weight: 600;
    font-size: 0.9rem;
    transition: transform 0.2s;
}
.view-detail-btn:hover {
    transform: translateY(-2px);
}
.empty-state {
    text-align: center;
    padding: 64px 20px;
    background: var(--m-surface);
    border-radius: var(--m-radius-lg);
    box-shadow: var(--m-shadow);
}
.empty-state .emoji {
    font-size: 4rem;
    margin-bottom: 16px;
}
.empty-state h3 {
    font-size: 1.5rem;
    color: var(--m-text);
    margin: 0 0 12px;
}
.empty-state p {
    color: var(--m-text-muted);
    margin: 0 0 24px;
}
.empty-state a {
    display: inline-block;
    padding: 12px 32px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    border-radius: var(--m-radius-lg);
    text-decoration: none;
    font-weight: 600;
}
</style>

<div class="m-shell">
    <?php require G5_THEME_PATH.'/modern/_nav.inc.php'; ?>
    
    <main class="m-container" style="padding: 32px 20px 48px; max-width: 900px; margin: 0 auto;">
        <div class="history-hero">
            <h1>๐Ÿ“š ๋‚˜์˜ ํƒ€๋กœ ๋ฆฌ๋”ฉ ๊ธฐ๋ก</h1>
            <p>์ €์žฅ๋œ ๋ฆฌ๋”ฉ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ํ™•์ธํ•˜์„ธ์š”</p>
            <a href="/tarot-spread" class="back-btn">โ† ์ƒˆ ๋ฆฌ๋”ฉ ํ•˜๋Ÿฌ ๊ฐ€๊ธฐ</a>
        </div>

        <?php if (count($readings) > 0): ?>
            <div class="readings-list">
                <?php foreach ($readings as $reading): ?>
                    <div class="reading-card">
                        <div class="reading-header">
                            <div class="reading-date">
                                ๐Ÿ—“๏ธ <?php echo date('Y๋…„ m์›” d์ผ H:i', strtotime($reading['reading_date'])); ?>
                            </div>
                            <div class="reading-id">#<?php echo $reading['id']; ?></div>
                        </div>
                        
                        <div class="cards-summary">
                            <div class="card-badge">
                                <strong>โณ ๊ณผ๊ฑฐ:</strong> <?php echo htmlspecialchars($reading['card1_name']); ?>
                                <span class="orientation"><?php echo $reading['card1_reversed'] ? '(์—ญ๋ฐฉํ–ฅ)' : '(์ •๋ฐฉํ–ฅ)'; ?></span>
                            </div>
                            <div class="card-badge">
                                <strong>โœจ ํ˜„์žฌ:</strong> <?php echo htmlspecialchars($reading['card2_name']); ?>
                                <span class="orientation"><?php echo $reading['card2_reversed'] ? '(์—ญ๋ฐฉํ–ฅ)' : '(์ •๋ฐฉํ–ฅ)'; ?></span>
                            </div>
                            <div class="card-badge">
                                <strong>๐Ÿ”ฎ ๋ฏธ๋ž˜:</strong> <?php echo htmlspecialchars($reading['card3_name']); ?>
                                <span class="orientation"><?php echo $reading['card3_reversed'] ? '(์—ญ๋ฐฉํ–ฅ)' : '(์ •๋ฐฉํ–ฅ)'; ?></span>
                            </div>
                        </div>
                        
                        <div class="interpretation-preview">
                            <?php 
                            $preview = mb_substr($reading['interpretation'], 0, 80, 'UTF-8');
                            if (mb_strlen($reading['interpretation'], 'UTF-8') > 80) {
                                $preview .= '...';
                            }
                            echo htmlspecialchars($preview);
                            ?>
                        </div>
                        
                        <a href="/tarot-spread/view?id=<?php echo $reading['id']; ?>" class="view-detail-btn">์ž์„ธํžˆ ๋ณด๊ธฐ โ†’</a>
                    </div>
                <?php endforeach; ?>
            </div>
        <?php else: ?>
            <div class="empty-state">
                <div class="emoji">๐Ÿ”ฎ</div>
                <h3>์•„์ง ์ €์žฅ๋œ ๋ฆฌ๋”ฉ์ด ์—†์–ด์š”</h3>
                <p>์ฒซ ํƒ€๋กœ ๋ฆฌ๋”ฉ์„ ํ•ด๋ณด์‹œ๊ฒ ์–ด์š”?</p>
                <a href="/tarot-spread">์นด๋“œ ๋ฝ‘์œผ๋Ÿฌ ๊ฐ€๊ธฐ โ†’</a>
            </div>
        <?php endif; ?>
    </main>
    
    <?php require G5_THEME_PATH.'/modern/_footer.inc.php'; ?>
</div>

<?php include_once('./tail.sub.php'); ?>
```

### ์ฃผ์š” ๊ธฐ๋Šฅ:

1. **๋ฆฌ๋”ฉ ๋ชฉ๋ก ์กฐํšŒ**: ํ˜„์žฌ ์‚ฌ์šฉ์ž(ํšŒ์›/๋น„ํšŒ์›)์˜ ๋ฆฌ๋”ฉ ๊ธฐ๋ก์„ ์ตœ์‹ ์ˆœ์œผ๋กœ ๊ฐ€์ ธ์˜ด
2. **์นด๋“œ ์š”์•ฝ**: ๊ฐ ๋ฆฌ๋”ฉ๋งˆ๋‹ค 3์žฅ ์นด๋“œ์˜ ์ด๋ฆ„๊ณผ ์ •์—ญ๋ฐฉํ–ฅ์„ ๋ฐฐ์ง€ ํ˜•ํƒœ๋กœ ํ‘œ์‹œ
3. **ํ•ด์„ ๋ฏธ๋ฆฌ๋ณด๊ธฐ**: ์ข…ํ•ฉ ํ•ด์„์˜ ์ฒซ 80์ž๋งŒ ํ‘œ์‹œ (๋ง์ค„์ž„ํ‘œ)
4. **์ƒ์„ธ ๋ณด๊ธฐ ๋งํฌ**: ๊ฐ ๋ฆฌ๋”ฉ์˜ ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋Š” ๋ฒ„ํŠผ (๋‹ค์Œ ๋‹จ๊ณ„์—์„œ ๊ตฌํ˜„)
5. **๋นˆ ์ƒํƒœ**: ์ €์žฅ๋œ ๋ฆฌ๋”ฉ์ด ์—†์„ ๋•Œ ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€์™€ ์ƒˆ ๋ฆฌ๋”ฉ ๋งํฌ

ํŒŒ์ผ์„ ์ €์žฅํ•˜๊ณ  `/tarot-spread/history`์— ์ ‘์†ํ•˜์—ฌ ๋ชฉ๋ก์ด ํ‘œ์‹œ๋˜๋Š”์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: `/tarot-spread/history` URL๋กœ ์ ‘๊ทผ ์‹œ ์ €์žฅ๋œ ๋ฆฌ๋”ฉ ๊ธฐ๋ก์ด ์นด๋“œ ํ˜•ํƒœ๋กœ ๋ชฉ๋ก ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๊ฐ ์นด๋“œ์—๋Š” ๋ฆฌ๋”ฉ ๋‚ ์งœ, 3์žฅ ์นด๋“œ ์š”์•ฝ, ํ•ด์„ ๋ฏธ๋ฆฌ๋ณด๊ธฐ, ์ž์„ธํžˆ ๋ณด๊ธฐ ๋ฒ„ํŠผ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ €์žฅ๋œ ๊ธฐ๋ก์ด ์—†์œผ๋ฉด ๋นˆ ์ƒํƒœ ์•ˆ๋‚ด ํ™”๋ฉด์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

5
Step 5
## Step 5: ๋ฆฌ๋”ฉ ์ƒ์„ธ ๋ณด๊ธฐ ํŽ˜์ด์ง€ & ๋ฉ”์ธ ํŽ˜์ด์ง€ ๋งํฌ ์ถ”๊ฐ€

### 1. ์ƒ์„ธ ๋ณด๊ธฐ ํŽ˜์ด์ง€ ์ƒ์„ฑ

`app/modules/tarot-spread/view/index.php` ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”:

```php
<?php
include_once('./_common.php');

// SQLite DB ์—ฐ๊ฒฐ ํ•จ์ˆ˜
function getTarotDB() {
    @mkdir(G5_DATA_PATH.'/modules', 0707, true);
    $db_path = G5_DATA_PATH.'/modules/tarot-spread.sqlite';
    $db = new PDO('sqlite:'.$db_path);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $db->exec("
        CREATE TABLE IF NOT EXISTS readings (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            user_id TEXT NOT NULL,
            reading_date DATETIME DEFAULT CURRENT_TIMESTAMP,
            card1_name TEXT NOT NULL,
            card1_reversed INTEGER NOT NULL,
            card2_name TEXT NOT NULL,
            card2_reversed INTEGER NOT NULL,
            card3_name TEXT NOT NULL,
            card3_reversed INTEGER NOT NULL,
            interpretation TEXT NOT NULL
        )
    ");
    
    return $db;
}

// ํƒ€๋กœ ์นด๋“œ ๋ฑ ๋ฐ์ดํ„ฐ (ํ‚ค์›Œ๋“œ ์กฐํšŒ์šฉ)
$tarot_deck = [
    'The Fool' => ['upright' => '์ƒˆ๋กœ์šด ์‹œ์ž‘, ์ˆœ์ˆ˜ํ•จ, ์ž์œ ', 'reversed' => '๋ฌด๋ชจํ•จ, ๊ฒฝ์†”ํ•จ, ๋ฆฌ์Šคํฌ'],
    'The Magician' => ['upright' => '์ฐฝ์กฐ๋ ฅ, ์˜์ง€, ๊ธฐ์ˆ ', 'reversed' => '์กฐ์ž‘, ์†์ž„์ˆ˜, ์žฌ๋Šฅ ๋‚ญ๋น„'],
    'The High Priestess' => ['upright' => '์ง๊ด€, ์‹ ๋น„, ์ž ์žฌ์˜์‹', 'reversed' => '๋น„๋ฐ€, ๋‹จ์ ˆ, ์นจ๋ฌต'],
    'The Empress' => ['upright' => 'ํ’์š”, ๋ชจ์„ฑ, ์ž์—ฐ', 'reversed' => '์˜์กด, ์งˆ์‹, ๊ณตํ—ˆํ•จ'],
    'The Emperor' => ['upright' => '๊ถŒ์œ„, ๊ตฌ์กฐ, ํ†ต์ œ', 'reversed' => '๋…์žฌ, ๊ฒฝ์ง, ๋ฏธ์„ฑ์ˆ™'],
    'The Hierophant' => ['upright' => '์ „ํ†ต, ๊ต์œก, ์‹ ๋…', 'reversed' => '๋ฐ˜ํ•ญ, ์ž์œ ์‚ฌ์ƒ, ๋น„์ •ํ†ต'],
    'The Lovers' => ['upright' => '์‚ฌ๋ž‘, ์กฐํ™”, ์„ ํƒ', 'reversed' => '๋ถˆ๊ท ํ˜•, ๊ฐˆ๋“ฑ, ์ž˜๋ชป๋œ ์„ ํƒ'],
    'The Chariot' => ['upright' => '์˜์ง€, ์Šน๋ฆฌ, ๊ฒฐ๋‹จ', 'reversed' => '๋ฐฉํ–ฅ ์ƒ์‹ค, ์ขŒ์ ˆ, ๊ณต๊ฒฉ์„ฑ'],
    'Strength' => ['upright' => '์šฉ๊ธฐ, ์ธ๋‚ด, ์ž์ œ๋ ฅ', 'reversed' => '์ž๊ธฐ ์˜์‹ฌ, ์•ฝํ•จ, ์ž์ œ๋ ฅ ๋ถ€์กฑ'],
    'The Hermit' => ['upright' => '๋‚ด๋ฉด ํƒ๊ตฌ, ๊ณ ๋…, ์ง€ํ˜œ', 'reversed' => '๊ณ ๋ฆฝ, ์™ธ๋กœ์›€, ์ฒ ํšŒ'],
    'Wheel of Fortune' => ['upright' => '์šด๋ช…, ๋ณ€ํ™”, ์ˆœํ™˜', 'reversed' => '๋ถˆ์šด, ์ €ํ•ญ, ์ •์ฒด'],
    'Justice' => ['upright' => '๊ณต์ •, ์ง„์‹ค, ๋ฒ•', 'reversed' => '๋ถˆ๊ณต์ •, ๊ฑฐ์ง“, ์ฑ…์ž„ ํšŒํ”ผ'],
    'The Hanged Man' => ['upright' => 'ํฌ์ƒ, ์ƒˆ๋กœ์šด ๊ด€์ , ๋Œ€๊ธฐ', 'reversed' => '์ง€์—ฐ, ์ €ํ•ญ, ํ—›๋œ ํฌ์ƒ'],
    'Death' => ['upright' => '์ข…๊ฒฐ, ๋ณ€ํ™”, ์žฌํƒ„์ƒ', 'reversed' => '์ €ํ•ญ, ์ •์ฒด, ๋‚ด๋ฉด์˜ ์ •ํ™”'],
    'Temperance' => ['upright' => '๊ท ํ˜•, ์ ˆ์ œ, ์น˜์œ ', 'reversed' => '๋ถˆ๊ท ํ˜•, ๊ณผ์ž‰, ๋ถ€์กฐํ™”'],
    'The Devil' => ['upright' => '์†๋ฐ•, ์ค‘๋…, ๋ฌผ์งˆ์ฃผ์˜', 'reversed' => 'ํ•ด๋ฐฉ, ์ž๊ฐ, ํƒˆ์ถœ'],
    'The Tower' => ['upright' => 'ํŒŒ๊ดด, ํ˜ผ๋ˆ, ๊ณ„์‹œ', 'reversed' => '์žฌ๋‚œ ํšŒํ”ผ, ๋‘๋ ค์›€, ์ง€์—ฐ๋œ ๋ณ€ํ™”'],
    'The Star' => ['upright' => 'ํฌ๋ง, ์˜๊ฐ, ํ‰์˜จ', 'reversed' => '์ ˆ๋ง, ์‹ ๋ขฐ ์ƒ์‹ค, ๋‹จ์ ˆ'],
    'The Moon' => ['upright' => 'ํ™˜์ƒ, ๋‘๋ ค์›€, ์ž ์žฌ์˜์‹', 'reversed' => 'ํ˜ผ๋ž€ ํ•ด์†Œ, ์ง„์‹ค, ๋ถˆ์•ˆ ๊ทน๋ณต'],
    'The Sun' => ['upright' => '๊ธฐ์จ, ์„ฑ๊ณต, ํ™œ๋ ฅ', 'reversed' => '๋น„๊ด€, ์šฐ์šธ, ์ง€์—ฐ๋œ ํ–‰๋ณต'],
    'Judgement' => ['upright' => '๊ฐ์„ฑ, ๊ฒฐ๋‹จ, ์žฌ์ƒ', 'reversed' => '์ž๊ธฐ ์˜์‹ฌ, ํ›„ํšŒ, ํŒ๋‹จ ์œ ๋ณด'],
    'The World' => ['upright' => '์™„์„ฑ, ์„ฑ์ทจ, ์—ฌํ–‰', 'reversed' => '๋ฏธ์™„์„ฑ, ์ง€์—ฐ, ๋ถ€์กฑํ•จ']
];

// ํ˜„์žฌ ์‚ฌ์šฉ์ž ID
$user_id = $is_member ? $member['mb_id'] : session_id();

// ๋ฆฌ๋”ฉ ID ๊ฐ€์ ธ์˜ค๊ธฐ
$reading_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;

if ($reading_id === 0) {
    die('์ž˜๋ชป๋œ ์ ‘๊ทผ์ž…๋‹ˆ๋‹ค.');
}

// ๋ฆฌ๋”ฉ ์กฐํšŒ (๋ณธ์ธ ๊ฒƒ๋งŒ)
$db = getTarotDB();
$stmt = $db->prepare("SELECT * FROM readings WHERE id = ? AND user_id = ?");
$stmt->execute([$reading_id, $user_id]);
$reading = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$reading) {
    die('๋ฆฌ๋”ฉ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.');
}

// ์นด๋“œ ์ •๋ณด ์žฌ๊ตฌ์„ฑ
$cards = [
    [
        'position' => '๊ณผ๊ฑฐ',
        'emoji' => 'โณ',
        'name' => $reading['card1_name'],
        'reversed' => (bool)$reading['card1_reversed'],
        'meaning' => isset($tarot_deck[$reading['card1_name']]) 
            ? ($reading['card1_reversed'] ? $tarot_deck[$reading['card1_name']]['reversed'] : $tarot_deck[$reading['card1_name']]['upright'])
            : ''
    ],
    [
        'position' => 'ํ˜„์žฌ',
        'emoji' => 'โœจ',
        'name' => $reading['card2_name'],
        'reversed' => (bool)$reading['card2_reversed'],
        'meaning' => isset($tarot_deck[$reading['card2_name']]) 
            ? ($reading['card2_reversed'] ? $tarot_deck[$reading['card2_name']]['reversed'] : $tarot_deck[$reading['card2_name']]['upright'])
            : ''
    ],
    [
        'position' => '๋ฏธ๋ž˜',
        'emoji' => '๐Ÿ”ฎ',
        'name' => $reading['card3_name'],
        'reversed' => (bool)$reading['card3_reversed'],
        'meaning' => isset($tarot_deck[$reading['card3_name']]) 
            ? ($reading['card3_reversed'] ? $tarot_deck[$reading['card3_name']]['reversed'] : $tarot_deck[$reading['card3_name']]['upright'])
            : ''
    ]
];

require_once(G5_THEME_PATH.'/modern/_head.inc.php');
include_once('./head.sub.php');
?>

<style>
.detail-hero {
    text-align: center;
    padding: 48px 20px;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    border-radius: var(--m-radius-lg);
    margin-bottom: 32px;
}
.detail-hero h1 {
    font-size: 2rem;
    font-weight: 700;
    margin: 0 0 12px;
}
.detail-hero .date {
    font-size: 1.1rem;
    opacity: 0.95;
    margin: 0 0 16px;
}
.back-link {
    display: inline-block;
    padding: 10px 24px;
    background: rgba(255, 255, 255, 0.2);
    color: white;
    border-radius: var(--m-radius-lg);
    text-decoration: none;
    font-weight: 600;
    transition: background 0.2s;
}
.back-link:hover {
    background: rgba(255, 255, 255, 0.3);
}
.cards-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 20px;
    margin-bottom: 32px;
}
.card-item {
    background: var(--m-surface);
    border-radius: var(--m-radius-lg);
    box-shadow: var(--m-shadow);
    padding: 24px;
    text-align: center;
}
.card-position {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-size: 1.1rem;
    font-weight: 600;
    color: #667eea;
    margin-bottom: 12px;
}
.card-name {
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--m-text);
    margin: 12px 0;
}
.card-orientation {
    display: inline-block;
    padding: 4px 12px;
    border-radius: 12px;
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 12px;
}
.card-orientation.upright {
    background: #d4edda;
    color: #155724;
}
.card-orientation.reversed {
    background: #f8d7da;
    color: #721c24;
}
.card-meaning {
    color: var(--m-text-muted);
    line-height: 1.6;
    font-size: 0.95rem;
}
.interpretation-box {
    background: var(--m-surface);
    border-radius: var(--m-radius-lg);
    box-shadow: var(--m-shadow);
    padding: 32px;
    margin-bottom: 32px;
}
.interpretation-box h3 {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--m-text);
    margin: 0 0 16px;
}
.interpretation-box p {
    font-size: 1.1rem;
    line-height: 1.8;
    color: var(--m-text);
    margin: 0;
}
</style>

<div class="m-shell">
    <?php require G5_THEME_PATH.'/modern/_nav.inc.php'; ?>
    
    <main class="m-container" style="padding: 32px 20px 48px; max-width: 900px; margin: 0 auto;">
        <div class="detail-hero">
            <h1>๐Ÿ”ฎ ํƒ€๋กœ ๋ฆฌ๋”ฉ ์ƒ์„ธ๋ณด๊ธฐ</h1>
            <div class="date">
                ๐Ÿ—“๏ธ <?php echo date('Y๋…„ m์›” d์ผ H:i', strtotime($reading['reading_date'])); ?>
            </div>
            <a href="/tarot-spread/history" class="back-link">โ† ๋ชฉ๋ก์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ</a>
        </div>

        <div class="cards-grid">
            <?php foreach ($cards as $card): ?>
                <div class="card-item">
                    <div class="card-position">
                        <span><?php echo $card['emoji']; ?></span>
                        <span><?php echo htmlspecialchars($card['position']); ?></span>
                    </div>
                    <div class="card-name"><?php echo htmlspecialchars($card['name']); ?></div>
                    <span class="card-orientation <?php echo $card['reversed'] ? 'reversed' : 'upright'; ?>">
                        <?php echo $card['reversed'] ? '์—ญ๋ฐฉํ–ฅ โ†“' : '์ •๋ฐฉํ–ฅ โ†‘'; ?>
                    </span>
                    <div class="card-meaning">
                        <?php echo htmlspecialchars($card['meaning']); ?>
                    </div>
                </div>
            <?php endforeach; ?>
        </div>
        
        <div class="interpretation-box">
            <h3>๐Ÿ”ฎ ์ข…ํ•ฉ ํ•ด์„</h3>
            <p><?php echo nl2br(htmlspecialchars($reading['interpretation'])); ?></p>
        </div>
    </main>
    
    <?php require G5_THEME_PATH.'/modern/_footer.inc.php'; ?>
</div>

<?php include_once('./tail.sub.php'); ?>
```

### 2. ๋ฉ”์ธ ํŽ˜์ด์ง€์— ๊ธฐ๋ก ๋ณด๊ธฐ ๋งํฌ ์ถ”๊ฐ€

`app/modules/tarot-spread/index.php`์˜ ํžˆ์–ด๋กœ ์„น์…˜ ์•„๋ž˜์— ๋งํฌ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์„ธ์š”:

```php
<div class="tarot-hero">
    <h1>๐Ÿ”ฎ ์˜ค๋Š˜์˜ ํƒ€๋กœ ์Šคํ”„๋ ˆ๋“œ</h1>
    <p>๊ณผ๊ฑฐ-ํ˜„์žฌ-๋ฏธ๋ž˜ 3์žฅ ์นด๋“œ๋กœ ๋‹น์‹ ์˜ ์šด์„ธ๋ฅผ ํ™•์ธํ•˜์„ธ์š”</p>
</div>

<!-- ์ด ๋ถ€๋ถ„ ์ถ”๊ฐ€ -->
<div style="text-align: center; margin-bottom: 24px;">
    <a href="/tarot-spread/history" style="display: inline-block; padding: 12px 32px; background: var(--m-surface); color: var(--m-text); border-radius: var(--m-radius-lg); text-decoration: none; font-weight: 600; box-shadow: var(--m-shadow); transition: transform 0.2s;" onmouseover="this.style.transform='translateY(-2px)'" onmouseout="this.style.transform='translateY(0)'">
        ๐Ÿ“š ๋‚˜์˜ ๋ฆฌ๋”ฉ ๊ธฐ๋ก ๋ณด๊ธฐ
    </a>
</div>
```

### ์ฃผ์š” ๊ธฐ๋Šฅ:

1. **์ƒ์„ธ ๋ณด๊ธฐ ํŽ˜์ด์ง€**: URL ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฆฌ๋”ฉ ID๋ฅผ ๋ฐ›์•„ ํ•ด๋‹น ๋ฆฌ๋”ฉ์˜ ์ „์ฒด ์ •๋ณด ํ‘œ์‹œ
2. **๊ถŒํ•œ ํ™•์ธ**: ๋ณธ์ธ์˜ ๋ฆฌ๋”ฉ๋งŒ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก user_id ์กฐ๊ฑด ์ถ”๊ฐ€
3. **์นด๋“œ ์ •๋ณด ์žฌ๊ตฌ์„ฑ**: DB์—์„œ ๊ฐ€์ ธ์˜จ ์นด๋“œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐฐ์—ด๋กœ ์žฌ๊ตฌ์„ฑํ•˜์—ฌ ํ‘œ์‹œ
4. **์ „์ฒด ํ•ด์„ ํ‘œ์‹œ**: ์ข…ํ•ฉ ํ•ด์„์„ ์ค„๋ฐ”๊ฟˆ ํฌํ•จํ•˜์—ฌ ์ „์ฒด ํ‘œ์‹œ
5. **๋‚ด๋น„๊ฒŒ์ด์…˜**: ๋ฉ”์ธ ํŽ˜์ด์ง€ โ†” ๋ชฉ๋ก โ†” ์ƒ์„ธ ํŽ˜์ด์ง€ ๊ฐ„ ์ด๋™ ๋งํฌ

ํŒŒ์ผ์„ ์ €์žฅํ•˜๊ณ  ๋ฆฌ๋”ฉ ๋ชฉ๋ก์—์„œ "์ž์„ธํžˆ ๋ณด๊ธฐ" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ์ƒ์„ธ ํŽ˜์ด์ง€๊ฐ€ ํ‘œ์‹œ๋˜๋Š”์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

๊ธฐ๋Œ€ ๊ฒฐ๊ณผ: ๋ฆฌ๋”ฉ ๋ชฉ๋ก์—์„œ "์ž์„ธํžˆ ๋ณด๊ธฐ" ํด๋ฆญ ์‹œ `/tarot-spread/view?id={๋ฆฌ๋”ฉID}` URL๋กœ ์ด๋™ํ•˜๋ฉฐ, ํ•ด๋‹น ๋ฆฌ๋”ฉ์˜ 3์žฅ ์นด๋“œ ์ „์ฒด ์ •๋ณด์™€ ์ข…ํ•ฉ ํ•ด์„์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๋ฉ”์ธ ํŽ˜์ด์ง€์—์„œ "๋‚˜์˜ ๋ฆฌ๋”ฉ ๊ธฐ๋ก ๋ณด๊ธฐ" ๋งํฌ๋ฅผ ํ†ตํ•ด ๋ชฉ๋ก ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ modern shell๋กœ ํ†ต์ผ๋œ ๋””์ž์ธ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

6
Step 6
## Step 6: ์นด๋“œ ๋’ค์ง‘๊ธฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ & ์ตœ์ข… ๋‹ค๋“ฌ๊ธฐ

`app/modules/tarot-spread/index.php` ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜์—ฌ ์นด๋“œ ๋ฝ‘๊ธฐ ์‹œ ๋’ค์ง‘ํžˆ๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ถ”๊ฐ€ํ•˜๊ณ , ์ „์ฒด์ ์ธ UX๋ฅผ ๊ฐœ์„ ํ•ด์ฃผ์„ธ์š”.

### ์ˆ˜์ • ๋‚ด์šฉ:

1. **์Šคํƒ€์ผ ๋ธ”๋ก์— ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ถ”๊ฐ€** (๊ธฐ์กด `<style>` ๋ธ”๋ก ํ•˜๋‹จ์— ์ถ”๊ฐ€):

```css
/* ์นด๋“œ ๋’ค์ง‘๊ธฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ */
@keyframes flipCard {
    0% {
        transform: perspective(1000px) rotateY(0deg);
        opacity: 0;
    }
    50% {
        transform: perspective(1000px) rotateY(90deg);
        opacity: 0.5;
    }
    100% {
        transform: perspective(1000px) rotateY(0deg);
        opacity: 1;
    }
}

.card-item.animate {
    animation: flipCard 0.8s ease-out;
}

.card-item:nth-child(1).animate {
    animation-delay: 0s;
}

.card-item:nth-child(2).animate {
    animation-delay: 0.2s;
}

.card-item:nth-child(3).animate {
    animation-delay: 0.4s;
}

/* ์นด๋“œ ๋’ท๋ฉด ํšจ๊ณผ (์„ ํƒ์ ) */
.card-back {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border-radius: var(--m-radius-lg);
    padding: 80px 20px;
    text-align: center;
    color: white;
    font-size: 3rem;
    box-shadow: var(--m-shadow);
}

/* ๋กœ๋”ฉ ์ƒํƒœ */
.loading-spinner {
    display: inline-block;
    width: 40px;
    height: 40px;
    border: 4px solid rgba(102, 126, 234, 0.2);
    border-radius: 50%;
    border-top-color: #667eea;
    animation: spin 1s linear infinite;
}

@keyframes spin {
    to { transform: rotate(360deg); }
}

/* ํ†ต๊ณ„ ๋ฐ•์Šค (๋ณด๋„ˆ์Šค) */
.stats-box {
    background: var(--m-surface);
    border-radius: var(--m-radius-lg);
    box-shadow: var(--m-shadow);
    padding: 24px;
    margin-top: 32px;
}

.stats-box h3 {
    color: var(--m-text);
    font-size: 1.3rem;
    font-weight: 600;
    margin: 0 0 16px;
}

.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 16px;
}

.stat-item {
    text-align: center;
    padding: 16px;
    background: rgba(102, 126, 234, 0.05);
    border-radius: var(--m-radius-lg);
}

.stat-number {
    font-size: 2rem;
    font-weight: 700;
    color: #667eea;
    margin-bottom: 4px;
}

.stat-label {
    font-size: 0.9rem;
    color: var(--m-text-muted);
}
```

2. **์นด๋“œ ๊ทธ๋ฆฌ๋“œ์— ์• ๋‹ˆ๋ฉ”์ด์…˜ ํด๋ž˜์Šค ์ถ”๊ฐ€** (๊ฒฐ๊ณผ ํ™”๋ฉด HTML ์ˆ˜์ •):

```php
<div class="cards-grid">
    <?php foreach ($spread as $index => $item): ?>
        <div class="card-item animate">
            <!-- ๊ธฐ์กด ์นด๋“œ ๋‚ด์šฉ ๋™์ผ -->
        </div>
    <?php endforeach; ?>
</div>
```

3. **ํ†ต๊ณ„ ์„น์…˜ ์ถ”๊ฐ€** (info-box ์•„๋ž˜์— ์ถ”๊ฐ€, ๋ณด๋„ˆ์Šค):

```php
<?php
// ๊ฐ„๋‹จํ•œ ํ†ต๊ณ„ ์กฐํšŒ
$db = getTarotDB();
$user_id = $is_member ? $member['mb_id'] : session_id();
$total_readings = $db->query("SELECT COUNT(*) FROM readings WHERE user_id = '{$user_id}'")->fetchColumn();
?>

<?php if ($total_readings > 0): ?>
<div class="stats-box">
    <h3>๐Ÿ“Š ๋‚˜์˜ ํƒ€๋กœ ํ†ต๊ณ„</h3>
    <div class="stats-grid">
        <div class="stat-item">
            <div class="stat-number"><?php echo $total_readings; ?></div>
            <div class="stat-label">์ด ๋ฆฌ๋”ฉ ํšŸ์ˆ˜</div>
        </div>
        <div class="stat-item">
            <div class="stat-number"><?php echo date('Y.m.d'); ?></div>
            <div class="stat-label">์˜ค๋Š˜ ๋‚ ์งœ</div>
        </div>
        <div class="stat-item">
            <div class="stat-number">22</div>
            <div class="stat-label">๋ฉ”์ด์ € ์•„๋ฅด์นด๋‚˜</div>
        </div>
    </div>
</div>
<?php endif; ?>
```

4. **์นด๋“œ ๋ฝ‘๊ธฐ ๋ฒ„ํŠผ์— ๋กœ๋”ฉ ์ƒํƒœ ์ถ”๊ฐ€** (์„ ํƒ์ , JS ํ•„์š” ์‹œ):

```php
<div class="draw-section">
    <form method="post" action="" id="drawForm">
        <button type="submit" name="draw" class="draw-btn" id="drawBtn">
            ๐ŸŽด ์นด๋“œ ๋ฝ‘๊ธฐ
        </button>
    </form>
</div>

<script>
document.getElementById('drawForm')?.addEventListener('submit', function() {
    const btn = document.getElementById('drawBtn');
    btn.innerHTML = '<span class="loading-spinner"></span>';
    btn.disabled = true;
});
</script>
```

5. **README ์ž‘์„ฑ** (ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— `README.md` ์ƒ์„ฑ):

```markdown
# ๐Ÿ”ฎ g5se ์˜ค๋Š˜์˜ ํƒ€๋กœ ์Šคํ”„๋ ˆ๋“œ ํ•ด์„๊ธฐ

๊ณผ๊ฑฐ-ํ˜„์žฌ-๋ฏธ๋ž˜ 3์žฅ ์นด๋“œ ๋ฆฌ๋”ฉ & ์šด์„ธ ์ €์žฅ ํ”Œ๋žซํผ

## โœจ ์ฃผ์š” ๊ธฐ๋Šฅ

- ๋ฉ”์ด์ € ์•„๋ฅด์นด๋‚˜ 22์žฅ ํƒ€๋กœ ๋ฑ
- 3์žฅ ์Šคํ”„๋ ˆ๋“œ (๊ณผ๊ฑฐ-ํ˜„์žฌ-๋ฏธ๋ž˜) ์ž๋™ ์ƒ์„ฑ
- ์ •๋ฐฉํ–ฅ/์—ญ๋ฐฉํ–ฅ ๋žœ๋ค ๊ฒฐ์ •
- ์นด๋“œ๋ณ„ ํ‚ค์›Œ๋“œ & ์ข…ํ•ฉ ํ•ด์„ ์ œ๊ณต
- ๋ฆฌ๋”ฉ ๊ฒฐ๊ณผ SQLite DB ์ €์žฅ
- ๊ณผ๊ฑฐ ๋ฆฌ๋”ฉ ๊ธฐ๋ก ๋ชฉ๋ก & ์ƒ์„ธ ๋ณด๊ธฐ
- ํšŒ์›/๋น„ํšŒ์› ๋ชจ๋‘ ์ด์šฉ ๊ฐ€๋Šฅ
- ๋‹คํฌ๋ชจ๋“œ ์ž๋™ ๋Œ€์‘
- ๋ฐ˜์‘ํ˜• ๋””์ž์ธ

## ๐Ÿš€ ์„ค์น˜ ๋ฐฉ๋ฒ•

1. g5se ์„ค์น˜ (https://github.com/gnuboard/g5se)
2. `app/modules/tarot-spread/` ํด๋”์— ํŒŒ์ผ ๋ณต์‚ฌ
3. `/tarot-spread` ์ ‘์†ํ•˜์—ฌ ์นด๋“œ ๋ฝ‘๊ธฐ

## ๐Ÿ“ ํŒŒ์ผ ๊ตฌ์กฐ

```
app/modules/tarot-spread/
โ”œโ”€โ”€ index.php          # ๋ฉ”์ธ ํŽ˜์ด์ง€ (์นด๋“œ ๋ฝ‘๊ธฐ)
โ”œโ”€โ”€ history/
โ”‚   โ””โ”€โ”€ index.php      # ๋ฆฌ๋”ฉ ๊ธฐ๋ก ๋ชฉ๋ก
โ””โ”€โ”€ view/
    โ””โ”€โ”€ index.php      # ๋ฆฌ๋”ฉ ์ƒ์„ธ ๋ณด๊ธฐ

data/modules/
โ””โ”€โ”€ tarot-spread.sqlite  # ๋ฆฌ๋”ฉ ๊ธฐ๋ก DB (์ž๋™ ์ƒ์„ฑ)
```

## ๐ŸŽจ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•

- ํƒ€๋กœ ๋ฑ ๋ฐ์ดํ„ฐ๋Š” `$tarot_deck` ๋ฐฐ์—ด์—์„œ ์ˆ˜์ • ๊ฐ€๋Šฅ
- ์ข…ํ•ฉ ํ•ด์„ ๋กœ์ง์€ ์นด๋“œ ๋ฝ‘๊ธฐ ์„น์…˜์—์„œ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•
- ์ƒ‰์ƒ/๋ ˆ์ด์•„์›ƒ์€ ์ธ๋ผ์ธ ์Šคํƒ€์ผ ๋˜๋Š” ๋ณ„๋„ CSS ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌ ๊ฐ€๋Šฅ

## ๐Ÿ“ ๋ผ์ด์„ ์Šค

MIT License
```

### ์ฃผ์š” ๊ฐœ์„  ์‚ฌํ•ญ:

1. **์นด๋“œ ๋’ค์ง‘๊ธฐ ์• ๋‹ˆ๋ฉ”์ด์…˜**: CSS `@keyframes`๋กœ 3์žฅ ์นด๋“œ๊ฐ€ ์ˆœ์ฐจ์ ์œผ๋กœ ๋’ค์ง‘ํžˆ๋Š” ํšจ๊ณผ
2. **๋กœ๋”ฉ ์Šคํ”ผ๋„ˆ**: ์นด๋“œ ๋ฝ‘๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ๋กœ๋”ฉ ํ‘œ์‹œ (์„ ํƒ์ )
3. **ํ†ต๊ณ„ ์„น์…˜**: ์ด ๋ฆฌ๋”ฉ ํšŸ์ˆ˜ ๋“ฑ ๊ฐ„๋‹จํ•œ ํ†ต๊ณ„ ํ‘œ์‹œ (๋ณด๋„ˆ์Šค)
4. **README ๋ฌธ์„œ**: ํ”„๋กœ์ ํŠธ ์„ค๋ช… & ์„ค์น˜ ๋ฐฉ๋ฒ• ์ •๋ฆฌ

ํŒŒ์ผ์„ ์ €์žฅํ•˜๊ณ  ์ „์ฒด ํ”Œ๋กœ์šฐ๋ฅผ ํ…Œ์ŠคํŠธํ•ด์ฃผ์„ธ์š”:
1. ๋ฉ”์ธ ํŽ˜์ด์ง€์—์„œ ์นด๋“œ ๋ฝ‘๊ธฐ
2. ๊ฒฐ๊ณผ ์ €์žฅ
3. ๋ฆฌ๋”ฉ ๊ธฐ๋ก ๋ชฉ๋ก ํ™•์ธ
4. ์ƒ์„ธ ๋ณด๊ธฐ ํŽ˜์ด์ง€ ํ™•์ธ
5. ๋‹คํฌ๋ชจ๋“œ ํ† ๊ธ€ ํ…Œ์ŠคํŠธ

๋ชจ๋“  ๊ธฐ๋Šฅ์ด ์ •์ƒ ์ž‘๋™ํ•˜๋ฉด ํ”„๋กœ์ ํŠธ ์™„์„ฑ์ž…๋‹ˆ๋‹ค! ๐ŸŽ‰

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

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

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

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

๋Œ“๊ธ€ (0)

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