API · WebSocket · 웹훅 계약 (IR-*)

02-requirements/api-contracts.html · LogiNippon · TRD · 2026-06-13 · 신뢰도 라벨 확인/추정/설계

이 페이지는 LogiNippon의 유선(wire) 계약을 단일 버전 진실원으로 고정한다 — REST(OpenAPI 3.1) · WebSocket(AsyncAPI) · 웹훅의 정확한 형상, 인증 스코프, 페이지네이션·레이트리밋·에러 규약, 그리고 외부 인터페이스(EDI·텔레매틱스·맵/기상)다. 계약은 @loginippon/contract 패키지로 추출되어 server·console·Flutter가 단일 소비하고, CI drift-gate가 불일치를 빌드 실패로 막는다. 본 페이지의 모든 엔드포인트는 as-built 구현 상태(DONE/STUB/ABSENT)를 정직하게 표기한다 — 계약은 고정되었으나 구현은 진입 단계로, 다수가 STUB/ABSENT다. 수치는 마스터 정규화 표(§4)에서 글자 그대로 인용하며 모두 "운영 데이터 없는 진입 단계의 초기 확정 목표(설계), 베이스라인으로 조정"임을 전제한다.

경계. 데이터 형상의 권위는 데이터 모델(data-model.html)이고, 인증·스코프·마스킹·서명 키의 권위는 보안 문서(security-privacy.html)다. 이 페이지는 그 형상을 유선에 직렬화하는 계약만 소유한다. 비기능 목표(가용성·레이트리밋 수치)는 nonfunctional.html·slo-catalog.html이 소유하고 여기선 계약 표면에 닿는 한도에서 인용·링크한다. 대시보드 채널 분리(WS vs 폴링)는 ADR-0010을 따른다.

1. 단일 계약 원칙 — IR-API-001

IR-API-001 단일 버전 계약 원천 + @loginippon/contract 추출 + CI drift-gate P0·MustPhase 1I 검사

요구. 시스템은 REST 표면을 OpenAPI 3.1 문서로, 실시간 표면을 AsyncAPI 문서로 기술하고, 이 둘을 단일 패키지 @loginippon/contract로 추출하여 server·console·Flutter app이 단일 소비하도록 반드시 한다(MUST). 생성된 타입·클라이언트가 손으로 쓴 모델과 어긋나면 CI의 drift-gate가 빌드를 실패시켜야 한다(MUST).

문제(현재 3중 손중복). as-built에서 같은 계약이 세 곳에서 손으로 중복된다 — ① server interfaces(server/src/types/index.ts), ② console console/src/lib/types.ts(server 타입 수기 복제, 코드 내 TODO: @loginippon/contract 추출), ③ Flutter 수기 모델(app/lib/core/models/job.dart·tracking_snapshot.dart·canonical_code.dart). 단일 추출이 없어 필드 추가 시 3곳 동기화에 의존하며, console·Flutter의 서버 의존 기능 전부가 계약 동결을 unblock 산출물로 대기한다(app: ShipmentWsClient/JobsRepository stub).

수용기준

  • Given @loginippon/contract가 OpenAPI 3.1 + AsyncAPI에서 타입/클라이언트를 생성 When server·console·Flutter 빌드가 이 패키지를 임포트 Then 세 레포에 동일 계약 버전이 단일 소스로 주입된다(중복 정의 0).
  • Given 누군가 server/src/types/index.ts의 응답 형상을 변경하고 OpenAPI 문서를 갱신하지 않음 When CI drift-gate 실행 Then 빌드가 실패한다(생성물 ≠ 선언물).
  • Given 클라이언트가 LogiNippon-Api-Version 응답 헤더를 읽음 When 비파괴적 필드 추가가 /v1 내에서 배포 Then 날짜 버전이 증가하고 기존 클라이언트는 깨지지 않는다.
