FUTURE_CAR SPEC TABLET - zero1ne-26/doc GitHub Wiki

[tablet-fe ๊ตฌํ˜„ ์ŠคํŽ™] ๋ฏธ๋ž˜์ฐจ ์—ฐ๋™ โ€” 2026-08-29ํŒ

  • ์ž‘์„ฑ: ๋ฏธ๋ž˜์ฐจ ํŒ€ ยท 2026-08-29 (2026-08-23ํŒ ์ „๋ฉด ์žฌ์ž‘์„ฑ โ€” ๊ณผ๊ฑฐ ๋‚ด์šฉ์€ ํ๊ธฐ)
  • ๋Œ€์ƒ ์ฝ”๋“œ: tablet-fe 60d353c (main) ยท ๋ฏธ๋ž˜์ฐจ ์„œ๋ฒ„ zer01ne-future-car-server main-2026 a1d3673 (์กฐ์ง ๋ฏธ๋Ÿฌ: zero1ne-26/future-car-server)
  • ๊ณ„์•ฝ ์ •๋ณธ: ์œ„ํ‚ค MQTT_SCHEMA-FUTURE_CAR โ€” ์ด ๋ฌธ์„œ๋Š” ํƒœ๋ธ”๋ฆฟ ๊ฐœ๋ฐœ์ž๊ฐ€ ํ•  ์ผ๋งŒ ๋‹ค๋ฃฌ๋‹ค. ํ† ํ”ฝยทํ•„๋“œ ์ •์˜๋Š” ์ •๋ณธ์„ ๋ณธ๋‹ค.
  • ๋ฏธ๋ž˜์ฐจ ์„œ๋ฒ„ ๋ฐฐํฌ ์ƒํƒœ: 2026-08-29 Mac Studio ๋ฐฐํฌ ์™„๋ฃŒ(์„œ๋ฒ„ a1d3673ยทํด๋ผ 51ba4a7, ๋‘˜ ๋‹ค 5cc571f/8e22f63 ์ดํ›„). ยง7 "๋ฐฐํฌ ์ „ํ›„ ์ฐจ์ด"์˜ "๋ฐฐํฌ ์ „" ๋™์ž‘์€ ๋” ์ด์ƒ ํ•ด๋‹น ์—†์Œ โ€” ๊ธฐ๋ก์šฉ์œผ๋กœ๋งŒ ๋‚จ๊ธด๋‹ค.

์š”์•ฝ: ํƒœ๋ธ”๋ฆฟ์ด ๋ฏธ๋ž˜์ฐจ์™€ ์ฃผ๊ณ ๋ฐ›๋Š” ์ฝ”๋“œ๋Š” ์ด๋ฏธ ๋‹ค ๋“ค์–ด๊ฐ€ ์žˆ๋‹ค(enter/exit ๋ฐœํ–‰, future-car/response ์ˆ˜์‹ , ๋…ธ์„ ๋„). 2026-08-28 ์ •์ฑ… ๋ณ€๊ฒฝ์œผ๋กœ ๋”ฑ ํ•˜๋‚˜๊ฐ€ ์ƒˆ๋กœ ํ•„์š”ํ•˜๋‹ค โ€” ์ฐจ ์•ˆ์— ์žˆ๋Š” ๋™์•ˆ ํƒœ๋ธ”๋ฆฟ์˜ ์ฑ„ํŒ… ์ž…๋ ฅ(ํ…์ŠคํŠธยท๋งˆ์ดํฌยท์ œ์•ˆ ์นฉ)์„ ์ž ๊ทธ๋Š” ๊ฒƒ(ยง2-A). ๋‚˜๋จธ์ง€๋Š” ๊ถŒ์žฅ ์‚ฌํ•ญ๊ณผ ํ™•์ธ ์‚ฌํ•ญ์ด๋‹ค.


๋ชฉ์ฐจ


0. ๋ฐฐ๊ฒฝ โ€” ๋ฏธ๋ž˜์ฐจ๊ฐ€ ๋ฌด์—‡์ด๊ณ  ๊ด€๋žŒ๊ฐ์—๊ฒŒ ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๋‚˜

์ „์‹œ์žฅ์—๋Š” ๋ฏธ๋ž˜์ฐจ(์‹ค๋ฌผ ์ฐจ + ์ฐจ ์•ˆ ๋””์Šคํ”Œ๋ ˆ์ด + ๋งˆ์ดํฌ)๊ฐ€ ํ•œ ๋Œ€ ์žˆ๋‹ค. ๊ด€๋žŒ๊ฐ์€ ํƒœ๋ธ”๋ฆฟ์„ ๋“ค๊ณ  ์—ฌ๋Ÿฌ ์žฅ์†Œ(์ง‘ยท๊ณต์›ยท๋งˆํŠธยท์ฐจ)๋ฅผ ๋Œ๋ฉฐ ํƒœ์Šคํฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š”๋ฐ, ๊ทธ์ค‘ "์ฐจ" ์žฅ์†Œ๊ฐ€ ๋ฏธ๋ž˜์ฐจ๋‹ค. ๋ฏธ๋ž˜์ฐจ ์ชฝ ์‹œ์Šคํ…œ์€ ๋‘˜์ด๋‹ค.

๊ตฌ์„ฑ ์—ญํ• 
๋ฏธ๋ž˜์ฐจ ์„œ๋ฒ„ (Mac Studio :8100, FastAPI) MQTT ๋กœ OCยทํƒœ๋ธ”๋ฆฟ๊ณผ ํ†ต์‹ . ๊ด€๋žŒ๊ฐ ๋ฐœํ™”๋ฅผ ์žฌ๋ฃŒ๋กœ LLM ์ด "์Šคํ…"(์ฐจ ์•ˆ ์—ฐ์ถœ ํ•œ ์žฅ๋ฉด)์„ 4๊ฐœ ์ƒ์„ฑํ•ด ํ™”๋ฉด์— ๋‚ด๋ ค๋ณด๋‚ด๊ณ , ํƒœ๋ธ”๋ฆฟ ์ฑ„ํŒ…์— ์งˆ๋ฌธ์„ ๋„์šฐ๊ณ , OC ์— ํƒœ์Šคํฌ ์‹œ์ž‘ยท์™„๋ฃŒ๋ฅผ ๋ณด๊ณ ํ•œ๋‹ค
๋ฏธ๋ž˜์ฐจ ํ™”๋ฉด (/ambient, ์ฐจ ์•ˆ ๋””์Šคํ”Œ๋ ˆ์ด) ์Šคํ…์„ ์žฌ์ƒํ•˜๊ณ , ์žฌ์ƒ์ด ๋๋‚˜๋ฉด ์„œ๋ฒ„์— ๋ณด๊ณ ํ•˜๊ณ , ๊ด€๋žŒ๊ฐ ์ฐจ๋ก€์— ๋งˆ์ดํฌ๋ฅผ ์—ด์–ด ๋ฐœํ™”๋ฅผ STT ํ•ด ์„œ๋ฒ„๋กœ ๋ณด๋‚ธ๋‹ค

