interactive-chat / docs /plans /persistence.md
Junhoee's picture
Upload 113 files
7d46a91 verified
|
Raw
History Blame Contribute Delete
9.23 kB

์ธํ„ฐ์Šคํ‹ฐ์…œ ํžˆ์Šคํ† ๋ฆฌ + ์„ธ์…˜ ์˜์†ํ™” โ€” ๊ตฌํ˜„ ๊ณ„ํš

์ž‘์„ฑ์ผ: 2026-07-06 ยท ์ƒํƒœ: ๊ตฌํ˜„ ์™„๋ฃŒ (2026-07-06, feature/persistence) ๊ฒ€์ฆ: pytest 26๊ฑด ํ†ต๊ณผ(์‹ ๊ทœ 8๊ฑด ํฌํ•จ) + ์„œ๋ฒ„ ์žฌ์‹œ์ž‘ e2e (E01-11 ์ง„ํ–‰ โ†’ kill/์žฌ๊ธฐ๋™ โ†’ GET ๋ณต์› ๋™์ผ ์นด๋“œ โ†’ advance ๊ณ„์† ์ง„ํ–‰ ยท ๋ฏธ์กด์žฌ ์„ธ์…˜ 404) ํ›„์† ์ˆ˜์ • (2026-07-06, ์œ ์ € ์‹คํ”Œ๋ ˆ์ด ํ”ผ๋“œ๋ฐฑ 2ํšŒ): ์˜ค๋ฒ„๋ ˆ์ด ๋ฐฉ์‹ ์ž์ฒด๋ฅผ ํ๊ธฐ โ€” ์—ฐ์ถœ ์ปท์„ ์ž์ฒด ๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ง„ ๋…๋ฆฝ ํŽ˜์ด์ง€๋กœ (์˜ˆ: 6 ๋ณธ๋ฌธ โ†’ 7 ์ปท โ†’ 8 ๋ณธ๋ฌธ, total 66 = 61+5). ๋ฒˆํ˜ธ๋Š” ์„œ๋ฒ„(router _page_index)๊ฐ€ ๊ถŒ์œ„, ์ปท ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ = progress.index - 1. ํ”„๋ก ํŠธ์˜ ์˜ค๋ฒ„๋ ˆ์ด/pendingPage/ํด๋ฆญ๊ฐ€๋“œ ๋กœ์ง ์ „๋ถ€ ์ œ๊ฑฐ โ†’ ์ผ๋ฐ˜ ํŽ˜์ด์ง€ ํ๋ฆ„์œผ๋กœ ๋‹จ์ˆœํ™”. Node DOM ์Šคํ… ์‹œ๋ฎฌ๋ ˆ์ด์…˜์œผ๋กœ ์ •/์—ญ๋ฐฉํ–ฅยท์ขŒํด๋ฆญ ํ†ต๊ณผ ๊ฒ€์ฆ ์„ ํ–‰ ๊ฒฐ์ • (์œ ์ € ํ™•์ •):

  • ํฌ์ผ“(์ฑ„ํŒ…) ์ค‘๊ฐ„ ์ƒํƒœ๋Š” ์˜์†ํ™”ํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ์„œ๋ฒ„ ์žฌ์‹œ์ž‘/๋ณต์› ์‹œ ํฌ์ผ“์€ ๋ฒ„๋ฆฌ๊ณ  ์ฝ๊ธฐ ํ™”๋ฉด์œผ๋กœ
  • ๋ณต์› ๋ฒ”์œ„๋Š” "ํ˜„์žฌ ํŽ˜์ด์ง€๋ถ€ํ„ฐ ์ด์–ด ์ฝ๊ธฐ"๋งŒ โ€” ๋’ค๋กœ๊ฐ€๊ธฐ ํžˆ์Šคํ† ๋ฆฌ๋Š” ์ƒˆ๋กœ๊ณ ์นจ ์‹œ ํฌ๊ธฐ ๊ถŒ์žฅ์•ˆ ์ฑ„ํƒ: SQLite + ์Šค๋ƒ…์ƒท + ๋งค ๋ณ€๊ฒฝ ์ฆ‰์‹œ ์“ฐ๊ธฐ(write-through) + localStorage ์„ธ์…˜ ID + ์ฝ˜ํ…์ธ  ๋ฒ„์ „ ์Šคํƒฌํ”„๋กœ ๋ฌดํšจํ™”

