확장 안전 공고수집 배치 구현 통합 계획

목적과 범위

이 문서는 20260730-확장-안전-공고수집-배치-tdd.md, 20260730-확장-안전-공고수집-배치-design-db.md, 20260730-확장-안전-공고수집-배치-design-fe-web.md 및 BE-33~BE-43, FE-19를 구현 순서로 통합한다. MySQL의 expand-only schema를 선행하고, 짧은 수집 slice와 durable SLA snapshot을 BE에서 구현한 뒤 기존 운영 화면에 additive 계약을 표시한다. 코드 변경은 이 계획의 범위가 아니다.

구현 전 차단 게이트 (G0)

C-01 — SLA snapshot item 계약 불일치

소비자slaSnapshot.items[] 계약
BE TDD API Contract §API ContractjobSourceId, sourceLabel, cycleStatus, isComplete, fetchedCount, abnormal, closeGuarded
DB 설계 snapshot source 테이블cycle status, fetched count, is-complete, abnormal, close-guarded만 영속
FE 설계 §API 연동위 필드 중 isComplete는 없고, 대신 listPageCount, detailRequestCount를 요구

두 요청량 필드는 09:00 당시의 immutable 값이어야 하지만 현 DB schema에는 captured_list_page_countcaptured_detail_request_count가 없다. 구현자가 current cycle의 값을 합성하면 SLA snapshot 불변성 계약을 깨므로 금지한다.

해결 소유자: senior BE + senior DBA + senior FE. 권고 결정: 요청량은 SLA late-source 목록의 요구사항이 아니므로 FE CollectionSlaSnapshotItem에서 listPageCountdetailRequestCount를 제거하고, TDD/DB 계약의 isComplete를 추가한다. 요청량은 current CollectionRun에서만 표시한다. 요청량을 SLA item에도 표시해야 한다는 제품 요구가 확인되면 반대로 DB에 두 captured count 컬럼을 expand-only로 추가하고 BE TDD/API와 FE 타입을 함께 정정한다. 결정·문서 정정·세 시니어의 재확인이 G0 통과 근거다.

C-02 — MySQL 작업의 티켓 식별자 부재

DBA migration은 모든 BE 티켓의 선행조건이지만 tickets/에는 DB/INFRA 티켓이 없다. 구현 시작 전에 DBA가 DB-01(또는 프로젝트가 정한 새 식별자) 티켓을 추가하고 migration, rollback, 검증을 그 티켓에 귀속해야 한다. 이 계획에서는 이를 DB-01: collection cycle queue expand schema로 표기한다. 실제 파일명과 PR 제목은 생성된 티켓 식별자에 맞춰 바꾼다.

G0가 닫히기 전에는 branch/worktree를 만들거나 구현 wave를 열지 않는다.

확정 계약 체크리스트

G0 통과 뒤 아래가 모든 작업자의 공통 계약이다.

경계계약검증 책임
MySQL → BEcycles (job_source_id, run_date) unique, seen (cycle_id, source_job_id) unique, host limit unique host, SLA header/item unique keys와 Q1~Q10 indexes; FK/ENUM/inline backfill 없이 Flyway expand-onlyMySQL implementer + infra reviewer
BE 수집 → externalcollectSlice(descriptor)는 transaction 밖에서 실행하며 slice/daily budget, opaque cursor, host throttle을 지킨다BE-34~39 tests
BE 상태 → OperationscycleStatus 6종, server-owned closeGuarded, BUDGET_EXHAUSTED는 abnormal=false, additive nullable fields 및 current summaryBE-40 contract tests
BE SLA → OperationsAPI에는 PENDING/CAPTURED/MISSED/NOT_APPLICABLE/UNAVAILABLE만 노출하고 CAPTURING은 노출하지 않는다. CAPTURED item/count는 immutable 09:00 gate 결과이고 MISSED는 재구성하지 않는다BE-43 + BE-40 tests
Operations API → FEURL/queryKey는 유지, v2 field가 없는 응답은 legacy 표시, closeGuarded 키가 있을 때 추론 금지, snapshot status는 서버 값만 소비FE-19 MSW/component/page tests
Releaselegacy collection scheduler와 v2 dispatcher의 같은 날 동시 outbound 요청 금지; ON 전 legacy disable, rollback은 v2 OFF → lease expiry → 다음 KST day legacy 재개BE-41 release test/operational evidence

통합 DAG