๊ด€๋žŒ๊ฐ์ด ๊ฒช๋Š” ์ˆœ์„œ (ํƒœ๋ธ”๋ฆฟ ์‹œ์ )

  1. ํƒœ๋ธ”๋ฆฟ์—์„œ "์ฐจ๋กœ ์ด๋™"์„ ํ™•์ •ํ•˜๋ฉด(TaskCompleteDialog) ํƒœ๋ธ”๋ฆฟ์ด enter ๋ฅผ ๋ณด๋‚ธ๋‹ค. ์ฐจ ํ™”๋ฉด์ด ๋Œ€๊ธฐ ํ™”๋ฉด์œผ๋กœ ๋ฐ”๋€Œ๊ณ , ํƒœ๋ธ”๋ฆฟ ์ฑ„ํŒ…์— "์ถœ๋ฐœ ํ• ๊นŒ์š”?" ์™€ ๋‹ต ํ›„๋ณด ์นฉ 2๊ฐœ๊ฐ€ ๋œฌ๋‹ค.
  2. ๊ด€๋žŒ๊ฐ์€ ์ฐจ์— ๋Œ€๊ณ  ๋‹ตํ•œ๋‹ค("๋„ค, ์ถœ๋ฐœํ•ด์š”"). ์ฐจ ๋งˆ์ดํฌ๊ฐ€ ๋ฐ›์•„ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๊ณ , ์„œ๋ฒ„๊ฐ€ ์Šคํ… 1์„ ๋งŒ๋“ ๋‹ค(10~30์ดˆ). ํƒœ๋ธ”๋ฆฟ์—๋Š” ์ด ๊ตฌ๊ฐ„(route)์ด ๋…ธ์„ ๋„์— ๊ทธ๋ ค์ง„๋‹ค.
  3. ์ฐจ ํ™”๋ฉด์ด ์Šคํ… 1์„ ์žฌ์ƒํ•œ๋‹ค. ๊ทธ๋™์•ˆ ํƒœ๋ธ”๋ฆฟ์˜ "์ฐจ๋Ÿ‰ ์ƒํƒœยท์ฃผํ–‰ ์ ๊ฒ€" ๊ฐ™์€ basic ํƒœ์Šคํฌ ์นด๋“œ๊ฐ€ "์ง„ํ–‰ ์ค‘" ์ด ๋œ๋‹ค.
  4. ์žฌ์ƒ์ด ๋๋‚˜๋ฉด ์นด๋“œ๊ฐ€ "์™„๋ฃŒ" ๋กœ ๋ฐ”๋€Œ๊ณ , ์ฑ„ํŒ…์— ๋‹ค์Œ ์งˆ๋ฌธ์ด ๋œฌ๋‹ค. ๊ด€๋žŒ๊ฐ์€ ๋‹ค์‹œ ์ฐจ์— ๋Œ€๊ณ  ๋‹ตํ•œ๋‹ค.
  5. 2~4 ๊ฐ€ ์Šคํ… 4๊นŒ์ง€ ๋ฐ˜๋ณต๋œ๋‹ค. ์Šคํ… 4 ์žฌ์ƒ์ด ๋๋‚˜๋ฉด ์งˆ๋ฌธ ์—†์ด ์ฐจ ํ™”๋ฉด์ด ์—”๋”ฉ์„ ๋ณด์—ฌ์ฃผ๊ณ , ํƒœ๋ธ”๋ฆฟ์—๋Š” ํ•˜์ฐจ ๊ฐ€๋Šฅ ์‹ ํ˜ธ(state.next="exit")๊ฐ€ ์˜จ๋‹ค.
  6. ํƒœ๋ธ”๋ฆฟ์—์„œ "๋‹ค์Œ ์žฅ์†Œ๋กœ ์ด๋™"์„ ํ™•์ •ํ•˜๋ฉด exit ๋ฅผ ๋ณด๋‚ธ๋‹ค. ์ฐจ ํ™”๋ฉด์€ ์ž‘๋ณ„ ํ™”๋ฉด, ์—ฌ์ • ์ข…๋ฃŒ.

2026-08-28 ์ •์ฑ… ๋ณ€๊ฒฝ โ€” ์™œ ํƒœ๋ธ”๋ฆฟ ์ž…๋ ฅ์„ ์ž ๊ทธ๋‚˜

์ด์ „ ์„ค๊ณ„๋Š” ๊ด€๋žŒ๊ฐ์ด ํƒœ๋ธ”๋ฆฟ ์ฑ„ํŒ…์— ๋‹ตํ•˜๋ฉด ๊ทธ ๋‹ต(ai/response.transcript)์„ ๋ฏธ๋ž˜์ฐจ๊ฐ€ ๊ตฌ๋…ํ•ด ์žฌ๋ฃŒ๋กœ ์ผ๋‹ค. ์ง€๊ธˆ์€ ์ฐจ ๋งˆ์ดํฌ๋กœ๋งŒ ๋ฐ›๋Š”๋‹ค. ์ด์œ ๋Š” ๋‘˜์ด๋‹ค.

  • ํƒœ๋ธ”๋ฆฟ์— ๋‹ตํ•˜๋ฉด OC ์˜ AI ๋™๋ฐ˜์ž๊ฐ€ ๋”ฐ๋กœ ๋‹ต์„ ํ•œ๋‹ค(์ฐจ ์•ˆ ์—ฐ์ถœ๊ณผ ํƒœ๋ธ”๋ฆฟ ์ฑ„ํŒ…์ด "๋”ฐ๋กœ ๋…ธ๋Š”" ๋ฌธ์ œ). OC ๊ฐ€ ai/mode=car ๋ฅผ ๊ตฌํ˜„ํ•ด ์Œ์„ฑ ๋ฐœํ™”์—๋Š” ๋‹ต์„ ์ƒ๋žตํ•˜์ง€๋งŒ, ํ…์ŠคํŠธ(์นฉ ํƒญยทํƒ€์ดํ•‘)์—๋Š” ์—ฌ์ „ํžˆ ๋‹ตํ•œ๋‹ค(ai_chat.go car ๋ถ„๊ธฐ๊ฐ€ type=voice ์•ˆ์—๋งŒ ์žˆ์Œ).
  • ๋ฏธ๋ž˜์ฐจ ์„œ๋ฒ„๋Š” ์•„์ง ai/response.transcript ๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  ์žˆ์–ด์„œ, ํƒœ๋ธ”๋ฆฟ์—์„œ ๋ณด๋‚ธ ๋ฌธ์žฅ๋„ ์Šคํ… ์žฌ๋ฃŒ๋กœ ์„ž์—ฌ ๋“ค์–ด๊ฐ„๋‹ค.

๊ทธ๋ž˜์„œ ์ฐจ ์•ˆ์— ์žˆ๋Š” ๋™์•ˆ(enter~exit) ํƒœ๋ธ”๋ฆฟ์€ ์ฑ„ํŒ… ์ž…๋ ฅ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค. ๋ฏธ๋ž˜์ฐจ๊ฐ€ ๋„์šฐ๋Š” ์งˆ๋ฌธยท์นฉ์€ ๋ณด์—ฌ์ฃผ๊ธฐ๋งŒ ํ•œ๋‹ค. ๊ด€๋žŒ๊ฐ์ด "๋ฌด์Šจ ๋ง์„ ํ•˜๋ฉด ๋˜๋Š”์ง€" ํžŒํŠธ๋กœ ์“ฐ๋ผ๋Š” ๋œป์ด๋‹ค.

ํƒœ์Šคํฌ ๊ทœ์น™ (์•Œ์•„๋งŒ ๋‘๋ฉด ๋˜๋Š” ๊ฒƒ)

  • ์ฐจ ์žฅ์†Œ ํƒœ์Šคํฌ ์ค‘ type=basic ๋งŒ ๋ฏธ๋ž˜์ฐจ๊ฐ€ ์ˆ˜ํ–‰ํ•œ๋‹ค โ€” ํƒœ๋ธ”๋ฆฟ์— ์กฐ์ž‘ UI ๊ฐ€ ์—†์–ด ์„œ๋ฒ„๊ฐ€ ์™„๋ฃŒํ•ด ์ค˜์•ผ ํ•˜๋Š” ํƒ€์ž…. ์Šคํ…๋งˆ๋‹ค ํ•˜๋‚˜์”ฉ AI ๊ฐ€ ๊ณจ๋ผ ์Šคํ… ์‹œ์ž‘์— task/start, ๋ Œ๋” ์™„๋ฃŒ์— task/complete ๋ฅผ OC ์— ๋ณด๋‚ธ๋‹ค.
  • ๊ทธ ์™ธ ํƒ€์ž…(vehicle_readyยทdetailedยทquote_briefing โ€ฆ ๋‹๋ณด๊ธฐ ๋ชจ๋‹ฌ)์€ ๋ฏธ๋ž˜์ฐจ๊ฐ€ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค. ์ง€๊ธˆ์ฒ˜๋Ÿผ ๊ด€๋žŒ๊ฐ์ด ํƒœ๋ธ”๋ฆฟ ๋ชจ๋‹ฌ์—์„œ ์™„๋ฃŒํ•œ๋‹ค.

1. ํ˜„์žฌ ๊ตฌํ˜„ ์ƒํƒœ (60d353c ๋Œ€์กฐ)

