From 34d4c4298ede35e5dbe8687323077711921b69c7 Mon Sep 17 00:00:00 2001
From: Joonseok-Lee <dlwnstjr31@hansung.ac.kr>
Date: Mon, 4 May 2026 12:47:00 +0900
Subject: [PATCH 01/13] =?UTF-8?q?Docs:=20Spring=20Kafka=20=EC=9D=98?=
 =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 build.gradle | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/build.gradle b/build.gradle
index d2b05bd..af3f677 100644
--- a/build.gradle
+++ b/build.gradle
@@ -29,6 +29,8 @@ dependencies {
 	implementation 'org.springframework.boot:spring-boot-starter-security'
 	implementation 'org.springframework.boot:spring-boot-starter-validation'
 	implementation 'org.springframework.boot:spring-boot-starter-web'
+	implementation 'org.springframework.kafka:spring-kafka'
+	testImplementation 'org.springframework.kafka:spring-kafka-test'
 	compileOnly 'org.projectlombok:lombok'
 	runtimeOnly 'com.mysql:mysql-connector-j'
 	annotationProcessor 'org.projectlombok:lombok'

From 773b1b4c0252a6aabe1f48ab778e4f2da66c547e Mon Sep 17 00:00:00 2001
From: Joonseok-Lee <dlwnstjr31@hansung.ac.kr>
Date: Mon, 4 May 2026 14:37:11 +0900
Subject: [PATCH 02/13] =?UTF-8?q?Feat:=20=EB=8F=99=ED=99=94=20=EC=83=9D?=
 =?UTF-8?q?=EC=84=B1=20=EC=9A=94=EC=B2=AD=EC=9D=B4=20=EB=93=A4=EC=96=B4?=
 =?UTF-8?q?=EC=98=AC=20=EB=95=8C,=20=ED=95=B4=EB=8B=B9=20=EC=9A=94?=
 =?UTF-8?q?=EC=B2=AD=EC=9D=84=20DTO=EB=A1=9C=20=EA=B4=80=EB=A6=AC=ED=95=A0?=
 =?UTF-8?q?=20=EC=88=98=20=EC=9E=88=EA=B2=8C=EB=81=94=20=EA=B0=9D=EC=B2=B4?=
 =?UTF-8?q?=20=EC=84=A0=EC=96=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../web/dto/FairytaleGenerateReq.java         | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 src/main/java/com/capstone/kkumteul/domain/fairytale/web/dto/FairytaleGenerateReq.java

diff --git a/src/main/java/com/capstone/kkumteul/domain/fairytale/web/dto/FairytaleGenerateReq.java b/src/main/java/com/capstone/kkumteul/domain/fairytale/web/dto/FairytaleGenerateReq.java
new file mode 100644
index 0000000..bdfaf66
--- /dev/null
+++ b/src/main/java/com/capstone/kkumteul/domain/fairytale/web/dto/FairytaleGenerateReq.java
@@ -0,0 +1,23 @@
+package com.capstone.kkumteul.domain.fairytale.web.dto;
+
+import com.capstone.kkumteul.domain.fairytale.entity.Background;
+import com.capstone.kkumteul.domain.fairytale.entity.CharSpecies;
+import com.capstone.kkumteul.domain.fairytale.entity.Morality;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public class FairytaleGenerateReq {
+
+    @NotNull(message = "배경은 비어있을 수 없습니다.")
+    private final Background background;
+
+    @NotNull(message = "등장인물 종류는 비어있을 수 없습니다.")
+    private final CharSpecies charSpecie;
+
+    @NotNull(message = "교훈은 비어있을 수 없습니다.")
+    private final Morality morality;
+
+}

From fc45113a6468a4be9ae4375f43303c02e922ccba Mon Sep 17 00:00:00 2001
From: Joonseok-Lee <dlwnstjr31@hansung.ac.kr>
Date: Mon, 4 May 2026 14:49:38 +0900
Subject: [PATCH 03/13] =?UTF-8?q?Feat:=20Kafka=20Producer=20=EC=84=A4?=
 =?UTF-8?q?=EC=A0=95,=20key=20-=20String,=20value=20-=20Json=EC=9C=BC?=
 =?UTF-8?q?=EB=A1=9C=20=ED=8C=8C=EC=8B=B1=ED=95=98=EB=8F=84=EB=A1=9D=20?=
 =?UTF-8?q?=ED=95=A8.=20=EB=98=90=ED=95=9C,=20KafkaTemplate=EB=A1=9C=20?=
 =?UTF-8?q?=EB=A9=94=EC=84=B8=EC=A7=80=20=EB=B6=80=EB=B6=84=EC=9D=84=20Mes?=
 =?UTF-8?q?sageInterface=EB=A1=9C=20=EB=9F=B0=ED=83=80=EC=9E=84=EC=97=90?=
 =?UTF-8?q?=20=ED=83=80=EC=9E=85=EC=9D=84=20=EC=B6=94=EB=A1=A0=ED=95=98?=
 =?UTF-8?q?=EA=B2=8C=20=ED=95=98=EC=97=AC=20=EB=8F=99=EC=A0=81=20=EB=8B=A4?=
 =?UTF-8?q?=ED=98=95=EC=84=B1=20=EC=84=A4=EA=B3=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../global/config/KafkaProducerConfig.java    | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 src/main/java/com/capstone/kkumteul/global/config/KafkaProducerConfig.java

diff --git a/src/main/java/com/capstone/kkumteul/global/config/KafkaProducerConfig.java b/src/main/java/com/capstone/kkumteul/global/config/KafkaProducerConfig.java
new file mode 100644
index 0000000..f368cad
--- /dev/null
+++ b/src/main/java/com/capstone/kkumteul/global/config/KafkaProducerConfig.java
@@ -0,0 +1,47 @@
+package com.capstone.kkumteul.global.config;
+
+import com.capstone.kkumteul.domain.kafka.dto.FairytaleGenerateMessage;
+import com.capstone.kkumteul.domain.kafka.dto.MessageInterface;
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.core.DefaultKafkaProducerFactory;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.core.ProducerFactory;
+import org.springframework.kafka.support.serializer.JsonSerializer;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+public class KafkaProducerConfig {
+
+    private final String KAFKA_URL;
+
+    public KafkaProducerConfig(
+            @Value("${KAFKA_URL}") String KAFKA_URL
+    ) { this.KAFKA_URL = KAFKA_URL; }
+
+    @Bean
+
+    public ProducerFactory<String, MessageInterface> producerFactory() {
+
+        Map<String, Object> config = new HashMap<>();
+
+        // key - String Serialization
+        // value - Json Serialization
+        config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, KAFKA_URL);
+        config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+        config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
+        config.put(JsonSerializer.ADD_TYPE_INFO_HEADERS, false);
+
+        return new DefaultKafkaProducerFactory<>(config);
+    }
+
+    @Bean
+    public KafkaTemplate<String, MessageInterface> kafkaTemplate() {
+        return new KafkaTemplate<>(producerFactory());
+    }
+}