근거 techspec 05-delivery-layer/delivery.md §설계 원칙 · ADR-0010(단일 @loginippon/contract 소비처 통일) · 구현 계약 패키지 미존재 ABSENT(server는 라우트로 계약을 구체화하나 OpenAPI/AsyncAPI 추출·drift-gate 부재) · 검증 CI 게이트 + 생성물 diff
계약 분리 규칙(설계). REST + 웹훅 = 외부 연동 채널, WebSocket = UI 레이어 전용(외부 시스템에 노출 안 함). 화주 TMS/WMS 연동은 폴링용 REST와 푸시용 웹훅으로만 한다 — overlay 레이어이지 ERP 대체가 아니다(Research/delivery-layer). 쓰기는 화물 등록·웹훅 구독으로 좁게 둔 읽기 위주 표면이다.

2. REST 엔드포인트 카탈로그 — IR-REST-catalog

/v1 엔드포인트(techspec 21개 + as-built 누락분 GET /v1/shipments/tracking 배치 라이브 추가). 구현상태 열은 마스터 §7 as-built에 정합한다(DONE=구현+테스트 / PARTIAL=부분 / STUB=껍데기·501·500·ack-only / ABSENT=미존재). Auth scope는 보안 문서(SR-AUTHZ-001 scope→endpoint 매트릭스)를 따르며, 모든 호출은 API Key의 tenant_id로 자동 필터링되고 타 테넌트 리소스는 404(존재 비노출)다.

MethodPath목적Auth scope구현상태
POST/v1/auth/tokenAPI Key/자격→단기 토큰 교환(grant=password / refresh_token)(public, 키/자격 필요)DONE
POST/v1/auth/ingest-token장수명 ingest 전용 토큰 발급(백그라운드 GPS)(인증 후, positions:write 한정 발급)DONE
GET/v1/shipments화물 목록(필터·커서 페이지)shipments:readDONE
POST/v1/shipments화물 등록(외부 TMS→우리)shipments:writeSTUB·500
GET/v1/shipments/tracking배치 라이브 스냅샷(N+1 회피, console FleetMap 6s 폴링 하드의존)shipments:readDONE
GET/v1/shipments/{id}화물 상세(상태+최신 위치+ETA+stops)shipments:readPARTIAL
GET/v1/shipments/{id}/tracking현재 상태 1건(라이브 DO 우선·D1 폴백) — 추적 링크·위젯용shipments:readDONE
GET/v1/shipments/{id}/events이벤트 타임라인(canonical)shipments:readDONE
GET/v1/shipments/{id}/positionsGPS 경로(샘플링·페이지)positions:readSTUB·빈배열
GET/v1/jobs드라이버 案件 목록(커서 페이지)shipments:readDONE
GET/v1/jobs/{id}案件 상세shipments:readDONE
POST/v1/jobs/{id}/accept案件 수락(캐리어/드라이버/차량 배정+상태 전이)shipments:readDONE
POST/v1/jobs/{id}/complete案件 완료(→ DELIVERED)shipments:readDONE
POST/v1/ingest/positionsGPS 배치 인제스트(오프라인 버퍼 flush)positions:writeDONE
GET/v1/vehicles/{id}/position차량 현재 위치(운송사 스코프)vehicles:readABSENT
GET/v1/geofences지오펜스 목록(거점)geofences:readABSENT
GET/v1/geofences/{id}지오펜스 상세(GeoJSON·임계)geofences:readABSENT
POST/v1/webhooks웹훅 구독 등록(이벤트 타입 선택)webhooks:writeSTUB·501
GET/v1/webhooks구독 목록(+최근 전달 상태)webhooks:readSTUB·빈배열
DELETE/v1/webhooks/{id}구독 해지webhooks:writeSTUB·204
POST/v1/webhooks/{id}/test테스트 이벤트 발송(서명 검증 점검)webhooks:writeSTUB·501
GET/v1/analytics/carriers/{id}캐리어 성능 지표(OTD·dwell·tracking rate)analytics:readABSENT
GET/v1/reports/nimachi?from=&to=荷待ち 기록(규제) — 메타+다운로드 URLreports:readDONE
GET/v1/reports/jitsuunso?from=&to=実運送体制管理簿 — 메타+다운로드 URLreports:readSTUB·501
GET/v1/reports/{report_id}/downloadR2 산출물 다운로드(테넌트 스코프·egress 무료)reports:readDONE
스텁/부재 정직 표기. POST /v1/shipments(화물 등록)는 현재 500 stub(shipments.ts "shipment registration not implemented", Phase 1 후반 예정). 웹훅 CRUD(webhooks.ts)는 501(구독 테이블·endpoint_secret 미생성). GET /v1/reports/jitsuunso(実運送体制管理簿)는 501(다단계 캐리어 체인 carrier.parent_carrier_id + GPS 검증 실운송 차량 결합 후속 의존). 부재(ABSENT): /v1/vehicles/{id}/position·/v1/geofences[/:id]·/v1/analytics/carriers/{id}(라우터에 TODO만, POST /v1/admin/drivers도 부재). {id}/positions·GET /webhooks는 라우트는 살아 있으나 빈 배열을 반환한다. GET /v1/shipments/tracking스펙 미기재 as-built 추가로, console FleetMap의 6s 폴링이 하드 의존하므로 계약에 반드시 편입한다.

