검토 결과를 구현 구조로 옮긴 제안

업무를 네 영역으로 나누고, 결과가 만들어진 과정도 남긴다.

제안 v1 · 현재 5+1+1 모델 · GBIS·경기데이터드림 · 2026-08-15 KST

기준정보, 관측, 모델 수명주기, 발행을 서로 다른 책임으로 둔다. 수집한 사실은 바꾸지 않고, 라벨과 특징은 버전으로 고정하며, 공개 결과에서는 사용한 모델과 근거까지 거슬러 올라갈 수 있게 한다.

제안 · 도메인 합의 전

한 줄 결론

처음에는 기존 두 프로세스와 한 데이터베이스를 유지한다. 배치 프로세스가 네 업무 영역의 쓰기를 맡고, 조회 프로세스는 완성된 공개본만 읽는다. 같은 PostgreSQL을 써도 스키마·역할·쓰기 주체는 나눈다.

현재 유지두 실행 프로세스, 한 물리 DB, 배치 중심 계산
새로 고정노선 버전, 관측 결과, 라벨·특징·모델 계보
막는 규칙오류를 빈 응답으로 바꾸기, 연구 자료를 공개 계열에 섞기
다음 단계도메인 합의 뒤 새 스키마와 새 API 설계

권장 전체 도메인 구조

전체 그림에는 네 업무 경계와 데이터가 넘어가는 방향만 남겼다. 필드와 메서드는 아래 영역별 클래스 그림에서 확인한다. 동료 문서처럼 큰 그림과 상세 그림을 분리해 한 화면의 글자 수를 줄였다.

그림 1 · 권장 전체 지도 — 외부 자료에서 읽기 전용 공개본까지

외부 자료 공급자, 기준정보, 관측, 모델 수명주기, 예보 발행, 읽기 전용 공개 조회의 순서로 이어지는 전체 지도입니다.

GBIS와 경기데이터드림에서 기준정보와 관측을 수집하고, 모델 수명주기와 예보 발행을 거쳐 PublicationQuery만 읽는 구조.
  • 기준정보 · catalogRouteVersionSourceKey가 당시의 노선 축과 공급자 키를 고정한다.
  • 관측 · observationCollectionAttemptObservationBatch가 호출 결과와 실제 관측을 나눈다.
  • 모델 수명주기 · modelingDatasetSnapshot부터 ModelRelease까지 학습·평가·선택 근거를 잇는다.
  • 예보 발행 · publicationPublicationBundle이 승인된 결과를 묶고 PublicationQuery가 현재 공개본만 읽는다.

이 그림은 처리 순서와 업무 경계만 보여준다. 클래스의 소유 관계나 데이터베이스 외래키를 뜻하지 않는다. 새 데이터베이스 스키마와 API 응답 형식은 도메인 합의 뒤 정한다.

먼저, 무엇이 어떻게 바뀌는가

동료안은 29개 타입을 한 장에 넣지 않고 수집 7개, 집계·예측 17개, 조회 API 5개로 나눴다. 권장안도 같은 형식으로 기준정보, 관측, 모델 수명주기, 예보 발행을 각각 그렸다. 본문 그림은 전체 구조를 한눈에 보도록 축소했다. 필드는 각 그림 아래의 ‘SVG 크게 보기’에서 읽을 수 있다.

비교 그림 A · 동료안과 권장안을 같은 밀도의 클래스 그림으로 비교
BEFORE동료안 v3원문 Mermaid 3개를 그대로 복원
AFTER권장안영역별 핵심 타입만 그리고 반복 계약은 아래 객체 지도에 유지
  1. 호출 결과와 실제 관측을 나눈다.
    CollectionAttempt는 호출 결과를, ObservationBatch는 검증된 관측을 맡는다.
  2. 기준정보에 적용 기간과 개정 이력을 더한다.
    RouteVersion, CatalogRevision, SourceKey로 당시 노선과 공급자 키를 남긴다.
  3. 모델 버전 뒤에 학습·평가·승인 근거를 잇는다.
    DatasetSnapshot → TrainingRun → ModelArtifact → EvaluationRun → SelectionDecision → ModelRelease를 연결한다.
  4. 화면·API 응답 모양을 업무 객체에서 분리한다.
    PublicationBundlePublicationQuery까지만 합의하고 새 API DTO는 그 뒤에 설계한다.
두 도메인 구조가 실행 프로세스와 저장소에서 만나는 방식 보기
BEFORE 동료안 v3의 핵심 흐름 동료 문서에 공개된 v3 실행 흐름을 한 장으로 요약
GBIS실시간 위치·좌석 응답
수집 · collectorSnapshotSourceSnapshot · BusObservation
PostgreSQL · 관측 테이블collector가 추가로 쓰고 processor가 나중에 읽음
집계·예측 · processorAggregationJobCellRiskChanceModelRouteForecast
PostgreSQL · 집계·예보 테이블processor가 쓰고 api는 조회만 함
조회 API · apiForecastRepository가 예보를 조회해 응답으로 바꿈
  • 처리·조회 분리와 미추정 상태는 그대로 살릴 강점이다.
  • 정상 응답·차량 없음과 호출 실패, 불완전 페이지를 별도 결과로 남길 자리가 부족하다.
  • 라벨·특징·학습·평가·선택·모델 발행의 연결 기록이 빠져 있다.