From 0c56107031d40ee9b7d107cf13b1aac2368208a6 Mon Sep 17 00:00:00 2001
From: Joonseok-Lee <dlwnstjr31@hansung.ac.kr>
Date: Mon, 4 May 2026 14:50:51 +0900
Subject: [PATCH 04/13] =?UTF-8?q?Feat:=20KafkaTemplate=EC=9D=98=20?=
 =?UTF-8?q?=EB=A9=94=EC=84=B8=EC=A7=80=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20?=
 =?UTF-8?q?=EB=8F=99=EC=A0=81=20=EB=8B=A4=ED=98=95=EC=84=B1=EC=9C=BC?=
 =?UTF-8?q?=EB=A1=9C=20=EC=84=A4=EA=B3=84=ED=95=98=EA=B8=B0=20=EC=9C=84?=
 =?UTF-8?q?=ED=95=B4=20MessageInterface=20=EC=9D=B8=ED=84=B0=ED=8E=98?=
 =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EA=B0=9D=EC=B2=B4=20=EC=84=A0=EC=96=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../kkumteul/domain/kafka/dto/MessageInterface.java         | 6 ++++++
 1 file changed, 6 insertions(+)
 create mode 100644 src/main/java/com/capstone/kkumteul/domain/kafka/dto/MessageInterface.java

diff --git a/src/main/java/com/capstone/kkumteul/domain/kafka/dto/MessageInterface.java b/src/main/java/com/capstone/kkumteul/domain/kafka/dto/MessageInterface.java
new file mode 100644
index 0000000..fd733ce
--- /dev/null
+++ b/src/main/java/com/capstone/kkumteul/domain/kafka/dto/MessageInterface.java
@@ -0,0 +1,6 @@
+package com.capstone.kkumteul.domain.kafka.dto;
+
+public interface MessageInterface {
+
+    Long getUserId();
+}

