move_detect/docs/pilot-runbook.md
유창욱 3f2823a764 refactor: rename cloud/ to server/ (cafe24 is web hosting, not cloud)
The PHP app runs on Cafe24 shared web hosting -- calling it 'cloud'
was misleading. Renames the directory, the edge client module, and
every doc/script/identifier that used the term.

- cloud/ -> server/ (incl. server/deploy/build_cafe24_package.sh paths)
- edge/cloudclient.py -> edge/serverclient.py, CloudClient -> ServerClient
- cloud/docs/cloud-deploy.md -> server/docs/server-deploy.md
- CLOUD_* env/config keys -> SERVER_*
- tests renamed to match

Tests: PHP 109 pass (4 skipped), pytest 167 pass. dist/ regenerated.
2026-07-20 11:30:52 +09:00

6.4 KiB

P1 파일럿 런북 (노트북 웹캠 엔드투엔드)

이 문서는 노트북 웹캠 하나로 엣지 → 서버 → 관리자 응답의 최소 경로를 돌리는 절차다. 실장비(Hailo·Pi5)·폐쇄망 전체 번들·드릴 게이트·SMS 연동은 후속(범위 밖, §6).

  • 엣지: python -m edge (또는 move-detect-edge) — CPU MoveNet pose → 감지 → HMAC 서명 POST.
  • 서버: 기존 server/ PHP 앱 — ingest + 대시보드 + 사고 상세 + 데스크 Web Audio 알림.

1. 빌드 머신 준비 (모델 · onnxruntime)

폐쇄망 원칙: onnxruntime 휠과 .onnx 모델은 빌드 머신에서 받아 번들한다. 타깃(폐쇄망)에서 인터넷을 받지 않는다. 노트북 파일럿은 빌드=타깃이 같은 머신이라 아래를 그대로 실행하면 된다.

pip install onnxruntime          # CPU 추론 런타임 (에어갭 타깃엔 오프라인 휠로 번들)
python -m edge.tools.fetch_movenet   # MoveNet SinglePose Lightning ONNX -> models/movenet_lightning.onnx

fetch_movenet.py의 URL은 빌드 편의용이다. 실제 내려받은 모델의 입력 크기/자료형과 출력 레이아웃 [1,1,17,3](y,x,score)를 어댑터 기대값과 대조하라(다르면 MoveNetPoseAdapter(input_size=...) 조정; COCO-17 remap 로직은 그대로). 어댑터 remap은 tests/test_movenet_pose.py(fake session)로 고정돼 있고, 실모델 경로는 tests/hardware/test_movenet_smoke.py가 모델이 번들됐을 때만 게이트로 검증한다.


2. 서버 로컬 기동

로컬 MySQL 8(스키마 CHECK 제약은 8.0.16+)과 PHP 8.2+ 필요. 상세 배포·전제조건(gd/argon2/HTTPS 등)은 server/docs/server-deploy.md 참조 — 여기선 로컬 최소 절차만.

  1. DB 생성 후 스키마 임포트: mysql <db> < server/schema.sql (10개 테이블).
  2. server/config.php를 server/config.example.php에서 복사, 로컬 DB DSN/계정 기입 (snapshot_dir는 쓰기 가능 경로로).
  3. 관리자 계정 · 디바이스 시크릿 등록 — 앱에 셀프 가입 흐름이 없으므로 직접 넣는다. CLI 스니펫과 SQL은 server-deploy.md §6(디바이스 시크릿) · §7(첫 관리자) 그대로 사용:
    • 시크릿 생성: php -r "echo bin2hex(random_bytes(32)), \"\n\";"
    • INSERT INTO devices (device_id, name, secret, config_version) VALUES ('pi-01','노트북','<시크릿>',1);
    • 관리자 해시: php -r "echo password_hash('바꿀-암구호', PASSWORD_ARGON2ID), \"\n\";"
    • INSERT INTO users (username, password_hash, role, ...) VALUES ('admin','<해시>','admin',NULL,0,0);
  4. 기동: php -S localhost:8000 -t server/public
    • 세션 쿠키가 cookie_secure라 순수 HTTP에선 로그인 쿠키가 안 붙을 수 있다. 로컬은 대개 localhost가 secure-context로 취급돼 동작하지만, 안 되면 server-deploy.md §8(HTTPS) 참조.

3. 엣지 환경변수

edge/config.py(load_config) + edge/daemon.py(main)가 읽는 실제 키:

env 의미 예시
DEVICE_ID devices.device_id와 일치 pi-01
DEVICE_SECRET devices.secret와 일치(HMAC) <§2에서 생성한 값>
CAFE24_URL 서버 베이스 URL http://localhost:8000
CAMERA_ID 이벤트/구역의 camera_id cam-01
MOVENET_ONNX 모델 경로 (필수, 없으면 즉시 KeyError) models/movenet_lightning.onnx
UVC_DEVICE OpenCV 캡처 인덱스 0
TARGET_FPS 프레임 간격 = 1/fps 12
QUEUE_DB 오프라인 큐 sqlite 경로 queue.db

감지 임계값(선택, 데모 단축용): FALL_PRONE_S(기본 3.0), FALL_NO_MOTION_S(10.0), IMMOBILE_S(120.0), GHOST_REAPPEAR_S(10.0), ZONE_DEBOUNCE_S(0.75), COOLDOWN_S(30.0).

export DEVICE_ID=pi-01 DEVICE_SECRET='<시크릿>' CAFE24_URL=http://localhost:8000 \
       CAMERA_ID=cam-01 MOVENET_ONNX=models/movenet_lightning.onnx UVC_DEVICE=0 TARGET_FPS=12
python -m edge        # 또는 move-detect-edge

4. 데모 시나리오

  1. 낙상: 웹캠 앞에서 눕는다 → FALL_PRONE_S(기본 3초) 후 fall(high) 이벤트.
  2. 위급 상승: 계속 안 움직이면 FALL_NO_MOTION_S(기본 10초) 후 no_motion(critical) → 대시보드에서 데스크 비프 반복(첫 클릭으로 오디오 언락 필요).
  3. 가시화: 목록의 이벤트 유형(링크) 클릭 → /events/{id}/view 상세 → 스냅샷 이미지 확인.
  4. 응답: 상세/목록에서 확인 → 미확인 critical이 사라지면 비프 정지.
  5. 역루프(구역): 대시보드 구역 설정에서 폴리곤 저장 → 발끝 진입 → zone_* 이벤트. 구역 변경은 엣지의 다음 config 폴링 때 적용된다 — 기본 cadence sync_every=150 프레임 ≈ 12fps에서 약 12초. 저장 후 ~15초 기다렸다가 진입할 것.
  6. 오프라인 큐: 네트워크(또는 php -S) 중단 상태에서 이벤트 발생 → 큐에 적재 → 복구 후 flush_every=300 프레임(≈25초)마다 flush로 밀린 이벤트 전송.
  7. 하트비트: heartbeat_every=900 프레임(≈75초)마다 POST /api/heartbeat(서명).

cadence(sync_every/heartbeat_every/flush_every)는 daemon.main() 기본값이며 env로 노출돼 있지 않다. 데모에서 더 빠른 주기가 필요하면 run_loop(...) 호출 인자를 임시 조정한다.


5. 검증(테스트)

pytest -q                                   # 엣지 유닛(하드웨어 스모크는 모델 없으면 skip)
cd server && ./vendor/bin/phpunit --display-warnings --display-deprecations   # 서버(0 warnings)

모델을 번들한 뒤 실추론 경로까지 확인하려면 models/movenet_lightning.onnx 존재 상태로 pytest -q — tests/hardware/test_movenet_smoke.py가 skip 해제돼 실행된다.


6. 파일럿 한계 (명시)

  • 단일 카메라 · CPU pose(저 fps) — 실장비 Hailo 가속은 후속.
  • 단일 프레임 스냅샷 — 前中後 링버퍼 다중 프레임은 P2.
  • 알림 1채널(데스크 Web Audio) — critical SMS/webhook 실연동은 후속(게이트 정보 필요).
  • 폐쇄망 전체 번들 아님 — onnxruntime/모델 fetch만 제공. 오프라인 휠·차단 설치·docker save 패키징은 별도 후속 태스크.
  • 드릴 게이트 · F14 컴플라이언스 · 감사 해시체인 — 범위 밖(P1-C/P3).