๋ฏธ๋ž˜์ฐจ ํŒ€์ด tablet-fe ์ฝ”๋“œ๋ฅผ ์ฝ๊ณ  ํ™•์ธํ•œ ๊ฒƒ. ์•„๋ž˜ ํ•ญ๋ชฉ์€ ์ถ”๊ฐ€ ์ž‘์—…์ด ์—†๋‹ค.

ํ•ญ๋ชฉ ์œ„์น˜ ์ƒํƒœ
future-car/response ๊ตฌ๋… ยท SSE ์ค‘๊ณ„ ยท state replay ์บ์‹œ server-bus.ts SESSION_SUFFIX.futureCar, handleFutureCarResponse(1014), bus.futureCarState(280) โœ…
zod ์Šคํ‚ค๋งˆ 4์ข… (stateยทrouteยทerrorยทstep strip) schema.ts 995~1053 โœ…
future-car-store (phaseยทstepยทcanExitยทrouteยทsegmentsยทlastError) store/future-car-store.ts โœ…
enter/exit ๋ฐœํ–‰ โ€” BFF ๋ผ์šฐํŠธ ยท ์–ด๋Œ‘ํ„ฐ ยท ๊ฐ€๋“œ app/api/orchestration/future-car/route.ts, future-car-client.ts, task-complete-dialog.tsx 101~135 โœ…
๋…ธ์„ ๋„(์ง€๋‚˜์˜จ ๊ตฌ๊ฐ„ ๋ˆ„์ ) components/main/cctv/vehicle-route-view.tsx โœ…
๋ฏธ๋ž˜์ฐจ ์งˆ๋ฌธยท์นฉ ํ‘œ์‹œ chat-store.receiveAiResponse(๋ชจ๋ฅด๋Š” context_id โ†’ AI ๋ฒ„๋ธ”) ยท receiveSuggestions โœ… ๊ธฐ์กด ๋กœ์ง ๊ทธ๋Œ€๋กœ
signout ์‹œ storeยทBFF ์บ์‹œ ์ดˆ๊ธฐํ™” end-session.ts 80, server-bus.ts 357 โœ…
๋ฏธ๋ž˜์ฐจ ๋ชจ๋“œ ์ž…๋ ฅ ์ž ๊ธˆ chat-input.tsx, chat-thread.tsx, use-ai-chat.ts โฌœ ์—†์Œ โ†’ ยง2-A
ํ•˜์ฐจ ์œ ๋„ UI (useFutureCarCanExit) future-car-store.ts 120 โ€” ์ •์˜๋งŒ ์žˆ๊ณ  ๋ฏธ์‚ฌ์šฉ โฌœ ๊ถŒ์žฅ โ†’ ยง2-B

2. ์ถ”๊ฐ€ ๊ตฌํ˜„

A. (ํ•„์ˆ˜) ๋ฏธ๋ž˜์ฐจ ๋ชจ๋“œ ์ž…๋ ฅ ์ž ๊ธˆ

๋ฌด์—‡์„

future-car-store.phase ๊ฐ€ waiting ยท driving ยท arrived ์ค‘ ํ•˜๋‚˜์ธ ๋™์•ˆ(= enter ์ดํ›„ exit ์ด์ „):

์ž ๊ธ€ ๊ฒƒ ์ง€๊ธˆ ์ฝ”๋“œ ์ž ๊ทผ ๋’ค
ํ…์ŠคํŠธ ์ž…๋ ฅ์ฐฝ chat-input.tsx:43 disabled = pending || sessionUuid === null ์กฐ๊ฑด์— inCar ์ถ”๊ฐ€ โ†’ Input disabled
๋งˆ์ดํฌ(press-and-hold) ๊ฐ™์€ disabled ๊ฐ€ usePushToTalk ๋กœ ์ „๋‹ฌ๋จ ์ž๋™์œผ๋กœ ํ•จ๊ป˜ ์ž ๊น€
์ „์†ก ๋ฒ„ํŠผ canSend โ† disabled ์ž๋™
์ œ์•ˆ ์นฉ ํƒญ chat-thread.tsx:76 onPickSuggestion โ†’ sendText ์นฉ์€ ํ‘œ์‹œํ•˜๋˜ disabled(ํƒญ ๋ฌด์‹œ)
ํ”„๋กœ๊ทธ๋žจ์  ์ „์†ก use-ai-chat.ts dispatch (sendTextยทsendSystemText ๊ณต์šฉ) inCar ๋ฉด return false โ€” ์–ด๋–ค ๊ฒฝ๋กœ๋กœ๋„ ai/request ๊ฐ€ ๋‚˜๊ฐ€์ง€ ์•Š๊ฒŒ ํ•˜๋Š” ์ตœ์ข… ๋ฐฉ์–ด์„ 

ํ‘œ์‹œ: ์ž…๋ ฅ์ฐฝ placeholder ๋ฅผ "์ฐจ๋Ÿ‰ ์•ˆ์—์„œ๋Š” ์ฐจ์— ์ง์ ‘ ๋ง์”€ํ•ด ์ฃผ์„ธ์š”" ๋กœ. ์นฉ์€ ํšŒ์ƒ‰์œผ๋กœ ๋ณด์ด๋˜ ๋ˆŒ๋ฆฌ์ง€ ์•Š๊ฒŒ(๊ด€๋žŒ๊ฐ์ด "์ด๋ ‡๊ฒŒ ๋‹ตํ•˜๋ฉด ๋˜๋Š”๊ตฌ๋‚˜" ํžŒํŠธ๋กœ ์ฝ๋Š”๋‹ค).

ํ•ด์ œ: phase ๊ฐ€ done(exit ๋’ค) ๋˜๋Š” idle(์ƒˆ plan) ๋˜๋Š” null(state ๋ฏธ์ˆ˜์‹ ) ์ด๋ฉด ์ž ๊ทธ์ง€ ์•Š๋Š”๋‹ค.

์™œ phase ๋กœ ํŒ๋‹จํ•˜๋‚˜ (์žฅ์†Œ ์ด๋ฆ„์ด ์•„๋‹ˆ๋ผ)

  • ์ž ๊ธˆ์˜ ๊ทผ๊ฑฐ๋Š” "๋ฏธ๋ž˜์ฐจ ์„œ๋ฒ„๊ฐ€ ๋ฐœํ™” ์ˆ˜์ง‘ ์ฐฝ์„ ์—ด์–ด ๋‘๊ณ  ์žˆ๋Š”๊ฐ€"์ด๊ณ , ๊ทธ๊ฑด ์ •ํ™•ํžˆ state.phase โˆˆ {waiting, driving, arrived} ๋‹ค.
  • state ๋Š” retained ๋ผ ์ƒˆ๋กœ๊ณ ์นจยทSSE ์žฌ์—ฐ๊ฒฐ ๋’ค์—๋„ ๋งˆ์ง€๋ง‰ ๊ฐ’์ด ์ฆ‰์‹œ ๋ณต์›๋œ๋‹ค(BFF futureCarState ์บ์‹œ + ๋ธŒ๋กœ์ปค retained ์ด์ค‘). ์žฅ์†Œ(activePhase.zone)๋กœ ํŒ๋‹จํ•˜๋ฉด ํƒœ๋ธ”๋ฆฟ ๋‹จ๊ณ„์™€ ์ฐจ ์ƒํƒœ๊ฐ€ ์–ด๊ธ‹๋‚˜๋Š” ์ˆœ๊ฐ„(์ด๋™ ํ™•์ • ์งํ›„ ๋“ฑ)์— ๊ตฌ๋ฉ์ด ์ƒ๊ธด๋‹ค.
  • null(์•„์ง state ๋ฅผ ๋ชป ๋ฐ›์Œ)์€ ์ž ๊ทธ์ง€ ์•Š๋Š”๋‹ค โ€” ๋ฏธ๋ž˜์ฐจ ์„œ๋ฒ„๊ฐ€ ์ฃฝ์–ด ์žˆ์–ด๋„ ํƒœ๋ธ”๋ฆฟ ์ฑ„ํŒ…์€ ์‚ด์•„ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