flowchart LR
    G0[G0: SLA item contract + DB-01 ticket] --> DB01[DB-01 MySQL expand migration]
    DB01 --> IR[Infra review APPROVED/COMMENT]
    IR --> BE33[BE-33 cycle domain contract]
    G0 --> FE19[FE-19 optional API types, MSW, UI]
    BE33 --> BE35[BE-35 DB host throttle]
    BE33 --> BE36[BE-36 Saramin/Wanted slice]
    BE33 --> BE37[BE-37 Jumpit/Surfit slice]
    BE33 --> BE38[BE-38 Remember/Jobkorea slice]
    BE33 --> BE39[BE-39 company-bound slice]
    BE33 --> BE42[BE-42 seen lifecycle]
    BE33 --> BE43[BE-43 SLA snapshot]
    IR --> BE35
    IR --> BE42
    IR --> BE43
    BE35 --> BE34[BE-34 dispatcher/lease recovery]
    BE36 --> BE34
    BE37 --> BE34
    BE38 --> BE34
    BE39 --> BE34
    BE43 --> BE34
    BE33 --> BE40[BE-40 Operations contract]
    BE43 --> BE40
    BE42 --> BE40
    BE34 --> BE41[BE-41 v2 integration release]
    BE40 --> BE41
    BE42 --> BE41
    BE43 --> BE41
    BE41 --> V[Cross-domain release verification]
    BE40 -. additive API integration evidence .-> V
    FE19 -. UI/API integration evidence .-> V

BE-34 ticket의 명시 의존에는 adapter tickets가 없지만, dispatcher가 실제 collectSlice를 실행하는 통합 테스트를 하려면 BE-35~39의 slice 구현이 필요하다. 따라서 이 계획에서는 기능 게이트로 이들을 모두 선행시킨다. BE-40에는 seenRowsOlderThan48Hours summary metric이 있으므로 BE-42도 API gate의 선행으로 둔다.

Wave 및 게이트

Wave도메인티켓/작업branch 및 worktree시작 조건종료 근거 / 다음 게이트
0계약G0 C-01, C-02코드 branch 없음사용자 구현 승인정정 문서 + 세 시니어 확인; DB-01 ticket 존재
1MySQLDB-01 migrationfeat/DB-01-collection-cycle-queue-schema, .worktrees/DB-01G0Flyway migration/test raw output, expand-only 확인, private-infra-reviewer APPROVED/COMMENT (G1)
2BE / FEBE-33; FE-19feat/BE-33-collection-cycle-domain-contract, .worktrees/BE-33; feat/FE-19-collection-cycle-operations-visibility, .worktrees/FE-19G1 for BE-33; G0 for FE-19 mock-only 작업각 PR code review merge. FE-19은 optional MSW/legacy tests만으로 병합 가능, 실제 API 통합은 G4에서 확인
3BEBE-35, BE-36, BE-37, BE-38, BE-39, BE-42, BE-43feat/<ticket-id>-<ticket-slug>, .worktrees/<ticket-id>BE-33 merged, G1티켓별 test exit 0 + code reviewer merge (G2); same-wave file overlap 없음 확인
4BEBE-34, BE-40feat/BE-34-collection-dispatcher-lease-recovery, .worktrees/BE-34; feat/BE-40-collection-operations-contract, .worktrees/BE-40G2: BE-34는 35~39/43, BE-40은 42/43까지 merge티켓별 tests/review merge (G3). API response fixture를 FE-19 test와 교차 검증
5BE 통합BE-41feat/BE-41-collection-v2-integration-release, .worktrees/BE-41G3 및 BE-42 mergedmulti-instance + 2,594 fixture + legacy/v2 mutual-exclusion test, review merge (G4)
6통합 확인코드 티켓 없음branch 없음G4 + FE-19 mergedBE-41 release verification와 FE-19 real additive response smoke evidence. main 머지는 dev 배포 트리거이며 prod 배포는 별도 QA PASS 필요

Wave 너비 분포는 코드 wave 기준 1, 2, 7, 2, 1이다. 단독 wave 1과 5는 각각 DB 인프라 리뷰 게이트와 공통 config/scheduler wiring이라는 의도된 단일 writer 통합 작업이다. 모든 작업 branch는 매 wave 시작 전 origin/main에서 독립으로 만들며, 한 ticket PR이 리뷰 통과하면 즉시 main에 squash merge하고 branch/worktree를 삭제한다. 장수명 feature branch는 만들지 않는다.

도메인 간 게이트 운영

  1. G0 계약 게이트: C-01/C-02가 해소되기 전 MySQL, BE, FE 구현을 시작하지 않는다.
  2. G1 인프라 게이트: DB-01의 Flyway 검증과 infra review verdict가 APPROVED 또는 COMMENT여야 BE-33을 시작한다.
  3. G2 slice/SLA 게이트: BE-33 및 BE-35~39/42/43의 merged PR과 raw test evidence를 확인한 뒤 BE-34/40을 시작한다.
  4. G3 API 게이트: BE-40의 additive API contract tests와 BE-34의 transaction-boundary/lease tests가 통과해야 BE-41의 common scheduler/config wiring을 시작한다.
  5. G4 release gate: BE-41은 legacy/v2 mutual exclusion, two-instance claim, budget fixture, 09:00 snapshot-before-notification을 증명해야 한다. FE-19은 real BE-40 response fixture로 legacy/v2 rendering을 확인한다.