기존 뼈대 유지
기록 보강
AFTER 권장 구조 네 업무 경계와 한 줄로 이어지는 생성 이력
GBIS · 경기데이터드림 · 향후 공급자각기 다른 코드·식별자·페이지 규칙
공급자별 변환·검증호출 결과 분류 · 페이지 취득 검사 · 외부 키 변환 · 보존 정책
① 기준정보 · ② 관측노선 버전과 공급자 대응표 · 호출 결과와 실제 관측·통과 근거
③ 모델 수명주기라벨 → 특징 → 학습 → 평가 → 선택 → 불변 모델 발행본
④ 예보 발행 → 읽기 전용 API승인된 모델·예측·공개 지표를 한 발행 묶음으로 고정
  • 정상 빈 응답·오류·불완전 기준정보를 서로 다른 기록으로 남긴다.
  • 모델별 입력·파일·평가·승인 기록을 분리해 다시 확인할 수 있게 한다.
  • 현재 공개용 자료와 과거 내부 연구 자료는 서로 다른 계열로 분리해 관리한다.

비포의 29개는 class, record, enum, interface, Spring Data repository를 같은 단위로 센 동료안의 목록이다. 권장안 59개 가운데 핵심 51개는 위 그림에 표시했다. 반복되는 규격·저장·평가 객체 8개는 아래 객체 지도와 계약 설명에 남겨 그림의 밀도를 낮췄다. 59는 목표 클래스 수가 아니며, 구현에서는 독립 규칙이 없는 얇은 타입을 합칠 수 있다.

비교 그림 B · 핵심 객체의 행선지 — 유지할 것, 나눌 것, 새로 둘 것
✓ 유지·보강 ↠ 책임 분리 → 이동·버전화 + 새로 추가
실시간 수집 창구SnapshotSource · 위치 수집에 맞춘 하나의 입구
역할 명확화
실시간 관측 전용 창구RealtimeObservationSource · 기존 변화 지점의 역할을 더 분명하게 한다.
기준정보 수집 창구 없음전 페이지 취득과 유효기간을 다룰 별도 입구가 없음
새로 추가
페이지형 기준정보 전용 창구ReferenceDatasetSource · 완결성과 공급자 버전을 별도 규칙으로 다룬다.
수집 코드 안의 호출 제한CallBudget · 호출당 비용을 수집 객체가 판단
정책 이동
공급자별 호출 정책ProviderCallPolicy · 계정·환경별 한도를 관리해 과도한 호출을 막는다.
호출과 관측이 한 묶음Snapshot에 두 의미가 함께 들어 있음
결과 분리
호출 결과와 관측을 분리CollectionAttempt · ObservationBatch로 차량 없음·오류·정상 행을 구분한다.
차량 관측BusObservation · 실제로 본 위치·좌석 사실
유지·보강
관측 유지, 식별 연결 분리BusObservation + PrivateVehicleRef · 공개 예보에 차량 식별값이 섞이지 않게 한다.
모든 모델에 같은 집계 입력CellRisk 하나로 모델 차이를 감춤
모델별 분리
모델별 입력 조건과 사용 가능 시점FeatureSpec → FeatureSnapshot · 없는 값을 0이나 다른 노선 값으로 대신하지 않는다.
모델 계약 하나ChanceModel의 한 입력·출력 모양을 모든 모델에 적용
계약 분리
예측 결과 형식은 공통, 모델 기록은 별도모델마다 입력·학습 방법·파일·승인 기록을 따로 관리한다. FullRiskPredictor · ModelRecipe · ModelArtifact · ModelBundle · ModelRelease
확률과 미추정 구분ChanceStateEstimated | NotEstimated를 나눔
의미 유지
구분 유지, 사유와 이력 보강Estimate + UnavailableReason · 확률 0과 계산 불가를 구분하고 생성 이력을 함께 남긴다.
예보에 모델 버전만 기록ChanceModel.version()RouteForecast에 남기지만 실제 파일·학습 자료·평가 근거까지 재현할 정보는 없다.
근거 확장
예보 생성·발행 이력 저장ModelRelease → ForecastRun → FullRiskForecast → PublicLineage → PublicationBundle로 어떤 모델로 언제 만든 예보인지 남긴다.
노선·학습·평가 결정 기록 부족모델 버전과 예보 기록은 있으나 노선 축·라벨·학습·평가·선택의 변경 이력은 없다.
새로 추가
변경·평가·발행 기록 추가RouteVersion · PassageEvidence · LabelPolicy · TrainingRun · EvaluationRun · SelectionDecision · PublicationBundle로 판단 근거를 다시 확인할 수 있게 한다.

이 대응표는 클래스 이름을 일괄 치환하라는 목록이 아니다. 먼저 오른쪽 책임과 상태 전이를 합의한 뒤, 실제 언어와 저장 방식에 맞춰 타입 수를 줄이거나 합친다. 설계 v3의 ForecastResponseStopResponse는 도메인에 옮기지 않는다. 새 응답 계약은 도메인 합의가 끝난 뒤 읽기 어댑터에서 설계한다.

전체 지도

각 경계가 소유하는 말과 기록을 한눈에 표시했다. 다른 경계의 사실을 다시 해석하거나 직접 고치지 않고, 버전이 붙은 참조로 이어 준다.

그림 1 · 권장 노선도 — 자료가 네 경계를 지나 공개 결과가 되는 길
보조 경계기준정보노선·정류장 축, 공급자 키, 차량 규격의 유효기간을 소유한다.
관측 근거관측호출 결과, 보존 가능한 수신 증거, 위치·좌석 사실과 통과 근거를 소유한다.
핵심 경계모델 수명주기라벨·특징·학습·평가·선택·모델 발행 결정을 소유한다.
공개 경계예보 발행승인된 모델의 만석 위험과 공개 평가 조회본을 한 묶음으로 발행한다.

