# Trex Core Project Structure - Baseline Mode: mixed - Baseline Seed: .stage-pilot/bootstrap/baseline.yaml - Status: draft - Owner: project maintainers - Last Updated (KST): 2026-07-29 (BAT-062 — 공통 계좌 자본배분 순수 정책) - Source Discovery / Batch: bootstrap-baseline (pre-Discovery, 3-phase lifecycle 밖의 bootstrap 산출물) ## Project Summary - trex 제품군의 공용 베이스로, 첫 도메인으로 trex-orbit 의 일일 거래 슬롯 생명주기(slot) 순수 도메인을 storage-agnostic 하게 이식한 코어다. ## Primary Domain - 자동매매 **자산 중심 영구 슬롯** 생명주기 도메인 (dcy-020 — universe 자산 1:1 영구 슬롯; 일일 풀 모델은 BAT-030 에서 폐기, DB 는 `trex-core-reset` 로 재초기화) ## Tech Stack - Python >=3.12 - pyproject.toml 기반 패키지 (setuptools) - pytest (단위 테스트) - ruff (린트) - storage-agnostic 순수 도메인 (현재 in-memory repository, PostgreSQL/psycopg 는 향후 영속화 단계에서 도입 예정) ## Primary Runtime - Type: daemon (sync + thread, no HTTP) + library (slot 도메인) - Entry Points: - `trex-core-daemon --config .toml` (console_script → `trex_core.runtime.daemon:main`) :: 슬롯 코어 데몬 — `--config` 필수(per-instance TOML; `max_active_slots`=M 캡). migrate+reconcile 후 7 백그라운드 스레드(intent RPC consumer / snapshot RPC consumer / control RPC consumer / snapshot scheduler[universe 슬롯 reconcile 포함] / execution / ledger / safety-sell)를 `instance_key` 큐로 기동, RabbitMQ messaging 으로 전략 모듈과 통신 (BAT-002 + BAT-007 + BAT-008 + BAT-011 + BAT-012 + BAT-013 + BAT-028/030) - `trex-core` (console_script → `trex_core.runtime.cli:main`) :: 운영 CLI (`pause`/`resume`/`paused` + `universe`/`slots`/`enter`/`exit`) (BAT-008/020) - `trex-core-reset` (console_script → `trex_core.runtime.reset:main`) :: DB 를 자산 중심 스키마로 wipe + 재초기화 (REQ-064, BAT-030 — 데이터 보존 cutover 대체; 운영자 실행, dry-run 기본, 파괴적·DB 전역) - RabbitMQ `trex.snapshot.req` / `trex.intent.req` / `trex.pause.req` / `trex.events` :: 매수·매도 전략 데몬과의 transport (docs/interface-contract.md) - SlotService / SlotRepository (Protocol) :: in-process 도메인 서비스 + 저장소 경계(라이브러리 사용) - MessagingTransport (Protocol) :: transport 추상화 (RabbitMQ / InMemory stub) - PortfolioHubReadPort (Protocol) :: portfolio-hub universe read 경계 (BAT-008) ## Purpose - This document is the current approved repository and package structure baseline. - It is a cross-cutting reference document for Discovery, REQ, Batch Design, Batch Verification, and implementation updates. ## Scope - Covers the top-level repository layout and package/module boundaries. - Does not duplicate detailed business rules, acceptance criteria, or implementation-only function signatures. ## Top-Level Structure ```text . ├── .github/ # Copilot instructions + StagePilot skill entrypoints │ ├── instructions/ │ └── skills/ ├── .stage-pilot/ # StagePilot 도구/템플릿/부트스트랩 seed │ ├── bootstrap/ │ │ └── baseline.yaml │ └── templates/ ├── docs/ # SDLC baseline 문서 + active index │ ├── batches/index.md │ ├── discovery/index.md │ ├── releases/index.md │ ├── srs/index.md │ ├── data-model.md │ ├── interface-contract.md │ ├── project-structure.md │ └── runtime-flows.md ├── CLAUDE.md # SDLC governance instructions ├── pyproject.toml # 패키지 메타(배포명 trex-core) + console_scripts(trex-core-daemon) + deps ├── trex_core/ │ ├── __init__.py │ ├── domain/slot/ # slot 순수 도메인 (BAT-001, 무의존) │ │ ├── __init__.py · state.py · models.py(+EXPECTED_SLOT_FIELDS) · errors.py │ │ ├── repository.py(Protocol, instance 스코프) · service.py · in_memory_repository.py │ ├── domain/capital_allocation.py # 전략 공통 계좌 자본배분 순수 정책 (BAT-062 / REQ-127) │ ├── domain/pricing.py # KRX 호가단위(tick) 산출 순수 함수 (BAT-044 / REQ-083, dcy-030) │ ├── application/ # 유스케이스 (BAT-002, BAT-004, BAT-006, BAT-007, BAT-008) │ │ ├── ports.py # IntentStore Protocol │ │ ├── intents.py # IntentService / BuyIntent / SellIntent / IntentDecision │ │ ├── broker_port.py # BrokerPort + OrderRequest/OrderAck/FillStatus + BalanceItem + calculate_fee (BAT-004/BAT-006/BAT-008) │ │ ├── execution.py # ExecutionService (dispatch·poll·transition·reconcile + ledger enqueue + event emit hook) │ │ ├── ledger_port.py # LedgerPort + LedgerTrade/LedgerWriteResult/예외 (BAT-006) │ │ ├── ledger_outbox.py # LedgerOutbox Protocol + LedgerWriter + InMemoryLedgerOutbox (BAT-006) │ │ ├── messaging.py # MessagingTransport Protocol + DTO + TransportHealth + keepalive_tick() no-op (BAT-007, BAT-047/REQ-092) │ │ ├── messaging_handlers.py # intent/snapshot/pause RPC handlers (+update_thresholds REQ-040) + slot event payload builder (BAT-007/BAT-008/BAT-011) │ │ ├── portfolio.py # PortfolioHubReadPort + SnapshotStore + PauseStore + envelope builder (BAT-008) │ │ ├── reconciliation.py # reconcile_positions + reconcile_core_holdings(REQ-062) (BAT-008/029) │ │ ├── snapshot_scheduler.py # SnapshotScheduler — daily fetch + swap + universe 슬롯 reconcile(REQ-058) (BAT-008/028) │ │ ├── watchdog.py # WatchdogStore — per-slot last_seen_at + expiry/grace 판정 (BAT-010 / REQ-034) │ │ ├── safety_sell.py # SafetySellService — forced_close / stop-loss·take-profit / 장 마감 트리거 (BAT-011 / REQ-037~039) │ │ ├── killswitch.py # KillSwitchService — 범위별 holding 즉시 청산 + day-scoped 제외 (BAT-012 / REQ-045) │ │ └── operator_report.py # 운영 조회 리포트 집계(보유·오늘 체결·실현 PnL·대기) 순수 함수 (BAT-046 / REQ-088, dcy-029) │ ├── adapters/ # 인프라 어댑터 (BAT-002, BAT-004, BAT-006, BAT-007, BAT-008) │ │ ├── broker/ # paper.py(결정적 async 더블 + 현재가 stub) · kis.py(KIS Open API + 잔고조회 + 현재가 polling) (BAT-004/BAT-008/BAT-011) │ │ ├── ledger/ # in_memory.py(stub) · portfolio_hub.py(HTTP 어댑터) (BAT-006) │ │ ├── messaging/ # topology.py(동적 큐명 빌더 + trex.direct/trex.broadcast exchange, BAT-013) · in_memory.py(stub, keepalive_tick no-op) · rabbitmq.py(pika 동기, declare_topology(instance_key), publish_event 재시도+강제 재연결, keepalive_tick, _publish_dlq ERROR 로그) (BAT-007/BAT-013/BAT-047) │ │ ├── portfolio/ # hub_read.py(HTTP) · stub_read.py(stub) · pause_store.py(Postgres) · killswitch_store.py(day-scoped, BAT-012) (BAT-008) │ │ └── persistence/ # postgresql.py(+PostgreSQLLedgerOutbox) · ops_checks.py(ledger-gap, transition_log 기반) · in_memory_intent_store.py · migrate.py · sql/(001~009, 010_literal_inactive_status.sql, 011_drop_pool_model_columns.sql) │ └── runtime/ # 데몬 (BAT-002, BAT-004, BAT-006, BAT-007, BAT-008) │ ├── config.py # DaemonConfig(+instance_key, max_active_slots) + KISConfig + PortfolioHubConfig + RabbitMQConfig + SnapshotScheduleConfig + SafetySellConfig + DaemonInstanceConfig.from_toml/from_config (env + per-instance TOML, BAT-013/028/030) │ ├── daemon.py # Daemon class: `--config` TOML 진입점(BAT-013) + setup(migrate/reconcile/declare-topology(instance_key)) + 7 worker threads(instance_key 큐 구독) + WatchdogStore + KillSwitchService + graceful shutdown. _execution_loop 각 틱 시작 시 event_publisher.keepalive_tick() 호출(REQ-092). _make_event_emitter 발행 최종 실패 시 ERROR 로그(REQ-093). │ ├── broker_provider.py # daemon/CLI 공용 broker source resolution: KIS fetched/env/break-glass와 day-scoped fetched credential 재사용 (BAT-057 / REQ-119) │ ├── reset.py # trex-core-reset: slot-core 테이블 wipe + 자산 중심 재초기화 (REQ-064, BAT-030) │ ├── logging_setup.py # 구조화 로깅(ISO8601 KST·레벨·Loki JSON·correlation id) + configure_logging (BAT-045 / REQ-084, dcy-029) │ └── cli.py # trex-core CLI: pause/resume/paused + universe/slots/enter/exit/cancel + report(REQ-088) (BAT-008/020/046 / REQ-032) └── tests/ ├── domain/slot/ # test_state / test_service / test_contract ├── domain/test_capital_allocation.py # 메가·탑50 대표값 + 무작위 현금 불변식 (BAT-062) ├── domain/ # test_domain_import_sweep (NFR-1 가드, BAT-006/BAT-007) ├── application/ # test_intent_concurrency · test_execution · test_execution_ledger · test_ledger_outbox · test_messaging_intent_consumer · test_messaging_snapshot_consumer · test_messaging_event_publisher ├── runtime/ # test_config_dotenv · test_daemon_no_http_surface (BAT-007 HTTP 표면 0 회귀 가드) ├── adapters/{broker,ledger,messaging,persistence}/ # paper/KIS · in_memory/portfolio-hub ledger · stub/RabbitMQ transport (게이트) · PG repo/migration/outbox │ └── messaging/test_publish_reliability.py # BAT-047 신규 — publish 재시도/keepalive/DLQ 가시성 단위 테스트 (mock 기반, 17건) ``` > 참고: domain(BAT-001)은 무의존 코어. application/adapters/runtime 은 BAT-002 에서 추가, BAT-004 에서 broker/execution 레이어 확장, BAT-006 에서 ledger 레이어 추가, BAT-007 에서 messaging 레이어(application MessagingTransport + adapters/messaging + sync+thread 데몬) 추가와 HTTP 어댑터 제거. 외부 의존(psycopg/httpx/redis/pika)은 adapters/runtime 에만 격리(NFR-1, import 스윕으로 강제). 브로커 주문은 BrokerPort 단일 세션(불변식 B), 슬롯 쓰기는 SlotService 단일 writer(불변식 A), ledger 기록은 집행 경로 단일 주체(NFR-3), 메시지 transport 는 MessagingTransport 단일 경계. ## Package / Module Responsibilities - `trex_core/domain/slot/` - 자산 중심 영구 슬롯 순수 도메인. 5 상태 머신(`state.py`, inactive 기준 + 인스턴스 스코프 advisory lock id), 데이터 모델 + 컬럼 계약(`models.py`, `EXPECTED_SLOT_FIELDS` 포함), 예외(`errors.py`), 저장소 계약(`repository.py` Protocol — instance 스코프 list/count/reconcile), 도메인 서비스(`service.py`), in-memory 구현(`in_memory_repository.py`). - 외부 의존 0 — stdlib 와 패키지 내부 참조만 사용(정적 import 스윕으로 확인됨). - `trex_core/domain/capital_allocation.py` (BAT-062 / dcy-042) - 계좌 가용 현금, 슬롯 수, 후보별 보호 한 주 가격을 받아 후보별 최대 배정액과 제외 사유를 결정한다. - 브로커·Portfolio Hub·전략·환경·저장소를 읽지 않는다. 호출 계층이 외부 입력과 후보·슬롯을 제공하고 최종 주문수량을 산출한다. - 최악 활성 슬롯 배정 합이 실제 현금을 넘지 않는 불변식을 모듈 내부와 속성 테스트에서 검증한다. - `trex_core/application/strategy_state.py` (BAT-042 / dcy-028) - slot strategy-state 저장소 경계: `StrategyStateStore` Protocol + `InMemoryStrategyStateStore` + 공용 `_cas`(occupancy_seq+version) + reject reason 상수 + byte size cap. opaque UTF-8 `data`(core 무해석). PG 구현은 `adapters/persistence/postgresql.py`의 `PgStrategyStateStore`(`slot_strategy_state` 테이블, 마이그레이션 014/015). 슬롯 본체에는 `Slot.occupancy_seq` 컬럼 1개만 추가(full 3계층 분할은 후속). - `tests/domain/slot/` - 상태머신/서비스 단위 테스트(`test_state`, `test_service`) + 컬럼 계약 가드(`test_contract`). InMemorySlotRepository 기반으로 실제 DB 없이 검증. - `docs/` - SDLC baseline(구조/흐름/인터페이스/데이터 모델) 및 active index(discovery/srs/batches/releases). - `pyproject.toml` - 패키지 메타데이터(배포명 `trex-core`, `requires-python >=3.12`), dev 의존성(pytest/ruff), pytest/ruff 설정. ## Dependency Rules - 순수 도메인(`trex_core/domain/slot/`, `trex_core/domain/capital_allocation.py`)은 저장소 구현, 브로커, 네트워크, CLI 등 인프라에 직접 의존하지 않는다. - 저장소 접근은 오직 `SlotRepository` Protocol 을 통해서만 이뤄지고 구현체는 주입된다. - 인프라(향후 PostgreSQL 구현, CLI, config)는 도메인을 의존할 수 있으나 그 역은 금지한다. ## Shared Boundaries - `SlotRepository` Protocol 이 도메인 ↔ 저장소 사이의 단일 경계다. - `slot_advisory_lock_id(instance_key)` 가 상태 변경 직렬화의 공유 기준점이다(인스턴스 스코프 — 공유 DB 인스턴스 간 격리, REQ-057). ## Current Gaps / Planned Changes - 영속화 구현체(PostgreSQL repository)와 SQL 스키마/마이그레이션은 이번 범위 밖 — 향후 도입. - CLI / 설정(config) 표면 없음(trex-orbit 의 `trex slot` CLI 미이식). - 패키지 네임스페이스는 `trex_core.domain.slot` 으로 확정(dcy-001 OQ-1, 배포명 `trex-core`). - 컬럼 계약 드리프트는 `EXPECTED_SLOT_FIELDS` + `test_contract.py` 로 강제(DB-side 검사는 영속화 반복 인계). ## Update Triggers - Update this document when package boundaries change. - Update this document when new top-level runtime or domain modules are added. - Update this document when a batch changes the approved structure baseline. ## Change Log - 2026-06-03 :: bootstrap-baseline 으로 초기 구조 baseline 생성(mixed: trex-orbit 코드 관찰 + 이관 계획 선언). - 2026-06-03 :: dcy-001 OQ-1 결정 반영 — planned 네임스페이스를 `app/` → `trex_core/` 로 정정(배포명 `trex-core`). - 2026-06-03 :: BAT-001 이식 완료 반영 — `trex_core/`·`tests/`·`pyproject.toml` planned→실제 정합(REQ-004). - 2026-06-03 :: BAT-002 — application/adapters/runtime 레이어(데몬+HTTP API+PostgreSQL) 추가, Primary Runtime=daemon+library(REQ-005~009). - 2026-06-04 :: BAT-004 — 브로커 집행 레이어 반영(BrokerPort/paper·KIS 어댑터, execution 루프, broker_order_id 실행큐·멱등, reconciliation) (REQ-011~015). - 2026-06-04 :: BAT-006 — ledger 레이어 추가(application LedgerPort/LedgerOutbox, adapters/ledger in_memory·portfolio_hub, persistence PostgreSQLLedgerOutbox + 002 마이그레이션, runtime ledger writer 루프, FillStatus 확장, NFR-1 import 스윕) (REQ-017~020). - 2026-06-05 :: BAT-007 — transport 전환(`adapters/api/` 제거, `application/messaging.py` + `application/messaging_handlers.py` 신설, `adapters/messaging/` 신설(topology/in_memory/rabbitmq), runtime/daemon 을 sync+thread 4 스레드 구조로 재구성, `RabbitMQConfig` + `TREX_RABBITMQ_URL` env, `TREX_API_HOST`/`TREX_API_PORT` 폐기, `fastapi`/`uvicorn` 의존 제거 + `pika` 도입, NFR-1 import 스윕에 pika/messaging 추가, HTTP 표면 0 회귀 가드) (REQ-021~026). - 2026-06-06 :: BAT-008 — portfolio-hub 스냅샷 read 레이어 추가(`application/portfolio.py` + `application/reconciliation.py` + `application/snapshot_scheduler.py` 신설, `adapters/portfolio/` 신설(hub_read/stub_read/pause_store), `BrokerPort.get_balance()` 확장 + paper/KIS 구현, `messaging_handlers` 에 snapshot envelope + pause RPC 추가, runtime/daemon 을 6 스레드로 확장(pause-rpc + snapshot-scheduler), `SnapshotScheduleConfig` + `TREX_SNAPSHOT_*` env, `runtime/cli.py` + `trex-core` 콘솔 스크립트, `003_create_snapshot_pause.sql` 마이그레이션, NFR-1 import 스윕 유지) (REQ-027~033; REQ-030 옵션 D 는 portfolio-hub#8 배포 후 별도 구현). - 2026-06-07 :: BAT-010 — safety-sell 기반 인프라(`application/watchdog.py` WatchdogStore 신설, `Slot` 에 `stop_loss_price`/`take_profit_price` 필드 + `004_add_price_thresholds.sql` additive 마이그레이션, `SlotService.sell()` 자율 매도 내부 경로, `make_snapshot_rpc_handler` 워치독 갱신, `SafetySellConfig` env 5종 파싱) (REQ-034~036, 041). - 2026-06-07 :: BAT-011 — safety-sell 트리거 레이어(`application/safety_sell.py` SafetySellService 신설 — forced_close/stop-loss·take-profit/장 마감, `BrokerPort.get_current_price()` + KIS `inquire-price`(`FHKST01010100`, CHG-04 정정)·paper stub, `SlotService.update_thresholds()` + intent RPC `update_thresholds` 액션, runtime/daemon 을 7 스레드로 확장(`trex-safety-sell`) + WatchdogStore 배선) (REQ-037~040, 042). - 2026-06-07 :: BAT-012 — 비상 정지/kill-switch(`trex.pause.req`→`trex.control.req` 제어 채널 + action dispatch, `application/killswitch.py` KillSwitchService + `adapters/portfolio/killswitch_store.py` + `005_create_killswitch_exclusion.sql` day-scoped 제외, snapshot masking 에 killswitch_today 추가, `make_control_rpc_handler` + kill_switch/resume_kill_switch, daemon control consumer 전환) (REQ-043~047). - 2026-06-07 :: BAT-013 — 다중 인스턴스 RabbitMQ 토폴로지(`topology.py` 동적 큐명 빌더 `intent/snapshot/control_queue(instance_key)` default 리터럴 하위호환 + `trex.direct`(topic)/`trex.broadcast`(fanout) exchange + `direct_routing_key`, `rabbitmq.declare_topology(instance_key)` per-instance 큐/바인딩+control dual, `config.DaemonInstanceConfig.from_toml`+`DaemonConfig.from_config`+`instance_key` 필드, daemon `--config` 필수 진입점 + instance_key 큐 구독, `.gitignore` 인스턴스 TOML + `config/instance.example.toml`) (REQ-048~051). - 2026-06-10 :: BAT-030 (dcy-020 마감) — 자산 중심 전환: `runtime/reset.py` + `trex-core-reset` 콘솔 스크립트(데이터 보존 cutover 폐기 — wipe+재초기화로 대체, REQ-064 CHG-20260610-03), `application/preallocation_scheduler.py` 삭제(일일 preallocation 폐기), 마이그레이션 010(inactive CHECK)/011(trading_date·entry_count drop), repo 계약 instance 스코프 개편, `ops_checks.py` transition_log 기반 재작성, config 에서 `total_slots`/`daily_preallocation_time` 제거 (REQ-056~065). - 2026-06-10 :: BAT-031 (dcy-021 포지션 사이징) — state.py(holding→pending_buy 전이), service.py(pending_sell qty sentinel), intents.py(증액 admission·SellIntent.qty), execution.py(부분 매도 dispatch·매수 체결 가중평균·브로커 정본 resync·증액 롤백), messaging_handlers.py(sell qty). 신규 코드 모듈 없음(기존 확장). (REQ-066/067/057/061/062) - 2026-07-29 :: BAT-062 (dcy-042 공통 계좌 자본배분) — `domain/capital_allocation.py` 순수 정책과 대표값·무작위 불변식 테스트 추가. 외부 현금·호가 조회와 최종 주문수량 산출은 호출 계층에 유지. (REQ-127)