Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
4fec7e4
feat: Kafka ๋ชจ๋“ˆ ์ถ”๊ฐ€ ๋ฐ ํ…Œ์ŠคํŠธ ์˜์กด์„ฑ ์„ค์ •
rnqhstmd Dec 19, 2025
9766e3a
feat: Kafka ์„ค์ •์— idempotence ๋ฐ max.in.flight.requests ์ถ”๊ฐ€
rnqhstmd Dec 19, 2025
f15071d
refactor: ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํด๋ž˜์Šค ์ œ๊ฑฐ
rnqhstmd Dec 19, 2025
e247031
feat: Kafka ์„ค์ •์— Dead Letter Queue ๋ฐ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๊ธฐ ์ถ”๊ฐ€
rnqhstmd Dec 19, 2025
374fea6
feat: ์ฃผ๋ฌธ ์ƒ์„ฑ ์‹œ Kafka ์ด๋ฒคํŠธ ๋ฐœํ–‰ ๋ฐ Outbox ํŒจํ„ด ์ ์šฉ
rnqhstmd Dec 19, 2025
f7d89bc
feat: ์ฟ ํฐ ์‚ฌ์šฉ ์‹œ ๋ฉฑ๋“ฑ์„ฑ ์ฒ˜๋ฆฌ ์ถ”๊ฐ€
rnqhstmd Dec 19, 2025
f0a2536
feat: ๊ฒฐ์ œ ์„ฑ๊ณต ๋ฐ ์‹คํŒจ ์‹œ Kafka ์ด๋ฒคํŠธ ๋ฐœํ–‰ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
rnqhstmd Dec 19, 2025
90c4f5e
feat: PaymentSucceededEvent์— transactionId ํ•„๋“œ ์ถ”๊ฐ€
rnqhstmd Dec 19, 2025
a8947ea
feat: ์œ ์ € ํ–‰๋™ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ์‹œ Kafka ์ด๋ฒคํŠธ ๋ฐœํ–‰ ๊ธฐ๋Šฅ ์ถ”๊ฐ€
rnqhstmd Dec 19, 2025
0591b1d
feat: AuditLog ์—”ํ‹ฐํ‹ฐ ์ถ”๊ฐ€ ๋ฐ ์ƒ์„ฑ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
4f9aab7
feat: AuditLogCommand ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ด๋ฒคํŠธ ์ƒ์„ฑ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
8482be0
feat: AuditLogConsumer ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ Kafka ์ด๋ฒคํŠธ ์ˆ˜์‹  ์ฒ˜๋ฆฌ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
db6ccf2
feat: AuditLogFacade ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ๊ฐ์‚ฌ ๋กœ๊ทธ ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
ef7d1e9
feat: AuditLogJpaRepository, AuditLogRepository, and AuditLogRepositoโ€ฆ
rnqhstmd Dec 19, 2025
e297043
feat: AuditLogService ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ๊ฐ์‚ฌ ๋กœ๊ทธ ์ €์žฅ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
cad42e8
feat: DlqMessage ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ DLQ ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
58baa37
feat: DlqConsumer ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ DLQ ๋ฉ”์‹œ์ง€ ์ˆ˜์‹  ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
cf5058a
feat: DlqMessageJpaRepository, DlqMessageRepository, and DlqMessageReโ€ฆ
rnqhstmd Dec 19, 2025
643d5f3
feat: DlqMessageService ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ DLQ ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
09facd9
feat: EventHandled ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
e1b347f
feat: EventHandled ํƒ€์ž… ์ถ”๊ฐ€
rnqhstmd Dec 19, 2025
dc8b650
feat: EventHandledJpaRepository, EventHandledRepository, and EventHanโ€ฆ
rnqhstmd Dec 19, 2025
5d0be8e
feat: EventHandledService ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
c6e9f85
feat: LikeChangedDto ๋ฐ UserActionDto ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
07ab357
feat: OrderEventDto ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ฃผ๋ฌธ ์ด๋ฒคํŠธ ์ƒ์„ฑ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
ddf1ec2
feat: LikeChangedEventProducer ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ข‹์•„์š” ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ ๋ฐœํ–‰ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
be27697
feat: MetricsType enum ์ถ”๊ฐ€ ๋ฐ ๋ฉ”ํŠธ๋ฆญ์Šค ์œ ํ˜• ์ •์˜
rnqhstmd Dec 19, 2025
22f1d7b
feat: OrderEventProducer ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ฃผ๋ฌธ ์ด๋ฒคํŠธ ๋ฐœํ–‰ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
f5a08e6
feat: OutboxEvent ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ด๋ฒคํŠธ ์ƒ์„ฑ, ์ƒํƒœ ๊ด€๋ฆฌ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
723923d
feat: OutboxEventPublisher ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ Pending ์ด๋ฒคํŠธ ๋ฐœํ–‰ ๋ฐ ์‹คํŒจํ•œ ์ด๋ฒคํŠธ ์žฌ์‹œ๋„ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
3934111
feat: OutboxEventJpaRepository ๋ฐ OutboxEventRepository ๊ตฌํ˜„ ์ถ”๊ฐ€
rnqhstmd Dec 19, 2025
d15c3bb
feat: OutboxService ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ด๋ฒคํŠธ ์ €์žฅ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
f4e1d2f
feat: PaymentEventDto ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ๊ฒฐ์ œ ์ด๋ฒคํŠธ ์ƒ์„ฑ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
da36ce5
feat: PaymentEventProducer ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ๊ฒฐ์ œ ์ด๋ฒคํŠธ ๋ฐœํ–‰ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
45f621d
feat: ProductLikeEventListener ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ข‹์•„์š” ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
b9be5f4
feat: ProductLikePayload ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ข‹์•„์š” ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ •์˜
rnqhstmd Dec 19, 2025
c778b93
feat: ProductMetrics ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ œํ’ˆ ๋ฉ”ํŠธ๋ฆญ์Šค ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ •์˜
rnqhstmd Dec 19, 2025
10d4e35
feat: ProductMetrics ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋ฐ JPA ๊ตฌํ˜„ ์ถ”๊ฐ€
rnqhstmd Dec 19, 2025
d329ede
feat: ProductMetricsCommand ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ๋ฉ”ํŠธ๋ฆญ์Šค ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
9592dd3
feat: ProductMetricsConsumer ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ๋ฉ”ํŠธ๋ฆญ์Šค ์ด๋ฒคํŠธ ์ˆ˜์‹  ์ฒ˜๋ฆฌ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
2fd71d6
feat: ProductMetricsFacade ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ๋ฉ”ํŠธ๋ฆญ์Šค ์ฒ˜๋ฆฌ ๋กœ์ง ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
3e36c1d
feat: ProductMetricsId ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ œํ’ˆ ๋ฉ”ํŠธ๋ฆญ์Šค ์‹๋ณ„์ž ์ •์˜
rnqhstmd Dec 19, 2025
c8c4846
feat: ProductMetricsService ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ๋ฉ”ํŠธ๋ฆญ์Šค ์ฒ˜๋ฆฌ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
d7fc8f9
feat: ProductStockPayload ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์žฌ๊ณ  ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ์šฉ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ •์˜
rnqhstmd Dec 19, 2025
d07e54a
feat: ProductViewedDto ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ œํ’ˆ ์กฐํšŒ ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ •์˜
rnqhstmd Dec 19, 2025
338e9ee
feat: StockChangedDto ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์žฌ๊ณ  ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ •์˜
rnqhstmd Dec 19, 2025
0191c6b
feat: ProductViewPayload ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ œํ’ˆ ์กฐํšŒ ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ •์˜
rnqhstmd Dec 19, 2025
bf2b3a1
feat: ProductViewedEventProducer ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ƒํ’ˆ ์กฐํšŒ ์ด๋ฒคํŠธ ๋ฐœํ–‰ ๋กœ์ง ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
ea14a5b
feat: StockChangedEventProducer ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์žฌ๊ณ  ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ ๋ฐœํ–‰ ๋กœ์ง ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
0828dff
feat: TimeConfig ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์‹œ์Šคํ…œ ๊ธฐ๋ณธ ์‹œ๊ฐ„ ์„ค์ •์„ ์œ„ํ•œ Clock ๋นˆ ์ •์˜
rnqhstmd Dec 19, 2025
2597a71
feat: UserActionEventProducer ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์œ ์ € ํ–‰๋™ ์ด๋ฒคํŠธ ๋ฐœํ–‰ ๋กœ์ง ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
e4801a9
feat: CommerceStreamerContextTest ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ปจํ…์ŠคํŠธ ๋กœ๋“œ ํ…Œ์ŠคํŠธ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
5c6dd2e
test: ProductMetricsConsumerTest ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ์ œํ’ˆ ๋ฉ”ํŠธ๋ฆญ ์ฒ˜๋ฆฌ ํ…Œ์ŠคํŠธ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
26a07ef
test: AuditLogConsumerTest ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ ๊ฐ์‚ฌ ๋กœ๊ทธ ์†Œ๋น„์ž ํ…Œ์ŠคํŠธ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
2dd4985
test: DlqConsumerTest ํด๋ž˜์Šค ์ถ”๊ฐ€ ๋ฐ DLQ ๋ฉ”์‹œ์ง€ ์†Œ๋น„ ๋กœ์ง ํ…Œ์ŠคํŠธ ๊ตฌํ˜„
rnqhstmd Dec 19, 2025
4847130
feat: ์นดํ”„์นด ํ† ํ”ฝ ๋ฐ ์ปจ์Šˆ๋จธ ๊ทธ๋ฃน ์ถ”๊ฐ€
rnqhstmd Dec 19, 2025
2fc3189
feat: ์นดํ”„์นด ํ† ํ”ฝ ๋ฐ ์ปจ์Šˆ๋จธ ๊ทธ๋ฃน ์ถ”๊ฐ€
rnqhstmd Dec 19, 2025
57dcf28
fix: ๊ฐœ์„ ๋œ DLQ ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ ๋กœ์ง ๋ฐ ์˜ค๋ฅ˜ ๋กœ๊น…
rnqhstmd Dec 19, 2025
88f8d6c
fix: yml ์ฝ”๋“œํฌ๋ฉง ๋ณ€๊ฒฝ
rnqhstmd Dec 19, 2025
75469d9
fix: ์ˆ˜์ •๋œ DLT ํŒŒํ‹ฐ์…˜ ์ฒ˜๋ฆฌ ๋กœ์ง
rnqhstmd Dec 19, 2025
c472a53
refactor: ์‚ฌ์šฉํ•˜์ง€์•Š๋Š” ๋ฉ”์„œ ์ œ๊ฑฐ
rnqhstmd Dec 19, 2025
9a5c84f
feat: ํด๋ฐฑ ์‹œ ์•„์›ƒ๋ฐ•์Šค ํŒจํ„ด ์ ์šฉ
rnqhstmd Dec 19, 2025
3555228
feat: ์„ค์ • ์ฝ”๋“œ ์œ„์น˜ ๋ณ€๊ฒฝ
rnqhstmd Dec 19, 2025
5643063
feat: ๋„๋ฉ”์ธ ํƒ€์ž…์œผ๋กœ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •
rnqhstmd Dec 19, 2025
a333fbf
feat: ์ƒํƒœ๊ฐ’์œผ๋กœ ์กฐํšŒํ•˜๋Š” ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
rnqhstmd Dec 19, 2025
9838f76
feat: Outbox ์ด๋ฒคํŠธ ์ €์žฅ์„ ์œ„ํ•œ Kafka ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ˆ˜์ •
rnqhstmd Dec 19, 2025
f16d113
feat: Kafka ๋ฆฌ์Šค๋„ˆ์— ํ—ˆ์šฉ๋œ ํ† ํ”ฝ ๊ฒ€์ฆ ๋กœ์ง ์ถ”๊ฐ€
rnqhstmd Dec 19, 2025
110c9db
chore: ๋„๋ฉ”์ธ ํƒ€์ž… ๊ฒ€์ฆ ๋ฉ”์„œ๋“œ ์‚ฌ์šฉํ•˜๋„๋ก ์ˆ˜์ •
rnqhstmd Dec 19, 2025
5515b9b
feat: ๊ฐœ์„ ๋œ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ๋กœ์ง ์ถ”๊ฐ€ ๋ฐ Kafka ์ด๋ฒคํŠธ ๋ฐœํ–‰ ์‹คํŒจ ๋กœ๊ทธ ์ˆ˜์ •
rnqhstmd Dec 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/commerce-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ dependencies {
// add-ons
implementation(project(":modules:jpa"))
implementation(project(":modules:redis"))
implementation(project(":modules:kafka"))
implementation(project(":supports:jackson"))
implementation(project(":supports:logging"))
implementation(project(":supports:monitoring"))
Expand All @@ -22,6 +23,10 @@ dependencies {

testImplementation("net.datafaker:datafaker:2.0.2")

// Kafka
testImplementation(testFixtures(project(":modules:kafka")))
testImplementation("org.springframework.kafka:spring-kafka-test")

// Resilience4j
implementation("io.github.resilience4j:resilience4j-spring-boot3")
implementation("org.springframework.boot:spring-boot-starter-aop")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ public OrderInfo createOrder(OrderPlaceCommand command) {
public void useCoupon(Long couponId) {
log.info("์ฟ ํฐ ์‚ฌ์šฉ ์ฒ˜๋ฆฌ: couponId={}", couponId);
Coupon coupon = couponService.getCouponWithOptimisticLock(couponId);
if (!coupon.canUse()) {
log.info("์ด๋ฏธ ์‚ฌ์šฉ๋œ ์ฟ ํฐ์ž…๋‹ˆ๋‹ค (๋ฉฑ๋“ฑ์„ฑ ์ฒ˜๋ฆฌ): couponId={}", couponId);
return;
}

coupon.use();
couponService.save(coupon);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.loopers.domain.outbox;

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.UUID;

@Entity
@Table(name = "outbox_event")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class OutboxEvent {

@Id
private String id;

@Column(name = "aggregate_type", nullable = false)
private String aggregateType;

@Column(name = "aggregate_id", nullable = false)
private String aggregateId;

@Column(name = "event_type", nullable = false)
private String eventType;

@Column(name = "topic", nullable = false)
private String topic;

@Column(name = "partition_key")
private String partitionKey;

@Column(name = "payload", columnDefinition = "TEXT", nullable = false)
private String payload;

@Column(name = "status", nullable = false)
@Enumerated(EnumType.STRING)
private OutboxStatus status;

@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;

@Column(name = "processed_at")
private LocalDateTime processedAt;

@Column(name = "retry_count")
private int retryCount;

@Column(name = "last_error")
private String lastError;

public static OutboxEvent create(
String aggregateType,
String aggregateId,
String eventType,
String topic,
String partitionKey,
String payload
) {
OutboxEvent event = new OutboxEvent();
event.id = UUID.randomUUID().toString();
event.aggregateType = aggregateType;
event.aggregateId = aggregateId;
event.eventType = eventType;
event.topic = topic;
event.partitionKey = partitionKey;
event.payload = payload;
event.status = OutboxStatus.PENDING;
event.createdAt = LocalDateTime.now();
event.retryCount = 0;
return event;
}

public void markAsProcessed() {
this.status = OutboxStatus.PROCESSED;
this.processedAt = LocalDateTime.now();
}

public void markAsFailed(String error) {
this.status = OutboxStatus.FAILED;
this.lastError = error;
this.retryCount++;
}

public void markForRetry() {
this.status = OutboxStatus.PENDING;
}

public enum OutboxStatus {
PENDING,
PROCESSED,
FAILED
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.loopers.domain.outbox;

import java.util.List;

public interface OutboxEventRepository {
OutboxEvent save(OutboxEvent event);
List<OutboxEvent> findPendingEvents(int limit);
List<OutboxEvent> findFailedEventsForRetry(int maxRetryCount, int limit);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.loopers.domain.outbox;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
public class OutboxService {

private final OutboxEventRepository outboxEventRepository;
private final ObjectMapper objectMapper;

@Transactional
public void saveEvent(
String aggregateType,
String aggregateId,
String eventType,
String topic,
String partitionKey,
Object payload
) {
try {
String payloadJson = objectMapper.writeValueAsString(payload);
OutboxEvent event = OutboxEvent.create(
aggregateType,
aggregateId,
eventType,
topic,
partitionKey,
payloadJson
);
outboxEventRepository.save(event);
log.debug("Outbox ์ด๋ฒคํŠธ ์ €์žฅ: aggregateType={}, aggregateId={}, eventType={}",
aggregateType, aggregateId, eventType);
} catch (JsonProcessingException e) {
log.error("Outbox ์ด๋ฒคํŠธ ์ง๋ ฌํ™” ์‹คํŒจ: aggregateType={}, aggregateId={}",
aggregateType, aggregateId, e);
throw new RuntimeException("์ด๋ฒคํŠธ ์ง๋ ฌํ™” ์‹คํŒจ", e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public record PaymentSucceededEvent(
Long couponId,
Long amount,
PaymentMethod paymentMethod,
String transactionId,
ZonedDateTime paidAt
) {
public static PaymentSucceededEvent of(Payment payment, Long couponId, ZonedDateTime paidAt) {
Expand All @@ -22,6 +23,7 @@ public static PaymentSucceededEvent of(Payment payment, Long couponId, ZonedDate
couponId,
payment.getAmountValue(),
payment.getPaymentMethod(),
payment.getTransactionId(),
paidAt != null ? paidAt : ZonedDateTime.now()
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.loopers.infrastructure.kafka.dto;

import java.util.UUID;

public record LikeChangedDto(
String eventId,
Long productId,
String likeType
) {
public static LikeChangedDto of(Long productId, String likeType) {
return new LikeChangedDto(
UUID.randomUUID().toString(),
productId,
likeType
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.loopers.infrastructure.kafka.dto;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

public record OrderEventDto(
String eventId,
Long orderId,
Long userId,
String orderStatus,
Long totalAmount,
Long discountAmount,
List<OrderItemDto> items,
LocalDateTime occurredAt
) {
public static OrderEventDto created(
Long orderId,
Long userId,
Long totalAmount,
Long discountAmount,
List<OrderItemDto> items
) {
return new OrderEventDto(
UUID.randomUUID().toString(),
orderId,
userId,
"CREATED",
totalAmount,
discountAmount,
items,
LocalDateTime.now()
);
}

public static OrderEventDto completed(Long orderId, Long userId) {
return new OrderEventDto(
UUID.randomUUID().toString(),
orderId,
userId,
"COMPLETED",
null,
null,
null,
LocalDateTime.now()
);
}

public static OrderEventDto failed(Long orderId, Long userId) {
return new OrderEventDto(
UUID.randomUUID().toString(),
orderId,
userId,
"FAILED",
null,
null,
null,
LocalDateTime.now()
);
}

public record OrderItemDto(
Long productId,
int quantity,
Long unitPrice
) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.loopers.infrastructure.kafka.dto;

import java.time.LocalDateTime;
import java.util.UUID;

public record PaymentEventDto(
String eventId,
Long orderId,
Long userId,
String paymentStatus,
String transactionId,
Long amount,
String failureReason,
LocalDateTime occurredAt
) {
public static PaymentEventDto success(Long orderId, Long userId, String transactionId, Long amount) {
return new PaymentEventDto(
UUID.randomUUID().toString(),
orderId,
userId,
"SUCCESS",
transactionId,
amount,
null,
LocalDateTime.now()
);
}

public static PaymentEventDto failed(Long orderId, Long userId, String failureReason) {
return new PaymentEventDto(
UUID.randomUUID().toString(),
orderId,
userId,
"FAILED",
null,
null,
failureReason,
LocalDateTime.now()
);
}

public static PaymentEventDto pending(Long orderId, Long userId, String transactionId) {
return new PaymentEventDto(
UUID.randomUUID().toString(),
orderId,
userId,
"PENDING",
transactionId,
null,
null,
LocalDateTime.now()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.loopers.infrastructure.kafka.dto;

import java.util.UUID;

public record ProductViewedDto(
String eventId,
Long productId
) {
public static ProductViewedDto of(Long productId) {
return new ProductViewedDto(
UUID.randomUUID().toString(),
productId
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.loopers.infrastructure.kafka.dto;

import java.util.UUID;

public record StockChangedDto(
String eventId,
Long productId,
int stock,
String changedType
) {
public static StockChangedDto of(Long productId, int stock, String changedType) {
return new StockChangedDto(
UUID.randomUUID().toString(),
productId,
stock,
changedType
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.loopers.infrastructure.kafka.dto;

import java.util.UUID;

public record UserActionDto(
String eventId,
Long userId,
String actionType,
String targetType,
Long targetId
) {
public static UserActionDto of(Long userId, String actionType, String targetType, Long targetId) {
return new UserActionDto(
UUID.randomUUID().toString(),
userId,
actionType,
targetType,
targetId
);
}
}
Loading