@startuml !theme mono title 여행 프로파일 서비스 - 클래스 다이어그램 ' 공통 컴포넌트 import !include common-base.txt package "com.unicorn.tripgen.profile" { ' Controller Layer package "controller" { class MemberController { - memberService: MemberService + getMembers(): ResponseEntity> + createMember(request: MemberRequest): ResponseEntity + getMemberById(memberId: UUID): ResponseEntity + updateMember(memberId: UUID, request: MemberRequest): ResponseEntity + deleteMember(memberId: UUID): ResponseEntity } class TripController { - tripService: TripService + getTrips(): ResponseEntity> + createTrip(request: TripRequest): ResponseEntity + getTripById(tripId: UUID): ResponseEntity + updateTrip(tripId: UUID, request: TripRequest): ResponseEntity + deleteTrip(tripId: UUID): ResponseEntity } class TransportController { - transportService: TransportService + getTransportSettings(tripId: UUID): ResponseEntity> + createTransportSetting(tripId: UUID, request: TransportSettingRequest): ResponseEntity + updateTransportSetting(tripId: UUID, transportId: UUID, request: TransportSettingRequest): ResponseEntity + deleteTransportSetting(tripId: UUID, transportId: UUID): ResponseEntity } } ' Service Layer package "service" { interface MemberService { + findAll(): List + findById(memberId: UUID): Member + create(memberDto: MemberDto): Member + update(memberId: UUID, memberDto: MemberDto): Member + delete(memberId: UUID): void + existsById(memberId: UUID): Boolean } class MemberServiceImpl implements MemberService { - memberRepository: MemberRepository - memberMapper: MemberMapper - cacheManager: CacheManager + findAll(): List + findById(memberId: UUID): Member + create(memberDto: MemberDto): Member + update(memberId: UUID, memberDto: MemberDto): Member + delete(memberId: UUID): void + existsById(memberId: UUID): Boolean - validateMember(memberDto: MemberDto): void - invalidateCache(memberId: UUID): void } interface TripService { + findAll(): List + findById(tripId: UUID): Trip + create(tripDto: TripDto): Trip + update(tripId: UUID, tripDto: TripDto): Trip + delete(tripId: UUID): void + addMemberToTrip(tripId: UUID, memberId: UUID): void + removeMemberFromTrip(tripId: UUID, memberId: UUID): void } class TripServiceImpl implements TripService { - tripRepository: TripRepository - memberService: MemberService - tripMapper: TripMapper - cacheManager: CacheManager - locationService: LocationService + findAll(): List + findById(tripId: UUID): Trip + create(tripDto: TripDto): Trip + update(tripId: UUID, tripDto: TripDto): Trip + delete(tripId: UUID): void + addMemberToTrip(tripId: UUID, memberId: UUID): void + removeMemberFromTrip(tripId: UUID, memberId: UUID): void - validateTrip(tripDto: TripDto): void - validateDateRange(startDate: LocalDate, endDate: LocalDate): void - enrichLocationData(location: Location): Location } interface TransportService { + findByTripId(tripId: UUID): List + create(tripId: UUID, transportDto: TransportSettingDto): TransportSetting + update(transportId: UUID, transportDto: TransportSettingDto): TransportSetting + delete(transportId: UUID): void + getDefaultTransport(tripId: UUID): TransportSetting } class TransportServiceImpl implements TransportService { - transportRepository: TransportSettingRepository - tripService: TripService - transportMapper: TransportSettingMapper + findByTripId(tripId: UUID): List + create(tripId: UUID, transportDto: TransportSettingDto): TransportSetting + update(transportId: UUID, transportDto: TransportSettingDto): TransportSetting + delete(transportId: UUID): void + getDefaultTransport(tripId: UUID): TransportSetting - ensureOnlyOneDefault(tripId: UUID, transportId: UUID): void } class LocationService { - restTemplate: RestTemplate - apiKey: String + geocode(address: String): Location + reverseGeocode(latitude: Double, longitude: Double): Location + validateCoordinates(latitude: Double, longitude: Double): Boolean } } ' Repository Layer package "repository" { interface MemberRepository extends JpaRepository { + findByNameContaining(name: String): List + findByAgeRange(minAge: Integer, maxAge: Integer): List + findByHealthStatus(status: HealthStatus): List } interface TripRepository extends JpaRepository { + findByDateRange(startDate: LocalDate, endDate: LocalDate): List + findByMemberId(memberId: UUID): List + findByDestinationCity(city: String): List + existsByTripNameAndDateRange(name: String, start: LocalDate, end: LocalDate): Boolean } interface TransportSettingRepository extends JpaRepository { + findByTripId(tripId: UUID): List + findByTripIdAndDate(tripId: UUID, date: LocalDate): Optional + findDefaultByTripId(tripId: UUID): Optional + deleteByTripId(tripId: UUID): void } } ' Domain/Entity Layer package "domain" { class Member implements Identifiable, Auditable { - id: UUID - name: String - age: Integer - healthStatus: HealthStatus - healthNote: String - preferences: Set - createdAt: LocalDateTime - updatedAt: LocalDateTime - createdBy: String - updatedBy: String + Member() + addPreference(preference: PreferenceType): void + removePreference(preference: PreferenceType): void + isHealthy(): Boolean } class Trip implements Identifiable, Auditable, Versionable { - id: UUID - tripName: String - startDate: LocalDate - endDate: LocalDate - origin: Location - destination: Location - accommodation: Accommodation - members: Set - transportSettings: Set - version: Long - createdAt: LocalDateTime - updatedAt: LocalDateTime - createdBy: String - updatedBy: String + Trip() + addMember(member: Member): void + removeMember(member: Member): void + getDuration(): Integer + isActive(): Boolean } class TransportSetting implements Identifiable, Auditable { - id: UUID - trip: Trip - date: LocalDate - transportType: TransportType - isDefault: Boolean - createdAt: LocalDateTime - updatedAt: LocalDateTime - createdBy: String - updatedBy: String + TransportSetting() + appliesTo(date: LocalDate): Boolean } class Location { - country: String - city: String - address: String - latitude: Double - longitude: Double + Location() + getDisplayName(): String + calculateDistance(other: Location): Double } class Accommodation { - name: String - address: String - phone: String - checkInTime: LocalTime - checkOutTime: LocalTime + Accommodation() + isValidCheckInTime(time: LocalTime): Boolean + isValidCheckOutTime(time: LocalTime): Boolean } enum HealthStatus { GOOD CAUTION LIMITED } enum PreferenceType { CULTURE NATURE ACTIVITY FOOD SHOPPING } enum TransportType { PUBLIC_TRANSPORT PRIVATE_CAR WALKING BICYCLE TAXI } } ' DTO Layer package "dto" { package "request" { class MemberRequest { - name: String - age: Integer - healthStatus: String - healthNote: String - preferences: List + validate(): void } class TripRequest { - tripName: String - startDate: LocalDate - endDate: LocalDate - origin: LocationRequest - destination: LocationRequest - accommodation: AccommodationRequest - memberIds: List + validate(): void } class LocationRequest { - country: String - city: String - address: String + validate(): void } class AccommodationRequest { - name: String - address: String - phone: String - checkInTime: String - checkOutTime: String + validate(): void } class TransportSettingRequest { - date: LocalDate - transportType: String - isDefault: Boolean + validate(): void } } package "response" { class MemberResponse { - id: UUID - name: String - age: Integer - healthStatus: String - healthNote: String - preferences: List - createdAt: LocalDateTime - updatedAt: LocalDateTime + static from(member: Member): MemberResponse } class TripResponse { - id: UUID - tripName: String - startDate: LocalDate - endDate: LocalDate - origin: LocationResponse - destination: LocationResponse - accommodation: AccommodationResponse - memberIds: List - createdAt: LocalDateTime - updatedAt: LocalDateTime + static from(trip: Trip): TripResponse } class LocationResponse { - country: String - city: String - address: String - latitude: Double - longitude: Double + static from(location: Location): LocationResponse } class AccommodationResponse { - name: String - address: String - phone: String - checkInTime: String - checkOutTime: String + static from(accommodation: Accommodation): AccommodationResponse } class TransportSettingResponse { - id: UUID - tripId: UUID - date: LocalDate - transportType: String - isDefault: Boolean - createdAt: LocalDateTime - updatedAt: LocalDateTime + static from(transportSetting: TransportSetting): TransportSettingResponse } } package "internal" { class MemberDto { - name: String - age: Integer - healthStatus: HealthStatus - healthNote: String - preferences: Set } class TripDto { - tripName: String - startDate: LocalDate - endDate: LocalDate - origin: Location - destination: Location - accommodation: Accommodation - memberIds: Set } class TransportSettingDto { - date: LocalDate - transportType: TransportType - isDefault: Boolean } } } ' Mapper Layer package "mapper" { interface MemberMapper { + toEntity(request: MemberRequest): Member + toEntity(dto: MemberDto): Member + toDto(request: MemberRequest): MemberDto + toDto(entity: Member): MemberDto + toResponse(entity: Member): MemberResponse + updateEntity(entity: Member, dto: MemberDto): void } interface TripMapper { + toEntity(request: TripRequest): Trip + toEntity(dto: TripDto): Trip + toDto(request: TripRequest): TripDto + toDto(entity: Trip): TripDto + toResponse(entity: Trip): TripResponse + updateEntity(entity: Trip, dto: TripDto): void } interface TransportSettingMapper { + toEntity(request: TransportSettingRequest): TransportSetting + toEntity(dto: TransportSettingDto): TransportSetting + toDto(request: TransportSettingRequest): TransportSettingDto + toDto(entity: TransportSetting): TransportSettingDto + toResponse(entity: TransportSetting): TransportSettingResponse + updateEntity(entity: TransportSetting, dto: TransportSettingDto): void } } } ' 관계 정의 ' Controller -> Service MemberController --> MemberService TripController --> TripService TransportController --> TransportService ' Service Implementation MemberServiceImpl --> MemberRepository MemberServiceImpl --> MemberMapper TripServiceImpl --> TripRepository TripServiceImpl --> MemberService TripServiceImpl --> TripMapper TripServiceImpl --> LocationService TransportServiceImpl --> TransportSettingRepository TransportServiceImpl --> TripService TransportServiceImpl --> TransportSettingMapper ' Repository -> Domain MemberRepository ..> Member TripRepository ..> Trip TransportSettingRepository ..> TransportSetting ' Domain Relationships Trip "1" *-- "0..*" Member : contains Trip "1" *-- "0..*" TransportSetting : has Trip "1" *-- "1" Location : origin Trip "1" *-- "1" Location : destination Trip "1" *-- "0..1" Accommodation : stays at TransportSetting "*" --> "1" Trip : belongs to Member --> HealthStatus Member --> PreferenceType TransportSetting --> TransportType ' DTO -> Domain mapping MemberMapper ..> Member MemberMapper ..> MemberRequest MemberMapper ..> MemberResponse MemberMapper ..> MemberDto TripMapper ..> Trip TripMapper ..> TripRequest TripMapper ..> TripResponse TripMapper ..> TripDto TransportSettingMapper ..> TransportSetting TransportSettingMapper ..> TransportSettingRequest TransportSettingMapper ..> TransportSettingResponse TransportSettingMapper ..> TransportSettingDto ' Response DTOs relationships TripResponse ..> LocationResponse TripResponse ..> AccommodationResponse LocationResponse ..> Location AccommodationResponse ..> Accommodation ' Request DTOs relationships TripRequest ..> LocationRequest TripRequest ..> AccommodationRequest ' Service -> Common components MemberServiceImpl --> CacheManager TripServiceImpl --> CacheManager LocationService --> RestTemplate @enduml