๋ฌธ์ œ ์ •์˜

  1. ์ธํ„ฐ์Šคํ‹ฐ์…œ ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„๊ทธ: ์—ฐ์ถœ ์ปท์ด ํžˆ์Šคํ† ๋ฆฌ์˜ ํŽ˜์ด์ง€๊ฐ€ ์•„๋‹ˆ๋ผ ์ผํšŒ์„ฑ ์˜ค๋ฒ„๋ ˆ์ด๋ผ์„œ, ๋’ค๋กœ ๋„˜๊ธฐ๋ฉด ์ด๋ฏธ์ง€๊ฐ€ ๊ฑด๋„ˆ๋›ฐ์–ด์ง€๊ณ  ์ด์ „ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋‚˜์˜จ๋‹ค. ์˜๋„๋Š” ์ •๋ฐฉํ–ฅ๊ณผ ๋™์ผํ•˜๊ฒŒ "์Šคํฌ๋ฆฝํŠธ โ†’ ์ด๋ฏธ์ง€ ํŽ˜์ด์ง€ โ†’ ์Šคํฌ๋ฆฝํŠธ"๊ฐ€ ์—ญ๋ฐฉํ–ฅ์—์„œ๋„ ์œ ์ง€๋˜๋Š” ๊ฒƒ.
  2. ์˜์†ํ™” ๋ถ€์žฌ: ํ”Œ๋ ˆ์ด ์„ธ์…˜์ด 3์ธต ๋ชจ๋‘ ํœ˜๋ฐœ์„ฑ โ€” router._sessions(ํŒŒ์ด์ฌ dict) ยท ADK InMemorySessionService ยท ๋ธŒ๋ผ์šฐ์ € SID(JS ๋ณ€์ˆ˜). ์ƒˆ๋กœ๊ณ ์นจ์ด๋ฉด ์„ธ์…˜ ID๋ฅผ ์žƒ๊ณ , ์„œ๋ฒ„ ์žฌ์‹œ์ž‘์ด๋ฉด ์ „ ์œ ์ € ์ง„ํ–‰์ด ์‚ฌ๋ผ์ง„๋‹ค. CLAUDE.md ๊ถŒ์œ„ ์›์น™("ํ˜„์žฌ ์œ ์ €์˜ ์„œ์‚ฌ ์œ„์น˜ ๊ถŒ์œ„: DB play_session.current_state_id")์ด ์˜ˆ์ •ํ•œ DB๊ฐ€ ์•„์ง ์—†๋‹ค.

์„ค๊ณ„ ํ•ต์‹ฌ

๋ณต์›์˜ ํ•จ์ • โ€” _enter() ๋ถ€์ˆ˜ํšจ๊ณผ

StoryEngine._enter()๋Š” ์ง„์ž… ์‹œ ์‡ ์•ฝ๋„ ์ฆ๊ฐ€ยท์ถ• ์ ์šฉยท์•Ž ํ™•๋ฆฝ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ๋ณต์›์„ _enter(current_id) ์žฌํ˜ธ์ถœ๋กœ ๊ตฌํ˜„ํ•˜๋ฉด ์ƒํƒœ๊ฐ€ ์ด์ค‘ ์ ์šฉ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ๋ณต์›์€ ๋ถ€์ˆ˜ํšจ๊ณผ ์—†๋Š” ์ „์šฉ ๊ฒฝ๋กœ๋กœ: ํ•„๋“œ๋ฅผ ์ง์ ‘ ๋ณต์›ํ•˜๊ณ , ํ˜„์žฌ ์นด๋“œ์˜ StepResult๋Š” ๋ Œ๋” ์ „์šฉ ๋ฉ”์„œ๋“œ๋กœ ์žฌ๊ตฌ์„ฑํ•œ๋‹ค (_visible_narration + card.choices๋Š” ์ˆœ์ˆ˜ ์กฐํšŒ).

์Šค๋ƒ…์ƒท ํŽ˜์ด๋กœ๋“œ (JSON ์ง๋ ฌํ™” โ€” ์ „ ํ•„๋“œ int/str/bool/list)

{
  "story":  {"current_id": "E04-07", "visited": [...], "preset_branch": null, "ending_id": null},
  "hidden": {"trust_score": 24, "doubt_score": 12, "frailty": 3,
             "awareness_established": true, "axis_log": [...]}
}
  • ending_id: ์—”๋”ฉ ๋„๋‹ฌ ์„ธ์…˜๋„ ๋ณต์› ๋Œ€์ƒ (์ƒˆ๋กœ๊ณ ์นจ ์‹œ ์—”๋”ฉ ํ™”๋ฉด ์œ ์ง€). ๋ณต์› ์‹œ chapter.ending_rules์—์„œ id๋กœ ์—ญ์กฐํšŒ
  • ํฌ์ผ“ ์ง„ํ–‰ ์ค‘ ์ €์žฅ๋ถ„์€ ์—†๋‹ค โ€” ํฌ์ผ“ ์•ˆ์˜ ์ฆ๋ถ„์€ close ์ปค๋ฐ‹ ํ›„์—๋งŒ ์˜์† ์ƒํƒœ์— ๋ฐ˜์˜ (๊ธฐ์กด ๋‹จ์ผ ๊ฒฝ๋กœ ์œ ์ง€). ํฌ์ผ“ ๋„์ค‘ ์„œ๋ฒ„๊ฐ€ ์ฃฝ์œผ๋ฉด ๊ทธ ๋Œ€ํ™”์˜ ์‹ ๋ขฐ์ถ• ์ฆ๋ถ„์€ ์œ ์‹ค๋œ๋‹ค (์Šน์ธ๋œ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„)
  • ๊ธฐ์กด HiddenState.to_session()์€ ํฌ์ผ“ ์ „์šฉ(๋ถ€๋ถ„ยทํ‚ค ์ƒ์ด)์ด๋ฏ€๋กœ ์žฌ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์Šค๋ƒ…์ƒท ๋ฉ”์„œ๋“œ๋ฅผ ๋ณ„๋„ ์ถ”๊ฐ€

์ฝ˜ํ…์ธ  ๋ฒ„์ „ ์Šคํƒฌํ”„

  • ContentRepository์— content_version ํ”„๋กœํผํ‹ฐ: chapter.id + ์ „์—ญ ์ˆœ์„œ์˜ ์นด๋“œ ID ๋ชฉ๋ก์„ sha256 ํ•ด์‹œ
  • ์ €์žฅ ์‹œ ์Šคํƒฌํ”„, ๋ณต์› ์‹œ ๋ถˆ์ผ์น˜๋ฉด ๋ฌดํšจํ™”(404 โ†’ ํ”„๋ก ํŠธ๊ฐ€ ์ƒˆ ์„ธ์…˜ ์‹œ์ž‘). ์นด๋“œ ๋ณธ๋ฌธ๋งŒ ๋ฐ”๋€ ๊ฒฝ์šฐ๋Š” ์žก์ง€ ๋ชปํ•˜์ง€๋งŒ(ID/์ˆœ์„œ ๋™์ผ) ๋ณต์›์ด ๊นจ์ง€์ง€๋Š” ์•Š์œผ๋ฏ€๋กœ ๋ฐ๋ชจ ์ˆ˜์šฉ

์ €์žฅ ์‹œ์  (write-through)

์˜์† ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ๋Š” ๋ชจ๋“  ์ง€์ ์—์„œ ์ฆ‰์‹œ ์ €์žฅ โ€” POST /session(์ƒ์„ฑ) ยท advance ยท choose ยท pocket/turn(์ˆ˜๋ ด ์ปค๋ฐ‹ ์‹œ) ยท pocket/close. pocket/open์€ ์˜์† ์ƒํƒœ ๋ฌด๋ณ€๊ฒฝ์ด๋ผ ์ €์žฅ ์—†์Œ.

๋™์‹œ์„ฑยท์ˆ˜๋ช…

  • uvicorn ์›Œ์ปค 1๊ฐœ ์ „์ œ ์œ ์ง€ (์ธ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ + ADK InMemory ์„ธ์…˜ ๋•Œ๋ฌธ). SQLite๋Š” WAL ๋ชจ๋“œ
  • ๊ฐ™์€ ์„ธ์…˜ ๋™์‹œ ์ ‘๊ทผ์€ ๋งˆ์ง€๋ง‰ ์“ฐ๊ธฐ ์Šน๋ฆฌ (๋ฐ๋ชจ ์ˆ˜์šฉ)
  • ์„œ๋ฒ„ ๊ธฐ๋™ ์‹œ 30์ผ ๋ฏธ๊ฐฑ์‹  ์„ธ์…˜ purge

๋ณ€๊ฒฝ ํŒŒ์ผ ๋ชฉ๋ก

