Skip to content

Feature/strategy crud - #1

Merged
liveforpresent merged 6 commits into
mainfrom
feature/strategy-crud
Aug 13, 2026
Merged

liveforpresent merged 6 commits into
mainfrom
feature/strategy-crud

Conversation

@liveforpresent

@liveforpresent liveforpresent commented Aug 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Feature-centric Gradle multi-module 구조와 공통 build convention을 구성했습니다.
  • Strategy 생성·단건 조회 vertical slice를 Web → Inbound Port → Application →
    Persistence/Snowflake Adapter 흐름으로 구현했습니다.
  • BacktestRun을 PENDING 상태로 생성하는 최소 RunBacktest slice와 Compute outbound port를
    추가했습니다.
  • context 소유 문서/OpenAPI 스냅샷을 동기화하고 core-api 전용 agent 규칙을 정리했습니다.

Implemented Use Cases

  • CreateStrategy: Snowflake 기반 Strategy ID 생성, 테스트용 MemberId 공급, PostgreSQL 저장.
  • GetStrategy: StrategyReader를 통한 단건 조회와 Web 응답 매핑.
  • RunBacktest: StrategyVersionId로 BacktestRun(PENDING) 생성. Compute 호출/폴링 구현은
    이번 범위에서 제외하고 outbound port만 정의.

Related ADR

  • ADR-002 — Primary Signal Asset은 명시적으로 지정.
  • ADR-013 — Strategy와 생성 후 불변인 StrategyVersion.
  • ADR-018 — Feature-centric Gradle 모듈, inbound/outbound port, technology-specific adapter.

Core ↔ Compute API Contract

  • Compute client 구현이나 요청/응답 동작은 변경하지 않았습니다.
  • 포함된 OpenAPI 파일은 context 저장소의 동기화 스냅샷입니다. 별도 Compute API 계약 변경 PR은
    없습니다.

Validation

  • ./gradlew.bat --no-daemon clean build
  • ./gradlew.bat --no-daemon check
  • ./gradlew.bat --no-daemon :strategy:application:test :app:test
  • 로컬 PostgreSQL에서 Strategy 생성 후 단건 조회, Actuator datasource health check를 확인했습니다.

Synchronize context-owned documentation and API contracts.

Related: ADR-018; Use Cases DefineStrategyVersion, GetStrategy, RunBacktest.
Add nested feature projects and shared build conventions; move the boot entry point into app.

Related: ADR-018.
Provide shared domain building blocks and the technology-specific Snowflake generator.

Related: ADR-018; typed identifier architecture.
Add feature modules, HTTP adapters, persistence adapters, and application services for strategy creation and retrieval.

Related: ADR-002, ADR-013; Use Cases DefineStrategyVersion, GetStrategy.
Add BacktestRun domain invariants and create the PENDING run through the RunBacktest port.

Related: Use Case RunBacktest; BacktestRun and BacktestResult invariants.
Keep repository-local agent rules focused on module boundaries, ports, persistence, and the external context source of truth.

Related: ADR-018; Use Cases DefineStrategyVersion, GetStrategy, RunBacktest.
@liveforpresent
liveforpresent requested a lite review from Copilot August 13, 2026 09:13
@liveforpresent
liveforpresent merged commit 40cfa53 into main Aug 13, 2026
1 check passed
@liveforpresent
liveforpresent deleted the feature/strategy-crud branch August 13, 2026 09:14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces the initial feature-centric multi-module foundation for Strategy and Backtest in core-api, including domain models, ports/application services, and first adapters (web/JPA/snowflake), plus shared kernel/infrastructure and Gradle convention plugins to standardize builds across modules.

Changes:

  • Added strategy bounded context with create/get use cases, domain invariants, and web + JPA persistence + Snowflake ID adapters.
  • Added backtest bounded context skeleton (pending-run creation + Compute client port + Snowflake ID adapter) with domain state-machine invariants.
  • Established shared modules (shared:kernel, shared:infrastructure), Gradle build-logic convention plugins, and updated settings/build layout (plus synced docs/ + openapi/ snapshots).

Reviewed changes