3. 공통 규약 — 버전 · 페이지네이션 · 레이트리밋 · 에러

3.1 버전

경로 프리픽스 /v1. 파괴적 변경은 /v2로, 비파괴적 필드 추가는 /v1 내에서. 모든 응답에 날짜 기반 마이너 버전 헤더 LogiNippon-Api-Version: 2026-05-31을 실어 클라이언트가 동작 변화를 감지하게 한다(server API_VERSION var와 정합; 웹훅 페이로드 api_version 필드와 동일 값).

3.2 커서 페이지네이션

커서 기반(offset 아님 — D1 대용량 스캔 회피). 요청 ?limit=50&cursor=…. 응답은 data[] + page 객체(next_cursor, has_more). 커서는 (occurred_at, id) 복합 키를 불투명 base64로 인코딩한다. as-built 정합: GET /v1/shipments·/v1/jobs 모두 { data, page:{ next_cursor, has_more } } 형상을 반환하며 has_more = (next_cursor != null)이다(shipments.ts·jobs.ts). 배치 GET /v1/shipments/tracking은 위치 있는 화물만 필터링한 { data }(page 없음, 지도 스냅샷 용도)를 반환한다.

3.3 레이트리밋

테넌트별(API Key 단위). 표준 헤더로 노출하고, 한도 수치는 NFR-SEC-RL-001(보안 문서가 권위)을 따른다. 모두 진입 단계 초기 확정 목표(설계), 운영 베이스라인으로 조정한다.

600/min
API Key당 지속(버스트 100/10s)
10/min
리포트 엔드포인트
1200/min
인제스트(positions)
429 + Retry-After
초과 시 응답
헤더의미
RateLimit-Limit윈도 내 허용 요청 수
RateLimit-Remaining남은 요청 수
RateLimit-Reset윈도 리셋까지 초
Retry-After429 시 재시도 대기 초
as-built 갭. 레이트리밋은 미구현이다 — 에러맵에는 RATE_LIMITED/429 코드가 존재하나 실제 미들웨어가 없어 한도가 강제되지 않는다(마스터 §7). 위 헤더·수치는 계약상 확정 목표이며 Phase 1 내 미들웨어 배선이 필요하다.

3.4 에러 엔벨로프

일관 형식(HTTP 상태 + 머신리더블 code + request_id + details). request_id는 로그·관측성(slo-catalog.html)과 상관(correlate)된다.

{
  "error": {
    "code": "SHIPMENT_NOT_FOUND",
    "message": "shipment SHP-2025-00456 not found in this tenant",
    "request_id": "req_01HF...",
    "details": []
  }
}
codeHTTP의미
UNAUTHENTICATED401토큰/자격 없음·무효
PERMISSION_DENIED403스코프 부족
SHIPMENT_NOT_FOUND404부재 또는 타 테넌트(존재 비노출)
VALIDATION_FAILED422본문/쿼리 검증 실패(예: 리포트 범위 위반)
RATE_LIMITED429레이트리밋 초과(+ Retry-After)
NOT_IMPLEMENTED501계약 고정·미구현(웹훅 CRUD·jitsuunso 등 STUB)
INTERNAL500내부 오류(현재 POST /v1/shipments stub 포함)