From 838f4ba5a6322312130939b736ba89fbe9cb53c9 Mon Sep 17 00:00:00 2001
From: Joonseok-Lee <dlwnstjr31@hansung.ac.kr>
Date: Mon, 4 May 2026 14:52:27 +0900
Subject: [PATCH 05/13] =?UTF-8?q?Feat:=20=EB=8F=99=ED=99=94=20=EC=83=9D?=
 =?UTF-8?q?=EC=84=B1=20=EC=9A=94=EC=B2=AD=EC=9D=84=20=EB=A1=9C=EC=BB=AC=20?=
 =?UTF-8?q?FastAPI=EB=A1=9C=20=EC=A0=84=ED=8C=8C=ED=95=98=EA=B8=B0=20?=
 =?UTF-8?q?=EC=9C=84=ED=95=B4=20=ED=95=84=EC=9A=94=ED=95=9C=20=EA=B0=92?=
 =?UTF-8?q?=EC=9D=84=20=EB=A9=94=EC=84=B8=EC=A7=80=EB=A1=9C=20=EC=A0=84?=
 =?UTF-8?q?=ED=8C=8C=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=A9=94=EC=84=B8?=
 =?UTF-8?q?=EC=A7=80=20=EA=B0=9D=EC=B2=B4=20=EC=84=A4=EA=B3=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../kafka/dto/FairytaleGenerateMessage.java   | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 src/main/java/com/capstone/kkumteul/domain/kafka/dto/FairytaleGenerateMessage.java

diff --git a/src/main/java/com/capstone/kkumteul/domain/kafka/dto/FairytaleGenerateMessage.java b/src/main/java/com/capstone/kkumteul/domain/kafka/dto/FairytaleGenerateMessage.java
new file mode 100644
index 0000000..f0488af
--- /dev/null
+++ b/src/main/java/com/capstone/kkumteul/domain/kafka/dto/FairytaleGenerateMessage.java
@@ -0,0 +1,20 @@
+package com.capstone.kkumteul.domain.kafka.dto;
+
+import com.capstone.kkumteul.domain.fairytale.entity.Background;
+import com.capstone.kkumteul.domain.fairytale.entity.CharSpecies;
+import com.capstone.kkumteul.domain.fairytale.entity.Morality;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+@AllArgsConstructor
+public class FairytaleGenerateMessage implements MessageInterface {
+
+     private final Long userId;
+
+     private final Background background;
+     private final CharSpecies charSpecies;
+     private final Morality morality;
+}

From 1fcde037857995ed945ac5992e6bb0f16adba001 Mon Sep 17 00:00:00 2001
From: Joonseok-Lee <dlwnstjr31@hansung.ac.kr>
Date: Mon, 4 May 2026 14:54:22 +0900
Subject: [PATCH 06/13] =?UTF-8?q?Feat:=20Kafka=EC=97=90=20=EB=A9=94?=
 =?UTF-8?q?=EC=84=B8=EC=A7=80=EB=A5=BC=20=EB=93=B1=EB=A1=9D=ED=95=98?=
 =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=ED=95=98=EB=8A=94=20=EC=84=9C=EB=B9=84?=
 =?UTF-8?q?=EC=8A=A4=20=EA=B0=9D=EC=B2=B4=EC=99=80=20=EB=8F=99=ED=99=94=20?=
 =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=EB=A5=BC=20?=
 =?UTF-8?q?=EC=A0=84=ED=8C=8C=ED=95=98=EB=8F=84=EB=A1=9D=20=ED=95=98?=
 =?UTF-8?q?=EB=8A=94=20=EB=A9=94=EC=86=8C=EB=93=9C=20=EC=9E=91=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../domain/kafka/service/EventService.java    | 33 +++++++++++++++++++
 1 file changed, 33 insertions(+)
 create mode 100644 src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java

diff --git a/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java b/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java
new file mode 100644
index 0000000..58e55c6
--- /dev/null
+++ b/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java
@@ -0,0 +1,33 @@
+package com.capstone.kkumteul.domain.kafka.service;
+
+import com.capstone.kkumteul.domain.fairytale.web.dto.FairytaleGenerateReq;
+import com.capstone.kkumteul.domain.kafka.dto.FairytaleGenerateMessage;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.stereotype.Service;
+
+/* 동화 생성 이벤트 전파 */
+
+@Service
+@Slf4j(topic = "event")
+@RequiredArgsConstructor
+public class EventService {
+
+    private final KafkaTemplate<String, FairytaleGenerateMessage> kafkaTemplate;
+
+    public void commentMessageCreate(Long userId, FairytaleGenerateReq request) {
+
+        FairytaleGenerateMessage message = FairytaleGenerateMessage.builder()
+                .userId(userId)
+                .background(request.getBackground())
+                .charSpecies(request.getCharSpecie())
+                .morality(request.getMorality())
+                .build();
+
+        log.info("fairytale_generate userId={}, message={}", userId, message);
+
+        kafkaTemplate.send("fairytale_generate", message);
+
+    }
+}

From df6059cb4b56a73f5ed380f840270f078fa1ca25 Mon Sep 17 00:00:00 2001
From: Joonseok-Lee <dlwnstjr31@hansung.ac.kr>
Date: Wed, 6 May 2026 19:41:05 +0900
Subject: [PATCH 07/13] =?UTF-8?q?Docs:=20Kafka=20=ED=85=8C=EC=8A=A4?=
 =?UTF-8?q?=ED=8A=B8=EB=A5=BC=20=EC=9C=84=ED=95=B4=20.env=EC=97=90=20Kafka?=
 =?UTF-8?q?=20=EC=8B=A4=EC=A0=9C=20=ED=86=B5=EC=8B=A0=20=EC=84=9C=EB=B2=84?=
 =?UTF-8?q?=20=EC=A3=BC=EC=86=8C=20=EA=B8=B0=EB=A1=9D=20=EB=B0=8F=20?=
 =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=EB=A5=BC=20?=
 =?UTF-8?q?=ED=86=B5=ED=95=B4=20.env=EB=A5=BC=20=EC=A7=81=EC=A0=91=20?=
 =?UTF-8?q?=EC=9D=BD=EA=B2=8C=ED=95=98=EC=97=AC=20Kafka=20=ED=86=B5?=
 =?UTF-8?q?=EC=8B=A0=20=EC=A3=BC=EC=86=8C=20=EC=A3=BC=EC=9E=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 build.gradle                                  |  3 ++
 .../kkumteul/kafka/KafkaProducerTest.java     | 51 +++++++++++++++++++
 2 files changed, 54 insertions(+)
 create mode 100644 src/test/java/com/capstone/kkumteul/kafka/KafkaProducerTest.java