공급자 필드명은 표준 관측과 후속 경계로 넘기지 않는다. 원래 결과 코드와 원문은 승인된 비공개 증거에만 머문다. 공개 조회는 발행 경계에서 끝나며 차량 연결값과 학습 내부 상태를 거슬러 읽지 않는다.

그림 2 · 의존 방향 — 공공 API와 미래 서비스 API를 도메인에서 분리한다
GBIS·경기데이터드림필드명, 업무 코드, 페이지 방식, 외부 식별자
공급자별 변환 경계호출 결과 분류 · 보존 정책 · 버전별 변환기 · 외부 키 매핑
네 업무 경계공급자 필드명을 모르는 내부 계약과 승인 뒤 바꾸지 않는 공개본
새 API는 승인된 공개본을 보여준다. 화면이나 응답 형식 때문에 내부 기준을 바꾸지 않는다.

네 업무 경계가 소유하는 것

업무 영역마다 쓰는 말과 실패 조건이 다르다. 다른 영역의 테이블을 직접 고치거나 객체 관계로 강하게 묶지 않는다.

그림 3 · 소유권 지도 — 각 경계의 책임과 금지선
기준정보 · catalog공급자 자료를 시간에 맞는 노선 축으로 바꾼다
소유
노선 버전, 정류장 순번, 외부 키 대응, 차량 규격 이력
입력
완결된 공공 기준정보 취득본
출력
RouteAxisRef, 유효시점이 붙은 참조
쓰기
기준정보 수집 작업만
소유하지 않음: 실시간 좌석, 라벨, 모델 점수, 공개 응답 모양
관측 · observation무슨 호출이 있었고 무엇을 실제로 보았는지 남긴다
소유
호출 결과, 수신 증거, 표준 관측, 회차, 통과 근거
입력
실시간 공급자 응답과 기준정보 참조
출력
ObservationBatch, PassageEvidence
쓰기
수집기·정규화기·통과 파생기만
소유하지 않음: 만석 정답, 특징 벡터, 모델 선택, 공개 확률
모델 수명주기 · modeling같은 정답과 평가 규격으로 학습·비교·승인한다
소유
라벨·특징 정책, 데이터 고정본, 학습·평가 실행, 산출물, 선택
입력
통과 근거, 기준정보 버전, 현재 수집 계열
출력
ModelRelease, 재현 가능한 예측·지표
쓰기
학습기·평가기·승인 작업만
소유하지 않음: 공공 API 원문, 활성 공개본 포인터, 화면 응답 모양
예보 발행 · publication승인된 결과만 비식별 조회본으로 내보낸다
소유
예보 실행, 만석 위험, 공개 평가 요약, 발행 묶음, 현재 공개본 표시
입력
활성 모델 발행본과 발행용 특징
출력
PublicationBundle과 읽기 계약
쓰기
발행 작업만, API는 읽기 전용
소유하지 않음: 차량 원본값, 원문 증거, 학습 중간 상태, 모델 선택 논리

한 번에 함께 저장할 범위

  • 같이 저장할 때 반드시 함께 맞아야 하는 값만 한 묶음으로 둔다. 업무 영역 사이는 바뀌지 않는 ID와 내용 목록으로 연결한다.
  • ObservationBatch가 모든 행을 한 객체 안에 들고 있을 필요는 없다. 묶음 전체를 검증한 뒤 관측 행을 한 번에 저장해도 같은 책임 범위다.
  • 현재값을 고치는 대신 새 버전·새 실행·새 결정을 추가한다. 과거 예측의 계보는 활성 모델이 바뀌어도 그대로 남는다.

권장 객체 지도

아래 이름은 책임을 고정하기 위한 설계 어휘다. 클래스 수 목표가 아니다. 값의 범위나 상태 전이를 지키지 않는 얇은 포장은 만들지 않는다.

그림 4 · 업무별 핵심 책임과 이를 맡는 객체

기준정보 · catalog

노선 버전 · 정류장 순서 · 노선 축 참조 · 적용 기간 · 기준정보 개정RouteVersion · RouteStop · RouteAxisRef · ValidityWindow · CatalogRevision 기준정보 취득 · 공급자 계약 참조 · 변환기 버전 · 공급자 키ReferenceDatasetAcquisition · SourceContractRef · AdapterVersion · SourceKey 차량 규격 개정 · 비공개 차량 연결VehicleSpecRevision · VehicleIdentityLink 공급 자료 범위 · 호출 허용과 재시도 규칙SourceCapability · ProviderCallPolicy 기준정보 수집 창구 · 기준정보 저장소ReferenceDatasetSource · CatalogStore

관측 · observation

공급자 호출 시도 · 호출 결과 분류CollectionAttempt · CollectionOutcome 관측 묶음 · 차량 관측 · 잔여석 판독 · 차량 위치ObservationBatch · BusObservation · SeatReading · BusPosition 같은 회차의 연속 관측 구간TripSegment · 같은 차량·노선·회차 안에서 이어지는 관측을 묶는다. 정류장 통과 증거PassageEvidence · 정확한 한 정류장 또는 가능한 정류장 구간을 파생 사실로 남긴다. 판정에 쓴 관측 참조EvidenceRef · 직전과 현재 관측을 각각 배치 ID·관측 ID로 가리켜 판정을 다시 확인할 수 있게 한다. 비공개 차량 참조PrivateVehicleRef 보존 정책 · 관측 변환 · 통과 증거 생성 · 실시간 관측 수집 창구RetentionPolicy · ObservationNormalizer · PassageDeriver · RealtimeObservationSource

모델 수명주기 · modeling

점 라벨 · 구간 학습 예시 · 라벨 규칙 · 특징 규격 · 특징 요구 조건 · 특징 고정본PointLabel · IntervalTrainingExample · LabelPolicy · FeatureSpec · FeatureRequirement · FeatureSnapshot 학습 자료 고정본 · 학습 실행 · 모델 학습법 · 모델 파일 · 보정 파일DatasetSnapshot · TrainingRun · ModelRecipe · ModelArtifact · CalibratorArtifact 평가 실행 · 평가 규칙 · 구간별 지표 · 선택 결정EvaluationRun · EvaluationProtocol · CohortMetric · SelectionDecision 모델 조합 · 승인 조건 · 승인 모델 발행본ModelBundle · ReleasePolicy · ModelRelease 만석 위험 예측 창구 · 사용한 모델과 입력이 연결된 개별 예측FullRiskPredictor · Prediction

예보 발행 · publication

예보 계산 실행 · 예보 대상ForecastRun · ForecastTarget 만석 위험 예보 · 추정 상태 · 예측 불가 사유FullRiskForecast · Estimate · UnavailableReason 공개 평가 요약 · 공개 결과 생성 이력ModelEvaluationView · PublicLineage 공개 묶음 · 현재 공개본 표시 · 공개본 조회 창구PublicationBundle · ActivePublication · PublicationQuery

공용 모듈에는 시각·내용 확인·직렬화처럼 업무 판단을 하지 않는 공통 기능만 둔다. Route·Vehicle 같은 도메인 객체를 공용 모듈에 몰아넣지 않는다.

수집 결과와 원문 보존을 먼저 분리한다

빈 차량 목록과 실패는 같은 값이 아니다. 호출 결과를 확정한 뒤에만 표준 관측을 만들고, 원문 보존은 공급자·데이터셋·필드별 정책으로 제한한다.

그림 5 · 호출 결과 — 성공·차량 없음·실패를 구분
요청공급자 · 작업/데이터셋 · 버전 · SourceKey · 페이지/호출 키
수신HTTP · 공급자 시각 원문 · 서버 수신 시각 · 필드 존재/자료형 · 본문 지문
업무 결과 분류공급자 결과 코드 · 응답 구조
무결성 검증행 수 · 필드 구조 · 중복
표준 관측성공 행일 때만 생성
정상 관측 · SUCCESS_ROWSGBIS 결과 코드 0과 검증된 행. 관측을 만들되 묶음 검증이 실패하면 전부 거부한다.
정상 응답·차량 없음 · SUCCESS_EMPTYGBIS 결과 코드 0이지만 차량 행이 없다. 정상 호출로 남기고 관측·통과 라벨은 만들지 않는다.
공급자 결과 없음 · NO_RESULTGBIS 결과 코드 4. 정상 응답·차량 없음이나 오류로 바꾸지 않고 공급자 의미를 그대로 보존한다.
오류 · BUSINESS / HTTP / TRANSPORT / MALFORMED업무·HTTP·통신·형식 오류를 각각 기록하고 다음 성공 응답과 관측 연결을 끊는다.
GBIS · 노선별 실시간 조회 source + operation + endpointVersion + adapterVersion + route SourceKey + poll key
  • 현재 위치 조회는 format=json을 요청에 명시한다. JSON을 요청했는데 게이트웨이의 XML 오류 봉투가 오면 정상 응답으로 읽지 않고 실제 형식과 오류 내용을 따로 남긴다.
  • 결과 코드 0의 행 있음·행 없음과 결과 코드 4를 서로 다른 지속 상태로 남긴다.
  • 알 수 없는 코드·필드 존재 여부·원래 자료형은 정규화 결과와 함께 증거에 보존한다.
경기데이터드림 · 데이터셋 페이지 취득 source + dataset + pIndex + pSize≤1000 + head.api_version + adapterVersion
  • Type을 생략하면 공식 기본값은 XML이다. 프로젝트는 JSON을 명시하고 실제 형식을 검증한다.
  • 정상 페이지의 head[].RESULT에서 INFO-000을 확인한다. 정상 봉투 없이 최상위 RESULT만 온 응답은 업무 오류 봉투로 따로 기록한다.
  • 모든 페이지와 전체 건수·API 버전이 맞아야 취득 완료 후보가 된다.
  • 공급자 스냅샷 토큰이 없으므로 완료 뒤에도 SOURCE_CONSISTENCY_UNKNOWN을 남긴다. 페이지 사이 변동 징후가 있으면 PAGE_DRIFT_SUSPECTED로 막는다.
그림 6 · 공급자별 보존 정책 — 원문은 기본 저장 대상이 아니다
GBIS 실시간현재 수집기의 받은 원본 전체 대조는 암호화 단기 격리소로 옮기는 안을 검토한다. 장기 보관 기준 기록에는 승인된 필드·결과 코드·시각·변환기 버전·파일 내용 확인값만 둔다.정책 결정 필요
경기데이터드림프로젝트 정책으로 번호판 원문을 폐기하고 목적별 비공개 연결값을 만들 수 있다. 이는 공급자 의무가 아니며 정규화·키·보존·파기 규칙 승인 전에는 확정하지 않는다.제안 · 승인 필요
차량 연결AUTOMB_IDVEH_ID는 근거·검증 상태·유효기간·대응 버전이 있는 비공개 VehicleIdentityLink가 있을 때만 잇는다. 없으면 공급자별 식별자로 남긴다.기본 분리
새 공급자보존 허용 필드, 기간, 키 정책, 오류 분류, 버전 전략이 등록되기 전에는 운영 수집을 시작하지 않는다.기본 거부