as-built 정합: ErrorCode union(server/src/types/index.ts)에 위 코드가 1:1 존재한다. NOT_IMPLEMENTED(501)는 스펙 표(401/403/404/422/429/500)에 더해 as-built에서 실재하는 스텁 코드다 — 계약에 명시한다.

4. JSON 예시 — 직렬화 계약

형상은 데이터 모델(data-model.html)의 3계층(Shipment→Stop→Event)·canonical_code와 1:1 정합한다. 캐리어 개인정보(드라이버 실명·番号板)는 화주 스코프에서 마스킹된다(SR-PII-001). eta_is_estimate는 D1의 0/1 정수를 API 계약에서 JSON boolean으로 정규화한다(shipmentJson).

4.1 Shipment 객체 — GET /v1/shipments/{id}

actual_carrier는 다단계 하청(元請→下請→孫請)에서 실시간 위치로 검증된 실운송 차량의 캐리어다(carrier.tier=PRIME/SUB1/SUB2/SUB3 + parent_carrier_id 체인). dwell_minutes: 143은 임계 120분 초과 → 荷待ち 예외(FR-ENG-EXC-002)로 잡힌다.

{
  "shipment_id": "SHP-2025-00456",
  "tenant_id": "TN-SHIPPER-KAO",
  "shipper_ref": "PO-98765",
  "mode": "TRUCK",
  "current_status": "IN_TRANSIT",
  "carrier":        { "carrier_id": "CR-PRIME-001", "name": "○○運輸 (元請)",   "tier": "PRIME" },
  "actual_carrier": { "carrier_id": "CR-SUB2-077",  "name": "△△急配 (孫請·실운송)", "tier": "SUB2" },
  "vehicle": { "vehicle_id": "VH-0231", "class": "MEDIUM", "plate": "品川 1*-**" },
  "driver":  { "driver_id": "DR-1180", "display_name": "佐**" },
  "planned_pickup_at":     "2025-05-15T09:00:00+09:00",
  "planned_delivery_at":   "2025-05-15T17:00:00+09:00",
  "predicted_delivery_eta":"2025-05-15T18:45:00+09:00",
  "eta_is_estimate": true,
  "stops": [
    { "stop_id": "ST-0456-1", "sequence": 1, "type": "PICKUP",
      "geofence_id": "GF-KOTO-DC-001", "address": "東京都江東区辰巳3-2-1",
      "planned_arrival_at": "2025-05-15T09:00:00+09:00",
      "actual_arrival_at":  "2025-05-15T09:12:00+09:00",
      "actual_departure_at":"2025-05-15T11:35:00+09:00",
      "dwell_minutes": 143 },
    { "stop_id": "ST-0456-2", "sequence": 2, "type": "DROPOFF",
      "geofence_id": "GF-OSAKA-CUST-014", "address": "大阪府吹田市...",
      "planned_arrival_at": "2025-05-15T17:00:00+09:00",
      "actual_arrival_at": null, "actual_departure_at": null, "dwell_minutes": null }
  ],
  "created_at": "2025-05-14T20:10:00+09:00"
}

타임스탬프는 ISO 8601 +09:00 오프셋 명시(DM-TS-001; 荷待ち 법정 계산 의존). as-built 주의: 현재 GET /:idcarrier/vehicle/driver join + PII 마스킹이 TODO(PARTIAL) — Shipment 행만 직렬화한다.

4.2 Tracking 스냅샷 — GET /v1/shipments/{id}/tracking

추적 링크·외부 위젯이 폴링하는 "지금 한 장면". 라이브 DO 우선, 콜드/부재 시 D1 투영 + ETA(공용 빌더 buildSnapshot; 배치 /tracking과 공유). staleness_seconds(마지막 핑 경과)·tracking_rate(추적 커버리지)를 정직하게 노출한다 — 스마트폰 GPS 한계를 숨기지 않는 원칙(KPI-TRACK-001).

