Moveet: 인시던트, 녹화 및 재생, icon rail UI, 및 500개 이상의 테스트

발행: (2026년 3월 16일 PM 07:38 GMT+9)
8 분 소요
원문: Dev.to

Source: Dev.to

무엇이 제공되었는가

🚦 차량 관리

차량을 이제 이름이 지정된 색상‑코드 플릿으로 그룹화할 수 있습니다. 플릿을 만들고 차량을 할당하면 UI가 플릿별로 경로와 마커를 색칠합니다 – 동일한 도로망을 공유하는 여러 운영자를 시뮬레이션할 때 유용합니다.

REST API

POST   /fleets
GET    /fleets
DELETE /fleets/:id
POST   /fleets/:id/assign
POST   /fleets/:id/unassign

WebSocket events

  • fleet:created
  • fleet:deleted
  • fleet:assigned

⚠️ 사고 및 동적 재경로 지정

네트워크 어디에서든 도로 사고를 발생시킬 수 있습니다. 영향을 받은 구간을 현재 통과하고 있는 모든 차량은 실시간으로 재경로 지정됩니다 – A*가 차량의 현재 위치에서 다시 실행되어 차단된 구간을 우회합니다.

REST API

POST   /incidents          # 사고 생성, 재경로 지정 트리거
GET    /incidents          # 활성 사고 목록
DELETE /incidents/:id      # 사고 해제, 차량이 정상 경로로 복귀
POST   /incidents/random   # 테스트용 무작위 사고

WebSocket event

  • vehicle:rerouted – 재경로 지정된 각 차량에 대해 발생

사고 마커가 지도에 표시됩니다.


🎬 세션 녹화 및 재생

모든 시뮬레이션 세션을 타임스탬프가 포함된 NDJSON 파일로 녹화할 수 있습니다. 형식은 헤더 라인 뒤에 한 줄에 하나씩 이벤트(방향 할당, 차량 스냅샷, 사고 등)가 기록됩니다.

REST API

POST   /recording/start
POST   /recording/stop
GET    /recordings

Replay control API

POST   /replay/start    { "file": "path/to/recording.ndjson" }
POST   /replay/pause
POST   /replay/resume
POST   /replay/stop
POST   /replay/seek     { "timestamp": 12000 }
POST   /replay/speed    { "speed": 2 }
GET    /replay/status

재생은 1×, 2×, 4× 속도를 지원합니다. UI는 서버 틱 사이를 부드럽게 보간한 진행 바를 표시해 500 ms마다 발생하는 점프를 방지합니다.


🖥 UI 재설계 – 아이콘 레일 + 패널 사이드바

이전의 떠다니는 오버레이는 왼쪽 가장자리에 위치한 아이콘 레일로 교체되었습니다 – 각 아이콘 버튼이 패널을 토글하는 수직 스트립입니다.

아이콘패널
🚗Vehicles – 목록, 필터, 선택
🗂Fleets – 생성, 할당, 색상
⚠️Incidents – 배지 수와 함께 활성 목록
Recordings – 시작/중지/탐색/재생
👁Visibility – 지도 레이어 토글
Speed – 시뮬레이션 속도 제어
⚙️Adapter – 소스/싱크 플러그인 핫‑스와핑

하단 도크에는 실시간 시뮬레이션 제어(재생/정지/리셋/녹화)가 위치하고, 재생 중에는 재생 전송 바로 축소됩니다.

모든 패널 컴포넌트는 공유 프리미티브(PanelShell, PanelHeader, PanelSection)와 통합 테마 토큰 세트로 구축되어, 개별 컴포넌트마다 임시 스타일을 적용하지 않아도 모든 패널이 일관된 모습을 유지합니다.


✅ 테스트 커버리지 – 410에서 502 테스트로 증가

시뮬레이터 테스트 스위트가 크게 확대되었습니다. 새로 추가된 파일:

파일내용
rateLimiter.test.ts윈도우 제한, 429 응답, IP별 추적, 정리 간격
helpers.test.tscalculateBearing, interpolatePosition, calculateDistance, nonCircularRouteEdges, estimateRouteDuration
serializer.test.ts플릿 할당 여부에 따른 serializeVehicle
config.test.tsverifyConfig – 파일 누락, 포트 범위, 속도 순서, 모든 숫자 제약
SimulationController.test.ts전체 라이프사이클: start, stop, getStatus, setOptions, getVehicles, getInterval, 모든 재생 메서드

