From 4f80189d57baf889d93b5838409e080eb8fdd3d4 Mon Sep 17 00:00:00 2001 From: djeon Date: Fri, 24 Oct 2025 15:44:55 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20add=20=ED=9A=8C=EC=9D=98=EC=8B=9C?= =?UTF-8?q?=EC=9E=91=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- meeting/logs/meeting-service.log | 423 ++++++++++++++++++ .../hgzero/meeting/biz/domain/Session.java | 70 +++ .../meeting/biz/service/MeetingService.java | 135 +++++- .../in/meeting/StartMeetingUseCase.java | 6 +- .../biz/usecase/out/SessionReader.java | 32 ++ .../biz/usecase/out/SessionWriter.java | 19 + .../infra/controller/MeetingController.java | 12 +- .../infra/dto/response/SessionResponse.java | 24 + .../infra/event/dto/MeetingStartedEvent.java | 5 + .../meeting/infra/gateway/SessionGateway.java | 64 +++ .../infra/gateway/entity/SessionEntity.java | 75 ++++ .../repository/SessionJpaRepository.java | 31 ++ 12 files changed, 870 insertions(+), 26 deletions(-) create mode 100644 meeting/src/main/java/com/unicorn/hgzero/meeting/biz/domain/Session.java create mode 100644 meeting/src/main/java/com/unicorn/hgzero/meeting/biz/usecase/out/SessionReader.java create mode 100644 meeting/src/main/java/com/unicorn/hgzero/meeting/biz/usecase/out/SessionWriter.java create mode 100644 meeting/src/main/java/com/unicorn/hgzero/meeting/infra/gateway/SessionGateway.java create mode 100644 meeting/src/main/java/com/unicorn/hgzero/meeting/infra/gateway/entity/SessionEntity.java create mode 100644 meeting/src/main/java/com/unicorn/hgzero/meeting/infra/gateway/repository/SessionJpaRepository.java diff --git a/meeting/logs/meeting-service.log b/meeting/logs/meeting-service.log index 14e6471..ca4f701 100644 --- a/meeting/logs/meeting-service.log +++ b/meeting/logs/meeting-service.log @@ -9954,3 +9954,426 @@ Caused by: io.lettuce.core.RedisReadOnlyException: READONLY You can't write agai (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 2025-10-24 15:16:51 [http-nio-8082-exec-4] INFO c.u.h.m.i.c.MeetingController - 회의 예약 완료 - userId: user-005, meetingId: 4b340eed-31d9-4b7b-a95f-65180d9f663e 2025-10-24 15:16:51 [http-nio-8082-exec-4] INFO c.u.hgzero.common.aop.LoggingAspect - [Controller] com.unicorn.hgzero.meeting.infra.controller.MeetingController.createMeeting 완료 - 실행시간: 1831ms +2025-10-24 15:19:59 [SpringApplicationShutdownHook] INFO c.a.m.e.i.EventHubConnectionProcessor - {"az.sdk.message":"Upstream connection publisher was completed. Terminating processor.","entityPath":"hgzero-eventhub-name"} +2025-10-24 15:19:59 [SpringApplicationShutdownHook] INFO c.a.c.a.i.ReactorConnection - {"az.sdk.message":"Disposing of ReactorConnection.","connectionId":"MF_281659_1761286483128","isTransient":false,"isInitiatedByClient":true,"shutdownMessage":"Disposed by client."} +2025-10-24 15:19:59 [SpringApplicationShutdownHook] INFO c.a.m.e.i.EventHubConnectionProcessor - {"az.sdk.message":"Channel is disposed.","entityPath":"hgzero-eventhub-name"} +2025-10-24 15:19:59 [SpringApplicationShutdownHook] INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default' +2025-10-24 15:19:59 [SpringApplicationShutdownHook] TRACE o.h.type.spi.TypeConfiguration$Scope - Handling #sessionFactoryClosed from [org.hibernate.internal.SessionFactoryImpl@c42ee90] for TypeConfiguration +2025-10-24 15:19:59 [SpringApplicationShutdownHook] DEBUG o.h.type.spi.TypeConfiguration$Scope - Un-scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration$Scope@626c0d] from SessionFactory [org.hibernate.internal.SessionFactoryImpl@c42ee90] +2025-10-24 15:19:59 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated... +2025-10-24 15:19:59 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed. +2025-10-24 15:37:09 [main] INFO c.u.h.meeting.MeetingApplication - Starting MeetingApplication using Java 21.0.8 with PID 96456 (/Users/daewoong/home/workspace/HGZero/meeting/build/classes/java/main started by daewoong in /Users/daewoong/home/workspace/HGZero/meeting) +2025-10-24 15:37:09 [main] DEBUG c.u.h.meeting.MeetingApplication - Running with Spring Boot v3.3.5, Spring v6.1.14 +2025-10-24 15:37:09 [main] INFO c.u.h.meeting.MeetingApplication - The following 1 profile is active: "dev" +2025-10-24 15:37:09 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode +2025-10-24 15:37:09 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode. +2025-10-24 15:37:09 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 59 ms. Found 6 JPA repository interfaces. +2025-10-24 15:37:10 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode +2025-10-24 15:37:10 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode. +2025-10-24 15:37:10 [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 15:37:10 [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 15:37:10 [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 15:37:10 [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.SessionJpaRepository; 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 15:37:10 [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 15:37:10 [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 15:37:10 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 12 ms. Found 0 Redis repository interfaces. +2025-10-24 15:37:10 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8082 (http) +2025-10-24 15:37:10 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-10-24 15:37:10 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.31] +2025-10-24 15:37:10 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-10-24 15:37:10 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 999 ms +2025-10-24 15:37:10 [main] INFO o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default] +2025-10-24 15:37:10 [main] INFO org.hibernate.Version - HHH000412: Hibernate ORM core version 6.5.3.Final +2025-10-24 15:37:10 [main] INFO o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration boolean -> org.hibernate.type.BasicTypeReference@7509226c +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration boolean -> org.hibernate.type.BasicTypeReference@7509226c +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Boolean -> org.hibernate.type.BasicTypeReference@7509226c +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration numeric_boolean -> org.hibernate.type.BasicTypeReference@4c9cce17 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.NumericBooleanConverter -> org.hibernate.type.BasicTypeReference@4c9cce17 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration true_false -> org.hibernate.type.BasicTypeReference@73316a0a +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.TrueFalseConverter -> org.hibernate.type.BasicTypeReference@73316a0a +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration yes_no -> org.hibernate.type.BasicTypeReference@63a7af06 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.YesNoConverter -> org.hibernate.type.BasicTypeReference@63a7af06 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration byte -> org.hibernate.type.BasicTypeReference@5f01fb5c +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration byte -> org.hibernate.type.BasicTypeReference@5f01fb5c +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Byte -> org.hibernate.type.BasicTypeReference@5f01fb5c +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration binary -> org.hibernate.type.BasicTypeReference@75c77add +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration byte[] -> org.hibernate.type.BasicTypeReference@75c77add +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration [B -> org.hibernate.type.BasicTypeReference@75c77add +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration binary_wrapper -> org.hibernate.type.BasicTypeReference@d5e3f55 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration wrapper-binary -> org.hibernate.type.BasicTypeReference@d5e3f55 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration image -> org.hibernate.type.BasicTypeReference@53df7e67 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration blob -> org.hibernate.type.BasicTypeReference@3d4b45b +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Blob -> org.hibernate.type.BasicTypeReference@3d4b45b +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_blob -> org.hibernate.type.BasicTypeReference@4d0b276e +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_blob_wrapper -> org.hibernate.type.BasicTypeReference@31531d0d +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration short -> org.hibernate.type.BasicTypeReference@19d76106 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration short -> org.hibernate.type.BasicTypeReference@19d76106 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Short -> org.hibernate.type.BasicTypeReference@19d76106 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration integer -> org.hibernate.type.BasicTypeReference@3f87780b +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration int -> org.hibernate.type.BasicTypeReference@3f87780b +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Integer -> org.hibernate.type.BasicTypeReference@3f87780b +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration long -> org.hibernate.type.BasicTypeReference@2ba318c2 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration long -> org.hibernate.type.BasicTypeReference@2ba318c2 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Long -> org.hibernate.type.BasicTypeReference@2ba318c2 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration float -> org.hibernate.type.BasicTypeReference@231d3ce +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration float -> org.hibernate.type.BasicTypeReference@231d3ce +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Float -> org.hibernate.type.BasicTypeReference@231d3ce +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration double -> org.hibernate.type.BasicTypeReference@204c5ddf +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration double -> org.hibernate.type.BasicTypeReference@204c5ddf +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Double -> org.hibernate.type.BasicTypeReference@204c5ddf +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration big_integer -> org.hibernate.type.BasicTypeReference@240f2efd +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.math.BigInteger -> org.hibernate.type.BasicTypeReference@240f2efd +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration big_decimal -> org.hibernate.type.BasicTypeReference@175957b6 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.math.BigDecimal -> org.hibernate.type.BasicTypeReference@175957b6 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration character -> org.hibernate.type.BasicTypeReference@1b7a4930 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration char -> org.hibernate.type.BasicTypeReference@1b7a4930 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Character -> org.hibernate.type.BasicTypeReference@1b7a4930 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration character_nchar -> org.hibernate.type.BasicTypeReference@591a4d25 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration string -> org.hibernate.type.BasicTypeReference@4bfe83d +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.String -> org.hibernate.type.BasicTypeReference@4bfe83d +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration nstring -> org.hibernate.type.BasicTypeReference@5906ebfb +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration characters -> org.hibernate.type.BasicTypeReference@10fc1a22 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration char[] -> org.hibernate.type.BasicTypeReference@10fc1a22 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration [C -> org.hibernate.type.BasicTypeReference@10fc1a22 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration wrapper-characters -> org.hibernate.type.BasicTypeReference@1b841e7d +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration text -> org.hibernate.type.BasicTypeReference@6081f330 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ntext -> org.hibernate.type.BasicTypeReference@eb695e8 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration clob -> org.hibernate.type.BasicTypeReference@7eebb316 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Clob -> org.hibernate.type.BasicTypeReference@7eebb316 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration nclob -> org.hibernate.type.BasicTypeReference@45273d40 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.NClob -> org.hibernate.type.BasicTypeReference@45273d40 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_clob -> org.hibernate.type.BasicTypeReference@2a504ea7 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_clob_char_array -> org.hibernate.type.BasicTypeReference@10f397d0 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_clob_character_array -> org.hibernate.type.BasicTypeReference@33a3e5db +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_nclob -> org.hibernate.type.BasicTypeReference@4f9213d2 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_nclob_character_array -> org.hibernate.type.BasicTypeReference@679f59f1 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_nclob_char_array -> org.hibernate.type.BasicTypeReference@6b5e1fc5 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration Duration -> org.hibernate.type.BasicTypeReference@47ffa248 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.Duration -> org.hibernate.type.BasicTypeReference@47ffa248 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration LocalDateTime -> org.hibernate.type.BasicTypeReference@18ac25e6 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.LocalDateTime -> org.hibernate.type.BasicTypeReference@18ac25e6 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration LocalDate -> org.hibernate.type.BasicTypeReference@5e1a7d3 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.LocalDate -> org.hibernate.type.BasicTypeReference@5e1a7d3 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration LocalTime -> org.hibernate.type.BasicTypeReference@1eda309d +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.LocalTime -> org.hibernate.type.BasicTypeReference@1eda309d +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTime -> org.hibernate.type.BasicTypeReference@248d2cec +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetDateTime -> org.hibernate.type.BasicTypeReference@248d2cec +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTimeWithTimezone -> org.hibernate.type.BasicTypeReference@5d77be8e +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTimeWithoutTimezone -> org.hibernate.type.BasicTypeReference@55a055cc +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTime -> org.hibernate.type.BasicTypeReference@1ab1d93d +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetTime -> org.hibernate.type.BasicTypeReference@1ab1d93d +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTimeUtc -> org.hibernate.type.BasicTypeReference@57167ccb +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTimeWithTimezone -> org.hibernate.type.BasicTypeReference@37753b69 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTimeWithoutTimezone -> org.hibernate.type.BasicTypeReference@602c167e +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTime -> org.hibernate.type.BasicTypeReference@74c04377 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.ZonedDateTime -> org.hibernate.type.BasicTypeReference@74c04377 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTimeWithTimezone -> org.hibernate.type.BasicTypeReference@10d49900 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTimeWithoutTimezone -> org.hibernate.type.BasicTypeReference@e645600 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration date -> org.hibernate.type.BasicTypeReference@e7b3e54 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Date -> org.hibernate.type.BasicTypeReference@e7b3e54 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration time -> org.hibernate.type.BasicTypeReference@78d61f17 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Time -> org.hibernate.type.BasicTypeReference@78d61f17 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration timestamp -> org.hibernate.type.BasicTypeReference@4cfe9594 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Timestamp -> org.hibernate.type.BasicTypeReference@4cfe9594 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Date -> org.hibernate.type.BasicTypeReference@4cfe9594 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration calendar -> org.hibernate.type.BasicTypeReference@60861e5d +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Calendar -> org.hibernate.type.BasicTypeReference@60861e5d +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.GregorianCalendar -> org.hibernate.type.BasicTypeReference@60861e5d +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration calendar_date -> org.hibernate.type.BasicTypeReference@37d81587 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration calendar_time -> org.hibernate.type.BasicTypeReference@7f3e9acc +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration instant -> org.hibernate.type.BasicTypeReference@47d4e28a +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.Instant -> org.hibernate.type.BasicTypeReference@47d4e28a +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration uuid -> org.hibernate.type.BasicTypeReference@177068db +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.UUID -> org.hibernate.type.BasicTypeReference@177068db +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration pg-uuid -> org.hibernate.type.BasicTypeReference@177068db +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration uuid-binary -> org.hibernate.type.BasicTypeReference@60f3239f +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration uuid-char -> org.hibernate.type.BasicTypeReference@6b103db7 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration class -> org.hibernate.type.BasicTypeReference@b3042ed +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Class -> org.hibernate.type.BasicTypeReference@b3042ed +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration currency -> org.hibernate.type.BasicTypeReference@1f12d5e0 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration Currency -> org.hibernate.type.BasicTypeReference@1f12d5e0 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Currency -> org.hibernate.type.BasicTypeReference@1f12d5e0 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration locale -> org.hibernate.type.BasicTypeReference@6604f246 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Locale -> org.hibernate.type.BasicTypeReference@6604f246 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration serializable -> org.hibernate.type.BasicTypeReference@c1386b4 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.io.Serializable -> org.hibernate.type.BasicTypeReference@c1386b4 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration timezone -> org.hibernate.type.BasicTypeReference@53d9af1 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.TimeZone -> org.hibernate.type.BasicTypeReference@53d9af1 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZoneOffset -> org.hibernate.type.BasicTypeReference@c89e263 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.ZoneOffset -> org.hibernate.type.BasicTypeReference@c89e263 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration url -> org.hibernate.type.BasicTypeReference@4d5ea776 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.net.URL -> org.hibernate.type.BasicTypeReference@4d5ea776 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration vector -> org.hibernate.type.BasicTypeReference@5d68be4f +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration row_version -> org.hibernate.type.BasicTypeReference@34eb5d01 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration object -> org.hibernate.type.JavaObjectType@5521407f +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Object -> org.hibernate.type.JavaObjectType@5521407f +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration null -> org.hibernate.type.NullType@7305cfb1 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_date -> org.hibernate.type.BasicTypeReference@582c1f8d +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_time -> org.hibernate.type.BasicTypeReference@443253a6 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_timestamp -> org.hibernate.type.BasicTypeReference@191774d6 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_calendar -> org.hibernate.type.BasicTypeReference@21ffc00e +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_calendar_date -> org.hibernate.type.BasicTypeReference@134955bb +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_calendar_time -> org.hibernate.type.BasicTypeReference@45b08b17 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_binary -> org.hibernate.type.BasicTypeReference@6723e6b3 +2025-10-24 15:37:10 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_serializable -> org.hibernate.type.BasicTypeReference@3883b5e9 +2025-10-24 15:37:10 [main] INFO o.s.o.j.p.SpringPersistenceUnitInfo - No LoadTimeWeaver setup: ignoring JPA class transformer +2025-10-24 15:37:10 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... +2025-10-24 15:37:11 [main] INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@162e29a1 +2025-10-24 15:37:11 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed. +2025-10-24 15:37:11 [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 15:37:11 [main] DEBUG o.h.t.d.sql.spi.DdlTypeRegistry - addDescriptor(2003, org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl@d641499) replaced previous registration(org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl@634d3439) +2025-10-24 15:37:11 [main] DEBUG o.h.t.d.sql.spi.DdlTypeRegistry - addDescriptor(6, org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType@44e0c3d) replaced previous registration(org.hibernate.type.descriptor.sql.internal.DdlTypeImpl@71891d6b) +2025-10-24 15:37:11 [main] DEBUG o.h.t.d.jdbc.spi.JdbcTypeRegistry - addDescriptor(2004, BlobTypeDescriptor(BLOB_BINDING)) replaced previous registration(BlobTypeDescriptor(DEFAULT)) +2025-10-24 15:37:11 [main] DEBUG o.h.t.d.jdbc.spi.JdbcTypeRegistry - addDescriptor(2005, ClobTypeDescriptor(CLOB_BINDING)) replaced previous registration(ClobTypeDescriptor(DEFAULT)) +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration JAVA_OBJECT -> org.hibernate.type.JavaObjectType@63896cf7 +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Object -> org.hibernate.type.JavaObjectType@63896cf7 +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Type registration key [java.lang.Object] overrode previous entry : `org.hibernate.type.JavaObjectType@5521407f` +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.DurationType -> basicType@1(java.time.Duration,3015) +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration Duration -> basicType@1(java.time.Duration,3015) +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.Duration -> basicType@1(java.time.Duration,3015) +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.OffsetDateTimeType -> basicType@2(java.time.OffsetDateTime,3003) +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTime -> basicType@2(java.time.OffsetDateTime,3003) +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetDateTime -> basicType@2(java.time.OffsetDateTime,3003) +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.ZonedDateTimeType -> basicType@3(java.time.ZonedDateTime,3003) +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTime -> basicType@3(java.time.ZonedDateTime,3003) +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.ZonedDateTime -> basicType@3(java.time.ZonedDateTime,3003) +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.OffsetTimeType -> basicType@4(java.time.OffsetTime,3007) +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTime -> basicType@4(java.time.OffsetTime,3007) +2025-10-24 15:37:11 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetTime -> basicType@4(java.time.OffsetTime,3007) +2025-10-24 15:37:11 [main] DEBUG o.h.type.spi.TypeConfiguration$Scope - Scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration@6fe337a5] to MetadataBuildingContext [org.hibernate.boot.internal.MetadataBuildingContextRootImpl@7d60bd5a] +2025-10-24 15:37:11 [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 15:37:11 [main] DEBUG o.h.type.spi.TypeConfiguration$Scope - Scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration@6fe337a5] to SessionFactoryImplementor [org.hibernate.internal.SessionFactoryImpl@188500e9] +2025-10-24 15:37:12 [main] DEBUG org.hibernate.SQL - + alter table if exists meetings + alter column description set data type TEXT +2025-10-24 15:37:12 [main] DEBUG org.hibernate.SQL - + alter table if exists meetings + alter column participants set data type TEXT +2025-10-24 15:37:12 [main] DEBUG org.hibernate.SQL - + alter table if exists minutes_sections + alter column content set data type TEXT +2025-10-24 15:37:12 [main] DEBUG org.hibernate.SQL - + create table sessions ( + session_id varchar(50) not null, + created_at timestamp(6) not null, + updated_at timestamp(6) not null, + ended_at timestamp(6), + meeting_id varchar(50) not null, + minutes_id varchar(50), + started_at timestamp(6) not null, + started_by varchar(50) not null, + status varchar(20) not null, + primary key (session_id) + ) +2025-10-24 15:37:12 [main] DEBUG org.hibernate.SQL - + alter table if exists templates + alter column description set data type TEXT +2025-10-24 15:37:12 [main] DEBUG org.hibernate.SQL - + alter table if exists templates + alter column sections set data type TEXT +2025-10-24 15:37:12 [main] DEBUG org.hibernate.SQL - + alter table if exists todos + alter column description set data type TEXT +2025-10-24 15:37:12 [main] TRACE o.h.type.spi.TypeConfiguration$Scope - Handling #sessionFactoryCreated from [org.hibernate.internal.SessionFactoryImpl@188500e9] for TypeConfiguration +2025-10-24 15:37:12 [main] INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default' +2025-10-24 15:37:12 [main] INFO o.s.d.j.r.query.QueryEnhancerFactory - Hibernate is in classpath; If applicable, HQL parser will be used. +2025-10-24 15:37:13 [main] INFO c.u.h.m.infra.cache.CacheConfig - Redis 연결 설정 - host: 20.249.177.114, port: 6379, database: 1, password: **** +2025-10-24 15:37:13 [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 15:37:13 [main] INFO c.u.h.m.infra.cache.CacheConfig - Redis 템플릿 설정 완료 +2025-10-24 15:37:13 [main] INFO c.u.h.m.infra.cache.CacheConfig - ObjectMapper 설정 완료 +2025-10-24 15:37:13 [main] INFO c.u.h.m.infra.config.EventHubConfig - Initializing Azure EventHub configuration with hub name: hgzero-eventhub-name +2025-10-24 15:37:13 [main] INFO c.u.h.m.infra.config.EventHubConfig - Creating EventHub producer for hub: hgzero-eventhub-name +2025-10-24 15:37:13 [main] INFO c.a.m.e.EventHubClientBuilder - {"az.sdk.message":"Emitting a single connection.","connectionId":"MF_e4b94c_1761287833470"} +2025-10-24 15:37:13 [main] INFO c.a.m.e.i.EventHubConnectionProcessor - {"az.sdk.message":"Setting next AMQP channel.","entityPath":"hgzero-eventhub-name"} +2025-10-24 15:37:13 [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 15:37:13 [main] WARN o.s.b.a.s.s.UserDetailsServiceAutoConfiguration - + +Using generated security password: fc24964d-2039-440d-8e58-2eb38fcd3eb8 + +This generated password is for development use only. Your security configuration must be updated before running your application in production. + +2025-10-24 15:37:13 [main] INFO o.s.s.c.a.a.c.InitializeUserDetailsBeanManagerConfigurer$InitializeUserDetailsManagerConfigurer - Global AuthenticationManager configured with UserDetailsService bean with name inMemoryUserDetailsManager +2025-10-24 15:37:13 [main] INFO c.u.h.m.infra.config.WebSocketConfig - WebSocket 핸들러 등록 완료 - endpoint: /ws/minutes/{minutesId} +2025-10-24 15:37:13 [main] INFO o.s.b.a.e.web.EndpointLinksResolver - Exposing 3 endpoints beneath base path '/actuator' +2025-10-24 15:37:13 [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 15:37:14 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8082 (http) with context path '/' +2025-10-24 15:37:14 [main] INFO c.u.h.meeting.MeetingApplication - Started MeetingApplication in 4.937 seconds (process running for 5.094) +2025-10-24 15:38:21 [http-nio-8082-exec-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet' +2025-10-24 15:38:21 [http-nio-8082-exec-1] INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet' +2025-10-24 15:38:21 [http-nio-8082-exec-1] INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 3 ms +2025-10-24 15:38:21 [http-nio-8082-exec-1] DEBUG o.s.security.web.FilterChainProxy - Securing POST /api/meetings/4b340eed-31d9-4b7b-a95f-65180d9f663e/start +2025-10-24 15:38:21 [http-nio-8082-exec-1] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext +2025-10-24 15:38:21 [http-nio-8082-exec-1] DEBUG o.s.security.web.FilterChainProxy - Secured POST /api/meetings/4b340eed-31d9-4b7b-a95f-65180d9f663e/start +2025-10-24 15:38:21 [http-nio-8082-exec-1] WARN o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolved [org.springframework.web.bind.MissingRequestHeaderException: Required request header 'X-User-Id' for method parameter type String is not present] +2025-10-24 15:38:21 [http-nio-8082-exec-1] DEBUG o.s.security.web.FilterChainProxy - Securing POST /error +2025-10-24 15:38:21 [http-nio-8082-exec-1] DEBUG o.s.security.web.FilterChainProxy - Secured POST /error +2025-10-24 15:38:22 [http-nio-8082-exec-1] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext +2025-10-24 15:39:50 [http-nio-8082-exec-4] DEBUG o.s.security.web.FilterChainProxy - Securing POST /api/meetings/4b340eed-31d9-4b7b-a95f-65180d9f663e/start +2025-10-24 15:39:50 [http-nio-8082-exec-4] DEBUG c.u.h.m.i.c.j.JwtAuthenticationFilter - 헤더 기반 인증된 사용자: dohyunjung (user-005) +2025-10-24 15:39:50 [http-nio-8082-exec-4] DEBUG o.s.security.web.FilterChainProxy - Secured POST /api/meetings/4b340eed-31d9-4b7b-a95f-65180d9f663e/start +2025-10-24 15:39:50 [http-nio-8082-exec-4] INFO c.u.hgzero.common.aop.LoggingAspect - [Controller] com.unicorn.hgzero.meeting.infra.controller.MeetingController.startMeeting 호출 - 파라미터: [4b340eed-31d9-4b7b-a95f-65180d9f663e, user-005, dohyunjung, dohyun.jung@example.com] +2025-10-24 15:39:50 [http-nio-8082-exec-4] INFO c.u.h.m.i.c.MeetingController - 회의 시작 요청 - meetingId: 4b340eed-31d9-4b7b-a95f-65180d9f663e, userId: user-005 +2025-10-24 15:39:51 [http-nio-8082-exec-4] INFO c.u.h.m.biz.service.MeetingService - Starting meeting: 4b340eed-31d9-4b7b-a95f-65180d9f663e +2025-10-24 15:39:51 [http-nio-8082-exec-4] DEBUG c.u.h.m.biz.service.MeetingService - Cache miss for meeting: 4b340eed-31d9-4b7b-a95f-65180d9f663e +2025-10-24 15:39:51 [http-nio-8082-exec-4] DEBUG org.hibernate.SQL - + select + me1_0.meeting_id, + me1_0.created_at, + me1_0.description, + me1_0.end_time, + me1_0.ended_at, + me1_0.location, + me1_0.organizer_id, + me1_0.participants, + me1_0.purpose, + me1_0.scheduled_at, + me1_0.started_at, + me1_0.status, + me1_0.template_id, + me1_0.title, + me1_0.updated_at + from + meetings me1_0 + where + me1_0.meeting_id=? +2025-10-24 15:39:51 [http-nio-8082-exec-4] DEBUG c.u.h.m.infra.cache.CacheService - 회의 정보 캐시 저장 - meetingId: 4b340eed-31d9-4b7b-a95f-65180d9f663e +2025-10-24 15:39:51 [http-nio-8082-exec-4] DEBUG org.hibernate.SQL - + select + se1_0.session_id, + se1_0.created_at, + se1_0.ended_at, + se1_0.meeting_id, + se1_0.minutes_id, + se1_0.started_at, + se1_0.started_by, + se1_0.status, + se1_0.updated_at + from + sessions se1_0 + where + se1_0.session_id=? +2025-10-24 15:39:51 [http-nio-8082-exec-4] DEBUG c.u.h.m.biz.service.MeetingService - Session created: sessionId=90de549f-ff4f-4098-a0c0-8f2cd28b1176, meetingId=4b340eed-31d9-4b7b-a95f-65180d9f663e +2025-10-24 15:39:51 [http-nio-8082-exec-4] DEBUG c.u.h.m.biz.service.MeetingService - Meeting status updated to IN_PROGRESS: 4b340eed-31d9-4b7b-a95f-65180d9f663e +2025-10-24 15:39:51 [http-nio-8082-exec-4] DEBUG c.u.h.m.infra.cache.CacheService - 캐시 삭제 - key: meeting:4b340eed-31d9-4b7b-a95f-65180d9f663e +2025-10-24 15:39:51 [http-nio-8082-exec-4] DEBUG c.u.h.m.biz.service.MeetingService - Meeting cache evicted: 4b340eed-31d9-4b7b-a95f-65180d9f663e +2025-10-24 15:39:51 [http-nio-8082-exec-4] DEBUG org.hibernate.SQL - + select + me1_0.minutes_id, + me1_0.created_at, + me1_0.created_by, + me1_0.finalized_at, + me1_0.finalized_by, + me1_0.meeting_id, + me1_0.status, + me1_0.title, + me1_0.updated_at, + me1_0.version, + s1_0.minutes_id, + s1_0.section_id, + s1_0.content, + s1_0.created_at, + s1_0.locked, + s1_0.locked_by, + s1_0."order", + s1_0.title, + s1_0.type, + s1_0.updated_at, + s1_0.verified + from + minutes me1_0 + left join + minutes_sections s1_0 + on me1_0.minutes_id=s1_0.minutes_id + where + me1_0.minutes_id=? +2025-10-24 15:39:51 [http-nio-8082-exec-4] DEBUG c.u.h.m.biz.service.MeetingService - Minutes draft created: minutesId=30e642a9-fa4d-4cbe-a838-33214aaa2170, meetingId=4b340eed-31d9-4b7b-a95f-65180d9f663e +2025-10-24 15:39:51 [http-nio-8082-exec-4] INFO c.a.c.a.i.ReactorConnection - {"az.sdk.message":"Creating and starting connection.","connectionId":"MF_e4b94c_1761287833470","hostName":"hgzero-eventhub-ns.servicebus.windows.net","port":5671} +2025-10-24 15:39:51 [http-nio-8082-exec-4] INFO c.a.c.a.i.ReactorExecutor - {"az.sdk.message":"Starting reactor.","connectionId":"MF_e4b94c_1761287833470"} +2025-10-24 15:39:51 [reactor-executor-1] INFO c.a.c.a.i.handler.ConnectionHandler - {"az.sdk.message":"onConnectionInit","connectionId":"MF_e4b94c_1761287833470","hostName":"hgzero-eventhub-ns.servicebus.windows.net","namespace":"hgzero-eventhub-ns.servicebus.windows.net"} +2025-10-24 15:39:51 [reactor-executor-1] INFO c.a.c.a.i.handler.ReactorHandler - {"az.sdk.message":"reactor.onReactorInit","connectionId":"MF_e4b94c_1761287833470"} +2025-10-24 15:39:51 [reactor-executor-1] INFO c.a.c.a.i.handler.ConnectionHandler - {"az.sdk.message":"onConnectionLocalOpen","connectionId":"MF_e4b94c_1761287833470","errorCondition":null,"errorDescription":null,"hostName":"hgzero-eventhub-ns.servicebus.windows.net"} +2025-10-24 15:39:51 [reactor-executor-1] INFO c.a.c.a.i.handler.ConnectionHandler - {"az.sdk.message":"onConnectionBound","connectionId":"MF_e4b94c_1761287833470","hostName":"hgzero-eventhub-ns.servicebus.windows.net","peerDetails":"hgzero-eventhub-ns.servicebus.windows.net:5671"} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.c.a.i.handler.ConnectionHandler - {"az.sdk.message":"onConnectionRemoteOpen","connectionId":"MF_e4b94c_1761287833470","hostName":"hgzero-eventhub-ns.servicebus.windows.net","remoteContainer":"f95a8629f37b4a79bf39489e5eb57624_G17"} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.m.e.i.EventHubConnectionProcessor - {"az.sdk.message":"Channel is now active.","entityPath":"hgzero-eventhub-name"} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.c.a.i.handler.SessionHandler - {"az.sdk.message":"onSessionRemoteOpen","connectionId":"MF_e4b94c_1761287833470","sessionName":"hgzero-eventhub-name","sessionIncCapacity":0,"sessionOutgoingWindow":2147483647} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.c.a.i.ReactorConnection - {"az.sdk.message":"Setting CBS channel.","connectionId":"MF_e4b94c_1761287833470"} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.c.a.i.handler.SessionHandler - {"az.sdk.message":"onSessionRemoteOpen","connectionId":"MF_e4b94c_1761287833470","sessionName":"cbs-session","sessionIncCapacity":0,"sessionOutgoingWindow":2147483647} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.c.a.i.ReactorConnection - {"az.sdk.message":"Emitting new response channel.","connectionId":"MF_e4b94c_1761287833470","entityPath":"$cbs","linkName":"cbs"} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.c.a.i.AmqpChannelProcessor - {"az.sdk.message":"Setting next AMQP channel.","connectionId":"MF_e4b94c_1761287833470","entityPath":"$cbs"} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.c.a.i.AmqpChannelProcessor - {"az.sdk.message":"Next AMQP channel received.","connectionId":"MF_e4b94c_1761287833470","entityPath":"$cbs","subscriberId":"un_93ac20_1761287992168"} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.c.a.i.handler.SendLinkHandler - {"az.sdk.message":"onLinkRemoteOpen","connectionId":"MF_e4b94c_1761287833470","linkName":"cbs:sender","entityPath":"$cbs","remoteTarget":"Target{address='$cbs', durable=NONE, expiryPolicy=SESSION_END, timeout=0, dynamic=false, dynamicNodeProperties=null, capabilities=null}"} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.c.a.i.AmqpChannelProcessor - {"az.sdk.message":"Channel is now active.","connectionId":"MF_e4b94c_1761287833470","entityPath":"$cbs"} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.c.a.i.handler.ReceiveLinkHandler - {"az.sdk.message":"onLinkRemoteOpen","connectionId":"MF_e4b94c_1761287833470","entityPath":"$cbs","linkName":"cbs:receiver","remoteSource":"Source{address='$cbs', durable=NONE, expiryPolicy=SESSION_END, timeout=0, dynamic=false, dynamicNodeProperties=null, distributionMode=null, filter=null, defaultOutcome=null, outcomes=null, capabilities=null}"} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.c.a.i.ActiveClientTokenManager - {"az.sdk.message":"Scheduling refresh token task.","scopes":"amqp://hgzero-eventhub-ns.servicebus.windows.net/hgzero-eventhub-name"} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.c.a.i.ReactorSession - {"az.sdk.message":"Creating a new send link.","connectionId":"MF_e4b94c_1761287833470","linkName":"hgzero-eventhub-name","sessionName":"hgzero-eventhub-name"} +2025-10-24 15:39:52 [reactor-executor-1] INFO c.a.c.a.i.handler.SendLinkHandler - {"az.sdk.message":"onLinkRemoteOpen","connectionId":"MF_e4b94c_1761287833470","linkName":"hgzero-eventhub-name","entityPath":"hgzero-eventhub-name","remoteTarget":"Target{address='hgzero-eventhub-name', durable=NONE, expiryPolicy=SESSION_END, timeout=0, dynamic=false, dynamicNodeProperties=null, capabilities=null}"} +2025-10-24 15:39:52 [http-nio-8082-exec-4] INFO c.u.h.m.i.e.p.EventHubPublisher - 이벤트 발행 완료: topic=meeting, type=MEETING_STARTED, partitionKey=4b340eed-31d9-4b7b-a95f-65180d9f663e +2025-10-24 15:39:52 [http-nio-8082-exec-4] DEBUG c.u.h.m.biz.service.MeetingService - MeetingStarted event published: meetingId=4b340eed-31d9-4b7b-a95f-65180d9f663e, sessionId=90de549f-ff4f-4098-a0c0-8f2cd28b1176 +2025-10-24 15:39:52 [http-nio-8082-exec-4] INFO c.u.h.m.biz.service.MeetingService - Meeting started successfully: meetingId=4b340eed-31d9-4b7b-a95f-65180d9f663e, sessionId=90de549f-ff4f-4098-a0c0-8f2cd28b1176, minutesId=30e642a9-fa4d-4cbe-a838-33214aaa2170 +2025-10-24 15:39:52 [http-nio-8082-exec-4] DEBUG org.hibernate.SQL - + /* insert for + com.unicorn.hgzero.meeting.infra.gateway.entity.SessionEntity */insert + into + sessions (created_at, ended_at, meeting_id, minutes_id, started_at, started_by, status, updated_at, session_id) + values + (?, ?, ?, ?, ?, ?, ?, ?, ?) +2025-10-24 15:39:52 [http-nio-8082-exec-4] DEBUG org.hibernate.SQL - + /* insert for + com.unicorn.hgzero.meeting.infra.gateway.entity.MinutesEntity */insert + into + minutes (created_at, created_by, finalized_at, finalized_by, meeting_id, status, title, updated_at, version, minutes_id) + values + (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +2025-10-24 15:39:52 [http-nio-8082-exec-4] DEBUG org.hibernate.SQL - + /* update + for com.unicorn.hgzero.meeting.infra.gateway.entity.MeetingEntity */update meetings + set + description=?, + end_time=?, + ended_at=?, + location=?, + organizer_id=?, + participants=?, + purpose=?, + scheduled_at=?, + started_at=?, + status=?, + template_id=?, + title=?, + updated_at=? + where + meeting_id=? +2025-10-24 15:39:52 [http-nio-8082-exec-4] DEBUG org.hibernate.SQL - + /* update + for com.unicorn.hgzero.meeting.infra.gateway.entity.SessionEntity */update sessions + set + ended_at=?, + meeting_id=?, + minutes_id=?, + started_at=?, + started_by=?, + status=?, + updated_at=? + where + session_id=? +2025-10-24 15:39:52 [http-nio-8082-exec-4] INFO c.u.h.m.i.c.MeetingController - 회의 시작 완료 - meetingId: 4b340eed-31d9-4b7b-a95f-65180d9f663e, sessionId: 90de549f-ff4f-4098-a0c0-8f2cd28b1176 +2025-10-24 15:39:52 [http-nio-8082-exec-4] INFO c.u.hgzero.common.aop.LoggingAspect - [Controller] com.unicorn.hgzero.meeting.infra.controller.MeetingController.startMeeting 완료 - 실행시간: 1797ms +2025-10-24 15:44:09 [lettuce-nioEventLoop-6-1] INFO i.l.core.protocol.CommandHandler - null Unexpected exception during request: java.net.SocketException: Connection reset +java.net.SocketException: Connection reset + at java.base/sun.nio.ch.SocketChannelImpl.throwConnectionReset(SocketChannelImpl.java:401) + at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:434) + at io.netty.buffer.PooledByteBuf.setBytes(PooledByteBuf.java:255) + at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1132) + at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:356) + at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:151) + at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) + at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) + at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) + at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) + at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) + at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) + at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) + at java.base/java.lang.Thread.run(Thread.java:1583) +2025-10-24 15:44:09 [lettuce-eventExecutorLoop-1-2] INFO i.l.core.protocol.ConnectionWatchdog - Reconnecting, last destination was /20.249.177.114:6379 +2025-10-24 15:44:09 [lettuce-nioEventLoop-6-2] INFO i.l.c.protocol.ReconnectionHandler - Reconnected to 20.249.177.114/:6379 diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/domain/Session.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/domain/Session.java new file mode 100644 index 0000000..cbe7d07 --- /dev/null +++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/domain/Session.java @@ -0,0 +1,70 @@ +package com.unicorn.hgzero.meeting.biz.domain; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +/** + * 회의 세션 도메인 모델 + * 회의가 시작되면 생성되고 회의 종료 시 종료됨 + */ +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Session { + + /** + * 세션 ID (UUID) + */ + private String sessionId; + + /** + * 회의 ID + */ + private String meetingId; + + /** + * 회의록 ID + */ + private String minutesId; + + /** + * 세션 시작자 (사용자 ID) + */ + private String startedBy; + + /** + * 세션 시작 시간 + */ + private LocalDateTime startedAt; + + /** + * 세션 종료 시간 + */ + private LocalDateTime endedAt; + + /** + * 세션 상태 (ACTIVE, CLOSED) + */ + @Builder.Default + private String status = "ACTIVE"; + + /** + * 세션 종료 + */ + public void close() { + this.status = "CLOSED"; + this.endedAt = LocalDateTime.now(); + } + + /** + * 세션이 활성 상태인지 확인 + */ + public boolean isActive() { + return "ACTIVE".equals(this.status); + } +} diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/service/MeetingService.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/service/MeetingService.java index 7360eeb..9d295a8 100644 --- a/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/service/MeetingService.java +++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/service/MeetingService.java @@ -3,10 +3,16 @@ package com.unicorn.hgzero.meeting.biz.service; import com.unicorn.hgzero.common.exception.BusinessException; import com.unicorn.hgzero.common.exception.ErrorCode; import com.unicorn.hgzero.meeting.biz.domain.Meeting; +import com.unicorn.hgzero.meeting.biz.domain.Minutes; +import com.unicorn.hgzero.meeting.biz.domain.Session; import com.unicorn.hgzero.meeting.biz.usecase.in.meeting.*; import com.unicorn.hgzero.meeting.biz.usecase.out.MeetingReader; import com.unicorn.hgzero.meeting.biz.usecase.out.MeetingWriter; +import com.unicorn.hgzero.meeting.biz.usecase.out.MinutesWriter; +import com.unicorn.hgzero.meeting.biz.usecase.out.SessionReader; +import com.unicorn.hgzero.meeting.biz.usecase.out.SessionWriter; import com.unicorn.hgzero.meeting.infra.cache.CacheService; +import com.unicorn.hgzero.meeting.infra.event.dto.MeetingStartedEvent; import com.unicorn.hgzero.meeting.infra.event.publisher.EventPublisher; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -34,6 +40,9 @@ public class MeetingService implements private final MeetingReader meetingReader; private final MeetingWriter meetingWriter; + private final SessionReader sessionReader; + private final SessionWriter sessionWriter; + private final MinutesWriter minutesWriter; private final CacheService cacheService; private final EventPublisher eventPublisher; @@ -123,36 +132,126 @@ public class MeetingService implements */ @Override @Transactional - public Meeting startMeeting(String meetingId) { + public Session startMeeting(String meetingId) { log.info("Starting meeting: {}", meetingId); - // Redis 캐시 조회 기능 필요 + // 1. Redis 캐시 조회 + Meeting meeting = cacheService.getCachedMeeting(meetingId, Meeting.class); - // 회의 조회 - Meeting meeting = meetingReader.findById(meetingId) - .orElseThrow(() -> new BusinessException(ErrorCode.ENTITY_NOT_FOUND)); + // 2. 캐시 미스시 DB 조회 및 캐싱 + if (meeting == null) { + log.debug("Cache miss for meeting: {}", meetingId); + meeting = meetingReader.findById(meetingId) + .orElseThrow(() -> { + log.error("Meeting not found: {}", meetingId); + return new BusinessException(ErrorCode.ENTITY_NOT_FOUND); + }); - // 권한 검증 (생성자 or 참석자) - - // 회의 상태 검증 - if (!"SCHEDULED".equals(meeting.getStatus())) { - throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE); + // 캐시 저장 (TTL: 10분) + try { + cacheService.cacheMeeting(meetingId, meeting, 600); + } catch (Exception e) { + log.warn("Failed to cache meeting: {}", meetingId, e); + } + } else { + log.debug("Cache hit for meeting: {}", meetingId); } - // 세션 생성 기능 필요 + // 3. 비즈니스 규칙 검증 + // TODO: 권한 검증 (생성자 또는 참석자) - userId 파라미터 필요 - // 회의 시작 + // 4. 회의 상태 확인 (SCHEDULED만 시작 가능) + if (!"SCHEDULED".equals(meeting.getStatus())) { + log.warn("Meeting is not in SCHEDULED status: meetingId={}, status={}", + meetingId, meeting.getStatus()); + + if ("IN_PROGRESS".equals(meeting.getStatus())) { + throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE, + "이미 진행 중인 회의입니다"); + } + + throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE, + "회의 상태가 올바르지 않습니다"); + } + + // 5. 회의 세션 생성 + String sessionId = UUID.randomUUID().toString(); + Session session = Session.builder() + .sessionId(sessionId) + .meetingId(meetingId) + .startedBy(meeting.getOrganizerId()) // TODO: 실제 사용자 ID 사용 + .startedAt(LocalDateTime.now()) + .status("ACTIVE") + .build(); + + // 6. 세션 저장 + Session savedSession = sessionWriter.save(session); + log.debug("Session created: sessionId={}, meetingId={}", sessionId, meetingId); + + // 7. 회의 상태를 IN_PROGRESS로 업데이트 meeting.start(); - - // 저장 Meeting updatedMeeting = meetingWriter.save(meeting); + log.debug("Meeting status updated to IN_PROGRESS: {}", meetingId); - // 회의록 초안 생성 필요 + // 8. 캐시 무효화 + try { + cacheService.evictCache("meeting:", meetingId); + log.debug("Meeting cache evicted: {}", meetingId); + } catch (Exception e) { + log.warn("Failed to evict meeting cache: {}", meetingId, e); + } - // 이벤트 발행 필요 + // 9. 회의록 초안 생성 (빈 회의록) + String minutesId = UUID.randomUUID().toString(); + Minutes minutesDraft = Minutes.builder() + .minutesId(minutesId) + .meetingId(meetingId) + .title(meeting.getTitle() + " - 회의록") + .sections(List.of()) + .status("DRAFT") + .version(1) + .createdBy(meeting.getOrganizerId()) // TODO: 실제 사용자 ID 사용 + .createdAt(LocalDateTime.now()) + .build(); - log.info("Meeting started successfully: {}", meetingId); - return updatedMeeting; + Minutes savedMinutes = minutesWriter.save(minutesDraft); + log.debug("Minutes draft created: minutesId={}, meetingId={}", minutesId, meetingId); + + // 세션에 회의록 ID 연결 + Session updatedSession = Session.builder() + .sessionId(savedSession.getSessionId()) + .meetingId(savedSession.getMeetingId()) + .minutesId(minutesId) + .startedBy(savedSession.getStartedBy()) + .startedAt(savedSession.getStartedAt()) + .status(savedSession.getStatus()) + .build(); + sessionWriter.save(updatedSession); + + // 10. 비동기 이벤트 발행 + try { + MeetingStartedEvent event = MeetingStartedEvent.builder() + .meetingId(meetingId) + .sessionId(sessionId) + .title(meeting.getTitle()) + .startTime(meeting.getStartedAt()) + .organizer(meeting.getOrganizerId()) + .participants(meeting.getParticipants()) + .minutesId(minutesId) + .eventTime(LocalDateTime.now()) + .build(); + + eventPublisher.publishMeetingStarted(event); + log.debug("MeetingStarted event published: meetingId={}, sessionId={}", + meetingId, sessionId); + } catch (Exception e) { + log.error("Failed to publish MeetingStarted event: meetingId={}", meetingId, e); + // 이벤트 발행 실패는 비즈니스 로직에 영향을 주지 않으므로 계속 진행 + } + + log.info("Meeting started successfully: meetingId={}, sessionId={}, minutesId={}", + meetingId, sessionId, minutesId); + return updatedSession; } /** diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/usecase/in/meeting/StartMeetingUseCase.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/usecase/in/meeting/StartMeetingUseCase.java index 04e0c5d..e467066 100644 --- a/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/usecase/in/meeting/StartMeetingUseCase.java +++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/usecase/in/meeting/StartMeetingUseCase.java @@ -1,6 +1,6 @@ package com.unicorn.hgzero.meeting.biz.usecase.in.meeting; -import com.unicorn.hgzero.meeting.biz.domain.Meeting; +import com.unicorn.hgzero.meeting.biz.domain.Session; /** * 회의 시작 UseCase @@ -9,6 +9,8 @@ public interface StartMeetingUseCase { /** * 회의 시작 + * @param meetingId 회의 ID + * @return 생성된 세션 정보 */ - Meeting startMeeting(String meetingId); + Session startMeeting(String meetingId); } diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/usecase/out/SessionReader.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/usecase/out/SessionReader.java new file mode 100644 index 0000000..9f37c0b --- /dev/null +++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/usecase/out/SessionReader.java @@ -0,0 +1,32 @@ +package com.unicorn.hgzero.meeting.biz.usecase.out; + +import com.unicorn.hgzero.meeting.biz.domain.Session; + +import java.util.List; +import java.util.Optional; + +/** + * Session Reader Port + */ +public interface SessionReader { + + /** + * ID로 세션 조회 + */ + Optional findById(String sessionId); + + /** + * 회의 ID로 세션 목록 조회 + */ + List findByMeetingId(String meetingId); + + /** + * 회의 ID로 활성 세션 조회 + */ + Optional findActiveSesionByMeetingId(String meetingId); + + /** + * 시작자 ID로 세션 목록 조회 + */ + List findByStartedBy(String startedBy); +} diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/usecase/out/SessionWriter.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/usecase/out/SessionWriter.java new file mode 100644 index 0000000..992f994 --- /dev/null +++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/biz/usecase/out/SessionWriter.java @@ -0,0 +1,19 @@ +package com.unicorn.hgzero.meeting.biz.usecase.out; + +import com.unicorn.hgzero.meeting.biz.domain.Session; + +/** + * Session Writer Port + */ +public interface SessionWriter { + + /** + * 세션 저장 + */ + Session save(Session session); + + /** + * 세션 삭제 + */ + void delete(String sessionId); +} diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/controller/MeetingController.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/controller/MeetingController.java index cd1dad4..36eab4c 100644 --- a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/controller/MeetingController.java +++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/controller/MeetingController.java @@ -149,12 +149,12 @@ public class MeetingController { // meeting id 유효성 검증 필요 - var sessionData = startMeetingUseCase.startMeeting(meetingId); - var response = SessionResponse.from(sessionData); - - log.info("회의 시작 완료 - meetingId: {}", meetingId); - - return ResponseEntity.ok(ApiResponse.success(response)); + var session = startMeetingUseCase.startMeeting(meetingId); + var response = SessionResponse.from(session, "ws://localhost:8080/ws/collaboration"); + + log.info("회의 시작 완료 - meetingId: {}, sessionId: {}", meetingId, session.getSessionId()); + + return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(response)); } /** diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/dto/response/SessionResponse.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/dto/response/SessionResponse.java index bfc1a69..fc0ec75 100644 --- a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/dto/response/SessionResponse.java +++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/dto/response/SessionResponse.java @@ -21,6 +21,12 @@ public class SessionResponse { @Schema(description = "회의 ID", example = "550e8400-e29b-41d4-a716-446655440000") private final String meetingId; + @Schema(description = "회의록 ID", example = "minutes-001") + private final String minutesId; + + @Schema(description = "세션 상태", example = "IN_PROGRESS") + private final String status; + @Schema(description = "WebSocket URL", example = "ws://localhost:8080/ws/collaboration") private final String websocketUrl; @@ -40,10 +46,28 @@ public class SessionResponse { return SessionResponse.builder() .sessionId("session-" + meeting.getMeetingId()) .meetingId(meeting.getMeetingId()) + .minutesId(null) // 실제로는 세션에서 가져와야 함 + .status(meeting.getStatus()) .websocketUrl("ws://localhost:8080/ws/collaboration") .sessionToken("session-token-" + System.currentTimeMillis()) .startedAt(meeting.getStartedAt() != null ? meeting.getStartedAt() : LocalDateTime.now()) .expiresAt(LocalDateTime.now().plusHours(4)) .build(); } + + /** + * Session 객체로부터 SessionResponse 생성 + */ + public static SessionResponse from(com.unicorn.hgzero.meeting.biz.domain.Session session, String websocketUrl) { + return SessionResponse.builder() + .sessionId(session.getSessionId()) + .meetingId(session.getMeetingId()) + .minutesId(session.getMinutesId()) + .status(session.getStatus()) + .websocketUrl(websocketUrl != null ? websocketUrl : "ws://localhost:8080/ws/collaboration") + .sessionToken("session-token-" + System.currentTimeMillis()) + .startedAt(session.getStartedAt()) + .expiresAt(session.getStartedAt().plusHours(4)) + .build(); + } } \ No newline at end of file diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/event/dto/MeetingStartedEvent.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/event/dto/MeetingStartedEvent.java index f446da5..16bde59 100644 --- a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/event/dto/MeetingStartedEvent.java +++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/event/dto/MeetingStartedEvent.java @@ -18,6 +18,11 @@ public class MeetingStartedEvent { */ private final String meetingId; + /** + * 세션 ID + */ + private final String sessionId; + /** * 회의 제목 */ diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/gateway/SessionGateway.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/gateway/SessionGateway.java new file mode 100644 index 0000000..3a039d1 --- /dev/null +++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/gateway/SessionGateway.java @@ -0,0 +1,64 @@ +package com.unicorn.hgzero.meeting.infra.gateway; + +import com.unicorn.hgzero.meeting.biz.domain.Session; +import com.unicorn.hgzero.meeting.biz.usecase.out.SessionReader; +import com.unicorn.hgzero.meeting.biz.usecase.out.SessionWriter; +import com.unicorn.hgzero.meeting.infra.gateway.entity.SessionEntity; +import com.unicorn.hgzero.meeting.infra.gateway.repository.SessionJpaRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * 세션 Gateway 구현체 + * SessionReader, SessionWriter 인터페이스 구현 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class SessionGateway implements SessionReader, SessionWriter { + + private final SessionJpaRepository sessionJpaRepository; + + @Override + public Optional findById(String sessionId) { + return sessionJpaRepository.findById(sessionId) + .map(SessionEntity::toDomain); + } + + @Override + public List findByMeetingId(String meetingId) { + return sessionJpaRepository.findByMeetingId(meetingId).stream() + .map(SessionEntity::toDomain) + .collect(Collectors.toList()); + } + + @Override + public Optional findActiveSesionByMeetingId(String meetingId) { + return sessionJpaRepository.findActiveSessionByMeetingId(meetingId) + .map(SessionEntity::toDomain); + } + + @Override + public List findByStartedBy(String startedBy) { + return sessionJpaRepository.findByStartedBy(startedBy).stream() + .map(SessionEntity::toDomain) + .collect(Collectors.toList()); + } + + @Override + public Session save(Session session) { + SessionEntity entity = SessionEntity.fromDomain(session); + SessionEntity savedEntity = sessionJpaRepository.save(entity); + return savedEntity.toDomain(); + } + + @Override + public void delete(String sessionId) { + sessionJpaRepository.deleteById(sessionId); + } +} diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/gateway/entity/SessionEntity.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/gateway/entity/SessionEntity.java new file mode 100644 index 0000000..3300b9e --- /dev/null +++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/gateway/entity/SessionEntity.java @@ -0,0 +1,75 @@ +package com.unicorn.hgzero.meeting.infra.gateway.entity; + +import com.unicorn.hgzero.common.entity.BaseTimeEntity; +import com.unicorn.hgzero.meeting.biz.domain.Session; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +/** + * 회의 세션 Entity + */ +@Entity +@Table(name = "sessions") +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SessionEntity extends BaseTimeEntity { + + @Id + @Column(name = "session_id", length = 50) + private String sessionId; + + @Column(name = "meeting_id", length = 50, nullable = false) + private String meetingId; + + @Column(name = "minutes_id", length = 50) + private String minutesId; + + @Column(name = "started_by", length = 50, nullable = false) + private String startedBy; + + @Column(name = "started_at", nullable = false) + private LocalDateTime startedAt; + + @Column(name = "ended_at") + private LocalDateTime endedAt; + + @Column(name = "status", length = 20, nullable = false) + @Builder.Default + private String status = "ACTIVE"; + + public Session toDomain() { + return Session.builder() + .sessionId(this.sessionId) + .meetingId(this.meetingId) + .minutesId(this.minutesId) + .startedBy(this.startedBy) + .startedAt(this.startedAt) + .endedAt(this.endedAt) + .status(this.status) + .build(); + } + + public static SessionEntity fromDomain(Session session) { + return SessionEntity.builder() + .sessionId(session.getSessionId()) + .meetingId(session.getMeetingId()) + .minutesId(session.getMinutesId()) + .startedBy(session.getStartedBy()) + .startedAt(session.getStartedAt()) + .endedAt(session.getEndedAt()) + .status(session.getStatus()) + .build(); + } + + public void close() { + this.status = "CLOSED"; + this.endedAt = LocalDateTime.now(); + } +} diff --git a/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/gateway/repository/SessionJpaRepository.java b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/gateway/repository/SessionJpaRepository.java new file mode 100644 index 0000000..649cb93 --- /dev/null +++ b/meeting/src/main/java/com/unicorn/hgzero/meeting/infra/gateway/repository/SessionJpaRepository.java @@ -0,0 +1,31 @@ +package com.unicorn.hgzero.meeting.infra.gateway.repository; + +import com.unicorn.hgzero.meeting.infra.gateway.entity.SessionEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; +import java.util.Optional; + +/** + * 세션 JPA Repository + */ +public interface SessionJpaRepository extends JpaRepository { + + /** + * 회의 ID로 세션 목록 조회 + */ + List findByMeetingId(String meetingId); + + /** + * 회의 ID로 활성 세션 조회 + */ + @Query("SELECT s FROM SessionEntity s WHERE s.meetingId = :meetingId AND s.status = 'ACTIVE'") + Optional findActiveSessionByMeetingId(@Param("meetingId") String meetingId); + + /** + * 시작자 ID로 세션 목록 조회 + */ + List findByStartedBy(String startedBy); +}