mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2026-06-13 11:39:11 +00:00
물리아키텍처 설계 완료
✨ 주요 기능 - Azure 기반 물리아키텍처 설계 (개발환경/운영환경) - 7개 마이크로서비스 물리 구조 설계 - 네트워크 아키텍처 다이어그램 작성 (Mermaid) - 환경별 비교 분석 및 마스터 인덱스 문서 📁 생성 파일 - design/backend/physical/physical-architecture.md (마스터) - design/backend/physical/physical-architecture-dev.md (개발환경) - design/backend/physical/physical-architecture-prod.md (운영환경) - design/backend/physical/*.mmd (4개 Mermaid 다이어그램) 🎯 핵심 성과 - 비용 최적화: 개발환경 월 $143, 운영환경 월 $2,860 - 확장성: 개발환경 100명 → 운영환경 10,000명 (100배) - 가용성: 개발환경 95% → 운영환경 99.9% - 보안: 다층 보안 아키텍처 (L1~L4) 🛠️ 기술 스택 - Azure Kubernetes Service (AKS) - Azure Database for PostgreSQL Flexible - Azure Cache for Redis Premium - Azure Service Bus Premium - Application Gateway + WAF 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,450 @@
|
||||
@startuml
|
||||
!theme mono
|
||||
|
||||
title User Service 클래스 다이어그램 (상세)
|
||||
|
||||
' ====================
|
||||
' 공통 컴포넌트 (참조)
|
||||
' ====================
|
||||
package "com.kt.event.common" <<rectangle>> {
|
||||
abstract class BaseTimeEntity {
|
||||
- createdAt: LocalDateTime
|
||||
- updatedAt: LocalDateTime
|
||||
}
|
||||
|
||||
interface ErrorCode {
|
||||
+ getCode(): String
|
||||
+ getMessage(): String
|
||||
}
|
||||
|
||||
class BusinessException extends RuntimeException {
|
||||
- errorCode: ErrorCode
|
||||
+ getErrorCode(): ErrorCode
|
||||
}
|
||||
|
||||
interface JwtTokenProvider {
|
||||
+ createAccessToken(): String
|
||||
+ validateToken(): boolean
|
||||
+ getExpirationFromToken(): Date
|
||||
}
|
||||
}
|
||||
|
||||
package "com.kt.event.user" {
|
||||
|
||||
' ====================
|
||||
' Presentation Layer
|
||||
' ====================
|
||||
package "controller" {
|
||||
class UserController {
|
||||
- userService: UserService
|
||||
- authenticationService: AuthenticationService
|
||||
|
||||
' UFR-USER-010: 회원가입
|
||||
+ register(request: RegisterRequest): ResponseEntity<RegisterResponse>
|
||||
|
||||
' UFR-USER-020: 로그인
|
||||
+ login(request: LoginRequest): ResponseEntity<LoginResponse>
|
||||
|
||||
' UFR-USER-040: 로그아웃
|
||||
+ logout(authHeader: String): ResponseEntity<LogoutResponse>
|
||||
|
||||
' UFR-USER-030: 프로필 관리
|
||||
+ getProfile(principal: UserPrincipal): ResponseEntity<ProfileResponse>
|
||||
+ updateProfile(principal: UserPrincipal, request: UpdateProfileRequest): ResponseEntity<ProfileResponse>
|
||||
+ changePassword(principal: UserPrincipal, request: ChangePasswordRequest): ResponseEntity<Void>
|
||||
}
|
||||
}
|
||||
|
||||
' ====================
|
||||
' Business Layer (Service)
|
||||
' ====================
|
||||
package "service" {
|
||||
interface UserService {
|
||||
+ register(request: RegisterRequest): RegisterResponse
|
||||
+ getProfile(userId: UUID): ProfileResponse
|
||||
+ updateProfile(userId: UUID, request: UpdateProfileRequest): ProfileResponse
|
||||
+ changePassword(userId: UUID, request: ChangePasswordRequest): void
|
||||
+ updateLastLoginAt(userId: UUID): void
|
||||
}
|
||||
|
||||
interface AuthenticationService {
|
||||
+ login(request: LoginRequest): LoginResponse
|
||||
+ logout(token: String): LogoutResponse
|
||||
}
|
||||
}
|
||||
|
||||
package "service.impl" {
|
||||
class UserServiceImpl implements UserService {
|
||||
- userRepository: UserRepository
|
||||
- storeRepository: StoreRepository
|
||||
- passwordEncoder: PasswordEncoder
|
||||
- jwtTokenProvider: JwtTokenProvider
|
||||
- redisTemplate: RedisTemplate<String, Object>
|
||||
|
||||
' UFR-USER-010: 회원가입
|
||||
+ register(request: RegisterRequest): RegisterResponse
|
||||
|
||||
' UFR-USER-030: 프로필 관리
|
||||
+ getProfile(userId: UUID): ProfileResponse
|
||||
+ updateProfile(userId: UUID, request: UpdateProfileRequest): ProfileResponse
|
||||
+ changePassword(userId: UUID, request: ChangePasswordRequest): void
|
||||
|
||||
' UFR-USER-020: 로그인 시각 업데이트
|
||||
+ updateLastLoginAt(userId: UUID): void
|
||||
|
||||
' 내부 메소드
|
||||
- saveSession(token: String, userId: UUID, role: String): void
|
||||
}
|
||||
|
||||
class AuthenticationServiceImpl implements AuthenticationService {
|
||||
- userRepository: UserRepository
|
||||
- storeRepository: StoreRepository
|
||||
- passwordEncoder: PasswordEncoder
|
||||
- jwtTokenProvider: JwtTokenProvider
|
||||
- userService: UserService
|
||||
- redisTemplate: RedisTemplate<String, Object>
|
||||
|
||||
' UFR-USER-020: 로그인
|
||||
+ login(request: LoginRequest): LoginResponse
|
||||
|
||||
' UFR-USER-040: 로그아웃
|
||||
+ logout(token: String): LogoutResponse
|
||||
|
||||
' 내부 메소드
|
||||
- saveSession(token: String, userId: UUID, role: String): void
|
||||
}
|
||||
}
|
||||
|
||||
' ====================
|
||||
' Data Access Layer
|
||||
' ====================
|
||||
package "repository" {
|
||||
interface UserRepository extends JpaRepository {
|
||||
+ findByEmail(email: String): Optional<User>
|
||||
+ findByPhoneNumber(phoneNumber: String): Optional<User>
|
||||
+ existsByEmail(email: String): boolean
|
||||
+ existsByPhoneNumber(phoneNumber: String): boolean
|
||||
+ updateLastLoginAt(userId: UUID, lastLoginAt: LocalDateTime): void
|
||||
}
|
||||
|
||||
interface StoreRepository extends JpaRepository {
|
||||
+ findByUserId(userId: UUID): Optional<Store>
|
||||
}
|
||||
}
|
||||
|
||||
' ====================
|
||||
' Domain Layer
|
||||
' ====================
|
||||
package "entity" {
|
||||
class User extends BaseTimeEntity {
|
||||
- id: UUID
|
||||
- name: String
|
||||
- phoneNumber: String
|
||||
- email: String
|
||||
- passwordHash: String
|
||||
- role: UserRole
|
||||
- status: UserStatus
|
||||
- lastLoginAt: LocalDateTime
|
||||
- store: Store
|
||||
|
||||
' 비즈니스 로직
|
||||
+ updateLastLoginAt(): void
|
||||
+ changePassword(newPasswordHash: String): void
|
||||
+ updateProfile(name: String, email: String, phoneNumber: String): void
|
||||
+ setStore(store: Store): void
|
||||
}
|
||||
|
||||
enum UserRole {
|
||||
OWNER
|
||||
ADMIN
|
||||
}
|
||||
|
||||
enum UserStatus {
|
||||
ACTIVE
|
||||
INACTIVE
|
||||
LOCKED
|
||||
WITHDRAWN
|
||||
}
|
||||
|
||||
class Store extends BaseTimeEntity {
|
||||
- id: UUID
|
||||
- name: String
|
||||
- industry: String
|
||||
- address: String
|
||||
- businessHours: String
|
||||
- user: User
|
||||
|
||||
' 비즈니스 로직
|
||||
+ updateInfo(name: String, industry: String, address: String, businessHours: String): void
|
||||
~ setUser(user: User): void
|
||||
}
|
||||
}
|
||||
|
||||
' ====================
|
||||
' DTO Layer
|
||||
' ====================
|
||||
package "dto.request" {
|
||||
class RegisterRequest {
|
||||
- name: String
|
||||
- phoneNumber: String
|
||||
- email: String
|
||||
- password: String
|
||||
- storeName: String
|
||||
- industry: String
|
||||
- address: String
|
||||
- businessHours: String
|
||||
}
|
||||
|
||||
class LoginRequest {
|
||||
- email: String
|
||||
- password: String
|
||||
}
|
||||
|
||||
class UpdateProfileRequest {
|
||||
- name: String
|
||||
- email: String
|
||||
- phoneNumber: String
|
||||
- storeName: String
|
||||
- industry: String
|
||||
- address: String
|
||||
- businessHours: String
|
||||
}
|
||||
|
||||
class ChangePasswordRequest {
|
||||
- currentPassword: String
|
||||
- newPassword: String
|
||||
}
|
||||
}
|
||||
|
||||
package "dto.response" {
|
||||
class RegisterResponse {
|
||||
- token: String
|
||||
- userId: UUID
|
||||
- userName: String
|
||||
- storeId: UUID
|
||||
- storeName: String
|
||||
}
|
||||
|
||||
class LoginResponse {
|
||||
- token: String
|
||||
- userId: UUID
|
||||
- userName: String
|
||||
- role: String
|
||||
- email: String
|
||||
}
|
||||
|
||||
class LogoutResponse {
|
||||
- success: boolean
|
||||
- message: String
|
||||
}
|
||||
|
||||
class ProfileResponse {
|
||||
- userId: UUID
|
||||
- userName: String
|
||||
- phoneNumber: String
|
||||
- email: String
|
||||
- role: String
|
||||
- storeId: UUID
|
||||
- storeName: String
|
||||
- industry: String
|
||||
- address: String
|
||||
- businessHours: String
|
||||
- createdAt: LocalDateTime
|
||||
- lastLoginAt: LocalDateTime
|
||||
}
|
||||
}
|
||||
|
||||
' ====================
|
||||
' Exception Layer
|
||||
' ====================
|
||||
package "exception" {
|
||||
enum UserErrorCode {
|
||||
USER_DUPLICATE_EMAIL
|
||||
USER_DUPLICATE_PHONE
|
||||
USER_NOT_FOUND
|
||||
AUTH_FAILED
|
||||
AUTH_INVALID_TOKEN
|
||||
AUTH_TOKEN_EXPIRED
|
||||
AUTH_UNAUTHORIZED
|
||||
PWD_INVALID_CURRENT
|
||||
PWD_SAME_AS_CURRENT
|
||||
|
||||
- errorCode: ErrorCode
|
||||
+ getCode(): String
|
||||
+ getMessage(): String
|
||||
}
|
||||
}
|
||||
|
||||
' ====================
|
||||
' Configuration Layer
|
||||
' ====================
|
||||
package "config" {
|
||||
class SecurityConfig {
|
||||
- jwtTokenProvider: JwtTokenProvider
|
||||
- allowedOrigins: String
|
||||
|
||||
+ filterChain(http: HttpSecurity): SecurityFilterChain
|
||||
+ corsConfigurationSource(): CorsConfigurationSource
|
||||
+ passwordEncoder(): PasswordEncoder
|
||||
}
|
||||
|
||||
class RedisConfig {
|
||||
- redisHost: String
|
||||
- redisPort: int
|
||||
|
||||
+ redisConnectionFactory(): RedisConnectionFactory
|
||||
+ redisTemplate(): RedisTemplate<String, Object>
|
||||
}
|
||||
|
||||
class AsyncConfig {
|
||||
+ taskExecutor(): Executor
|
||||
}
|
||||
|
||||
class SwaggerConfig {
|
||||
+ customOpenAPI(): OpenAPI
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
' ====================
|
||||
' Layer 간 의존성 관계
|
||||
' ====================
|
||||
|
||||
' Controller → Service
|
||||
UserController --> UserService : uses
|
||||
UserController --> AuthenticationService : uses
|
||||
|
||||
' Service → Repository
|
||||
UserServiceImpl --> UserRepository : uses
|
||||
UserServiceImpl --> StoreRepository : uses
|
||||
AuthenticationServiceImpl --> UserRepository : uses
|
||||
AuthenticationServiceImpl --> StoreRepository : uses
|
||||
AuthenticationServiceImpl --> UserService : uses
|
||||
|
||||
' Service → Entity (도메인 로직 호출)
|
||||
UserServiceImpl ..> User : creates/updates
|
||||
UserServiceImpl ..> Store : creates/updates
|
||||
AuthenticationServiceImpl ..> User : reads
|
||||
|
||||
' Repository → Entity
|
||||
UserRepository --> User : manages
|
||||
StoreRepository --> Store : manages
|
||||
|
||||
' Service → DTO
|
||||
UserServiceImpl ..> RegisterRequest : receives
|
||||
UserServiceImpl ..> UpdateProfileRequest : receives
|
||||
UserServiceImpl ..> ChangePasswordRequest : receives
|
||||
UserServiceImpl ..> RegisterResponse : returns
|
||||
UserServiceImpl ..> ProfileResponse : returns
|
||||
AuthenticationServiceImpl ..> LoginRequest : receives
|
||||
AuthenticationServiceImpl ..> LoginResponse : returns
|
||||
AuthenticationServiceImpl ..> LogoutResponse : returns
|
||||
|
||||
' Controller → DTO
|
||||
UserController ..> RegisterRequest : receives
|
||||
UserController ..> LoginRequest : receives
|
||||
UserController ..> UpdateProfileRequest : receives
|
||||
UserController ..> ChangePasswordRequest : receives
|
||||
UserController ..> RegisterResponse : returns
|
||||
UserController ..> LoginResponse : returns
|
||||
UserController ..> LogoutResponse : returns
|
||||
UserController ..> ProfileResponse : returns
|
||||
|
||||
' Entity 관계
|
||||
User "1" -- "0..1" Store : has >
|
||||
User +-- UserRole
|
||||
User +-- UserStatus
|
||||
|
||||
' Exception
|
||||
UserServiceImpl ..> UserErrorCode : throws
|
||||
AuthenticationServiceImpl ..> UserErrorCode : throws
|
||||
UserErrorCode --> ErrorCode : wraps
|
||||
|
||||
' Configuration
|
||||
SecurityConfig --> JwtTokenProvider : uses
|
||||
SecurityConfig ..> PasswordEncoder : creates
|
||||
UserServiceImpl --> PasswordEncoder : uses
|
||||
AuthenticationServiceImpl --> PasswordEncoder : uses
|
||||
|
||||
' Common 컴포넌트 사용
|
||||
User --|> BaseTimeEntity
|
||||
Store --|> BaseTimeEntity
|
||||
UserServiceImpl ..> JwtTokenProvider : uses
|
||||
AuthenticationServiceImpl ..> JwtTokenProvider : uses
|
||||
UserServiceImpl ..> BusinessException : throws
|
||||
AuthenticationServiceImpl ..> BusinessException : throws
|
||||
|
||||
' Notes
|
||||
note top of UserController
|
||||
<b>Presentation Layer</b>
|
||||
- REST API 엔드포인트 제공
|
||||
- 요청/응답 DTO 변환
|
||||
- 인증 정보 추출 (UserPrincipal)
|
||||
- Swagger 문서화
|
||||
end note
|
||||
|
||||
note top of UserService
|
||||
<b>Business Layer</b>
|
||||
- 비즈니스 로직 처리
|
||||
- 트랜잭션 관리
|
||||
- 도메인 객체 조작
|
||||
- 검증 및 예외 처리
|
||||
end note
|
||||
|
||||
note top of UserRepository
|
||||
<b>Data Access Layer</b>
|
||||
- JPA 기반 데이터 액세스
|
||||
- CRUD 및 커스텀 쿼리
|
||||
- 트랜잭션 경계
|
||||
end note
|
||||
|
||||
note top of User
|
||||
<b>Domain Layer</b>
|
||||
- 핵심 비즈니스 엔티티
|
||||
- 도메인 로직 포함
|
||||
- 불변성 및 일관성 보장
|
||||
end note
|
||||
|
||||
note right of UserServiceImpl
|
||||
<b>핵심 기능</b>
|
||||
|
||||
1. 회원가입 (register)
|
||||
- 중복 검증 (이메일, 전화번호)
|
||||
- 비밀번호 해싱
|
||||
- User/Store 생성
|
||||
- JWT 토큰 발급
|
||||
- Redis 세션 저장
|
||||
|
||||
2. 프로필 관리
|
||||
- 프로필 조회/수정
|
||||
- 비밀번호 변경 (현재 비밀번호 검증)
|
||||
|
||||
3. 로그인 시각 업데이트
|
||||
- 비동기 처리 (@Async)
|
||||
end note
|
||||
|
||||
note right of AuthenticationServiceImpl
|
||||
<b>핵심 기능</b>
|
||||
|
||||
1. 로그인 (login)
|
||||
- 이메일/비밀번호 검증
|
||||
- JWT 토큰 발급
|
||||
- Redis 세션 저장
|
||||
- 최종 로그인 시각 업데이트
|
||||
|
||||
2. 로그아웃 (logout)
|
||||
- JWT 토큰 검증
|
||||
- Redis 세션 삭제
|
||||
- JWT Blacklist 추가
|
||||
end note
|
||||
|
||||
note bottom of User
|
||||
<b>User-Store 관계</b>
|
||||
|
||||
- OneToOne 양방향 관계
|
||||
- User가 Store를 소유
|
||||
- Cascade ALL, Orphan Removal
|
||||
- Lazy Loading
|
||||
end note
|
||||
|
||||
@enduml
|
||||
Reference in New Issue
Block a user