주목할 만한 테스트 패턴SimulationController 테스트는 VehicleManager.prototype.setRandomDestination을 스텁해 작은 테스트‑네트워크에서 A* 호출을 방지하고, 테스트 후 복원합니다. 재생 테스트는 각 테스트 전에 임시 디렉터리에 최소 NDJSON 파일을 작성하고, afterEach에서 모든 것을 정리합니다.


📡 WebSocket – 100 ms 배치 + 역압

Vehicle position updates are now batched every 100 ms before bro

adcast. 클라이언트의 쓰기 버퍼가 백업되면, 브로드캐스터는 무한히 늘어나는 큐를 만들지 않고 해당 클라이언트를 건너뜁니다. 이렇게 하면 연결 품질 저하 없이 50–100대의 차량을 시뮬레이터에서 사용할 수 있습니다.

All broadcast event types

vehicles          – 배치된 위치 배열 (100 ms 윈도우)
status            – 시뮬레이션 상태 (running / ready / interval)
options           – 현재 StartOptions
heatzones         – HeatZoneFeature[]
direction         – 활성 디스패치 할당
waypoint:reached  – 차량이 웨이포인트에 도달
route:completed   – 차량이 전체 경로를 완료
reset             – 시뮬레이션이 리셋됨
fleet:created / fleet:deleted / fleet:assigned
incident:created / incident:cleared
vehicle:rerouted  – 실시간 A* 재경로 트리거

🔧 CI improvements

GitHub Actions 워크플로는 이전에 npm ci를 병렬로 세 번 실행했습니다(작업당 한 번씩). 이제 setup 작업을 별도로 두어 한 번만 설치하고 package-lock.json을 기준으로 node_modules를 캐시합니다. Lint, test, build 작업은 해당 캐시를 복원합니다. build 작업은 또한 커밋별 키와 브랜치 수준 복원 키를 사용해 .turbo/를 캐시합니다.


Architecture diagram (updated)

┌──────────────────────────────────────┐
│  apps/ui                             │
│  React 19 · D3 7 · Vite · TS 5.8    │
│  Mercator SVG map, 1×–15× zoom       │
│  Icon rail · Panel sidebar · Dock    │
└──────────────┬───────────────────────┘

아키텍처 개요

               │ REST + WebSocket

┌──────────────────────────────────────┐
│  apps/simulator                      │
│  Express 4 · ws 8 · Turf.js 7       │
│  GeoJSON graph · A* · LRU cache      │
│  WS broadcaster · 100ms batching     │
└──────────────┬───────────────────────┘
               │ GET /vehicles · POST /sync

┌──────────────────────────────────────┐
│  apps/adapter (optional)             │
│  Source plugins: static / graphql /  │
│  rest / mysql / postgres             │
│  Sink plugins: console / graphql /    │
│  rest / redpanda / redis / webhook   │
└──────────────────────────────────────┘

빠른 시작

curl -O https://raw.githubusercontent.com/ivannovazzi/moveet/main/docker-compose.ghcr.yml
docker compose -f docker-compose.ghcr.yml up

열어보세요. 구성이나 API 키가 필요 없습니다.

Repository:


댓글에서 A 구현, D3 렌더러, 혹은 녹화 포맷에 대해 자유롭게 질문해주세요.*

0 조회
Back to Blog

관련 글

더 보기 »

오픈소스를 위한 지속적인 운영

Ryan은 Chainguard CEO인 Dan Lorenc와 함께 앉아 그의 팀이 인터넷의 기반인 오픈 소스 프로젝트를 포킹 아카이브를 통해 어떻게 살아 있게 유지하고 있는지에 대해 이야기합니다.

OpenSUSE 칼파

Kalpa는 원자적이고 트랜잭션 기반의 Linux 운영 체제로, Plasma Desktop Environment를 제공합니다. !Matrix badgehttps://img.shields.io/matrix/kalpa%3Aopensus...