๊ตฌํ˜„ ์œ„์น˜ ์ œ์•ˆ

// use-ai-chat.ts โ€” dispatch ๋งจ ์•ž
const carPhase = useFutureCarStore.getState().phase
if (carPhase === 'waiting' || carPhase === 'driving' || carPhase === 'arrived') return false

// chat-input.tsx
const carPhase = useFutureCarPhase()
const inCar = carPhase === 'waiting' || carPhase === 'driving' || carPhase === 'arrived'
const disabled = pending || sessionUuid === null || inCar
// placeholder: inCar ? '์ฐจ๋Ÿ‰ ์•ˆ์—์„œ๋Š” ์ฐจ์— ์ง์ ‘ ๋ง์”€ํ•ด ์ฃผ์„ธ์š”' : โ€ฆ

// chat-thread.tsx โ€” ์นฉ ๋ฒ„ํŠผ์— disabled={inCar}, onPickSuggestion ์€ inCar ๋ฉด no-op

inCar ํŒ์ •์„ store ์…€๋ ‰ํ„ฐ(useFutureCarInCar())๋กœ ํ•˜๋‚˜ ๋‘๊ณ  ์„ธ ๊ณณ์ด ๊ฐ™์ด ์“ฐ๋ฉด ์กฐ๊ฑด์ด ํฉ์–ด์ง€์ง€ ์•Š๋Š”๋‹ค.

์—ฃ์ง€ ์ผ€์ด์Šค

์ƒํ™ฉ ๊ธฐ๋Œ€ ๋™์ž‘
enter ๋ฐœํ–‰ ์งํ›„ state waiting ์ด ์˜ค๊ธฐ ์ „ 0.1~1์ดˆ ์•„์ง ์•ˆ ์ž ๊น€. ์ด ํ‹ˆ์— ๋ณด๋‚ธ ๋ฌธ์žฅ์€ ๋ฏธ๋ž˜์ฐจ ์ฐฝ์ด ์ด๋ฏธ ์—ด๋ ค ์žˆ์–ด ์žฌ๋ฃŒ๋กœ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋‹ค โ€” ํ—ˆ์šฉ ๋ฒ”์œ„(๊ด€๋žŒ๊ฐ์ด ๊ทธ ์ˆœ๊ฐ„ ํƒ€์ดํ•‘ํ•  ๊ฐ€๋Šฅ์„ฑ ๋‚ฎ์Œ). ์›ํ•˜๋ฉด enter ๋ฐœํ–‰ ์‹œ์ ์— ๋‚™๊ด€์ ์œผ๋กœ ์ž ๊ฐ€๋„ ๋œ๋‹ค
pending ์ƒํƒœ(ํƒœ๋ธ”๋ฆฟ์ด ๋‹ต์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ค‘)์—์„œ enter pending ์ด ๋จผ์ € ์ž ๊ทธ๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์ถฉ๋Œ ์—†์Œ. car ๋ชจ๋“œ์—์„œ OC ๊ฐ€ message ์—†์ด transcript ๋งŒ ๋Œ๋ ค์ค˜๋„ receiveAiResponse ๊ฐ€ pending ์„ ํ‘ผ๋‹ค(๋นˆ ๋ฒ„๋ธ” ์•ˆ ์ƒ๊น€)
exit ๋ฐœํ–‰ โ†’ state done ์ฆ‰์‹œ ํ•ด์ œ. done ๋’ค OC ai/mode=chat ๋„ ํ•จ๊ป˜ ๊ฐ€๋ฏ€๋กœ OC AI ๋‹ต๋ณ€์ด ์ •์ƒ ๋ณต๊ท€
์ƒˆ๋กœ๊ณ ์นจ retained state ๋กœ phase ๋ณต์› โ†’ ์ž ๊ธˆ ๋ณต์›
๋ฏธ๋ž˜์ฐจ ์„œ๋ฒ„ ์žฌ์‹œ์ž‘ state ๋Š” DB ๋ณต์› ํ›„ ์žฌ๋ฐœํ–‰๋œ๋‹ค. ๊ทธ ์‚ฌ์ด์—” ๋งˆ์ง€๋ง‰ retained ๊ฐ’์ด ์œ ์ง€
signout useFutureCarStore.reset() โ†’ phase null โ†’ ํ•ด์ œ

B. (๊ถŒ์žฅ) ํ•˜์ฐจ ์œ ๋„

state ยท phase=arrived ยท next="exit" (์Šคํ… 4 ๋ Œ๋” ์™„๋ฃŒ) ๊ฐ€ ์˜ค๋ฉด canExit === true ๊ฐ€ ๋œ๋‹ค. ์ง€๊ธˆ์€ ์ด ๊ฐ’์„ ์•„๋ฌด UI ๋„ ์ฝ์ง€ ์•Š์•„ ๊ด€๋žŒ๊ฐ์ด ์Šค์Šค๋กœ "๋‹ค์Œ ์žฅ์†Œ๋กœ ์ด๋™"์„ ๋ˆŒ๋Ÿฌ์•ผ ํ•œ๋‹ค. ์ฐจ ํ™”๋ฉด์€ ์ด๋•Œ "์ฒดํ—˜์ด ๋ชจ๋‘ ๋๋‚ฌ์Šต๋‹ˆ๋‹ค / ๋’ท์ชฝ ์ถœ๊ตฌ๋กœ ํ‡ด์žฅํ•ด ์ฃผ์„ธ์š”" ๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ์œผ๋ฏ€๋กœ, ํƒœ๋ธ”๋ฆฟ์—๋„ ๊ฐ™์€ ๋งฅ๋ฝ์˜ ์•ˆ๋‚ด("์ฐจ์—์„œ ๋‚ด๋ ค ๋‹ค์Œ ์žฅ์†Œ๋กœ ์ด๋™ํ•ด ์ฃผ์„ธ์š”" + ์ด๋™ ํ™•์ •์œผ๋กœ ์—ฐ๊ฒฐ)๋ฅผ ๋„์šฐ๋ฉด ๊ด€๋žŒ๊ฐ์ด ํ—ค๋งค์ง€ ์•Š๋Š”๋‹ค. useFutureCarCanExit() ๊ฐ€ ์ด๋ฏธ ์žˆ๋‹ค. ์–ด๋””์— ๋„์šธ์ง€๋Š” ํƒœ๋ธ”๋ฆฟ UX ๊ฒฐ์ •์ด๋‹ค(๋…ธ์„ ๋„ ์บก์…˜, ํƒœ์Šคํฌ ํŒจ๋„ ์ƒ๋‹จ ๋ฐฐ๋„ˆ ๋“ฑ).

C. (ํ™•์ธ) ์ฐจ๋Ÿ‰ ํƒœ์Šคํฌ ์นด๋“œ

๋ฏธ๋ž˜์ฐจ ์„œ๋ฒ„๊ฐ€ ์Šคํ…๋งˆ๋‹ค task/start(์Šคํ… ์‹œ์ž‘) โ†’ task/complete(๋ Œ๋” ์™„๋ฃŒ) ๋ฅผ OC ์— ๋ณด๋‚ด๋ฉด OC ๊ฐ€ dashboard ๋ฅผ in_progress โ†’ completed ๋กœ ์žฌ๋ฐœํ–‰ํ•œ๋‹ค. ํƒœ๋ธ”๋ฆฟ์˜ basic ์นด๋“œ(task-panel.tsx STATUS_STYLE)๋Š” ์ด๋ฏธ active(์ง„ํ–‰ ์ค‘) ๋ฐฐ์ง€๋ฅผ ๊ทธ๋ฆฌ๋ฏ€๋กœ ์ฝ”๋“œ ๋ณ€๊ฒฝ ์—†์ด ์Šคํ… ๋™์•ˆ "์ง„ํ–‰ ์ค‘" โ†’ ๋๋‚˜๋ฉด "์™„๋ฃŒ" ๋กœ ๋ณด์—ฌ์•ผ ํ•œ๋‹ค. ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ๋ณด์ด๋Š”์ง€๋งŒ ํ™•์ธํ•ด ๋‹ฌ๋ผ. non-basic ์นด๋“œ(๋‹๋ณด๊ธฐ)๋Š” ๋ฐฐ์ง€๊ฐ€ ์—†๊ณ  ๋ฏธ๋ž˜์ฐจ๊ฐ€ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ณ€ํ™” ์—†์Œ.