Copilot reviewed 82 out of 95 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
strategy/port/src/main/kotlin/com/refinvest/core/strategy/port/outbound/StrategyStore.kt Outbound persistence port for Strategy.
strategy/port/src/main/kotlin/com/refinvest/core/strategy/port/outbound/StrategyReader.kt Outbound read port and read-model for strategies.
strategy/port/src/main/kotlin/com/refinvest/core/strategy/port/outbound/StrategyIdGenerator.kt Outbound port for strategy ID generation.
strategy/port/src/main/kotlin/com/refinvest/core/strategy/port/outbound/MemberIdProvider.kt Outbound port for resolving the current member.
strategy/port/src/main/kotlin/com/refinvest/core/strategy/port/inbound/strategy/get/GetStrategyUseCase.kt Inbound query use case definition for get strategy.
strategy/port/src/main/kotlin/com/refinvest/core/strategy/port/inbound/strategy/get/GetStrategyResult.kt Query result DTO for get strategy.
strategy/port/src/main/kotlin/com/refinvest/core/strategy/port/inbound/strategy/get/GetStrategyQuery.kt Query DTO for get strategy.
strategy/port/src/main/kotlin/com/refinvest/core/strategy/port/inbound/strategy/create/CreateStrategyUseCase.kt Inbound command use case definition for create strategy.
strategy/port/src/main/kotlin/com/refinvest/core/strategy/port/inbound/strategy/create/CreateStrategyResult.kt Command result DTO for create strategy.
strategy/port/src/main/kotlin/com/refinvest/core/strategy/port/inbound/strategy/create/CreateStrategyCommand.kt Command DTO for create strategy.
strategy/port/build.gradle.kts Declares strategy:port module and dependency on strategy:domain.
strategy/domain/src/test/kotlin/com/refinvest/core/strategy/domain/StrategyVersionTest.kt Tests for StrategyVersion invariants.
strategy/domain/src/test/kotlin/com/refinvest/core/strategy/domain/StrategyTest.kt Tests for Strategy aggregate behavior.
strategy/domain/src/main/kotlin/com/refinvest/core/strategy/domain/StrategyVersion.kt Domain entity for immutable strategy versions + invariants.
strategy/domain/src/main/kotlin/com/refinvest/core/strategy/domain/StrategyIdentifiers.kt Typed identifiers for strategy bounded context.
strategy/domain/src/main/kotlin/com/refinvest/core/strategy/domain/StrategyDsl.kt DSL primitives for strategy conditions/metrics and basic validation.
strategy/domain/src/main/kotlin/com/refinvest/core/strategy/domain/Strategy.kt Strategy aggregate root with versions list.
strategy/domain/build.gradle.kts Declares strategy:domain and dependency on shared:kernel.
strategy/application/src/test/kotlin/com/refinvest/core/strategy/application/strategy/get/GetStrategyServiceTest.kt Tests for get-strategy application service mapping.
strategy/application/src/test/kotlin/com/refinvest/core/strategy/application/strategy/create/CreateStrategyServiceTest.kt Tests for create-strategy orchestration and persistence.
strategy/application/src/main/kotlin/com/refinvest/core/strategy/application/strategy/get/GetStrategyService.kt Spring application service implementing GetStrategyUseCase.
strategy/application/src/main/kotlin/com/refinvest/core/strategy/application/strategy/create/CreateStrategyService.kt Spring application service implementing CreateStrategyUseCase.
strategy/application/build.gradle.kts Declares strategy:application module wiring.
strategy/adapter/web/src/main/kotlin/com/refinvest/core/strategy/adapter/web/strategy/StrategyController.kt REST controller exposing create/get endpoints for strategies.
strategy/adapter/web/src/main/kotlin/com/refinvest/core/strategy/adapter/web/strategy/get/GetStrategyResponse.kt Web response DTO for get strategy.
strategy/adapter/web/src/main/kotlin/com/refinvest/core/strategy/adapter/web/strategy/create/CreateStrategyResponse.kt Web response DTO for create strategy.
strategy/adapter/web/src/main/kotlin/com/refinvest/core/strategy/adapter/web/strategy/create/CreateStrategyRequest.kt Web request DTO with validation for create strategy.
strategy/adapter/web/build.gradle.kts Declares web adapter dependencies (Spring MVC/validation/Jackson).
strategy/adapter/snowflake/src/test/kotlin/com/refinvest/core/strategy/adapter/out/id/SnowflakeStrategyIdGeneratorTest.kt Tests for Snowflake-backed StrategyIdGenerator.
strategy/adapter/snowflake/src/main/kotlin/com/refinvest/core/strategy/adapter/out/id/SnowflakeStrategyIdGenerator.kt Adapter implementing StrategyIdGenerator using shared Snowflake generator.
strategy/adapter/snowflake/build.gradle.kts Declares snowflake adapter dependencies.
strategy/adapter/persistence/src/main/kotlin/com/refinvest/core/strategy/adapter/out/persistence/StrategyJpaStore.kt Spring Data repository for StrategyJpaEntity writes.
strategy/adapter/persistence/src/main/kotlin/com/refinvest/core/strategy/adapter/out/persistence/StrategyJpaReader.kt Spring Data repository for reading strategies by ID.
strategy/adapter/persistence/src/main/kotlin/com/refinvest/core/strategy/adapter/out/persistence/StrategyJpaEntity.kt JPA entity mapping for strategies table.
strategy/adapter/persistence/src/main/kotlin/com/refinvest/core/strategy/adapter/out/persistence/JpaStrategyStoreAdapter.kt Adapter implementing StrategyStore via JPA.
strategy/adapter/persistence/src/main/kotlin/com/refinvest/core/strategy/adapter/out/persistence/JpaStrategyReaderAdapter.kt Adapter implementing StrategyReader via JPA.
strategy/adapter/persistence/build.gradle.kts Declares persistence adapter dependencies (Spring Data JPA).
src/test/kotlin/com/refinvest/RefinvestApplicationTests.kt Removed old root-level Spring Boot test (moved into app).
src/main/resources/application.yaml Removed old root-level application config (moved into app).
shared/kernel/src/main/kotlin/com/refinvest/core/common/domain/Identifier.kt Introduces shared typed-ID interface.
shared/kernel/src/main/kotlin/com/refinvest/core/common/domain/DomainEvent.kt Introduces shared domain event marker.
shared/kernel/src/main/kotlin/com/refinvest/core/common/domain/DomainEntity.kt Introduces shared base domain entity.
shared/kernel/src/main/kotlin/com/refinvest/core/common/domain/AggregateRoot.kt Introduces shared aggregate root with event recording.
shared/kernel/build.gradle.kts Declares shared:kernel as a domain module.
shared/infrastructure/src/test/kotlin/com/refinvest/core/shared/infrastructure/id/SnowflakeIdGeneratorTest.kt Tests for Snowflake ID generator behavior.
shared/infrastructure/src/main/kotlin/com/refinvest/core/shared/infrastructure/id/SnowflakeIdGenerator.kt Shared Snowflake ID generator implementation.
shared/infrastructure/build.gradle.kts Declares shared:infrastructure module.
settings.gradle.kts Adds included build-logic and includes all modules.
openapi/core-api.yaml Adds/updates public Core API OpenAPI contract snapshot.
openapi/compute-api.yaml Adds/updates internal Compute API OpenAPI contract snapshot.
gradle/libs.versions.toml Centralized dependency catalog for versions and libraries.
docs/USECASES.md Synced use case catalog snapshot.
docs/ROADMAP.md Synced roadmap snapshot.
docs/README.md Documents that docs/ and openapi/ are auto-synced.
docs/GLOSSARY.md Synced glossary snapshot.
docs/GIT_WORKFLOW.md Synced git workflow snapshot.
docs/DOMAIN.md Synced domain model snapshot.
docs/DECISIONS.md Synced ADR snapshot.
docs/ARCHITECTURE.md Synced architecture snapshot.
docs/AI_AGENT.md Synced agent workflow snapshot.
build.gradle.kts Simplifies root build; moves build config into convention plugins.
build-logic/src/main/kotlin/spring-boot-application-conventions.gradle.kts Convention plugin for Spring Boot application modules.
build-logic/src/main/kotlin/spring-adapter-conventions.gradle.kts Convention plugin for Spring adapters with BOM import.
build-logic/src/main/kotlin/kotlin-common-conventions.gradle.kts Convention plugin for Kotlin/JVM defaults + test platform setup.
build-logic/src/main/kotlin/jpa-adapter-conventions.gradle.kts Convention plugin for JPA adapters (kotlin-jpa).
build-logic/src/main/kotlin/domain-conventions.gradle.kts Convention plugin forbidding framework deps in domain modules.
build-logic/settings.gradle.kts Build-logic settings and version-catalog wiring.
build-logic/build.gradle.kts Build-logic buildscript with plugin dependencies.
backtest/port/src/main/kotlin/com/refinvest/core/backtest/port/outbound/ComputeClient.kt Outbound port + DTOs for Compute backtest request/response.
backtest/port/src/main/kotlin/com/refinvest/core/backtest/port/outbound/BacktestRunStore.kt Outbound store and ID generator ports for backtest runs.
backtest/port/src/main/kotlin/com/refinvest/core/backtest/port/inbound/backtest/run/RunBacktestUseCase.kt Inbound use case for running a backtest (pending creation).
backtest/port/src/main/kotlin/com/refinvest/core/backtest/port/inbound/backtest/run/RunBacktestResult.kt Result DTO for run-backtest use case.
backtest/port/src/main/kotlin/com/refinvest/core/backtest/port/inbound/backtest/run/RunBacktestCommand.kt Command DTO for run-backtest use case.
backtest/port/build.gradle.kts Declares backtest:port module and domain dependency.
backtest/domain/src/test/kotlin/com/refinvest/core/backtest/domain/BacktestRunTest.kt Tests for backtest run state machine invariants.
backtest/domain/src/main/kotlin/com/refinvest/core/backtest/domain/BacktestRun.kt BacktestRun aggregate with strict state validation.
backtest/domain/src/main/kotlin/com/refinvest/core/backtest/domain/BacktestResult.kt Domain model for backtest results and related value types.
backtest/domain/src/main/kotlin/com/refinvest/core/backtest/domain/BacktestIdentifiers.kt Typed identifiers for backtest bounded context.
backtest/domain/build.gradle.kts Declares backtest:domain module.
backtest/application/src/test/kotlin/com/refinvest/core/backtest/application/backtest/run/RunBacktestServiceTest.kt Tests for pending backtest run creation service.
backtest/application/src/main/kotlin/com/refinvest/core/backtest/application/backtest/run/RunBacktestService.kt Application service creating/persisting pending runs.
backtest/application/build.gradle.kts Declares backtest:application module wiring.
backtest/adapter/snowflake/src/test/kotlin/com/refinvest/core/backtest/adapter/out/id/SnowflakeBacktestRunIdGeneratorTest.kt Tests for Snowflake-backed BacktestRunIdGenerator.
backtest/adapter/snowflake/src/main/kotlin/com/refinvest/core/backtest/adapter/out/id/SnowflakeBacktestRunIdGenerator.kt Adapter implementing BacktestRunIdGenerator.
backtest/adapter/snowflake/build.gradle.kts Declares backtest snowflake adapter dependencies.
backtest/adapter/compute/src/main/java/com/refinvest/core/backtest/adapter/out/compute/package-info.java Placeholder boundary for compute integration adapter package.
backtest/adapter/compute/build.gradle.kts Declares compute adapter module (currently placeholder).
app/src/test/kotlin/com/refinvest/RefinvestApplicationTests.kt Integration tests for wiring, health, and strategy HTTP flows.
app/src/main/resources/application.yaml Application runtime configuration (DB, actuator, app properties).
app/src/main/kotlin/com/refinvest/RefinvestApplication.kt Spring Boot application entrypoint.
app/src/main/kotlin/com/refinvest/core/config/StrategyConfiguration.kt App-layer beans (Clock, test member provider).
app/src/main/kotlin/com/refinvest/core/config/IdGenerationConfiguration.kt App-layer bean for shared Snowflake generator.
app/build.gradle.kts Declares app module dependencies and runtime/test deps.
AGENTS.md Adds repo-local conventions and guardrails.
.gitignore Ignores .env and local /context/ checkout.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +40 to +43
@GetMapping("/{strategyId}")
fun get(@PathVariable strategyId: Long): GetStrategyResponse {
val result = getStrategyUseCase.execute(GetStrategyQuery(StrategyId(strategyId)))
?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "Strategy not found")
Comment thread gradle/libs.versions.toml
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect" }
postgresql = { module = "org.postgresql:postgresql" }
h2 = { module = "com.h2database:h2" }
jackson-module-kotlin = { module = "tools.jackson.module:jackson-module-kotlin" }
Comment on lines +8 to +10
val createdAt: Instant,
val latestVersionId: String?,
val versions: List<Any> = emptyList(),
Comment on lines +10 to +15
class GetStrategyService(
private val strategyReader: StrategyReader,
) : GetStrategyUseCase {
override fun execute(query: GetStrategyQuery): GetStrategyResult? =
strategyReader.findById(query.strategyId)?.let { strategy ->
GetStrategyResult(
Comment on lines +40 to +45
data class ComputeConditionPayload(
val operator: String,
val logicalCombinator: String?,
val operandA: MetricReferencePayload,
val operandB: ComputeConditionOperandPayload,
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants