feat(multi-instance): dcy-009 BAT-013 — RabbitMQ 다중 인스턴스 토폴로지 (REQ-048~051)

dcy-009(다중 인스턴스 RabbitMQ 토폴로지) 전체 SDLC: draft-req → confirm-req →
draft-batch(BAT-013) → run-batch-delivery → confirm-req-implemented.

- REQ-048 (Configuration): DaemonInstanceConfig.from_toml + DaemonConfig.from_config
  (env 병합, portfolio_hub_token 주입) + 데몬 --config 필수 argparse + .gitignore 인스턴스
  TOML + config/instance.example.toml
- REQ-049 (Interface): topology 동적 큐명 빌더 intent/snapshot/control_queue(instance_key)
  — default=리터럴 큐명(하위호환), named=`{base}.{instance_key}` + daemon per-instance 구독
- REQ-050 (Integration): trex.direct(topic)/trex.broadcast(fanout) exchange +
  declare_topology(instance_key) per-instance binding + control dual binding + direct_routing_key
- REQ-051 (Documentation): interface-contract/runtime-flows/project-structure 정합

하위호환: instance_key="default" → 기존 리터럴 큐명·RPC 경로 무회귀(FR-5).
split-brain 방지(NFR-3): 인스턴스 전용 큐. 민감값(NFR-4): TOML + gitignore.

검증: 신규 9 단위 + RabbitMQ 라우팅 2, 단위 271 passed,
인프라 게이트 301 passed(directed 격리 S-2 + broadcast dual S-3 + default 무회귀 S-4),
ruff clean. REQ-048~051 Implemented, BAT-013 release-candidate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 15:10:36 +09:00
co-authored by Claude Opus 4.8
parent 7e23648489
commit 9f83c64a40
24 changed files with 1223 additions and 85 deletions
@@ -0,0 +1,148 @@
# req-048: per-instance TOML 설정 로더 + `--config` 필수
- Status: Implemented
- Type: Configuration
- Priority: High
- Owner: project maintainers
## Intent
다중 인스턴스 운영을 위해 인스턴스별 TOML 설정 파일을 도입한다. 데몬 기동 시 `--config <path>.toml` 인자를 **필수**로 받고, TOML 에서 `instance_key` 와 `portfolio_hub_token` 을 읽는다. 이 두 값은 `.env` 에 넣지 않는 것을 원칙으로 하며(민감값 분리), 기존 `DaemonConfig.from_env()` 와 병합해 최종 설정을 구성한다(dcy-009 FR-1, NFR-4, OQ-2/A-5).
## Requirement
- `config.py` 에 `DaemonInstanceConfig` dataclass(`instance_key: str`, `portfolio_hub_token: str`)와 `from_toml(path)` 로더를 추가한다(stdlib `tomllib` 사용).
- `DaemonConfig` 구성 시 `--config <path>.toml` 의 TOML 값을 `from_env()` 결과와 병합하는 팩토리(예: `from_config(toml_path)`)를 추가한다. `portfolio_hub_token` 은 TOML 값을 사용해 `PortfolioHubConfig.token` 에 주입한다.
- 데몬 기동 진입점은 `--config` 를 **필수 인자**로 받는다. 인자 없이 기동하면 오류 메시지를 출력하고 비정상 종료(exit code ≠ 0)한다. 기본값 fallback 없음(OQ-2 Answered).
- `instance_key` 와 `portfolio_hub_token` 은 `.env`/OS env 에서 읽지 않는다. TOML 미존재/필수 필드 누락 시 명확한 오류로 종료한다.
- `.gitignore` 에 인스턴스 TOML 경로 패턴(예: `*.toml` 또는 `config/*.toml`)을 추가해 설정 파일이 커밋되지 않게 한다. 토큰/instance_key 는 로그에 평문 출력하지 않는다(NFR-4).
## Acceptance Criteria
1. Given `inst-1.toml`(`instance_key="inst-1"`, `portfolio_hub_token="tok"`), When `DaemonInstanceConfig.from_toml("inst-1.toml")`, Then `instance_key="inst-1"`, `portfolio_hub_token="tok"` 로 파싱된다.
2. Given `--config` 인자 없이 데몬 기동, When 진입점 실행, Then 오류 메시지 출력 + exit code ≠ 0 으로 종료한다(기본값 fallback 없음).
3. Given TOML 에 `portfolio_hub_token` 이 있고 `.env`/OS env 에 `TREX_PORTFOLIO_HUB_TOKEN` 미설정, When 최종 설정 구성, Then `PortfolioHubConfig.token` 에 TOML 값이 주입된다(S-5).
4. Given TOML 에 필수 필드(`instance_key`) 누락, When `from_toml`/`from_config`, Then 명확한 오류로 실패한다(조용한 기본값 금지).
5. Given 저장소, When `.gitignore` 확인, Then 인스턴스 TOML 경로 패턴이 무시 대상이다.
6. Given 데몬 기동 로그, When 출력 확인, Then `portfolio_hub_token` 평문이 로그에 노출되지 않는다.
## Impacted Area
- Docs:
- `docs/project-structure.md` — 설정 파일 계층(TOML + env) (REQ-051 처리)
- Modules:
- `trex_core/runtime/config.py` — `DaemonInstanceConfig` + `from_toml` + `from_config` 병합
- 데몬 진입점(`trex_core/runtime/daemon.py:main` 또는 `__main__`) — `--config` 필수 파싱(argparse)
- `.gitignore` — 인스턴스 TOML 패턴
- Tests:
- `tests/runtime/` — TOML 로더 파싱/필수 인자/토큰 주입/누락 오류
## Notes
- dcy-009 OQ-2 Answered: `--config` 필수, fallback 없음(split-brain 위험 회피). A-5.
- NFR-4(민감값 비노출)는 본 REQ 의 gitignore + 로그 미노출 AC 로 흡수.
- DATA_TOML_SCHEMA_FULL(dcy-009 §10): 최소 필드 `instance_key`/`portfolio_hub_token`. 추가 필드는 본 REQ 구현 스키마에서 확장 가능.
- KIS 자격증명/DSN/RABBITMQ_URL 등 나머지 env 는 이번 범위에서 `.env` 유지(CONFIRM_ENV_RESIDUAL).
## Change Log
### CHG-20260607-01
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- dcy-009(confirmed) → REQ-048 초안 생성.
#### Intent
- per-instance TOML 로더 + `--config` 필수(FR-1, NFR-4)를 Configuration REQ 로 정규화.
#### Acceptance Criteria Delta
- Added: AC-1~6 전체
#### Impacted Area Delta
- Docs: project-structure.md (REQ-051)
- Modules: config.py, daemon 진입점, .gitignore
- Tests: tests/runtime TOML 로더
#### Delivery Trace Delta
- Batches: none (미할당)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: confirm-req 로 승인.
### CHG-20260607-02
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- Proposed → Approved (confirm-req).
#### Intent
- 승인 게이트 통과: 필수 필드·구체 AC·Impacted Area·Change Log 완비. dcy-009(confirmed) 범위·결정(OQ-2 TOML 필수)과 모순 없음. TOML 추가 필드 스키마는 구현 단계 확장 가능 비핵심.
#### Acceptance Criteria Delta
- (변경 없음)
#### Impacted Area Delta
- (변경 없음)
#### Delivery Trace Delta
- Batches: none (미할당)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current
- Follow-up Action: suggest-batch-reqs / draft-batch 로 delivery 편성.
### CHG-20260607-03
- Date: 2026-06-07
- Author: Justin Ko
#### Change Summary
- Status Approved → Implemented (confirm-req-implemented, 근거 batch BAT-013 release-candidate).
#### Intent
- BAT-013 verification 의 AC↔evidence(로더 6 단위: from_toml/필수 누락/token 주입 S-5/default ik/`--config` 누락 subprocess 종료 AC-2/gitignore)로 AC-1~6 충족. NFR-4(민감값) 흡수.
#### Acceptance Criteria Delta
- (변경 없음)
#### Impacted Area Delta
- (변경 없음)
#### Delivery Trace Delta
- Batches: BAT-013 (release-candidate)
- Releases: none
#### Revalidation Impact
- Reverification Needed: no
- Existing Implementation Invalidated: no
- Status Recommendation: keep-current (Implemented)
- Follow-up Action: draft-release 로 BAT-013 배포 편성. token .env 제거는 배포 rollout.