D. (์ฃผ์˜) ์ฐจ ์•ˆ์—์„œ ํ”„๋กœ๊ทธ๋žจ์ด ๋ณด๋‚ด๋Š” ai/request

use-task-summary.ts ๋Š” dashboard ์ฒซ ์ˆ˜์‹  ๋•Œ ํ•˜๋ฃจ ์š”์•ฝ์„ ai/request type=text ๋กœ ๋ณด๋‚ธ๋‹ค. ์ด๊ฑด ์„ธ์…˜ ์ดˆ์ž…(= enter ์ „)์ด๋ผ ๋ฏธ๋ž˜์ฐจ๊ฐ€ ์ฐฝ ๋ฐ–(closed)์œผ๋กœ ๋ฒ„๋ฆฌ๋ฏ€๋กœ ๋ฌธ์ œ์—†๋‹ค. ์•ž์œผ๋กœ ์ฐจ ์•ˆ(waiting~arrived)์—์„œ ์ž๋™์œผ๋กœ ai/request ๋ฅผ ๋ณด๋‚ด๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜์ง€ ๋ง ๊ฒƒ โ€” ๋ฏธ๋ž˜์ฐจ๊ฐ€ ๊ด€๋žŒ๊ฐ ๋ฐœํ™”๋กœ ์˜ค์ธํ•ด ์Šคํ…์„ ์ƒ์„ฑํ•œ๋‹ค. ยง2-A ์˜ dispatch ๊ฐ€๋“œ๊ฐ€ ์ด๊ฑธ ๋ง‰๋Š” ์ตœ์ข… ๋ฐฉ์–ด์„ ์ด๋‹ค.


3. ๋ฏธ๋ž˜์ฐจ โ†’ ํƒœ๋ธ”๋ฆฟ: ์–ธ์ œ ๋ฌด์—‡์ด ์˜ค๊ณ  ๋ฌด์—‡์„ ๋ณด์—ฌ์ฃผ๋‚˜

ํ† ํ”ฝ orchestration/{sessionId}/future-car/response (QoS 1). ํ•„๋“œ ์ •์˜๋Š” ์ •๋ณธ ยง5. ์—ฌ๊ธฐ์„œ๋Š” ์‹œ๊ฐ„ ์ˆœ์œผ๋กœ ๋ฌด์—‡์ด ์˜ค๋Š”์ง€๋ฅผ ์ ๋Š”๋‹ค.

์‹œ์  ๊ด€๋žŒ๊ฐ ยท ์ฐจ ํ™”๋ฉด ๋„์ฐฉํ•˜๋Š” ๋ฉ”์‹œ์ง€ ํƒœ๋ธ”๋ฆฟ
ํŽ˜๋ฅด์†Œ๋‚˜ ์ƒ์„ฑ ์งํ›„ ์ฐจ์™€ ๋ฌด๊ด€ state {step:0, phase:"idle", prev_place?, next_place?} (retained) ์ƒˆ ์—ฌ์ •. ๊ตฌ๊ฐ„ยท์—๋Ÿฌ ๋น„์šฐ๊ธฐ(๊ตฌํ˜„๋จ). ์ž ๊ธˆ ์•„๋‹˜
ํƒœ๋ธ”๋ฆฟ์ด enter ๋ฐœํ–‰ ์ฐจ ํ™”๋ฉด ๋Œ€๊ธฐ. ๋งˆ์ดํฌ ์—ด๋ฆผ state {phase:"waiting"} โ†’ ์ด์–ด์„œ ์ฑ„ํŒ… ํ† ํ”ฝ์— ai/response {message:"์ถœ๋ฐœ ํ• ๊นŒ์š”?"} + ai/suggestions ["๋„ค, ์ถœ๋ฐœํ•ด์š”!","์ž ๊น๋งŒ์š”, ์ค€๋น„ ์ข€ ํ• ๊ฒŒ์š”"] ์ž ๊ธˆ ์‹œ์ž‘. ์ฑ„ํŒ…์— ์งˆ๋ฌธยท์นฉ ํ‘œ์‹œ(์นฉ ๋น„ํ™œ์„ฑ)
๊ด€๋žŒ๊ฐ์ด ์ฐจ์— ๋งํ•จ โ†’ ์ƒ์„ฑ ์ค‘ ๋Œ€๊ธฐ ํ™”๋ฉด ์œ ์ง€. "์ž ์‹œ๋งŒ์š”" (์—†์Œ, 10~30์ดˆ) ๋ณ€ํ™” ์—†์Œ
์ƒ์„ฑ ์™„๋ฃŒ ์Šคํ… ์žฌ์ƒ ์‹œ์ž‘. ๋งˆ์ดํฌ ๋‹ซํž˜ route {step:1, from_stop_id?, from_place?, to_stop_id?, to_place?} โ†’ step {step:1, phase:"driving", data:{โ€ฆ}} ๋…ธ์„ ๋„ ๊ตฌ๊ฐ„ ํ‘œ์‹œ. step.data ๋Š” ๋ฌด์‹œ(์Šคํ‚ค๋งˆ๊ฐ€ strip). basic ์นด๋“œ "์ง„ํ–‰ ์ค‘"(OC dashboard ๊ฒฝ์œ )
์žฌ์ƒ ์™„๋ฃŒ ๋งˆ์ง€๋ง‰ ์žฅ๋ฉด ์œ ์ง€. ๋งˆ์ดํฌ ์—ด๋ฆผ state {step:1, phase:"arrived"} (next ์—†์Œ) โ†’ ์ฑ„ํŒ…์— ai/response {message:<์งˆ๋ฌธ>} + ai/suggestions ์นด๋“œ "์™„๋ฃŒ". ์ฑ„ํŒ…์— ๋‹ค์Œ ์งˆ๋ฌธยท์นฉ(๋น„ํ™œ์„ฑ)
์Šคํ… 2ยท3 ์œ„ ๋ฐ˜๋ณต
์Šคํ… 4 ์žฌ์ƒ ์™„๋ฃŒ ์—”๋”ฉ ํ™”๋ฉด. ๋งˆ์ดํฌ ์•ˆ ์—ด๋ฆผ state {step:4, phase:"arrived", next:"exit"} โ€” ์งˆ๋ฌธ ์—†์Œ canExit=true โ†’ ํ•˜์ฐจ ์œ ๋„(ยง2-B)
ํƒœ๋ธ”๋ฆฟ์ด exit ๋ฐœํ–‰ ์ž‘๋ณ„ ํ™”๋ฉด state {phase:"done"} ์ž ๊ธˆ ํ•ด์ œ. ๋…ธ์„ ๋„ ์ข…๋ฃŒ ์ƒํƒœ
๋‹ค์Œ ๊ด€๋žŒ๊ฐ state {phase:"idle"} ์ดˆ๊ธฐํ™”
์ƒ์„ฑ ์‹คํŒจ ๋“ฑ ์ฐจ ํ™”๋ฉด์ด ๋งˆ์ดํฌ๋ฅผ ๋‹ค์‹œ ์—ฐ๋‹ค error {step?, code, message} JOURNEY_ENDED ๋Š” ํ‘œ์‹œ ์•ˆ ํ•จ(์ •์ƒ ์ข…๋ฃŒ). ๊ทธ ์™ธ๋Š” ์•ˆ๋‚ด