구체적인 단기 격리 기간은 이 문서에서 임의로 정하지 않는다. 소유자가 기간·삭제·백업 반영을 승인하고 자동 파기 시험이 통과해야 한다. 기간이 지나 원문을 지우면 미래의 새 필드를 과거 응답에서 다시 해석할 수 없다. 이 손실까지 알고 승인해야 한다.

비공개 식별값과 원문 보관의 구현 조건
  • serviceKeyKEY 실제값은 URL·로그·수신 증거에 남기지 않는다. 요청 전에 비밀 참조로 주입하고 기록 전에 가린다.
  • 복구할 수 없는 연결값이 필요하면 목적·공급자·필드별로 분리한 HMAC을 쓴다. 정규화 규칙, 알고리즘, key_id, 토큰 버전과 128비트 이상의 출력 길이를 기록하고, 키 접근·회전·폐기를 감사한다.
  • HMAC 키 원문은 코드·평문 환경변수·데이터베이스·수집 자료와 분리된 관리형 KMS/HSM에 둔다. 수집 역할에는 지정 키의 MAC 생성 권한만 주고 키 반출·복호화·다른 키 사용 권한은 주지 않는다.
  • 원본값이 없으면 임의 연결값을 만들지 않고 UNTRACKED로 둔다. 해시나 HMAC을 익명화의 보증으로 표현하지 않는다.
  • 격리 원문은 승인된 수집·감사 역할만 읽는다. 조회 API와 학습기는 읽지 못하며, 읽기·키 사용·삭제와 백업 사본 파기를 모두 감사한다.

변환 경계의 정확한 규칙

  • 잔여석 0은 만석이다. -1은 공급자 정보 없음 값, 필드 누락은 FIELD_ABSENT, nullNULL_VALUE, 자료형·파싱 실패는 PARSE_ERROR로 따로 남긴다. 이후 화면에서 모두 ‘정보 없음’으로 보여도 근거는 합치지 않는다.
  • 혼잡도 공식 코드는 문자열 1~4다. 실응답 정수 0은 프로젝트 호환값인 ‘미산출’로만 다루며 ‘여유’로 해석하지 않는다.
  • 외부 식별자는 SourceKey(source, namespace, value) 범위 안에서만 같다고 본다. 검증된 대응표 없이 공급자 사이 숫자를 결합하지 않는다.
  • RouteVersion은 내부 노선축의 유효기간이다. GBIS API 주소 버전, 변환기 버전, 경기데이터드림 head.api_version, 내부 기준정보 개정 번호를 각각 다른 값으로 기록한다.
  • GBIS 기반정보가 주는 areaVersion·routeVersion·routeLineVersion·routeStationVersion·stationVersion·vehicleVersion도 한 값으로 합치지 않고 취득본에 각각 보존한다.
  • 경기데이터드림 기준정보는 모든 페이지와 전체 건수·API 버전이 맞을 때 ReferenceDatasetAcquisition을 완료한다. 스냅샷 토큰이 없으므로 공급자 일관성은 ‘알 수 없음’으로 남기고, 페이지 변동 징후가 있으면 기준정보로 승격하지 않는다.
  • 공급자가 기록한 원문 시각 queryTimeRaw, 서버 수신 시각, 처음 사용할 수 있게 된 시각을 따로 둔다. 늦게 온 정정은 과거 행을 고치지 않고 새 관측이 이전 관측을 가리키게 한다.

통과 근거와 만석 라벨을 다른 객체로 둔다

PassageEvidence는 무엇을 관측했는지 말하고, LabelPolicy는 그 근거를 어떤 정답으로 읽을지 결정한다. 라벨 규칙이 바뀌어도 관측 사실은 고치지 않는다.

그림 7 · 통과 근거 만들기 — 점 근거와 구간 근거를 분리
점 근거 · POINT
  • 같은 노선·차량·회차·한국 표준시(KST) 날짜
  • 인접한 성공 응답, 경과시간 0초 초과 90초 이하
  • last_passed가 정확히 1 증가
  • 정류장 S 출발 (2,S), 출발 뒤 교차로 통과 (0,S), 다음 정류장 도착 (1,S+1)
  • S에 막 도착한 (1,S)는 출발 뒤 라벨이 아님
구간 근거 · INTERVAL
  • 같은 차량 연결은 유효하지만 순번을 건너뜀
  • 또는 90초를 넘어 정확한 점을 확정할 수 없음
  • 후보 정류장 1~6개와 전체 가중치 1을 보존
  • 점 근거로 승격하지 않고 검열된 근거로 유지
성공 행이 아닌 응답 · 회차 변경 · KST 날짜 변경 · 식별 불일치에서는 관측 연결을 즉시 끊는다.
통과 근거PassageEvidence · 관측 근거와 후보 정류장
라벨 규칙LabelPolicy · 목표 사건 · 시간 상한 · 검열 규칙 · 버전
점 라벨PointLabel · Full · NotFull · Unknown
점 근거 → 점 라벨Full | NotFull은 운영 후보 5개와 비운영 참조 1개의 기본 학습에 쓴다. Unknown은 학습에서 뺀다.
구간 근거 → 구간 학습 행끝점 Full | NotFull, 후보 정류장 1~6개, 각 후보 가중치 1/n을 묶는다. 구간 검열 모델에만 넣고 다른 5개 기본 모델과 Platt 보정에는 넣지 않는다.