각 ticket의 private-code-reviewer verdict가 모든 P0P3 반영을 확인한 뒤에만 PR auto-merge한다. G1의 MySQL migration만 private-infra-reviewer를 사용한다. 완료 선언은 rules/COMPLETION-RULE.md §14의 raw test/PR artifacts가 있어야 한다.

작업자 handoff 메시지

MySQL implementer

G0 통과와 DB-01 ticket 생성 후 시작하세요. origin/main에서 feat/DB-01-collection-cycle-queue-schema / .worktrees/DB-01을 만드세요. DB 설계의 신규 cycles, seen postings, external host limits, SLA snapshot header, SLA snapshot sources와 Q1~Q10 index를 Flyway expand-only DDL로 구현하세요. FK, ENUM, JSON, BOOLEAN, inline backfill DML은 금지하고 DATETIME(6), table/column COMMENT, 유일키와 index 명명 규칙을 지키세요. 기존 runs table은 변경하지 마세요. Flyway migration validation/integration test raw output, migration filename, rollback (새 테이블은 남겨도 됨)을 보고하세요. push 후 infra review를 요청하고, verdict APPROVED/COMMENT 전에는 merge하지 마세요.

BE lead (private-senior-be)

G0/G1 통과 후 BE wave를 지휘하세요. 티켓별 branch/worktree는 최신 origin/main에서 독립 생성하고 single-writer 검사를 하세요. Wave 2는 BE-33, wave 3은 BE-35~39/42/43 병렬, wave 4는 BE-34/40, wave 5는 BE-41입니다. 특히 HTTP 호출과 throttle wait에는 Spring transaction이 없어야 하며, stale lease token 저장은 0 row로 거부하고 같은 KST day 재호출을 만들면 안 됩니다. SLA capture는 DB gate로 cycle write와 직렬화하고, cutoff를 놓치면 current state를 재구성하지 않고 MISSED만 기록하세요. BE-40은 C-01에서 확정된 exact item contract만 노출하세요. 각 ticket은 test exit 0 raw output, reviewer verdict, PR URL/merge raw output을 TPM에 보내고, 선행 merged evidence 없이 후행 wave를 열지 마세요.

FE lead (private-senior-fe)

G0의 C-01 exact API 타입이 정정·확정된 뒤 FE-19를 진행하세요. origin/main 기준 feat/FE-19-collection-cycle-operations-visibility / .worktrees/FE-19을 사용합니다. BE-40 병합 전에는 MSW/optional additive contract와 legacy fallback으로 구현·검토할 수 있지만, G4에서 실제 BE-40 response fixture로 반드시 다시 검증하세요. closeGuarded 키가 있으면 서버 값만 사용하고 null도 legacy fallback의 근거로 쓰지 마세요. SLA UI는 captureStatus만으로 분기하며 브라우저 시간·current cycles로 count/items를 추론하지 마세요. build/test raw output, review verdict, PR merge evidence를 보고하세요.

Reviewers

Infra reviewer: DB-01에 대해 expand-only, no-FK/ENUM/inline-DML, column/index/unique key, Flyway validation, rollback compatibility를 확인하고 APPROVED, COMMENT, REQUEST_CHANGES verdict 및 근거를 남기세요.

Code reviewer: 각 BE/FE ticket PR에서 TDD/DB/FE 계약, wave의 single-writer scope, tests raw output, P0P3를 검토하세요. P0P3 모두 반영될 때만 squash auto-merge를 수행하세요. BE-43/40은 CAPTURING 비노출·immutable CAPTURED·MISSED no-reconstruction, BE-41은 legacy/v2 no-double-collection, FE-19는 optional/legacy 및 closeGuarded semantics를 필수 확인 항목으로 삼으세요.

진행 상태

도메인Wave 0Wave 1Wave 2Wave 3Wave 4Wave 5Wave 6
계약차단: C-01/C-02------
MySQL-대기 DB-01-----
BE--대기 BE-33대기 35~39/42/43대기 34/40대기 41검증 대기
FE--대기 FE-19---API 통합 검증 대기

차단 요인

  • C-01: FE SLA item 필드와 BE/DB immutable snapshot 필드가 일치하지 않는다.
  • C-02: MySQL 선행 migration을 추적·리뷰·PR 머지할 ticket ID가 없다.

이 두 항목이 해소되면 위 계획을 진행 중으로 전환하고 G1부터 실행한다.