-
Notifications
You must be signed in to change notification settings - Fork 0
DEVELOPMENT
로컬에서 SPOT·실 카메라·실 태블릿 없이 코드를 작성·검증하는 절차. CI 통과 + 사무실 미러 환경 검증을 거쳐 전시장에 배포한다.
SPOT·실 카메라·실 태블릿 없이 로컬에서 풀 스택을 처음 띄우기까지 순서대로 점검하는 부트스트랩 체크리스트. 각 항목의 상세 절차는 아래 해당 섹션을 따른다. 이 체크리스트의 종착점 = §6 Phase 0 게이트(
mosquitto + bridge + fake-frigate → vision/zone/enter 발행 확인).표기:
[ ]갖추거나 만들 것 ·[?]확인·점검할 것.
- Docker 24.0+ + Compose v2 (
docker compose version) - Python 3.12 +
uv, Node.js 20 LTS (uv --version/node -v) -
mosquitto-clients(mosquitto_sub/mosquitto_pub— 버스 라이브 테일용) - (옵션) NVIDIA GPU 또는 USB Coral — vision/Frigate 검증 시에만
- 모노레포 clone +
pre-commit install - Python 서비스
uv sync --dev(orchestrator·bridge·mcp-robot-adapter) - Node 서비스
npm ci(mcp-tablet-gateway·apps/tablet)
-
DEV_MODE=true— tablet-gateway 고정 토큰DEV_TOKEN허용 (§4.3) - fake-spot 자격
bosdyn:bosdyn명시 (§8 트러블슈팅) -
ANTHROPIC_API_KEY— Phase 0에는 불필요, Phase 1(orchestrator) 진입 시 필요 - [?]
.env.dev가.gitignore에 포함됐는지 — 시크릿 커밋 금지
-
docker-compose.dev.yml로 mosquitto 기동 - passwd 파일 권한·uid (
chown 1883:1883 passwd, §8) - ACL 로드 — 각 서비스 계정이 필요한 토픽만 사용하도록 (SERVICES.md §1)
- [?]
mosquitto_sub -h localhost -t '#' -v로 연결 확인
- HA 컨테이너 기동 +
configuration.yaml기본값 로드 - HA의 MQTT integration이 mosquitto에 연결됐는지 (Settings → Devices & Services)
- recorder(SQLite) 동작 확인 — HA가 상태 저장 계층임
- [?]
http://localhost:8123Developer Tools → States 접근 가능
-
ROBOT_ADAPTER=mock으로 mcp-robot-adapter 기동 —MockAdapter(§4.1) -
tests/tools/fake-frigate.py실행 가능 확인 (§4.2) - fake-spot gRPC 시뮬레이터 — Phase 1 진입 시 (§3 compose)
-
tests/tools/fake-tablet.htmlWSS 연결 — Phase 3 진입 시 (§4.3)
-
tests/integration/run-phase-0.sh— mosquitto + bridge + fake-frigate 부팅 - [?] fake-frigate
frigate/events발행 → bridge가vision/zone/enter로 변환·발행하는지 라이브 테일 확인 - [?] CloudEvents envelope·
traceparent가 메시지에 정상 부착됐는지 (MQTT_SCHEMA.md §1)
완료 기준: 로컬에서 mosquitto·HA·bridge가 떠 있고, fake-frigate 이벤트 한 건이 vision/zone/enter로 변환되어 버스에 흐르는 것을 mosquitto_sub로 확인할 수 있다.
| 항목 | 권장 사양 |
|---|---|
| OS | Ubuntu 22.04 / macOS 14+ / WSL2 Ubuntu |
| RAM | 16GB 이상 |
| CPU | 4 코어 이상 |
| GPU(Graphics Processing Unit, 그래픽 처리 장치) | (옵션) Frigate/vision 검증 시 NVIDIA GPU 또는 USB Coral |
| Docker | 24.0+ + Compose v2 |
| Python | 3.12 |
| Node.js | 20 LTS |
git clone https://github.com/OWNER/zerone.git
cd zerone
# pre-commit 훅 설치
pip install pre-commit
pre-commit install
# Python 서비스 dev 의존성
cd services/orchestrator && uv sync --dev && cd ../..
cd services/bridge && uv sync --dev && cd ../..
cd services/mcp-robot-adapter && uv sync --dev && cd ../..
# Node.js 서비스
cd services/mcp-tablet-gateway && npm ci && cd ../..
# 태블릿 앱
cd apps/tablet && npm ci && cd ../..deploy/docker-compose.yml은 운영용 핀(pin) 이미지를 사용한다. 개발 시에는 deploy/docker-compose.dev.yml overlay로 다음을 변경:
- 자체 서비스를
image:대신build:로 로컬 빌드. - 외부 카메라·로봇 자리에 mock 컨테이너 배치.
- 환경변수에
LOG_LEVEL=debug. - 포트를 모두
localhost에 노출 (디버깅 편의).
# deploy/docker-compose.dev.yml
services:
bridge:
build: ../services/bridge
image: zerone/bridge:dev
environment:
- LOG_LEVEL=debug
orchestrator:
build: ../services/orchestrator
image: zerone/orchestrator:dev
environment:
- LOG_LEVEL=debug
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
mcp-robot-adapter:
build: ../services/mcp-robot-adapter
image: zerone/mcp-robot-adapter:dev
environment:
- ROBOT_ADAPTER=mock # 핵심: 실 SPOT 대신 mock
- LOG_LEVEL=debug
mcp-tablet-gateway:
build: ../services/mcp-tablet-gateway
image: zerone/mcp-tablet-gateway:dev
# mock 카메라 (Frigate 대체 또는 RTSP 시뮬레이션)
fake-rtsp:
image: linuxserver/ffmpeg:latest
command: >
-re -stream_loop -1 -i /assets/sample.mp4
-c copy -f rtsp rtsp://0.0.0.0:8554/live
volumes: [../tests/fixtures/video:/assets:ro]
ports: ["8554:8554"]
# mock SPOT (gRPC 시뮬레이터)
fake-spot:
build: ../tests/mocks/fake-spot
ports: ["50051:50051"]기동:
cd deploy
docker compose -f docker-compose.yml -f docker-compose.dev.yml up --buildmcp-robot-adapter의 ROBOT_ADAPTER=mock 환경변수로 활성화. 다음 동작을 시뮬레이션:
| capability | 동작 |
|---|---|
goto |
0.5 m/s 가정으로 위치 보간, 1Hz robot/{id}/state publish |
follow |
가상 사용자 위치를 일정 거리 유지 |
stop |
즉시 stop, current_action=null |
look_at |
yaw 변경, 1초 후 completed ack |
gesture |
2초 후 completed |
# services/mcp-robot-adapter/src/adapter/adapters/mock.py (요지)
class MockAdapter(RobotAdapter):
def __init__(self, robot_id: str):
self.robot_id = robot_id
self.pose = {"x": 0, "y": 0, "yaw": 0, "zone_id": "cafe"}
self.battery = 100
self.current_action = None
async def execute(self, capability, params):
if capability == "goto":
asyncio.create_task(self._simulate_goto(params))
...
return {"command_id": ulid.new().str, "status": "accepted"}실제 RTSP(Real Time Streaming Protocol, 실시간 스트리밍 프로토콜) 없이 frigate/events를 발행하는 작은 스크립트:
# tests/tools/fake-frigate.py
import json, paho.mqtt.client as mqtt, time, ulid
events = [
{"type": "new", "after": {"id": ulid.new().str, "camera": "cafe_cam_01",
"label": "person", "score": 0.95,
"current_zones": ["cafe_zone"],
"entered_zones": ["cafe_zone"]}},
# 5초 후 park 이동
{"type": "update", "after": {"camera": "park_cam_01", ...}},
]
c = mqtt.Client(); c.connect("localhost", 1883)
for e in events:
c.publish("frigate/events", json.dumps(e), qos=1)
time.sleep(5)실행:
python tests/tools/fake-frigate.py브라우저 기반 간단 WSS(WebSocket Secure, 보안 웹소켓) 클라이언트:
<!-- tests/tools/fake-tablet.html -->
<script>
const ws = new WebSocket("ws://localhost:8080?token=DEV_TOKEN");
ws.onmessage = (e) => console.log("RX:", JSON.parse(e.data));
function selectOption(id) {
ws.send(JSON.stringify({intent_type: "option_select", payload: {option_id: id}}));
}
</script>
<button onclick="selectOption('drink_recommend')">커피 추천</button>페어링 우회를 위해 mcp-tablet-gateway에 DEV_MODE=true 환경변수 시 고정 토큰 DEV_TOKEN로 로그인 허용.
cd services/orchestrator
uv run pytest -v --cov=src
# 가드레일 fuzz 테스트
uv run pytest tests/test_guardrail.py::test_reject_invalid_velocity -vcd services/mcp-tablet-gateway
npm testcd apps/tablet
npm test
npm run e2e:ios # detox iOS각 Phase 진입 전 검증할 시나리오. 모두 mock으로 가능. (로컬 환경을 처음 세우는 단계별 준비는 §0 참조.)
| Phase | 통합 테스트 |
|---|---|
| 0 | mosquitto + bridge + fake-frigate → vision/zone/enter 발행 확인 |
| 1 | + orchestrator + fake-spot → Claude tool call → MockAdapter 동작 |
| 2 | + 실 SPOT (사무실 미러) — fake-frigate 유지 |
| 3 | + tablet-app + fake-tablet HTML → 옵션 선택 round-trip |
| 4 | 4 zone × 2 robot 동시 시나리오 (혼잡 시뮬레이션) |
| 5 | LLM(Large Language Model, 대규모 언어 모델) 단절 시 폴백 시나리오 4종 모두 발동 |
자동화: tests/integration/run-phase-N.sh 스크립트로 mock 환경 부팅 + 시나리오 실행 + assert.
| 검사 | 도구 | 기준 |
|---|---|---|
| Python lint | ruff check |
0 violation |
| Python type | mypy --strict |
0 error |
| Python test |
pytest + coverage
|
통과 + coverage > 70% |
| TS lint | eslint |
0 error |
| TS type | tsc --noEmit |
0 error |
| TS test |
vitest / jest
|
통과 |
| 컨테이너 vuln | Trivy CRITICAL/HIGH | 0 (또는 명시적 ignore) |
| pre-commit | trailing whitespace, large file 등 | 통과 |
| 증상 | 원인 / 해결 |
|---|---|
orchestrator가 host.docker.internal:8123 접근 실패 |
extra_hosts 누락 — compose에 host-gateway 매핑 확인 |
mosquitto에 connection refused |
passwd 파일 권한·uid 확인 (chown 1883:1883 passwd) |
| Frigate가 RTSP에서 stream 못 받음 |
ffprobe rtsp://... 로 컨테이너 밖에서 먼저 검증 |
bridge가 vision/zone/enter 발행 안 함 |
frigate/events 라이브 테일 확인 → ReID(Re-identification, 보행자 재식별) registry 매칭 실패 가능 (mock 토큰 사용 권장) |
| Claude tool call이 무한 반복 | guardrail에서 거부 → orchestrator가 빈 응답으로 재시도 → 시스템 프롬프트에 "거부 시 종료" 명시 |
| SPOT 시뮬레이터 인증 실패 | bosdyn-client는 simulator의 bosdyn:bosdyn 기본 자격 사용 — .env.dev에 명시 |
전시장 진입 전 검증할 미니 환경:
- 카메라 1대 (페어링·테스트용)
- SPOT 1대 (사무실 평지)
- 태블릿 1대
- mosquitto/HA/orchestrator/bridge/robot-adapter/tablet-gateway 풀 스택
전시장 환경과의 차이를 tests/integration/MIRROR_DIFFS.md에 기록 → 차이가 위험을 만들지 않는지 검토.
| 용도 | 도구 |
|---|---|
| MQTT(Message Queuing Telemetry Transport, 메시지 큐 텔레메트리 전송 프로토콜) 라이브 테일 | mosquitto_sub -h localhost -t '#' -v |
| trace_id 추적 | Loki query `{service="orchestrator"} |
| Claude 호출 분석 | LangSmith (선택) 또는 LOG_LEVEL=debug 시 stdout |
| HA entity 상태 |
http://localhost:8123 Developer Tools → States |
| 컨테이너 ↔ 호스트 통신 | nc -zv host.docker.internal 8123 |