์•Œ์•„๋‘˜ ๊ฒƒ:

  • ์ƒ์„ฑ ์ค‘์—๋Š” ์•„๋ฌด ๋ฉ”์‹œ์ง€๋„ ์•ˆ ์˜จ๋‹ค. route ๊ฐ€ ์˜ฌ ๋•Œ๊นŒ์ง€ "์ด๋™ ์ค€๋น„ ์ค‘" ์ •๋„๋กœ ๋‘๋ฉด ๋œ๋‹ค. ์ง„ํ–‰ ํ‘œ์‹œ๋ฅผ ํƒœ๋ธ”๋ฆฟ์ด ๋งŒ๋“ค ํ•„์š” ์—†๋‹ค.
  • state ๋งŒ retained. routeยทstepยทerror ๋Š” ๋†“์น˜๋ฉด ๋‹ค์‹œ ์•ˆ ์˜จ๋‹ค โ€” ๊ทธ๋ž˜์„œ segments ๋ฅผ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ˆ„์ ํ•œ๋‹ค(๊ตฌํ˜„๋จ).
  • next ๋Š” ์Šคํ… 4 arrived ์—๋งŒ ์‹ค๋ฆฐ๋‹ค. ํ‚ค ์กด์žฌ ์—ฌ๋ถ€๋กœ ํŒ๋‹จ(๊ตฌํ˜„๋จ: message.next === 'exit').
  • error.code: STEP_NOT_READY(์ƒ์„ฑ ์ค‘ ์ง„ํ–‰ ์š”์ฒญ) ยท GENERATION_FAILED(LLM ์‹คํŒจ โ€” ๊ด€๋žŒ๊ฐ์ด ๋‹ค์‹œ ๋งํ•˜๋ฉด ์žฌ์‹œ๋„) ยท PLAN_MISSING(plan ์—†์Œ) ยท JOURNEY_ENDED(exit ๋’ค/์Šคํ… ์ดˆ๊ณผ, ์ •์ƒ).

4. ํƒœ๋ธ”๋ฆฟ โ†’ ๋ฏธ๋ž˜์ฐจ: enter ยท exit

ํ† ํ”ฝ orchestration/{sessionId}/future-car/request (QoS 1, retain=false). ํŽ˜์ด๋กœ๋“œ {"type":"enter"} / {"type":"exit"}. ๊ตฌํ˜„๋ผ ์žˆ๋‹ค.

๋ฐœํ–‰ ์‹œ์  (๊ตฌํ˜„๋จ) ๊ฐ€๋“œ (๊ตฌํ˜„๋จ) ๋ฏธ๋ž˜์ฐจ์—์„œ ์ผ์–ด๋‚˜๋Š” ์ผ
๋‹ค์Œ ๋ชฉ์ ์ง€๊ฐ€ ์ฐจ๋Ÿ‰์ด๊ณ  ์ด๋™์„ ํ™•์ •ํ•  ๋•Œ phase โˆˆ {null, idle} ์ผ ๋•Œ๋งŒ ๋ฐœํ™” ์ฐฝ ์—ด๋ฆผ ยท state waiting ยท ai/mode car ยท ์ฑ„ํŒ…์— "์ถœ๋ฐœ ํ• ๊นŒ์š”?" ยท ์ฐจ ํ™”๋ฉด ๋Œ€๊ธฐ + ๋งˆ์ดํฌ
์ง€๊ธˆ ์žฅ์†Œ๊ฐ€ ์ฐจ๋Ÿ‰์ด๊ณ  ๋‹ค์Œ ์žฅ์†Œ๋กœ ์ด๋™์„ ํ™•์ •ํ•  ๋•Œ phase โˆˆ {null, waiting, driving, arrived} ๋ฐœํ™” ์ฐฝ ๋‹ซํž˜ ยท state done ยท ai/mode chat ยท ์ฐจ ํ™”๋ฉด ์ž‘๋ณ„

โš ๏ธ exit ๋Š” ์–ธ์ œ ๋ณด๋‚ด๋„ ์—ฌ์ •์„ ๊ทธ ์ž๋ฆฌ์—์„œ ๋๋‚ธ๋‹ค. ์Šคํ… 2 ์žฌ์ƒ ์ค‘์— ๊ด€๋žŒ๊ฐ์ด ํƒœ๋ธ”๋ฆฟ์—์„œ "์ด๋™ ํ™•์ •"์„ ๋ˆŒ๋Ÿฌ ๋ฒ„๋ฆฌ๋ฉด ์ฐจ ํ™”๋ฉด์€ ์ฆ‰์‹œ ์ž‘๋ณ„ ํ™”๋ฉด์œผ๋กœ ๊ฐ€๊ณ  ๋‚จ์€ ์Šคํ…์€ ๋ฒ„๋ ค์ง„๋‹ค. ํ˜„์žฌ ๊ฐ€๋“œ๋Š” ์ด๋ฅผ ๋ง‰์ง€ ์•Š๋Š”๋‹ค(๊ณ„์•ฝ์ƒ ์œ ํšจ). ์šด์˜์—์„œ "์Šคํ… 4 ๋๋‚˜๊ธฐ ์ „์—” ์ด๋™ ํ™•์ •์„ ๋ˆ„๋ฅด์ง€ ์•Š๊ฒŒ" ์•ˆ๋‚ดํ•˜๊ฑฐ๋‚˜, ยง2-B ์ฒ˜๋Ÿผ canExit ๊ฐ€ ์ฐธ์ผ ๋•Œ๋งŒ ์ฐจ๋Ÿ‰ ๋‹จ๊ณ„์˜ ์ด๋™ ํ™•์ •์„ ์—ด์–ด ๋‘๋Š” ๊ฒƒ์„ ๊ถŒํ•œ๋‹ค โ€” ํ›„์ž๋Š” ํƒœ๋ธ”๋ฆฟ UX ๊ฒฐ์ •์ด๋ผ ์š”์ฒญ์ด ์•„๋‹ˆ๋ผ ์ œ์•ˆ์ด๋‹ค.

advanceยทstart ๋Š” ๋ณด๋‚ด์ง€ ์•Š๋Š”๋‹ค(ํ๊ธฐ. ๋ณด๋‚ด๋ฉด ๋ฐœํ™” ์—†์ด ๊ฐ•์ œ ์ง„ํ–‰๋ผ deprecated ๋กœ ๊ธฐ๋ก๋œ๋‹ค).


5. ์ฑ„ํŒ… ํ† ํ”ฝ์—์„œ ์ผ์–ด๋‚˜๋Š” ์ผ

ํƒœ๋ธ”๋ฆฟ์ด ์ด๋ฏธ ๊ตฌ๋…ํ•˜๋Š” ai/responseยทai/suggestions ์— ๋ฏธ๋ž˜์ฐจ๊ฐ€ ์ง์ ‘ ๋ฐœํ–‰ํ•œ๋‹ค. OC ๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๋Š”๋‹ค.

ํ† ํ”ฝ ๋ฏธ๋ž˜์ฐจ ๋ฐœํ–‰ ๋‚ด์šฉ ํƒœ๋ธ”๋ฆฟ ๋™์ž‘ (๊ธฐ์กด ๋กœ์ง)
orchestration/{sid}/ai/response {"ok":true, "context_id":"<๋ฏธ๋ž˜์ฐจ UUID>", "message":"์ถœ๋ฐœ ํ• ๊นŒ์š”?"} context_id ๊ฐ€ ํƒœ๋ธ”๋ฆฟ ๊ฒƒ์ด ์•„๋‹ˆ๋ฏ€๋กœ isCurrent=false โ†’ AI ๋ฒ„๋ธ”๋กœ ํ‘œ์‹œ
orchestration/{sid}/ai/suggestions {"context_id":"<๊ฐ™์€ ๊ฐ’>", "suggestions":["๋„ค, ์ถœ๋ฐœํ•ด์š”!","์ž ๊น๋งŒ์š”, ์ค€๋น„ ์ข€ ํ• ๊ฒŒ์š”"]} (์ตœ๋Œ€ 3๊ฐœ) receiveSuggestions โ†’ ์นฉ ํ‘œ์‹œ. ยง2-A ๋’ค์—๋Š” ํƒญ ๋ถˆ๊ฐ€

๋ฐœํ–‰ ์‹œ์ : enter ์งํ›„ 1ํšŒ, ์Šคํ… 1~3 ๋ Œ๋” ์™„๋ฃŒ ์งํ›„ ๊ฐ 1ํšŒ. ์Šคํ… 4 ๋’ค์—๋Š” ์—†๋‹ค. retain=false.