A. ์ธํ„ฐ์Šคํ‹ฐ์…œ ํžˆ์Šคํ† ๋ฆฌ (๋ฒ„๊ทธ ์ˆ˜์ • โ€” ํ”„๋ก ํŠธ ๋‹จ๋…)

ํŒŒ์ผ ๋ณ€๊ฒฝ
web/index.html ํžˆ์Šคํ† ๋ฆฌ ํ•ญ๋ชฉ์„ 2์ข…์œผ๋กœ ํƒ€์ž…ํ™”: {kind:'page', html, progress, ep} ยท {kind:'inter', image, caption, progress, ep}. โ‘  showStep(): step.image ์žˆ์œผ๋ฉด inter ํ•ญ๋ชฉ์„ ๋จผ์ € pushํ•˜๊ณ  ์˜ค๋ฒ„๋ ˆ์ด ํ‘œ์‹œ, ์˜ค๋ฒ„๋ ˆ์ด ํด๋ฆญ ์‹œ page ํ•ญ๋ชฉ push + ๋ Œ๋” โ‘ก go(): ์ปค์„œ ์ด๋™์„ ๊ณตํ†ต renderEntry(cursor)๋กœ ํ†ต์ผ โ€” inter ํ•ญ๋ชฉ์ด๋ฉด ์˜ค๋ฒ„๋ ˆ์ด ํ‘œ์‹œ, page ํ•ญ๋ชฉ์ด๋ฉด HTML ๋ณต์› + ์˜ค๋ฒ„๋ ˆ์ด ๋‹ซ๊ธฐ โ‘ข ๋ธŒ๋ผ์šฐ์ง• ์ค‘ ์˜ค๋ฒ„๋ ˆ์ด ํด๋ฆญ = go(+1) (์˜ค๋ฒ„๋ ˆ์ด๊ฐ€ ๋‚ด๋น„ ์กด์„ ๋ฎ์œผ๋ฏ€๋กœ; โ† ํ‚ค๋Š” ๊ณ„์† ๋™์ž‘) โ‘ฃ choose()์˜ ์Šค๋ƒ…์ƒท ๊ฐฑ์‹ (history[cursor].html)์€ page ํ•ญ๋ชฉ์—๋งŒ ๋‹ฟ์œผ๋ฏ€๋กœ ๊ทธ๋Œ€๋กœ

B. ์˜์†ํ™”