공통 목표는 ‘목표 정류장 출발 뒤 잔여석이 0인 사건’이다. 이 사건의 확률을 p_full로 부른다. 그 여집합은 비만석 확률이지 실제 탑승 성공률이 아니다.

모델은 구현 하나가 아니라 수명주기로 관리한다

현재 5개 운영 후보, 1개 보정층, 1개 비운영 참조는 역할이 다르다. 공통 예측 규칙은 만석 위험이라는 결과만 맞추고, 필요한 특징·실제 모델 파일·지원 범위·예측 불가 사유는 모델별로 보존해야 한다.

그림 8 · 학습부터 모델 발행까지 — 실행, 산출물, 결정을 분리
  1. 학습 자료 확정DatasetSnapshot · 포함한 행 전체와 사용 목적
  2. 학습TrainingRun · 코드·난수 초기값·환경·학습 구간
  3. 파일 보관ModelArtifact · 실제 바이트와 호환 계약
  4. 평가EvaluationRun · 고정 미래구간과 같은 라벨
  5. 선택SelectionDecision · 승인·보류·기각 근거
  6. 배포 승인ModelRelease · 범위·채널별 승인 뒤 변경 금지
입력 확인모델마다 필요한 자료와 시점을 확인
지원 범위 확인공급자·노선·기간에서 계산 가능한지 확인
만석 위험 또는 예측 불가확률 0과 계산할 수 없음을 구분
개발 계약 보기
FullRiskPredictor
  requires() → FeatureRequirement
  supports(RouteAxisRef, ModelBundle) → boolean
  predict(ForecastTarget, FeatureSnapshot, ModelBundle)
    → Prediction(
        estimate = Estimated(p_full, lineage) | NotEstimated(reason),
        modelBundleRef,
        featureSnapshotRef)

ModelBundle =
  BaseBundle(baseArtifactRef@version/digest)
  | CalibratedBundle(
      baseArtifactRef = logistic_interactions@version/digest,
      calibratorArtifactRef,
      rawFallback = FORBIDDEN)

Every bundle
  featureSpec + labelPolicy + supportedScope

FeatureSnapshot.availableAt ≤ ForecastTarget.at
모델이 요구하는 특징을 해당 공급자·노선·기간이 모두 제공할 때만 발행할 수 있다. 부족한 입력을 0이나 다른 노선 값으로 대신하지 않는다.
운영 후보 5개구간 검열 · 상호작용 로지스틱 · GAM · 경험 베이즈 · 계층 로지스틱. 같은 사건과 평가 규격에서만 선택 대상이 된다.
보정층 1개Platt 보정은 logistic_interactions의 동일 버전·파일 내용 확인값과 더 앞선 날짜의 교차검증 밖 예측을 참조한다. 단독 후보가 아니며 보정 실패 때 원래 확률로 돌아가지 않는다.
비운영 참조 1개그래디언트 부스팅 상한은 비교용이다. 선택·발행 대상이 아니다.
점 라벨 입력선Full | NotFull과 각 모델의 FeatureSnapshot이 운영 후보 5개와 비운영 참조 1개로 간다.
구간 근거 전용 입력선후보 정류장 1~6개와 1/n 가중치는 interval_censored에만 간다. 다른 기본 모델과 Platt 보정으로 가는 선은 없다.
운영 후보 5개 구간 검열 · 상호작용 로지스틱 · GAM · 경험 베이즈 · 계층 로지스틱
각 모델 파일 → 같은 평가 실행 → 선택 결정. 승인된 모델만 ModelRelease로 넘어간다.
Platt 보정 경로 logistic_interactions@version/digest + 더 앞선 날짜의 OOF 원래 p_full + 점 라벨
50행 이상 · 만석 5건 이상 · 비만석 20건 이상일 때만 CalibratorArtifact를 만든다. 미달이면 NotEstimated(CALIBRATOR_INELIGIBLE)로 끝내며 원래 확률을 대신 내보내지 않는다.
그래디언트 부스팅 참조 같은 점 라벨로 비교하되 운영 상한을 살피는 비운영 기준선
평가까지만 점선으로 연결한다. 선택 결정과 모델 발행으로 넘어가는 길은 막는다.
현재 상태 · 운영 후보 5개, 보정층 1개, 비운영 참조 1개 등 7개 모두 잠정 단계이며 활성 선택·모델 발행본은 없다. 보정 대상 2,894건 중 사용 행은 0건이라 Platt 보정은 적용되지 않았다.

자료 목적을 명시하고 혼합을 검사 단계에서 막는다

DatasetSnapshot, 실행, 산출물은 public_current 또는 internal_research 중 하나만 가진다. 공개 계열이 내부 연구 계열을 부모로 참조하면 생성 단계에서 오류로 기록한다.