OC ์ชฝ ๋™์ž‘(์ฐธ๊ณ ): enter ๋•Œ ๋ฏธ๋ž˜์ฐจ๊ฐ€ ai/mode {car} ๋ฅผ retained ๋กœ ์˜ฌ๋ฆฌ๋ฉด OC ๋Š” ๊ทธ ์„ธ์…˜์˜ ์Œ์„ฑ ai/request ์— LLM ๋‹ต๋ณ€ยท์ œ์•ˆ์„ ์ƒ๋žตํ•˜๊ณ  transcript ๋งŒ ๋Œ๋ ค์ค€๋‹ค(message ์—†์Œ โ†’ ํƒœ๋ธ”๋ฆฟ์—” ๋นˆ ๋ฒ„๋ธ” ์—†์ด pending ๋งŒ ํ’€๋ฆผ). exit ๋•Œ {chat} ์œผ๋กœ ๋ณต๊ท€. ์ด๊ฑด ์ž ๊ธˆ์ด ๋šซ๋ ธ์„ ๋•Œ์˜ 2์ฐจ ์•ˆ์ „์žฅ์น˜์ด๊ณ , 1์ฐจ๋Š” ยง2-A ๋‹ค.


6. ๊ฒ€์ฆ ์ ˆ์ฐจ

๋ฏธ๋ž˜์ฐจ ์„œ๋ฒ„ ๋„๊ตฌ(์ „์‹œ๋ง Tailscale ์•ˆ์—์„œ๋งŒ):

์ฃผ์†Œ ์šฉ๋„
http://creator-mac-studio.tail69930a.ts.net:8100/mqtt ์ฃผ๊ณ ๋ฐ›์€ MQTT ์›๋ฌธ ์‹œ๊ฐ„์ˆœ + ์ˆ˜๋™ ๋ฐœํ–‰(enter/exit/advance) + DB ์ด๋ ฅ ํ† ๊ธ€
POST โ€ฆ:8100/ambient/utterance {"session_id":"โ€ฆ","transcript":"๋„ค, ์ถœ๋ฐœํ•ด์š”","source":"debug"} ์ฐจ ๋งˆ์ดํฌ ์—†์ด ๊ด€๋žŒ๊ฐ ๋ฐœํ™” ํ‰๋‚ด โ†’ ์Šคํ… ์ƒ์„ฑ
GET โ€ฆ:8100/ambient/session/{session_id} ์„ธ์…˜ ์Šค๋ƒ…์ƒท(phaseยทstepยท์™„๋ฃŒ ํƒœ์Šคํฌยท์ˆ˜์ง‘ ๋ฐœํ™”)
GET โ€ฆ:8100/logs?session_id=โ€ฆ ์„œ๋ฒ„ ์ง„ํ–‰ ๋กœ๊ทธ(DB, ์žฌ์‹œ์ž‘ ๋’ค์—๋„ ๋‚จ์Œ)
โ€ฆ:8100/docs Swagger

6-1. ์ž ๊ธˆ ๊ฒ€์ฆ (์ฐจ ํ™”๋ฉด ์—†์ด)

  1. ํƒœ๋ธ”๋ฆฟ์—์„œ ํŽ˜๋ฅด์†Œ๋‚˜ ์ƒ์„ฑ โ†’ /mqtt ์—์„œ ๊ทธ ์„ธ์…˜์˜ state idle ํ™•์ธ. ํƒœ๋ธ”๋ฆฟ ์ฑ„ํŒ… ์ž…๋ ฅ ๊ฐ€๋Šฅ์ด์–ด์•ผ ํ•œ๋‹ค.
  2. ํƒœ๋ธ”๋ฆฟ์—์„œ ์ฐจ๋กœ ์ด๋™ ํ™•์ •(๋˜๋Š” /mqtt ์ˆ˜๋™ enter) โ†’ state waiting ์ˆ˜์‹  โ†’ ์ž…๋ ฅ์ฐฝยท๋งˆ์ดํฌยท์นฉ ์ž ๊น€, placeholder ์•ˆ๋‚ด ๋ฌธ๊ตฌ, ์ฑ„ํŒ…์— "์ถœ๋ฐœ ํ• ๊นŒ์š”?" + ์นฉ 2๊ฐœ(๋น„ํ™œ์„ฑ).
  3. POST /ambient/utterance ๋กœ "๋„ค, ์ถœ๋ฐœํ•ด์š”" โ†’ 10~30์ดˆ ๋’ค routeยทstep โ†’ ๋…ธ์„ ๋„ ๊ตฌ๊ฐ„ ํ‘œ์‹œ. ์—ฌ์ „ํžˆ ์ž ๊น€.
  4. /mqtt ์—์„œ ๊ทธ ์„ธ์…˜์˜ state arrived ๊ฐ€ ์˜ฌ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค(์ฐจ ํ™”๋ฉด์ด ์—†์œผ๋ฉด ๋ Œ๋” ์™„๋ฃŒ ๋ณด๊ณ ๊ฐ€ ์•ˆ ์˜ค๋ฏ€๋กœ POST โ€ฆ:8100/ambient/step-rendered {"session_id","step":1} ๋กœ ํ‰๋‚ด) โ†’ ์ฑ„ํŒ…์— ์Šคํ… 1 ์งˆ๋ฌธยท์นฉ. ์—ฌ์ „ํžˆ ์ž ๊น€. basic ์นด๋“œ๊ฐ€ "์ง„ํ–‰ ์ค‘"โ†’"์™„๋ฃŒ"(ยง2-C).
  5. 3~4 ๋ฅผ ์Šคํ… 4๊นŒ์ง€ โ†’ state arrived next=exit โ†’ ํ•˜์ฐจ ์œ ๋„(ยง2-B) ํ‘œ์‹œ.
  6. ์ด๋™ ํ™•์ •(๋˜๋Š” ์ˆ˜๋™ exit) โ†’ state done โ†’ ์ž ๊ธˆ ํ•ด์ œ, ์ฑ„ํŒ… ์ž…๋ ฅ ๊ฐ€๋Šฅ.
  7. ์ƒˆ๋กœ๊ณ ์นจํ•ด์„œ 2 ๋‹จ๊ณ„ ์ƒํƒœ๋ฅผ ๋‹ค์‹œ ์—ด์–ด ๋ดค์„ ๋•Œ ์ž ๊ธˆ์ด ๋ณต์›๋˜๋Š”์ง€(retained state).

6-2. ์‹ค์ฐจ ๊ฒ€์ฆ (์ฐจ ํ™”๋ฉด ์žˆ์Œ)

์ฐจ ํ™”๋ฉด /ambient ๊ฐ€ ์—ด๋ ค ์žˆ์œผ๋ฉด 3~4 ๋‹จ๊ณ„์˜ ๋ฐœํ™”ยท๋ Œ๋” ์™„๋ฃŒ๊ฐ€ ์ž๋™์œผ๋กœ ์ผ์–ด๋‚œ๋‹ค. ๊ด€๋žŒ๊ฐ์ด ์ฐจ์— ๋งํ–ˆ์„ ๋•Œ ํƒœ๋ธ”๋ฆฟ ์ฑ„ํŒ…์— ๊ทธ ๋ง์ด ์‚ฌ์šฉ์ž ๋ฒ„๋ธ”๋กœ ๋œจ์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ •์ƒ์ด๋‹ค(์ฐจ ๋งˆ์ดํฌ ๋ฐœํ™”๋Š” ํƒœ๋ธ”๋ฆฟ ์ฑ„ํŒ…๊ณผ ๋ฌด๊ด€ํ•œ HTTP ๊ฒฝ๋กœ).


7. ๋ฐฐํฌ ์ „ํ›„ ์ฐจ์ด

2026-08-29 ๋ฐฐํฌ ์™„๋ฃŒ๋กœ ์•„๋ž˜๋Š” ๊ธฐ๋ก์šฉ์ด๋‹ค.

