diff --git a/build/reports/problems/problems-report.html b/build/reports/problems/problems-report.html
index 4c29f95..54d21ff 100644
--- a/build/reports/problems/problems-report.html
+++ b/build/reports/problems/problems-report.html
@@ -650,7 +650,7 @@ code + .copy-button {
diff --git a/meeting/build.gradle b/meeting/build.gradle
index 078034a..f85d3aa 100644
--- a/meeting/build.gradle
+++ b/meeting/build.gradle
@@ -21,7 +21,15 @@ dependencies {
// WebSocket
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'org.springframework.boot:spring-boot-starter-reactor-netty'
-
- // Kafka
- implementation 'org.springframework.kafka:spring-kafka'
+
+ // Azure EventHub
+ implementation 'com.azure:azure-messaging-eventhubs:5.15.0'
+ implementation 'com.azure:azure-messaging-eventhubs-checkpointstore-blob:1.16.1'
+ implementation 'com.azure:azure-identity:1.9.0'
+
+ // Jackson for JSON processing
+ implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
+
+ // Retry support
+ implementation 'org.springframework.retry:spring-retry'
}
diff --git a/meeting/logs/meeting-service.log b/meeting/logs/meeting-service.log
index 0cd9398..5deacef 100644
--- a/meeting/logs/meeting-service.log
+++ b/meeting/logs/meeting-service.log
@@ -781,3 +781,258 @@ This generated password is for development use only. Your security configuration
2025-10-24 10:00:22 [SpringApplicationShutdownHook] DEBUG o.h.type.spi.TypeConfiguration$Scope - Un-scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration$Scope@6d1e60ad] from SessionFactory [org.hibernate.internal.SessionFactoryImpl@5444c63f]
2025-10-24 10:00:22 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
2025-10-24 10:00:22 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
+2025-10-24 10:34:45 [main] INFO c.u.h.meeting.MeetingApplication - Starting MeetingApplication using Java 21.0.8 with PID 96972 (/Users/daewoong/home/workspace/HGZero/meeting/build/classes/java/main started by daewoong in /Users/daewoong/home/workspace/HGZero/meeting)
+2025-10-24 10:34:45 [main] DEBUG c.u.h.meeting.MeetingApplication - Running with Spring Boot v3.3.5, Spring v6.1.14
+2025-10-24 10:34:45 [main] INFO c.u.h.meeting.MeetingApplication - The following 1 profile is active: "dev"
+2025-10-24 10:34:46 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
+2025-10-24 10:34:46 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
+2025-10-24 10:34:46 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 57 ms. Found 5 JPA repository interfaces.
+2025-10-24 10:34:46 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
+2025-10-24 10:34:46 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode.
+2025-10-24 10:34:46 [main] INFO o.s.d.r.c.RepositoryConfigurationExtensionSupport - Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.unicorn.hgzero.meeting.infra.gateway.repository.MeetingJpaRepository; If you want this repository to be a Redis repository, consider annotating your entities with one of these annotations: org.springframework.data.redis.core.RedisHash (preferred), or consider extending one of the following types with your repository: org.springframework.data.keyvalue.repository.KeyValueRepository
+2025-10-24 10:34:46 [main] INFO o.s.d.r.c.RepositoryConfigurationExtensionSupport - Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.unicorn.hgzero.meeting.infra.gateway.repository.MinutesJpaRepository; If you want this repository to be a Redis repository, consider annotating your entities with one of these annotations: org.springframework.data.redis.core.RedisHash (preferred), or consider extending one of the following types with your repository: org.springframework.data.keyvalue.repository.KeyValueRepository
+2025-10-24 10:34:46 [main] INFO o.s.d.r.c.RepositoryConfigurationExtensionSupport - Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.unicorn.hgzero.meeting.infra.gateway.repository.MinutesSectionJpaRepository; If you want this repository to be a Redis repository, consider annotating your entities with one of these annotations: org.springframework.data.redis.core.RedisHash (preferred), or consider extending one of the following types with your repository: org.springframework.data.keyvalue.repository.KeyValueRepository
+2025-10-24 10:34:46 [main] INFO o.s.d.r.c.RepositoryConfigurationExtensionSupport - Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.unicorn.hgzero.meeting.infra.gateway.repository.TemplateJpaRepository; If you want this repository to be a Redis repository, consider annotating your entities with one of these annotations: org.springframework.data.redis.core.RedisHash (preferred), or consider extending one of the following types with your repository: org.springframework.data.keyvalue.repository.KeyValueRepository
+2025-10-24 10:34:46 [main] INFO o.s.d.r.c.RepositoryConfigurationExtensionSupport - Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.unicorn.hgzero.meeting.infra.gateway.repository.TodoJpaRepository; If you want this repository to be a Redis repository, consider annotating your entities with one of these annotations: org.springframework.data.redis.core.RedisHash (preferred), or consider extending one of the following types with your repository: org.springframework.data.keyvalue.repository.KeyValueRepository
+2025-10-24 10:34:46 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 11 ms. Found 0 Redis repository interfaces.
+2025-10-24 10:34:46 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8082 (http)
+2025-10-24 10:34:46 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat]
+2025-10-24 10:34:46 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.31]
+2025-10-24 10:34:46 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
+2025-10-24 10:34:46 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 962 ms
+2025-10-24 10:34:46 [main] INFO o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
+2025-10-24 10:34:46 [main] INFO org.hibernate.Version - HHH000412: Hibernate ORM core version 6.5.3.Final
+2025-10-24 10:34:46 [main] INFO o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration boolean -> org.hibernate.type.BasicTypeReference@1a8b22b5
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration boolean -> org.hibernate.type.BasicTypeReference@1a8b22b5
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Boolean -> org.hibernate.type.BasicTypeReference@1a8b22b5
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration numeric_boolean -> org.hibernate.type.BasicTypeReference@5f781173
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.NumericBooleanConverter -> org.hibernate.type.BasicTypeReference@5f781173
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration true_false -> org.hibernate.type.BasicTypeReference@43cf5bff
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.TrueFalseConverter -> org.hibernate.type.BasicTypeReference@43cf5bff
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration yes_no -> org.hibernate.type.BasicTypeReference@2b464384
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.YesNoConverter -> org.hibernate.type.BasicTypeReference@2b464384
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration byte -> org.hibernate.type.BasicTypeReference@681b42d3
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration byte -> org.hibernate.type.BasicTypeReference@681b42d3
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Byte -> org.hibernate.type.BasicTypeReference@681b42d3
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration binary -> org.hibernate.type.BasicTypeReference@77f7352a
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration byte[] -> org.hibernate.type.BasicTypeReference@77f7352a
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration [B -> org.hibernate.type.BasicTypeReference@77f7352a
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration binary_wrapper -> org.hibernate.type.BasicTypeReference@4ede8888
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration wrapper-binary -> org.hibernate.type.BasicTypeReference@4ede8888
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration image -> org.hibernate.type.BasicTypeReference@571db8b4
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration blob -> org.hibernate.type.BasicTypeReference@65a2755e
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Blob -> org.hibernate.type.BasicTypeReference@65a2755e
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_blob -> org.hibernate.type.BasicTypeReference@2b3242a5
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_blob_wrapper -> org.hibernate.type.BasicTypeReference@11120583
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration short -> org.hibernate.type.BasicTypeReference@2bf0c70d
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration short -> org.hibernate.type.BasicTypeReference@2bf0c70d
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Short -> org.hibernate.type.BasicTypeReference@2bf0c70d
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration integer -> org.hibernate.type.BasicTypeReference@5d8e4fa8
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration int -> org.hibernate.type.BasicTypeReference@5d8e4fa8
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Integer -> org.hibernate.type.BasicTypeReference@5d8e4fa8
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration long -> org.hibernate.type.BasicTypeReference@649009d6
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration long -> org.hibernate.type.BasicTypeReference@649009d6
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Long -> org.hibernate.type.BasicTypeReference@649009d6
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration float -> org.hibernate.type.BasicTypeReference@652f26da
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration float -> org.hibernate.type.BasicTypeReference@652f26da
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Float -> org.hibernate.type.BasicTypeReference@652f26da
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration double -> org.hibernate.type.BasicTypeReference@484a5ddd
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration double -> org.hibernate.type.BasicTypeReference@484a5ddd
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Double -> org.hibernate.type.BasicTypeReference@484a5ddd
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration big_integer -> org.hibernate.type.BasicTypeReference@6796a873
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.math.BigInteger -> org.hibernate.type.BasicTypeReference@6796a873
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration big_decimal -> org.hibernate.type.BasicTypeReference@3acc3ee
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.math.BigDecimal -> org.hibernate.type.BasicTypeReference@3acc3ee
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration character -> org.hibernate.type.BasicTypeReference@1f293cb7
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration char -> org.hibernate.type.BasicTypeReference@1f293cb7
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Character -> org.hibernate.type.BasicTypeReference@1f293cb7
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration character_nchar -> org.hibernate.type.BasicTypeReference@5972e3a
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration string -> org.hibernate.type.BasicTypeReference@5790cbcb
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.String -> org.hibernate.type.BasicTypeReference@5790cbcb
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration nstring -> org.hibernate.type.BasicTypeReference@32c6d164
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration characters -> org.hibernate.type.BasicTypeReference@645c9f0f
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration char[] -> org.hibernate.type.BasicTypeReference@645c9f0f
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration [C -> org.hibernate.type.BasicTypeReference@645c9f0f
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration wrapper-characters -> org.hibernate.type.BasicTypeReference@58068b40
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration text -> org.hibernate.type.BasicTypeReference@999cd18
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ntext -> org.hibernate.type.BasicTypeReference@dd060be
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration clob -> org.hibernate.type.BasicTypeReference@df432ec
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Clob -> org.hibernate.type.BasicTypeReference@df432ec
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration nclob -> org.hibernate.type.BasicTypeReference@6144e499
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.NClob -> org.hibernate.type.BasicTypeReference@6144e499
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_clob -> org.hibernate.type.BasicTypeReference@26f204a4
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_clob_char_array -> org.hibernate.type.BasicTypeReference@28295554
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_clob_character_array -> org.hibernate.type.BasicTypeReference@4e671ef
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_nclob -> org.hibernate.type.BasicTypeReference@42403dc6
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_nclob_character_array -> org.hibernate.type.BasicTypeReference@74a1d60e
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_nclob_char_array -> org.hibernate.type.BasicTypeReference@16c0be3b
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration Duration -> org.hibernate.type.BasicTypeReference@219edc05
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.Duration -> org.hibernate.type.BasicTypeReference@219edc05
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration LocalDateTime -> org.hibernate.type.BasicTypeReference@62f37bfd
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.LocalDateTime -> org.hibernate.type.BasicTypeReference@62f37bfd
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration LocalDate -> org.hibernate.type.BasicTypeReference@1818d00b
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.LocalDate -> org.hibernate.type.BasicTypeReference@1818d00b
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration LocalTime -> org.hibernate.type.BasicTypeReference@b3a8455
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.LocalTime -> org.hibernate.type.BasicTypeReference@b3a8455
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTime -> org.hibernate.type.BasicTypeReference@5c930fc3
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetDateTime -> org.hibernate.type.BasicTypeReference@5c930fc3
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTimeWithTimezone -> org.hibernate.type.BasicTypeReference@25c6ab3f
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTimeWithoutTimezone -> org.hibernate.type.BasicTypeReference@7b80af04
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTime -> org.hibernate.type.BasicTypeReference@2447940d
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetTime -> org.hibernate.type.BasicTypeReference@2447940d
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTimeUtc -> org.hibernate.type.BasicTypeReference@60ee7a51
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTimeWithTimezone -> org.hibernate.type.BasicTypeReference@70e1aa20
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTimeWithoutTimezone -> org.hibernate.type.BasicTypeReference@e67d3b7
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTime -> org.hibernate.type.BasicTypeReference@1618c98a
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.ZonedDateTime -> org.hibernate.type.BasicTypeReference@1618c98a
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTimeWithTimezone -> org.hibernate.type.BasicTypeReference@5b715ea
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTimeWithoutTimezone -> org.hibernate.type.BasicTypeReference@787a0fd6
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration date -> org.hibernate.type.BasicTypeReference@48b09105
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Date -> org.hibernate.type.BasicTypeReference@48b09105
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration time -> org.hibernate.type.BasicTypeReference@18b45500
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Time -> org.hibernate.type.BasicTypeReference@18b45500
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration timestamp -> org.hibernate.type.BasicTypeReference@25110bb9
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Timestamp -> org.hibernate.type.BasicTypeReference@25110bb9
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Date -> org.hibernate.type.BasicTypeReference@25110bb9
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration calendar -> org.hibernate.type.BasicTypeReference@dbda472
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Calendar -> org.hibernate.type.BasicTypeReference@dbda472
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.GregorianCalendar -> org.hibernate.type.BasicTypeReference@dbda472
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration calendar_date -> org.hibernate.type.BasicTypeReference@41492479
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration calendar_time -> org.hibernate.type.BasicTypeReference@7bef7505
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration instant -> org.hibernate.type.BasicTypeReference@568ef502
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.Instant -> org.hibernate.type.BasicTypeReference@568ef502
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration uuid -> org.hibernate.type.BasicTypeReference@36f05595
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.UUID -> org.hibernate.type.BasicTypeReference@36f05595
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration pg-uuid -> org.hibernate.type.BasicTypeReference@36f05595
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration uuid-binary -> org.hibernate.type.BasicTypeReference@3e12c5de
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration uuid-char -> org.hibernate.type.BasicTypeReference@3e55d844
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration class -> org.hibernate.type.BasicTypeReference@1f521c69
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Class -> org.hibernate.type.BasicTypeReference@1f521c69
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration currency -> org.hibernate.type.BasicTypeReference@2b3abeeb
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration Currency -> org.hibernate.type.BasicTypeReference@2b3abeeb
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Currency -> org.hibernate.type.BasicTypeReference@2b3abeeb
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration locale -> org.hibernate.type.BasicTypeReference@3aeb267
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Locale -> org.hibernate.type.BasicTypeReference@3aeb267
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration serializable -> org.hibernate.type.BasicTypeReference@13a9cdae
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.io.Serializable -> org.hibernate.type.BasicTypeReference@13a9cdae
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration timezone -> org.hibernate.type.BasicTypeReference@1c972ae6
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.TimeZone -> org.hibernate.type.BasicTypeReference@1c972ae6
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZoneOffset -> org.hibernate.type.BasicTypeReference@62a41279
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.ZoneOffset -> org.hibernate.type.BasicTypeReference@62a41279
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration url -> org.hibernate.type.BasicTypeReference@146fa9c0
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.net.URL -> org.hibernate.type.BasicTypeReference@146fa9c0
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration vector -> org.hibernate.type.BasicTypeReference@49f6c25e
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration row_version -> org.hibernate.type.BasicTypeReference@6c13019c
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration object -> org.hibernate.type.JavaObjectType@1c79d093
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Object -> org.hibernate.type.JavaObjectType@1c79d093
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration null -> org.hibernate.type.NullType@7a587e84
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_date -> org.hibernate.type.BasicTypeReference@622ba721
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_time -> org.hibernate.type.BasicTypeReference@7509226c
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_timestamp -> org.hibernate.type.BasicTypeReference@4c9cce17
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_calendar -> org.hibernate.type.BasicTypeReference@73316a0a
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_calendar_date -> org.hibernate.type.BasicTypeReference@63a7af06
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_calendar_time -> org.hibernate.type.BasicTypeReference@5f01fb5c
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_binary -> org.hibernate.type.BasicTypeReference@75c77add
+2025-10-24 10:34:46 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_serializable -> org.hibernate.type.BasicTypeReference@d5e3f55
+2025-10-24 10:34:47 [main] INFO o.s.o.j.p.SpringPersistenceUnitInfo - No LoadTimeWeaver setup: ignoring JPA class transformer
+2025-10-24 10:34:47 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
+2025-10-24 10:34:47 [main] INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@244f356
+2025-10-24 10:34:47 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
+2025-10-24 10:34:47 [main] WARN org.hibernate.orm.deprecation - HHH90000025: PostgreSQLDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default)
+2025-10-24 10:34:47 [main] DEBUG o.h.t.d.sql.spi.DdlTypeRegistry - addDescriptor(2003, org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl@2cd2c764) replaced previous registration(org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl@d17d554)
+2025-10-24 10:34:47 [main] DEBUG o.h.t.d.sql.spi.DdlTypeRegistry - addDescriptor(6, org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType@1f1c7fde) replaced previous registration(org.hibernate.type.descriptor.sql.internal.DdlTypeImpl@2b409174)
+2025-10-24 10:34:47 [main] DEBUG o.h.t.d.jdbc.spi.JdbcTypeRegistry - addDescriptor(2004, BlobTypeDescriptor(BLOB_BINDING)) replaced previous registration(BlobTypeDescriptor(DEFAULT))
+2025-10-24 10:34:47 [main] DEBUG o.h.t.d.jdbc.spi.JdbcTypeRegistry - addDescriptor(2005, ClobTypeDescriptor(CLOB_BINDING)) replaced previous registration(ClobTypeDescriptor(DEFAULT))
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration JAVA_OBJECT -> org.hibernate.type.JavaObjectType@571c7572
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Object -> org.hibernate.type.JavaObjectType@571c7572
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Type registration key [java.lang.Object] overrode previous entry : `org.hibernate.type.JavaObjectType@1c79d093`
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.DurationType -> basicType@1(java.time.Duration,3015)
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration Duration -> basicType@1(java.time.Duration,3015)
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.Duration -> basicType@1(java.time.Duration,3015)
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.OffsetDateTimeType -> basicType@2(java.time.OffsetDateTime,3003)
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTime -> basicType@2(java.time.OffsetDateTime,3003)
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetDateTime -> basicType@2(java.time.OffsetDateTime,3003)
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.ZonedDateTimeType -> basicType@3(java.time.ZonedDateTime,3003)
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTime -> basicType@3(java.time.ZonedDateTime,3003)
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.ZonedDateTime -> basicType@3(java.time.ZonedDateTime,3003)
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.OffsetTimeType -> basicType@4(java.time.OffsetTime,3007)
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTime -> basicType@4(java.time.OffsetTime,3007)
+2025-10-24 10:34:47 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetTime -> basicType@4(java.time.OffsetTime,3007)
+2025-10-24 10:34:47 [main] DEBUG o.h.type.spi.TypeConfiguration$Scope - Scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration@28100232] to MetadataBuildingContext [org.hibernate.boot.internal.MetadataBuildingContextRootImpl@26728255]
+2025-10-24 10:34:48 [main] INFO o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
+2025-10-24 10:34:48 [main] DEBUG o.h.type.spi.TypeConfiguration$Scope - Scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration@28100232] to SessionFactoryImplementor [org.hibernate.internal.SessionFactoryImpl@4c9235c0]
+2025-10-24 10:34:48 [main] DEBUG org.hibernate.SQL -
+ alter table if exists meetings
+ alter column description set data type TEXT
+2025-10-24 10:34:48 [main] DEBUG org.hibernate.SQL -
+ alter table if exists meetings
+ alter column participants set data type TEXT
+2025-10-24 10:34:48 [main] DEBUG org.hibernate.SQL -
+ alter table if exists minutes_sections
+ alter column content set data type TEXT
+2025-10-24 10:34:48 [main] DEBUG org.hibernate.SQL -
+ alter table if exists templates
+ alter column description set data type TEXT
+2025-10-24 10:34:48 [main] DEBUG org.hibernate.SQL -
+ alter table if exists templates
+ alter column sections set data type TEXT
+2025-10-24 10:34:48 [main] DEBUG org.hibernate.SQL -
+ alter table if exists todos
+ alter column description set data type TEXT
+2025-10-24 10:34:48 [main] TRACE o.h.type.spi.TypeConfiguration$Scope - Handling #sessionFactoryCreated from [org.hibernate.internal.SessionFactoryImpl@4c9235c0] for TypeConfiguration
+2025-10-24 10:34:48 [main] INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
+2025-10-24 10:34:48 [main] INFO o.s.d.j.r.query.QueryEnhancerFactory - Hibernate is in classpath; If applicable, HQL parser will be used.
+2025-10-24 10:34:49 [main] INFO c.u.h.m.infra.cache.CacheConfig - Redis 연결 설정 - host: 20.249.177.114, port: 6379, database: 1
+2025-10-24 10:34:49 [main] ERROR i.n.r.d.DnsServerAddressStreamProviders - Unable to load io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProvider, fallback to system defaults. This may result in incorrect DNS resolutions on MacOS. Check whether you have a dependency on 'io.netty:netty-resolver-dns-native-macos'. Use DEBUG level to see the full stack: java.lang.UnsatisfiedLinkError: failed to load the required native library
+2025-10-24 10:34:49 [main] INFO c.u.h.m.infra.cache.CacheConfig - Redis 템플릿 설정 완료
+2025-10-24 10:34:49 [main] INFO c.u.h.m.infra.cache.CacheConfig - ObjectMapper 설정 완료
+2025-10-24 10:34:49 [main] INFO c.u.h.m.infra.config.EventHubConfig - Initializing Azure EventHub configuration with hub name: hgzero-eventhub-name
+2025-10-24 10:34:49 [main] INFO c.u.h.m.infra.config.EventHubConfig - Creating EventHub producer for hub: hgzero-eventhub-name
+2025-10-24 10:34:49 [main] INFO c.a.m.e.EventHubClientBuilder - {"az.sdk.message":"Emitting a single connection.","connectionId":"MF_f60409_1761269689442"}
+2025-10-24 10:34:49 [main] INFO c.a.m.e.i.EventHubConnectionProcessor - {"az.sdk.message":"Setting next AMQP channel.","entityPath":"hgzero-eventhub-name"}
+2025-10-24 10:34:49 [main] WARN o.s.b.a.o.j.JpaBaseConfiguration$JpaWebConfiguration - spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
+2025-10-24 10:34:49 [main] WARN o.s.b.a.s.s.UserDetailsServiceAutoConfiguration -
+
+Using generated security password: 7caeb7e6-784c-4408-aecd-e7bec17a7d2d
+
+This generated password is for development use only. Your security configuration must be updated before running your application in production.
+
+2025-10-24 10:34:49 [main] INFO o.s.s.c.a.a.c.InitializeUserDetailsBeanManagerConfigurer$InitializeUserDetailsManagerConfigurer - Global AuthenticationManager configured with UserDetailsService bean with name inMemoryUserDetailsManager
+2025-10-24 10:34:49 [main] INFO c.u.h.m.infra.config.WebSocketConfig - WebSocket 핸들러 등록 완료 - endpoint: /ws/minutes/{minutesId}
+2025-10-24 10:34:49 [main] INFO o.s.b.a.e.web.EndpointLinksResolver - Exposing 3 endpoints beneath base path '/actuator'
+2025-10-24 10:34:49 [main] DEBUG o.s.s.web.DefaultSecurityFilterChain - Will secure any request with filters: DisableEncodeUrlFilter, WebAsyncManagerIntegrationFilter, SecurityContextHolderFilter, HeaderWriterFilter, CorsFilter, LogoutFilter, JwtAuthenticationFilter, RequestCacheAwareFilter, SecurityContextHolderAwareRequestFilter, AnonymousAuthenticationFilter, SessionManagementFilter, ExceptionTranslationFilter, AuthorizationFilter
+2025-10-24 10:34:50 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8082 (http) with context path '/'
+2025-10-24 10:34:50 [main] INFO c.u.h.meeting.MeetingApplication - Started MeetingApplication in 4.678 seconds (process running for 4.839)
+2025-10-24 10:34:56 [http-nio-8082-exec-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
+2025-10-24 10:34:56 [http-nio-8082-exec-1] INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
+2025-10-24 10:34:56 [http-nio-8082-exec-1] INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 1 ms
+2025-10-24 10:34:56 [http-nio-8082-exec-1] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/index.html
+2025-10-24 10:34:56 [http-nio-8082-exec-1] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
+2025-10-24 10:34:56 [http-nio-8082-exec-1] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/index.html
+2025-10-24 10:34:56 [http-nio-8082-exec-2] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/swagger-ui.css
+2025-10-24 10:34:56 [http-nio-8082-exec-3] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/index.css
+2025-10-24 10:34:56 [http-nio-8082-exec-2] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
+2025-10-24 10:34:56 [http-nio-8082-exec-5] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/swagger-ui-standalone-preset.js
+2025-10-24 10:34:56 [http-nio-8082-exec-6] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/swagger-initializer.js
+2025-10-24 10:34:56 [http-nio-8082-exec-2] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/swagger-ui.css
+2025-10-24 10:34:56 [http-nio-8082-exec-5] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
+2025-10-24 10:34:56 [http-nio-8082-exec-6] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
+2025-10-24 10:34:56 [http-nio-8082-exec-3] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
+2025-10-24 10:34:56 [http-nio-8082-exec-5] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/swagger-ui-standalone-preset.js
+2025-10-24 10:34:56 [http-nio-8082-exec-6] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/swagger-initializer.js
+2025-10-24 10:34:56 [http-nio-8082-exec-4] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/swagger-ui-bundle.js
+2025-10-24 10:34:56 [http-nio-8082-exec-3] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/index.css
+2025-10-24 10:34:56 [http-nio-8082-exec-4] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
+2025-10-24 10:34:56 [http-nio-8082-exec-4] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/swagger-ui-bundle.js
+2025-10-24 10:34:56 [http-nio-8082-exec-7] DEBUG o.s.security.web.FilterChainProxy - Securing GET /v3/api-docs/swagger-config
+2025-10-24 10:34:56 [http-nio-8082-exec-7] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
+2025-10-24 10:34:56 [http-nio-8082-exec-7] DEBUG o.s.security.web.FilterChainProxy - Secured GET /v3/api-docs/swagger-config
+2025-10-24 10:34:56 [http-nio-8082-exec-7] INFO c.u.hgzero.common.aop.LoggingAspect - [Controller] org.springdoc.webmvc.ui.SwaggerConfigResource.openapiJson 호출 - 파라미터: [SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@5b7947ec]]
+2025-10-24 10:34:56 [http-nio-8082-exec-7] INFO c.u.hgzero.common.aop.LoggingAspect - [Controller] org.springdoc.webmvc.ui.SwaggerConfigResource.openapiJson 완료 - 실행시간: 0ms
+2025-10-24 10:34:56 [http-nio-8082-exec-8] DEBUG o.s.security.web.FilterChainProxy - Securing GET /v3/api-docs
+2025-10-24 10:34:56 [http-nio-8082-exec-8] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
+2025-10-24 10:34:56 [http-nio-8082-exec-8] DEBUG o.s.security.web.FilterChainProxy - Secured GET /v3/api-docs
+2025-10-24 10:34:56 [http-nio-8082-exec-8] INFO c.u.hgzero.common.aop.LoggingAspect - [Controller] org.springdoc.webmvc.api.OpenApiWebMvcResource.openapiJson 호출 - 파라미터: [SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@7089f4a5], /v3/api-docs, ko_KR]
+2025-10-24 10:34:57 [http-nio-8082-exec-8] INFO o.s.api.AbstractOpenApiResource - Init duration for springdoc-openapi is: 340 ms
+2025-10-24 10:34:57 [http-nio-8082-exec-8] INFO c.u.hgzero.common.aop.LoggingAspect - [Controller] org.springdoc.webmvc.api.OpenApiWebMvcResource.openapiJson 완료 - 실행시간: 349ms
diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/config/EventHubConfig.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/config/EventHubConfig.java
index 4e61b16..a5dd275 100644
--- a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/config/EventHubConfig.java
+++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/config/EventHubConfig.java
@@ -1,91 +1,40 @@
package com.unicorn.hgzero.meeting.infra.config;
+import com.azure.messaging.eventhubs.EventHubClientBuilder;
+import com.azure.messaging.eventhubs.EventHubProducerClient;
+import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
-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 java.util.HashMap;
-import java.util.Map;
/**
- * Event Hub (Kafka) 설정
- * 이벤트 발행을 위한 Kafka 설정
+ * Azure EventHub 설정
+ * 이벤트 발행을 위한 EventHub 설정
*/
@Configuration
@Slf4j
public class EventHubConfig {
- @Value("${spring.kafka.bootstrap-servers:localhost:9092}")
- private String bootstrapServers;
+ @Value("${eventhub.connection-string}")
+ private String connectionString;
- @Value("${spring.kafka.producer.client-id:meeting-service}")
- private String clientId;
+ @Value("${eventhub.name}")
+ private String eventHubName;
- @Value("${spring.kafka.producer.acks:all}")
- private String acks;
-
- @Value("${spring.kafka.producer.retries:3}")
- private Integer retries;
-
- @Value("${spring.kafka.producer.batch-size:16384}")
- private Integer batchSize;
-
- @Value("${spring.kafka.producer.linger-ms:5}")
- private Integer lingerMs;
-
- @Value("${spring.kafka.producer.buffer-memory:33554432}")
- private Long bufferMemory;
-
- /**
- * Kafka Producer 설정
- */
- @Bean
- public ProducerFactory producerFactory() {
- Map configProps = new HashMap<>();
-
- // 기본 설정
- configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
- configProps.put(ProducerConfig.CLIENT_ID_CONFIG, clientId);
- configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
- configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
-
- // 성능 및 안정성 설정
- configProps.put(ProducerConfig.ACKS_CONFIG, acks);
- configProps.put(ProducerConfig.RETRIES_CONFIG, retries);
- configProps.put(ProducerConfig.BATCH_SIZE_CONFIG, batchSize);
- configProps.put(ProducerConfig.LINGER_MS_CONFIG, lingerMs);
- configProps.put(ProducerConfig.BUFFER_MEMORY_CONFIG, bufferMemory);
-
- // 중복 방지 설정
- configProps.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true);
- configProps.put(ProducerConfig.MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION, 5);
-
- // 압축 설정
- configProps.put(ProducerConfig.COMPRESSION_TYPE_CONFIG, "snappy");
-
- log.info("Kafka Producer 설정 완료 - bootstrapServers: {}, clientId: {}",
- bootstrapServers, clientId);
-
- return new DefaultKafkaProducerFactory<>(configProps);
+ @PostConstruct
+ public void init() {
+ log.info("Initializing Azure EventHub configuration with hub name: {}", eventHubName);
}
/**
- * Kafka Template
+ * EventHub Producer Client 생성
*/
- @Bean
- public KafkaTemplate kafkaTemplate() {
- KafkaTemplate template = new KafkaTemplate<>(producerFactory());
-
- // 메시지 전송 결과 로깅
- template.setProducerListener(new org.springframework.kafka.support.LoggingProducerListener<>());
-
- log.info("Kafka Template 설정 완료");
- return template;
+ @Bean(name = "eventProducer")
+ public EventHubProducerClient eventProducer() {
+ log.info("Creating EventHub producer for hub: {}", eventHubName);
+ return new EventHubClientBuilder()
+ .connectionString(connectionString, eventHubName)
+ .buildProducerClient();
}
}
\ No newline at end of file
diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/event/constant/EventHubConstants.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/event/constant/EventHubConstants.java
new file mode 100644
index 0000000..e1c2dab
--- /dev/null
+++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/event/constant/EventHubConstants.java
@@ -0,0 +1,30 @@
+package com.unicorn.hgzero.meeting.infra.event.constant;
+
+/**
+ * EventHub 이벤트 관련 상수 정의
+ * Azure EventHub에서 사용하는 이벤트 타입과 토픽 정의
+ */
+public class EventHubConstants {
+
+ // 이벤트 타입 상수
+ public static final String EVENT_TYPE_MEETING_STARTED = "MEETING_STARTED";
+ public static final String EVENT_TYPE_MEETING_ENDED = "MEETING_ENDED";
+ public static final String EVENT_TYPE_TODO_ASSIGNED = "TODO_ASSIGNED";
+ public static final String EVENT_TYPE_TODO_COMPLETED = "TODO_COMPLETED";
+ public static final String EVENT_TYPE_MINUTES_FINALIZED = "MINUTES_FINALIZED";
+ public static final String EVENT_TYPE_NOTIFICATION_REQUEST = "NOTIFICATION_REQUEST";
+
+ // 토픽 이름 상수
+ public static final String TOPIC_MEETING = "meeting";
+ public static final String TOPIC_TODO = "todo";
+ public static final String TOPIC_MINUTES = "minutes";
+ public static final String TOPIC_NOTIFICATION = "notification";
+
+ // 속성 키 상수
+ public static final String PROPERTY_TYPE = "type";
+ public static final String PROPERTY_TOPIC = "topic";
+
+ private EventHubConstants() {
+ // 유틸리티 클래스는 인스턴스화 방지
+ }
+}
diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/event/publisher/EventHubPublisher.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/event/publisher/EventHubPublisher.java
index c837d20..3c94636 100644
--- a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/event/publisher/EventHubPublisher.java
+++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/event/publisher/EventHubPublisher.java
@@ -1,102 +1,69 @@
package com.unicorn.hgzero.meeting.infra.event.publisher;
+import com.azure.messaging.eventhubs.EventData;
+import com.azure.messaging.eventhubs.EventDataBatch;
+import com.azure.messaging.eventhubs.EventHubProducerClient;
+import com.azure.messaging.eventhubs.models.CreateBatchOptions;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.unicorn.hgzero.meeting.infra.event.constant.EventHubConstants;
import com.unicorn.hgzero.meeting.infra.event.dto.MeetingStartedEvent;
import com.unicorn.hgzero.meeting.infra.event.dto.MeetingEndedEvent;
import com.unicorn.hgzero.meeting.infra.event.dto.TodoAssignedEvent;
import com.unicorn.hgzero.meeting.infra.event.dto.NotificationRequestEvent;
import java.time.LocalDate;
import java.time.LocalDateTime;
-import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
/**
- * Event Hub 이벤트 발행 구현체
- * Kafka를 통한 이벤트 발행
+ * Azure EventHub 이벤트 발행 구현체
+ * Azure EventHub를 통한 이벤트 발행
*/
@Component
-@RequiredArgsConstructor
@Slf4j
public class EventHubPublisher implements EventPublisher {
- private final KafkaTemplate kafkaTemplate;
+ private final EventHubProducerClient eventProducer;
private final ObjectMapper objectMapper;
- @Value("${app.event.topic.meeting-started:meeting-started}")
- private String meetingStartedTopic;
-
- @Value("${app.event.topic.meeting-ended:meeting-ended}")
- private String meetingEndedTopic;
-
- @Value("${app.event.topic.todo-assigned:todo-assigned}")
- private String todoAssignedTopic;
-
- @Value("${app.event.topic.notification-request:notification-request}")
- private String notificationRequestTopic;
-
- @Value("${app.event.topic.todo-completed:todo-completed}")
- private String todoCompletedTopic;
-
- @Value("${app.event.topic.minutes-finalized:minutes-finalized}")
- private String minutesFinalizedTopic;
+ public EventHubPublisher(
+ @Qualifier("eventProducer") EventHubProducerClient eventProducer,
+ ObjectMapper objectMapper) {
+ this.eventProducer = eventProducer;
+ this.objectMapper = objectMapper;
+ }
@Override
public void publishMeetingStarted(MeetingStartedEvent event) {
- try {
- String payload = objectMapper.writeValueAsString(event);
- kafkaTemplate.send(meetingStartedTopic, event.getMeetingId(), payload);
- log.info("회의 시작 이벤트 발행 완료 - meetingId: {}", event.getMeetingId());
- } catch (Exception e) {
- log.error("회의 시작 이벤트 발행 실패 - meetingId: {}", event.getMeetingId(), e);
- throw new RuntimeException("회의 시작 이벤트 발행 실패", e);
- }
+ publishEvent(event, event.getMeetingId(),
+ EventHubConstants.TOPIC_MEETING,
+ EventHubConstants.EVENT_TYPE_MEETING_STARTED);
}
@Override
public void publishMeetingEnded(MeetingEndedEvent event) {
- try {
- String payload = objectMapper.writeValueAsString(event);
- kafkaTemplate.send(meetingEndedTopic, event.getMeetingId(), payload);
- log.info("회의 종료 이벤트 발행 완료 - meetingId: {}", event.getMeetingId());
- } catch (Exception e) {
- log.error("회의 종료 이벤트 발행 실패 - meetingId: {}", event.getMeetingId(), e);
- throw new RuntimeException("회의 종료 이벤트 발행 실패", e);
- }
+ publishEvent(event, event.getMeetingId(),
+ EventHubConstants.TOPIC_MEETING,
+ EventHubConstants.EVENT_TYPE_MEETING_ENDED);
}
@Override
public void publishTodoAssigned(TodoAssignedEvent event) {
- try {
- String payload = objectMapper.writeValueAsString(event);
- kafkaTemplate.send(todoAssignedTopic, event.getTodoId(), payload);
- log.info("Todo 할당 이벤트 발행 완료 - todoId: {}", event.getTodoId());
- } catch (Exception e) {
- log.error("Todo 할당 이벤트 발행 실패 - todoId: {}", event.getTodoId(), e);
- throw new RuntimeException("Todo 할당 이벤트 발행 실패", e);
- }
+ publishEvent(event, event.getTodoId(),
+ EventHubConstants.TOPIC_TODO,
+ EventHubConstants.EVENT_TYPE_TODO_ASSIGNED);
}
@Override
public void publishNotificationRequest(NotificationRequestEvent event) {
- try {
- String payload = objectMapper.writeValueAsString(event);
- kafkaTemplate.send(notificationRequestTopic, event.getRecipientId(), payload);
- log.info("알림 요청 이벤트 발행 완료 - type: {}, recipientId: {}",
- event.getNotificationType(), event.getRecipientId());
- } catch (Exception e) {
- log.error("알림 요청 이벤트 발행 실패 - type: {}, recipientId: {}",
- event.getNotificationType(), event.getRecipientId(), e);
- throw new RuntimeException("알림 요청 이벤트 발행 실패", e);
- }
+ publishEvent(event, event.getRecipientId(),
+ EventHubConstants.TOPIC_NOTIFICATION,
+ EventHubConstants.EVENT_TYPE_NOTIFICATION_REQUEST);
}
- // 편의 메서드 구현
-
@Override
- public void publishTodoAssigned(String todoId, String title, String assigneeId, String assigneeName,
+ public void publishTodoAssigned(String todoId, String title, String assigneeId, String assigneeName,
String assignedBy, String assignedByName, LocalDate dueDate) {
TodoAssignedEvent event = TodoAssignedEvent.builder()
.todoId(todoId)
@@ -108,60 +75,85 @@ public class EventHubPublisher implements EventPublisher {
.dueDate(dueDate)
.assignedAt(LocalDateTime.now())
.build();
-
+
publishTodoAssigned(event);
}
@Override
public void publishTodoCompleted(String todoId, String title, String assigneeId, String assigneeName,
- String completedBy, String completedByName) {
- try {
- // Todo 완료 이벤트는 NotificationRequestEvent로 발행
- NotificationRequestEvent event = NotificationRequestEvent.builder()
- .notificationType("TODO_COMPLETED")
- .recipientId(assigneeId)
- .recipientName(assigneeName)
- .title("Todo 완료")
- .message(String.format("Todo '%s'가 완료되었습니다", title))
- .relatedEntityId(todoId)
- .relatedEntityType("TODO")
- .requestedBy(completedBy)
- .requestedByName(completedByName)
- .eventTime(LocalDateTime.now())
- .build();
+ String completedBy, String completedByName) {
+ NotificationRequestEvent event = NotificationRequestEvent.builder()
+ .notificationType("TODO_COMPLETED")
+ .recipientId(assigneeId)
+ .recipientName(assigneeName)
+ .title("Todo 완료")
+ .message(String.format("Todo '%s'가 완료되었습니다", title))
+ .relatedEntityId(todoId)
+ .relatedEntityType("TODO")
+ .requestedBy(completedBy)
+ .requestedByName(completedByName)
+ .eventTime(LocalDateTime.now())
+ .build();
- String payload = objectMapper.writeValueAsString(event);
- kafkaTemplate.send(todoCompletedTopic, todoId, payload);
- log.info("Todo 완료 이벤트 발행 완료 - todoId: {}", todoId);
- } catch (Exception e) {
- log.error("Todo 완료 이벤트 발행 실패 - todoId: {}", todoId, e);
- throw new RuntimeException("Todo 완료 이벤트 발행 실패", e);
- }
+ publishEvent(event, todoId,
+ EventHubConstants.TOPIC_TODO,
+ EventHubConstants.EVENT_TYPE_TODO_COMPLETED);
}
@Override
public void publishMinutesFinalized(String minutesId, String title, String finalizedBy, String finalizedByName) {
- try {
- // 회의록 확정 이벤트는 NotificationRequestEvent로 발행
- NotificationRequestEvent event = NotificationRequestEvent.builder()
- .notificationType("MINUTES_FINALIZED")
- .recipientId(finalizedBy)
- .recipientName(finalizedByName)
- .title("회의록 확정")
- .message(String.format("회의록 '%s'가 확정되었습니다", title))
- .relatedEntityId(minutesId)
- .relatedEntityType("MINUTES")
- .requestedBy(finalizedBy)
- .requestedByName(finalizedByName)
- .eventTime(LocalDateTime.now())
- .build();
+ NotificationRequestEvent event = NotificationRequestEvent.builder()
+ .notificationType("MINUTES_FINALIZED")
+ .recipientId(finalizedBy)
+ .recipientName(finalizedByName)
+ .title("회의록 확정")
+ .message(String.format("회의록 '%s'가 확정되었습니다", title))
+ .relatedEntityId(minutesId)
+ .relatedEntityType("MINUTES")
+ .requestedBy(finalizedBy)
+ .requestedByName(finalizedByName)
+ .eventTime(LocalDateTime.now())
+ .build();
+
+ publishEvent(event, minutesId,
+ EventHubConstants.TOPIC_MINUTES,
+ EventHubConstants.EVENT_TYPE_MINUTES_FINALIZED);
+ }
+
+ /**
+ * 이벤트 발행 공통 메서드
+ *
+ * @param event 발행할 이벤트 객체
+ * @param partitionKey 파티션 키 (이벤트 ID 등)
+ * @param topic 토픽 이름
+ * @param eventType 이벤트 타입
+ * @param 이벤트 타입
+ */
+ private void publishEvent(T event, String partitionKey, String topic, String eventType) {
+ try {
+ CreateBatchOptions options = new CreateBatchOptions()
+ .setPartitionKey(partitionKey);
+
+ EventDataBatch batch = eventProducer.createBatch(options);
+ String eventJson = objectMapper.writeValueAsString(event);
+ EventData eventData = new EventData(eventJson);
+
+ // 이벤트 속성 설정
+ eventData.getProperties().put(EventHubConstants.PROPERTY_TYPE, eventType);
+ eventData.getProperties().put(EventHubConstants.PROPERTY_TOPIC, topic);
+
+ if (!batch.tryAdd(eventData)) {
+ throw new RuntimeException("이벤트 크기가 너무 큽니다");
+ }
+
+ eventProducer.send(batch);
+ log.info("이벤트 발행 완료: topic={}, type={}, partitionKey={}",
+ topic, eventType, partitionKey);
- String payload = objectMapper.writeValueAsString(event);
- kafkaTemplate.send(minutesFinalizedTopic, minutesId, payload);
- log.info("회의록 확정 이벤트 발행 완료 - minutesId: {}", minutesId);
} catch (Exception e) {
- log.error("회의록 확정 이벤트 발행 실패 - minutesId: {}", minutesId, e);
- throw new RuntimeException("회의록 확정 이벤트 발행 실패", e);
+ log.error("이벤트 발행 실패: topic={}, type={}, partitionKey={}, error={}",
+ topic, eventType, partitionKey, e.getMessage(), e);
+ throw new RuntimeException("이벤트 발행 중 오류가 발생했습니다", e);
}
}
-}
\ No newline at end of file
+}
diff --git a/meeting/src/main/resources/application.yml b/meeting/src/main/resources/application.yml
index 965323f..4c08da4 100644
--- a/meeting/src/main/resources/application.yml
+++ b/meeting/src/main/resources/application.yml
@@ -125,5 +125,11 @@ api:
# Azure EventHub Configuration
eventhub:
connection-string: ${EVENTHUB_CONNECTION_STRING:}
- name: ${EVENTHUB_NAME:hgzero-eventhub-name}
+ name: ${EVENTHUB_NAME:hgzero-events}
consumer-group: ${EVENTHUB_CONSUMER_GROUP:$Default}
+
+# Azure Storage Configuration (for EventHub checkpoints)
+azure:
+ storage:
+ connection-string: ${AZURE_STORAGE_CONNECTION_STRING:}
+ container: ${AZURE_STORAGE_CONTAINER:hgzero-checkpoints}