# 0. 문서 상태 이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다. - 상태: confirmed - 문서 ID: dcy-033_20260621_suite-alarm-delivery-notifier - 이슈명: 제품군 알람 전달 체계 — 모듈 발신 + 중앙 notifier(trex-notifier) → 텔레그램(P1 아웃바운드) - 작성 시각(KST): 2026-06-21 (KST) - 마지막 갱신 시각(KST): 2026-06-21 (KST, draft-req trex-core-dev) - 대체됨: 없음 - 후속 Discovery 참조: 없음 - 생성된 REQ 참조: - trex-core: REQ-098 (알람 envelope wire 계약), REQ-099 (trex.alerts exchange 토폴로지), REQ-100 (core CRITICAL emitter 배선), REQ-101 (알람 발신 흐름 baseline 정합) — 모두 Approved - (cross-repo, 모듈 emitter/서비스 — 각 repo SRS) trex-orb-v1: REQ-039 / trex-tsl-v1: REQ-024 / kis-data-hub: REQ-057 / trex-notifier: REQ-001~008 — 모두 Approved (confirm-req 팀장 2026-06-21). ※각 dev가 trex-core 범위 밖이라 미기재한 역참조를 팀장이 보강. # 1. 계획 상태 요약 현재 Discovery가 어떤 배경에서 작성되고 있는지, 연계 문서가 있는지, 지금 시점의 해석이 무엇인지 짧게 요약한다. - 연계 문서 현황: - 관련 점수 파일: 미생성 - 관련 TODO/메모: `/home/genichin/workspace/trex-lead/ALARM-INVENTORY.md`(0단계 알람 인벤토리 스윕 결과 — core/orb/tsl/kdh ~100개 조건, 본 Discovery의 source-of-truth), `repos/trex-notifier`(부트스트랩 완료된 신규 서비스 repo) - 해석: - TREX 제품군엔 운영자에게 이상을 즉시 알리는 구조화된 알람 채널이 없다. ~100개 알람 후보가 로그(또는 예외)로만 존재하고, CRITICAL 상황도 운영자가 능동 인지해야 한다. M2(tsl 매도 라이브)에서 운영자가 첫 거래일을 수기 감시해야 하는 부담도 이 갭에서 나온다. - 토론으로 큰 방향은 확정됐다: 신규 `trex-notifier`가 알람을 중앙 수집해 텔레그램으로 전달(P1 아웃바운드만). 본 Discovery는 그 알람 **전달 계약과 아키텍처**를 trex-core 변경 단위로 정식화한다(envelope는 trex-core 소유 wire 계약). # 2. 요구사항 판정 결과 이번 요청이 기존 요구사항과 비교해 신규인지, 유사한지, 중복인지 판단하고 그 근거를 남긴다. - 판정: 신규 - 근거 - dcy-029(운영 관측성 — 로깅/PnL 뷰), dcy-031(이벤트 발행 신뢰성)은 인접하나 "이상을 운영자에게 능동 푸시"하는 알람 전달 체계는 어디서도 다루지 않았다. 기존은 전부 pull(로그/CLI) 기반이다. - 제품군 횡단 신규 컴포넌트(trex-notifier)와 신규 wire 계약(알람 envelope)을 도입하므로 독립 주기로 추적하는 편이 명확하다. # 3. 문제점의 요약 문제의 현재 상태, 기대 상태, 관련 이해관계자, 제약사항을 정리한다. - 현재 상태 - trex-core에 구조화 알람 채널 부재 — 운영자 표면은 CLI `trex-core report` + 구조화 로그(Loki)뿐(`daemon.py:248`에 alert 주석 1건). 푸시 메커니즘 없음. - 인벤토리 스윕(ALARM-INVENTORY.md) 결과: core/orb/tsl/kdh에 ~100개 알람 후보. 대부분 WARN/ERROR로 로깅되나 **일부 CRITICAL은 예외 raise만 되고 로그조차 없다**(예: 토큰 격리, RPC 타임아웃 누적). 등급도 모듈마다 제각각. - 연쇄/상관 실재: kis-data-hub 인증실패/다운 1건 → orb `kdh_auth_failure` + tsl `kis_auth_failure_abort` 동시 발생. 단 core safety-sell은 직접 KIS(다른 키)라 독립. - `trex-notifier` repo는 부트스트랩 완료(골격+거버넌스+baseline, root commit `078d37d`, private). 단 전송 방식·의존성은 본 Discovery 확정까지 비어 있다. - 기대 상태 - 각 모듈이 이상 조건을 표준 **알람 envelope**로 발신하면, 중앙 `trex-notifier`가 등급 판정·중복/상관 억제 후 CRITICAL은 텔레그램 즉시 푸시, WARN은 일일 다이제스트로 전달한다. - 크래시·정지로 자기 알람을 못 내는 데몬은 **하트비트(침묵=장애)** 로 탐지된다. - 알람 전달이 기존 wire 계약(slots RPC/trex.events)·로그 저장 경로를 건드리지 않는다(가산·격리). - 이해관계자 - 사장님 — 운영자(알람 최종 수신자), 범위·보안·외부노출 결재자 - 팀장(Claude) — Discovery/게이트, 인벤토리 작성자 - trex-core-dev — envelope 계약 + core emitter delivery - 각 모듈 dev(orb/tsl/kdh) — 모듈별 emitter delivery - service-dev — trex-notifier 서비스 delivery - 제약사항 - 기존 wire 계약(slots RPC, trex.events) 스키마 변경 금지 — 알람은 가산적 신규 채널로만. - orb/tsl/kdh는 `trex_core`를 import하지 않는다 — 공유는 **규약(envelope)** 이지 런타임 코드가 아니다(모듈당 thin emitter). - notifier는 로그 firehose 게이트웨이가 아니다 — 로그 저장은 인프라 슈퍼(Vector/Promtail→Loki) 담당. notifier는 알람만. - core는 텔레그램을 직접 호출하지 않는다(외부 의존·시크릿 격리). 시크릿(봇 토큰)은 notifier 1곳. - 알람 채널이 의존하는 인프라(RabbitMQ/Loki)가 장애나면 그 경로 알람이 못 나간다 → 하트비트 필요. ## 주요 사용자 시나리오 사용자 또는 운영자가 실제로 어떤 상황에서 이 변경을 필요로 하는지 대표 시나리오를 적는다. - 운영자: tsl 매도 라이브 첫날, `sell_signal_rejected_terminal`(포지션 못 팜) 발생 → 즉시 텔레그램 CRITICAL 푸시로 인지하고 개입. 현재는 로그를 들여다봐야만 알 수 있다. - 운영자: kis-data-hub 인증 만료 → orb·tsl 동시 알람을 notifier가 "시세 허브 장애 — 2개 모듈 영향" 1건으로 묶어 전달(폭풍 억제). - 운영자: tsl 데몬이 크래시해 침묵 → 하트비트 부재로 notifier가 "tsl 데몬 응답 없음" 알람. - 운영자: 장마감 후 WARN 다이제스트("오늘 백필 2건, watchdog 인수 0건, stale 양보 0건")로 비긴급 이상을 한 번에 검토. # 4. 이번에 정의할 변경 이번 Discovery에서 다루는 핵심 변경 항목을 목록으로 적는다. - 변경 1 — **알람 envelope 계약(trex-core 소유)**: `source / severity(critical·warn·info) / code / title / fields / occurred_at / schema_version` 표준 메시지 스키마 정의. 전 모듈이 이 규약으로 발신. - 변경 2 — **알람 전송 채널**: 전용 **`trex.alerts` AMQP exchange**(확정, 사장님 2026-06-21) — 가산·격리(기존 slots RPC/trex.events 불변). 모듈은 기존 RabbitMQ 연결로 발행, notifier가 단일 소비자. - 변경 3 — **모듈별 emitter**: core/orb/tsl/kdh 각 repo에 thin 알람 발신기(기존 연결 재사용, ~십수 줄). 인벤토리 CRITICAL 집합부터 배선. - 변경 4 — **trex-notifier P1**: 알람 수집 → 등급 판정 → 중복/상관 억제 → 텔레그램(CRITICAL 즉시 / WARN 다이제스트) + 하트비트. ## 영향 범위 변경이 미칠 코드/문서/운영 범위를 명시한다. - 코드 영향: - trex-core: 알람 emitter(신규) + `trex.alerts` 채널 선언(채택 시). 기존 execution/safety_sell 등의 CRITICAL 지점에서 emit 호출. - trex-orb-v1 / trex-tsl-v1 / kis-data-hub: 각 thin emitter + 주요 알람 지점 emit 호출(각 repo 별 batch). - trex-notifier: classifier/deduplicator/sender/heartbeat 구현 + 진입점 + 의존성(텔레그램·AMQP 라이브러리) 확정. - 문서 영향: - trex-core `docs/interface-contract.md` — 알람 envelope + `trex.alerts` 채널 계약 신설. - trex-core `docs/runtime-flows.md` — 알람 발신 흐름 추가(baseline 갱신). - trex-notifier `docs/runtime-flows.md` — TBD였던 전송 방식 확정 반영. - `docs/discovery/index.md` 갱신. - 운영 영향: - 운영자에게 텔레그램 알람 수신 채널·등급 정책이 신규 운영 절차로 추가(런북). - 봇 토큰·화이트리스트 chat id 운영 비밀로 관리(notifier 1곳). # 5. 요구사항 목록 실제로 구현과 검증으로 이어질 요구사항을 기능/비기능으로 나누어 정리하고, 범위 경계를 명확히 적는다. ## 기능 요구사항 - FR-1: 표준 알람 envelope 스키마(`source/severity/code/title/fields/occurred_at/schema_version`)를 trex-core가 wire 계약으로 정의하고 `docs/interface-contract.md`에 명시한다. - FR-2: 각 모듈(core/orb/tsl/kdh)이 인벤토리 CRITICAL 집합(ALARM-INVENTORY.md §A)의 조건 발생 시 envelope로 알람을 발신한다. - FR-3: trex-notifier가 알람을 수집해 등급별로 처리한다 — CRITICAL은 텔레그램 즉시 푸시, WARN은 일일 다이제스트, INFO는 제외(로그만). - FR-4: trex-notifier가 동일 근본원인의 상관 알람을 묶고(예: 시세 허브 장애 → 다모듈), 반복 알람을 rate-limit/중복 억제한다. - FR-5: trex-notifier가 하트비트(dead-man's switch)로 데몬 침묵=장애를 탐지·알린다. - FR-6: trex-core `docs/runtime-flows.md`에 알람 발신 흐름을, trex-notifier `docs/runtime-flows.md`에 확정 전송 방식을 반영한다(baseline 갱신). ## 비기능 요구사항 성능, 운영성, 일관성, 자동화 안정성 등 기능 외 요구사항을 적는다. - NFR-1: 알람 채널은 **가산·격리** — 기존 wire 계약(slots RPC, trex.events) 스키마를 변경하지 않는다. orb/tsl/kdh 기존 동작 무회귀. - NFR-2: 보안 — 텔레그램 봇 토큰 시크릿은 notifier 1곳에만, 수신 대상은 화이트리스트(사장님 chat id). core/orb/tsl/kdh에 외부 시크릿 유입 없음. - NFR-3: 신뢰성 — 알람 경로(notifier/RabbitMQ)가 죽어도 모듈 본업(매매)과 로그 저장은 영향 없음. notifier는 SPOF가 아니다. - NFR-4: 모듈측 비용 최소 — emitter는 thin(기존 연결 재사용), `trex_core` import 없이 envelope 규약만 공유. ## 범위 경계 이번 반복에서 반드시 포함할 범위와 명시적으로 제외할 범위를 구분한다. - In Scope - 알람 envelope 계약 + 전송 채널 + 모듈 emitter(CRITICAL 집합) + trex-notifier P1(수집·등급·상관/중복억제·텔레그램·하트비트). - Out of Scope - **인바운드 명령 게이트**(텔레그램으로 시스템 제어) — P2/P3 후속 별도 discovery(보안·인가·감사). - **로그 저장/Loki 적재** — 인프라 슈퍼(Vector/Promtail) 담당. notifier 경유 금지. - 인벤토리 ~100개 code 전량 배선 — CRITICAL 우선, WARN 다이제스트는 점진. INFO 제외. - 후보 C(core가 외부 푸시 직접 호출), 기존 slots RPC/trex.events 스키마 변경. # 6. 리스크/가정 목록 불확실성과 전제 조건을 분리해서 적는다. ## 리스크 - R-1 (Medium): 알람 폭풍 — 장애 시 다모듈·매사이클 알람이 쏟아져 알람 피로 유발. - 완화 방안: notifier 상관/중복억제 + rate-limit(FR-4) + 등급화(CRITICAL만 즉시 푸시). - R-2 (Medium): 알람의 역설 — 알람 채널이 의존하는 인프라(RabbitMQ/notifier) 장애 시 그 경로 알람 미전달. - 완화 방안: 하트비트(침묵=장애, FR-5). 매매 안전망(core safety-sell)은 알람과 독립이라 알람 실패가 거래 보호를 깨지 않음. - R-3 (Low): 보안 — 봇 토큰 유출 시 알람 수신 노출(P1은 읽기 방향이라 제어 위험은 없음). - 완화 방안: 토큰 1곳 격리(NFR-2), 화이트리스트, 인바운드 명령은 범위 밖(P3로 분리). ## 가정 아직 확정되지 않았지만 현재 문서 작성의 기반이 되는 전제를 적는다. - A-1: 모듈들은 이미 RabbitMQ 연결을 보유(core=broker, orb/tsl=intent/slots RPC)하므로 AMQP emitter는 기존 연결 재사용으로 저비용이다. - A-2: 알람은 저빈도 이벤트라 전용 채널의 트래픽·복잡도 부담이 작다. - A-3: 인프라 로그 슈퍼(Vector/Promtail→Loki)는 알람과 별개로 존재/구성된다(로그 저장은 본 범위 밖). - A-4: trex-notifier는 단일 컨테이너 내 bare 프로세스로 다른 모듈과 공존 배포된다. ## 오픈 질문 답을 아직 모르는 항목을 적는다. - OQ-1: 모듈→notifier 알람 전송 방식 — **전용 `trex.alerts` AMQP exchange**(권고: 실시간·격리·소비자 상관억제) vs **로그-tee**(슈퍼가 alert 라인 tee, 모듈측 코드 0이나 Loki 의존·지연). - 상태: Answered — **전용 `trex.alerts` AMQP exchange로 확정**(사장님 2026-06-21). - 처리 방안: trex-notifier는 `trex.alerts` 소비자. 각 모듈은 기존 RabbitMQ 연결로 발행. 가산·격리(orb/tsl 기존 계약 불변). trex-notifier 의존성(AMQP 클라이언트)·runtime-flows에 반영. - 종료 조건: 충족됨. - OQ-2: P1 즉시-푸시(CRITICAL paging) 대상 code 집합 확정 — ALARM-INVENTORY.md §A 제안 집합을 사장님이 검토해 실제 폰을 울릴 항목을 확정. - 상태: Answered — **ALARM-INVENTORY.md §A 전체(약 25개 code)를 P1 CRITICAL paging으로 채택**(사장님 2026-06-21). 항목 축소 없음 — 알람 폭풍은 항목 삭제가 아니라 notifier 상관/rate-limit(FR-4)으로 제어. - 처리 방안: §A의 core/tsl/orb/kdh CRITICAL code 전체가 즉시-푸시 대상. delivery에서 각 모듈 emitter가 해당 code 배선. - 종료 조건: 충족됨. # 7. 초기 성공 기준 이 변경이 성공했다고 판단할 기준을 측정 가능하게 정의한다. - S-1: 확정된 CRITICAL 조건 발생 시 운영자 텔레그램에 알람이 도달한다(엔드투엔드). - S-2: 동일 근본원인의 다모듈 알람이 1건으로 묶이고, 반복 알람이 rate-limit된다(폭풍 억제). - S-3: 데몬 침묵(크래시/정지) 시 하트비트 부재로 장애가 탐지된다. 기존 wire 계약·매매 동작은 무회귀. ## 측정 방식 및 데이터 출처 각 성공 기준을 어떻게 측정할지와 어떤 데이터나 문서를 근거로 쓸지 적는다. - S-1 측정 방식: CRITICAL 조건 주입(테스트/시뮬) → 텔레그램 수신 확인 / 데이터 출처: notifier 로그 + 텔레그램 메시지. - S-2 측정 방식: 다모듈 동시 알람·반복 알람 주입 → 묶임/억제 단언 / 데이터 출처: notifier 상관·rate-limit 테스트. - S-3 측정 방식: 데몬 하트비트 중단 시뮬 → 장애 알람 발생 단언 + 기존 wire/매매 회귀 스위트 / 데이터 출처: notifier 테스트 + 각 모듈 회귀 테스트(interface-contract diff 0). # 8. REQ로 넘기기 전 확인 체크 REQ 초안 작성 단계로 넘기기 전에 무엇이 확정되어야 하는지 확인한다. - [x] 범위(In Scope/Out of Scope) 확정 - 기준: P1(아웃바운드 알람)만 In Scope, 명령 게이트·로그 저장 제외에 사장님 동의 — 확정(토론 합의) - [x] 성공 지표의 측정 방식/데이터 출처 확정 - 기준: S-1~S-3 측정안 합의 - [x] High 영향 리스크 우선순위 및 해소 책임자 지정 - 기준: 현재 High 리스크 없음(R-1/R-2 Medium) — 폭풍억제·하트비트 책임자(notifier service-dev) 지정 - [x] 모든 오픈 질문(OQ) `Open` 상태 없음 확인 - 기준: OQ-1(전송=`trex.alerts` AMQP)·OQ-2(paging=§A 전체) 모두 Answered(사장님 2026-06-21) - [x] Freeze 확정 담당자(CONFIRMED_BY) 지정 - 기준: confirm-discovery 시 팀장이 CONFIRMED_BY로 기록 — 팀장(Claude) # 9. 파일 처리 결과 이 Discovery 문서 생성/갱신 결과와 참조 문서를 기록한다. - 처리 결과: 생성 - 생성 경로: docs/discovery/dcy-033_20260621_suite-alarm-delivery-notifier.md - 참조 문서: - /home/genichin/workspace/trex-lead/ALARM-INVENTORY.md (인벤토리 스윕 — 현재상태/요구사항 근거) - docs/discovery/dcy-029_20260616_operational-observability-logging-and-pnl-view.md (운영 관측성 인접) - docs/interface-contract.md, docs/runtime-flows.md (envelope/채널 계약 + 발신 흐름 baseline 갱신 대상) # 10. 사용자 결정 필요 항목 요약 사용자나 승인자가 결정해야 하는 항목만 모아 정리한다. ## DECIDE - (해소) 알람 전송 방식 = 전용 `trex.alerts` AMQP exchange — 사장님 확정(2026-06-21, OQ-1). - (해소) P1 CRITICAL paging 집합 = ALARM-INVENTORY.md §A 전체(약 25개 code) — 사장님 확정(2026-06-21, OQ-2). ## CONFIRM - (확정) P1(아웃바운드 알람)만 범위, 인바운드 명령 게이트·로그 저장은 후속 분리 — 사장님 확정(2026-06-21). ## DATA - {{DATA_TELEGRAM_BOT}} — 텔레그램 봇 토큰 + 수신 chat id(화이트리스트). delivery 단계 필요(사장님 BotFather 생성). # 11. Discovery Freeze REQ 초안 작성 인계 시점의 확정 플래그와 섹션 참조만 기록한다. ## 섹션 참조 - 범위: [# 5. 요구사항 목록 > 범위 경계](#5-요구사항-목록) - 리스크/오픈 질문: [# 6. 리스크/가정 목록](#6-리스크가정-목록) - 성공 기준: [# 7. 초기 성공 기준](#7-초기-성공-기준) - 인계 전 확인: [# 8. REQ로 넘기기 전 확인 체크](#8-req로-넘기기-전-확인-체크) - 사용자 결정 필요: [# 10. 사용자 결정 필요 항목 요약](#10-사용자-결정-필요-항목-요약) ## Freeze 플래그 - Handoff Decision: REQ Drafting 진행 가능 - Handoff Rationale: confirm-discovery 완료. OQ-1(전송=`trex.alerts` AMQP)·OQ-2(paging=§A 전체) 모두 사장님 확정 → Open OQ 0건. 범위(P1 아웃바운드)·성공기준·리스크 책임자 확정. DATA(텔레그램 봇 토큰)는 delivery 단계 필요(비차단). 단 **구현(delivery)은 첫 tsl REL(M2) 이후 큐잉** — draft-req는 병렬 가능하나 delivery 우선순위는 M2 뒤. - Ready for REQ Drafting: true - Confirmed By: 팀장(Claude) - Confirmed At (KST): 2026-06-21 (KST)