jhbkjh 3075a5d49f 물리아키텍처 설계 완료
 주요 기능
- 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>
2025-10-29 15:13:01 +09:00

451 lines
13 KiB
Plaintext

@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