diff --git a/build.gradle b/build.gradle
index af3f677..292218c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -42,6 +42,9 @@ dependencies {
 	implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
 	runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
 	runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'
+
+	// for Kafka test
+	testImplementation 'me.paulschwarz:spring-dotenv:4.0.0'
 }
 
 tasks.named('test') {
diff --git a/src/test/java/com/capstone/kkumteul/kafka/KafkaProducerTest.java b/src/test/java/com/capstone/kkumteul/kafka/KafkaProducerTest.java
new file mode 100644
index 0000000..deef991
--- /dev/null
+++ b/src/test/java/com/capstone/kkumteul/kafka/KafkaProducerTest.java
@@ -0,0 +1,51 @@
+package com.capstone.kkumteul.kafka;
+
+import com.capstone.kkumteul.domain.fairytale.entity.Background;
+import com.capstone.kkumteul.domain.fairytale.entity.CharSpecies;
+import com.capstone.kkumteul.domain.fairytale.entity.Morality;
+import com.capstone.kkumteul.domain.kafka.dto.FairytaleGenerateMessage;
+import com.capstone.kkumteul.domain.kafka.dto.MessageInterface;
+import com.capstone.kkumteul.global.config.KafkaProducerConfig;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.support.SendResult;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@SpringBootTest(
+        classes = KafkaProducerConfig.class,
+        properties = "KAFKA_URL=52.78.205.133:9092"
+)
+class KafkaProducerTest {
+
+    @Autowired
+    private KafkaTemplate<String, MessageInterface> kafkaTemplate;
+
+    @Test
+    void messagePublicationTest() throws Exception {
+
+        FairytaleGenerateMessage message = FairytaleGenerateMessage.builder()
+                .userId(1L)
+                .background(Background.FOREST_NATURE)
+                .charSpecies(CharSpecies.ANIMAL)
+                .morality(Morality.KINDNESS_REWARDED)
+                .build();
+
+        CompletableFuture<SendResult<String, MessageInterface>> future =
+                kafkaTemplate.send("fairytale_generate", message);
+
+        SendResult<String, MessageInterface> result = future.get(10, TimeUnit.SECONDS);
+
+        assertThat(result.getRecordMetadata().topic()).isEqualTo("fairytale_generate");
+        assertThat(result.getRecordMetadata().offset()).isGreaterThanOrEqualTo(0);
+
+        System.out.println("토픽: " + result.getRecordMetadata().topic());
+        System.out.println("파티션: " + result.getRecordMetadata().partition());
+        System.out.println("오프셋: " + result.getRecordMetadata().offset());
+    }
+}

From d228a432925b6efecb20948bc403f5fcf20d900a Mon Sep 17 00:00:00 2001
From: Joonseok-Lee <dlwnstjr31@hansung.ac.kr>
Date: Wed, 6 May 2026 19:41:23 +0900
Subject: [PATCH 08/13] =?UTF-8?q?Test:=20Kafka=20=ED=86=B5=EC=8B=A0=20?=
 =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=ED=81=B4=EB=9E=98=EC=8A=A4,=20?=
 =?UTF-8?q?=EB=A9=94=EC=86=8C=EB=93=9C=20=EC=9E=91=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/capstone/kkumteul/kafka/KafkaProducerTest.java    | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/test/java/com/capstone/kkumteul/kafka/KafkaProducerTest.java b/src/test/java/com/capstone/kkumteul/kafka/KafkaProducerTest.java
index deef991..1611b9e 100644
--- a/src/test/java/com/capstone/kkumteul/kafka/KafkaProducerTest.java
+++ b/src/test/java/com/capstone/kkumteul/kafka/KafkaProducerTest.java
@@ -18,8 +18,7 @@
 import static org.assertj.core.api.Assertions.assertThat;
 
 @SpringBootTest(
-        classes = KafkaProducerConfig.class,
-        properties = "KAFKA_URL=52.78.205.133:9092"
+        classes = KafkaProducerConfig.class
 )
 class KafkaProducerTest {
 

From 383bcc3c687a0882055b0762e45092b4d74dc97c Mon Sep 17 00:00:00 2001
From: Joonseok-Lee <dlwnstjr31@hansung.ac.kr>
Date: Wed, 6 May 2026 19:43:03 +0900
Subject: [PATCH 09/13] =?UTF-8?q?Fix:=20kakfa=20=ED=85=9C=ED=94=8C?=
 =?UTF-8?q?=EB=A6=BF=20=EC=A0=9C=EB=84=A4=EB=A6=AD=EC=9D=84=20=EC=84=A0?=
 =?UTF-8?q?=EC=96=B8=ED=95=9C=20Bean=20=ED=83=80=EC=9E=85=EA=B3=BC=20?=
 =?UTF-8?q?=EC=9D=BC=EC=B9=98=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?=
 =?UTF-8?q?=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../capstone/kkumteul/domain/kafka/service/EventService.java   | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java b/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java
index 58e55c6..3891864 100644
--- a/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java
+++ b/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java
@@ -2,6 +2,7 @@
 
 import com.capstone.kkumteul.domain.fairytale.web.dto.FairytaleGenerateReq;
 import com.capstone.kkumteul.domain.kafka.dto.FairytaleGenerateMessage;
+import com.capstone.kkumteul.domain.kafka.dto.MessageInterface;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.kafka.core.KafkaTemplate;
@@ -14,7 +15,7 @@
 @RequiredArgsConstructor
 public class EventService {
 
-    private final KafkaTemplate<String, FairytaleGenerateMessage> kafkaTemplate;
+    private final KafkaTemplate<String, MessageInterface> kafkaTemplate;
 
     public void commentMessageCreate(Long userId, FairytaleGenerateReq request) {
 

From 2a477d3503c2800d31c124b75e26929efed3d46f Mon Sep 17 00:00:00 2001
From: Joonseok-Lee <dlwnstjr31@hansung.ac.kr>
Date: Thu, 7 May 2026 18:50:40 +0900
Subject: [PATCH 10/13] =?UTF-8?q?Docs:=20Kafka=20=ED=85=8C=EC=8A=A4?=
 =?UTF-8?q?=ED=8A=B8=EB=A5=BC=20=EC=9C=84=ED=95=B4=20.env=20=EB=82=B4?=
 =?UTF-8?q?=EC=9D=98=20Kafka=20=EA=B2=BD=EB=A1=9C=EB=A5=BC=20=EC=A7=81?=
 =?UTF-8?q?=EC=A0=91=20=EC=A3=BC=EC=9E=85=EB=B0=9B=EA=B2=8C=20=ED=95=98?=
 =?UTF-8?q?=EB=8A=94=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EB=9D=BC=EC=9D=B4?=
 =?UTF-8?q?=EB=B8=8C=EB=9F=AC=EB=A6=AC=EB=A5=BC=20=EB=93=B1=EB=A1=9D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 build.gradle | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/build.gradle b/build.gradle
index 292218c..053c33c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -43,8 +43,8 @@ dependencies {
 	runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
 	runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'
 
-	// for Kafka test
-	testImplementation 'me.paulschwarz:spring-dotenv:4.0.0'
+	// .env 파일 로딩
+	implementation 'me.paulschwarz:spring-dotenv:4.0.0'
 }
 
 tasks.named('test') {

From 5002fd1408506c98b88a4bcd77544f86a4ecbe70 Mon Sep 17 00:00:00 2001
From: Joonseok-Lee <dlwnstjr31@hansung.ac.kr>
Date: Thu, 7 May 2026 18:51:15 +0900
Subject: [PATCH 11/13] =?UTF-8?q?Fix:=20DI=EB=B0=9B=EB=8D=98=20kafkaTempla?=
 =?UTF-8?q?te=EC=9D=98=20=EB=A7=A4=EA=B0=9C=EB=B3=80=EC=88=98=EB=A5=BC=20F?=
 =?UTF-8?q?airytaleGenerateReq=EC=97=90=EC=84=9C=20MessageInterface?=
 =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../capstone/kkumteul/domain/kafka/service/EventService.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java b/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java
index 3891864..cc8c3b4 100644
--- a/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java
+++ b/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java
@@ -17,7 +17,7 @@ public class EventService {
 
     private final KafkaTemplate<String, MessageInterface> kafkaTemplate;
 
-    public void commentMessageCreate(Long userId, FairytaleGenerateReq request) {
+    public void createFairytaleMessageSend(Long userId, FairytaleGenerateReq request) {
 
         FairytaleGenerateMessage message = FairytaleGenerateMessage.builder()
                 .userId(userId)

From 8bab1403db09f2a132634f2cba6fa78482085aff Mon Sep 17 00:00:00 2001
From: Joonseok-Lee <dlwnstjr31@hansung.ac.kr>
Date: Thu, 7 May 2026 18:51:38 +0900
Subject: [PATCH 12/13] =?UTF-8?q?Feat:=20=EB=8F=99=ED=99=94=20=EC=83=9D?=
 =?UTF-8?q?=EC=84=B1=20=EC=9A=94=EC=B2=AD=EC=9D=B4=20=EB=93=A4=EC=96=B4?=
 =?UTF-8?q?=EC=98=AC=20=EC=8B=9C,=20Kafka=EC=97=90=20=EB=8F=99=ED=99=94=20?=
 =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=A9=94=EC=84=B8=EC=A7=80=20=EB=93=B1?=
 =?UTF-8?q?=EB=A1=9D=ED=95=98=EB=8A=94=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?=
 =?UTF-8?q?=EB=9F=AC=20=EB=A9=94=EC=86=8C=EB=93=9C=EB=A5=BC=20=EA=B5=AC?=
 =?UTF-8?q?=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../web/controller/FairytaleController.java      | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/src/main/java/com/capstone/kkumteul/domain/fairytale/web/controller/FairytaleController.java b/src/main/java/com/capstone/kkumteul/domain/fairytale/web/controller/FairytaleController.java
index 8780372..acc463a 100644
--- a/src/main/java/com/capstone/kkumteul/domain/fairytale/web/controller/FairytaleController.java
+++ b/src/main/java/com/capstone/kkumteul/domain/fairytale/web/controller/FairytaleController.java
@@ -3,10 +3,13 @@
 import com.capstone.kkumteul.domain.fairytale.entity.Island;
 import com.capstone.kkumteul.domain.fairytale.service.FairytaleService;
 import com.capstone.kkumteul.domain.fairytale.web.dto.FairytaleDetailRes;
+import com.capstone.kkumteul.domain.fairytale.web.dto.FairytaleGenerateReq;
 import com.capstone.kkumteul.domain.fairytale.web.dto.FairytaleListRes;
+import com.capstone.kkumteul.domain.kafka.service.EventService;
 import com.capstone.kkumteul.domain.user.entity.User;
 import com.capstone.kkumteul.global.response.SuccessResponse;
 import com.capstone.kkumteul.global.security.AuthUser;
+import jakarta.validation.Valid;
 import lombok.RequiredArgsConstructor;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
@@ -21,6 +24,19 @@
 public class FairytaleController {
 
     private final FairytaleService fairytaleService;
+    private final EventService eventService;
+
+    @PostMapping
+    public ResponseEntity<SuccessResponse<?>> createFairytale(
+            @AuthUser User user,
+            @Valid @RequestBody FairytaleGenerateReq request
+    ) {
+        eventService.createFairytaleMessageSend(user.getId(), request);
+
+        return ResponseEntity
+                .status(HttpStatus.CREATED)
+                .body(SuccessResponse.empty());
+    }
 
     @GetMapping("/my")
     public ResponseEntity<SuccessResponse<Page<FairytaleListRes>>> getMyFairytales(

From 603562eb89b9f6563506a3c2014d22490c3f7bbf Mon Sep 17 00:00:00 2001
From: Joonseok-Lee <dlwnstjr31@hansung.ac.kr>
Date: Thu, 7 May 2026 19:00:53 +0900
Subject: [PATCH 13/13] =?UTF-8?q?Docs:=20=EC=82=AC=EC=9A=A9=ED=95=98?=
 =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20import=EB=AC=B8=20=EC=B5=9C?=
 =?UTF-8?q?=EC=A0=81=ED=99=94?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../fairytale/exception/FairytaleErrorCode.java       |  2 +-
 .../fairytale/web/dto/FairytaleGenerateReq.java       |  2 +-
 .../kkumteul/domain/game/entity/NodeCategory.java     |  3 +--
 .../kkumteul/domain/game/service/GameServiceImpl.java |  6 +-----
 .../kkumteul/domain/kafka/service/EventService.java   | 11 ++++++++++-
 .../kkumteul/global/config/KafkaProducerConfig.java   |  1 -
 .../global/exception/GlobalExceptionHandler.java      |  2 +-
 .../capstone/kkumteul/kafka/KafkaProducerTest.java    |  8 +++++---
 8 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/src/main/java/com/capstone/kkumteul/domain/fairytale/exception/FairytaleErrorCode.java b/src/main/java/com/capstone/kkumteul/domain/fairytale/exception/FairytaleErrorCode.java
index ad82647..4c3abb1 100644
--- a/src/main/java/com/capstone/kkumteul/domain/fairytale/exception/FairytaleErrorCode.java
+++ b/src/main/java/com/capstone/kkumteul/domain/fairytale/exception/FairytaleErrorCode.java
@@ -4,7 +4,7 @@
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
-import static com.capstone.kkumteul.global.constant.StaticValue.*;
+import static com.capstone.kkumteul.global.constant.StaticValue.NOT_FOUND;
 
 @Getter
 @AllArgsConstructor
diff --git a/src/main/java/com/capstone/kkumteul/domain/fairytale/web/dto/FairytaleGenerateReq.java b/src/main/java/com/capstone/kkumteul/domain/fairytale/web/dto/FairytaleGenerateReq.java
index bdfaf66..386732a 100644
--- a/src/main/java/com/capstone/kkumteul/domain/fairytale/web/dto/FairytaleGenerateReq.java
+++ b/src/main/java/com/capstone/kkumteul/domain/fairytale/web/dto/FairytaleGenerateReq.java
@@ -15,7 +15,7 @@ public class FairytaleGenerateReq {
     private final Background background;
 
     @NotNull(message = "등장인물 종류는 비어있을 수 없습니다.")
-    private final CharSpecies charSpecie;
+    private final CharSpecies charSpecies;
 
     @NotNull(message = "교훈은 비어있을 수 없습니다.")
     private final Morality morality;
diff --git a/src/main/java/com/capstone/kkumteul/domain/game/entity/NodeCategory.java b/src/main/java/com/capstone/kkumteul/domain/game/entity/NodeCategory.java
index cd29c58..3cf97a6 100644
--- a/src/main/java/com/capstone/kkumteul/domain/game/entity/NodeCategory.java
+++ b/src/main/java/com/capstone/kkumteul/domain/game/entity/NodeCategory.java
@@ -1,10 +1,9 @@
 package com.capstone.kkumteul.domain.game.entity;
 
+import com.capstone.kkumteul.domain.game.exception.InvalidCategoryException;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
-import com.capstone.kkumteul.domain.game.exception.InvalidCategoryException;
-
 import java.util.Arrays;
 
 @Getter
diff --git a/src/main/java/com/capstone/kkumteul/domain/game/service/GameServiceImpl.java b/src/main/java/com/capstone/kkumteul/domain/game/service/GameServiceImpl.java
index 68fe4c7..6ea1cb9 100644
--- a/src/main/java/com/capstone/kkumteul/domain/game/service/GameServiceImpl.java
+++ b/src/main/java/com/capstone/kkumteul/domain/game/service/GameServiceImpl.java
@@ -1,12 +1,8 @@
 package com.capstone.kkumteul.domain.game.service;
 
 import com.capstone.kkumteul.domain.fairytale.entity.Fairytale;
-import com.capstone.kkumteul.domain.game.entity.GraphEdge;
-import com.capstone.kkumteul.domain.game.entity.GraphNode;
-import com.capstone.kkumteul.domain.game.entity.NodeCategory;
-import com.capstone.kkumteul.domain.game.entity.EdgeChoice;
-import com.capstone.kkumteul.domain.game.entity.GameResult;
 import com.capstone.kkumteul.domain.fairytale.exception.FairytaleNotFoundException;
+import com.capstone.kkumteul.domain.game.entity.*;
 import com.capstone.kkumteul.domain.game.exception.*;
 import com.capstone.kkumteul.domain.game.repository.EdgeChoiceRepository;
 import com.capstone.kkumteul.domain.game.repository.GameResultRepository;
diff --git a/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java b/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java
index cc8c3b4..18d4aeb 100644
--- a/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java
+++ b/src/main/java/com/capstone/kkumteul/domain/kafka/service/EventService.java
@@ -5,6 +5,7 @@
 import com.capstone.kkumteul.domain.kafka.dto.MessageInterface;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.kafka.core.KafkaTemplate;
 import org.springframework.stereotype.Service;
 
@@ -17,6 +18,9 @@ public class EventService {
 
     private final KafkaTemplate<String, MessageInterface> kafkaTemplate;
 
+    @Value("${FAIRYTALE_GENERATION}")
+    private String FAIRYTALE_GENERATION;
+
     public void createFairytaleMessageSend(Long userId, FairytaleGenerateReq request) {
 
         FairytaleGenerateMessage message = FairytaleGenerateMessage.builder()
@@ -28,7 +32,12 @@ public void createFairytaleMessageSend(Long userId, FairytaleGenerateReq request
 
         log.info("fairytale_generate userId={}, message={}", userId, message);
 
-        kafkaTemplate.send("fairytale_generate", message);
+        kafkaTemplate.send(FAIRYTALE_GENERATION, message)
+                .whenComplete((result, e) -> {
+                    if (e != null) {
+                        log.error("fairytale_generate failed", e);
+                    }
+                });
 
     }
 }
diff --git a/src/main/java/com/capstone/kkumteul/global/config/KafkaProducerConfig.java b/src/main/java/com/capstone/kkumteul/global/config/KafkaProducerConfig.java
index f368cad..f04bf37 100644
--- a/src/main/java/com/capstone/kkumteul/global/config/KafkaProducerConfig.java
+++ b/src/main/java/com/capstone/kkumteul/global/config/KafkaProducerConfig.java
@@ -1,6 +1,5 @@
 package com.capstone.kkumteul.global.config;
 
-import com.capstone.kkumteul.domain.kafka.dto.FairytaleGenerateMessage;
 import com.capstone.kkumteul.domain.kafka.dto.MessageInterface;
 import org.apache.kafka.clients.producer.ProducerConfig;
 import org.apache.kafka.common.serialization.StringSerializer;
diff --git a/src/main/java/com/capstone/kkumteul/global/exception/GlobalExceptionHandler.java b/src/main/java/com/capstone/kkumteul/global/exception/GlobalExceptionHandler.java
index d35e58e..477184d 100644
--- a/src/main/java/com/capstone/kkumteul/global/exception/GlobalExceptionHandler.java
+++ b/src/main/java/com/capstone/kkumteul/global/exception/GlobalExceptionHandler.java
@@ -8,10 +8,10 @@
 import org.springframework.validation.BindException;
 import org.springframework.web.HttpRequestMethodNotSupportedException;
 import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
 import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
-import org.springframework.web.bind.MissingServletRequestParameterException;
 import org.springframework.web.multipart.support.MissingServletRequestPartException;
 import org.springframework.web.servlet.NoHandlerFoundException;
 import org.springframework.web.servlet.resource.NoResourceFoundException;
diff --git a/src/test/java/com/capstone/kkumteul/kafka/KafkaProducerTest.java b/src/test/java/com/capstone/kkumteul/kafka/KafkaProducerTest.java
index 1611b9e..9578cc9 100644
--- a/src/test/java/com/capstone/kkumteul/kafka/KafkaProducerTest.java
+++ b/src/test/java/com/capstone/kkumteul/kafka/KafkaProducerTest.java
@@ -6,6 +6,7 @@
 import com.capstone.kkumteul.domain.kafka.dto.FairytaleGenerateMessage;
 import com.capstone.kkumteul.domain.kafka.dto.MessageInterface;
 import com.capstone.kkumteul.global.config.KafkaProducerConfig;
+import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
@@ -17,6 +18,7 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 
+@Slf4j
 @SpringBootTest(
         classes = KafkaProducerConfig.class
 )
@@ -43,8 +45,8 @@ void messagePublicationTest() throws Exception {
         assertThat(result.getRecordMetadata().topic()).isEqualTo("fairytale_generate");
         assertThat(result.getRecordMetadata().offset()).isGreaterThanOrEqualTo(0);
 
-        System.out.println("토픽: " + result.getRecordMetadata().topic());
-        System.out.println("파티션: " + result.getRecordMetadata().partition());
-        System.out.println("오프셋: " + result.getRecordMetadata().offset());
+        log.info("토픽: {}", result.getRecordMetadata().topic());
+        log.info("파티션: {}", result.getRecordMetadata().partition());
+        log.info("오프셋: {}", result.getRecordMetadata().offset());
     }
 }