{
  "shipment_id": "SHP-2025-00456",
  "status": "IN_TRANSIT",
  "as_of": "2025-05-15T14:30:05+09:00",
  "position": {
    "lat": 35.1702, "lon": 136.8816, "h3_r10": "8a4f1d2a3b07fff",
    "heading_deg": 248, "speed_kmh": 82,
    "captured_at": "2025-05-15T14:29:50+09:00",
    "staleness_seconds": 15
  },
  "next_stop": {
    "stop_id": "ST-0456-2", "type": "DROPOFF",
    "eta": "2025-05-15T18:45:00+09:00", "eta_is_estimate": true,
    "promised": "2025-05-15T17:00:00+09:00", "delay_minutes": 105
  },
  "current_dwell": null,
  "tracking_rate": 0.93
}
정직 노출 + as-built. 최종 고객(受取人) 스코프에서는 position이 생략되고 ETA만 노출된다(個人情報保護法 — SR-PII-001; Phase 1엔 consignee 역할 미존재). staleness_seconds는 console 폴링 예산(핀 >60s = stale 표시, >300s = dropNFR-PERF-003b)을 구동한다. 주의: tracking_rate는 계약 필드이나 Phase 1 미산출(정직한 unknown — 기대 대비 수신 핑 cadence 계산은 후속, buildSnapshot 주석). current_dwell도 현재 항상 null이다.

5. WebSocket 실시간 프로토콜 — IR-WS-001

IR-WS-001 AsyncAPI WebSocket 계약(Flutter 단일-shipment 뷰 전용) P1·ShouldPhase 1T 테스트

요구. 시스템은 단일 화물 실시간 뷰를 위해 채널 /v1/shipments/{id}/ws(Durable Object 백엔드)를 AsyncAPI 문서로 기술하고, 메시지 타입·인증 핸드셰이크·heartbeat·reconnect·화주 스코프 마스킹을 계약으로 고정해야 한다(MUST). 이 채널은 UI 레이어 전용이며 외부 시스템 연동으로 노출하지 않는다(외부는 REST/웹훅).

형상. 서버→클라이언트 메시지 타입: position_update(좌표·heading·speed·captured_at·staleness_seconds; Tracking 스냅샷의 position 형상과 동형) · status_change(canonical current_status 전이). 인증은 핸드셰이크 시 토큰(?token= 또는 첫 프레임)으로 검증 후 테넌트/스코프 스코핑. heartbeat(주기 ping/pong)와 reconnect(끊김 시 클라 재접속) 규약 포함. 화주 스코프에서 position 마스킹 규칙(受取人=ETA만)은 REST와 동일하게 적용.

수용기준

  • Given 유효 토큰으로 /v1/shipments/{id}/ws 핸드셰이크 When 차량 위치 핑이 인제스트 Then 대시보드 broadcast까지 p95 ≤ 1.5s, p99 ≤ 3s(NFR-PERF-003) 내 position_update가 푸시된다.
  • Given 무효/만료 토큰 When 핸드셰이크 Then 연결이 거부된다(401 동등).
  • Given 受取人(consignee) 스코프 When position_update 발생 Then position이 마스킹되고 ETA만 전달된다.
  • Given 연결 끊김 When reconnect Then heartbeat로 생존을 확인하고 마지막 상태를 재동기화한다.
근거 techspec delivery.md §실시간 지도·설계 원칙(WS=UI 전용) · ADR-0010(Flutter 단일-shipment=WS, console 플릿=6s 폴링) · 구현 ShipmentDO=DONE(서버 측 DO 동작); Flutter ShipmentWsClient=STUB($wsBaseUrl/v1/shipments/$id/ws 경로만, auth/reconnect 없음) · 검증 DO broadcast 통합 테스트

6. 웹훅 카탈로그 — IR-WH-001

IR-WH-001 웹훅 이벤트 계약 — 서명·멱등·재시도·구독 모델 P0·MustPhase 1T 테스트

요구. 이벤트 발생 시 화주 시스템에 HTTP POST하고(발송·재시도는 Queues notify가 담당), 각 POST에 표준 전달 헤더를 붙이며, 수신자가 서명을 검증하고 Event-Id멱등 처리할 수 있도록 계약을 고정해야 한다(MUST). 구독 모델(webhook_subscription·webhook_delivery)을 위한 0004 마이그레이션 신설을 요구한다.

