mirror of
https://github.com/hwanny1128/HGZero.git
synced 2026-06-13 04:49:11 +00:00
add new meeting
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package com.unicorn.hgzero.meeting;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
/**
|
||||
* Meeting Service Application
|
||||
* 회의, 회의록, Todo, 실시간 협업 관리 서비스 메인 클래스
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@ComponentScan(basePackages = {"com.unicorn.hgzero.meeting", "com.unicorn.hgzero.common"})
|
||||
public class MeetingApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MeetingApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,16 @@ import java.util.List;
|
||||
@AllArgsConstructor
|
||||
public class Dashboard {
|
||||
|
||||
/**
|
||||
* 사용자 ID
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 조회 기간
|
||||
*/
|
||||
private String period;
|
||||
|
||||
/**
|
||||
* 다가오는 회의 목록
|
||||
*/
|
||||
@@ -49,6 +59,11 @@ public class Dashboard {
|
||||
*/
|
||||
private Integer totalMeetings;
|
||||
|
||||
/**
|
||||
* 예정된 회의 수
|
||||
*/
|
||||
private Integer scheduledMeetings;
|
||||
|
||||
/**
|
||||
* 진행 중인 회의 수
|
||||
*/
|
||||
@@ -59,11 +74,31 @@ public class Dashboard {
|
||||
*/
|
||||
private Integer completedMeetings;
|
||||
|
||||
/**
|
||||
* 전체 회의록 수
|
||||
*/
|
||||
private Integer totalMinutes;
|
||||
|
||||
/**
|
||||
* 초안 상태 회의록 수
|
||||
*/
|
||||
private Integer draftMinutes;
|
||||
|
||||
/**
|
||||
* 확정된 회의록 수
|
||||
*/
|
||||
private Integer finalizedMinutes;
|
||||
|
||||
/**
|
||||
* 전체 Todo 수
|
||||
*/
|
||||
private Integer totalTodos;
|
||||
|
||||
/**
|
||||
* 대기 중인 Todo 수
|
||||
*/
|
||||
private Integer pendingTodos;
|
||||
|
||||
/**
|
||||
* 완료된 Todo 수
|
||||
*/
|
||||
|
||||
@@ -84,4 +84,19 @@ public class Minutes {
|
||||
public boolean isFinalized() {
|
||||
return "FINALIZED".equals(this.status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 버전 증가
|
||||
*/
|
||||
public void incrementVersion() {
|
||||
this.version++;
|
||||
}
|
||||
|
||||
/**
|
||||
* 회의록 제목 업데이트
|
||||
*/
|
||||
public void updateTitle(String title) {
|
||||
this.title = title;
|
||||
this.version++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,4 +95,12 @@ public class MinutesSection {
|
||||
public boolean isVerified() {
|
||||
return Boolean.TRUE.equals(this.verified);
|
||||
}
|
||||
|
||||
/**
|
||||
* 섹션 정보 업데이트
|
||||
*/
|
||||
public void update(String title, String content) {
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,4 +97,15 @@ public class Todo {
|
||||
LocalDate.now().isAfter(this.dueDate) &&
|
||||
!isCompleted();
|
||||
}
|
||||
|
||||
/**
|
||||
* Todo 정보 업데이트
|
||||
*/
|
||||
public void update(String title, String description, String assigneeId, LocalDate dueDate, String priority) {
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.assigneeId = assigneeId;
|
||||
this.dueDate = dueDate;
|
||||
this.priority = priority;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public class MinutesService implements
|
||||
}
|
||||
|
||||
// 제목 수정
|
||||
minutes.update(title, minutes.getSections());
|
||||
minutes.updateTitle(title);
|
||||
|
||||
// 저장
|
||||
Minutes updatedMinutes = minutesWriter.save(minutes);
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.unicorn.hgzero.meeting.infra.config;
|
||||
|
||||
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;
|
||||
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
|
||||
.requestMatchers("/swagger-ui/**", "/swagger-ui.html", "/v3/api-docs/**", "/swagger-resources/**", "/webjars/**").permitAll()
|
||||
// Health check
|
||||
.requestMatchers("/health").permitAll()
|
||||
// WebSocket endpoints
|
||||
.requestMatchers("/ws/**").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"
|
||||
));
|
||||
|
||||
// 자격 증명 허용
|
||||
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.meeting.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 설정
|
||||
* Meeting Service API 문서화를 위한 설정
|
||||
*/
|
||||
@Configuration
|
||||
public class SwaggerConfig {
|
||||
|
||||
@Bean
|
||||
public OpenAPI openAPI() {
|
||||
return new OpenAPI()
|
||||
.info(apiInfo())
|
||||
.addServersItem(new Server()
|
||||
.url("http://localhost:8081")
|
||||
.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("8081")
|
||||
.description("Server port"))))
|
||||
.addSecurityItem(new SecurityRequirement().addList("Bearer Authentication"))
|
||||
.components(new Components()
|
||||
.addSecuritySchemes("Bearer Authentication", createAPIKeyScheme()));
|
||||
}
|
||||
|
||||
private Info apiInfo() {
|
||||
return new Info()
|
||||
.title("Meeting Service API")
|
||||
.description("회의, 회의록, Todo, 실시간 협업 관리 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");
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package com.unicorn.hgzero.meeting.infra.config.jwt;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* JWT 인증 필터
|
||||
* HTTP 요청에서 JWT 토큰을 추출하여 인증을 수행
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private final JwtTokenProvider jwtTokenProvider;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
|
||||
String token = jwtTokenProvider.resolveToken(request);
|
||||
|
||||
if (StringUtils.hasText(token) && jwtTokenProvider.validateToken(token)) {
|
||||
String userId = jwtTokenProvider.getUserId(token);
|
||||
String username = null;
|
||||
String authority = null;
|
||||
|
||||
try {
|
||||
username = jwtTokenProvider.getUsername(token);
|
||||
} catch (Exception e) {
|
||||
log.debug("JWT에 username 클레임이 없음: {}", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
authority = jwtTokenProvider.getAuthority(token);
|
||||
} catch (Exception e) {
|
||||
log.debug("JWT에 authority 클레임이 없음: {}", e.getMessage());
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(userId)) {
|
||||
// UserPrincipal 객체 생성 (username과 authority가 없어도 동작)
|
||||
UserPrincipal userPrincipal = UserPrincipal.builder()
|
||||
.userId(userId)
|
||||
.username(username != null ? username : "unknown")
|
||||
.authority(authority != null ? authority : "USER")
|
||||
.build();
|
||||
|
||||
UsernamePasswordAuthenticationToken authentication =
|
||||
new UsernamePasswordAuthenticationToken(
|
||||
userPrincipal,
|
||||
null,
|
||||
Collections.singletonList(new SimpleGrantedAuthority(authority != null ? authority : "USER"))
|
||||
);
|
||||
|
||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
log.debug("인증된 사용자: {} ({})", userPrincipal.getUsername(), userId);
|
||||
}
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldNotFilter(HttpServletRequest request) {
|
||||
String path = request.getRequestURI();
|
||||
return path.startsWith("/actuator") ||
|
||||
path.startsWith("/swagger-ui") ||
|
||||
path.startsWith("/v3/api-docs") ||
|
||||
path.equals("/health") ||
|
||||
path.startsWith("/ws");
|
||||
}
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
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()
|
||||
.setSigningKey(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()
|
||||
.setSigningKey(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
return claims.getSubject();
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT 토큰에서 사용자명 추출
|
||||
*/
|
||||
public String getUsername(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
return claims.get("username", String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT 토큰에서 권한 정보 추출
|
||||
*/
|
||||
public String getAuthority(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
return claims.get("authority", String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 토큰 만료 시간 확인
|
||||
*/
|
||||
public boolean isTokenExpired(String token) {
|
||||
try {
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(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()
|
||||
.setSigningKey(secretKey)
|
||||
.build()
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
return claims.getExpiration();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.unicorn.hgzero.meeting.infra.config.jwt;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 인증된 사용자 정보
|
||||
* JWT 토큰에서 추출된 사용자 정보를 담는 Principal 객체
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@RequiredArgsConstructor
|
||||
public class UserPrincipal {
|
||||
|
||||
/**
|
||||
* 사용자 고유 ID
|
||||
*/
|
||||
private final String userId;
|
||||
|
||||
/**
|
||||
* 사용자명
|
||||
*/
|
||||
private final String username;
|
||||
|
||||
/**
|
||||
* 사용자 권한
|
||||
*/
|
||||
private final String authority;
|
||||
|
||||
/**
|
||||
* 사용자 ID 반환 (별칭)
|
||||
*/
|
||||
public String getName() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 관리자 권한 여부 확인
|
||||
*/
|
||||
public boolean isAdmin() {
|
||||
return "ADMIN".equals(authority);
|
||||
}
|
||||
|
||||
/**
|
||||
* 일반 사용자 권한 여부 확인
|
||||
*/
|
||||
public boolean isUser() {
|
||||
return "USER".equals(authority) || authority == null;
|
||||
}
|
||||
}
|
||||
+26
-26
@@ -55,19 +55,19 @@ public class DashboardGateway implements DashboardReader {
|
||||
.count();
|
||||
|
||||
// 통계 객체 생성
|
||||
Dashboard.Statistics statistics = new Dashboard.Statistics(
|
||||
totalMeetings,
|
||||
scheduledMeetings,
|
||||
inProgressMeetings,
|
||||
completedMeetings,
|
||||
totalMinutes,
|
||||
draftMinutes,
|
||||
finalizedMinutes,
|
||||
totalTodos,
|
||||
pendingTodos,
|
||||
completedTodos,
|
||||
overdueTodos
|
||||
);
|
||||
Dashboard.Statistics statistics = Dashboard.Statistics.builder()
|
||||
.totalMeetings((int) totalMeetings)
|
||||
.scheduledMeetings((int) scheduledMeetings)
|
||||
.inProgressMeetings((int) inProgressMeetings)
|
||||
.completedMeetings((int) completedMeetings)
|
||||
.totalMinutes((int) totalMinutes)
|
||||
.draftMinutes((int) draftMinutes)
|
||||
.finalizedMinutes((int) finalizedMinutes)
|
||||
.totalTodos((int) totalTodos)
|
||||
.pendingTodos((int) pendingTodos)
|
||||
.completedTodos((int) completedTodos)
|
||||
.overdueTodos((int) overdueTodos)
|
||||
.build();
|
||||
|
||||
// 대시보드 생성
|
||||
return Dashboard.builder()
|
||||
@@ -121,19 +121,19 @@ public class DashboardGateway implements DashboardReader {
|
||||
.count();
|
||||
|
||||
// 통계 객체 생성
|
||||
Dashboard.Statistics statistics = new Dashboard.Statistics(
|
||||
totalMeetings,
|
||||
scheduledMeetings,
|
||||
inProgressMeetings,
|
||||
completedMeetings,
|
||||
totalMinutes,
|
||||
draftMinutes,
|
||||
finalizedMinutes,
|
||||
totalTodos,
|
||||
pendingTodos,
|
||||
completedTodos,
|
||||
overdueTodos
|
||||
);
|
||||
Dashboard.Statistics statistics = Dashboard.Statistics.builder()
|
||||
.totalMeetings((int) totalMeetings)
|
||||
.scheduledMeetings((int) scheduledMeetings)
|
||||
.inProgressMeetings((int) inProgressMeetings)
|
||||
.completedMeetings((int) completedMeetings)
|
||||
.totalMinutes((int) totalMinutes)
|
||||
.draftMinutes((int) draftMinutes)
|
||||
.finalizedMinutes((int) finalizedMinutes)
|
||||
.totalTodos((int) totalTodos)
|
||||
.pendingTodos((int) pendingTodos)
|
||||
.completedTodos((int) completedTodos)
|
||||
.overdueTodos((int) overdueTodos)
|
||||
.build();
|
||||
|
||||
// 대시보드 생성
|
||||
return Dashboard.builder()
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
package com.unicorn.hgzero.meeting.biz.domain;
|
||||
package com.unicorn.hgzero.meeting.infra.gateway.entity;
|
||||
|
||||
import com.unicorn.hgzero.common.entity.BaseTimeEntity;
|
||||
import com.unicorn.hgzero.meeting.biz.domain.Template;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
|
||||
Reference in New Issue
Block a user