ํŒŒ์ผ ๋ณ€๊ฒฝ
engine/services/state.py HiddenState.snapshot() -> dict / HiddenState.from_snapshot(d) ์ถ”๊ฐ€ (์ „ ํ•„๋“œ. to_session()๊ณผ ๋ณ„๊ฐœ โ€” ํฌ์ผ“ ๊ฒฝ๋กœ ๋ถˆ๋ณ€)
engine/services/story.py โ‘  snapshot() -> dict (story ํŒŒํŠธ) โ‘ก StoryEngine.restore(repo, snap) -> StoryEngine ํด๋ž˜์Šค๋ฉ”์„œ๋“œ โ€” ๋ถ€์ˆ˜ํšจ๊ณผ ์—†์ด ํ•„๋“œ ์ง์ ‘ ๋ณต์› โ‘ข current_step() -> StepResult โ€” ํ˜„์žฌ ์นด๋“œ/์—”๋”ฉ์˜ StepResult๋ฅผ ๋ Œ๋” ์ „์šฉ์œผ๋กœ ์žฌ๊ตฌ์„ฑ
engine/repositories/content.py content_version ํ”„๋กœํผํ‹ฐ (sha256 ์Šคํƒฌํ”„)
engine/repositories/play_session.py ์‹ ๊ทœ. stdlib sqlite3, WAL. ํ…Œ์ด๋ธ” play_session(sid TEXT PK, payload TEXT, content_version TEXT, updated_at TEXT). ๋ฉ”์„œ๋“œ: save(sid, payload, version) / `load(sid, version) -> dict
engine/router.py โ‘  PlaySessionRepository(ROOT/"data"/"sessions.db") ์ƒ์„ฑ + ๊ธฐ๋™ ์‹œ purge() โ‘ก _sessions dict๋Š” ์บ์‹œ๋กœ ์œ ์ง€, _get() ๋ฏธ์Šค ์‹œ ์ €์žฅ์†Œ์—์„œ ๋กœ๋“œ โ†’ StoryEngine.restore + current_step()์œผ๋กœ PlaySession ์žฌ๊ตฌ์„ฑ (pocket_sid=None โ€” ํฌ์ผ“ ํ๊ธฐ) โ‘ข ์ €์žฅ ํ—ฌํผ _save(sid, ps)๋ฅผ ์ƒ์„ฑ/advance/choose/pocket ์ˆ˜๋ ด/close์— write-through
web/index.html โ‘  ๊ธฐ๋™ ์‹œ localStorage.carmilla_sid ์žˆ์œผ๋ฉด GET /api/session/{sid} ์‹œ๋„ โ€” ์„ฑ๊ณต ์‹œ ํ‘œ์ง€ ๋ฒ„ํŠผ์ด "์ด์–ด ์ฝ๊ธฐ"๋กœ ๋™์ž‘(์ƒˆ ์„ธ์…˜ ์ƒ์„ฑ ์ƒ๋žต, ํ˜„์žฌ ํŽ˜์ด์ง€๋ถ€ํ„ฐ), 404๋ฉด sid ํ๊ธฐ ํ›„ ๊ธฐ์กด ํ๋ฆ„ โ‘ก ์„ธ์…˜ ์ƒ์„ฑ ์‹œ sid๋ฅผ localStorage์— ์ €์žฅ โ‘ข ์—”๋”ฉ "๋‹ค์‹œ, ์ฒ˜์Œ์˜ ๋ฐค์œผ๋กœ" ํด๋ฆญ ์‹œ sid ์ œ๊ฑฐ ํ›„ reload
.gitignore data/ ์ถ”๊ฐ€
tests/test_persistence.py ์‹ ๊ทœ. โ‘  ์Šค๋ƒ…์ƒทโ†’๋ณต์› ๋ผ์šด๋“œํŠธ๋ฆฝ: ๋ช‡ ์นด๋“œ ์ง„ํ–‰ ํ›„ ๋ณต์›ํ–ˆ์„ ๋•Œ current_id/์ˆจ์€ ์ƒํƒœ/์ง„ํ–‰๋„ ๋™์ผ โ‘ก ๋ณต์›์ด ์‡ ์•ฝ๋„ยท์ถ•์„ ์žฌ์ ์šฉํ•˜์ง€ ์•Š์Œ (ํ•ต์‹ฌ ํšŒ๊ท€) โ‘ข ์—”๋”ฉ ์„ธ์…˜ ๋ณต์› โ‘ฃ ์ €์žฅ์†Œ save/load + ๋ฒ„์ „ ๋ถˆ์ผ์น˜ ์‹œ None โ‘ค ๋ผ์šฐํ„ฐ ๋ ˆ๋ฒจ: _sessions ์บ์‹œ ๋น„์šด ๋’ค(์žฌ์‹œ์ž‘ ๋ชจ์‚ฌ) GET์œผ๋กœ ๋ณต์›๋˜๊ณ  ํฌ์ผ“์€ ๋‹ซํ˜€ ์žˆ์Œ
docs/contract/demo_api.md GET /api/session/{sid}๊ฐ€ ๋ณต์› ์ง„์ž…์ ์ž„์„ ๋ช…์‹œ (404 = ๋ฏธ์กด์žฌ ๋˜๋Š” ์ฝ˜ํ…์ธ  ๋ฒ„์ „ ๋ถˆ์ผ์น˜ โ†’ ์ƒˆ ์„ธ์…˜ ์ƒ์„ฑํ•  ๊ฒƒ). ํฌ์ผ“ ๋น„์˜์† ๋ช…์‹œ
docs/plans/persistence.md ๋ณธ ๋ฌธ์„œ

๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š” ๊ฒƒ

  • engine/app.py โ€” ADK InMemorySessionService ์œ ์ง€ (ํฌ์ผ“ ๋น„์˜์† ๊ฒฐ์ •์— ๋”ฐ๋ผ SqliteSessionService ๋ถˆํ•„์š”)
  • engine/services/pocket.py โ€” ํฌ์ผ“ ์ปค๋ฐ‹ ๋‹จ์ผ ๊ฒฝ๋กœ ๋ถˆ๋ณ€
  • content/ โ€” ๋ฌด๋ณ€๊ฒฝ (์ฝ˜ํ…์ธ  ์ปค๋ฐ‹ ๊ธˆ์ง€ ๊ทœ์น™)

์ž‘์—… ์ˆœ์„œ

  1. P1 โ€” ์ธํ„ฐ์Šคํ‹ฐ์…œ ํžˆ์Šคํ† ๋ฆฌ (web/index.html ๋‹จ๋…, ์„œ๋ฒ„ ๋ฌด๊ด€) โ†’ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ •/์—ญ๋ฐฉํ–ฅ ์ˆ˜๋™ ํ™•์ธ
  2. P2 โ€” ์Šค๋ƒ…์ƒท/๋ณต์› ์—”์ง„ (state.py, story.py) + ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (๋ถ€์ˆ˜ํšจ๊ณผ ๋ฏธ์žฌ์ ์šฉ ํšŒ๊ท€ ํฌํ•จ)
  3. P3 โ€” SQLite ์ €์žฅ์†Œ + ๋ผ์šฐํ„ฐ write-through/๋ณต์› (play_session.py, content.py, router.py) + ๋ผ์šฐํ„ฐ ํ…Œ์ŠคํŠธ
  4. P4 โ€” ํ”„๋ก ํŠธ ์ด์–ด ์ฝ๊ธฐ (web/index.html localStorage) โ†’ ์ƒˆ๋กœ๊ณ ์นจยท์„œ๋ฒ„ ์žฌ์‹œ์ž‘ ํ›„ ์ด์–ด ์ฝ๊ธฐ ์ˆ˜๋™ ํ™•์ธ
  5. P5 โ€” ๋ฌธ์„œ ๊ฐฑ์‹  (demo_api.md, ARCHITECTURE.md ์น˜ํŠธ์‹œํŠธ 1์ค„)

๊ฒ€์ฆ: pytest tests/ -q ์ „๊ฑด ํ†ต๊ณผ + ์ˆ˜๋™ ์‹œ๋‚˜๋ฆฌ์˜ค 3์ข… (โ‘  ์ด๋ฏธ์ง€ ํŽ˜์ด์ง€ ๋’ค๋กœ๊ฐ€๊ธฐ/์•ž์œผ๋กœ๊ฐ€๊ธฐ โ‘ก ์ƒˆ๋กœ๊ณ ์นจ ํ›„ ์ด์–ด ์ฝ๊ธฐ โ‘ข uvicorn ์žฌ์‹œ์ž‘ ํ›„ ์ด์–ด ์ฝ๊ธฐ โ€” ํฌ์ผ“ ์ค‘์ด์—ˆ๋‹ค๋ฉด ์ฝ๊ธฐ ํ™”๋ฉด์œผ๋กœ).

๋ฆฌ์Šคํฌ / ํ•œ๊ณ„ (์Šน์ธ๋œ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„ ํฌํ•จ)

  • ํฌ์ผ“ ๋„์ค‘ ์„œ๋ฒ„ ์‚ฌ๋ง ์‹œ ๊ทธ ๋Œ€ํ™”์˜ ์‹ ๋ขฐ์ถ• ์ฆ๋ถ„ ์œ ์‹ค (ํฌ์ผ“ ๋น„์˜์† ๊ฒฐ์ •์˜ ๊ท€๊ฒฐ)
  • ์ƒˆ๋กœ๊ณ ์นจ ์‹œ ๋’ค๋กœ๊ฐ€๊ธฐ ํžˆ์Šคํ† ๋ฆฌยท์„ ํƒ ๊ฒฐ๊ณผ ์‚ฐ๋ฌธ์€ ์†Œ์‹ค, ํ˜„์žฌ ํŽ˜์ด์ง€๋ถ€ํ„ฐ (๊ฒฐ์ • โ‘ค)
  • ์นด๋“œ ๋ณธ๋ฌธ๋งŒ ๋ฐ”๋€ ์ฝ˜ํ…์ธ  ๊ฐฑ์‹ ์€ ๋ฒ„์ „ ์Šคํƒฌํ”„๊ฐ€ ๊ฐ์ง€ ๋ชปํ•จ (ID/์ˆœ์„œ ๋™์ผ ์‹œ) โ€” ๋ณต์›์€ ์•ˆ ๊นจ์ง
  • ๋ฉ€ํ‹ฐ ์›Œ์ปค/๋ฉ€ํ‹ฐ ํ”„๋กœ์„ธ์Šค๋Š” ์—ฌ์ „ํžˆ ๋น„์ง€์› (ADK ์„ธ์…˜ยท์บ์‹œ๊ฐ€ ์ธ๋ฉ”๋ชจ๋ฆฌ)