구독 가능한 type(7종). canonical 이벤트(DM-EVT-ENUM-001)와 정합: SHIPMENT_ARRIVED_PICKUP · PICKUP_COMPLETED · SHIPMENT_ARRIVED_DELIVERY · SHIPMENT_DELIVERED · SHIPMENT_EXCEPTION(지연·荷待ち 초과·추적 손실 등 data.canonical_code로 세분) · DWELL_THRESHOLD_EXCEEDED · TEST(POST /v1/webhooks/{id}/test 발송).

수용기준

  • Given 구독한 type의 이벤트 발생 When notify 큐가 전달 Then 첫 시도 또는 재시도 내 2xx 비율 ≥ 99.0% / 28일(NFR-RELY-001), 발신 타임아웃 5s hard.
  • Given 수신자가 signed = "{X-LogiNippon-Timestamp}." + raw_body로 HMAC-SHA256 계산 When X-LogiNippon-Signaturev1과 상수시간 비교 Then 일치 시 수락, 타임스탬프 윈도 ±300s 초과 시 거부(replay 방지).
  • Given 같은 X-LogiNippon-Event-Id가 두 번 도착(at-least-once) When 수신자가 처리한 id 기록 Then 중복은 무시된다(멱등).
  • Given 전달 실패 When 재시도 래더 소진(8회) Then 구독을 disabled로 표시하고 대시보드 알림 + 재활성 경로 제공.
  • Given 이벤트가 순서 뒤바뀜 When 수신자 처리 Then occurred_at 기준 정렬(더 오래된 status로 덮어쓰지 않음).
근거 techspec delivery.md §웹훅 · FR-DLV-WH-001(재시도 래더·HMAC 권위) · 구현 notify 큐 handleNotifyBatch=STUB(ack-only; 구독 테이블·endpoint_secret·HMAC POST·전달상태 없음), 웹훅 CRUD=501; 0004 마이그레이션=ABSENT · 검증 서명·멱등·재시도 통합 테스트

6.1 웹훅 페이로드

{
  "id": "evt_01HF8Z9Q3K7M2N",
  "type": "SHIPMENT_EXCEPTION",
  "api_version": "2026-05-31",
  "occurred_at": "2025-05-15T14:30:00+09:00",
  "shipment_id": "SHP-2025-00456",
  "data": {
    "canonical_code": "LATE_DELIVERY_PREDICTED",
    "severity": "HIGH",
    "predicted_eta": "2025-05-15T18:45:00+09:00",
    "promised_eta":  "2025-05-15T17:00:00+09:00",
    "delay_minutes": 105,
    "current_location": { "lat": 35.1702, "lon": 136.8816 }
  }
}

6.2 전달 헤더

헤더용도
X-LogiNippon-Signaturet=1747287000,v1=5d41402a...HMAC-SHA256({timestamp}.{raw_body}, endpoint_secret)
X-LogiNippon-Timestamp1747287000서명 대상 타임스탬프(replay 방지, 허용 윈도 ±300s)
X-LogiNippon-Event-Idevt_01HF8Z9Q3K7M2N멱등성 키(data.id와 동일)
X-LogiNippon-Deliverydlv_01HF...이 전달 시도의 고유 ID(재시도마다 다름)
X-LogiNippon-Webhook-Idwh_01HF...구독 ID
Content-Typeapplication/json

6.3 재시도 래더 · 멱등 · 순서

지수 백오프 래더(초): [0, 60, 300, 1800, 7200, 21600, 43200, 86400]8회, 최대 전달수명 24h, 8연속 실패 시 auto-disable + 대시보드 재활성(FR-DLV-WH-001notify max_retries=8과 정합). 전달은 at-least-once(같은 id가 두 번 올 수 있음, 재시도는 같은 id·다른 X-LogiNippon-Delivery). 성공 조건: 수신자 2xx를 5초 내; 그 외(타임아웃·5xx·연결 실패)는 실패로 재시도. 순서 보장 없음 — 수신자는 occurred_at 기준으로 정렬·판단한다.

