mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 10:16:24 +00:00
Merge branch 'main' of https://github.com/hwanny1128/HGZero
This commit is contained in:
commit
fc1e63611d
286
ai/logs/ai-service.log
Normal file
286
ai/logs/ai-service.log
Normal file
@ -0,0 +1,286 @@
|
||||
2025-10-24 09:23:35 [main] INFO com.unicorn.hgzero.ai.AiApplication - Starting AiApplication using Java 21.0.8 with PID 92971 (/Users/daewoong/home/workspace/HGZero/ai/build/classes/java/main started by daewoong in /Users/daewoong/home/workspace/HGZero/ai)
|
||||
2025-10-24 09:23:35 [main] DEBUG com.unicorn.hgzero.ai.AiApplication - Running with Spring Boot v3.3.0, Spring v6.1.8
|
||||
2025-10-24 09:23:35 [main] INFO com.unicorn.hgzero.ai.AiApplication - No active profile set, falling back to 1 default profile: "default"
|
||||
2025-10-24 09:23:36 [main] WARN o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'jpaAuditingHandler' defined in null: Cannot register bean definition [Root bean: class [org.springframework.data.auditing.AuditingHandler]; scope=; abstract=false; lazyInit=null; autowireMode=2; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=from; initMethodNames=null; destroyMethodNames=null] for bean 'jpaAuditingHandler' since there is already [Root bean: class [org.springframework.data.auditing.AuditingHandler]; scope=; abstract=false; lazyInit=null; autowireMode=2; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=from; initMethodNames=null; destroyMethodNames=null] bound.
|
||||
2025-10-24 09:23:36 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger -
|
||||
|
||||
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
|
||||
2025-10-24 09:23:36 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter -
|
||||
|
||||
***************************
|
||||
APPLICATION FAILED TO START
|
||||
***************************
|
||||
|
||||
Description:
|
||||
|
||||
The bean 'jpaAuditingHandler' could not be registered. A bean with that name has already been defined and overriding is disabled.
|
||||
|
||||
Action:
|
||||
|
||||
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
|
||||
|
||||
2025-10-24 09:42:56 [main] INFO com.unicorn.hgzero.ai.AiApplication - Starting AiApplication using Java 21.0.8 with PID 93771 (/Users/daewoong/home/workspace/HGZero/ai/build/classes/java/main started by daewoong in /Users/daewoong/home/workspace/HGZero/ai)
|
||||
2025-10-24 09:42:56 [main] DEBUG com.unicorn.hgzero.ai.AiApplication - Running with Spring Boot v3.3.5, Spring v6.1.14
|
||||
2025-10-24 09:42:56 [main] INFO com.unicorn.hgzero.ai.AiApplication - No active profile set, falling back to 1 default profile: "default"
|
||||
2025-10-24 09:42:56 [main] WARN o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'jpaAuditingHandler' defined in null: Cannot register bean definition [Root bean: class [org.springframework.data.auditing.AuditingHandler]; scope=; abstract=false; lazyInit=null; autowireMode=2; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=from; initMethodNames=null; destroyMethodNames=null] for bean 'jpaAuditingHandler' since there is already [Root bean: class [org.springframework.data.auditing.AuditingHandler]; scope=; abstract=false; lazyInit=null; autowireMode=2; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=from; initMethodNames=null; destroyMethodNames=null] bound.
|
||||
2025-10-24 09:42:56 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger -
|
||||
|
||||
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
|
||||
2025-10-24 09:42:56 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter -
|
||||
|
||||
***************************
|
||||
APPLICATION FAILED TO START
|
||||
***************************
|
||||
|
||||
Description:
|
||||
|
||||
The bean 'jpaAuditingHandler' could not be registered. A bean with that name has already been defined and overriding is disabled.
|
||||
|
||||
Action:
|
||||
|
||||
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
|
||||
|
||||
2025-10-24 09:43:58 [main] INFO com.unicorn.hgzero.ai.AiApplication - Starting AiApplication using Java 21.0.8 with PID 93809 (/Users/daewoong/home/workspace/HGZero/ai/build/classes/java/main started by daewoong in /Users/daewoong/home/workspace/HGZero/ai)
|
||||
2025-10-24 09:43:58 [main] DEBUG com.unicorn.hgzero.ai.AiApplication - Running with Spring Boot v3.3.5, Spring v6.1.14
|
||||
2025-10-24 09:43:58 [main] INFO com.unicorn.hgzero.ai.AiApplication - No active profile set, falling back to 1 default profile: "default"
|
||||
2025-10-24 09:43:58 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
|
||||
2025-10-24 09:43:58 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
|
||||
2025-10-24 09:43:58 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 65 ms. Found 1 JPA repository interface.
|
||||
2025-10-24 09:43:58 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
|
||||
2025-10-24 09:43:58 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode.
|
||||
2025-10-24 09:43:58 [main] INFO o.s.d.r.c.RepositoryConfigurationExtensionSupport - Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.unicorn.hgzero.ai.infra.gateway.repository.ProcessedTranscriptJpaRepository; 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 09:43:58 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 3 ms. Found 0 Redis repository interfaces.
|
||||
2025-10-24 09:43:59 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8083 (http)
|
||||
2025-10-24 09:43:59 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat]
|
||||
2025-10-24 09:43:59 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.31]
|
||||
2025-10-24 09:43:59 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
|
||||
2025-10-24 09:43:59 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 990 ms
|
||||
2025-10-24 09:43:59 [main] INFO o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2025-10-24 09:43:59 [main] INFO org.hibernate.Version - HHH000412: Hibernate ORM core version 6.5.3.Final
|
||||
2025-10-24 09:43:59 [main] INFO o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration boolean -> org.hibernate.type.BasicTypeReference@24c84e65
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration boolean -> org.hibernate.type.BasicTypeReference@24c84e65
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Boolean -> org.hibernate.type.BasicTypeReference@24c84e65
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration numeric_boolean -> org.hibernate.type.BasicTypeReference@7337bd2e
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.NumericBooleanConverter -> org.hibernate.type.BasicTypeReference@7337bd2e
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration true_false -> org.hibernate.type.BasicTypeReference@4604e051
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.TrueFalseConverter -> org.hibernate.type.BasicTypeReference@4604e051
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration yes_no -> org.hibernate.type.BasicTypeReference@4535bdc6
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.YesNoConverter -> org.hibernate.type.BasicTypeReference@4535bdc6
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration byte -> org.hibernate.type.BasicTypeReference@23e86863
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration byte -> org.hibernate.type.BasicTypeReference@23e86863
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Byte -> org.hibernate.type.BasicTypeReference@23e86863
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration binary -> org.hibernate.type.BasicTypeReference@6df87ffd
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration byte[] -> org.hibernate.type.BasicTypeReference@6df87ffd
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration [B -> org.hibernate.type.BasicTypeReference@6df87ffd
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration binary_wrapper -> org.hibernate.type.BasicTypeReference@c1f0c7b
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration wrapper-binary -> org.hibernate.type.BasicTypeReference@c1f0c7b
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration image -> org.hibernate.type.BasicTypeReference@642c5bb3
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration blob -> org.hibernate.type.BasicTypeReference@4e79c25
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Blob -> org.hibernate.type.BasicTypeReference@4e79c25
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_blob -> org.hibernate.type.BasicTypeReference@2ace1cd3
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_blob_wrapper -> org.hibernate.type.BasicTypeReference@5e46a125
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration short -> org.hibernate.type.BasicTypeReference@5831989d
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration short -> org.hibernate.type.BasicTypeReference@5831989d
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Short -> org.hibernate.type.BasicTypeReference@5831989d
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration integer -> org.hibernate.type.BasicTypeReference@608f310a
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration int -> org.hibernate.type.BasicTypeReference@608f310a
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Integer -> org.hibernate.type.BasicTypeReference@608f310a
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration long -> org.hibernate.type.BasicTypeReference@3a7d914c
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration long -> org.hibernate.type.BasicTypeReference@3a7d914c
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Long -> org.hibernate.type.BasicTypeReference@3a7d914c
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration float -> org.hibernate.type.BasicTypeReference@515940af
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration float -> org.hibernate.type.BasicTypeReference@515940af
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Float -> org.hibernate.type.BasicTypeReference@515940af
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration double -> org.hibernate.type.BasicTypeReference@5f8df69
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration double -> org.hibernate.type.BasicTypeReference@5f8df69
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Double -> org.hibernate.type.BasicTypeReference@5f8df69
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration big_integer -> org.hibernate.type.BasicTypeReference@1ce6a9bd
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.math.BigInteger -> org.hibernate.type.BasicTypeReference@1ce6a9bd
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration big_decimal -> org.hibernate.type.BasicTypeReference@4a47bc9c
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.math.BigDecimal -> org.hibernate.type.BasicTypeReference@4a47bc9c
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration character -> org.hibernate.type.BasicTypeReference@5100c143
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration char -> org.hibernate.type.BasicTypeReference@5100c143
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Character -> org.hibernate.type.BasicTypeReference@5100c143
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration character_nchar -> org.hibernate.type.BasicTypeReference@12404f9d
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration string -> org.hibernate.type.BasicTypeReference@3b42b729
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.String -> org.hibernate.type.BasicTypeReference@3b42b729
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration nstring -> org.hibernate.type.BasicTypeReference@4c164f81
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration characters -> org.hibernate.type.BasicTypeReference@1bcb8599
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration char[] -> org.hibernate.type.BasicTypeReference@1bcb8599
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration [C -> org.hibernate.type.BasicTypeReference@1bcb8599
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration wrapper-characters -> org.hibernate.type.BasicTypeReference@b671dda
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration text -> org.hibernate.type.BasicTypeReference@25b20860
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ntext -> org.hibernate.type.BasicTypeReference@5ba63110
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration clob -> org.hibernate.type.BasicTypeReference@1c0680b0
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Clob -> org.hibernate.type.BasicTypeReference@1c0680b0
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration nclob -> org.hibernate.type.BasicTypeReference@2f3cd727
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.NClob -> org.hibernate.type.BasicTypeReference@2f3cd727
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_clob -> org.hibernate.type.BasicTypeReference@1af82ba8
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_clob_char_array -> org.hibernate.type.BasicTypeReference@703cb756
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_clob_character_array -> org.hibernate.type.BasicTypeReference@5897aae1
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_nclob -> org.hibernate.type.BasicTypeReference@11dbcb3b
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_nclob_character_array -> org.hibernate.type.BasicTypeReference@4aa517c3
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_nclob_char_array -> org.hibernate.type.BasicTypeReference@5f369fc6
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration Duration -> org.hibernate.type.BasicTypeReference@3a13f663
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.Duration -> org.hibernate.type.BasicTypeReference@3a13f663
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration LocalDateTime -> org.hibernate.type.BasicTypeReference@75de7009
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.LocalDateTime -> org.hibernate.type.BasicTypeReference@75de7009
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration LocalDate -> org.hibernate.type.BasicTypeReference@17a77a7e
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.LocalDate -> org.hibernate.type.BasicTypeReference@17a77a7e
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration LocalTime -> org.hibernate.type.BasicTypeReference@7c840fe3
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.LocalTime -> org.hibernate.type.BasicTypeReference@7c840fe3
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTime -> org.hibernate.type.BasicTypeReference@59014efe
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetDateTime -> org.hibernate.type.BasicTypeReference@59014efe
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTimeWithTimezone -> org.hibernate.type.BasicTypeReference@5f5923ef
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTimeWithoutTimezone -> org.hibernate.type.BasicTypeReference@7381d6f0
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTime -> org.hibernate.type.BasicTypeReference@2f262474
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetTime -> org.hibernate.type.BasicTypeReference@2f262474
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTimeUtc -> org.hibernate.type.BasicTypeReference@7c03f9d0
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTimeWithTimezone -> org.hibernate.type.BasicTypeReference@6ad3fbe4
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTimeWithoutTimezone -> org.hibernate.type.BasicTypeReference@17189618
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTime -> org.hibernate.type.BasicTypeReference@983050b
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.ZonedDateTime -> org.hibernate.type.BasicTypeReference@983050b
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTimeWithTimezone -> org.hibernate.type.BasicTypeReference@6aadb092
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTimeWithoutTimezone -> org.hibernate.type.BasicTypeReference@1f547af8
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration date -> org.hibernate.type.BasicTypeReference@4caf875c
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Date -> org.hibernate.type.BasicTypeReference@4caf875c
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration time -> org.hibernate.type.BasicTypeReference@5d15789f
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Time -> org.hibernate.type.BasicTypeReference@5d15789f
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration timestamp -> org.hibernate.type.BasicTypeReference@5abb7a8f
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Timestamp -> org.hibernate.type.BasicTypeReference@5abb7a8f
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Date -> org.hibernate.type.BasicTypeReference@5abb7a8f
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration calendar -> org.hibernate.type.BasicTypeReference@6684589a
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Calendar -> org.hibernate.type.BasicTypeReference@6684589a
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.GregorianCalendar -> org.hibernate.type.BasicTypeReference@6684589a
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration calendar_date -> org.hibernate.type.BasicTypeReference@5621a671
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration calendar_time -> org.hibernate.type.BasicTypeReference@2006fdaa
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration instant -> org.hibernate.type.BasicTypeReference@21688427
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.Instant -> org.hibernate.type.BasicTypeReference@21688427
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration uuid -> org.hibernate.type.BasicTypeReference@656c5818
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.UUID -> org.hibernate.type.BasicTypeReference@656c5818
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration pg-uuid -> org.hibernate.type.BasicTypeReference@656c5818
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration uuid-binary -> org.hibernate.type.BasicTypeReference@3e2578ea
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration uuid-char -> org.hibernate.type.BasicTypeReference@29592929
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration class -> org.hibernate.type.BasicTypeReference@4cf5d999
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Class -> org.hibernate.type.BasicTypeReference@4cf5d999
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration currency -> org.hibernate.type.BasicTypeReference@4bdef487
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration Currency -> org.hibernate.type.BasicTypeReference@4bdef487
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Currency -> org.hibernate.type.BasicTypeReference@4bdef487
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration locale -> org.hibernate.type.BasicTypeReference@5ea9373e
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Locale -> org.hibernate.type.BasicTypeReference@5ea9373e
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration serializable -> org.hibernate.type.BasicTypeReference@3e595da3
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.io.Serializable -> org.hibernate.type.BasicTypeReference@3e595da3
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration timezone -> org.hibernate.type.BasicTypeReference@5c0272e0
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.TimeZone -> org.hibernate.type.BasicTypeReference@5c0272e0
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZoneOffset -> org.hibernate.type.BasicTypeReference@60c4cf2b
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.ZoneOffset -> org.hibernate.type.BasicTypeReference@60c4cf2b
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration url -> org.hibernate.type.BasicTypeReference@774304ca
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.net.URL -> org.hibernate.type.BasicTypeReference@774304ca
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration vector -> org.hibernate.type.BasicTypeReference@303fbc4
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration row_version -> org.hibernate.type.BasicTypeReference@4cd90c36
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration object -> org.hibernate.type.JavaObjectType@3dbbed3e
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Object -> org.hibernate.type.JavaObjectType@3dbbed3e
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration null -> org.hibernate.type.NullType@64540344
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_date -> org.hibernate.type.BasicTypeReference@b2d8dcd
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_time -> org.hibernate.type.BasicTypeReference@1397b141
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_timestamp -> org.hibernate.type.BasicTypeReference@579dde54
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_calendar -> org.hibernate.type.BasicTypeReference@30b9728f
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_calendar_date -> org.hibernate.type.BasicTypeReference@6b899971
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_calendar_time -> org.hibernate.type.BasicTypeReference@453a30f8
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_binary -> org.hibernate.type.BasicTypeReference@7cec3975
|
||||
2025-10-24 09:43:59 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_serializable -> org.hibernate.type.BasicTypeReference@73a116d
|
||||
2025-10-24 09:43:59 [main] INFO o.s.o.j.p.SpringPersistenceUnitInfo - No LoadTimeWeaver setup: ignoring JPA class transformer
|
||||
2025-10-24 09:43:59 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
|
||||
2025-10-24 09:43:59 [main] INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@720c0996
|
||||
2025-10-24 09:43:59 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
|
||||
2025-10-24 09:44:00 [main] DEBUG o.h.t.d.sql.spi.DdlTypeRegistry - addDescriptor(2003, org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl@15549dd7) replaced previous registration(org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl@1e75af65)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.h.t.d.sql.spi.DdlTypeRegistry - addDescriptor(6, org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType@25a2c4dc) replaced previous registration(org.hibernate.type.descriptor.sql.internal.DdlTypeImpl@29d81c22)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.h.t.d.jdbc.spi.JdbcTypeRegistry - addDescriptor(2004, BlobTypeDescriptor(BLOB_BINDING)) replaced previous registration(BlobTypeDescriptor(DEFAULT))
|
||||
2025-10-24 09:44:00 [main] DEBUG o.h.t.d.jdbc.spi.JdbcTypeRegistry - addDescriptor(2005, ClobTypeDescriptor(CLOB_BINDING)) replaced previous registration(ClobTypeDescriptor(DEFAULT))
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration JAVA_OBJECT -> org.hibernate.type.JavaObjectType@35e357b
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Object -> org.hibernate.type.JavaObjectType@35e357b
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Type registration key [java.lang.Object] overrode previous entry : `org.hibernate.type.JavaObjectType@3dbbed3e`
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.DurationType -> basicType@1(java.time.Duration,3015)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration Duration -> basicType@1(java.time.Duration,3015)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.Duration -> basicType@1(java.time.Duration,3015)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.OffsetDateTimeType -> basicType@2(java.time.OffsetDateTime,3003)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTime -> basicType@2(java.time.OffsetDateTime,3003)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetDateTime -> basicType@2(java.time.OffsetDateTime,3003)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.ZonedDateTimeType -> basicType@3(java.time.ZonedDateTime,3003)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTime -> basicType@3(java.time.ZonedDateTime,3003)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.ZonedDateTime -> basicType@3(java.time.ZonedDateTime,3003)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.OffsetTimeType -> basicType@4(java.time.OffsetTime,3007)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTime -> basicType@4(java.time.OffsetTime,3007)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetTime -> basicType@4(java.time.OffsetTime,3007)
|
||||
2025-10-24 09:44:00 [main] DEBUG o.h.type.spi.TypeConfiguration$Scope - Scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration@755009f2] to MetadataBuildingContext [org.hibernate.boot.internal.MetadataBuildingContextRootImpl@1756a471]
|
||||
2025-10-24 09:44:00 [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 09:44:00 [main] DEBUG o.h.type.spi.TypeConfiguration$Scope - Scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration@755009f2] to SessionFactoryImplementor [org.hibernate.internal.SessionFactoryImpl@139da216]
|
||||
2025-10-24 09:44:00 [main] DEBUG org.hibernate.SQL -
|
||||
create table processed_transcripts (
|
||||
transcript_id varchar(50) not null,
|
||||
created_at timestamp(6) not null,
|
||||
updated_at timestamp(6) not null,
|
||||
decisions TEXT,
|
||||
discussions TEXT,
|
||||
meeting_id varchar(50) not null,
|
||||
pending_items TEXT,
|
||||
status varchar(20) not null,
|
||||
summary TEXT,
|
||||
primary key (transcript_id)
|
||||
)
|
||||
2025-10-24 09:44:00 [main] TRACE o.h.type.spi.TypeConfiguration$Scope - Handling #sessionFactoryCreated from [org.hibernate.internal.SessionFactoryImpl@139da216] for TypeConfiguration
|
||||
2025-10-24 09:44:00 [main] INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
|
||||
2025-10-24 09:44:01 [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 09:44:01 [main] WARN o.s.b.a.s.s.UserDetailsServiceAutoConfiguration -
|
||||
|
||||
Using generated security password: 95eb4232-3294-428d-b23f-4e7e714862aa
|
||||
|
||||
This generated password is for development use only. Your security configuration must be updated before running your application in production.
|
||||
|
||||
2025-10-24 09:44:01 [main] INFO o.s.s.c.a.a.c.InitializeUserDetailsBeanManagerConfigurer$InitializeUserDetailsManagerConfigurer - Global AuthenticationManager configured with UserDetailsService bean with name inMemoryUserDetailsManager
|
||||
2025-10-24 09:44:01 [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 09:44:01 [main] INFO o.s.b.a.e.web.EndpointLinksResolver - Exposing 3 endpoints beneath base path '/actuator'
|
||||
2025-10-24 09:44:01 [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 09:44:01 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8083 (http) with context path '/'
|
||||
2025-10-24 09:44:01 [main] INFO com.unicorn.hgzero.ai.AiApplication - Started AiApplication in 3.911 seconds (process running for 4.067)
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-1] INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-1] INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 3 ms
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-1] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/index.html
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-1] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-1] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/index.html
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-2] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/swagger-ui.css
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-2] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-2] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/swagger-ui.css
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-3] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/index.css
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-4] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/swagger-ui-bundle.js
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-4] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-5] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/swagger-ui-standalone-preset.js
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-4] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/swagger-ui-bundle.js
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-5] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-6] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/swagger-initializer.js
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-5] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/swagger-ui-standalone-preset.js
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-6] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-6] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/swagger-initializer.js
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-3] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-3] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/index.css
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-8] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/favicon-32x32.png
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-8] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-7] DEBUG o.s.security.web.FilterChainProxy - Securing GET /v3/api-docs/swagger-config
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-8] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/favicon-32x32.png
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-7] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-7] DEBUG o.s.security.web.FilterChainProxy - Secured GET /v3/api-docs/swagger-config
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-7] INFO c.u.hgzero.common.aop.LoggingAspect - [Controller] org.springdoc.webmvc.ui.SwaggerConfigResource.openapiJson 호출 - 파라미터: [SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@4e36d653]]
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-7] INFO c.u.hgzero.common.aop.LoggingAspect - [Controller] org.springdoc.webmvc.ui.SwaggerConfigResource.openapiJson 완료 - 실행시간: 0ms
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-9] DEBUG o.s.security.web.FilterChainProxy - Securing GET /v3/api-docs
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-9] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-9] DEBUG o.s.security.web.FilterChainProxy - Secured GET /v3/api-docs
|
||||
2025-10-24 09:45:34 [http-nio-8083-exec-9] INFO c.u.hgzero.common.aop.LoggingAspect - [Controller] org.springdoc.webmvc.api.OpenApiWebMvcResource.openapiJson 호출 - 파라미터: [SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@668a5138], /v3/api-docs, ko_KR]
|
||||
2025-10-24 09:45:35 [http-nio-8083-exec-9] INFO o.s.api.AbstractOpenApiResource - Init duration for springdoc-openapi is: 229 ms
|
||||
2025-10-24 09:45:35 [http-nio-8083-exec-9] INFO c.u.hgzero.common.aop.LoggingAspect - [Controller] org.springdoc.webmvc.api.OpenApiWebMvcResource.openapiJson 완료 - 실행시간: 239ms
|
||||
2025-10-24 09:46:36 [SpringApplicationShutdownHook] INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
|
||||
2025-10-24 09:46:36 [SpringApplicationShutdownHook] TRACE o.h.type.spi.TypeConfiguration$Scope - Handling #sessionFactoryClosed from [org.hibernate.internal.SessionFactoryImpl@139da216] for TypeConfiguration
|
||||
2025-10-24 09:46:36 [SpringApplicationShutdownHook] DEBUG o.h.type.spi.TypeConfiguration$Scope - Un-scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration$Scope@35883f25] from SessionFactory [org.hibernate.internal.SessionFactoryImpl@139da216]
|
||||
2025-10-24 09:46:36 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
|
||||
2025-10-24 09:46:36 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
|
||||
@ -3,6 +3,7 @@ package com.unicorn.hgzero.ai;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
|
||||
/**
|
||||
* AI Service Application
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
package com.unicorn.hgzero.ai.biz.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 추출된 Todo 도메인 모델
|
||||
* AI가 회의록에서 추출한 Todo 정보
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ExtractedTodo {
|
||||
|
||||
/**
|
||||
* Todo 내용
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 담당자
|
||||
*/
|
||||
private String assignee;
|
||||
|
||||
/**
|
||||
* 마감일
|
||||
*/
|
||||
private LocalDate dueDate;
|
||||
|
||||
/**
|
||||
* 우선순위 (HIGH, MEDIUM, LOW)
|
||||
*/
|
||||
private String priority;
|
||||
|
||||
/**
|
||||
* 관련 회의록 섹션
|
||||
*/
|
||||
private String sectionReference;
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
package com.unicorn.hgzero.ai.biz.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 처리된 회의록 도메인 모델
|
||||
* AI가 처리한 회의록 정보를 담는 도메인 객체
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ProcessedTranscript {
|
||||
|
||||
/**
|
||||
* 회의록 ID
|
||||
*/
|
||||
private String transcriptId;
|
||||
|
||||
/**
|
||||
* 회의 ID
|
||||
*/
|
||||
private String meetingId;
|
||||
|
||||
/**
|
||||
* 전체 요약
|
||||
*/
|
||||
private String summary;
|
||||
|
||||
/**
|
||||
* 논의사항 목록
|
||||
*/
|
||||
private List<DiscussionItem> discussions;
|
||||
|
||||
/**
|
||||
* 결정사항 목록
|
||||
*/
|
||||
private List<DecisionItem> decisions;
|
||||
|
||||
/**
|
||||
* 보류사항 목록
|
||||
*/
|
||||
private List<String> pendingItems;
|
||||
|
||||
/**
|
||||
* 생성 시간
|
||||
*/
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 상태 (DRAFT, COMPLETED)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 논의사항 아이템
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class DiscussionItem {
|
||||
private String topic;
|
||||
private String speaker;
|
||||
private String content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 결정사항 아이템
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class DecisionItem {
|
||||
private String content;
|
||||
private String decisionMaker;
|
||||
private String category;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.unicorn.hgzero.ai.biz.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 관련 회의록 도메인 모델
|
||||
* RAG 검색으로 찾은 관련 회의록 정보
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RelatedMinutes {
|
||||
|
||||
/**
|
||||
* 회의록 ID
|
||||
*/
|
||||
private String transcriptId;
|
||||
|
||||
/**
|
||||
* 회의 제목
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 회의 날짜
|
||||
*/
|
||||
private LocalDate date;
|
||||
|
||||
/**
|
||||
* 참석자 목록
|
||||
*/
|
||||
private List<String> participants;
|
||||
|
||||
/**
|
||||
* 관련도 점수 (0-100)
|
||||
*/
|
||||
private Double relevanceScore;
|
||||
|
||||
/**
|
||||
* 공통 키워드 목록
|
||||
*/
|
||||
private List<String> commonKeywords;
|
||||
|
||||
/**
|
||||
* 회의록 링크
|
||||
*/
|
||||
private String link;
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
package com.unicorn.hgzero.ai.biz.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 제안사항 도메인 모델
|
||||
* AI가 제안하는 논의사항 또는 결정사항
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Suggestion {
|
||||
|
||||
/**
|
||||
* 제안 ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 제안 유형 (DISCUSSION, DECISION)
|
||||
*/
|
||||
private SuggestionType type;
|
||||
|
||||
/**
|
||||
* 제안 내용
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 우선순위 (HIGH, MEDIUM, LOW)
|
||||
*/
|
||||
private String priority;
|
||||
|
||||
/**
|
||||
* 제안 이유
|
||||
*/
|
||||
private String reason;
|
||||
|
||||
/**
|
||||
* 신뢰도 점수 (0-1)
|
||||
*/
|
||||
private Double confidence;
|
||||
|
||||
/**
|
||||
* 관련 안건
|
||||
*/
|
||||
private String relatedAgenda;
|
||||
|
||||
/**
|
||||
* 예상 소요 시간 (분)
|
||||
*/
|
||||
private Integer estimatedTime;
|
||||
|
||||
/**
|
||||
* 참여자 목록 (결정사항인 경우)
|
||||
*/
|
||||
private List<String> participants;
|
||||
|
||||
/**
|
||||
* 카테고리 (결정사항인 경우: 기술, 일정, 리소스, 정책, 기타)
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 원문 발췌 (결정사항인 경우)
|
||||
*/
|
||||
private String extractedFrom;
|
||||
|
||||
/**
|
||||
* 배경 설명 (결정사항인 경우)
|
||||
*/
|
||||
private String context;
|
||||
|
||||
/**
|
||||
* 제안 유형
|
||||
*/
|
||||
public enum SuggestionType {
|
||||
DISCUSSION, // 논의사항
|
||||
DECISION // 결정사항
|
||||
}
|
||||
}
|
||||
54
ai/src/main/java/com/unicorn/hgzero/ai/biz/domain/Term.java
Normal file
54
ai/src/main/java/com/unicorn/hgzero/ai/biz/domain/Term.java
Normal file
@ -0,0 +1,54 @@
|
||||
package com.unicorn.hgzero.ai.biz.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 전문용어 도메인 모델
|
||||
* 회의록에서 감지된 전문용어 정보
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Term {
|
||||
|
||||
/**
|
||||
* 용어명
|
||||
*/
|
||||
private String term;
|
||||
|
||||
/**
|
||||
* 텍스트 위치 정보
|
||||
*/
|
||||
private TextPosition position;
|
||||
|
||||
/**
|
||||
* 신뢰도 점수 (0-1)
|
||||
*/
|
||||
private Double confidence;
|
||||
|
||||
/**
|
||||
* 용어 카테고리 (기술, 업무, 도메인)
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 하이라이트 여부
|
||||
*/
|
||||
private Boolean highlight;
|
||||
|
||||
/**
|
||||
* 텍스트 위치
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class TextPosition {
|
||||
private Integer line;
|
||||
private Integer offset;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.unicorn.hgzero.ai.biz.gateway;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* LLM Gateway 인터페이스
|
||||
* OpenAI API 연동을 추상화
|
||||
*/
|
||||
public interface LlmGateway {
|
||||
|
||||
/**
|
||||
* 회의록 자동 작성 (LLM 기반)
|
||||
*
|
||||
* @param transcriptText STT 변환 텍스트
|
||||
* @param title 회의 제목
|
||||
* @param participants 참석자 목록
|
||||
* @param agenda 회의 안건
|
||||
* @return LLM 생성 회의록 (JSON 형식)
|
||||
*/
|
||||
String generateTranscript(String transcriptText, String title, List<String> participants, List<String> agenda);
|
||||
|
||||
/**
|
||||
* Todo 추출 (LLM 기반)
|
||||
*
|
||||
* @param minutesContent 회의록 내용
|
||||
* @return 추출된 Todo JSON
|
||||
*/
|
||||
String extractTodos(String minutesContent);
|
||||
|
||||
/**
|
||||
* 섹션 요약 생성 (LLM 기반)
|
||||
*
|
||||
* @param sectionContent 섹션 내용
|
||||
* @param meetingContext 회의 맥락
|
||||
* @return 생성된 요약 (2-3문장)
|
||||
*/
|
||||
String generateSummary(String sectionContent, String meetingContext);
|
||||
|
||||
/**
|
||||
* 전문용어 감지 (LLM 기반)
|
||||
*
|
||||
* @param text 분석할 텍스트
|
||||
* @param organizationId 조직 ID
|
||||
* @return 감지된 용어 JSON
|
||||
*/
|
||||
String detectTerms(String text, String organizationId);
|
||||
|
||||
/**
|
||||
* 논의사항 제안 (LLM 기반)
|
||||
*
|
||||
* @param transcriptText 현재 회의록 텍스트
|
||||
* @param agenda 회의 안건
|
||||
* @return 논의사항 제안 JSON
|
||||
*/
|
||||
String suggestDiscussions(String transcriptText, List<String> agenda);
|
||||
|
||||
/**
|
||||
* 결정사항 제안 (LLM 기반)
|
||||
*
|
||||
* @param transcriptText 현재 회의록 텍스트
|
||||
* @return 결정사항 제안 JSON
|
||||
*/
|
||||
String suggestDecisions(String transcriptText);
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.unicorn.hgzero.ai.biz.gateway;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* RAG 검색 Gateway 인터페이스
|
||||
* Azure AI Search 연동을 추상화
|
||||
*/
|
||||
public interface SearchGateway {
|
||||
|
||||
/**
|
||||
* 관련 회의록 검색 (벡터 유사도 기반)
|
||||
*
|
||||
* @param meetingId 회의 ID
|
||||
* @param transcriptId 회의록 ID
|
||||
* @param limit 최대 개수
|
||||
* @return 관련 회의록 JSON
|
||||
*/
|
||||
String searchRelatedTranscripts(String meetingId, String transcriptId, int limit);
|
||||
|
||||
/**
|
||||
* 용어 설명을 위한 문서 검색
|
||||
*
|
||||
* @param term 용어명
|
||||
* @param meetingId 회의 ID
|
||||
* @param context 맥락
|
||||
* @return 관련 문서 JSON
|
||||
*/
|
||||
String searchTermExplanation(String term, String meetingId, String context);
|
||||
|
||||
/**
|
||||
* 회의록 인덱싱 (벡터 임베딩 저장)
|
||||
*
|
||||
* @param transcriptId 회의록 ID
|
||||
* @param content 회의록 내용
|
||||
* @param metadata 메타데이터
|
||||
*/
|
||||
void indexTranscript(String transcriptId, String content, String metadata);
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
package com.unicorn.hgzero.ai.biz.gateway;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.ProcessedTranscript;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 회의록 데이터 Gateway 인터페이스
|
||||
* 회의록 영속성 관리를 추상화
|
||||
*/
|
||||
public interface TranscriptGateway {
|
||||
|
||||
/**
|
||||
* 회의록 저장
|
||||
*
|
||||
* @param transcript 처리된 회의록
|
||||
* @return 저장된 회의록
|
||||
*/
|
||||
ProcessedTranscript save(ProcessedTranscript transcript);
|
||||
|
||||
/**
|
||||
* 회의록 ID로 조회
|
||||
*
|
||||
* @param transcriptId 회의록 ID
|
||||
* @return 회의록 (Optional)
|
||||
*/
|
||||
Optional<ProcessedTranscript> findById(String transcriptId);
|
||||
|
||||
/**
|
||||
* 회의 ID로 조회
|
||||
*
|
||||
* @param meetingId 회의 ID
|
||||
* @return 회의록 (Optional)
|
||||
*/
|
||||
Optional<ProcessedTranscript> findByMeetingId(String meetingId);
|
||||
|
||||
/**
|
||||
* 회의 ID 목록으로 조회
|
||||
*
|
||||
* @param meetingIds 회의 ID 목록
|
||||
* @return 회의록 목록
|
||||
*/
|
||||
List<ProcessedTranscript> findByMeetingIds(List<String> meetingIds);
|
||||
|
||||
/**
|
||||
* 상태로 조회
|
||||
*
|
||||
* @param status 상태
|
||||
* @return 회의록 목록
|
||||
*/
|
||||
List<ProcessedTranscript> findByStatus(String status);
|
||||
|
||||
/**
|
||||
* 회의록 존재 여부 확인
|
||||
*
|
||||
* @param meetingId 회의 ID
|
||||
* @return 존재 여부
|
||||
*/
|
||||
boolean existsByMeetingId(String meetingId);
|
||||
|
||||
/**
|
||||
* 회의록 삭제
|
||||
*
|
||||
* @param transcriptId 회의록 ID
|
||||
*/
|
||||
void delete(String transcriptId);
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package com.unicorn.hgzero.ai.biz.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.unicorn.hgzero.ai.biz.domain.RelatedMinutes;
|
||||
import com.unicorn.hgzero.ai.biz.gateway.SearchGateway;
|
||||
import com.unicorn.hgzero.ai.biz.usecase.RelatedTranscriptSearchUseCase;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 관련 회의록 검색 Service
|
||||
* RAG 기반 벡터 유사도 검색
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RelatedTranscriptSearchService implements RelatedTranscriptSearchUseCase {
|
||||
|
||||
private final SearchGateway searchGateway;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
public List<RelatedMinutes> findRelatedTranscripts(String meetingId, String transcriptId, int limit) {
|
||||
log.info("Searching related transcripts: meetingId={}, transcriptId={}, limit={}",
|
||||
meetingId, transcriptId, limit);
|
||||
|
||||
// RAG 검색
|
||||
String searchResult = searchGateway.searchRelatedTranscripts(meetingId, transcriptId, limit);
|
||||
|
||||
// TODO: JSON 파싱 및 RelatedMinutes 리스트 생성
|
||||
// 현재는 mock 데이터 반환
|
||||
return List.of(
|
||||
RelatedMinutes.builder()
|
||||
.transcriptId("aa0e8400-e29b-41d4-a716-446655440005")
|
||||
.title("프로젝트 X 주간 회의")
|
||||
.date(LocalDate.of(2025, 1, 15))
|
||||
.participants(List.of("김철수", "이영희"))
|
||||
.relevanceScore(85.5)
|
||||
.commonKeywords(List.of("MSA", "API Gateway", "Spring Boot"))
|
||||
.link("/transcripts/aa0e8400-e29b-41d4-a716-446655440005")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.unicorn.hgzero.ai.biz.service;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.gateway.LlmGateway;
|
||||
import com.unicorn.hgzero.ai.biz.usecase.SectionSummaryUseCase;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 섹션 AI 요약 재생성 Service
|
||||
* LLM 기반 섹션 요약 생성
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SectionSummaryService implements SectionSummaryUseCase {
|
||||
|
||||
private final LlmGateway llmGateway;
|
||||
|
||||
@Override
|
||||
public String regenerateSummary(String sectionId, String sectionContent, String meetingId) {
|
||||
log.info("Regenerating section summary: sectionId={}, meetingId={}", sectionId, meetingId);
|
||||
|
||||
// LLM을 통한 요약 생성
|
||||
String meetingContext = meetingId != null ? "회의 ID: " + meetingId : "";
|
||||
return llmGateway.generateSummary(sectionContent, meetingContext);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.unicorn.hgzero.ai.biz.service;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.Suggestion;
|
||||
import com.unicorn.hgzero.ai.biz.gateway.LlmGateway;
|
||||
import com.unicorn.hgzero.ai.biz.usecase.SuggestionUseCase;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 논의사항/결정사항 제안 Service
|
||||
* LLM 기반 실시간 회의 제안
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SuggestionService implements SuggestionUseCase {
|
||||
|
||||
private final LlmGateway llmGateway;
|
||||
|
||||
@Override
|
||||
public List<Suggestion> suggestDiscussions(String meetingId, String transcriptText) {
|
||||
log.info("Suggesting discussions: meetingId={}", meetingId);
|
||||
|
||||
// TODO: 회의 안건 조회
|
||||
List<String> agenda = List.of();
|
||||
|
||||
// LLM을 통한 논의사항 제안
|
||||
String llmResponse = llmGateway.suggestDiscussions(transcriptText, agenda);
|
||||
|
||||
// TODO: JSON 파싱 및 Suggestion 리스트 생성
|
||||
return List.of(
|
||||
Suggestion.builder()
|
||||
.id("sugg-001")
|
||||
.type(Suggestion.SuggestionType.DISCUSSION)
|
||||
.content("보안 요구사항 검토")
|
||||
.priority("HIGH")
|
||||
.reason("안건에 포함되어 있으나 아직 논의되지 않음")
|
||||
.confidence(0.9)
|
||||
.relatedAgenda("프로젝트 개요")
|
||||
.estimatedTime(15)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Suggestion> suggestDecisions(String meetingId, String transcriptText) {
|
||||
log.info("Suggesting decisions: meetingId={}", meetingId);
|
||||
|
||||
// LLM을 통한 결정사항 제안
|
||||
String llmResponse = llmGateway.suggestDecisions(transcriptText);
|
||||
|
||||
// TODO: JSON 파싱 및 Suggestion 리스트 생성
|
||||
return List.of(
|
||||
Suggestion.builder()
|
||||
.id("dec-001")
|
||||
.type(Suggestion.SuggestionType.DECISION)
|
||||
.content("React로 프론트엔드 개발")
|
||||
.category("기술")
|
||||
.participants(List.of("김철수", "이영희"))
|
||||
.confidence(0.85)
|
||||
.extractedFrom("프론트엔드는 React로 개발하기로 했습니다")
|
||||
.context("팀원 대부분이 React 경험이 있어 개발 속도가 빠를 것으로 예상")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.unicorn.hgzero.ai.biz.service;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.Term;
|
||||
import com.unicorn.hgzero.ai.biz.gateway.LlmGateway;
|
||||
import com.unicorn.hgzero.ai.biz.usecase.TermDetectionUseCase;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 전문용어 감지 Service
|
||||
* LLM 기반 전문용어 자동 감지
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class TermDetectionService implements TermDetectionUseCase {
|
||||
|
||||
private final LlmGateway llmGateway;
|
||||
|
||||
@Override
|
||||
public List<Term> detectTerms(String meetingId, String text, String organizationId) {
|
||||
log.info("Detecting terms: meetingId={}, organizationId={}", meetingId, organizationId);
|
||||
|
||||
// LLM을 통한 전문용어 감지
|
||||
String llmResponse = llmGateway.detectTerms(text, organizationId);
|
||||
|
||||
// TODO: JSON 파싱 및 Term 리스트 생성
|
||||
// 현재는 mock 데이터 반환
|
||||
return List.of(
|
||||
Term.builder()
|
||||
.term("MSA")
|
||||
.position(Term.TextPosition.builder().line(5).offset(42).build())
|
||||
.confidence(0.92)
|
||||
.category("기술")
|
||||
.highlight(true)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package com.unicorn.hgzero.ai.biz.service;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.gateway.SearchGateway;
|
||||
import com.unicorn.hgzero.ai.biz.usecase.TermExplanationUseCase;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 전문용어 설명 Service
|
||||
* RAG 기반 맥락적 용어 설명 생성
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class TermExplanationService implements TermExplanationUseCase {
|
||||
|
||||
private final SearchGateway searchGateway;
|
||||
|
||||
@Override
|
||||
public TermExplanationResult explainTerm(String term, String meetingId, String context) {
|
||||
log.info("Explaining term: term={}, meetingId={}", term, meetingId);
|
||||
|
||||
// RAG 검색
|
||||
String searchResult = searchGateway.searchTermExplanation(term, meetingId, context);
|
||||
|
||||
// TODO: JSON 파싱 및 TermExplanationResult 생성
|
||||
// 현재는 mock 데이터 반환
|
||||
return new TermExplanationResult(
|
||||
"MSA",
|
||||
"Microservices Architecture의 약자",
|
||||
"이번 프로젝트에서는 확장성과 독립 배포를 위해 MSA를 적용하기로 결정",
|
||||
List.of(
|
||||
"2024년 프로젝트 X에서 주문/결제/배송 서비스를 독립적으로 구성",
|
||||
"서비스별 독립 배포로 배포 시간 70% 단축"
|
||||
),
|
||||
List.of(new RelatedProject("프로젝트 X", "동일한 MSA 아키텍처 적용")),
|
||||
List.of(new PastDiscussion(
|
||||
LocalDate.of(2024, 12, 15),
|
||||
List.of("김철수", "이영희"),
|
||||
"MSA 아키텍처의 장단점을 비교하고 적용 방안을 논의",
|
||||
"/transcripts/bb0e8400-e29b-41d4-a716-446655440006"
|
||||
)),
|
||||
List.of(new Reference(
|
||||
"MSA 아키텍처 가이드",
|
||||
"위키",
|
||||
"https://wiki.example.com/msa-guide"
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package com.unicorn.hgzero.ai.biz.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.unicorn.hgzero.ai.biz.domain.ExtractedTodo;
|
||||
import com.unicorn.hgzero.ai.biz.gateway.LlmGateway;
|
||||
import com.unicorn.hgzero.ai.biz.usecase.TodoExtractionUseCase;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Todo 자동 추출 Service
|
||||
* LLM 기반 액션 아이템 추출
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class TodoExtractionService implements TodoExtractionUseCase {
|
||||
|
||||
private final LlmGateway llmGateway;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
public List<ExtractedTodo> extractTodos(String meetingId, String minutesContent, String userId) {
|
||||
log.info("Extracting todos from minutes: meetingId={}, userId={}", meetingId, userId);
|
||||
|
||||
// LLM을 통한 Todo 추출
|
||||
String llmResponse = llmGateway.extractTodos(minutesContent);
|
||||
|
||||
// TODO: JSON 파싱 및 ExtractedTodo 리스트 생성
|
||||
// 현재는 mock 데이터 반환
|
||||
return List.of(
|
||||
ExtractedTodo.builder()
|
||||
.content("API 설계서 작성")
|
||||
.assignee("박민수")
|
||||
.dueDate(LocalDate.of(2025, 1, 30))
|
||||
.priority("HIGH")
|
||||
.sectionReference("결정사항 #3")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,180 @@
|
||||
package com.unicorn.hgzero.ai.biz.service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.unicorn.hgzero.ai.biz.domain.ProcessedTranscript;
|
||||
import com.unicorn.hgzero.ai.biz.gateway.LlmGateway;
|
||||
import com.unicorn.hgzero.ai.biz.gateway.SearchGateway;
|
||||
import com.unicorn.hgzero.ai.biz.gateway.TranscriptGateway;
|
||||
import com.unicorn.hgzero.ai.biz.usecase.TranscriptProcessUseCase;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 회의록 자동 작성 Service
|
||||
* LLM 기반 회의록 생성 및 저장
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class TranscriptProcessService implements TranscriptProcessUseCase {
|
||||
|
||||
private final LlmGateway llmGateway;
|
||||
private final SearchGateway searchGateway;
|
||||
private final TranscriptGateway transcriptGateway;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ProcessedTranscript processTranscript(
|
||||
String meetingId,
|
||||
String transcriptText,
|
||||
String userId,
|
||||
String userName,
|
||||
String title,
|
||||
List<String> participants,
|
||||
List<String> agenda
|
||||
) {
|
||||
log.info("Processing transcript for meeting: meetingId={}, userId={}", meetingId, userId);
|
||||
|
||||
// 1. LLM을 통한 회의록 자동 생성
|
||||
String llmResponse = llmGateway.generateTranscript(transcriptText, title, participants, agenda);
|
||||
log.debug("LLM response received: length={}", llmResponse.length());
|
||||
|
||||
// 2. LLM 응답 파싱
|
||||
ProcessedTranscript processedTranscript = parseTranscriptFromLlm(llmResponse, meetingId);
|
||||
|
||||
// 3. 회의록 저장
|
||||
ProcessedTranscript saved = transcriptGateway.save(processedTranscript);
|
||||
log.info("Transcript saved: transcriptId={}, meetingId={}", saved.getTranscriptId(), meetingId);
|
||||
|
||||
// 4. RAG 인덱싱 (비동기 처리 고려)
|
||||
indexTranscriptForSearch(saved);
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ProcessedTranscript getTranscript(String transcriptId) {
|
||||
log.debug("Retrieving transcript: transcriptId={}", transcriptId);
|
||||
return transcriptGateway.findById(transcriptId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Transcript not found: " + transcriptId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ProcessedTranscript getTranscriptByMeetingId(String meetingId) {
|
||||
log.debug("Retrieving transcript by meetingId: {}", meetingId);
|
||||
return transcriptGateway.findByMeetingId(meetingId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Transcript not found for meeting: " + meetingId));
|
||||
}
|
||||
|
||||
/**
|
||||
* LLM 응답을 ProcessedTranscript 도메인으로 파싱
|
||||
*/
|
||||
private ProcessedTranscript parseTranscriptFromLlm(String llmResponse, String meetingId) {
|
||||
try {
|
||||
JsonNode root = objectMapper.readTree(llmResponse);
|
||||
|
||||
// Discussions 파싱
|
||||
List<ProcessedTranscript.DiscussionItem> discussions = new ArrayList<>();
|
||||
if (root.has("discussions")) {
|
||||
root.get("discussions").forEach(node -> {
|
||||
discussions.add(ProcessedTranscript.DiscussionItem.builder()
|
||||
.topic(node.get("topic").asText())
|
||||
.speaker(node.get("speaker").asText())
|
||||
.content(node.get("content").asText())
|
||||
.build());
|
||||
});
|
||||
}
|
||||
|
||||
// Decisions 파싱
|
||||
List<ProcessedTranscript.DecisionItem> decisions = new ArrayList<>();
|
||||
if (root.has("decisions")) {
|
||||
root.get("decisions").forEach(node -> {
|
||||
decisions.add(ProcessedTranscript.DecisionItem.builder()
|
||||
.content(node.get("content").asText())
|
||||
.decisionMaker(node.get("decisionMaker").asText())
|
||||
.category(node.get("category").asText())
|
||||
.build());
|
||||
});
|
||||
}
|
||||
|
||||
// Pending items 파싱
|
||||
List<String> pendingItems = new ArrayList<>();
|
||||
if (root.has("pendingItems")) {
|
||||
root.get("pendingItems").forEach(node -> pendingItems.add(node.asText()));
|
||||
}
|
||||
|
||||
return ProcessedTranscript.builder()
|
||||
.transcriptId(UUID.randomUUID().toString())
|
||||
.meetingId(meetingId)
|
||||
.summary(root.has("summary") ? root.get("summary").asText() : "")
|
||||
.discussions(discussions)
|
||||
.decisions(decisions)
|
||||
.pendingItems(pendingItems)
|
||||
.createdAt(LocalDateTime.now())
|
||||
.status("DRAFT")
|
||||
.build();
|
||||
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("Failed to parse LLM response: {}", llmResponse, e);
|
||||
throw new RuntimeException("Failed to parse transcript from LLM", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RAG 검색을 위한 회의록 인덱싱
|
||||
*/
|
||||
private void indexTranscriptForSearch(ProcessedTranscript transcript) {
|
||||
try {
|
||||
String content = buildSearchableContent(transcript);
|
||||
String metadata = buildMetadata(transcript);
|
||||
|
||||
searchGateway.indexTranscript(transcript.getTranscriptId(), content, metadata);
|
||||
log.debug("Transcript indexed for search: transcriptId={}", transcript.getTranscriptId());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to index transcript for search: transcriptId={}",
|
||||
transcript.getTranscriptId(), e);
|
||||
// 인덱싱 실패는 치명적이지 않으므로 예외를 전파하지 않음
|
||||
}
|
||||
}
|
||||
|
||||
private String buildSearchableContent(ProcessedTranscript transcript) {
|
||||
StringBuilder content = new StringBuilder();
|
||||
content.append(transcript.getSummary()).append("\n\n");
|
||||
|
||||
if (transcript.getDiscussions() != null) {
|
||||
transcript.getDiscussions().forEach(d ->
|
||||
content.append(d.getTopic()).append(": ").append(d.getContent()).append("\n")
|
||||
);
|
||||
}
|
||||
|
||||
if (transcript.getDecisions() != null) {
|
||||
transcript.getDecisions().forEach(d ->
|
||||
content.append("결정: ").append(d.getContent()).append("\n")
|
||||
);
|
||||
}
|
||||
|
||||
return content.toString();
|
||||
}
|
||||
|
||||
private String buildMetadata(ProcessedTranscript transcript) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(transcript);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.warn("Failed to serialize transcript metadata", e);
|
||||
return "{}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.unicorn.hgzero.ai.biz.usecase;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.RelatedMinutes;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 관련 회의록 검색 UseCase
|
||||
* RAG 기반 벡터 유사도 검색으로 관련 회의록 조회
|
||||
*/
|
||||
public interface RelatedTranscriptSearchUseCase {
|
||||
|
||||
/**
|
||||
* 관련 회의록 검색
|
||||
*
|
||||
* @param meetingId 회의 ID
|
||||
* @param transcriptId 회의록 ID
|
||||
* @param limit 반환할 최대 개수
|
||||
* @return 관련 회의록 목록
|
||||
*/
|
||||
List<RelatedMinutes> findRelatedTranscripts(String meetingId, String transcriptId, int limit);
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.unicorn.hgzero.ai.biz.usecase;
|
||||
|
||||
/**
|
||||
* 섹션 AI 요약 재생성 UseCase
|
||||
* 사용자가 작성한 섹션 내용을 기반으로 AI 요약 재생성
|
||||
*/
|
||||
public interface SectionSummaryUseCase {
|
||||
|
||||
/**
|
||||
* 섹션 요약 재생성
|
||||
*
|
||||
* @param sectionId 섹션 ID
|
||||
* @param sectionContent 섹션 내용 (Markdown 형식)
|
||||
* @param meetingId 회의 ID (선택적, 맥락 이해용)
|
||||
* @return 생성된 AI 요약 (2-3문장)
|
||||
*/
|
||||
String regenerateSummary(String sectionId, String sectionContent, String meetingId);
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.unicorn.hgzero.ai.biz.usecase;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.Suggestion;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 논의사항/결정사항 제안 UseCase
|
||||
* AI 기반 실시간 회의 제안 기능
|
||||
*/
|
||||
public interface SuggestionUseCase {
|
||||
|
||||
/**
|
||||
* 논의사항 제안
|
||||
*
|
||||
* @param meetingId 회의 ID
|
||||
* @param transcriptText 현재까지의 회의록 텍스트
|
||||
* @return 논의사항 제안 목록
|
||||
*/
|
||||
List<Suggestion> suggestDiscussions(String meetingId, String transcriptText);
|
||||
|
||||
/**
|
||||
* 결정사항 제안
|
||||
*
|
||||
* @param meetingId 회의 ID
|
||||
* @param transcriptText 현재까지의 회의록 텍스트
|
||||
* @return 결정사항 제안 목록
|
||||
*/
|
||||
List<Suggestion> suggestDecisions(String meetingId, String transcriptText);
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.unicorn.hgzero.ai.biz.usecase;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.Term;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 전문용어 감지 UseCase
|
||||
* 회의록 텍스트에서 전문용어를 자동으로 감지
|
||||
*/
|
||||
public interface TermDetectionUseCase {
|
||||
|
||||
/**
|
||||
* 전문용어 감지
|
||||
*
|
||||
* @param meetingId 회의 ID
|
||||
* @param text 분석할 회의록 텍스트
|
||||
* @param organizationId 조직 ID
|
||||
* @return 감지된 전문용어 목록
|
||||
*/
|
||||
List<Term> detectTerms(String meetingId, String text, String organizationId);
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.unicorn.hgzero.ai.biz.usecase;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 전문용어 설명 UseCase
|
||||
* RAG 기반 맥락적 용어 설명 생성
|
||||
*/
|
||||
public interface TermExplanationUseCase {
|
||||
|
||||
/**
|
||||
* 용어 설명 생성
|
||||
*
|
||||
* @param term 용어명
|
||||
* @param meetingId 회의 ID
|
||||
* @param context 현재 회의 맥락 (선택)
|
||||
* @return 용어 설명 결과
|
||||
*/
|
||||
TermExplanationResult explainTerm(String term, String meetingId, String context);
|
||||
|
||||
/**
|
||||
* 용어 설명 결과
|
||||
*/
|
||||
record TermExplanationResult(
|
||||
String term,
|
||||
String basicDefinition,
|
||||
String contextualMeaning,
|
||||
List<String> useCases,
|
||||
List<RelatedProject> relatedProjects,
|
||||
List<PastDiscussion> pastDiscussions,
|
||||
List<Reference> references
|
||||
) {}
|
||||
|
||||
record RelatedProject(String name, String relevance) {}
|
||||
record PastDiscussion(java.time.LocalDate date, List<String> participants, String summary, String link) {}
|
||||
record Reference(String title, String type, String link) {}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.unicorn.hgzero.ai.biz.usecase;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.ExtractedTodo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Todo 자동 추출 UseCase
|
||||
* 회의록에서 액션 아이템을 자동으로 추출하고 담당자 식별
|
||||
*/
|
||||
public interface TodoExtractionUseCase {
|
||||
|
||||
/**
|
||||
* 회의록에서 Todo 추출
|
||||
*
|
||||
* @param meetingId 회의 ID
|
||||
* @param minutesContent 회의록 전체 내용 (Markdown 형식)
|
||||
* @param userId 요청자 ID
|
||||
* @return 추출된 Todo 목록
|
||||
*/
|
||||
List<ExtractedTodo> extractTodos(String meetingId, String minutesContent, String userId);
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package com.unicorn.hgzero.ai.biz.usecase;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.ProcessedTranscript;
|
||||
|
||||
/**
|
||||
* 회의록 자동 작성 UseCase
|
||||
* STT에서 변환된 텍스트를 받아 LLM 기반으로 회의록 자동 작성
|
||||
*/
|
||||
public interface TranscriptProcessUseCase {
|
||||
|
||||
/**
|
||||
* 회의록 자동 작성
|
||||
*
|
||||
* @param meetingId 회의 ID
|
||||
* @param transcriptText STT에서 변환된 텍스트
|
||||
* @param userId 사용자 ID
|
||||
* @param userName 사용자 이름
|
||||
* @param title 회의 제목
|
||||
* @param participants 참석자 목록
|
||||
* @param agenda 회의 안건
|
||||
* @return 처리된 회의록
|
||||
*/
|
||||
ProcessedTranscript processTranscript(
|
||||
String meetingId,
|
||||
String transcriptText,
|
||||
String userId,
|
||||
String userName,
|
||||
String title,
|
||||
java.util.List<String> participants,
|
||||
java.util.List<String> agenda
|
||||
);
|
||||
|
||||
/**
|
||||
* 회의록 조회
|
||||
*
|
||||
* @param transcriptId 회의록 ID
|
||||
* @return 처리된 회의록
|
||||
*/
|
||||
ProcessedTranscript getTranscript(String transcriptId);
|
||||
|
||||
/**
|
||||
* 회의 ID로 회의록 조회
|
||||
*
|
||||
* @param meetingId 회의 ID
|
||||
* @return 처리된 회의록
|
||||
*/
|
||||
ProcessedTranscript getTranscriptByMeetingId(String meetingId);
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
package com.unicorn.hgzero.ai.infra.config;
|
||||
|
||||
import com.unicorn.hgzero.common.security.JwtTokenProvider;
|
||||
import com.unicorn.hgzero.common.security.filter.JwtAuthenticationFilter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Spring Security 설정
|
||||
* JWT 기반 인증 및 API 보안 설정
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@RequiredArgsConstructor
|
||||
public class SecurityConfig {
|
||||
|
||||
private final JwtTokenProvider jwtTokenProvider;
|
||||
|
||||
@Value("${cors.allowed-origins:http://localhost:3000,http://localhost:8080,http://localhost:8081,http://localhost:8082,http://localhost:8083,http://localhost:8084}")
|
||||
private String allowedOrigins;
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
// Actuator endpoints
|
||||
.requestMatchers("/actuator/**").permitAll()
|
||||
// Swagger UI endpoints - context path와 상관없이 접근 가능하도록 설정
|
||||
.requestMatchers("/swagger-ui/**", "/swagger-ui.html", "/v3/api-docs/**", "/swagger-resources/**", "/webjars/**").permitAll()
|
||||
// Health check
|
||||
.requestMatchers("/health").permitAll()
|
||||
// All other requests require authentication
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider),
|
||||
UsernamePasswordAuthenticationFilter.class)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
|
||||
// 환경변수에서 허용할 Origin 패턴 설정
|
||||
String[] origins = allowedOrigins.split(",");
|
||||
configuration.setAllowedOriginPatterns(Arrays.asList(origins));
|
||||
|
||||
// 허용할 HTTP 메소드
|
||||
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
|
||||
|
||||
// 허용할 헤더
|
||||
configuration.setAllowedHeaders(Arrays.asList(
|
||||
"Authorization", "Content-Type", "X-Requested-With", "Accept",
|
||||
"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers",
|
||||
"X-User-Id", "X-User-Name"
|
||||
));
|
||||
|
||||
// 자격 증명 허용
|
||||
configuration.setAllowCredentials(true);
|
||||
|
||||
// Pre-flight 요청 캐시 시간
|
||||
configuration.setMaxAge(3600L);
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
return source;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package com.unicorn.hgzero.ai.infra.config;
|
||||
|
||||
import io.swagger.v3.oas.models.Components;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Contact;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
import io.swagger.v3.oas.models.servers.Server;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Swagger/OpenAPI 설정
|
||||
* AI Service API 문서화를 위한 설정
|
||||
*/
|
||||
@Configuration
|
||||
public class SwaggerConfig {
|
||||
|
||||
@Bean
|
||||
public OpenAPI openAPI() {
|
||||
return new OpenAPI()
|
||||
.info(apiInfo())
|
||||
.addServersItem(new Server()
|
||||
.url("http://localhost:8083")
|
||||
.description("Local Development"))
|
||||
.addServersItem(new Server()
|
||||
.url("{protocol}://{host}:{port}")
|
||||
.description("Custom Server")
|
||||
.variables(new io.swagger.v3.oas.models.servers.ServerVariables()
|
||||
.addServerVariable("protocol", new io.swagger.v3.oas.models.servers.ServerVariable()
|
||||
._default("http")
|
||||
.description("Protocol (http or https)")
|
||||
.addEnumItem("http")
|
||||
.addEnumItem("https"))
|
||||
.addServerVariable("host", new io.swagger.v3.oas.models.servers.ServerVariable()
|
||||
._default("localhost")
|
||||
.description("Server host"))
|
||||
.addServerVariable("port", new io.swagger.v3.oas.models.servers.ServerVariable()
|
||||
._default("8083")
|
||||
.description("Server port"))))
|
||||
.addSecurityItem(new SecurityRequirement().addList("Bearer Authentication"))
|
||||
.components(new Components()
|
||||
.addSecuritySchemes("Bearer Authentication", createAPIKeyScheme()));
|
||||
}
|
||||
|
||||
private Info apiInfo() {
|
||||
return new Info()
|
||||
.title("AI Service API")
|
||||
.description("AI 기반 회의록 자동 작성 및 분석 서비스 API")
|
||||
.version("1.0.0")
|
||||
.contact(new Contact()
|
||||
.name("HGZero Development Team")
|
||||
.email("dev@hgzero.com"));
|
||||
}
|
||||
|
||||
private SecurityScheme createAPIKeyScheme() {
|
||||
return new SecurityScheme()
|
||||
.type(SecurityScheme.Type.HTTP)
|
||||
.bearerFormat("JWT")
|
||||
.scheme("bearer");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package com.unicorn.hgzero.ai.infra.controller;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.usecase.TermExplanationUseCase;
|
||||
import com.unicorn.hgzero.ai.infra.dto.response.TermExplanationResponse;
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.*;
|
||||
import com.unicorn.hgzero.common.dto.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 전문용어 설명 Controller
|
||||
* GET /api/terms/{term}/explain
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/terms")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Tag(name = "Term", description = "전문용어 감지 및 설명 API")
|
||||
public class ExplanationController {
|
||||
|
||||
private final TermExplanationUseCase termExplanationUseCase;
|
||||
|
||||
@GetMapping("/{term}/explain")
|
||||
@Operation(summary = "맥락 기반 용어 설명", description = "전문용어에 대한 맥락 기반 설명을 생성합니다")
|
||||
public ResponseEntity<ApiResponse<TermExplanationResponse>> explainTerm(
|
||||
@PathVariable String term,
|
||||
@RequestParam String meetingId,
|
||||
@RequestParam(required = false) String context) {
|
||||
|
||||
log.info("용어 설명 요청 - term: {}, meetingId: {}", term, meetingId);
|
||||
|
||||
TermExplanationUseCase.TermExplanationResult result = termExplanationUseCase.explainTerm(
|
||||
term,
|
||||
meetingId,
|
||||
context
|
||||
);
|
||||
|
||||
TermExplanationResponse response = TermExplanationResponse.builder()
|
||||
.term(result.term())
|
||||
.basicDefinition(result.basicDefinition())
|
||||
.contextualMeaning(result.contextualMeaning())
|
||||
.useCases(result.useCases())
|
||||
.relatedProjects(result.relatedProjects().stream()
|
||||
.map(p -> RelatedProjectDto.builder()
|
||||
.name(p.name())
|
||||
.relevance(p.relevance())
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
.pastDiscussions(result.pastDiscussions().stream()
|
||||
.map(d -> PastDiscussionDto.builder()
|
||||
.date(d.date())
|
||||
.participants(d.participants())
|
||||
.summary(d.summary())
|
||||
.link(d.link())
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
.references(result.references().stream()
|
||||
.map(r -> ReferenceDto.builder()
|
||||
.title(r.title())
|
||||
.type(r.type())
|
||||
.link(r.link())
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
.build();
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package com.unicorn.hgzero.ai.infra.controller;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.RelatedMinutes;
|
||||
import com.unicorn.hgzero.ai.biz.usecase.RelatedTranscriptSearchUseCase;
|
||||
import com.unicorn.hgzero.ai.infra.dto.response.RelatedTranscriptsResponse;
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.RelatedTranscriptDto;
|
||||
import com.unicorn.hgzero.common.dto.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 관련 회의록 조회 Controller
|
||||
* GET /api/transcripts/{meetingId}/related
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/transcripts")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Tag(name = "Relation", description = "관련 회의록 조회 API")
|
||||
public class RelationController {
|
||||
|
||||
private final RelatedTranscriptSearchUseCase relatedTranscriptSearchUseCase;
|
||||
|
||||
@GetMapping("/{meetingId}/related")
|
||||
@Operation(summary = "관련 회의록 조회", description = "벡터 유사도 검색을 통해 관련된 회의록을 찾아 반환합니다")
|
||||
public ResponseEntity<ApiResponse<RelatedTranscriptsResponse>> findRelatedTranscripts(
|
||||
@PathVariable String meetingId,
|
||||
@RequestParam String transcriptId,
|
||||
@RequestParam(defaultValue = "5") int limit) {
|
||||
|
||||
log.info("관련 회의록 조회 요청 - meetingId: {}, transcriptId: {}, limit: {}", meetingId, transcriptId, limit);
|
||||
|
||||
List<RelatedMinutes> relatedMinutes = relatedTranscriptSearchUseCase.findRelatedTranscripts(
|
||||
meetingId,
|
||||
transcriptId,
|
||||
limit
|
||||
);
|
||||
|
||||
RelatedTranscriptsResponse response = RelatedTranscriptsResponse.builder()
|
||||
.relatedTranscripts(relatedMinutes.stream()
|
||||
.map(r -> RelatedTranscriptDto.builder()
|
||||
.transcriptId(r.getTranscriptId())
|
||||
.title(r.getTitle())
|
||||
.date(r.getDate())
|
||||
.participants(r.getParticipants())
|
||||
.relevanceScore(r.getRelevanceScore())
|
||||
.commonKeywords(r.getCommonKeywords())
|
||||
.link(r.getLink())
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
.totalCount(relatedMinutes.size())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.unicorn.hgzero.ai.infra.controller;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.usecase.SectionSummaryUseCase;
|
||||
import com.unicorn.hgzero.ai.infra.dto.request.SectionSummaryRequest;
|
||||
import com.unicorn.hgzero.ai.infra.dto.response.SectionSummaryResponse;
|
||||
import com.unicorn.hgzero.common.dto.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 섹션 AI 요약 재생성 Controller
|
||||
* POST /api/sections/{sectionId}/regenerate-summary
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/sections")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Tag(name = "Section", description = "섹션 AI 요약 재생성 API")
|
||||
public class SectionController {
|
||||
|
||||
private final SectionSummaryUseCase sectionSummaryUseCase;
|
||||
|
||||
@PostMapping("/{sectionId}/regenerate-summary")
|
||||
@Operation(summary = "섹션 AI 요약 재생성", description = "사용자가 작성한 섹션 내용을 기반으로 AI 요약을 재생성합니다")
|
||||
public ResponseEntity<ApiResponse<SectionSummaryResponse>> regenerateSummary(
|
||||
@PathVariable String sectionId,
|
||||
@Valid @RequestBody SectionSummaryRequest request) {
|
||||
|
||||
log.info("섹션 요약 재생성 요청 - sectionId: {}, meetingId: {}", sectionId, request.getMeetingId());
|
||||
|
||||
String summary = sectionSummaryUseCase.regenerateSummary(
|
||||
sectionId,
|
||||
request.getSectionContent(),
|
||||
request.getMeetingId()
|
||||
);
|
||||
|
||||
SectionSummaryResponse response = SectionSummaryResponse.builder()
|
||||
.summary(summary)
|
||||
.generatedAt(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
package com.unicorn.hgzero.ai.infra.controller;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.Suggestion;
|
||||
import com.unicorn.hgzero.ai.biz.usecase.SuggestionUseCase;
|
||||
import com.unicorn.hgzero.ai.infra.dto.request.DiscussionSuggestionRequest;
|
||||
import com.unicorn.hgzero.ai.infra.dto.request.DecisionSuggestionRequest;
|
||||
import com.unicorn.hgzero.ai.infra.dto.response.DiscussionSuggestionResponse;
|
||||
import com.unicorn.hgzero.ai.infra.dto.response.DecisionSuggestionResponse;
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.DiscussionSuggestionDto;
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.DecisionSuggestionDto;
|
||||
import com.unicorn.hgzero.common.dto.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 논의사항/결정사항 제안 Controller
|
||||
* POST /api/suggestions/discussion
|
||||
* POST /api/suggestions/decision
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/suggestions")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Tag(name = "Suggestion", description = "논의사항/결정사항 제안 API")
|
||||
public class SuggestionController {
|
||||
|
||||
private final SuggestionUseCase suggestionUseCase;
|
||||
|
||||
@PostMapping("/discussion")
|
||||
@Operation(summary = "논의사항 제안", description = "현재 회의 진행 상황을 분석하여 추가로 논의하면 좋을 주제를 제안합니다")
|
||||
public ResponseEntity<ApiResponse<DiscussionSuggestionResponse>> suggestDiscussion(
|
||||
@Valid @RequestBody DiscussionSuggestionRequest request) {
|
||||
|
||||
log.info("논의사항 제안 요청 - meetingId: {}", request.getMeetingId());
|
||||
|
||||
List<Suggestion> suggestions = suggestionUseCase.suggestDiscussions(
|
||||
request.getMeetingId(),
|
||||
request.getTranscriptText()
|
||||
);
|
||||
|
||||
DiscussionSuggestionResponse response = DiscussionSuggestionResponse.builder()
|
||||
.suggestions(suggestions.stream()
|
||||
.map(s -> DiscussionSuggestionDto.builder()
|
||||
.id(s.getId())
|
||||
.topic(s.getContent())
|
||||
.reason(s.getReason())
|
||||
.priority(s.getPriority())
|
||||
.relatedAgenda(s.getRelatedAgenda())
|
||||
.estimatedTime(s.getEstimatedTime())
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
.totalCount(suggestions.size())
|
||||
.timestamp(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
|
||||
@PostMapping("/decision")
|
||||
@Operation(summary = "결정사항 제안", description = "회의록 텍스트에서 결정사항 패턴을 감지하여 제안합니다")
|
||||
public ResponseEntity<ApiResponse<DecisionSuggestionResponse>> suggestDecision(
|
||||
@Valid @RequestBody DecisionSuggestionRequest request) {
|
||||
|
||||
log.info("결정사항 제안 요청 - meetingId: {}", request.getMeetingId());
|
||||
|
||||
List<Suggestion> suggestions = suggestionUseCase.suggestDecisions(
|
||||
request.getMeetingId(),
|
||||
request.getTranscriptText()
|
||||
);
|
||||
|
||||
DecisionSuggestionResponse response = DecisionSuggestionResponse.builder()
|
||||
.suggestions(suggestions.stream()
|
||||
.map(s -> DecisionSuggestionDto.builder()
|
||||
.id(s.getId())
|
||||
.content(s.getContent())
|
||||
.category(s.getCategory())
|
||||
.decisionMaker("") // TODO: Extract from suggestion
|
||||
.participants(s.getParticipants())
|
||||
.confidence(s.getConfidence())
|
||||
.extractedFrom(s.getExtractedFrom())
|
||||
.context(s.getContext())
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
.totalCount(suggestions.size())
|
||||
.timestamp(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
package com.unicorn.hgzero.ai.infra.controller;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.Term;
|
||||
import com.unicorn.hgzero.ai.biz.usecase.TermDetectionUseCase;
|
||||
import com.unicorn.hgzero.ai.infra.dto.request.TermDetectionRequest;
|
||||
import com.unicorn.hgzero.ai.infra.dto.response.TermDetectionResponse;
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.DetectedTermDto;
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.HighlightInfoDto;
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.TextPositionDto;
|
||||
import com.unicorn.hgzero.common.dto.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 전문용어 감지 Controller
|
||||
* POST /api/terms/detect
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/terms")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Tag(name = "Term", description = "전문용어 감지 및 설명 API")
|
||||
public class TermController {
|
||||
|
||||
private final TermDetectionUseCase termDetectionUseCase;
|
||||
|
||||
@PostMapping("/detect")
|
||||
@Operation(summary = "전문용어 감지", description = "회의록 텍스트에서 전문용어를 자동으로 감지합니다")
|
||||
public ResponseEntity<ApiResponse<TermDetectionResponse>> detectTerms(
|
||||
@Valid @RequestBody TermDetectionRequest request) {
|
||||
|
||||
log.info("전문용어 감지 요청 - meetingId: {}, organizationId: {}",
|
||||
request.getMeetingId(), request.getOrganizationId());
|
||||
|
||||
List<Term> terms = termDetectionUseCase.detectTerms(
|
||||
request.getMeetingId(),
|
||||
request.getText(),
|
||||
request.getOrganizationId()
|
||||
);
|
||||
|
||||
List<DetectedTermDto> detectedTerms = terms.stream()
|
||||
.map(t -> DetectedTermDto.builder()
|
||||
.term(t.getTerm())
|
||||
.position(t.getPosition() != null ? TextPositionDto.builder()
|
||||
.line(t.getPosition().getLine())
|
||||
.offset(t.getPosition().getOffset())
|
||||
.build() : null)
|
||||
.confidence(t.getConfidence())
|
||||
.category(t.getCategory())
|
||||
.highlight(t.getHighlight())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<HighlightInfoDto> highlightInfo = detectedTerms.stream()
|
||||
.filter(t -> Boolean.TRUE.equals(t.getHighlight()))
|
||||
.map(t -> HighlightInfoDto.builder()
|
||||
.term(t.getTerm())
|
||||
.position(t.getPosition())
|
||||
.style("background-color: yellow")
|
||||
.tooltip("용어 설명 로딩 중...")
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
TermDetectionResponse response = TermDetectionResponse.builder()
|
||||
.detectedTerms(detectedTerms)
|
||||
.totalCount(detectedTerms.size())
|
||||
.highlightInfo(highlightInfo)
|
||||
.build();
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package com.unicorn.hgzero.ai.infra.controller;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.ExtractedTodo;
|
||||
import com.unicorn.hgzero.ai.biz.usecase.TodoExtractionUseCase;
|
||||
import com.unicorn.hgzero.ai.infra.dto.request.TodoExtractionRequest;
|
||||
import com.unicorn.hgzero.ai.infra.dto.response.TodoExtractionResponse;
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.ExtractedTodoDto;
|
||||
import com.unicorn.hgzero.common.dto.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Todo 자동 추출 Controller
|
||||
* POST /api/todos/extract
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/todos")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Tag(name = "Todo", description = "Todo 자동 추출 API")
|
||||
public class TodoController {
|
||||
|
||||
private final TodoExtractionUseCase todoExtractionUseCase;
|
||||
|
||||
@PostMapping("/extract")
|
||||
@Operation(summary = "Todo 자동 추출", description = "회의록에서 액션 아이템을 자동으로 추출하고 담당자를 식별합니다")
|
||||
public ResponseEntity<ApiResponse<TodoExtractionResponse>> extractTodos(
|
||||
@RequestHeader("X-User-Id") String userId,
|
||||
@Valid @RequestBody TodoExtractionRequest request) {
|
||||
|
||||
log.info("Todo 추출 요청 - meetingId: {}, userId: {}", request.getMeetingId(), userId);
|
||||
|
||||
List<ExtractedTodo> todos = todoExtractionUseCase.extractTodos(
|
||||
request.getMeetingId(),
|
||||
request.getMinutesContent(),
|
||||
request.getUserId() != null ? request.getUserId() : userId
|
||||
);
|
||||
|
||||
TodoExtractionResponse response = TodoExtractionResponse.builder()
|
||||
.meetingId(request.getMeetingId())
|
||||
.todos(todos.stream()
|
||||
.map(t -> ExtractedTodoDto.builder()
|
||||
.content(t.getContent())
|
||||
.assignee(t.getAssignee())
|
||||
.dueDate(t.getDueDate())
|
||||
.priority(t.getPriority())
|
||||
.sectionReference(t.getSectionReference())
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
.totalCount(todos.size())
|
||||
.extractedAt(LocalDateTime.now())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
package com.unicorn.hgzero.ai.infra.controller;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.ProcessedTranscript;
|
||||
import com.unicorn.hgzero.ai.biz.usecase.TranscriptProcessUseCase;
|
||||
import com.unicorn.hgzero.ai.infra.dto.request.TranscriptProcessRequest;
|
||||
import com.unicorn.hgzero.ai.infra.dto.response.TranscriptProcessResponse;
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.*;
|
||||
import com.unicorn.hgzero.common.dto.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 회의록 자동 작성 Controller
|
||||
* POST /api/transcripts/process
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/transcripts")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Tag(name = "Transcript", description = "회의록 자동 작성 API")
|
||||
public class TranscriptController {
|
||||
|
||||
private final TranscriptProcessUseCase transcriptProcessUseCase;
|
||||
|
||||
@PostMapping("/process")
|
||||
@Operation(summary = "회의록 자동 작성", description = "STT에서 변환된 텍스트를 받아 LLM 기반으로 회의록을 자동 작성합니다")
|
||||
public ResponseEntity<ApiResponse<TranscriptProcessResponse>> processTranscript(
|
||||
@RequestHeader("X-User-Id") String userId,
|
||||
@RequestHeader("X-User-Name") String userName,
|
||||
@Valid @RequestBody TranscriptProcessRequest request) {
|
||||
|
||||
log.info("회의록 자동 작성 요청 - meetingId: {}, userId: {}", request.getMeetingId(), userId);
|
||||
|
||||
ProcessedTranscript result = transcriptProcessUseCase.processTranscript(
|
||||
request.getMeetingId(),
|
||||
request.getTranscriptText(),
|
||||
request.getUserId() != null ? request.getUserId() : userId,
|
||||
request.getUserName() != null ? request.getUserName() : userName,
|
||||
request.getContext() != null ? request.getContext().getTitle() : "",
|
||||
request.getContext() != null ? request.getContext().getParticipants() : null,
|
||||
request.getContext() != null ? request.getContext().getAgenda() : null
|
||||
);
|
||||
|
||||
TranscriptProcessResponse response = mapToResponse(result);
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
}
|
||||
|
||||
private TranscriptProcessResponse mapToResponse(ProcessedTranscript domain) {
|
||||
return TranscriptProcessResponse.builder()
|
||||
.transcriptId(domain.getTranscriptId())
|
||||
.meetingId(domain.getMeetingId())
|
||||
.content(mapContent(domain))
|
||||
.suggestions(null) // TODO: 실시간 제안 기능 구현 시 추가
|
||||
.createdAt(domain.getCreatedAt())
|
||||
.status(domain.getStatus())
|
||||
.build();
|
||||
}
|
||||
|
||||
private TranscriptContentDto mapContent(ProcessedTranscript domain) {
|
||||
return TranscriptContentDto.builder()
|
||||
.summary(domain.getSummary())
|
||||
.discussions(domain.getDiscussions().stream()
|
||||
.map(d -> DiscussionItemDto.builder()
|
||||
.topic(d.getTopic())
|
||||
.speaker(d.getSpeaker())
|
||||
.content(d.getContent())
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
.decisions(domain.getDecisions().stream()
|
||||
.map(d -> DecisionItemDto.builder()
|
||||
.content(d.getContent())
|
||||
.decisionMaker(d.getDecisionMaker())
|
||||
.category(d.getCategory())
|
||||
.build())
|
||||
.collect(Collectors.toList()))
|
||||
.pendingItems(domain.getPendingItems())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 결정사항 아이템 DTO
|
||||
* 결정 내용, 결정자, 카테고리 포함
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DecisionItemDto {
|
||||
|
||||
/**
|
||||
* 결정 내용
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 결정자
|
||||
*/
|
||||
private String decisionMaker;
|
||||
|
||||
/**
|
||||
* 결정 카테고리 (기술, 일정, 리소스, 정책, 기타)
|
||||
*/
|
||||
private String category;
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 결정사항 제안 DTO
|
||||
* AI가 감지한 결정사항 패턴 정보
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DecisionSuggestionDto {
|
||||
|
||||
/**
|
||||
* 제안 ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 결정 내용
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 결정 카테고리 (기술, 일정, 리소스, 정책, 기타)
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 결정자
|
||||
*/
|
||||
private String decisionMaker;
|
||||
|
||||
/**
|
||||
* 참여자 목록
|
||||
*/
|
||||
private List<String> participants;
|
||||
|
||||
/**
|
||||
* 신뢰도 점수 (0-1)
|
||||
*/
|
||||
private Double confidence;
|
||||
|
||||
/**
|
||||
* 원문 발췌
|
||||
*/
|
||||
private String extractedFrom;
|
||||
|
||||
/**
|
||||
* 결정 배경
|
||||
*/
|
||||
private String context;
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 감지된 전문용어 DTO
|
||||
* 회의록에서 감지된 전문용어 정보
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DetectedTermDto {
|
||||
|
||||
/**
|
||||
* 용어명
|
||||
*/
|
||||
private String term;
|
||||
|
||||
/**
|
||||
* 텍스트 위치 정보
|
||||
*/
|
||||
private TextPositionDto position;
|
||||
|
||||
/**
|
||||
* 신뢰도 점수 (0-1)
|
||||
*/
|
||||
private Double confidence;
|
||||
|
||||
/**
|
||||
* 용어 카테고리 (기술, 업무, 도메인)
|
||||
*/
|
||||
private String category;
|
||||
|
||||
/**
|
||||
* 하이라이트 여부
|
||||
*/
|
||||
private Boolean highlight;
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 논의사항 아이템 DTO
|
||||
* 논의 주제, 발언자, 논의 내용 포함
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DiscussionItemDto {
|
||||
|
||||
/**
|
||||
* 논의 주제
|
||||
*/
|
||||
private String topic;
|
||||
|
||||
/**
|
||||
* 발언자
|
||||
*/
|
||||
private String speaker;
|
||||
|
||||
/**
|
||||
* 논의 내용
|
||||
*/
|
||||
private String content;
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 논의사항 제안 DTO
|
||||
* AI가 추천하는 논의 주제 정보
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DiscussionSuggestionDto {
|
||||
|
||||
/**
|
||||
* 제안 ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 논의 주제
|
||||
*/
|
||||
private String topic;
|
||||
|
||||
/**
|
||||
* 제안 이유
|
||||
*/
|
||||
private String reason;
|
||||
|
||||
/**
|
||||
* 우선순위 (HIGH, MEDIUM, LOW)
|
||||
*/
|
||||
private String priority;
|
||||
|
||||
/**
|
||||
* 관련 안건
|
||||
*/
|
||||
private String relatedAgenda;
|
||||
|
||||
/**
|
||||
* 예상 소요 시간 (분)
|
||||
*/
|
||||
private Integer estimatedTime;
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 에러 응답 DTO
|
||||
* API 에러 발생 시 통일된 형식으로 에러 정보 반환
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ErrorResponseDto {
|
||||
|
||||
/**
|
||||
* 에러 코드
|
||||
*/
|
||||
private String error;
|
||||
|
||||
/**
|
||||
* 에러 메시지
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 에러 발생 시각
|
||||
*/
|
||||
private LocalDateTime timestamp;
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 추출된 Todo DTO
|
||||
* AI가 회의록에서 추출한 Todo 정보
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ExtractedTodoDto {
|
||||
|
||||
/**
|
||||
* Todo 내용
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 담당자
|
||||
*/
|
||||
private String assignee;
|
||||
|
||||
/**
|
||||
* 마감일
|
||||
*/
|
||||
private LocalDate dueDate;
|
||||
|
||||
/**
|
||||
* 우선순위 (HIGH, MEDIUM, LOW)
|
||||
*/
|
||||
private String priority;
|
||||
|
||||
/**
|
||||
* 관련 회의록 섹션
|
||||
*/
|
||||
private String sectionReference;
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 하이라이트 정보 DTO
|
||||
* 용어 하이라이트 스타일과 툴팁 정보
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class HighlightInfoDto {
|
||||
|
||||
/**
|
||||
* 용어명
|
||||
*/
|
||||
private String term;
|
||||
|
||||
/**
|
||||
* 텍스트 위치 정보
|
||||
*/
|
||||
private TextPositionDto position;
|
||||
|
||||
/**
|
||||
* 하이라이트 스타일
|
||||
*/
|
||||
private String style;
|
||||
|
||||
/**
|
||||
* 툴팁 텍스트
|
||||
*/
|
||||
private String tooltip;
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 회의 맥락 정보 DTO
|
||||
* 회의 제목, 참석자, 안건, 이전 회의록 등의 맥락 정보를 전달
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MeetingContextDto {
|
||||
|
||||
/**
|
||||
* 회의 제목
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 참석자 목록
|
||||
*/
|
||||
private List<String> participants;
|
||||
|
||||
/**
|
||||
* 회의 안건 목록
|
||||
*/
|
||||
private List<String> agenda;
|
||||
|
||||
/**
|
||||
* 이전 회의록 내용
|
||||
*/
|
||||
private String previousContent;
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 과거 논의 DTO
|
||||
* 전문용어 관련 과거 논의 정보
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PastDiscussionDto {
|
||||
|
||||
/**
|
||||
* 논의 날짜
|
||||
*/
|
||||
private LocalDate date;
|
||||
|
||||
/**
|
||||
* 참석자 목록
|
||||
*/
|
||||
private List<String> participants;
|
||||
|
||||
/**
|
||||
* 논의 요약
|
||||
*/
|
||||
private String summary;
|
||||
|
||||
/**
|
||||
* 회의록 링크
|
||||
*/
|
||||
private String link;
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 실시간 추천사항 DTO
|
||||
* 논의 주제와 결정사항 제안을 포함
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RealtimeSuggestionsDto {
|
||||
|
||||
/**
|
||||
* 논의 주제 제안 목록
|
||||
*/
|
||||
private List<DiscussionSuggestionDto> discussionTopics;
|
||||
|
||||
/**
|
||||
* 결정사항 제안 목록
|
||||
*/
|
||||
private List<DecisionSuggestionDto> decisions;
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 참조 문서 DTO
|
||||
* 전문용어 관련 참조 문서 정보
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ReferenceDto {
|
||||
|
||||
/**
|
||||
* 문서 제목
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 문서 유형 (위키, 매뉴얼, 회의록, 보고서)
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 문서 URL
|
||||
*/
|
||||
private String link;
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 관련 프로젝트 DTO
|
||||
* 전문용어와 관련된 프로젝트 정보
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RelatedProjectDto {
|
||||
|
||||
/**
|
||||
* 프로젝트명
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 연관성 설명
|
||||
*/
|
||||
private String relevance;
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 관련 회의록 DTO
|
||||
* RAG 검색으로 찾은 관련 회의록 정보
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RelatedTranscriptDto {
|
||||
|
||||
/**
|
||||
* 회의록 ID
|
||||
*/
|
||||
private String transcriptId;
|
||||
|
||||
/**
|
||||
* 회의 제목
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 회의 날짜
|
||||
*/
|
||||
private LocalDate date;
|
||||
|
||||
/**
|
||||
* 참석자 목록
|
||||
*/
|
||||
private List<String> participants;
|
||||
|
||||
/**
|
||||
* 관련도 점수 (0-100%)
|
||||
*/
|
||||
private Double relevanceScore;
|
||||
|
||||
/**
|
||||
* 공통 키워드 목록
|
||||
*/
|
||||
private List<String> commonKeywords;
|
||||
|
||||
/**
|
||||
* 회의록 링크
|
||||
*/
|
||||
private String link;
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 텍스트 위치 정보 DTO
|
||||
* 줄 번호와 오프셋 정보를 포함
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TextPositionDto {
|
||||
|
||||
/**
|
||||
* 줄 번호
|
||||
*/
|
||||
private Integer line;
|
||||
|
||||
/**
|
||||
* 시작 오프셋
|
||||
*/
|
||||
private Integer offset;
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 회의록 내용 DTO
|
||||
* 전체 요약, 논의사항, 결정사항, 보류사항 포함
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TranscriptContentDto {
|
||||
|
||||
/**
|
||||
* 전체 요약
|
||||
*/
|
||||
private String summary;
|
||||
|
||||
/**
|
||||
* 논의사항 목록
|
||||
*/
|
||||
private List<DiscussionItemDto> discussions;
|
||||
|
||||
/**
|
||||
* 결정사항 목록
|
||||
*/
|
||||
private List<DecisionItemDto> decisions;
|
||||
|
||||
/**
|
||||
* 보류사항 목록
|
||||
*/
|
||||
private List<String> pendingItems;
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 결정사항 제안 요청 DTO
|
||||
* 회의록 텍스트에서 결정사항 패턴을 감지하여 제안 요청
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DecisionSuggestionRequest {
|
||||
|
||||
/**
|
||||
* 회의 ID (필수)
|
||||
*/
|
||||
@NotBlank(message = "회의 ID는 필수입니다")
|
||||
private String meetingId;
|
||||
|
||||
/**
|
||||
* 현재까지의 회의록 텍스트 (필수)
|
||||
*/
|
||||
@NotBlank(message = "회의록 텍스트는 필수입니다")
|
||||
private String transcriptText;
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 논의사항 제안 요청 DTO
|
||||
* 현재 회의 진행 상황을 분석하여 추가 논의 주제 제안 요청
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DiscussionSuggestionRequest {
|
||||
|
||||
/**
|
||||
* 회의 ID (필수)
|
||||
*/
|
||||
@NotBlank(message = "회의 ID는 필수입니다")
|
||||
private String meetingId;
|
||||
|
||||
/**
|
||||
* 현재까지의 회의록 텍스트 (필수)
|
||||
*/
|
||||
@NotBlank(message = "회의록 텍스트는 필수입니다")
|
||||
private String transcriptText;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 섹션 AI 요약 재생성 요청 DTO
|
||||
* 사용자가 작성한 섹션 내용을 기반으로 AI 요약 재생성 요청
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SectionSummaryRequest {
|
||||
|
||||
/**
|
||||
* 사용자가 작성/수정한 섹션 내용 (필수, Markdown 형식)
|
||||
*/
|
||||
@NotBlank(message = "섹션 내용은 필수입니다")
|
||||
private String sectionContent;
|
||||
|
||||
/**
|
||||
* 회의 ID (맥락 이해용, 선택적)
|
||||
*/
|
||||
private String meetingId;
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 전문용어 감지 요청 DTO
|
||||
* 회의록 텍스트에서 전문용어를 자동으로 감지 요청
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TermDetectionRequest {
|
||||
|
||||
/**
|
||||
* 회의 ID (필수)
|
||||
*/
|
||||
@NotBlank(message = "회의 ID는 필수입니다")
|
||||
private String meetingId;
|
||||
|
||||
/**
|
||||
* 분석할 회의록 텍스트 (필수)
|
||||
*/
|
||||
@NotBlank(message = "분석할 텍스트는 필수입니다")
|
||||
private String text;
|
||||
|
||||
/**
|
||||
* 조직 ID
|
||||
*/
|
||||
private String organizationId;
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* Todo 자동 추출 요청 DTO
|
||||
* 회의록에서 액션 아이템을 자동으로 추출하고 담당자 식별 요청
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TodoExtractionRequest {
|
||||
|
||||
/**
|
||||
* 회의 ID (필수)
|
||||
*/
|
||||
@NotBlank(message = "회의 ID는 필수입니다")
|
||||
private String meetingId;
|
||||
|
||||
/**
|
||||
* 요청자 ID
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 회의록 전체 내용 (필수, Markdown 형식)
|
||||
*/
|
||||
@NotBlank(message = "회의록 내용은 필수입니다")
|
||||
private String minutesContent;
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.request;
|
||||
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.MeetingContextDto;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 회의록 자동 작성 요청 DTO
|
||||
* STT에서 변환된 텍스트를 받아 LLM 기반 회의록 자동 작성 요청
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TranscriptProcessRequest {
|
||||
|
||||
/**
|
||||
* 회의 ID (필수)
|
||||
*/
|
||||
@NotBlank(message = "회의 ID는 필수입니다")
|
||||
private String meetingId;
|
||||
|
||||
/**
|
||||
* STT에서 변환된 텍스트 (필수)
|
||||
*/
|
||||
@NotBlank(message = "회의록 텍스트는 필수입니다")
|
||||
private String transcriptText;
|
||||
|
||||
/**
|
||||
* 사용자 ID
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 사용자 이름
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 회의 맥락 정보
|
||||
*/
|
||||
private MeetingContextDto context;
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.response;
|
||||
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.DecisionSuggestionDto;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 결정사항 제안 응답 DTO
|
||||
* AI가 감지한 결정사항 패턴 목록 반환
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DecisionSuggestionResponse {
|
||||
|
||||
/**
|
||||
* 결정사항 제안 목록
|
||||
*/
|
||||
private List<DecisionSuggestionDto> suggestions;
|
||||
|
||||
/**
|
||||
* 제안 개수
|
||||
*/
|
||||
private Integer totalCount;
|
||||
|
||||
/**
|
||||
* 생성 시각
|
||||
*/
|
||||
private LocalDateTime timestamp;
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.response;
|
||||
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.DiscussionSuggestionDto;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 논의사항 제안 응답 DTO
|
||||
* AI가 제안하는 추가 논의 주제 목록 반환
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DiscussionSuggestionResponse {
|
||||
|
||||
/**
|
||||
* 논의사항 제안 목록
|
||||
*/
|
||||
private List<DiscussionSuggestionDto> suggestions;
|
||||
|
||||
/**
|
||||
* 제안 개수
|
||||
*/
|
||||
private Integer totalCount;
|
||||
|
||||
/**
|
||||
* 생성 시각
|
||||
*/
|
||||
private LocalDateTime timestamp;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.response;
|
||||
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.RelatedTranscriptDto;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 관련 회의록 조회 응답 DTO
|
||||
* RAG 검색으로 찾은 관련 회의록 목록 반환
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RelatedTranscriptsResponse {
|
||||
|
||||
/**
|
||||
* 관련 회의록 목록
|
||||
*/
|
||||
private List<RelatedTranscriptDto> relatedTranscripts;
|
||||
|
||||
/**
|
||||
* 관련 회의록 개수
|
||||
*/
|
||||
private Integer totalCount;
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.response;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 섹션 요약 응답 DTO
|
||||
* AI가 생성한 섹션 요약 반환
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SectionSummaryResponse {
|
||||
|
||||
/**
|
||||
* 생성된 AI 요약 (2-3문장)
|
||||
*/
|
||||
private String summary;
|
||||
|
||||
/**
|
||||
* 생성 시간
|
||||
*/
|
||||
private LocalDateTime generatedAt;
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.response;
|
||||
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.DetectedTermDto;
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.HighlightInfoDto;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 전문용어 감지 응답 DTO
|
||||
* 감지된 전문용어 목록과 하이라이트 정보 반환
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TermDetectionResponse {
|
||||
|
||||
/**
|
||||
* 감지된 용어 목록
|
||||
*/
|
||||
private List<DetectedTermDto> detectedTerms;
|
||||
|
||||
/**
|
||||
* 감지된 용어 개수
|
||||
*/
|
||||
private Integer totalCount;
|
||||
|
||||
/**
|
||||
* 하이라이트 정보 목록
|
||||
*/
|
||||
private List<HighlightInfoDto> highlightInfo;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.response;
|
||||
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.PastDiscussionDto;
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.ReferenceDto;
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.RelatedProjectDto;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 전문용어 설명 응답 DTO
|
||||
* RAG 기반 맥락적 용어 설명 반환
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TermExplanationResponse {
|
||||
|
||||
/**
|
||||
* 용어명
|
||||
*/
|
||||
private String term;
|
||||
|
||||
/**
|
||||
* 간단한 정의
|
||||
*/
|
||||
private String basicDefinition;
|
||||
|
||||
/**
|
||||
* 현재 회의 맥락에서의 의미
|
||||
*/
|
||||
private String contextualMeaning;
|
||||
|
||||
/**
|
||||
* 실제 사용 사례 목록
|
||||
*/
|
||||
private List<String> useCases;
|
||||
|
||||
/**
|
||||
* 관련 프로젝트 목록
|
||||
*/
|
||||
private List<RelatedProjectDto> relatedProjects;
|
||||
|
||||
/**
|
||||
* 과거 논의 목록
|
||||
*/
|
||||
private List<PastDiscussionDto> pastDiscussions;
|
||||
|
||||
/**
|
||||
* 참조 문서 목록
|
||||
*/
|
||||
private List<ReferenceDto> references;
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.response;
|
||||
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.ExtractedTodoDto;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Todo 추출 응답 DTO
|
||||
* AI가 추출한 Todo 목록 반환
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TodoExtractionResponse {
|
||||
|
||||
/**
|
||||
* 회의 ID
|
||||
*/
|
||||
private String meetingId;
|
||||
|
||||
/**
|
||||
* 추출된 Todo 목록
|
||||
*/
|
||||
private List<ExtractedTodoDto> todos;
|
||||
|
||||
/**
|
||||
* 추출된 Todo 개수
|
||||
*/
|
||||
private Integer totalCount;
|
||||
|
||||
/**
|
||||
* 추출 시간
|
||||
*/
|
||||
private LocalDateTime extractedAt;
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.unicorn.hgzero.ai.infra.dto.response;
|
||||
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.RealtimeSuggestionsDto;
|
||||
import com.unicorn.hgzero.ai.infra.dto.common.TranscriptContentDto;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 회의록 자동 작성 응답 DTO
|
||||
* LLM 기반으로 생성된 회의록 정보 반환
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TranscriptProcessResponse {
|
||||
|
||||
/**
|
||||
* 생성된 회의록 ID
|
||||
*/
|
||||
private String transcriptId;
|
||||
|
||||
/**
|
||||
* 회의 ID
|
||||
*/
|
||||
private String meetingId;
|
||||
|
||||
/**
|
||||
* 회의록 내용
|
||||
*/
|
||||
private TranscriptContentDto content;
|
||||
|
||||
/**
|
||||
* 실시간 추천사항
|
||||
*/
|
||||
private RealtimeSuggestionsDto suggestions;
|
||||
|
||||
/**
|
||||
* 생성 시간
|
||||
*/
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
/**
|
||||
* 회의록 상태 (DRAFT, COMPLETED)
|
||||
*/
|
||||
private String status;
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
package com.unicorn.hgzero.ai.infra.gateway;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.domain.ProcessedTranscript;
|
||||
import com.unicorn.hgzero.ai.biz.gateway.TranscriptGateway;
|
||||
import com.unicorn.hgzero.ai.infra.gateway.entity.ProcessedTranscriptEntity;
|
||||
import com.unicorn.hgzero.ai.infra.gateway.repository.ProcessedTranscriptJpaRepository;
|
||||
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 구현체
|
||||
* JPA Repository를 사용한 회의록 영속성 관리
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TranscriptGatewayImpl implements TranscriptGateway {
|
||||
|
||||
private final ProcessedTranscriptJpaRepository repository;
|
||||
|
||||
@Override
|
||||
public ProcessedTranscript save(ProcessedTranscript transcript) {
|
||||
log.debug("Saving transcript: transcriptId={}, meetingId={}",
|
||||
transcript.getTranscriptId(), transcript.getMeetingId());
|
||||
|
||||
ProcessedTranscriptEntity entity = ProcessedTranscriptEntity.fromDomain(transcript);
|
||||
ProcessedTranscriptEntity saved = repository.save(entity);
|
||||
|
||||
log.info("Transcript saved successfully: transcriptId={}", saved.getTranscriptId());
|
||||
return saved.toDomain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ProcessedTranscript> findById(String transcriptId) {
|
||||
log.debug("Finding transcript by id: {}", transcriptId);
|
||||
return repository.findById(transcriptId)
|
||||
.map(ProcessedTranscriptEntity::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ProcessedTranscript> findByMeetingId(String meetingId) {
|
||||
log.debug("Finding transcript by meetingId: {}", meetingId);
|
||||
return repository.findByMeetingId(meetingId)
|
||||
.map(ProcessedTranscriptEntity::toDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProcessedTranscript> findByMeetingIds(List<String> meetingIds) {
|
||||
log.debug("Finding transcripts by meetingIds: count={}", meetingIds.size());
|
||||
return repository.findByMeetingIdIn(meetingIds).stream()
|
||||
.map(ProcessedTranscriptEntity::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProcessedTranscript> findByStatus(String status) {
|
||||
log.debug("Finding transcripts by status: {}", status);
|
||||
return repository.findByStatus(status).stream()
|
||||
.map(ProcessedTranscriptEntity::toDomain)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean existsByMeetingId(String meetingId) {
|
||||
log.debug("Checking transcript existence by meetingId: {}", meetingId);
|
||||
return repository.existsByMeetingId(meetingId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String transcriptId) {
|
||||
log.debug("Deleting transcript: {}", transcriptId);
|
||||
repository.deleteById(transcriptId);
|
||||
log.info("Transcript deleted successfully: {}", transcriptId);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,179 @@
|
||||
package com.unicorn.hgzero.ai.infra.gateway.entity;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.unicorn.hgzero.ai.biz.domain.ProcessedTranscript;
|
||||
import com.unicorn.hgzero.common.entity.BaseTimeEntity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 처리된 회의록 Entity
|
||||
* AI가 처리한 회의록 정보를 데이터베이스에 영속화
|
||||
*/
|
||||
@Slf4j
|
||||
@Entity
|
||||
@Table(name = "processed_transcripts")
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ProcessedTranscriptEntity extends BaseTimeEntity {
|
||||
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Id
|
||||
@Column(name = "transcript_id", length = 50)
|
||||
private String transcriptId;
|
||||
|
||||
@Column(name = "meeting_id", length = 50, nullable = false)
|
||||
private String meetingId;
|
||||
|
||||
@Column(name = "summary", columnDefinition = "TEXT")
|
||||
private String summary;
|
||||
|
||||
/**
|
||||
* 논의사항 목록 (JSON 형식)
|
||||
*/
|
||||
@Column(name = "discussions", columnDefinition = "TEXT")
|
||||
private String discussions;
|
||||
|
||||
/**
|
||||
* 결정사항 목록 (JSON 형식)
|
||||
*/
|
||||
@Column(name = "decisions", columnDefinition = "TEXT")
|
||||
private String decisions;
|
||||
|
||||
/**
|
||||
* 보류사항 목록 (콤마 구분)
|
||||
*/
|
||||
@Column(name = "pending_items", columnDefinition = "TEXT")
|
||||
private String pendingItems;
|
||||
|
||||
@Column(name = "status", length = 20, nullable = false)
|
||||
@Builder.Default
|
||||
private String status = "DRAFT";
|
||||
|
||||
/**
|
||||
* Entity를 Domain 모델로 변환
|
||||
*/
|
||||
public ProcessedTranscript toDomain() {
|
||||
return ProcessedTranscript.builder()
|
||||
.transcriptId(this.transcriptId)
|
||||
.meetingId(this.meetingId)
|
||||
.summary(this.summary)
|
||||
.discussions(parseDiscussions(this.discussions))
|
||||
.decisions(parseDecisions(this.decisions))
|
||||
.pendingItems(parsePendingItems(this.pendingItems))
|
||||
.createdAt(this.getCreatedAt())
|
||||
.status(this.status)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Domain 모델에서 Entity로 변환
|
||||
*/
|
||||
public static ProcessedTranscriptEntity fromDomain(ProcessedTranscript domain) {
|
||||
return ProcessedTranscriptEntity.builder()
|
||||
.transcriptId(domain.getTranscriptId())
|
||||
.meetingId(domain.getMeetingId())
|
||||
.summary(domain.getSummary())
|
||||
.discussions(formatDiscussions(domain.getDiscussions()))
|
||||
.decisions(formatDecisions(domain.getDecisions()))
|
||||
.pendingItems(formatPendingItems(domain.getPendingItems()))
|
||||
.status(domain.getStatus())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 상태 업데이트
|
||||
*/
|
||||
public void updateStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 요약 업데이트
|
||||
*/
|
||||
public void updateSummary(String summary) {
|
||||
this.summary = summary;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Private Helper Methods - JSON 변환
|
||||
// ========================================
|
||||
|
||||
private static List<ProcessedTranscript.DiscussionItem> parseDiscussions(String json) {
|
||||
if (json == null || json.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(json,
|
||||
new TypeReference<List<ProcessedTranscript.DiscussionItem>>() {});
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("Failed to parse discussions JSON: {}", json, e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatDiscussions(List<ProcessedTranscript.DiscussionItem> discussions) {
|
||||
if (discussions == null || discussions.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
return objectMapper.writeValueAsString(discussions);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("Failed to format discussions to JSON", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static List<ProcessedTranscript.DecisionItem> parseDecisions(String json) {
|
||||
if (json == null || json.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(json,
|
||||
new TypeReference<List<ProcessedTranscript.DecisionItem>>() {});
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("Failed to parse decisions JSON: {}", json, e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatDecisions(List<ProcessedTranscript.DecisionItem> decisions) {
|
||||
if (decisions == null || decisions.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
return objectMapper.writeValueAsString(decisions);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("Failed to format decisions to JSON", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> parsePendingItems(String items) {
|
||||
if (items == null || items.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return Arrays.asList(items.split(","));
|
||||
}
|
||||
|
||||
private static String formatPendingItems(List<String> items) {
|
||||
if (items == null || items.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return String.join(",", items);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package com.unicorn.hgzero.ai.infra.gateway.repository;
|
||||
|
||||
import com.unicorn.hgzero.ai.infra.gateway.entity.ProcessedTranscriptEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 처리된 회의록 JPA Repository
|
||||
* 회의록 데이터 영속성 관리
|
||||
*/
|
||||
@Repository
|
||||
public interface ProcessedTranscriptJpaRepository extends JpaRepository<ProcessedTranscriptEntity, String> {
|
||||
|
||||
/**
|
||||
* 회의 ID로 회의록 조회
|
||||
*/
|
||||
Optional<ProcessedTranscriptEntity> findByMeetingId(String meetingId);
|
||||
|
||||
/**
|
||||
* 회의 ID 목록으로 회의록 목록 조회
|
||||
*/
|
||||
List<ProcessedTranscriptEntity> findByMeetingIdIn(List<String> meetingIds);
|
||||
|
||||
/**
|
||||
* 상태로 회의록 목록 조회
|
||||
*/
|
||||
List<ProcessedTranscriptEntity> findByStatus(String status);
|
||||
|
||||
/**
|
||||
* 회의 ID와 상태로 회의록 조회
|
||||
*/
|
||||
Optional<ProcessedTranscriptEntity> findByMeetingIdAndStatus(String meetingId, String status);
|
||||
|
||||
/**
|
||||
* 회의 ID로 회의록 존재 여부 확인
|
||||
*/
|
||||
boolean existsByMeetingId(String meetingId);
|
||||
}
|
||||
@ -0,0 +1,146 @@
|
||||
package com.unicorn.hgzero.ai.infra.llm;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.gateway.LlmGateway;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* OpenAI LLM Gateway 구현체
|
||||
* OpenAI API를 사용한 LLM 연동
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class OpenAiLlmGateway implements LlmGateway {
|
||||
|
||||
// TODO: OpenAI API 클라이언트 주입
|
||||
// private final OpenAiClient openAiClient;
|
||||
|
||||
@Override
|
||||
public String generateTranscript(String transcriptText, String title, List<String> participants, List<String> agenda) {
|
||||
log.info("Generating transcript using OpenAI: title={}", title);
|
||||
|
||||
// TODO: OpenAI API 호출
|
||||
// 1. 프롬프트 구성 (회의록 자동 작성 프롬프트)
|
||||
// 2. GPT-4 호출
|
||||
// 3. 응답 JSON 파싱
|
||||
// 4. 반환
|
||||
|
||||
// 임시 mock 응답
|
||||
return """
|
||||
{
|
||||
"summary": "회의록 자동 생성 요약",
|
||||
"discussions": [
|
||||
{
|
||||
"topic": "프로젝트 진행 상황",
|
||||
"speaker": "김철수",
|
||||
"content": "현재 80% 진행 중"
|
||||
}
|
||||
],
|
||||
"decisions": [
|
||||
{
|
||||
"content": "React로 프론트엔드 개발",
|
||||
"decisionMaker": "이영희",
|
||||
"category": "기술"
|
||||
}
|
||||
],
|
||||
"pendingItems": ["추가 예산 검토", "외주 업체 선정"]
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String extractTodos(String minutesContent) {
|
||||
log.info("Extracting todos using OpenAI");
|
||||
|
||||
// TODO: OpenAI API 호출 (Todo 추출 프롬프트)
|
||||
return """
|
||||
{
|
||||
"todos": [
|
||||
{
|
||||
"content": "API 설계서 작성",
|
||||
"assignee": "박민수",
|
||||
"dueDate": "2025-01-30",
|
||||
"priority": "HIGH",
|
||||
"sectionReference": "결정사항 #3"
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateSummary(String sectionContent, String meetingContext) {
|
||||
log.info("Generating section summary using OpenAI");
|
||||
|
||||
// TODO: OpenAI API 호출 (섹션 요약 프롬프트)
|
||||
return "AI 기반 회의록 자동화 서비스로 결정. 타겟은 중소기업 및 스타트업이며, 주요 기능은 음성인식, AI 요약, Todo 추출입니다.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String detectTerms(String text, String organizationId) {
|
||||
log.info("Detecting terms using OpenAI: organizationId={}", organizationId);
|
||||
|
||||
// TODO: OpenAI API 호출 (전문용어 감지 프롬프트)
|
||||
return """
|
||||
{
|
||||
"terms": [
|
||||
{
|
||||
"term": "MSA",
|
||||
"position": {"line": 5, "offset": 42},
|
||||
"confidence": 0.92,
|
||||
"category": "기술",
|
||||
"highlight": true
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String suggestDiscussions(String transcriptText, List<String> agenda) {
|
||||
log.info("Suggesting discussions using OpenAI");
|
||||
|
||||
// TODO: OpenAI API 호출 (논의사항 제안 프롬프트)
|
||||
return """
|
||||
{
|
||||
"suggestions": [
|
||||
{
|
||||
"id": "sugg-001",
|
||||
"topic": "보안 요구사항 검토",
|
||||
"reason": "안건에 포함되어 있으나 아직 논의되지 않음",
|
||||
"priority": "HIGH",
|
||||
"relatedAgenda": "프로젝트 개요",
|
||||
"estimatedTime": 15
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String suggestDecisions(String transcriptText) {
|
||||
log.info("Suggesting decisions using OpenAI");
|
||||
|
||||
// TODO: OpenAI API 호출 (결정사항 제안 프롬프트)
|
||||
return """
|
||||
{
|
||||
"suggestions": [
|
||||
{
|
||||
"id": "dec-001",
|
||||
"content": "React로 프론트엔드 개발",
|
||||
"category": "기술",
|
||||
"decisionMaker": "김철수",
|
||||
"participants": ["김철수", "이영희"],
|
||||
"confidence": 0.85,
|
||||
"extractedFrom": "프론트엔드는 React로 개발하기로 했습니다",
|
||||
"context": "팀원 대부분이 React 경험이 있어 개발 속도가 빠를 것으로 예상"
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,100 @@
|
||||
package com.unicorn.hgzero.ai.infra.search;
|
||||
|
||||
import com.unicorn.hgzero.ai.biz.gateway.SearchGateway;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Azure AI Search Gateway 구현체
|
||||
* RAG 기반 벡터 검색 기능 제공
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AzureAiSearchGateway implements SearchGateway {
|
||||
|
||||
// TODO: Azure AI Search 클라이언트 주입
|
||||
// private final SearchClient searchClient;
|
||||
|
||||
@Override
|
||||
public String searchRelatedTranscripts(String meetingId, String transcriptId, int limit) {
|
||||
log.info("Searching related transcripts: meetingId={}, transcriptId={}, limit={}",
|
||||
meetingId, transcriptId, limit);
|
||||
|
||||
// TODO: Azure AI Search 벡터 검색
|
||||
// 1. 회의록 내용으로 임베딩 생성
|
||||
// 2. 벡터 유사도 검색
|
||||
// 3. 상위 N개 결과 반환
|
||||
|
||||
// 임시 mock 응답
|
||||
return """
|
||||
{
|
||||
"relatedTranscripts": [
|
||||
{
|
||||
"transcriptId": "aa0e8400-e29b-41d4-a716-446655440005",
|
||||
"title": "프로젝트 X 주간 회의",
|
||||
"date": "2025-01-15",
|
||||
"participants": ["김철수", "이영희"],
|
||||
"relevanceScore": 85.5,
|
||||
"commonKeywords": ["MSA", "API Gateway", "Spring Boot"],
|
||||
"link": "/transcripts/aa0e8400-e29b-41d4-a716-446655440005"
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String searchTermExplanation(String term, String meetingId, String context) {
|
||||
log.info("Searching term explanation: term={}, meetingId={}", term, meetingId);
|
||||
|
||||
// TODO: Azure AI Search 문서 검색
|
||||
// 1. 용어와 맥락으로 검색 쿼리 구성
|
||||
// 2. 과거 회의록, 위키, 매뉴얼 검색
|
||||
// 3. 관련 문서 반환
|
||||
|
||||
// 임시 mock 응답
|
||||
return """
|
||||
{
|
||||
"term": "MSA",
|
||||
"basicDefinition": "Microservices Architecture의 약자",
|
||||
"contextualMeaning": "이번 프로젝트에서는 확장성과 독립 배포를 위해 MSA를 적용하기로 결정",
|
||||
"useCases": [
|
||||
"2024년 프로젝트 X에서 주문/결제/배송 서비스를 독립적으로 구성",
|
||||
"서비스별 독립 배포로 배포 시간 70% 단축"
|
||||
],
|
||||
"relatedProjects": [
|
||||
{"name": "프로젝트 X", "relevance": "동일한 MSA 아키텍처 적용"}
|
||||
],
|
||||
"pastDiscussions": [
|
||||
{
|
||||
"date": "2024-12-15",
|
||||
"participants": ["김철수", "이영희"],
|
||||
"summary": "MSA 아키텍처의 장단점을 비교하고 적용 방안을 논의",
|
||||
"link": "/transcripts/bb0e8400-e29b-41d4-a716-446655440006"
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"title": "MSA 아키텍처 가이드",
|
||||
"type": "위키",
|
||||
"link": "https://wiki.example.com/msa-guide"
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void indexTranscript(String transcriptId, String content, String metadata) {
|
||||
log.info("Indexing transcript: transcriptId={}", transcriptId);
|
||||
|
||||
// TODO: Azure AI Search 인덱싱
|
||||
// 1. 회의록 내용 임베딩 생성
|
||||
// 2. 벡터와 메타데이터를 인덱스에 저장
|
||||
// 3. 검색 가능 상태로 만들기
|
||||
|
||||
log.debug("Transcript indexed successfully: {}", transcriptId);
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -51,7 +51,7 @@ public class JwtTokenProvider {
|
||||
public boolean validateToken(String token) {
|
||||
try {
|
||||
Jwts.parser()
|
||||
.setSigningKey(secretKey)
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token);
|
||||
return true;
|
||||
@ -72,7 +72,7 @@ public class JwtTokenProvider {
|
||||
*/
|
||||
public String getUserId(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(secretKey)
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
@ -85,7 +85,7 @@ public class JwtTokenProvider {
|
||||
*/
|
||||
public String getUsername(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(secretKey)
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
@ -98,7 +98,7 @@ public class JwtTokenProvider {
|
||||
*/
|
||||
public String getAuthority(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(secretKey)
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
@ -112,7 +112,7 @@ public class JwtTokenProvider {
|
||||
public boolean isTokenExpired(String token) {
|
||||
try {
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(secretKey)
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
@ -128,7 +128,7 @@ public class JwtTokenProvider {
|
||||
*/
|
||||
public Date getExpirationDate(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(secretKey)
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
@ -268,3 +268,285 @@ This generated password is for development use only. Your security configuration
|
||||
2025-10-24 08:55:17 [SpringApplicationShutdownHook] DEBUG o.h.type.spi.TypeConfiguration$Scope - Un-scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration$Scope@18773ecb] from SessionFactory [org.hibernate.internal.SessionFactoryImpl@1f13eabb]
|
||||
2025-10-24 08:55:17 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
|
||||
2025-10-24 08:55:17 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
|
||||
2025-10-24 09:48:24 [main] INFO c.u.h.meeting.MeetingApplication - Starting MeetingApplication using Java 21.0.8 with PID 93979 (/Users/daewoong/home/workspace/HGZero/meeting/build/classes/java/main started by daewoong in /Users/daewoong/home/workspace/HGZero/meeting)
|
||||
2025-10-24 09:48:24 [main] DEBUG c.u.h.meeting.MeetingApplication - Running with Spring Boot v3.3.5, Spring v6.1.14
|
||||
2025-10-24 09:48:24 [main] INFO c.u.h.meeting.MeetingApplication - The following 1 profile is active: "dev"
|
||||
2025-10-24 09:48:24 [main] WARN o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.unicorn.hgzero.meeting.MeetingApplication]
|
||||
2025-10-24 09:48:24 [main] ERROR o.s.boot.SpringApplication - Application run failed
|
||||
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.unicorn.hgzero.meeting.MeetingApplication]
|
||||
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:179)
|
||||
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:417)
|
||||
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:290)
|
||||
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:349)
|
||||
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:118)
|
||||
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:789)
|
||||
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:607)
|
||||
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
|
||||
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
|
||||
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456)
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)
|
||||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352)
|
||||
at com.unicorn.hgzero.meeting.MeetingApplication.main(MeetingApplication.java:38)
|
||||
Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'jwtTokenProvider' for bean class [com.unicorn.hgzero.common.security.JwtTokenProvider] conflicts with existing, non-compatible bean definition of same name and class [com.unicorn.hgzero.meeting.infra.config.jwt.JwtTokenProvider]
|
||||
at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.checkCandidate(ClassPathBeanDefinitionScanner.java:361)
|
||||
at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:288)
|
||||
at org.springframework.context.annotation.ComponentScanAnnotationParser.parse(ComponentScanAnnotationParser.java:128)
|
||||
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:306)
|
||||
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:246)
|
||||
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:197)
|
||||
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:165)
|
||||
... 13 common frames omitted
|
||||
2025-10-24 09:52:41 [main] INFO c.u.h.meeting.MeetingApplication - Starting MeetingApplication using Java 21.0.8 with PID 94433 (/Users/daewoong/home/workspace/HGZero/meeting/build/classes/java/main started by daewoong in /Users/daewoong/home/workspace/HGZero/meeting)
|
||||
2025-10-24 09:52:41 [main] DEBUG c.u.h.meeting.MeetingApplication - Running with Spring Boot v3.3.5, Spring v6.1.14
|
||||
2025-10-24 09:52:41 [main] INFO c.u.h.meeting.MeetingApplication - The following 1 profile is active: "dev"
|
||||
2025-10-24 09:52:41 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
|
||||
2025-10-24 09:52:41 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
|
||||
2025-10-24 09:52:41 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 65 ms. Found 5 JPA repository interfaces.
|
||||
2025-10-24 09:52:41 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
|
||||
2025-10-24 09:52:41 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode.
|
||||
2025-10-24 09:52:41 [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 09:52:41 [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 09:52:41 [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 09:52:41 [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 09:52:41 [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 09:52:41 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 12 ms. Found 0 Redis repository interfaces.
|
||||
2025-10-24 09:52:42 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8082 (http)
|
||||
2025-10-24 09:52:42 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat]
|
||||
2025-10-24 09:52:42 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.31]
|
||||
2025-10-24 09:52:42 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
|
||||
2025-10-24 09:52:42 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 1082 ms
|
||||
2025-10-24 09:52:42 [main] INFO o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
|
||||
2025-10-24 09:52:42 [main] INFO org.hibernate.Version - HHH000412: Hibernate ORM core version 6.5.3.Final
|
||||
2025-10-24 09:52:42 [main] INFO o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration boolean -> org.hibernate.type.BasicTypeReference@ef85567
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration boolean -> org.hibernate.type.BasicTypeReference@ef85567
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Boolean -> org.hibernate.type.BasicTypeReference@ef85567
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration numeric_boolean -> org.hibernate.type.BasicTypeReference@1c2fb9e8
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.NumericBooleanConverter -> org.hibernate.type.BasicTypeReference@1c2fb9e8
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration true_false -> org.hibernate.type.BasicTypeReference@ec3944
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.TrueFalseConverter -> org.hibernate.type.BasicTypeReference@ec3944
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration yes_no -> org.hibernate.type.BasicTypeReference@2e4339c1
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.YesNoConverter -> org.hibernate.type.BasicTypeReference@2e4339c1
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration byte -> org.hibernate.type.BasicTypeReference@62dc1203
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration byte -> org.hibernate.type.BasicTypeReference@62dc1203
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Byte -> org.hibernate.type.BasicTypeReference@62dc1203
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration binary -> org.hibernate.type.BasicTypeReference@35d0749
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration byte[] -> org.hibernate.type.BasicTypeReference@35d0749
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration [B -> org.hibernate.type.BasicTypeReference@35d0749
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration binary_wrapper -> org.hibernate.type.BasicTypeReference@621a387f
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration wrapper-binary -> org.hibernate.type.BasicTypeReference@621a387f
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration image -> org.hibernate.type.BasicTypeReference@552088cc
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration blob -> org.hibernate.type.BasicTypeReference@57eed461
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Blob -> org.hibernate.type.BasicTypeReference@57eed461
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_blob -> org.hibernate.type.BasicTypeReference@3c62f69a
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_blob_wrapper -> org.hibernate.type.BasicTypeReference@f08f8a9
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration short -> org.hibernate.type.BasicTypeReference@5ebf776c
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration short -> org.hibernate.type.BasicTypeReference@5ebf776c
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Short -> org.hibernate.type.BasicTypeReference@5ebf776c
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration integer -> org.hibernate.type.BasicTypeReference@7fd3fd06
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration int -> org.hibernate.type.BasicTypeReference@7fd3fd06
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Integer -> org.hibernate.type.BasicTypeReference@7fd3fd06
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration long -> org.hibernate.type.BasicTypeReference@54ae1240
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration long -> org.hibernate.type.BasicTypeReference@54ae1240
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Long -> org.hibernate.type.BasicTypeReference@54ae1240
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration float -> org.hibernate.type.BasicTypeReference@1c2b65cc
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration float -> org.hibernate.type.BasicTypeReference@1c2b65cc
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Float -> org.hibernate.type.BasicTypeReference@1c2b65cc
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration double -> org.hibernate.type.BasicTypeReference@390a7532
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration double -> org.hibernate.type.BasicTypeReference@390a7532
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Double -> org.hibernate.type.BasicTypeReference@390a7532
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration big_integer -> org.hibernate.type.BasicTypeReference@595184d8
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.math.BigInteger -> org.hibernate.type.BasicTypeReference@595184d8
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration big_decimal -> org.hibernate.type.BasicTypeReference@7d49a1a0
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.math.BigDecimal -> org.hibernate.type.BasicTypeReference@7d49a1a0
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration character -> org.hibernate.type.BasicTypeReference@3a0baec0
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration char -> org.hibernate.type.BasicTypeReference@3a0baec0
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Character -> org.hibernate.type.BasicTypeReference@3a0baec0
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration character_nchar -> org.hibernate.type.BasicTypeReference@50c2ef56
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration string -> org.hibernate.type.BasicTypeReference@560d6d2
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.String -> org.hibernate.type.BasicTypeReference@560d6d2
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration nstring -> org.hibernate.type.BasicTypeReference@3514237f
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration characters -> org.hibernate.type.BasicTypeReference@520ee6b3
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration char[] -> org.hibernate.type.BasicTypeReference@520ee6b3
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration [C -> org.hibernate.type.BasicTypeReference@520ee6b3
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration wrapper-characters -> org.hibernate.type.BasicTypeReference@15f11bfb
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration text -> org.hibernate.type.BasicTypeReference@16a499d1
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ntext -> org.hibernate.type.BasicTypeReference@2bf4fa1
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration clob -> org.hibernate.type.BasicTypeReference@27210a3b
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Clob -> org.hibernate.type.BasicTypeReference@27210a3b
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration nclob -> org.hibernate.type.BasicTypeReference@3a12f3e7
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.NClob -> org.hibernate.type.BasicTypeReference@3a12f3e7
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_clob -> org.hibernate.type.BasicTypeReference@84a9f65
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_clob_char_array -> org.hibernate.type.BasicTypeReference@70700b8a
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_clob_character_array -> org.hibernate.type.BasicTypeReference@5fafa76d
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_nclob -> org.hibernate.type.BasicTypeReference@720ffab4
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_nclob_character_array -> org.hibernate.type.BasicTypeReference@2e62e227
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration materialized_nclob_char_array -> org.hibernate.type.BasicTypeReference@5ebe903a
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration Duration -> org.hibernate.type.BasicTypeReference@7c88d04f
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.Duration -> org.hibernate.type.BasicTypeReference@7c88d04f
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration LocalDateTime -> org.hibernate.type.BasicTypeReference@71df5f30
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.LocalDateTime -> org.hibernate.type.BasicTypeReference@71df5f30
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration LocalDate -> org.hibernate.type.BasicTypeReference@4895e8f6
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.LocalDate -> org.hibernate.type.BasicTypeReference@4895e8f6
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration LocalTime -> org.hibernate.type.BasicTypeReference@62808e9e
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.LocalTime -> org.hibernate.type.BasicTypeReference@62808e9e
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTime -> org.hibernate.type.BasicTypeReference@58b03029
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetDateTime -> org.hibernate.type.BasicTypeReference@58b03029
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTimeWithTimezone -> org.hibernate.type.BasicTypeReference@539dd2d0
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTimeWithoutTimezone -> org.hibernate.type.BasicTypeReference@3428420d
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTime -> org.hibernate.type.BasicTypeReference@523ade68
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetTime -> org.hibernate.type.BasicTypeReference@523ade68
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTimeUtc -> org.hibernate.type.BasicTypeReference@b529d7e
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTimeWithTimezone -> org.hibernate.type.BasicTypeReference@3664c596
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTimeWithoutTimezone -> org.hibernate.type.BasicTypeReference@40aad17d
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTime -> org.hibernate.type.BasicTypeReference@44e79e9e
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.ZonedDateTime -> org.hibernate.type.BasicTypeReference@44e79e9e
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTimeWithTimezone -> org.hibernate.type.BasicTypeReference@5bc14211
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTimeWithoutTimezone -> org.hibernate.type.BasicTypeReference@4b99648a
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration date -> org.hibernate.type.BasicTypeReference@5d2e65bd
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Date -> org.hibernate.type.BasicTypeReference@5d2e65bd
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration time -> org.hibernate.type.BasicTypeReference@254513e8
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Time -> org.hibernate.type.BasicTypeReference@254513e8
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration timestamp -> org.hibernate.type.BasicTypeReference@74450c9b
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.sql.Timestamp -> org.hibernate.type.BasicTypeReference@74450c9b
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Date -> org.hibernate.type.BasicTypeReference@74450c9b
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration calendar -> org.hibernate.type.BasicTypeReference@74f89bad
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Calendar -> org.hibernate.type.BasicTypeReference@74f89bad
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.GregorianCalendar -> org.hibernate.type.BasicTypeReference@74f89bad
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration calendar_date -> org.hibernate.type.BasicTypeReference@5ad50b02
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration calendar_time -> org.hibernate.type.BasicTypeReference@570299e3
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration instant -> org.hibernate.type.BasicTypeReference@bff764c
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.Instant -> org.hibernate.type.BasicTypeReference@bff764c
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration uuid -> org.hibernate.type.BasicTypeReference@3beaa16d
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.UUID -> org.hibernate.type.BasicTypeReference@3beaa16d
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration pg-uuid -> org.hibernate.type.BasicTypeReference@3beaa16d
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration uuid-binary -> org.hibernate.type.BasicTypeReference@49153009
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration uuid-char -> org.hibernate.type.BasicTypeReference@a1b7549
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration class -> org.hibernate.type.BasicTypeReference@7aa63f50
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Class -> org.hibernate.type.BasicTypeReference@7aa63f50
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration currency -> org.hibernate.type.BasicTypeReference@142918a0
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration Currency -> org.hibernate.type.BasicTypeReference@142918a0
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Currency -> org.hibernate.type.BasicTypeReference@142918a0
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration locale -> org.hibernate.type.BasicTypeReference@745cf754
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.Locale -> org.hibernate.type.BasicTypeReference@745cf754
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration serializable -> org.hibernate.type.BasicTypeReference@25bc65ab
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.io.Serializable -> org.hibernate.type.BasicTypeReference@25bc65ab
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration timezone -> org.hibernate.type.BasicTypeReference@6eab92f3
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.util.TimeZone -> org.hibernate.type.BasicTypeReference@6eab92f3
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZoneOffset -> org.hibernate.type.BasicTypeReference@321b7b9e
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.ZoneOffset -> org.hibernate.type.BasicTypeReference@321b7b9e
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration url -> org.hibernate.type.BasicTypeReference@21eedcde
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.net.URL -> org.hibernate.type.BasicTypeReference@21eedcde
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration vector -> org.hibernate.type.BasicTypeReference@67396475
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration row_version -> org.hibernate.type.BasicTypeReference@55b74e6b
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration object -> org.hibernate.type.JavaObjectType@1f293cb7
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Object -> org.hibernate.type.JavaObjectType@1f293cb7
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration null -> org.hibernate.type.NullType@28295554
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_date -> org.hibernate.type.BasicTypeReference@4e671ef
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_time -> org.hibernate.type.BasicTypeReference@74a1d60e
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_timestamp -> org.hibernate.type.BasicTypeReference@16c0be3b
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_calendar -> org.hibernate.type.BasicTypeReference@219edc05
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_calendar_date -> org.hibernate.type.BasicTypeReference@62f37bfd
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_calendar_time -> org.hibernate.type.BasicTypeReference@1818d00b
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_binary -> org.hibernate.type.BasicTypeReference@b3a8455
|
||||
2025-10-24 09:52:42 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration imm_serializable -> org.hibernate.type.BasicTypeReference@5c930fc3
|
||||
2025-10-24 09:52:42 [main] INFO o.s.o.j.p.SpringPersistenceUnitInfo - No LoadTimeWeaver setup: ignoring JPA class transformer
|
||||
2025-10-24 09:52:42 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
|
||||
2025-10-24 09:52:43 [main] INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@5ac53209
|
||||
2025-10-24 09:52:43 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
|
||||
2025-10-24 09:52:43 [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 09:52:43 [main] DEBUG o.h.t.d.sql.spi.DdlTypeRegistry - addDescriptor(2003, org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl@602b7944) replaced previous registration(org.hibernate.type.descriptor.sql.internal.ArrayDdlTypeImpl@5f8d4b51)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.h.t.d.sql.spi.DdlTypeRegistry - addDescriptor(6, org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType@55821edf) replaced previous registration(org.hibernate.type.descriptor.sql.internal.DdlTypeImpl@5e5a2b74)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.h.t.d.jdbc.spi.JdbcTypeRegistry - addDescriptor(2004, BlobTypeDescriptor(BLOB_BINDING)) replaced previous registration(BlobTypeDescriptor(DEFAULT))
|
||||
2025-10-24 09:52:43 [main] DEBUG o.h.t.d.jdbc.spi.JdbcTypeRegistry - addDescriptor(2005, ClobTypeDescriptor(CLOB_BINDING)) replaced previous registration(ClobTypeDescriptor(DEFAULT))
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration JAVA_OBJECT -> org.hibernate.type.JavaObjectType@d17d554
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.lang.Object -> org.hibernate.type.JavaObjectType@d17d554
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Type registration key [java.lang.Object] overrode previous entry : `org.hibernate.type.JavaObjectType@1f293cb7`
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.DurationType -> basicType@1(java.time.Duration,3015)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration Duration -> basicType@1(java.time.Duration,3015)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.Duration -> basicType@1(java.time.Duration,3015)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.OffsetDateTimeType -> basicType@2(java.time.OffsetDateTime,3003)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetDateTime -> basicType@2(java.time.OffsetDateTime,3003)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetDateTime -> basicType@2(java.time.OffsetDateTime,3003)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.ZonedDateTimeType -> basicType@3(java.time.ZonedDateTime,3003)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration ZonedDateTime -> basicType@3(java.time.ZonedDateTime,3003)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.ZonedDateTime -> basicType@3(java.time.ZonedDateTime,3003)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration org.hibernate.type.OffsetTimeType -> basicType@4(java.time.OffsetTime,3007)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration OffsetTime -> basicType@4(java.time.OffsetTime,3007)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.hibernate.type.BasicTypeRegistry - Adding type registration java.time.OffsetTime -> basicType@4(java.time.OffsetTime,3007)
|
||||
2025-10-24 09:52:43 [main] DEBUG o.h.type.spi.TypeConfiguration$Scope - Scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration@20a116a0] to MetadataBuildingContext [org.hibernate.boot.internal.MetadataBuildingContextRootImpl@6dbdeb69]
|
||||
2025-10-24 09:52:43 [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 09:52:43 [main] DEBUG o.h.type.spi.TypeConfiguration$Scope - Scoping TypeConfiguration [org.hibernate.type.spi.TypeConfiguration@20a116a0] to SessionFactoryImplementor [org.hibernate.internal.SessionFactoryImpl@2fb9695a]
|
||||
2025-10-24 09:52:43 [main] DEBUG org.hibernate.SQL -
|
||||
alter table if exists meetings
|
||||
alter column description set data type TEXT
|
||||
2025-10-24 09:52:43 [main] DEBUG org.hibernate.SQL -
|
||||
alter table if exists meetings
|
||||
alter column participants set data type TEXT
|
||||
2025-10-24 09:52:44 [main] DEBUG org.hibernate.SQL -
|
||||
alter table if exists minutes_sections
|
||||
alter column content set data type TEXT
|
||||
2025-10-24 09:52:44 [main] DEBUG org.hibernate.SQL -
|
||||
alter table if exists templates
|
||||
alter column description set data type TEXT
|
||||
2025-10-24 09:52:44 [main] DEBUG org.hibernate.SQL -
|
||||
alter table if exists templates
|
||||
alter column sections set data type TEXT
|
||||
2025-10-24 09:52:44 [main] DEBUG org.hibernate.SQL -
|
||||
alter table if exists todos
|
||||
alter column description set data type TEXT
|
||||
2025-10-24 09:52:44 [main] TRACE o.h.type.spi.TypeConfiguration$Scope - Handling #sessionFactoryCreated from [org.hibernate.internal.SessionFactoryImpl@2fb9695a] for TypeConfiguration
|
||||
2025-10-24 09:52:44 [main] INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
|
||||
2025-10-24 09:52:44 [main] INFO o.s.d.j.r.query.QueryEnhancerFactory - Hibernate is in classpath; If applicable, HQL parser will be used.
|
||||
2025-10-24 09:52:44 [main] INFO c.u.h.m.infra.cache.CacheConfig - Redis 연결 설정 - host: 20.249.177.114, port: 6379, database: 1
|
||||
2025-10-24 09:52:44 [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 09:52:45 [main] INFO c.u.h.m.infra.cache.CacheConfig - Redis 템플릿 설정 완료
|
||||
2025-10-24 09:52:45 [main] INFO c.u.h.m.infra.cache.CacheConfig - ObjectMapper 설정 완료
|
||||
2025-10-24 09:52:45 [main] INFO c.u.h.m.infra.config.EventHubConfig - Kafka Producer 설정 완료 - bootstrapServers: localhost:9092, clientId: meeting-service
|
||||
2025-10-24 09:52:45 [main] INFO c.u.h.m.infra.config.EventHubConfig - Kafka Template 설정 완료
|
||||
2025-10-24 09:52:45 [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 09:52:45 [main] WARN o.s.b.a.s.s.UserDetailsServiceAutoConfiguration -
|
||||
|
||||
Using generated security password: 6a508fa4-1e2b-4962-9e95-4376005b678f
|
||||
|
||||
This generated password is for development use only. Your security configuration must be updated before running your application in production.
|
||||
|
||||
2025-10-24 09:52:45 [main] INFO o.s.s.c.a.a.c.InitializeUserDetailsBeanManagerConfigurer$InitializeUserDetailsManagerConfigurer - Global AuthenticationManager configured with UserDetailsService bean with name inMemoryUserDetailsManager
|
||||
2025-10-24 09:52:45 [main] INFO c.u.h.m.infra.config.WebSocketConfig - WebSocket 핸들러 등록 완료 - endpoint: /ws/minutes/{minutesId}
|
||||
2025-10-24 09:52:45 [main] INFO o.s.b.a.e.web.EndpointLinksResolver - Exposing 3 endpoints beneath base path '/actuator'
|
||||
2025-10-24 09:52:45 [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 09:52:45 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8082 (http) with context path '/'
|
||||
2025-10-24 09:52:45 [main] INFO c.u.h.meeting.MeetingApplication - Started MeetingApplication in 4.905 seconds (process running for 5.065)
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-1] INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-1] INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 2 ms
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-1] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/index.html
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-1] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-1] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/index.html
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-2] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/index.css
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-3] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/swagger-ui.css
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-5] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/swagger-ui-standalone-preset.js
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-3] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-5] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-2] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-5] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/swagger-ui-standalone-preset.js
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-3] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/swagger-ui.css
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-6] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/swagger-initializer.js
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-4] DEBUG o.s.security.web.FilterChainProxy - Securing GET /swagger-ui/swagger-ui-bundle.js
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-2] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/index.css
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-6] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-4] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-4] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/swagger-ui-bundle.js
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-6] DEBUG o.s.security.web.FilterChainProxy - Secured GET /swagger-ui/swagger-initializer.js
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-7] DEBUG o.s.security.web.FilterChainProxy - Securing GET /v3/api-docs/swagger-config
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-7] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-7] DEBUG o.s.security.web.FilterChainProxy - Secured GET /v3/api-docs/swagger-config
|
||||
2025-10-24 09:53:46 [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@611897cb]]
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-7] INFO c.u.hgzero.common.aop.LoggingAspect - [Controller] org.springdoc.webmvc.ui.SwaggerConfigResource.openapiJson 완료 - 실행시간: 0ms
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-8] DEBUG o.s.security.web.FilterChainProxy - Securing GET /v3/api-docs
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-8] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-8] DEBUG o.s.security.web.FilterChainProxy - Secured GET /v3/api-docs
|
||||
2025-10-24 09:53:46 [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@5922449e], /v3/api-docs, ko_KR]
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-8] INFO o.s.api.AbstractOpenApiResource - Init duration for springdoc-openapi is: 328 ms
|
||||
2025-10-24 09:53:46 [http-nio-8082-exec-8] INFO c.u.hgzero.common.aop.LoggingAspect - [Controller] org.springdoc.webmvc.api.OpenApiWebMvcResource.openapiJson 완료 - 실행시간: 338ms
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.unicorn.hgzero.meeting.infra.config;
|
||||
|
||||
import com.unicorn.hgzero.common.security.JwtTokenProvider;
|
||||
import com.unicorn.hgzero.meeting.infra.config.jwt.JwtAuthenticationFilter;
|
||||
import com.unicorn.hgzero.meeting.infra.config.jwt.JwtTokenProvider;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.unicorn.hgzero.meeting.infra.config.jwt;
|
||||
|
||||
import com.unicorn.hgzero.common.security.JwtTokenProvider;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
@ -1,138 +0,0 @@
|
||||
package com.unicorn.hgzero.meeting.infra.config.jwt;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.MalformedJwtException;
|
||||
import io.jsonwebtoken.UnsupportedJwtException;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import io.jsonwebtoken.security.SecurityException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* JWT 토큰 제공자
|
||||
* JWT 토큰의 생성, 검증, 파싱을 담당
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class JwtTokenProvider {
|
||||
|
||||
private final SecretKey secretKey;
|
||||
private final long tokenValidityInMilliseconds;
|
||||
|
||||
public JwtTokenProvider(@Value("${jwt.secret}") String secret,
|
||||
@Value("${jwt.access-token-validity:3600}") long tokenValidityInSeconds) {
|
||||
this.secretKey = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8));
|
||||
this.tokenValidityInMilliseconds = tokenValidityInSeconds * 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP 요청에서 JWT 토큰 추출
|
||||
*/
|
||||
public String resolveToken(HttpServletRequest request) {
|
||||
String bearerToken = request.getHeader("Authorization");
|
||||
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
|
||||
return bearerToken.substring(7);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT 토큰 유효성 검증
|
||||
*/
|
||||
public boolean validateToken(String token) {
|
||||
try {
|
||||
Jwts.parser()
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token);
|
||||
return true;
|
||||
} catch (SecurityException | MalformedJwtException e) {
|
||||
log.debug("Invalid JWT signature: {}", e.getMessage());
|
||||
} catch (ExpiredJwtException e) {
|
||||
log.debug("Expired JWT token: {}", e.getMessage());
|
||||
} catch (UnsupportedJwtException e) {
|
||||
log.debug("Unsupported JWT token: {}", e.getMessage());
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.debug("JWT token compact of handler are invalid: {}", e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT 토큰에서 사용자 ID 추출
|
||||
*/
|
||||
public String getUserId(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
return claims.getSubject();
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT 토큰에서 사용자명 추출
|
||||
*/
|
||||
public String getUsername(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
return claims.get("username", String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT 토큰에서 권한 정보 추출
|
||||
*/
|
||||
public String getAuthority(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
return claims.get("authority", String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 토큰 만료 시간 확인
|
||||
*/
|
||||
public boolean isTokenExpired(String token) {
|
||||
try {
|
||||
Claims claims = Jwts.parser()
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
return claims.getExpiration().before(new Date());
|
||||
} catch (Exception e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 토큰에서 만료 시간 추출
|
||||
*/
|
||||
public Date getExpirationDate(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.verifyWith(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
return claims.getExpiration();
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user