미해결 결정 · RFC 백로그 (OD-*)
이 페이지는 본 TRD가 아직 닫지 못한 결정을 표면화하고, 결정 가능한 것은 추천을 명시하며, 외부(법무·파트너·관청) 의존이 남은 것은 그 의존을 명시한다. 각 미해결 결정(OD-*)은 상태·옵션·추천·영향·차단되는 요구사항·오너·기한을 한 표로 고정한다. flagship 결정은 OD-001 — 대시보드 아키텍처 모순의 해소(ADR-0010)로, 본 TRD가 추가하는 6번째 항목(Svelte console vs Flutter Web 대시보드 모순 해소)을 정규 텍스트로 제시한다. 여기 등장하는 모든 수치는 NFR 페이지·SLO 카탈로그가 소유한 진입 단계 초기 확정 목표(설계)이며, 운영 베이스라인으로 조정한다 — 달성치는 기재하지 않는다.
읽는 법. "추천"은 본 TRD가 내부적으로 결정 가능하다고 판단한 방향이다. "외부의존"으로 표시된 결정은 추천을 제시하되 최종 확정 권한이 우리에게 없음을 분명히 한다(법무·파트너·監督官庁). 차단되는 요구사항은 상대 링크로 가리키며, 본 페이지는 그 ID를 재정의하지 않는다. 상태 배지는 해소-제안(Proposed-Resolved) / 조사중 / 차단(외부의존)로 구분한다.
OD-001 · 대시보드 아키텍처 — ADR-0010 (해소-제안)
본 TRD의 flagship 결정이다. ADR-0003 (제품 앱으로 Flutter)은 "드라이버 앱 = Flutter 네이티브, 화주 대시보드 = Flutter Web"으로 결정했으나(상태: 채택됨, 2026-05-31), as-built는 정반대 상태에 있다 — 채택된 Flutter Web 대시보드는 미구현(app/lib/.../main_dashboard.dart 비동작 placeholder)인 반면, 미채택의 Astro+Svelte console은 실제 동작하는 컨트롤 타워다. ADR-0010은 이 "채택된 것은 미구현, 동작하는 것은 미채택"의 모순을 해소한다.
결정(제안·해소). Astro+Svelte console 레포를 운영자/운송사 컨트롤 타워(실시간 플릿 맵·shipments·규제 리포트·프로비저닝)로 공식 채택하고, 화주는 console 내 SHIPPER_VIEWER 읽기전용 + CustomerTrack(추적 링크)로 커버한다. ADR-0003의 "화주 대시보드=Flutter Web"은 드라이버 앱 전용(Flutter=드라이버 + 선택적 최소 화주 모바일 뷰)으로 재범위화(amend)한다.
근거. console(Astro 6.4·Svelte 5·MapLibre)이 실제로 동작하는 컨트롤 타워(4탭: map/ships/reports/issue, FleetMap 6s 폴링, nimachi 리포트)인 반면, Flutter app의 대시보드 엔트리(main_dashboard.dart)는 비동작 placeholder다. "채택된" 것은 미구현, 동작하는 것은 미채택 상태의 모순.
귀결. console에 거버닝 ADR + README 부여, 단일 @loginippon/contract 소비처를 console+server+Flutter로 통일, 프론트 로드맵 unblock. 실시간 전송 분리: Flutter 단일-shipment 뷰=WebSocket(NFR-PERF-003 p95 ≤ 1.5s, p99 ≤ 3s), console 플릿 개요=6s 폴링(NFR-PERF-003b 핀 >60s = stale 표시, >300s = drop). 상태: 해소-제안(Proposed-Resolved), 오너=아키텍트, 마이그레이션 노트 포함.
실시간 전송 분리(귀결 상세). 두 대시보드는 같은 진실원(D1·ShipmentDO)을 다른 전송 경로로 본다 — 둘을 혼동하지 않는 것이 ADR-0010의 핵심 운영 규약이다.
| 소비처 | 뷰 | 전송 | 지연 예산 (초기 확정치 설계) | as-built |
|---|---|---|---|---|
Flutter app | 단일 shipment 라이브 | WebSocket (ShipmentDO fan-out) | NFR-PERF-003 p95 ≤ 1.5s / p99 ≤ 3s | ShipmentWsClient stub (auth/reconnect 없음) STUB |
console (FleetMap) | 플릿 전체 개요 | 6s 폴링 (GET /v1/shipments/tracking) | NFR-PERF-003b >60s stale / >300s drop | 동작·하드의존 DONE |
마이그레이션 노트. ① console에 거버닝 ADR(ADR-0010)·README 신설(현재 부재) → 레포 권위 확정. ② console/src/lib/types.ts가 server 타입을 손으로 중복 중(파일 상단 // TODO: server 와 공유 패키지(@loginippon/contract)로 추출해 단일 소스화.) → @loginippon/contract 추출 후 console·server·Flutter 단일 소비. ③ Flutter main_dashboard.dart 화주 대시보드 야망 제거, 드라이버 앱 + 선택적 최소 화주 모바일 뷰로 재범위화. ④ ADR-0003 문서에 amend 주석 추가(상태는 "채택됨" 유지, 대시보드 범위만 ADR-0010이 상위 규정).
| 속성 | 값 |
|---|---|
| 상태 | 해소-제안 (Proposed-Resolved) |
| 옵션 | (A) ADR-0003 그대로 — Flutter Web 화주 대시보드 신규 구축 / (B·추천) console=컨트롤 타워 공식 채택, 화주=SHIPPER_VIEWER+CustomerTrack, Flutter=드라이버 전용 재범위화 / (C) 둘 병행 — 중복·계약 분기 비용 |
| 추천 | (B) — 동작하는 자산을 채택해 프론트 로드맵 unblock, 단일 계약으로 수렴 |
| 영향 | 프론트 전 레포 권위·로드맵; @loginippon/contract 단일화; 실시간 전송 이원화 정합 |
| 차단되는 요구사항 | NFR-PERF-003·NFR-PERF-003b(전송 경로 확정 전제), IR-WS-001(WS 계약), Flutter 드라이버 앱 unblock |
| 오너 | 아키텍트 |
| 기한 | Phase 1 진입 게이트 전(계약 동결과 함께) Phase 1 |
OD-002 · 브랜드 확정 — 'LogiNippon' 가칭 → 정식명
'LogiNippon'은 전 레포 가칭(working name)이다. web/src/config.ts는 의도적으로 단일 상수로 중앙화했으나(SITE.name = 'LogiNippon', 주석 "WORKING brand name (placeholder) … swapped in one place once the final name is set"), 그 외 레포에는 하드코딩이 흩어져 있어 단일 스왑으로 끝나지 않는다.
- web:
web/src/config.ts단일 상수(스왑 용이) +url: 'https://loginippon-web.pages.dev'·contactEmail: 'hello@loginippon.example'예시값. - console: 다수 하드코딩 —
console/src/components/LoginForm.svelte,console/src/components/ConsoleApp.svelte(헤더 라벨LogiNippon+ dev 로그인 키'loginippon-dev'),console/src/pages/index.astro(<title>LogiNippon — Control Tower</title>). - server:
server/wrangler.jsonc리소스명 하드코딩(name: "loginippon-server", D1loginippon, R2loginippon-proof/-exports/-gps-archive, 큐loginippon-geofence-eval등, Analyticsloginippon_metrics). 리네임 시 리소스명 변경은 마이그레이션(생성된 리소스명은 사후 변경 불가 → 신규 생성·데이터 이전 동반) → pipeline-ops 리소스 확정/리네임 체크리스트와 연동. - app(Flutter): 브랜드 팔레트
#1F5FA8계열 공유(주석 기준), 표시 문자열 하드코딩.
| 속성 | 값 |
|---|---|
| 상태 | 조사중 |
| 옵션 | (A) 'LogiNippon' 정식 채택 / (B) 신규 정식명 — 상표·도메인 가용성 확인 후 |
| 추천 | 정식명 확정 후 단일-스왑 경로 강제: 모든 표시 문자열을 web/config.ts 패턴처럼 상수화하고, 리소스명은 사전 출시에 확정. 출시 후 리네임은 리소스 마이그레이션 비용을 유발하므로 런치 전이 게이트. |
| 영향 | web·console·server·app 4레포 + wrangler 리소스명 + 도메인/이메일. 표시 문자열은 저비용, 리소스명은 고비용(이전). |
| 차단되는 요구사항 | 없음(기능 차단 아님) — 단, OD-005 리소스 프로비저닝과 동시 수행해야 이중 리네임 회피. |
| 오너 | 제품/창업 |
| 기한 | 사전 출시(프로비저닝 전) Phase 0 |
OD-003 · 토큰 저장 하드닝 — console localStorage → httpOnly 쿠키
console는 인증 토큰을 localStorage에 저장한다(console/src/lib/auth.ts 상단 // MVP: 토큰을 localStorage 에 둔다(웹). 후속에 httpOnly 쿠키+짧은 수명/회전으로 강화(07 보안).). localStorage 토큰은 XSS 시 탈취 가능(JS 접근 가능)하다. TTL 정책 자체는 FR-AUTH-001(access 3600s, refresh 2592000s 로테이션-only, KV revocation 전파 ≤60s)이 소유하므로 여기서는 저장 매체 전환만 다룬다. 정규 위협·저장 요구는 SR-TOKEN-STORE-001이 소유한다.
| 속성 | 값 |
|---|---|
| 상태 | 조사중 |
| 옵션 | (A) httpOnly + Secure + SameSite 쿠키(refresh) + 메모리 보관(access) / (B) localStorage 유지 + CSP·XSS 방어 강화 / (C) BFF 세션 프록시 |
| 추천 | (A) — refresh 토큰을 httpOnly 쿠키로, access는 메모리. 짧은 수명·회전(FR-AUTH-001 정합). sunset 일정: localStorage 경로는 (A) 배선 완료 시 제거. |
| 영향 | console 인증 플로우(console/src/lib/auth.ts·session.svelte.ts), server set-cookie 응답·CSRF 가드 추가 |
| 차단되는 요구사항 | SR-TOKEN-STORE-001(저장 하드닝), FR-AUTH-001(매체 무관 TTL은 별도) |
| 오너 | 보안 |
| 기한 | 화주(SHIPPER_VIEWER) 외부 노출 전(사전 출시) Phase 1 |
OD-004 · CSV 인코딩 — UTF-8 BOM vs Shift_JIS (監督官庁 포맷)
荷待ち 기록·実運送体制管理簿 CSV의 문자 인코딩이 미확정이다. 일본 행정·표계산(Excel) 관행상 Shift_JIS 또는 UTF-8 BOM 요구가 갈린다. 인코딩 규칙(RR-CSV-001)은 regulatory 페이지가 소유하며, 본 결정은 監督官庁 공식 포맷의 사실 확인에 의존한다. 그 사실은 아직 법무 서명 전이므로 RR-LEGAL-001 플래그를 단다 — 추정으로 확정하지 않는다.
| 속성 | 값 |
|---|---|
| 상태 | 차단 · 외부의존(법무·관청) |
| 옵션 | (A) UTF-8 BOM(Excel 더블클릭 호환) / (B) Shift_JIS(레거시 관청 호환) / (C) 양식별 선택 + 다운로드 시 인코딩 옵션 |
| 추천(잠정) | (A) UTF-8 BOM을 기본으로 하되, 監督官庁 공식 포맷이 Shift_JIS를 요구하는 것으로 법무 확인 시 (C)로 확장. 공식 포맷 확정 전에는 형식 고정 금지. |
| 영향 | server/src/lib/reports.ts CSV 직렬화, RR-CSV-001 수용기준 |
| 차단되는 요구사항 | RR-CSV-001, RR-LEGAL-001(공식 포맷 법무 확인), FR-RPT-NIMACHI-001 |
| 오너 | 규제/법무 (확정 권한 외부) |
| 기한 | 規制 리포트 외부 제출 개시 전 Phase 1 |
OD-005 · 리소스 프로비저닝 — wrangler placeholder ID 실 프로비저닝
server/wrangler.jsonc의 모든 Cloudflare 리소스 ID가 placeholder이며 미프로비저닝이다(파일 헤더 // IDs below are PLACEHOLDERS.). D1 database_id: "00000000-0000-0000-0000-000000000000", KV GEOFENCE_H3=0000000000000000000000000000000a·CONFIG=…000b·AUTH_KEYS=…000c, staging/production은 STAGING_DB_ID·PROD_DB_ID 등 토큰. 실 프로비저닝(wrangler d1 create / kv namespace create / r2 bucket create / queues create)과 인쇄된 ID 환경별 붙여넣기, 그리고 무료 티어 한도 대비 비용 재확인이 필요하다.
| 속성 | 값 |
|---|---|
| 상태 | 조사중 (사전 출시 게이트) |
| 옵션 | (A) dev/staging/prod 3환경 각각 독립 리소스 생성(현 wrangler 구조) / (B) dev=prod 공유(비권장, 격리 위반) |
| 추천 | (A) — 환경별 독립 D1/KV/R2/Queues(wrangler.jsonc env.staging/env.production 구조 그대로). 프로비저닝 직후 무료 티어 한도(NFR-COST-001) 대비 비용 재확인. |
| 영향 | 전 배포 파이프라인. OD-002(리네임) 미확정 시 리소스명을 두 번 만들게 되므로 OD-002와 동시 수행. |
| 차단되는 요구사항 | 모든 배포·OPS-*(3환경 토폴로지), NFR-COST-001 비용 가드레일 실측 기반 |
| 오너 | 플랫폼/운영 |
| 기한 | 사전 출시(OD-002 직후) Phase 0 |
OD-006 · 용량 베이스라인 — 런치 후 실측으로 스케일 트리거 확정
스케일·비용 트리거 수치는 현재 운영 데이터 없는 진입 단계의 초기 확정 목표(설계)다. NFR-SCALE-001(동시 활성 DO > 5,000 OR DO active-wall-time 월 임계 초과 → 종료 화물 D1 60s 폴링)과 NFR-COST-001의 임계는 런치 후 실측 pings/sec·D1 쓰기율로 검증·재조정해야 한다. 측정 평면이 전제이지만 현재 METRICS writeDataPoint가 TODO(SLI 미측정)이므로, 용량 베이스라인 확정의 선행 조건은 OBS-METRICS-001(메트릭 방출)이다.
| 속성 | 값 |
|---|---|
| 상태 | 조사중 (런치 후 실측 의존) |
| 옵션 | (A) 설계 트리거를 런치 후 실측으로 검증·고정 / (B) 부하 모델만으로 사전 확정(데이터 없이 — 비권장) |
| 추천 | (A) — 런치 후 28일 롤링 실측(pings/sec, D1 쓰기율, 동시 활성 DO)으로 NFR-SCALE-001·NFR-COST-001 임계를 확정. 명시적 개정 트리거로 관리. |
| 영향 | 스케일 정책·비용 알람 임계의 실효성. 측정 없이는 트리거가 "의도"에 머문다. |
| 차단되는 요구사항 | NFR-SCALE-001, NFR-COST-001 확정; 선행 OBS-METRICS-001 |
| 오너 | 플랫폼/운영 |
| 기한 | 런치 후 첫 분기 베이스라인 리뷰 Phase 2 |
OD-007 · 런타임 config 권위 — D1 vs KV CONFIG
런타임 설정의 권위 출처가 둘로 갈려 있다. KV CONFIG에 ETA 속도(고속 80 / 도심 30 / 기본 50 km/h)·추적손실 임계(45min)·dwell(120)·feature flag가 시드되었으나 런타임 미read이고, 실제로 dwell은 D1 geofence.dwell_threshold_min에서 읽힌다(server/migrations/0001_init.sql: dwell_threshold_min INTEGER NOT NULL DEFAULT 120, 荷待ち 법정 2시간, 테넌트 override). 즉 ETA 룰 파라미터는 KV에서 런타임 read되지 않고(코드 상수 사용), dwell은 D1 권위다. 어느 것이 권위인지 정리하고 feature flag read 경로를 배선해야 한다.
- 현 상태(as-built). ETA 속도/추적손실/dwell/flags 모두 KV
CONFIG에 시드 → 그러나 FR-ENG-ETA-001 룰 ETA는 KV에서 런타임 read하지 않음(현재 미read). dwell 임계만 D1geofence.dwell_threshold_min에서 실제 read(테넌트별 override가 D1에서 자연스러움). - 모순. 같은 값(dwell 120)이 KV·D1 양쪽에 존재 → 단일 권위 미정. feature flag는 read 경로 자체가 없음.
| 속성 | 값 |
|---|---|
| 상태 | 조사중 |
| 옵션 | (A) 테넌트-스코프(dwell 등 override 필요)=D1 권위, 글로벌 핫 파라미터(ETA 속도·flags)=KV 권위 / (B) 전부 KV로 통일 + D1은 캐시 / (C) 전부 D1로 통일 |
| 추천 | (A) — 테넌트 override가 필요한 값(dwell_threshold_min)은 D1 권위, 글로벌 ETA 룰 파라미터·feature flag는 KV CONFIG 권위 + 런타임 read 경로 배선. KV 중복 dwell 시드는 제거하거나 D1 부트스트랩 시드로만 사용. |
| 영향 | server/src/lib ETA·config read 경로, feature flag 거버넌스(OPS-*), FR-ENG-ETA-001(KV 런타임 read 수용기준) |
| 차단되는 요구사항 | FR-ENG-ETA-001(KV CONFIG 런타임 read), FR-ENG-EXC-002(dwell > 120min 권위), feature flag 배선 |
| 오너 | 아키텍트/백엔드 |
| 기한 | ETA 룰 운영화 전 Phase 1 |
OD-008 · GS1 흡수 — 대형 화주 GS1(SSCC/GLN) 채택 시 표준 식별자 승격
데이터 모델은 GS1 표준 식별자 흡수 여지를 남겨 둔다. techspec 02-data-model/model.md §미래: GS1 표준 흡수: "GS1 Japan이 SSCC(출하포장 시리얼)·GLN(장소 식별)을 보급 중이나 중소 운송사 도입률은 낮다 추정. 대형 화주가 GS1을 채택하면 shipment.shipper_ref/geofence에 GLN을 흡수해 표준 식별자로 승격할 수 있는 여지를 남겨 둔다." GS1 Japan이 SSCC·GLN 등 물류 표준 식별자를 보급하고 総合物流施策大綱이 GS1 표준 활용 방침을 명시한 것은 확인이나, 중소 운송사 도입률은 추정으로 낮다.
| 속성 | 값 |
|---|---|
| 상태 | 차단 · 외부의존(파트너 채택) |
| 옵션 | (A) 지금 GLN/SSCC 컬럼을 선반영 / (B·추천) 여지만 남기고 대형 화주 채택 신호 시 승격 / (C) 무시 |
| 추천(잠정) | (B) — shipment.shipper_ref/geofence에 GLN 흡수 경로를 설계상 열어 두되, 대형 화주가 GS1을 실제 채택할 때 표준 식별자로 승격. 도입률이 낮은 현 단계에서 선반영은 과투자. |
| 영향 | DM-ID-001 식별자 정책(GLN/SSCC 승격 시 매핑), shipper/geofence 식별 체계 |
| 차단되는 요구사항 | 없음(여지 보존) — 승격 시 DM-ID-001 개정 |
| 오너 | 데이터/제품 (채택 신호는 외부) |
| 기한 | 대형 화주 GS1 채택 신호 시(트리거 기반) Phase 2 |
결정 요약 매트릭스
| ID | 결정 | 상태 | 추천 | 오너 | 기한 |
|---|---|---|---|---|---|
| OD-001 | 대시보드 아키텍처 (ADR-0010) | 해소-제안 | console=컨트롤 타워, Flutter=드라이버 전용 | 아키텍트 | Phase 1 게이트 |
| OD-002 | 브랜드 가칭 → 정식명 | 조사중 | 단일-스왑 + 사전 출시 확정 | 제품/창업 | 사전 출시 |
| OD-003 | 토큰 저장 하드닝 | 조사중 | httpOnly 쿠키 + 메모리 access | 보안 | 화주 노출 전 |
| OD-004 | CSV 인코딩 | 차단·법무 | UTF-8 BOM 기본 → 법무 확인 시 확장 | 규제/법무 | 외부 제출 전 |
| OD-005 | 리소스 프로비저닝 | 조사중 | 3환경 독립 + 비용 재확인 | 플랫폼/운영 | 사전 출시 |
| OD-006 | 용량 베이스라인 | 조사중 | 런치 후 실측으로 트리거 확정 | 플랫폼/운영 | 런치 후 |
| OD-007 | 런타임 config 권위 | 조사중 | D1=테넌트 override, KV=글로벌+flags | 아키텍트/백엔드 | ETA 운영화 전 |
| OD-008 | GS1 흡수 | 차단·파트너 | 여지 보존, 채택 신호 시 승격 | 데이터/제품 | 트리거 기반 |
근거·상호참조
- techspec ADR: adr/0003-flutter-for-app.md (대시보드=Flutter Web 원결정, OD-001이 ADR-0010으로 amend)
- techspec 데이터 모델: 02-data-model/model.md §미래: GS1 표준 흡수 (OD-008), 00-overview/glossary.md (GS1/SSCC/GLN)
- techspec 운영: 08-operations/delivery-pipeline.md, observability-slo.md, 07-security/security-privacy.md
- Research: data-acquisition (GS1 코드 활용·総合物流施策大綱), data-model (SSCC/GLN 식별자)
- 코드(server):
server/wrangler.jsonc(placeholder ID — D100000000-0000-0000-0000-000000000000, KV…000a/000b/000c; OD-005),server/migrations/0001_init.sql(dwell_threshold_min DEFAULT 120; OD-007),server/src/lib/reports.ts(CSV; OD-004) - 코드(console):
console/src/lib/auth.ts(localStorage 토큰; OD-003),console/src/lib/types.ts(@loginippon/contract추출 TODO; OD-001),console/src/components/{LoginForm,ConsoleApp}.svelte·pages/index.astro(브랜드 하드코딩; OD-002) - 코드(web):
web/src/config.ts(SITE.name = 'LogiNippon'working name; OD-002) - TRD 상호참조: 목적·범위, 아키텍처 베이스라인(ADR-0010 요약), 기능 요구(FR-AUTH-001·FR-ENG-ETA-001·FR-ENG-EXC-002·FR-RPT-NIMACHI-001), 데이터 모델(DM-ID-001), API 계약(IR-WS-001), 비기능(NFR-PERF-003/003b·NFR-SCALE-001·NFR-COST-001), 보안·프라이버시(SR-TOKEN-STORE-001), 규제(RR-CSV-001·RR-LEGAL-001), SLO 카탈로그(OBS-METRICS-001), 파이프라인·운영(OPS-*)