8회
재시도 횟수(max_retries)
24h
최대 전달 수명
±300s
서명 replay 윈도
5s
발신 타임아웃 hard
구독 모델 신설 요구. 웹훅 구독·전달 상태를 영속화하려면 0004 마이그레이션(webhook_subscription: 구독별 endpoint_secret·구독 type·상태; webhook_delivery: 시도/상태 succeeded/failed/disabled)이 신설되어야 한다(현재 마이그레이션은 0001_init·0002_auth·0003_geofence_membership까지만 존재). 전진전용 expand-first 마이그레이션 거버넌스는 pipeline-ops.html을 따른다.

7. 외부 인터페이스 — IR-EDI-001 · IR-TELE-001 · IR-EXT-001

IR-EDI-001 EDI 214 상태 통보 어댑터(인바운드/아웃바운드) P2·CouldPhase 2A 분석

요구. 대형 화주 연동을 위해 EDI 214(Transportation Carrier Shipment Status Message) 어댑터를 권장(SHOULD)한다 — 인바운드 상태를 source_type=EDI_X12(또는 EDIFACT) 이벤트로 정규화하고, 아웃바운드로 화주 시스템에 상태를 반환한다. 소스 정밀도는 EDI_X12(HIGH)(DM-EVT-PREC-001)로 위치 기반(GEOFENCE/APP_GPS=MED)보다 우선.

수용기준

  • Given EDI 214 메시지 수신 When 어댑터 정규화 Then canonical_code로 매핑되어 이벤트 타임라인에 정합 삽입(미매핑 <1%/일, KPI-NORM-001).
근거 techspec delivery.md §알림(EDI 214 반환, 어댑터 Phase 2+) · 구현 ABSENT(SourceType union에 EDI_X12/EDIFACT 자리만 존재) · 검증 매핑 정확도 매트릭스 · GS1 흡수는 OD-008
IR-TELE-001 텔레매틱스 인제스트 인터페이스(차재기·디지타코) P2·CouldPhase 2A 분석

요구. 차재 텔레매틱스(디지털 타코그래프·차재 단말)에서 위치/주행 데이터를 source_type=TELEMATICS(정밀도 MED)로 수집하는 인터페이스를 권장(SHOULD)한다 — 스마트폰 GPS 미보유 차량의 tracking rate(KPI-TRACK-001 ≥85%) 보강 경로.

수용기준

  • Given 텔레매틱스 위치 스트림 When 인제스트 Then PositionPing 계약으로 정규화되어 동일 dedup·지오펜스 파이프라인을 탄다.
근거 techspec acquisition.md(다소스 수집) · 구현 ABSENT(SourceType=TELEMATICS 자리만) · 검증 인제스트 계약 적합성

7.1 외부 IF 요약 — IR-EXT-001

우리가 소비하는 외부 인터페이스(아웃바운드 의존). 인증 시크릿은 server에 바인딩되어 있다(MAPS_API_KEY·JMA_API_KEY·LINE_CHANNEL_TOKEN).

외부 IF용도시크릿/바인딩구현상태신뢰도
Google Maps Platform거리·교통(룰 ETA FR-ENG-ETA-001), 지도 렌더(일본 도로·일본어 우선)MAPS_API_KEYABSENT(시크릿만, 호출 미배선)설계
国土地理院 타일지도 대안(무료·고정밀 국내 타일)—(공개 타일)ABSENT추정
JMA(気象庁)기상 데이터(ETA·예외 보정 입력)JMA_API_KEYABSENT(시크릿만)설계
LINE / LINE Works운영팀 실시간 예외 알림(1순위 채널 — 일본 B2B 현장 지배적)LINE_CHANNEL_TOKENSTUB(notify kind:'line' 큐 자리, 발송 미구현)확인
RR-LEGAL 플래그(미확인 규제 사실). EDI 214·実運送体制管理簿 등 규제 출력의 공식 제출 포맷·필드 사양은 법무 확인이 필요하다(미확정). 公式 포맷 동결 전까지 IR-EDI-001·jitsuunso 계약의 필드 매핑은 잠정이며, 법무 서명 플래그 RR-LEGAL-001을 따른다. CSV 인코딩(Shift_JIS vs UTF-8) 법무 결정은 OD-004.

근거·상호참조