현재 모델 역할별 필요한 특징과 발행 조건
역할실제 필요한 입력산출물에 고정할 것발행 조건
구간 검열 추정점 라벨과 최대 6개 후보 정류장의 구간 근거, 노선·정류장·시간대계층별 건수·사전확률·축소 강도·상위값 사용 규칙구간 규칙과 실제 집계 계층이 선언과 일치
상호작용 로지스틱노선, 시간대, 노선×정류장, 노선×시간대, 노선×정류장×시간대. 독립 정류장 주효과는 없음계수·특징 순서·처음 보는 범주의 처리지원 범위 밖과 효과 0을 구분
GAMtiming.response_received_at을 한국 표준시의 연속된 시간으로 바꾼 값과 노선축 정류장 위치시간의 sin/cos 주기항·축 범위·기저함수·계수·처음 보는 노선의 처리시간대를 연속 시각 대신 넣지 않고, 노선 개편 때 새 축 버전을 사용
경험 베이즈점 라벨, 노선·정류장·시간대와 계층별 집계계층별 건수·사전확률·축소 강도·상위값 사용 규칙실제 집계 순서와 선언이 일치
계층 로지스틱절편+정규화 정류장 위치, 시간대, 노선, 노선×정류장 범주, 노선×시간대. 평일/주말 입력은 없음계수·특징 순서·노선별 범위·수준별 규제값처음 보는 노선을 다른 노선으로 대신 처리하지 않음
Platt 보정층logistic_interactions 동일 버전·파일 내용 확인값의 원래 p_full, 더 앞선 날짜의 OOF 예측, 점 라벨기본 모델 참조·보정 파일·50/5/20 적격 조건·원래 확률 대체 금지를 한 조합으로 고정조건 미달이면 CALIBRATOR_INELIGIBLE. 원래 확률을 대신 반환하지 않음
그래디언트 부스팅 참조노선·정류장 위치, response_received_at의 한국 표준시 연속 시간, 별도 평일/주말·시간대트리 전체·한 종류 라벨만 있을 때의 처리·지원 범위평가까지만 수행하고 비운영 비교용 상태를 유지

예측, 평가, 공개 발행을 한 계보로 연결한다

모델 파일 이름만 남기면 재현할 수 없다. 공개 확률과 성능 지표는 각각 어떤 자료·규칙·실행·결정에서 왔는지 중간 기록이 빠지지 않은 연결 정보를 가져야 한다.

그림 9 · 공개 결과의 생성 기록 — 현재 공개본을 바꿔도 과거 기록은 그대로 둔다
수집·관측호출 · 증거 · 표준 관측 · 노선 버전
라벨·특징통과 근거 · 라벨 정책 · 특징 규격
학습·모델데이터 고정본 · 학습 실행 · 모델 파일 · 조합
평가·선택평가 규격 · 구간별 지표 · 결정 · 모델 발행본
예보·발행예보 실행 · 만석 위험 · 공개 묶음
승인 모델ModelRelease · 사용할 모델 조합과 범위
예보 계산ForecastRun · 시작할 때 승인 모델을 고정
공개본PublicationBundle · 예보·평가 요약·생성 기록을 함께 교체

현재 공개본 표시(ActivePublication)는 채널별 완성본 하나를 가리킨다. 새 묶음을 모두 쓴 뒤 한 번의 DB 변경으로 표시를 바꾸며, 이전 묶음은 그대로 남긴다.

성능 숫자와 선택 관문을 분리한다

표본이 작아도 실제 측정값은 표본 수·기간·상태와 함께 공개할 수 있다. 다만 그 숫자를 모델 선택 근거로 쓸 수 있는지는 별도 상태로 판정한다.

그림 10 · 평가 지표 상태 — 공개 가능성과 선택 가능성은 같은 뜻이 아니다
비교 구간노선 × 평일/주말 × 출근/퇴근/그 밖의 시간
표본 설명평가한 통과 수 · 실제 만석 수 · 평가 기간
쉬운 지표확률 오차 · 만석을 놓친 비율 · 과하게 경고한 비율
측정 완료MEASURED · 값·표본·기간을 공개한다. 선택 조건은 별도 검사한다.
표본 부족LOW_SAMPLE · 측정값은 보이되 작은 표본 경고와 불확실성을 붙인다.
자료 없음EMPTY · 해당 평일·주말·출근·퇴근 구간에 평가 사건이 없다.
비교 불가NOT_COMPARABLE · 라벨·모델·구간 버전이 달라 같은 순위표에 놓지 않는다.

새 표본이 쌓이면 새 EvaluationRun과 지표를 추가한다. 모델·라벨·구간 정의가 바뀌면 새 계열을 시작해 성능 변화의 원인을 구분한다.

처음에는 두 프로세스로 충분하다

업무 경계와 배포 단위를 같은 수로 맞출 필요는 없다. 쓰기 경로는 배치에 모으고, 조회 프로세스는 발행 스키마만 읽게 한다.

그림 11 · 실행·저장 구조 — 두 프로세스 안의 업무 영역과 읽기 전용 조회
app-batch
  • 기준정보·실시간 수집
  • 정규화·통과 근거 생성
  • 학습·평가·선택
  • 예보 계산·발행본 생성
  • 보존·감사 작업
app-api
  • publication 스키마만 읽기
  • 활성 묶음 조회·캐시
  • 새 API 계약으로 변환
  • 관측·모델 테이블 직접 조회 금지
  • 원본 차량값 권한 없음
PostgreSQLcatalog · observation · modeling · publication 스키마와 역할 분리. 스키마 내부 FK만 기본 허용.
제한 원문 보관소암호화 단기 격리, 필드별 보존, 승인 기한 자동 삭제, 비상 접근 감사. 학습기와 API는 접근하지 못한다.
모델 파일 보관소모델 바이트와 구성 목록을 파일 내용 확인값으로 변경되지 않게 저장한다. 모델 발행본은 실제 파일 확인값을 가리킨다.