๋ฏธ๋ž˜์ฐจ ์„œ๋ฒ„ 5cc571f ๊ฐ€ Mac Studio ์— ๋ฐฐํฌ๋˜๊ธฐ ์ „(10321ac)์—๋Š”:

  • task/start ๊ฐ€ ๋‚˜๊ฐ€์ง€ ์•Š๋Š”๋‹ค โ†’ ์นด๋“œ๊ฐ€ "๋Œ€๊ธฐ"์—์„œ ๋ฐ”๋กœ "์™„๋ฃŒ"๋กœ ๊ฐ„๋‹ค(ยง2-C ๋Š” ๋ฐฐํฌ ํ›„ ํ™•์ธ).
  • ๋ชจ๋‹ฌํ˜•(non-basic) ํƒœ์Šคํฌ๋„ ๋ฏธ๋ž˜์ฐจ๊ฐ€ task/complete ๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค โ†’ ๊ด€๋žŒ๊ฐ์ด ์—ด์–ด๋ณด์ง€ ์•Š์€ ๋‹๋ณด๊ธฐ ํƒœ์Šคํฌ๊ฐ€ ์™„๋ฃŒ๋กœ ๋ฐ”๋€” ์ˆ˜ ์žˆ๋‹ค(๋ฐฐํฌ ํ›„ ์‚ฌ๋ผ์ง).
  • ์ฐจ ๋งˆ์ดํฌ ๊ฒฝ๋กœ(/ambient/utterance ์ •์‹ ํŠธ๋ฆฌ๊ฑฐ)๊ฐ€ ์—†๋‹ค โ†’ ์‹ค์ฐจ ๊ฒ€์ฆ(ยง6-2)์€ ๋ฐฐํฌ ํ›„. ยง6-1 ์€ ์ง€๊ธˆ๋„ ๊ฐ€๋Šฅ.

ยง2-A ์ž ๊ธˆ์€ ๋ฐฐํฌ ์ „ํ›„์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ง€๊ธˆ ๋„ฃ์–ด๋„ ๋œ๋‹ค โ€” state.phase ๋Š” ์ด๋ฏธ ๋‚˜๊ฐ€๊ณ  ์žˆ๋‹ค.


8. ์žฅ์• ยท์˜ˆ์™ธ ์ƒํ™ฉ

์ƒํ™ฉ ํƒœ๋ธ”๋ฆฟ์— ๋ณด์ด๋Š” ๊ฒƒ ํƒœ๋ธ”๋ฆฟ์ด ํ•  ์ผ
๋ฏธ๋ž˜์ฐจ ์„œ๋ฒ„๊ฐ€ ์ฃฝ์–ด ์žˆ์Œ enter ๋’ค state waiting ์ด ์•ˆ ์˜ด ์ž ๊ธˆ ์•ˆ ๊ฑธ๋ฆผ(phase null/idle). ์ฑ„ํŒ…์€ OC ์™€ ํ‰์†Œ์ฒ˜๋Ÿผ. ๊ด€๋žŒ๊ฐ์€ ์ฐจ ์ฒดํ—˜ ์—†์ด ๋‹ค์Œ ์žฅ์†Œ๋กœ โ€” exit ๋Š” phase null ์—์„œ๋„ ๋ฐœํ–‰๋˜๋ฏ€๋กœ ๋ฌธ์ œ์—†์Œ
์Šคํ… ์ƒ์„ฑ ์‹คํŒจ error {code:"GENERATION_FAILED"} ์•ˆ๋‚ด๋งŒ. ์ฐจ ํ™”๋ฉด์ด ๋งˆ์ดํฌ๋ฅผ ๋‹ค์‹œ ์—ด๊ณ  ๊ด€๋žŒ๊ฐ์ด ๋‹ค์‹œ ๋งํ•˜๋ฉด ์žฌ์‹œ๋„๋œ๋‹ค. ํƒœ๋ธ”๋ฆฟ์€ ์•„๋ฌด๊ฒƒ๋„ ๋ณด๋‚ด์ง€ ์•Š๋Š”๋‹ค
๊ด€๋žŒ๊ฐ์ด ์ฐจ์— ๋งํ•˜์ง€ ์•Š์Œ arrived ์—์„œ ๋ฉˆ์ถค ์ง„ํ–‰ ๋ถˆ๊ฐ€(์„ค๊ณ„ ์ „์ œ). ํ˜„์žฅ ์Šคํƒœํ”„๊ฐ€ ์ฐจ์— ๋งํ•˜๋„๋ก ์•ˆ๋‚ด. ๋น„์ƒ์‹œ ์„œ๋ฒ„ /mqtt ์˜ advance ๋กœ ๊ฐ•์ œ ์ง„ํ–‰
์ฐจ ๋งˆ์ดํฌ ๊ถŒํ•œ ๊ฑฐ๋ถ€ยทSTT ์˜ค๋ฅ˜ ์œ„์™€ ๊ฐ™์Œ ์œ„์™€ ๊ฐ™์Œ(์ฐจ ํ™”๋ฉด ํ•˜๋‹จ์— ๋ถ‰์€ ํ‘œ์‹œ๊ฐ€ ๋œฌ๋‹ค โ€” ์šด์˜์ž ํ™•์ธ์šฉ)
SSE ์žฌ์—ฐ๊ฒฐ BFF ์บ์‹œ replay ๋กœ state ๋ณต์› ์—†์Œ(๊ตฌํ˜„๋จ)
๋ฏธ๋ž˜์ฐจ ์„œ๋ฒ„ ์žฌ์‹œ์ž‘ state ๋Š” DB ๋ณต์› ํ›„ ์žฌ๋ฐœํ–‰. ๋Œ€ํ™” ํžˆ์Šคํ† ๋ฆฌ๋Š” ๋ณต์› ์•ˆ ๋จ(๋‹ค์Œ ์Šคํ… ํ’ˆ์งˆโ†“) ์—†์Œ
OC ์ด๋ฒคํŠธ ํŒ์—…์ด ์ฐจ ์•ˆ์—์„œ ๋œธ event ํŒ์—…(์žฅ์†Œ ๋ฌด๊ด€) ์ง€๊ธˆ์ฒ˜๋Ÿผ ํ‘œ์‹œยท๋‹ซ๊ธฐ. ์ฐจ๊ฐ€ ์ด๋ฒคํŠธ์— ๋ฐ˜์‘ํ• ์ง€๋Š” ๋ฏธ์ • โ€” ํƒœ๋ธ”๋ฆฟ ๋ณ€๊ฒฝ ์š”์ฒญ ์—†์Œ
exit ๋ฅผ ์ผ์ฐ ๋ณด๋ƒ„ state done, ์ฐจ ์ž‘๋ณ„ ํ™”๋ฉด ยง4 ๊ฒฝ๊ณ  ์ฐธ๊ณ 

9. ๋ณ€๊ฒฝ ์ด๋ ฅ ยท ๋ฌธ์˜

๋‚ ์งœ ๋‚ด์šฉ
2026-08-23 ์ดˆํŒ โ€” ๊ตฌ๋…ยทstoreยทenter/exit ๋ฐœํ–‰ ๊ฐ€์ด๋“œ (tablet-fe ์— ๋ฏธ๋ž˜์ฐจ ์ฝ”๋“œ 0๊ฑด ์‹œ์ )
2026-08-29 ์ „๋ฉด ์žฌ์ž‘์„ฑ โ€” ๊ตฌํ˜„ ์™„๋ฃŒ๋ถ„ ์ •๋ฆฌ, ์ž…๋ ฅ ์ž ๊ธˆ(ยง2-A) ์‹ ๊ทœ ์š”์ฒญ, ํ•˜์ฐจ ์œ ๋„ยทํƒœ์Šคํฌ ์นด๋“œยทํƒ€์ž„๋ผ์ธยท๊ฒ€์ฆยท์˜ˆ์™ธ ์ถ”๊ฐ€. ์ฐจ ๋งˆ์ดํฌ STT ์ •์ฑ… ๋ฐ˜์˜

๋ฌธ์˜: ๋ฏธ๋ž˜์ฐจ ํŒ€. ์„œ๋ฒ„ ํŠธ๋ž˜ํ”ฝยท๋กœ๊ทธ๋Š” ์œ„ ยง6 ๋„๊ตฌ๋กœ ์ง์ ‘ ๋ณผ ์ˆ˜ ์žˆ๋‹ค โ€” "์™œ ์•ˆ ์™”๋‚˜"๋Š” /mqtt ์™€ /logs?session_id= ์— ๋‚จ๋Š”๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