규제 출력 명세 (RR-*) — 킬러 피처
이 문서는 LogiNippon의 진입 쐐기인 규제 출력(規制 出力)을 외부 감사가 가능한 구체 산출물 명세로 고정한다. 規制를 "도입 이유"로 외부에서 생성하는 전략(전략 2 — 규제를 킬러앱으로)을, 実運送体制管理簿·荷待ち 기록·구속시간 데이터의 컬럼·집계·인코딩·리포트 생명주기·provenance로 전환한다. 모든 수치는 마스터 정규화표(§4)에서 그대로 인용한 진입 단계 초기 확정치이며, 운영 베이스라인으로 분기 조정한다. 規制 포맷 자체가 공식 미확정인 항목은 RR-LEGAL-001 법무 서명 플래그로 묶는다. 이 페이지의 합격선은 단 하나 — "수기(手記) 작성을 대체한다"를 체크 가능한 수용기준으로 만든다.
1. 왜 킬러 피처인가 — 시장이 도입 이유를 만든다
일반 트래킹 SaaS는 화주가 "왜 도입하나"를 스스로 정당화해야 한다(H1 — 화주의 지불 의사는 부분 검증). 規制 출력은 그 정당화를 법이 외부에서 생성한다: 안 하면 행정지도·벌금이라 "도입 이유"가 시장 밖에서 온다. 이것이 Research/landscape-map의 화이트스페이스("規制 대응 × 실시간 가시성 × 다단계 하청 관통")로 들어가 MOVO(3.2만 거점·80만 드라이버 ID·バース 6년 1위) 같은 선점 사업자와 정면 경쟁을 회피하는 쐐기다.
3개 規制 산출물의 as-built 완성도는 다음과 같다. 이 페이지의 요구사항 카드는 이 격차를 닫는 명세다.
| 規制 산출물 | 법적 근거 | RR-ID | as-built 구현상태 |
|---|---|---|---|
| 荷待ち 기록(NIMACHI_RECORD) | 物流効率化法 2026.4 · 荷待ち 2h 목표 | RR-NIMACHI-001 | DONE CSV end-to-end |
| 実運送体制管理簿(JITSUUNSO_KANRIBO) | 改正物流法 2025.4 · 元請 의무 | RR-JITSUUNSO-001 | STUB 501(청부체인+검증 미구현) |
| 구속시간 데이터(KOSOKU_TIME) | 2024년 문제 · 연 3,400h/960h | RR-KOSOKU-001 | PARTIAL 타임스탬프 원천만 |
2. 実運送体制管理簿 — 청부 계층 × 위치 검증
改正物流法(2025년 4월)은 元請에게 "실제로 화물을 운반하는 사업자"를 기록하는 実運送体制管理簿 작성을 의무화한다 확인. 우리는 데이터 모델의 청부 계층(DM-SCHEMA-001)에서 이를 자동 구성한다 — carrier.tier(PRIME/SUB1/SUB2/SUB3 = 元請/下請/孫請...)와 carrier.parent_carrier_id(위탁 상위) 체인을 따라 올라가며, 마지막 단의 실운송 사업자를 actual_carrier로 식별한다. 여기에 위치 핑이 실제로 도착한 차량을 결합해 "장부상 실운송"과 "물리적 실운송"을 일치시킨다.
2.1 필수 컬럼 (改正物流法 기재 항목 기준 — 공식 포맷 미확정)
| 실운송체제관리부 항목 | 우리 데이터 원천(verbatim) | 비고 |
|---|---|---|
| 실운송 사업자 명칭 | carrier.name (실운송 단 = tier 체인 최하위 actual_carrier) | 외부 노출 시 화주 스코프 마스킹(SR-PII-001) |
| 청부 계층(元請/下請/孫請) | carrier.tier + carrier.parent_carrier_id 체인 | CHECK 제약: PRIME/SUB1/SUB2/SUB3 |
| 실제 운송 차량 | 실시간 위치로 검증된 actual_carrier / vehicle.vehicle_id | "장부 ≠ 물리" 불일치 탐지의 핵심 |
| 운송 기간(period) | regulatory_report.period_start / period_end | JST 자정 경계(DM-TS-001) |
| 운송 화물 식별 | shipment.shipment_id · shipper_ref | 송り状番号 정규화 레이어 연결 |
요구. 시스템은 한 테넌트·기간에 대해 청부 계층(carrier.tier + carrier.parent_carrier_id 체인)을 元請→실운송 단까지 따라가 실운송 사업자 명칭·계층·실제 운송 차량·기간을 담은 実運送体制管理簿를 반드시 생성해야 한다(MUST). 각 행의 "실제 운송 차량"은 해당 화물에 실시간 위치 핑이 실제로 도착한 차량으로 검증되어야 한다(MUST) — 장부상 청부와 물리적 운송의 불일치를 표면화한다.
수용기준
- Given
tier=SUB2이고parent_carrier_id가 SUB1→PRIME으로 이어지는 화물, WhenGET /v1/reports/jitsuunso?from=&to=호출, Then 응답 산출물의 1행은 元請·下請·孫請 3단과 실운송(孫請) 사업자 명칭을 포함한다. - Given 어떤 화물의 실운송 단에 검증 핑이 0건, When 리포트 생성, Then 그 행은 "위치 미검증" 플래그가 표시되어 수기 대체용으로 그대로 제출 불가 상태를 명시한다(공란 위장 금지).
- Given 타 테넌트 화물, When 호출, Then 결과에 포함되지 않는다(
tenant_id스코프, 비노출 404 일관). - Given 공식 포맷 미확정, When 산출물 헤더 생성, Then RR-LEGAL-001 법무 확인 전까지 컬럼 집합을 改正物流法 기재 항목 기준 잠정안으로 명시(라벨 추정).
GET /v1/reports/jitsuunso는 현재 notImplemented(c) 501 STUB이다(server/src/routes/reports.ts). 데이터 토대(carrier.tier·parent_carrier_id 컬럼)는 마이그레이션 0001_init.sql에 존재하나, 청부 체인 순회 + 위치 검증 결합 로직이 미구현이다. regulatory_report.kind enum에는 이미 JITSUUNSO_KANRIBO가 예약되어 있다.
3. 荷待ち 기록 — as-built end-to-end
物流効率化法(2026.4 전면시행)은 荷待ち·荷役 상한 목표를 2시간으로 둔다 확인. 우리는 지오펜스 엔진이 측정한 stop.dwell_minutes(= actual_departure_at − actual_arrival_at)를 거점·운송·기간 차원으로 집계하고, 2시간 초과 건을 플래그한다. 이 산출물은 as-built에서 CSV end-to-end로 완성(server/src/lib/reports.ts buildNimachiReport() → R2 EXPORTS + D1 메타)되어, 規制 출력 중 유일하게 동작하는 킬러 피처다.
| 집계 차원 | 지표 | 원천 |
|---|---|---|
| 거점별(facility) | mean + p90 체류, 2시간 초과 건수 | geofence.name JOIN |
| 운송별(carrier) | 캐리어 스코어카드 입력(荷待ち 개선 협상 근거) | shipment.carrier_id |
| 기간별(period) | 일/월 롤업(Cron 자동 생성) | regulatory_report.period_start/end |
| 초과 플래그 | dwell_minutes > threshold → exceeded=1 | 임계 기본 120분(테넌트 override) |
as-built CSV 컬럼(verbatim, reports.ts 헤더): shipment_id, facility, stop_type, actual_arrival_at, actual_departure_at, dwell_minutes, threshold_min, exceeded. 임계는 행별 geofence.dwell_threshold_min ?? 120으로 평가한다.
요구. 시스템은 stop.dwell_minutes를 거점·운송·기간 차원으로 집계하고, 각 거점에 대해 평균(mean)과 p90을 산출하며, 법정 임계 120분(FR-ENG-EXC-002 荷待ち 초과; geofence.dwell_threshold_min 테넌트 override)을 초과한 건을 반드시 플래그해야 한다(MUST). 산출물은 Excel(JP)이 日本語 시설명을 깨짐 없이 여는 인코딩이어야 한다(RR-CSV-001).
수용기준
- Given
dwell_minutes=143이고 임계 120인 stop, When 荷待ち 리포트 생성, Then 그 행은threshold_min=120ANDexceeded=1로 표기된다. - Given 한 거점의 dwell 분포, When 집계, Then 출력은 mean과 p90을 함께 노출한다(평균만으로 꼬리를 숨기지 않음).
- Given
captured_at오프셋이 +09:00 외로 혼재, When 기간 필터, Thendatetime()정규화로 JST 자정 경계 비교가 정확하다(DM-TS-001). - Given 같은 (tenant, from, to) 재요청, When 생성, Then 결정적
report_id/r2_key로 누적 없이 덮어쓴다.
buildNimachiReport()는 행 단위 CSV(거점별 mean/p90 집계 컬럼은 미산출)를 출력한다. mean+p90 집계 차원은 본 요구사항이 추가하는 명세 항목(분석 리포트 RR-NIMACHI 확장)이며, 행 데이터에서 산출 가능하므로 설계로 둔다. CSV 셀은 OWASP formula-injection 가드(=+-@ 접두 시 ' 무력화)를 이미 적용한다.
4. 구속시간 데이터 — 보조 데이터(전용 노무관리 아님)
2024년 문제는 트럭 드라이버 연간 구속시간 상한 3,400시간, 시간외 노동 상한 960시간(형사처벌)을 도입했다 확인. 우리는 전용 노무관리 시스템을 대체하지 않는다 — 운행·체류 타임스탬프를 구속시간 산정의 객관적 보조 데이터로 제공한다. 원천은 event.occurred_at(운행·도착·출발), stop.actual_arrival_at/actual_departure_at(체류), 그리고 그 차분으로서의 dwell_minutes이다. 데이터는 5년 보존(RET-EVENT-001 분쟁/規制)을 따른다.
요구. 시스템은 드라이버/차량별 운행·체류 타임스탬프(event.occurred_at, stop.actual_arrival_at/actual_departure_at)를 연 3,400h/시간외 960h 상한 맥락에서 검토 가능한 구속시간 보조 데이터로 권장 출력한다(SHOULD). 이는 노무관리 산정의 객관 입력이지 산정 자체가 아님을 산출물에 명시해야 한다(MUST — 책임 경계).
수용기준
- Given 한 드라이버의 한 기간 운행, When 구속시간 데이터 export, Then 각 운행의 시작·종료·각 거점 체류(분)가 결손 없이 타임스탬프로 노출된다.
- Given 산출물, When 헤더/주석 생성, Then "전용 노무관리 대체 아님, 보조 데이터" 고지와 3,400h/960h 맥락 라벨을 포함한다.
- Given 타임스탬프 결손 행, When 집계, Then 누락이 명시되어 구속시간이 과소 산정되지 않도록 경고한다.
5. CSV 인코딩 결정 — Excel-JP vs 監督官庁
規制 산출물은 두 소비자가 충돌하는 인코딩 요구를 갖는다: 화주가 Excel(JP)로 여는 일상 운영은 UTF-8 BOM + CRLF가 日本語를 깨짐 없이 연다. 반면 일부 監督官庁(감독관청) 제출 양식은 여전히 Shift_JIS를 전제할 수 있다. as-built 코드는 전자(UTF-8 BOM + CRLF)를 채택했다(reports.ts toCsv() — '' + lines.join('\r\n')).
| 소비자 | 인코딩 | 판정 |
|---|---|---|
| 화주 일상 운영(Excel-JP) | UTF-8 BOM + CRLF | as-built 기본 DONE |
| 監督官庁 공식 제출 | Shift_JIS(양식 의존) | 법무 확인 전 미정 추정 |
요구. 시스템은 規制 CSV를 기본 UTF-8 BOM + CRLF로 생성해야 한다(MUST — Excel-JP 호환). 監督官庁 제출 양식이 Shift_JIS를 요구함이 법무로 확인되면, 그 산출물에 한해 Shift_JIS 변형을 권장 추가한다(SHOULD). 어떤 변형이든 셀 formula-injection 가드(^[=+\-@\t\r] 접두 ')와 RFC-4180 인용 규칙을 유지해야 한다(MUST).
수용기준
- Given 日本語 시설명("○○物流センター"), When 화주가 Excel-JP로 산출 CSV를 연다, Then 文字化け(모지바케) 없이 표시된다(BOM 검증).
- Given 셀 값이
=cmd로 시작, When CSV 생성, Then 셀은'=cmd로 무력화되어 수식 실행되지 않는다. - Given 監督官庁 양식이 Shift_JIS 요구로 확인(법무), When 해당 kind 생성, Then Shift_JIS 변형이 동일 행 데이터로 제공된다(미확인 시 기본 UTF-8 유지).
6. 리포트 생명주기 — 상태머신 · 메타 · 서명 URL
規制 리포트는 비동기 생성·저장·전달의 생명주기를 갖는다. D1 regulatory_report 테이블이 메타데이터(verbatim 컬럼: report_id, tenant_id, kind, period_start, period_end, r2_key, generated_at)를, R2 EXPORTS 버킷이 실제 파일을 담는다(egress 무료라 화주·監督官庁이 반복 다운로드해도 비용 0). 생성은 Cron이 트리거한다: 일 리포트 0 17 * * *(=02:00 JST 荷待ち), 월 롤업 0 19 1 * *(=04:00 JST 1일). 다운로드는 R2 서명 URL로 서빙하며 TTL 300s(FR-RPT-RANGE-001 정합).
요구. 규제 리포트는 명시적 상태머신 PENDING → READY → FAILED를 가져야 한다(MUST): Cron/요청이 생성을 시작하면 PENDING, R2 PUT + D1 메타 커밋 성공 시 READY, 집계·PUT 실패 시 FAILED(사유 기록). 메타는 D1 regulatory_report(kind ∈ {JITSUUNSO_KANRIBO, NIMACHI_RECORD, KOSOKU_TIME})에 저장하고, 파일은 R2 EXPORTS에 r2_key로 저장한다(MUST). 다운로드는 TTL 300s 서명 URL로만 노출한다(MUST — FR-RPT-RANGE-001 정합).
수용기준
- Given 생성 시작, When R2 PUT + D1 INSERT 성공, Then 상태=READY이고
generated_at이 채워지며 다운로드 URL이 반환된다. - Given 집계 중 예외, When 생성, Then 상태=FAILED로 기록되고(반쪽 산출물을 READY로 노출하지 않음), Cron 루프는 타 테넌트로 계속 진행한다.
- Given Cron
0 17 * * *발화, When 전 테넌트 순회, Then 각 테넌트의 전일(JST) 荷待ち 리포트가 R2+D1에 적재된다. - Given READY 리포트, When 다운로드 요청, Then 서명 URL TTL 300s가 적용되어 만료 후 접근 불가하다.
regulatory_report 스키마(0001_init.sql)에는 상태 컬럼이 없다 — 성공 시 INSERT/UPSERT만 일어난다(즉 사실상 READY만 존재). PENDING/FAILED 상태를 표면화하려면 마이그레이션 추가(전진전용 expand-first — OPS)가 필요하다. 또한 다운로드는 현재 워커가 R2 객체를 직접 스트리밍하는 방식(obj.body 응답)으로, "TTL 300s 서명 URL 리다이렉트"는 본 요구사항이 고정하는 명세이며 구현은 설계다.
7. Provenance — 집계 → 원천 이벤트 추적성
監督官庁 제출물은 감사를 견뎌야 한다: "이 荷待ち 통계의 어느 행이 어느 event/stop에서 나왔는가"를 되짚을 수 있어야 한다. regulatory_report는 집계 산출물이므로, 산출물의 각 행과 그것을 구성한 원천 이벤트·stop 사이의 FK 추적 링크가 필요하다. 이는 데이터 모델의 provenance 요구(FR-PROV-001)를 規制 출력 맥락으로 특화한 것이다.
요구. 규제 리포트의 각 집계 행은 그것을 구성한 원천(stop.stop_id / shipment.shipment_id / 관련 event.event_id)으로 되짚을 수 있어야 한다(MUST). 시스템은 어느 stop·event가 어느 regulatory_report 집계에 들어갔는지 감사 추적(audit trail)을 제공해야 한다(MUST). 荷待ち CSV는 이미 행 단위로 shipment_id를 노출하므로 행→화물 역추적이 가능하다.
수용기준
- Given 한 荷待ち 리포트 행, When 감사자가 출처를 질의, Then 그 행의
shipment_id·stop(arrival/departure)·임계가 원천stop/event로 결정적으로 연결된다. - Given 동일 (tenant, from, to) 재생성, When 원천 이벤트가 불변(immutable, DM-SCHEMA-001), Then 재생성 산출물이 이전과 동일하다(재현성 = 감사 신뢰).
- Given 집계에 포함된 stop, When 추적, Then 누락·중복 없이 1:1 매핑이 검증된다.
8. 법무 확인 플래그 + 화이트스페이스 결합
規制 사실에는 라벨(확인/추정)을 붙이되, 공식 제출 포맷·인코딩 같은 규범적 형식이 미확정인 항목은 단일 법무 서명 게이트로 묶는다. 이는 "법으로 의무화됨"(확인)과 "어떤 양식으로 제출하느냐"(미확정)를 분리해, 엔지니어링이 잘못된 포맷을 사실처럼 출하하지 않게 한다.
요구. 규제 산출물의 공식 형식이 미확정인 모든 항목(実運送体制管理簿 공식 컬럼 집합, 監督官庁 제출 인코딩/양식, 보존기간 법정 최소)은 출시 전 법무 서명을 받아야 한다(MUST). 법무 확인 전 산출물은 라벨 추정으로 표시되고 "공식 제출 가능"으로 광고되지 않는다(MUST).
수용기준
- Given 実運送体制管理簿 컬럼 집합, When 출시 게이트 점검, Then 改正物流法 公式 기재 항목과 대조한 법무 확인 기록이 존재한다(없으면 추정 유지).
- Given CSV 인코딩(RR-CSV-001·OD-004), When 監督官庁 제출 경로 활성화, Then Shift_JIS/UTF-8 결정이 법무로 확정되어 있다.
- Given 보존기간, When RET-* 적용, Then 規制 산출물 7년(RET-REG-001)이 법정 최소로 법무 서명되어 있다.
8.1 화이트스페이스 결합 — "수기 작성을 대체"의 합격선
이 페이지의 모든 요구사항은 하나의 검증으로 수렴한다: 운영자가 実運送体制管理簿·荷待ち 기록을 수기로 작성하던 작업을, 우리 산출물이 그대로 대체하는가. 다단계 하청을 관통하는 위치 검증이 이 대체를 단순 양식 자동화기와 구별 짓는다(Research/landscape-map 화이트스페이스). 합격선 체크리스트:
| 수기 작업 | 우리 대체 | "대체됨" 체크 |
|---|---|---|
| 元請이 청부 계층을 손으로 적음 | RR-JITSUUNSO-001 청부 체인 자동 구성 | 3단 체인 + 실운송 단 명칭이 자동 채워짐 |
| 실제 운송 차량을 신고에 의존 | 실시간 위치로 검증된 actual_carrier | 장부≠물리 불일치가 플래그됨 |
| 荷待ち를 운전일보에 수기 기록 | RR-NIMACHI-001 dwell_minutes 자동 집계 | 2h 초과 건이 exceeded=1로 자동 표기 |
| Excel에 붙여 月次 제출 양식 작성 | RR-CSV-001 Excel-JP 호환 CSV + RR-LIFECYCLE-001 Cron 자동 생성 | 일/월 자동 생성, 다운로드 즉시 |
| "이 수치 어디서 나왔나" 감사 대응 | RR-PROV-001 원천 추적 | 행→stop/event 역추적 가능 |
근거·상호참조
- techspec(설계): 05-delivery-layer/delivery.md §규제 출력 — 킬러 피처(実運送体制管理簿·荷待ち 기록·구속시간·생성·전달)
- techspec(전략): 06-product/strategy.md §전략 2 — 규제를 킬러앱으로, 선점 사업자(MOVO) 회피, H1~H4 가설 검증
- techspec(데이터): 02-data-model/model.md — 청부 계층(
carrier.tier/parent_carrier_id)·regulatory_report메타·provenance - 코드(as-built, DONE):
server/src/lib/reports.ts—buildNimachiReport(),csvCell()/toCsv()(UTF-8 BOM+CRLF, formula-injection 가드) - 코드(as-built):
server/src/routes/reports.ts—/v1/reports/nimachi(DONE)·/v1/reports/jitsuunso(501 STUB)·/:report_id/download - 코드(as-built):
server/src/consumers/cron.ts—0 17 * * *(일)/0 19 1 * *(월) 規制 리포트 생성 - 코드(스키마):
server/migrations/0001_init.sql—carrier(tier CHECK PRIME/SUB1/SUB2/SUB3)·regulatory_report(kind CHECK)·stop.dwell_minutes - Research(시장 근거): Research/implications-for-us · landscape-map · japan-market — 규제 킬러앱·화이트스페이스·2024년 문제
- TRD 상호참조 — 요구사항: FR-RPT-NIMACHI-001, FR-RPT-JITSUUNSO-001, FR-RPT-KOSOKU-001, FR-RPT-RANGE-001, FR-ENG-EXC-002, FR-PROV-001
- TRD 상호참조 — 데이터·보안·운영: DM-SCHEMA-001, DM-TS-001, SR-PII-001, RET-EVENT-001 · RET-REG-001, OD-004, pipeline-ops
- TRD 상호참조 — 제품: strategy-risk(전략 2·R2 MOVO), KPI-DWELL-001