메시지 브로커, 모델별 서버, 경계별 물리 DB는 지금 도입하지 않는다. 병렬 팀 소유·독립 확장·장애 격리 요구가 실제로 생길 때 분리한다.

실행 역할별 읽기와 쓰기 권한
역할읽기쓰기금지
collector · 수집공급자 설정·기준정보 참조수집 시도·격리 증거라벨·모델·발행
normalizer · 정규화승인된 증거·기준정보표준 관측·비공개 연결값공개 조회본
trainer · 학습/평가표준 관측·통과 근거·기준정보모델 수명주기 산출물원문·번호판·활성 발행 포인터
publisher · 발행승인된 모델 발행본·발행용 특징공개 묶음·포인터모델 선택 결정 수정
api_reader · 조회활성 공개 묶음없음그 밖의 내부 스키마·수신 증거·차량 연결값

변경 영향을 가능한 한 한 업무 영역에 가둔다

새 공급자나 모델을 추가할 때 기존 관측과 과거 평가를 고치지 않는다. 새 버전과 대응표를 추가하고, 같은 기존 기능 유지 검사를 통과시킨다.

변경 시 수정할 경계와 유지할 경계
변경바꾸는 곳그대로 두는 곳필수 증거
새 공공 API공급자 변환기·보존 정책·SourceKey 대응표라벨·모델·발행 의미고정 입력 예시와 오류 분류
새 후보 모델ModelRecipe·FeatureSpec·예측 구현관측·라벨·공개 발행실제 모델 파일을 사용한 동일 평가
노선 개편새 RouteVersion·RouteAxisRef과거 관측·라벨·예측유효기간과 정류장 대응
평가 구간 변경CohortDefinition·EvaluationProtocol모델 파일·기존 지표 계열새 비교 계열 ID
새 서비스 API공개 묶음을 응답으로 바꾸는 계약수집·모델 내부 객체도메인 합의 뒤 계약 시험
보존 정책 변경RetentionPolicy·삭제 작업·권한공개 예보 의미만료·백업 사본 전파·감사 시험

현재 경로를 버리지 않고 옮기는 순서

전면 재작성 대신 같은 수집 자료에서 기존 결과와 새 결과를 함께 만들고 전건 대조한다. 단계마다 되돌릴 수 있는 지점을 남긴다.

그림 12 · 이행 순서 — 의미 계약부터 발행 전환까지
  1. 뜻과 규칙 합의

    만석 위험의 뜻과 호출 결과·노선 변경·통과 근거·라벨 규칙을 사례로 합의한다.

  2. 원문 정책 결정과 변환 경계 도입

    GBIS 단기 격리·장기 증거 정책, 경기데이터드림 번호판 폐기, 역할 권한과 구체적인 보존 기간을 승인한다.

  3. 관측·통과 근거 이중 생성

    같은 응답에서 기존 행과 새 ObservationBatch·PassageEvidence를 만들고 오류·무차량·회차·90초 경계를 전건 대조한다.

  4. 데이터 고정본과 실제 모델 산출물 생성

    FeatureSpec·DatasetSnapshot·TrainingRun·ModelArtifact를 만들고 5+1+1 역할을 실제 파일 내용 확인값으로 묶는다.

  5. 평가·선택·비공개 병행 발행

    고정 미래구간과 평일·주말·출근·퇴근 지표를 만들고, SelectionDecision을 통과한 모델 발행본으로 비공개 예보를 함께 계산한다.

  6. 발행본 전환 뒤 새 API 설계

    PublicationBundle 동등성과 권한을 확인해 현재 공개본 표시를 바꾼다. 그다음 공개 조회본에 맞춰 새 스키마와 API를 설계한다.

구현 시작 전 승인 관문

  • GBIS 원문 보존과 기존 호환성 명세의 충돌을 기간·필드·권한·삭제 시점을 정한 하나의 정책으로 해소했다.
  • 정상 차량 있음·정상 차량 없음·업무 오류·전송 오류가 저장과 라벨에서 구분된다.
  • 점·구간 근거, 회차·한국 표준시 날짜·90초·응답 단절 규칙이 고정 시험 예시와 일치한다.
  • public_current 계열이 internal_research 부모를 참조할 수 없다.
  • 학습·평가·발행이 같은 ModelBundle 파일 내용 확인값과 LabelPolicy를 가리킨다.
  • 운영 후보 5개만 선택 대상이며 보정층과 비운영 참조의 역할이 타입으로 분리된다.
  • API 역할이 수신 증거·차량 연결·모델 수명주기 스키마와 원본 차량값을 읽지 못한다.
  • 도메인 합의 전에는 새 서비스 스키마와 HTTP 응답 필드를 확정하지 않는다.
이번 제안에서 의도적으로 만들지 않는 것
  • 모델마다 별도 서버를 두지 않는다.
  • 경계마다 물리 DB나 메시지 브로커를 두지 않는다.
  • 실행 도중 모델을 임의로 바꾸는 기능을 만들지 않는다. 작업 시작 때 승인된 모델 발행본 하나를 고정한다.
  • 공급자 응답용 객체, 화면 응답용 객체, DB 저장용 객체를 업무 객체와 같은 것으로 취급하지 않는다.

근거와 적용 범위

이 페이지는 목표 도메인 제안이지 구현 완료 보고가 아니다. 도메인 합의 뒤 스키마·저장소·새 API를 설계하고, 실제 구현·전환·권한·계약 시험 증거로 다시 검증해야 한다.