├── .githooks ├── install.sh └── prepare-commit-msg ├── .github ├── codeowners └── workflows │ ├── develop_server_deployer.yaml │ ├── develop_server_integrator.yaml │ ├── pr_validator.yml │ ├── production_server_deployer.yaml │ └── unit_test_runner.yaml ├── .gitignore ├── Dockerfile-http ├── README.md ├── application ├── build.gradle.kts └── src │ ├── main │ ├── kotlin │ │ └── com │ │ │ └── studentcenter │ │ │ └── weave │ │ │ └── application │ │ │ ├── chat │ │ │ ├── port │ │ │ │ ├── inbound │ │ │ │ │ ├── CreateChatRoom.kt │ │ │ │ │ ├── GetChatMessage.kt │ │ │ │ │ ├── GetChatRoom.kt │ │ │ │ │ └── SendChatMessage.kt │ │ │ │ └── outbound │ │ │ │ │ ├── ChatMessagePublisher.kt │ │ │ │ │ ├── ChatMessageRepository.kt │ │ │ │ │ └── ChatRoomRepository.kt │ │ │ ├── service │ │ │ │ ├── CreateChatRoomService.kt │ │ │ │ ├── GetChatMessageService.kt │ │ │ │ ├── GetChatRoomService.kt │ │ │ │ └── SendChatMessageService.kt │ │ │ └── vo │ │ │ │ └── ChatRoomDetail.kt │ │ │ ├── common │ │ │ ├── config │ │ │ │ └── ApplicationConfig.kt │ │ │ ├── exception │ │ │ │ ├── AuthException.kt │ │ │ │ └── UniversityVerificationException.kt │ │ │ ├── properties │ │ │ │ ├── JwtTokenProperties.kt │ │ │ │ ├── MeetingTeamInvitationProperties.kt │ │ │ │ └── OpenIdProperties.kt │ │ │ └── security │ │ │ │ └── context │ │ │ │ ├── UserSecurityContext.kt │ │ │ │ └── UserSecuritySupport.kt │ │ │ ├── meeting │ │ │ ├── port │ │ │ │ ├── inbound │ │ │ │ │ ├── CancelAllMeeting.kt │ │ │ │ │ ├── CancelEndedPendingMeeting.kt │ │ │ │ │ ├── CreateMeetingAttendance.kt │ │ │ │ │ ├── FindMyRequestMeetingByReceivingTeamId.kt │ │ │ │ │ ├── GetAllOtherTeamMemberInfo.kt │ │ │ │ │ ├── GetMeetingAttendances.kt │ │ │ │ │ ├── NotifyMeetingEvent.kt │ │ │ │ │ ├── RequestMeeting.kt │ │ │ │ │ ├── ScrollPendingMeeting.kt │ │ │ │ │ └── ScrollPreparedMeeting.kt │ │ │ │ └── outbound │ │ │ │ │ ├── MeetingAttendanceRepository.kt │ │ │ │ │ ├── MeetingEventMessagePort.kt │ │ │ │ │ ├── MeetingEventPublisher.kt │ │ │ │ │ └── MeetingRepository.kt │ │ │ ├── service │ │ │ │ ├── application │ │ │ │ │ ├── CancelAllMeetingService.kt │ │ │ │ │ ├── CancelEndedPendingMeetingService.kt │ │ │ │ │ ├── CreateMeetingAttendanceService.kt │ │ │ │ │ ├── FindMyRequestMeetingByReceivingTeamIdService.kt │ │ │ │ │ ├── GetAllOtherTeamMemberInfoService.kt │ │ │ │ │ ├── GetMeetingAttendancesService.kt │ │ │ │ │ ├── NotifyMeetingEventService.kt │ │ │ │ │ ├── RequestMeetingService.kt │ │ │ │ │ ├── ScrollPendingMeetingService.kt │ │ │ │ │ └── ScrollPreparedMeetingService.kt │ │ │ │ └── domain │ │ │ │ │ ├── MeetingAttendanceDomainService.kt │ │ │ │ │ ├── MeetingDomainService.kt │ │ │ │ │ ├── MeetingEventService.kt │ │ │ │ │ └── impl │ │ │ │ │ ├── MeetingAttendanceDomainServiceImpl.kt │ │ │ │ │ └── MeetingDomainServiceImpl.kt │ │ │ └── vo │ │ │ │ ├── MeetingMatchingEvent.kt │ │ │ │ ├── PendingMeetingInfo.kt │ │ │ │ └── PreparedMeetingInfo.kt │ │ │ ├── meetingTeam │ │ │ ├── port │ │ │ │ ├── inbound │ │ │ │ │ ├── CreateInvitationLink.kt │ │ │ │ │ ├── CreateMeetingTeam.kt │ │ │ │ │ ├── DeleteMeetingTeam.kt │ │ │ │ │ ├── EditMeetingTeam.kt │ │ │ │ │ ├── GetAllMeetingTeamInfo.kt │ │ │ │ │ ├── GetListMeetingTeam.kt │ │ │ │ │ ├── GetMeetingTeam.kt │ │ │ │ │ ├── GetMeetingTeamByInvitationCode.kt │ │ │ │ │ ├── GetMeetingTeamDetail.kt │ │ │ │ │ ├── GetMyMeetingTeam.kt │ │ │ │ │ ├── JoinMeetingTeam.kt │ │ │ │ │ └── LeaveMeetingTeam.kt │ │ │ │ └── outbound │ │ │ │ │ ├── MeetingTeamInvitationRepository.kt │ │ │ │ │ ├── MeetingTeamMemberSummaryRepository.kt │ │ │ │ │ └── MeetingTeamRepository.kt │ │ │ ├── service │ │ │ │ ├── application │ │ │ │ │ ├── CreateInvitationLinkService.kt │ │ │ │ │ ├── CreateMeetingTeamService.kt │ │ │ │ │ ├── DeleteMeetingTeamService.kt │ │ │ │ │ ├── EditMeetingTeamService.kt │ │ │ │ │ ├── GetAllMeetingTeamInfoService.kt │ │ │ │ │ ├── GetListMeetingTeamService.kt │ │ │ │ │ ├── GetMeetingTeamByInvitationCodeService.kt │ │ │ │ │ ├── GetMeetingTeamDetailService.kt │ │ │ │ │ ├── GetMeetingTeamService.kt │ │ │ │ │ ├── GetMyMeetingTeamService.kt │ │ │ │ │ ├── JoinMeetingTeamService.kt │ │ │ │ │ └── LeaveMeetingTeamService.kt │ │ │ │ └── domain │ │ │ │ │ ├── MeetingTeamDomainService.kt │ │ │ │ │ └── impl │ │ │ │ │ └── MeetingTeamDomainServiceImpl.kt │ │ │ ├── util │ │ │ │ ├── MeetingTeamInvitationService.kt │ │ │ │ └── impl │ │ │ │ │ └── MeetingTeamInvitationServiceImpl.kt │ │ │ └── vo │ │ │ │ ├── MeetingMemberDetail.kt │ │ │ │ ├── MeetingTeamInfo.kt │ │ │ │ ├── MeetingTeamInvitation.kt │ │ │ │ ├── MeetingTeamListFilter.kt │ │ │ │ ├── MemberInfo.kt │ │ │ │ └── MyMeetingTeamInfo.kt │ │ │ ├── suggestion │ │ │ ├── port │ │ │ │ ├── inbound │ │ │ │ │ └── CreateSuggestion.kt │ │ │ │ └── outbound │ │ │ │ │ └── SuggestionRepository.kt │ │ │ └── service │ │ │ │ └── CreateSuggestionService.kt │ │ │ ├── university │ │ │ ├── port │ │ │ │ ├── inbound │ │ │ │ │ ├── GetMajor.kt │ │ │ │ │ └── GetUniversity.kt │ │ │ │ └── outbound │ │ │ │ │ ├── MajorRepository.kt │ │ │ │ │ └── UniversityRepository.kt │ │ │ └── service │ │ │ │ ├── application │ │ │ │ ├── GetMajorService.kt │ │ │ │ └── GetUniversityService.kt │ │ │ │ └── domain │ │ │ │ ├── MajorDomainService.kt │ │ │ │ ├── UniversityDomainService.kt │ │ │ │ └── impl │ │ │ │ ├── MajorDomainServiceImpl.kt │ │ │ │ └── UniversityDomainServiceImpl.kt │ │ │ └── user │ │ │ ├── port │ │ │ ├── inbound │ │ │ │ ├── CompleteProfileImageUpload.kt │ │ │ │ ├── GetMyProfile.kt │ │ │ │ ├── GetProfileImageUploadUrl.kt │ │ │ │ ├── GetUser.kt │ │ │ │ ├── Logout.kt │ │ │ │ ├── RefreshToken.kt │ │ │ │ ├── RegisterUser.kt │ │ │ │ ├── SendVerificationEmail.kt │ │ │ │ ├── SocialLogin.kt │ │ │ │ ├── UnregisterUser.kt │ │ │ │ ├── UpdateMyAnimalType.kt │ │ │ │ ├── UpdateMyHeight.kt │ │ │ │ ├── UpdateMyKakaoId.kt │ │ │ │ ├── UpdateMyMbti.kt │ │ │ │ └── VerifyUniversityVerificationNumber.kt │ │ │ └── outbound │ │ │ │ ├── DeletedUserInfoRepository.kt │ │ │ │ ├── UserAuthInfoRepository.kt │ │ │ │ ├── UserEventPort.kt │ │ │ │ ├── UserProfileImageUrlPort.kt │ │ │ │ ├── UserRefreshTokenRepository.kt │ │ │ │ ├── UserRepository.kt │ │ │ │ ├── UserSilRepository.kt │ │ │ │ ├── UserUniversityVerificationInfoRepository.kt │ │ │ │ ├── UserVerificationNumberRepository.kt │ │ │ │ └── VerificationNumberMailer.kt │ │ │ ├── service │ │ │ ├── application │ │ │ │ ├── CompleteProfileImageUploadService.kt │ │ │ │ ├── GetMyProfileService.kt │ │ │ │ ├── GetProfileImageUploadUrlService.kt │ │ │ │ ├── GetUserService.kt │ │ │ │ ├── LogoutService.kt │ │ │ │ ├── RefreshTokenService.kt │ │ │ │ ├── RegisterUserService.kt │ │ │ │ ├── SendVerificationEmailService.kt │ │ │ │ ├── SocialLoginService.kt │ │ │ │ ├── UnregisterUserService.kt │ │ │ │ ├── UpdateMyAnimalTypeService.kt │ │ │ │ ├── UpdateMyHeightService.kt │ │ │ │ ├── UpdateMyKakaoIdService.kt │ │ │ │ ├── UpdateMyMbtiService.kt │ │ │ │ └── VerifyUniversityVerificationNumberService.kt │ │ │ ├── domain │ │ │ │ ├── DeletedUserInfoService.kt │ │ │ │ ├── UserAuthInfoDomainService.kt │ │ │ │ ├── UserDomainService.kt │ │ │ │ ├── UserSilDomainService.kt │ │ │ │ ├── UserUniversityVerificationInfoDomainService.kt │ │ │ │ └── impl │ │ │ │ │ ├── DeletedUserInfoServiceImpl.kt │ │ │ │ │ ├── UserAuthInfoDomainServiceImpl.kt │ │ │ │ │ ├── UserDomainServiceImpl.kt │ │ │ │ │ ├── UserSilDomainServiceImpl.kt │ │ │ │ │ └── UserUniversityVerificationInfoDomainServiceImpl.kt │ │ │ └── util │ │ │ │ ├── UserTokenService.kt │ │ │ │ ├── UserTokenType.kt │ │ │ │ └── impl │ │ │ │ ├── UserTokenServiceImpl.kt │ │ │ │ └── strategy │ │ │ │ ├── AppleOpenIdTokenResolveStrategy.kt │ │ │ │ ├── KakaoOpenIdTokenResolveStrategy.kt │ │ │ │ ├── OpenIdTokenResolveStrategy.kt │ │ │ │ ├── OpenIdTokenResolveStrategyFactory.kt │ │ │ │ └── OpenIdTokenResolveStrategyFactoryImpl.kt │ │ │ └── vo │ │ │ ├── UserAuthentication.kt │ │ │ ├── UserTokenClaims.kt │ │ │ └── UserUniversityVerificationNumber.kt │ └── resources │ │ └── application-application.yaml │ ├── test │ └── kotlin │ │ └── com │ │ └── studentcenter │ │ └── weave │ │ └── application │ │ ├── chat │ │ └── service │ │ │ ├── CreateChatRoomServiceTest.kt │ │ │ ├── GetChatRoomServiceTest.kt │ │ │ └── SendChatMessageServiceTest.kt │ │ ├── meeting │ │ └── service │ │ │ └── application │ │ │ ├── CancelEndedPendingMeetingServiceTest.kt │ │ │ ├── FindMyRequestMeetingByReceivingTeamIdServiceTest.kt │ │ │ ├── GetAllOtherTeamMemberInfoServiceTest.kt │ │ │ ├── GetMeetingAttendancesServiceTest.kt │ │ │ ├── MeetingRequestServiceTest.kt │ │ │ ├── NotifyMeetingEventServiceTest.kt │ │ │ ├── ScrollPendingMeetingServiceTest.kt │ │ │ └── ScrollPreparedMeetingServiceTest.kt │ │ ├── meetingTeam │ │ └── service │ │ │ ├── application │ │ │ ├── CreateInvitationLinkTest.kt │ │ │ ├── CreateMeetingTeamTest.kt │ │ │ ├── DeleteMeetingTeamTest.kt │ │ │ ├── EditMeetingTeamTest.kt │ │ │ ├── GetMeetingTeamByInvitationTest.kt │ │ │ ├── GetMeetingTeamDetailTest.kt │ │ │ ├── JoinMeetingTeamServiceTest.kt │ │ │ └── LeaveMeetingTeamTest.kt │ │ │ └── util │ │ │ └── impl │ │ │ └── MeetingTeamInvitationServiceImplTest.kt │ │ ├── suggestion │ │ └── service │ │ │ └── CreateSuggestionServiceTest.kt │ │ ├── university │ │ └── service │ │ │ └── application │ │ │ ├── GetMajorTest.kt │ │ │ └── GetUniversityTest.kt │ │ └── user │ │ └── service │ │ ├── application │ │ ├── CompleteProfileImageUploadTest.kt │ │ ├── GetMyProfileTest.kt │ │ ├── GetProfileImageUploadUrlTest.kt │ │ ├── LogoutTest.kt │ │ ├── RefreshTokenTest.kt │ │ ├── RegisterUserTest.kt │ │ ├── SendVerificationEmailTest.kt │ │ ├── SocialLoginTest.kt │ │ ├── UnregisterUserTest.kt │ │ ├── UpdateMyAnimalTypeTest.kt │ │ ├── UpdateMyHeightTest.kt │ │ ├── UpdateMyKakaoIdTest.kt │ │ ├── UpdateMyMbtiTest.kt │ │ └── VerifyUniversityVerificationNumberTest.kt │ │ ├── domain │ │ └── impl │ │ │ ├── UserAuthInfoDomainServiceImplTest.kt │ │ │ └── UserDomainServiceImplTest.kt │ │ └── util │ │ └── impl │ │ ├── UserTokenServiceImplTest.kt │ │ └── strategy │ │ ├── AppleOpenIdTokenResolveStrategyTest.kt │ │ └── KakaoOpenIdTokenResolveStrategyTest.kt │ └── testFixtures │ └── kotlin │ └── com │ └── studentcenter │ └── weave │ └── application │ ├── chat │ └── outbound │ │ ├── ChatMessagePublisherSpy.kt │ │ ├── ChatMessageRepositorySpy.kt │ │ └── ChatRoomRepositorySpy.kt │ ├── common │ └── properties │ │ ├── JwtTokenPropertiesFixtureFactory.kt │ │ ├── MeetingTeamInvitationPropertiesFixtureFactory.kt │ │ └── OpenIdPropertiesFixtureFactory.kt │ ├── meeting │ └── outbound │ │ ├── MeetingAttendanceRepositorySpy.kt │ │ ├── MeetingEventMessagePortSpy.kt │ │ └── MeetingRepositorySpy.kt │ ├── meetingTeam │ ├── outbound │ │ ├── MeetingTeamInvitationRepositorySpy.kt │ │ ├── MeetingTeamMemberSummaryRepositorySpy.kt │ │ └── MeetingTeamRepositorySpy.kt │ └── vo │ │ ├── MeetingTeamInfoCreator.kt │ │ └── MeetingTeamInvitationFixtureFactory.kt │ ├── suggestion │ └── outbound │ │ └── SuggestionRepositorySpy.kt │ ├── university │ └── port │ │ └── outbound │ │ ├── MajorRepositorySpy.kt │ │ └── UniversityRepositorySpy.kt │ └── user │ ├── port │ ├── inbound │ │ └── GetUserStub.kt │ └── outbound │ │ ├── DeletedUserInfoRepositorySpy.kt │ │ ├── UserAuthInfoRepositorySpy.kt │ │ ├── UserEventPortStub.kt │ │ ├── UserProfileImageUrlPortStub.kt │ │ ├── UserRefreshTokenRepositorySpy.kt │ │ ├── UserRepositorySpy.kt │ │ ├── UserSilRepositorySpy.kt │ │ ├── UserUniversityVerificationInfoRepositorySpy.kt │ │ └── UserVerificationNumberRepositorySpy.kt │ ├── service │ └── util │ │ └── impl │ │ └── strategy │ │ └── OpenIdTokenResolveStrategyFactoryStub.kt │ └── vo │ ├── UserAuthenticationFixtureFactory.kt │ └── UserTokenClaimsFixtureFactory.kt ├── bootstrap └── http │ ├── build.gradle.kts │ ├── compose-dev.yaml │ ├── compose-local.yaml │ └── src │ ├── main │ ├── kotlin │ │ └── com │ │ │ └── studentcenter │ │ │ └── weave │ │ │ └── bootstrap │ │ │ ├── WeaveHttpApplication.kt │ │ │ ├── auth │ │ │ ├── api │ │ │ │ └── AuthApi.kt │ │ │ ├── controller │ │ │ │ └── AuthRestController.kt │ │ │ └── dto │ │ │ │ ├── RefreshLoginTokenResponse.kt │ │ │ │ ├── RefreshTokenRequest.kt │ │ │ │ ├── SocialLoginRequest.kt │ │ │ │ └── SocialLoginResponse.kt │ │ │ ├── chat │ │ │ ├── api │ │ │ │ ├── ChatMessageApi.kt │ │ │ │ └── ChatRoomApi.kt │ │ │ ├── controller │ │ │ │ ├── ChatMessageHandler.kt │ │ │ │ ├── ChatMessageRestController.kt │ │ │ │ ├── ChatRoomRestController.kt │ │ │ │ └── ChatWebSocketController.kt │ │ │ └── dto │ │ │ │ ├── ChatRoomDetailResponse.kt │ │ │ │ ├── GetChatMessagesRequest.kt │ │ │ │ ├── GetChatMessagesResponse.kt │ │ │ │ └── SendChatMessageRequest.kt │ │ │ ├── common │ │ │ ├── config │ │ │ │ ├── OpenApiConfig.kt │ │ │ │ ├── WebMvcConfig.kt │ │ │ │ └── WebSocketConfig.kt │ │ │ ├── exception │ │ │ │ ├── ApiException.kt │ │ │ │ ├── CustomExceptionHandler.kt │ │ │ │ ├── ErrorResponse.kt │ │ │ │ ├── UnknownExceptionHandler.kt │ │ │ │ └── WebSocketExceptionHandler.kt │ │ │ └── security │ │ │ │ ├── annotation │ │ │ │ ├── RegisterTokenClaim.kt │ │ │ │ └── Secured.kt │ │ │ │ ├── filter │ │ │ │ ├── ExceptionHandlingFilter.kt │ │ │ │ └── JwtAuthenticationFilter.kt │ │ │ │ ├── interceptor │ │ │ │ ├── AuthorizationInterceptor.kt │ │ │ │ ├── StompAuthInterceptor.kt │ │ │ │ └── StompExceptionHandler.kt │ │ │ │ └── resolver │ │ │ │ └── RegisterTokenArgumentResolver.kt │ │ │ ├── meeting │ │ │ ├── api │ │ │ │ └── MeetingApi.kt │ │ │ ├── controller │ │ │ │ ├── MeetingEventHandler.kt │ │ │ │ └── MeetingRestController.kt │ │ │ └── dto │ │ │ │ ├── KakaoIdResponse.kt │ │ │ │ ├── MeetingAttendancesResponse.kt │ │ │ │ ├── MeetingRequestRequest.kt │ │ │ │ ├── MeetingResponse.kt │ │ │ │ ├── MeetingTeamDto.kt │ │ │ │ ├── PendingMeetingScrollRequest.kt │ │ │ │ ├── PendingMeetingScrollResponse.kt │ │ │ │ ├── PreparedMeetingScrollRequest.kt │ │ │ │ └── PreparedMeetingScrollResponse.kt │ │ │ ├── meetingTeam │ │ │ ├── api │ │ │ │ └── MeetingTeamApi.kt │ │ │ ├── controller │ │ │ │ └── MeetingTeamRestController.kt │ │ │ └── dto │ │ │ │ ├── MeetingTeamCreateInvitationResponse.kt │ │ │ │ ├── MeetingTeamCreateRequest.kt │ │ │ │ ├── MeetingTeamEditRequest.kt │ │ │ │ ├── MeetingTeamGetByInvitationCodeResponse.kt │ │ │ │ ├── MeetingTeamGetDetailResponse.kt │ │ │ │ ├── MeetingTeamGetListRequest.kt │ │ │ │ ├── MeetingTeamGetListResponse.kt │ │ │ │ ├── MeetingTeamGetLocationsResponse.kt │ │ │ │ ├── MeetingTeamGetMyRequest.kt │ │ │ │ ├── MeetingTeamGetMyResponse.kt │ │ │ │ └── MeetingTeamMemberDetailResponse.kt │ │ │ ├── scheduler │ │ │ ├── component │ │ │ │ └── PendingMeetingExpireScheduler.kt │ │ │ └── config │ │ │ │ └── SchedulerConfig.kt │ │ │ ├── suggestion │ │ │ ├── api │ │ │ │ └── SuggestionApi.kt │ │ │ ├── controller │ │ │ │ └── SuggestionRestController.kt │ │ │ └── dto │ │ │ │ └── SuggestionCreateRequest.kt │ │ │ ├── university │ │ │ ├── api │ │ │ │ └── UnivApi.kt │ │ │ ├── controller │ │ │ │ └── UnivRestController.kt │ │ │ └── dto │ │ │ │ ├── MajorsResponse.kt │ │ │ │ ├── UniversitiesResponse.kt │ │ │ │ └── UniversityResponse.kt │ │ │ └── user │ │ │ ├── api │ │ │ └── UserApi.kt │ │ │ ├── controller │ │ │ └── UserRestController.kt │ │ │ └── dto │ │ │ ├── UserCompleteProfileImageUploadRequest.kt │ │ │ ├── UserGetAvailableAnimalTypesResponse.kt │ │ │ ├── UserGetMyProfileResponse.kt │ │ │ ├── UserGetProfileImageUploadUrlResponse.kt │ │ │ ├── UserModifyMyMbtiRequest.kt │ │ │ ├── UserRegisterRequest.kt │ │ │ ├── UserRegisterResponse.kt │ │ │ ├── UserSetMyAnimalTypeRequest.kt │ │ │ ├── UserSetMyHeightRequest.kt │ │ │ ├── UserSetMyKakaoIdRequest.kt │ │ │ ├── UserUnivVerificationSendRequest.kt │ │ │ └── UserUnivVerificationVerifyRequest.kt │ └── resources │ │ ├── application.yaml │ │ └── static │ │ └── .well-known │ │ ├── apple-app-site-association │ │ └── assetlinks.json │ ├── test │ ├── kotlin │ │ └── com │ │ │ └── studentcenter │ │ │ └── weave │ │ │ └── bootstrap │ │ │ ├── chat │ │ │ └── controller │ │ │ │ └── ChatMessageHandlerTest.kt │ │ │ ├── common │ │ │ └── security │ │ │ │ ├── filter │ │ │ │ └── JwtAuthenticationFilterTest.kt │ │ │ │ └── interceptor │ │ │ │ └── AuthorizationInterceptorTest.kt │ │ │ └── integration │ │ │ ├── CreateMeetingAttendanceIntegrationTest.kt │ │ │ ├── IntegrationTestDescribeSpec.kt │ │ │ └── UserSilDomainServiceIntegrationTest.kt │ └── resources │ │ └── compose-test.yaml │ └── testFixtures │ └── kotlin │ └── com │ └── studentcenter │ └── weave │ └── bootstrap │ └── controller │ ├── AuthorizationInterceptorTestController.kt │ └── JwtAuthenticationFilterTestController.kt ├── build.gradle.kts ├── docs └── weave-infra.jpg ├── domain ├── build.gradle.kts └── src │ ├── main │ └── kotlin │ │ └── com │ │ └── studentcenter │ │ └── weave │ │ └── domain │ │ ├── chat │ │ └── entity │ │ │ ├── ChatMember.kt │ │ │ ├── ChatMessage.kt │ │ │ └── ChatRoom.kt │ │ ├── common │ │ ├── AggregateRoot.kt │ │ ├── DomainEntity.kt │ │ └── DomainEvent.kt │ │ ├── meeting │ │ ├── entity │ │ │ ├── Meeting.kt │ │ │ └── MeetingAttendance.kt │ │ ├── enums │ │ │ ├── MeetingStatus.kt │ │ │ └── TeamType.kt │ │ ├── event │ │ │ └── MeetingCompletedEvent.kt │ │ └── exception │ │ │ └── MeetingException.kt │ │ ├── meetingTeam │ │ ├── entity │ │ │ ├── MeetingMember.kt │ │ │ ├── MeetingTeam.kt │ │ │ └── MeetingTeamMemberSummary.kt │ │ ├── enums │ │ │ ├── Location.kt │ │ │ ├── MeetingMemberRole.kt │ │ │ └── MeetingTeamStatus.kt │ │ ├── exception │ │ │ └── MeetingTeamException.kt │ │ └── vo │ │ │ └── TeamIntroduce.kt │ │ ├── suggestion │ │ └── entity │ │ │ └── Suggestion.kt │ │ ├── university │ │ ├── entity │ │ │ ├── Major.kt │ │ │ └── University.kt │ │ └── vo │ │ │ ├── MajorName.kt │ │ │ └── UniversityName.kt │ │ └── user │ │ ├── entity │ │ ├── DeletedUserInfo.kt │ │ ├── User.kt │ │ ├── UserAuthInfo.kt │ │ ├── UserProfileImage.kt │ │ ├── UserSil.kt │ │ └── UserUniversityVerificationInfo.kt │ │ ├── enums │ │ ├── AnimalType.kt │ │ ├── Gender.kt │ │ └── SocialLoginProvider.kt │ │ ├── exception │ │ └── UserException.kt │ │ └── vo │ │ ├── BirthYear.kt │ │ ├── Height.kt │ │ ├── KakaoId.kt │ │ ├── Mbti.kt │ │ ├── MbtiAffinityScore.kt │ │ └── Nickname.kt │ ├── test │ └── kotlin │ │ └── com │ │ └── studentcenter │ │ └── weave │ │ └── domain │ │ ├── chat │ │ └── entity │ │ │ └── ChatRoomTest.kt │ │ ├── meeting │ │ └── entity │ │ │ └── MeetingTest.kt │ │ ├── meetingTeam │ │ ├── entity │ │ │ ├── MeetingTeamMemberSummaryTest.kt │ │ │ └── MeetingTeamTest.kt │ │ └── vo │ │ │ └── TeamIntroduceTest.kt │ │ ├── university │ │ ├── entity │ │ │ ├── MajorTest.kt │ │ │ └── UniversityTest.kt │ │ └── vo │ │ │ ├── MajorNameTest.kt │ │ │ └── UniversityNameTest.kt │ │ └── user │ │ ├── entity │ │ ├── DeletedUserInfoTest.kt │ │ ├── UserAuthInfoTest.kt │ │ ├── UserProfileImageTest.kt │ │ ├── UserSilTest.kt │ │ └── UserTest.kt │ │ └── vo │ │ ├── BirthYearTest.kt │ │ ├── HeightTest.kt │ │ ├── MbtiTest.kt │ │ └── NicknameTest.kt │ └── testFixtures │ └── kotlin │ └── com │ └── studentcenter │ └── weave │ └── domain │ ├── chat │ └── entity │ │ ├── ChatMemberFixtureFactory.kt │ │ ├── ChatMessageFixtureFactory.kt │ │ └── ChatRoomFixtureFactory.kt │ ├── meeting │ └── entity │ │ ├── MeetingAttendanceFixtureFactory.kt │ │ └── MeetingFixtureFactory.kt │ ├── meetingTeam │ └── entity │ │ ├── MeetingTeamFixtureFactory.kt │ │ └── MeetingTeamMemberSummaryFixtureFactory.kt │ ├── university │ └── entity │ │ ├── MajorFixtureFactory.kt │ │ └── UniversityFixtureFactory.kt │ └── user │ └── entity │ ├── DeletedUserInfoFixtureFactory.kt │ ├── UserAuthInfoFixtureFactory.kt │ ├── UserFixtureFactory.kt │ └── UserUniversityVerificationInfoFixtureFactory.kt ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── infrastructure ├── aws │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── kotlin │ │ └── com │ │ │ └── studentcenter │ │ │ └── weave │ │ │ └── infrastructure │ │ │ └── aws │ │ │ ├── config │ │ │ └── AwsConfig.kt │ │ │ └── s3 │ │ │ ├── adapter │ │ │ └── UserProfileImageUrlS3Adapter.kt │ │ │ └── config │ │ │ ├── S3BucketProperties.kt │ │ │ └── S3Config.kt │ │ └── resources │ │ └── application-aws.yaml ├── client │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── kotlin │ │ └── com │ │ │ └── studentcenter │ │ │ └── weave │ │ │ └── infrastructure │ │ │ └── client │ │ │ ├── common │ │ │ ├── config │ │ │ │ └── ClientConfig.kt │ │ │ ├── event │ │ │ │ └── EventType.kt │ │ │ └── properties │ │ │ │ └── ClientProperties.kt │ │ │ └── discord │ │ │ ├── common │ │ │ └── vo │ │ │ │ └── DiscordMessage.kt │ │ │ ├── meeting │ │ │ └── adaptor │ │ │ │ └── MeetingEventMessageDiscordAdaptor.kt │ │ │ ├── user │ │ │ └── adaptor │ │ │ │ └── UserEventDiscordAdaptor.kt │ │ │ └── util │ │ │ └── DiscordClient.kt │ │ └── resources │ │ └── application-client.yaml ├── mail │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── kotlin │ │ └── com │ │ │ └── studentcenter │ │ │ └── weave │ │ │ └── infrastructure │ │ │ └── mail │ │ │ ├── adaptor │ │ │ └── VerificationNumberGmailAdaptor.kt │ │ │ ├── common │ │ │ ├── config │ │ │ │ └── MailConfig.kt │ │ │ └── exception │ │ │ │ └── MailException.kt │ │ │ └── ses │ │ │ ├── config │ │ │ └── SesConfig.kt │ │ │ ├── properties │ │ │ └── SesProperties.kt │ │ │ └── service │ │ │ └── AmazonSimpleEmailService.kt │ │ └── resources │ │ ├── application-mail.yaml │ │ └── mail-templates │ │ └── email-verification-number.html ├── persistence │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── kotlin │ │ └── com │ │ │ └── studentcenter │ │ │ └── weave │ │ │ └── infrastructure │ │ │ └── persistence │ │ │ ├── chat │ │ │ ├── adapter │ │ │ │ ├── ChatMessageJpaAdapter.kt │ │ │ │ └── ChatRoomJpaAdapter.kt │ │ │ ├── enitty │ │ │ │ ├── ChatMessageJpaEntity.kt │ │ │ │ └── ChatRoomJpaEntity.kt │ │ │ └── repository │ │ │ │ ├── ChatMessageJpaRepository.kt │ │ │ │ └── ChatRoomJpaRepository.kt │ │ │ ├── common │ │ │ ├── config │ │ │ │ └── PersistenceConfig.kt │ │ │ └── exception │ │ │ │ └── PersistenceException.kt │ │ │ ├── meeting │ │ │ ├── adapter │ │ │ │ ├── MeetingAttendanceJpaAdapter.kt │ │ │ │ └── MeetingJpaAdapter.kt │ │ │ ├── entity │ │ │ │ ├── MeetingAttendanceJpaEntity.kt │ │ │ │ └── MeetingJpaEntity.kt │ │ │ └── repository │ │ │ │ ├── MeetingAttendanceJpaRepository.kt │ │ │ │ └── MeetingJpaRepository.kt │ │ │ ├── meetingTeam │ │ │ ├── adapter │ │ │ │ ├── MeetingTeamJpaAdapter.kt │ │ │ │ └── MeetingTeamMemberSummaryJpaAdapter.kt │ │ │ ├── entity │ │ │ │ ├── MeetingMemberJpaEntity.kt │ │ │ │ ├── MeetingTeamJpaEntity.kt │ │ │ │ └── MeetingTeamMemberSummaryJpaEntity.kt │ │ │ └── repository │ │ │ │ ├── MeetingTeamJpaRepository.kt │ │ │ │ └── MeetingTeamMemberSummaryJpaRepository.kt │ │ │ ├── suggestion │ │ │ ├── adapter │ │ │ │ └── SuggestionJpaAdapter.kt │ │ │ ├── entity │ │ │ │ └── SuggestionJpaEntity.kt │ │ │ └── repository │ │ │ │ └── SuggestionJpaRepository.kt │ │ │ ├── university │ │ │ ├── adapter │ │ │ │ ├── MajorJpaAdapter.kt │ │ │ │ └── UniversityJpaAdapter.kt │ │ │ ├── entity │ │ │ │ ├── MajorJpaEntity.kt │ │ │ │ └── UniversityJpaEntity.kt │ │ │ └── repository │ │ │ │ ├── MajorJpaRepository.kt │ │ │ │ └── UniversityJpaRepository.kt │ │ │ └── user │ │ │ ├── adapter │ │ │ ├── DeletedUserInfoJpaAdapter.kt │ │ │ ├── UserAuthInfoJpaAdapter.kt │ │ │ ├── UserJpaAdapter.kt │ │ │ ├── UserSilJpaAdapter.kt │ │ │ └── UserUniversityVerificationInfoJpaAdapter.kt │ │ │ ├── entity │ │ │ ├── DeletedUserInfoJpaEntity.kt │ │ │ ├── PreRegisteredEmail.kt │ │ │ ├── UserAuthInfoJpaEntity.kt │ │ │ ├── UserJpaEntity.kt │ │ │ ├── UserProfileImageJpaEntity.kt │ │ │ ├── UserSilJpaEntity.kt │ │ │ └── UserUniveristyVerificationInfoJpaEntity.kt │ │ │ └── repository │ │ │ ├── DeletedUserInfoJpaRepository.kt │ │ │ ├── PreRegisteredEmailRepository.kt │ │ │ ├── UserAuthInfoJpaRepository.kt │ │ │ ├── UserJpaRepository.kt │ │ │ ├── UserSilJpaRepository.kt │ │ │ └── UserUniversityVerificationInfoJpaRepository.kt │ │ └── resources │ │ ├── application-persistence.yaml │ │ └── db │ │ ├── migration │ │ ├── V10__update_universities.sql │ │ ├── V11__change_meeting_team_add_gender.sql │ │ ├── V12__create_user_university_verification_info.sql │ │ ├── V13__create_meeting_member.sql │ │ ├── V14__create_meeting_and_meeting_attendance.sql │ │ ├── V15__create_meeting_team_member_summary.sql │ │ ├── V16__add_user_kakao_id.sql │ │ ├── V17__add_university_display_name.sql │ │ ├── V18__add_profile_image.sql │ │ ├── V19__create_chat_room.sql │ │ ├── V1__init_user_auth_info.sql │ │ ├── V20__create_chat_message.sql │ │ ├── V21__create_pre_registered_user.sql │ │ ├── V22__create_suggestion.sql │ │ ├── V2__Create_universities_and_majors.sql │ │ ├── V3__create_user.sql │ │ ├── V4__user_add_column.sql │ │ ├── V5__create_meeting_team.sql │ │ ├── V6__create_deleted_user_info.sql │ │ ├── V7__meeting_team_add_status_column.sql │ │ ├── V8__create_user_sil.sql │ │ └── V9__change_user_id_index_to_unique.sql │ │ └── seed │ │ ├── 230205_insert_university_major.sql │ │ ├── 230408_insert_temp_university_major.sql │ │ ├── insert_meeting.sql │ │ ├── insert_meeting_team_and_meeting_member.sql │ │ └── insert_user.sql └── redis │ ├── build.gradle.kts │ └── src │ └── main │ ├── kotlin │ └── com │ │ └── studentcenter │ │ └── weave │ │ └── infrastructure │ │ └── redis │ │ ├── chat │ │ ├── adapter │ │ │ ├── ChatMessageRedisConsumer.kt │ │ │ └── ChatMessageRedisPublisher.kt │ │ └── config │ │ │ └── ChatMessageRedisConfig.kt │ │ ├── common │ │ ├── config │ │ │ └── RedisConfig.kt │ │ └── properties │ │ │ └── RedisProperties.kt │ │ ├── meetingTeam │ │ ├── adapter │ │ │ └── MeetingTeamInvitationRedisAdapter.kt │ │ ├── entity │ │ │ └── MeetingTeamInvitationRedisHash.kt │ │ └── repository │ │ │ └── MeetingTeamInvitationRedisRepository.kt │ │ └── user │ │ ├── adapter │ │ ├── UserRefreshTokenRedisAdapter.kt │ │ └── UserVerificationNumberRedisAdapter.kt │ │ ├── entity │ │ ├── UserRefreshTokenRedisHash.kt │ │ └── UserVerificationNumberRedisHash.kt │ │ └── repository │ │ ├── UserRefreshTokenRedisRepository.kt │ │ └── UserVerificationNumberRedisRepository.kt │ └── resources │ └── application-redis.yaml ├── settings.gradle.kts └── support ├── common ├── build.gradle.kts └── src │ ├── main │ └── kotlin │ │ └── com │ │ └── studentcenter │ │ └── weave │ │ └── support │ │ └── common │ │ ├── dto │ │ ├── ScrollRequest.kt │ │ └── ScrollResponse.kt │ │ ├── exception │ │ ├── CustomException.kt │ │ └── SystemException.kt │ │ ├── uuid │ │ └── UuidCreator.kt │ │ └── vo │ │ ├── Email.kt │ │ ├── UpdateParam.kt │ │ └── Url.kt │ └── test │ └── kotlin │ └── com │ └── studentcenter │ └── weave │ └── support │ └── common │ └── vo │ ├── EmailTest.kt │ └── UrlTest.kt ├── jacoco └── build.gradle.kts ├── lock ├── build.gradle.kts └── src │ ├── main │ └── kotlin │ │ └── com │ │ └── studentcenter │ │ └── weave │ │ └── support │ │ └── lock │ │ ├── DistributedLock.kt │ │ ├── DistributedLockAspect.kt │ │ ├── DistributedLockConfig.kt │ │ └── DistributedLockTransactionProcessor.kt │ └── testFixtures │ └── kotlin │ └── com │ └── studentcetner │ └── weave │ └── support │ └── lock │ └── DistributedLockTestInitializer.kt ├── logger └── build.gradle.kts └── security ├── build.gradle.kts └── src ├── main └── kotlin │ └── com │ └── studentcenter │ └── weave │ └── support │ └── security │ ├── authority │ └── Authentication.kt │ ├── context │ ├── SecurityContext.kt │ └── SecurityContextHolder.kt │ └── jwt │ ├── exception │ └── JwtException.kt │ ├── util │ └── JwtTokenProvider.kt │ └── vo │ ├── JwtClaims.kt │ └── JwtClaimsDsl.kt └── test └── kotlin └── com └── studentcenter └── weave └── support └── security └── jwt └── util └── JwtTokenProviderTest.kt /.githooks/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp .githooks/* .git/hooks 4 | chmod +x .git/hooks/* 5 | -------------------------------------------------------------------------------- /.githooks/prepare-commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$BRANCHES_TO_SKIP" ]; then 4 | BRANCHES_TO_SKIP=(main release) 5 | fi 6 | 7 | BRANCH_NAME=$(git symbolic-ref --short HEAD) 8 | BRANCH_NAME="${BRANCH_NAME##*/}" 9 | JIRA_ID=`echo $BRANCH_NAME | egrep -o 'WEAV-[0-9]+'` 10 | 11 | BRANCH_EXCLUDED=$(printf "%s\n" "${BRANCHES_TO_SKIP[@]}" | grep -c "^$BRANCH_NAME$") 12 | BRANCH_IN_COMMIT=$(grep -c "$JIRA_ID" $1) 13 | 14 | if [ -n $JIRA_ID ] && ! [[ $BRANCH_EXCLUDED -eq 1 ]] && ! [[ $BRANCH_IN_COMMIT -ge 1 ]]; then 15 | sed -i.bak -e "1s/^/[${JIRA_ID}] /" $1 16 | fi 17 | -------------------------------------------------------------------------------- /.github/codeowners: -------------------------------------------------------------------------------- 1 | * @waterfogSW @dojinyou @rilac1 2 | -------------------------------------------------------------------------------- /Dockerfile-http: -------------------------------------------------------------------------------- 1 | # Build stage 2 | FROM gradle:jdk17 AS build 3 | COPY --chown=gradle:gradle . /home/gradle/src 4 | WORKDIR /home/gradle/src 5 | RUN gradle :bootstrap:http:bootJar --no-daemon 6 | 7 | # Package stage 8 | FROM openjdk:17 9 | COPY --from=build /home/gradle/src/bootstrap/http/build/libs/http-*.jar /app.jar 10 | EXPOSE 8080 11 | ENTRYPOINT ["java","-jar","/app.jar"] 12 | -------------------------------------------------------------------------------- /application/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.tasks.bundling.BootJar 2 | 3 | val jar: Jar by tasks 4 | val bootJar: BootJar by tasks 5 | 6 | bootJar.enabled = false 7 | jar.enabled = true 8 | 9 | dependencies { 10 | implementation(project(":support:lock")) 11 | implementation(project(":support:common")) 12 | implementation(project(":support:security")) 13 | implementation(project(":domain")) 14 | 15 | implementation(libs.spring.tx) 16 | implementation(libs.spring.boot.core) 17 | testImplementation(testFixtures(project(":domain"))) 18 | testFixturesImplementation(testFixtures(project(":domain"))) 19 | testFixturesImplementation(testFixtures(project(":support:lock"))) 20 | } 21 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/chat/port/inbound/CreateChatRoom.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.chat.port.inbound 2 | 3 | import com.studentcenter.weave.domain.meeting.event.MeetingCompletedEvent 4 | 5 | interface CreateChatRoom { 6 | 7 | fun invoke(meetingCompletedEvent: MeetingCompletedEvent) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/chat/port/inbound/GetChatMessage.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.chat.port.inbound 2 | 3 | import com.studentcenter.weave.domain.chat.entity.ChatMessage 4 | import com.studentcenter.weave.support.common.dto.ScrollRequest 5 | import com.studentcenter.weave.support.common.dto.ScrollResponse 6 | import java.util.UUID 7 | 8 | interface GetChatMessage { 9 | 10 | fun getScrollList(query: ScrollListQuery): ScrollListResult 11 | 12 | data class ScrollListQuery( 13 | val chatRoomId: UUID, 14 | override val next: UUID?, 15 | override val limit: Int 16 | ) : ScrollRequest( 17 | next = next, 18 | limit = limit 19 | ) 20 | 21 | data class ScrollListResult( 22 | override val items: List, 23 | override val next: UUID?, 24 | ) : ScrollResponse( 25 | items = items, 26 | next = next, 27 | total = items.size, 28 | ) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/chat/port/inbound/GetChatRoom.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.chat.port.inbound 2 | 3 | import com.studentcenter.weave.application.chat.vo.ChatRoomDetail 4 | import java.util.* 5 | 6 | interface GetChatRoom { 7 | 8 | fun getDetailById(id: UUID): ChatRoomDetail 9 | 10 | } 11 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/chat/port/inbound/SendChatMessage.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.chat.port.inbound 2 | 3 | import com.studentcenter.weave.domain.chat.entity.ChatMessage 4 | import java.util.* 5 | 6 | fun interface SendChatMessage { 7 | 8 | fun invoke( 9 | roomId: UUID, 10 | userId: UUID, 11 | contents: List, 12 | ) 13 | 14 | } 15 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/chat/port/outbound/ChatMessagePublisher.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.chat.port.outbound 2 | 3 | import com.studentcenter.weave.domain.chat.entity.ChatMessage 4 | 5 | interface ChatMessagePublisher { 6 | 7 | fun publish(chatMessage: ChatMessage) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/chat/port/outbound/ChatMessageRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.chat.port.outbound 2 | 3 | import com.studentcenter.weave.application.chat.port.inbound.GetChatMessage 4 | import com.studentcenter.weave.domain.chat.entity.ChatMessage 5 | 6 | interface ChatMessageRepository { 7 | 8 | fun save(chatMessage: ChatMessage) 9 | 10 | fun getScrollList(query: GetChatMessage.ScrollListQuery): List 11 | 12 | } 13 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/chat/port/outbound/ChatRoomRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.chat.port.outbound 2 | 3 | import com.studentcenter.weave.domain.chat.entity.ChatRoom 4 | import java.util.UUID 5 | 6 | interface ChatRoomRepository { 7 | 8 | fun save(chatRoom: ChatRoom) 9 | 10 | fun getById(id: UUID): ChatRoom 11 | 12 | } 13 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/chat/service/CreateChatRoomService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.chat.service 2 | 3 | import com.studentcenter.weave.application.chat.port.inbound.CreateChatRoom 4 | import com.studentcenter.weave.application.chat.port.outbound.ChatRoomRepository 5 | import com.studentcenter.weave.domain.chat.entity.ChatRoom 6 | import com.studentcenter.weave.domain.meeting.event.MeetingCompletedEvent 7 | import org.springframework.stereotype.Service 8 | 9 | @Service 10 | class CreateChatRoomService( 11 | private val chatRoomRepository: ChatRoomRepository, 12 | ) : CreateChatRoom { 13 | 14 | override fun invoke(meetingCompletedEvent: MeetingCompletedEvent) { 15 | ChatRoom 16 | .create(meetingCompletedEvent.entity) 17 | .also { chatRoomRepository.save(it) } 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/common/config/ApplicationConfig.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.common.config 2 | 3 | import org.springframework.boot.context.properties.ConfigurationPropertiesScan 4 | import org.springframework.boot.context.properties.EnableConfigurationProperties 5 | import org.springframework.context.annotation.ComponentScan 6 | import org.springframework.context.annotation.Configuration 7 | 8 | 9 | @Configuration 10 | @ComponentScan(basePackages = ["com.studentcenter.weave.application"], lazyInit = true) 11 | @EnableConfigurationProperties 12 | @ConfigurationPropertiesScan(basePackages = ["com.studentcenter.weave.application"]) 13 | class ApplicationConfig 14 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/common/exception/AuthException.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.common.exception 2 | 3 | import com.studentcenter.weave.support.common.exception.CustomException 4 | 5 | sealed class AuthException( 6 | codeNumber: Int, 7 | message: String, 8 | ) : CustomException(CODE_PREFIX, codeNumber, message) { 9 | 10 | class RefreshTokenNotFound(message: String = "") : 11 | AuthException(codeNumber = 1, message = message) 12 | 13 | class UserNotAuthenticated(message: String = "인증되지 않은 사용자 입니다") : 14 | AuthException(codeNumber = 2, message = message) 15 | 16 | companion object { 17 | const val CODE_PREFIX = "AUTH" 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/common/properties/JwtTokenProperties.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.common.properties 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties 4 | 5 | @ConfigurationProperties(value = "auth.jwt") 6 | data class JwtTokenProperties( 7 | val issuer: String, 8 | val access: TokenProperties, 9 | val refresh: TokenProperties, 10 | val register: TokenProperties, 11 | ) { 12 | 13 | data class TokenProperties( 14 | val expireSeconds: Long, 15 | val secret: String 16 | ) 17 | 18 | } 19 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/common/properties/MeetingTeamInvitationProperties.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.common.properties 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties 4 | 5 | @ConfigurationProperties(value = "meeting.team.invitation") 6 | data class MeetingTeamInvitationProperties( 7 | val urlPrefix: String, 8 | val expireSeconds: Long, 9 | ) 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/common/properties/OpenIdProperties.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.common.properties 2 | 3 | import com.studentcenter.weave.domain.user.enums.SocialLoginProvider 4 | import org.springframework.boot.context.properties.ConfigurationProperties 5 | 6 | @ConfigurationProperties(value = "auth.open-id") 7 | data class OpenIdProperties( 8 | val providers: Map 9 | ) { 10 | data class Properties( 11 | val jwksUri: String, 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/common/security/context/UserSecurityContext.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.common.security.context 2 | 3 | import com.studentcenter.weave.application.user.vo.UserAuthentication 4 | import com.studentcenter.weave.support.security.context.SecurityContext 5 | 6 | class UserSecurityContext( 7 | private var authentication: UserAuthentication, 8 | ) : SecurityContext { 9 | 10 | override fun getAuthentication(): UserAuthentication { 11 | return authentication 12 | } 13 | 14 | override fun setAuthentication(authentication: UserAuthentication) { 15 | this.authentication = authentication 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/common/security/context/UserSecuritySupport.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.common.security.context 2 | 3 | import com.studentcenter.weave.application.common.exception.AuthException 4 | import com.studentcenter.weave.application.user.vo.UserAuthentication 5 | import com.studentcenter.weave.support.security.context.SecurityContextHolder 6 | 7 | fun getCurrentUserAuthentication(): UserAuthentication { 8 | val userAuthentication: UserAuthentication? = SecurityContextHolder 9 | .getContext() 10 | ?.getAuthentication() 11 | 12 | return userAuthentication ?: run { 13 | throw AuthException.UserNotAuthenticated() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/port/inbound/CancelAllMeeting.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.port.inbound 2 | 3 | import java.util.* 4 | 5 | fun interface CancelAllMeeting { 6 | 7 | fun invoke(command: Command) 8 | 9 | data class Command(val teamId: UUID) 10 | } 11 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/port/inbound/CancelEndedPendingMeeting.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.port.inbound 2 | 3 | fun interface CancelEndedPendingMeeting { 4 | 5 | fun invoke() 6 | } 7 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/port/inbound/CreateMeetingAttendance.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.port.inbound 2 | 3 | import java.util.* 4 | 5 | fun interface CreateMeetingAttendance { 6 | 7 | fun invoke(meetingId: UUID, attendance: Boolean) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/port/inbound/FindMyRequestMeetingByReceivingTeamId.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.port.inbound 2 | 3 | import com.studentcenter.weave.domain.meeting.entity.Meeting 4 | import java.util.* 5 | 6 | fun interface FindMyRequestMeetingByReceivingTeamId { 7 | 8 | fun invoke(receivingTeamId: UUID): Meeting? 9 | 10 | } 11 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/port/inbound/GetAllOtherTeamMemberInfo.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.port.inbound 2 | 3 | import com.studentcenter.weave.application.meetingTeam.vo.MemberInfo 4 | import java.util.* 5 | 6 | fun interface GetAllOtherTeamMemberInfo { 7 | 8 | fun invoke(meetingId: UUID): List 9 | 10 | } 11 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/port/inbound/GetMeetingAttendances.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.port.inbound 2 | 3 | import com.studentcenter.weave.domain.meeting.entity.MeetingAttendance 4 | import java.util.* 5 | 6 | fun interface GetMeetingAttendances { 7 | 8 | fun invoke(meetingId: UUID): List 9 | 10 | } 11 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/port/inbound/NotifyMeetingEvent.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.port.inbound 2 | 3 | import com.studentcenter.weave.domain.meeting.event.MeetingCompletedEvent 4 | 5 | interface NotifyMeetingEvent { 6 | 7 | fun notifyMeetingCompleted(meetingCompletedEvent: MeetingCompletedEvent) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/port/inbound/RequestMeeting.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.port.inbound 2 | 3 | import java.util.* 4 | 5 | fun interface RequestMeeting { 6 | 7 | fun invoke(command: Command) 8 | 9 | data class Command( 10 | val receivingMeetingTeamId: UUID, 11 | ) 12 | 13 | } 14 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/port/inbound/ScrollPendingMeeting.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.port.inbound 2 | 3 | import com.studentcenter.weave.application.meeting.vo.PendingMeetingInfo 4 | import com.studentcenter.weave.domain.meeting.enums.TeamType 5 | import com.studentcenter.weave.support.common.dto.ScrollResponse 6 | import java.util.* 7 | 8 | fun interface ScrollPendingMeeting { 9 | 10 | fun invoke(query: Query): Result 11 | 12 | data class Query( 13 | val teamType: TeamType, 14 | val next: UUID?, 15 | val limit: Int, 16 | ) 17 | 18 | data class Result( 19 | override val items: List, 20 | override val next: UUID?, 21 | ) : ScrollResponse( 22 | items = items, 23 | next = next, 24 | total = items.size, 25 | ) 26 | 27 | } 28 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/port/inbound/ScrollPreparedMeeting.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.port.inbound 2 | 3 | import com.studentcenter.weave.application.meeting.vo.PreparedMeetingInfo 4 | import com.studentcenter.weave.support.common.dto.ScrollRequest 5 | import com.studentcenter.weave.support.common.dto.ScrollResponse 6 | import java.util.* 7 | 8 | fun interface ScrollPreparedMeeting { 9 | 10 | fun invoke(query: Query): Result 11 | 12 | data class Query( 13 | override val next: UUID?, 14 | override val limit: Int, 15 | ) : ScrollRequest(next, limit) 16 | 17 | data class Result( 18 | override val items: List, 19 | override val next: UUID?, 20 | ) : ScrollResponse( 21 | items = items, 22 | next = next, 23 | total = items.size, 24 | ) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/port/outbound/MeetingAttendanceRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.port.outbound 2 | 3 | import com.studentcenter.weave.domain.meeting.entity.MeetingAttendance 4 | import java.util.* 5 | 6 | interface MeetingAttendanceRepository { 7 | 8 | fun findAllByMeetingId(meetingId: UUID): List 9 | 10 | fun countByMeetingIdAndIsAttend(meetingId: UUID): Int 11 | 12 | fun save(meetingAttendance: MeetingAttendance) 13 | 14 | fun existsByMeetingIdAndMeetingMemberId(meetingId: UUID, meetingMemberId: UUID): Boolean 15 | 16 | } 17 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/port/outbound/MeetingEventMessagePort.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.port.outbound 2 | 3 | import com.studentcenter.weave.application.meeting.vo.MeetingMatchingEvent 4 | 5 | fun interface MeetingEventMessagePort { 6 | 7 | fun sendMeetingIsMatchedMessage(meetingMatchingEvent: MeetingMatchingEvent) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/port/outbound/MeetingEventPublisher.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.port.outbound 2 | 3 | import com.studentcenter.weave.domain.meeting.event.MeetingCompletedEvent 4 | 5 | interface MeetingEventPublisher { 6 | 7 | fun publish(meetingCompletedEvent: MeetingCompletedEvent) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/service/application/CancelAllMeetingService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.service.application 2 | 3 | import com.studentcenter.weave.application.meeting.port.inbound.CancelAllMeeting 4 | import com.studentcenter.weave.application.meeting.service.domain.MeetingDomainService 5 | import org.springframework.stereotype.Service 6 | import org.springframework.transaction.annotation.Transactional 7 | 8 | @Service 9 | class CancelAllMeetingService( 10 | private val meetingDomainService: MeetingDomainService, 11 | ) : CancelAllMeeting { 12 | 13 | @Transactional 14 | override fun invoke(command: CancelAllMeeting.Command) { 15 | meetingDomainService.cancelAllNotFinishedMeetingByTeamId(command.teamId) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/service/application/CancelEndedPendingMeetingService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.service.application 2 | 3 | import com.studentcenter.weave.application.meeting.port.inbound.CancelEndedPendingMeeting 4 | import com.studentcenter.weave.application.meeting.port.outbound.MeetingRepository 5 | import org.springframework.stereotype.Service 6 | import org.springframework.transaction.annotation.Transactional 7 | 8 | @Service 9 | @Transactional 10 | class CancelEndedPendingMeetingService( 11 | private val meetingRepository: MeetingRepository, 12 | ) : CancelEndedPendingMeeting { 13 | 14 | override fun invoke() { 15 | meetingRepository.cancelEndedPendingMeeting() 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/service/application/GetMeetingAttendancesService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.service.application 2 | 3 | import com.studentcenter.weave.application.meeting.port.inbound.GetMeetingAttendances 4 | import com.studentcenter.weave.application.meeting.service.domain.MeetingAttendanceDomainService 5 | import com.studentcenter.weave.domain.meeting.entity.MeetingAttendance 6 | import org.springframework.stereotype.Service 7 | import java.util.* 8 | 9 | @Service 10 | class GetMeetingAttendancesService( 11 | private val meetingAttendanceDomainService: MeetingAttendanceDomainService, 12 | ) : GetMeetingAttendances { 13 | 14 | override fun invoke(meetingId: UUID): List { 15 | return meetingAttendanceDomainService.findAllByMeetingId(meetingId) 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/service/domain/MeetingAttendanceDomainService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.service.domain 2 | 3 | import com.studentcenter.weave.domain.meeting.entity.MeetingAttendance 4 | import java.util.* 5 | 6 | interface MeetingAttendanceDomainService { 7 | 8 | fun findAllByMeetingId(meetingId: UUID): List 9 | 10 | fun countByMeetingIdAndIsAttend(meetingId: UUID): Int 11 | 12 | fun save(meetingAttendance: MeetingAttendance) 13 | 14 | fun existsByMeetingIdAndMeetingMemberId(meetingId: UUID, meetingMemberId: UUID): Boolean 15 | 16 | } 17 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/service/domain/MeetingEventService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.service.domain 2 | 3 | import com.studentcenter.weave.application.meeting.port.outbound.MeetingEventPublisher 4 | import com.studentcenter.weave.domain.meeting.event.MeetingCompletedEvent 5 | import org.springframework.context.ApplicationEventPublisher 6 | import org.springframework.stereotype.Service 7 | 8 | @Service 9 | class MeetingEventService( 10 | private val eventPublisher: ApplicationEventPublisher, 11 | ): MeetingEventPublisher { 12 | 13 | override fun publish(meetingCompletedEvent: MeetingCompletedEvent) { 14 | eventPublisher.publishEvent(meetingCompletedEvent) 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/vo/MeetingMatchingEvent.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.vo 2 | 3 | import com.studentcenter.weave.domain.meeting.entity.Meeting 4 | import com.studentcenter.weave.domain.user.vo.Mbti 5 | 6 | data class MeetingMatchingEvent( 7 | val meeting: Meeting, 8 | val memberCount: Int, 9 | val matchedMeetingCount: Int, 10 | val requestingMeetingTeamMbti: Mbti, 11 | val receivingMeetingTeamMbti: Mbti, 12 | ) 13 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/vo/PendingMeetingInfo.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.vo 2 | 3 | import com.studentcenter.weave.application.meetingTeam.vo.MeetingTeamInfo 4 | import com.studentcenter.weave.domain.meeting.enums.MeetingStatus 5 | import com.studentcenter.weave.domain.meeting.enums.TeamType 6 | import java.time.LocalDateTime 7 | import java.util.* 8 | 9 | data class PendingMeetingInfo( 10 | val id: UUID, 11 | val requestingTeam: MeetingTeamInfo, 12 | val receivingTeam: MeetingTeamInfo, 13 | val teamType: TeamType, 14 | val status: MeetingStatus, 15 | val createdAt: LocalDateTime, 16 | val pendingEndAt: LocalDateTime, 17 | ) 18 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meeting/vo/PreparedMeetingInfo.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.vo 2 | 3 | import com.studentcenter.weave.application.meetingTeam.vo.MeetingTeamInfo 4 | import com.studentcenter.weave.domain.meeting.enums.MeetingStatus 5 | import java.time.LocalDateTime 6 | import java.util.* 7 | 8 | data class PreparedMeetingInfo( 9 | val id: UUID, 10 | val memberCount: Int, 11 | val otherTeam: MeetingTeamInfo, 12 | val status: MeetingStatus, 13 | val createdAt: LocalDateTime, 14 | ) 15 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/port/inbound/CreateInvitationLink.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.port.inbound 2 | 3 | import com.studentcenter.weave.support.common.vo.Url 4 | import java.util.* 5 | 6 | fun interface CreateInvitationLink { 7 | 8 | fun invoke(meetingTeamId: UUID): Result 9 | 10 | data class Result( 11 | val meetingTeamInvitationCode: UUID, 12 | val meetingTeamInvitationLink: Url, 13 | ) 14 | 15 | } 16 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/port/inbound/CreateMeetingTeam.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.port.inbound 2 | 3 | import com.studentcenter.weave.domain.meetingTeam.enums.Location 4 | import com.studentcenter.weave.domain.meetingTeam.vo.TeamIntroduce 5 | 6 | fun interface CreateMeetingTeam { 7 | 8 | fun invoke(command: Command) 9 | 10 | data class Command( 11 | val teamIntroduce: TeamIntroduce, 12 | val memberCount: Int, 13 | val location: Location 14 | ) 15 | 16 | } 17 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/port/inbound/DeleteMeetingTeam.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.port.inbound 2 | 3 | import java.util.* 4 | 5 | fun interface DeleteMeetingTeam { 6 | 7 | fun invoke(id: UUID) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/port/inbound/EditMeetingTeam.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.port.inbound 2 | 3 | import com.studentcenter.weave.domain.meetingTeam.enums.Location 4 | import com.studentcenter.weave.domain.meetingTeam.vo.TeamIntroduce 5 | import java.util.* 6 | 7 | fun interface EditMeetingTeam { 8 | 9 | fun invoke(command: Command) 10 | 11 | data class Command( 12 | val id: UUID, 13 | val location: Location?, 14 | val memberCount: Int?, 15 | val teamIntroduce: TeamIntroduce?, 16 | ) 17 | 18 | } 19 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/port/inbound/GetAllMeetingTeamInfo.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.port.inbound 2 | 3 | import com.studentcenter.weave.application.meetingTeam.vo.MeetingTeamInfo 4 | import java.util.* 5 | 6 | fun interface GetAllMeetingTeamInfo { 7 | 8 | fun invoke(ids: List): List 9 | 10 | } 11 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/port/inbound/GetMeetingTeamByInvitationCode.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.port.inbound 2 | 3 | import com.studentcenter.weave.domain.meetingTeam.entity.MeetingTeam 4 | import java.util.* 5 | 6 | fun interface GetMeetingTeamByInvitationCode { 7 | 8 | fun invoke(invitationCode: UUID): MeetingTeam 9 | 10 | } 11 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/port/inbound/GetMeetingTeamDetail.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.port.inbound 2 | 3 | import com.studentcenter.weave.application.meetingTeam.vo.MeetingMemberDetail 4 | import com.studentcenter.weave.domain.meetingTeam.entity.MeetingTeam 5 | import com.studentcenter.weave.domain.user.vo.MbtiAffinityScore 6 | import java.util.* 7 | 8 | fun interface GetMeetingTeamDetail { 9 | 10 | fun invoke(command: Command): Result 11 | 12 | data class Command( 13 | val meetingId: UUID 14 | ) 15 | 16 | data class Result( 17 | val meetingTeam: MeetingTeam, 18 | val members: List, 19 | val affinityScore: MbtiAffinityScore? = null 20 | ) 21 | 22 | } 23 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/port/inbound/GetMyMeetingTeam.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.port.inbound 2 | 3 | import com.studentcenter.weave.application.meetingTeam.vo.MyMeetingTeamInfo 4 | import com.studentcenter.weave.support.common.dto.ScrollResponse 5 | import java.util.* 6 | 7 | fun interface GetMyMeetingTeam { 8 | 9 | fun invoke(command: Command): Result 10 | 11 | data class Command( 12 | val next: UUID?, 13 | val limit: Int, 14 | ) 15 | 16 | data class Result( 17 | override val items: List, 18 | override val next: UUID?, 19 | ) : ScrollResponse( 20 | items = items, 21 | next = next, 22 | total = items.size, 23 | ) 24 | 25 | } 26 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/port/inbound/JoinMeetingTeam.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.port.inbound 2 | 3 | import java.util.* 4 | 5 | fun interface JoinMeetingTeam { 6 | 7 | fun invoke(invitationCode: UUID) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/port/inbound/LeaveMeetingTeam.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.port.inbound 2 | 3 | import java.util.* 4 | 5 | fun interface LeaveMeetingTeam { 6 | 7 | fun invoke(id: UUID) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/port/outbound/MeetingTeamInvitationRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.port.outbound 2 | 3 | import com.studentcenter.weave.application.meetingTeam.vo.MeetingTeamInvitation 4 | import java.util.* 5 | 6 | interface MeetingTeamInvitationRepository { 7 | 8 | fun save(meetingTeamInvitation: MeetingTeamInvitation) 9 | 10 | fun findByInvitationCode(invitationCode: UUID): MeetingTeamInvitation? 11 | 12 | } 13 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/port/outbound/MeetingTeamMemberSummaryRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.port.outbound 2 | 3 | import com.studentcenter.weave.domain.meetingTeam.entity.MeetingTeamMemberSummary 4 | import java.util.* 5 | 6 | interface MeetingTeamMemberSummaryRepository { 7 | 8 | fun save(meetingTeamMemberSummary: MeetingTeamMemberSummary) 9 | 10 | fun deleteById(id: UUID) 11 | 12 | fun getById(id: UUID): MeetingTeamMemberSummary 13 | 14 | fun getByMeetingTeamId(meetingTeamId: UUID): MeetingTeamMemberSummary 15 | 16 | } 17 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/service/domain/MeetingTeamDomainService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.service.domain 2 | 3 | import com.studentcenter.weave.domain.meetingTeam.entity.MeetingTeam 4 | import com.studentcenter.weave.domain.meetingTeam.entity.MeetingTeamMemberSummary 5 | import com.studentcenter.weave.domain.user.vo.MbtiAffinityScore 6 | import java.util.* 7 | 8 | interface MeetingTeamDomainService { 9 | 10 | /** 11 | * 팀 간 MBTI 궁합 점수를 계산해요 12 | * @return null - 팀간 MBTI 궁합 점수를 계산할 수 없는 경우 13 | */ 14 | fun calculateTeamMbtiAffinityScore( 15 | meetingTeam: MeetingTeam, 16 | targetMeetingTeam: MeetingTeam, 17 | ): MbtiAffinityScore? 18 | 19 | 20 | fun getMeetingTeamMemberSummaryByMeetingTeamId(meetingTeamId: UUID): MeetingTeamMemberSummary 21 | 22 | } 23 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/util/MeetingTeamInvitationService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.util 2 | 3 | import com.studentcenter.weave.application.meetingTeam.vo.MeetingTeamInvitation 4 | import java.util.* 5 | 6 | interface MeetingTeamInvitationService { 7 | 8 | fun create(teamId: UUID): MeetingTeamInvitation 9 | 10 | fun findByInvitationCode(invitationCode: UUID): MeetingTeamInvitation? 11 | 12 | } 13 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/vo/MeetingTeamInfo.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.vo 2 | 3 | import com.studentcenter.weave.domain.meetingTeam.entity.MeetingTeam 4 | 5 | data class MeetingTeamInfo( 6 | val team: MeetingTeam, 7 | val memberInfos: List 8 | ) 9 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/vo/MeetingTeamInvitation.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.vo 2 | 3 | import com.studentcenter.weave.support.common.vo.Url 4 | import java.util.* 5 | import kotlin.time.Duration 6 | 7 | data class MeetingTeamInvitation( 8 | val teamId: UUID, 9 | val invitationCode: UUID, 10 | val invitationLink: Url, 11 | val expirationDuration: Duration, 12 | ) 13 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/vo/MeetingTeamListFilter.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.vo 2 | 3 | import com.studentcenter.weave.domain.meetingTeam.enums.Location 4 | import com.studentcenter.weave.domain.meetingTeam.enums.MeetingTeamStatus 5 | import com.studentcenter.weave.domain.user.enums.Gender 6 | 7 | data class MeetingTeamListFilter( 8 | val memberCount: Int?, 9 | val youngestMemberBirthYear: Int, 10 | val oldestMemberBirthYear: Int, 11 | val preferredLocations: List?, 12 | val gender: Gender?, 13 | val status: MeetingTeamStatus, 14 | ) 15 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/meetingTeam/vo/MemberInfo.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.vo 2 | 3 | import com.studentcenter.weave.domain.meetingTeam.enums.MeetingMemberRole 4 | import com.studentcenter.weave.domain.university.entity.Major 5 | import com.studentcenter.weave.domain.university.entity.University 6 | import com.studentcenter.weave.domain.user.entity.User 7 | import java.util.* 8 | 9 | data class MemberInfo( 10 | val id: UUID, 11 | val user: User, 12 | val university: University, 13 | val role: MeetingMemberRole, 14 | val major: Major? = null, 15 | ) 16 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/suggestion/port/inbound/CreateSuggestion.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.suggestion.port.inbound 2 | 3 | import java.util.* 4 | 5 | interface CreateSuggestion { 6 | 7 | fun invoke(command: Command) 8 | 9 | data class Command( 10 | val userId: UUID, 11 | val contents: String, 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/suggestion/port/outbound/SuggestionRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.suggestion.port.outbound 2 | 3 | import com.studentcenter.weave.domain.suggestion.entity.Suggestion 4 | 5 | interface SuggestionRepository { 6 | 7 | fun save(suggestion: Suggestion) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/suggestion/service/CreateSuggestionService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.suggestion.service 2 | 3 | import com.studentcenter.weave.application.suggestion.port.inbound.CreateSuggestion 4 | import com.studentcenter.weave.application.suggestion.port.outbound.SuggestionRepository 5 | import com.studentcenter.weave.domain.suggestion.entity.Suggestion 6 | import org.springframework.stereotype.Service 7 | 8 | @Service 9 | class CreateSuggestionService( 10 | private val suggestionRepository: SuggestionRepository, 11 | ) : CreateSuggestion { 12 | 13 | override fun invoke(command: CreateSuggestion.Command) { 14 | Suggestion.create( 15 | userId = command.userId, 16 | contents = command.contents 17 | ).also { 18 | suggestionRepository.save(it) 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/university/port/inbound/GetMajor.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.university.port.inbound 2 | 3 | import com.studentcenter.weave.domain.university.entity.Major 4 | import java.util.* 5 | 6 | interface GetMajor { 7 | 8 | fun getById(id: UUID): Major 9 | 10 | fun findAllByUniversityId(universityId: UUID): List 11 | 12 | } 13 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/university/port/inbound/GetUniversity.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.university.port.inbound 2 | 3 | import com.studentcenter.weave.domain.university.entity.University 4 | import com.studentcenter.weave.domain.university.vo.UniversityName 5 | import java.util.* 6 | 7 | interface GetUniversity { 8 | 9 | fun findAll(): List 10 | 11 | fun getById(id: UUID): University 12 | 13 | fun getByName(name: UniversityName): University 14 | 15 | } 16 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/university/port/outbound/MajorRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.university.port.outbound 2 | 3 | import com.studentcenter.weave.domain.university.entity.Major 4 | import java.util.* 5 | 6 | interface MajorRepository { 7 | 8 | fun getById(id: UUID): Major 9 | 10 | fun findAllByUnivId(univId: UUID): List 11 | 12 | } 13 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/university/port/outbound/UniversityRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.university.port.outbound 2 | 3 | import com.studentcenter.weave.domain.university.entity.University 4 | import com.studentcenter.weave.domain.university.vo.UniversityName 5 | import java.util.* 6 | 7 | interface UniversityRepository { 8 | 9 | fun findAll(): List 10 | 11 | fun getById(id: UUID): University 12 | 13 | fun getByName(name: UniversityName): University 14 | 15 | } 16 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/university/service/application/GetMajorService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.university.service.application 2 | 3 | import com.studentcenter.weave.application.university.port.inbound.GetMajor 4 | import com.studentcenter.weave.application.university.service.domain.MajorDomainService 5 | import com.studentcenter.weave.domain.university.entity.Major 6 | import org.springframework.stereotype.Service 7 | import org.springframework.transaction.annotation.Transactional 8 | import java.util.* 9 | 10 | @Service 11 | @Transactional(readOnly = true) 12 | class GetMajorService( 13 | private val majorDomainService: MajorDomainService, 14 | ): GetMajor { 15 | 16 | override fun getById(id: UUID): Major { 17 | return majorDomainService.getById(id) 18 | } 19 | 20 | override fun findAllByUniversityId(universityId: UUID): List { 21 | return majorDomainService.findAllByUniversityId(universityId) 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/university/service/domain/MajorDomainService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.university.service.domain 2 | 3 | import com.studentcenter.weave.domain.university.entity.Major 4 | import java.util.* 5 | 6 | interface MajorDomainService { 7 | 8 | fun getById(id: UUID): Major 9 | 10 | fun findAllByUniversityId(univId: UUID): List 11 | 12 | } 13 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/university/service/domain/UniversityDomainService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.university.service.domain 2 | 3 | import com.studentcenter.weave.domain.university.entity.University 4 | import com.studentcenter.weave.domain.university.vo.UniversityName 5 | import java.util.* 6 | 7 | interface UniversityDomainService { 8 | 9 | fun findAll(): List 10 | 11 | fun getById(id: UUID): University 12 | 13 | fun getByName(name: UniversityName): University 14 | 15 | } 16 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/university/service/domain/impl/MajorDomainServiceImpl.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.university.service.domain.impl 2 | 3 | import com.studentcenter.weave.application.university.port.outbound.MajorRepository 4 | import com.studentcenter.weave.application.university.service.domain.MajorDomainService 5 | import com.studentcenter.weave.domain.university.entity.Major 6 | import org.springframework.stereotype.Service 7 | import java.util.* 8 | 9 | @Service 10 | class MajorDomainServiceImpl( 11 | private val majorRepository: MajorRepository 12 | ) : MajorDomainService { 13 | override fun getById(id: UUID): Major { 14 | return majorRepository.getById(id) 15 | } 16 | 17 | override fun findAllByUniversityId(univId: UUID): List { 18 | return majorRepository.findAllByUnivId(univId = univId) 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/inbound/CompleteProfileImageUpload.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.UserProfileImage 4 | import java.util.* 5 | 6 | fun interface CompleteProfileImageUpload { 7 | 8 | fun invoke(command: Command) 9 | 10 | data class Command( 11 | val imageId: UUID, 12 | val extension: UserProfileImage.Extension, 13 | ) 14 | 15 | } 16 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/inbound/GetProfileImageUploadUrl.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.UserProfileImage 4 | import com.studentcenter.weave.support.common.vo.Url 5 | import java.util.* 6 | 7 | fun interface GetProfileImageUploadUrl { 8 | 9 | fun invoke(extension: UserProfileImage.Extension): Result 10 | 11 | data class Result( 12 | val imageId: UUID, 13 | val extension: UserProfileImage.Extension, 14 | val uploadUrl: Url, 15 | ) 16 | 17 | } 18 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/inbound/GetUser.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.User 4 | import java.util.* 5 | 6 | interface GetUser { 7 | 8 | fun getById(id: UUID): User 9 | 10 | fun getAllByIds(ids: List): List 11 | 12 | } 13 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/inbound/Logout.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | fun interface Logout { 4 | 5 | fun invoke() 6 | 7 | } 8 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/inbound/RefreshToken.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | 4 | fun interface RefreshToken { 5 | 6 | fun invoke(command: Command): Result 7 | 8 | data class Command( 9 | val refreshToken: String, 10 | ) 11 | 12 | 13 | data class Result( 14 | val accessToken: String, 15 | val refreshToken: String, 16 | ) 17 | 18 | } 19 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/inbound/SendVerificationEmail.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | import com.studentcenter.weave.support.common.vo.Email 4 | 5 | fun interface SendVerificationEmail { 6 | 7 | fun invoke(universityEmail: Email) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/inbound/SocialLogin.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | import com.studentcenter.weave.domain.user.enums.SocialLoginProvider 4 | 5 | fun interface SocialLogin { 6 | 7 | fun invoke(command: Command): Result 8 | 9 | data class Command( 10 | val socialLoginProvider: SocialLoginProvider, 11 | val idToken: String, 12 | ) 13 | 14 | sealed class Result { 15 | 16 | data class Success( 17 | val accessToken: String, 18 | val refreshToken: String, 19 | ) : Result() 20 | 21 | data class NotRegistered( 22 | val registerToken: String, 23 | ) : Result() 24 | 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/inbound/UnregisterUser.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | fun interface UnregisterUser { 4 | 5 | fun invoke(command: Command) 6 | 7 | data class Command( 8 | val reason: String? = null, 9 | ) 10 | 11 | } 12 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/inbound/UpdateMyAnimalType.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | import com.studentcenter.weave.domain.user.enums.AnimalType 4 | 5 | fun interface UpdateMyAnimalType { 6 | 7 | fun invoke(animalType: AnimalType) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/inbound/UpdateMyHeight.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | import com.studentcenter.weave.domain.user.vo.Height 4 | 5 | fun interface UpdateMyHeight { 6 | 7 | fun invoke(height: Height) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/inbound/UpdateMyKakaoId.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | import com.studentcenter.weave.domain.user.vo.KakaoId 4 | 5 | fun interface UpdateMyKakaoId { 6 | 7 | fun invoke(kakaoId: KakaoId) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/inbound/UpdateMyMbti.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | import com.studentcenter.weave.domain.user.vo.Mbti 4 | 5 | fun interface UpdateMyMbti { 6 | 7 | fun invoke(mbti: Mbti) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/inbound/VerifyUniversityVerificationNumber.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | import com.studentcenter.weave.application.user.vo.UserUniversityVerificationNumber 4 | import com.studentcenter.weave.support.common.vo.Email 5 | 6 | fun interface VerifyUniversityVerificationNumber { 7 | 8 | fun invoke(command: Command) 9 | 10 | data class Command( 11 | val universityEmail: Email, 12 | val verificationNumber: UserUniversityVerificationNumber, 13 | ) 14 | 15 | } 16 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/outbound/DeletedUserInfoRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.DeletedUserInfo 4 | 5 | interface DeletedUserInfoRepository { 6 | 7 | fun save(deletedUserInfo: DeletedUserInfo) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/outbound/UserAuthInfoRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.UserAuthInfo 4 | import com.studentcenter.weave.support.common.vo.Email 5 | import java.util.* 6 | 7 | interface UserAuthInfoRepository { 8 | 9 | fun findByEmail(email: Email): UserAuthInfo? 10 | 11 | fun save(userAuthInfo: UserAuthInfo) 12 | 13 | fun getByUserId(userId: UUID): UserAuthInfo 14 | 15 | fun deleteById(id: UUID) 16 | 17 | } 18 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/outbound/UserEventPort.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.User 4 | 5 | fun interface UserEventPort { 6 | 7 | fun sendRegistrationMessage( 8 | user: User, 9 | userCount: Int, 10 | ) 11 | 12 | } 13 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/outbound/UserProfileImageUrlPort.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.UserProfileImage 4 | import com.studentcenter.weave.support.common.vo.Url 5 | import java.util.* 6 | 7 | interface UserProfileImageUrlPort { 8 | 9 | fun getUploadImageUrl( 10 | imageId: UUID, 11 | extension: UserProfileImage.Extension, 12 | ): Url 13 | 14 | fun findByIdAndExtension( 15 | imageId: UUID, 16 | extension: UserProfileImage.Extension, 17 | ): Url 18 | 19 | } 20 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/outbound/UserRefreshTokenRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import java.util.* 4 | 5 | interface UserRefreshTokenRepository { 6 | 7 | fun save( 8 | userId: UUID, 9 | refreshToken: String, 10 | expirationSeconds: Long 11 | ) 12 | 13 | fun existsByUserId(userId: UUID): Boolean 14 | 15 | fun deleteByUserId(userId: UUID) 16 | 17 | } 18 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/outbound/UserRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.User 4 | import com.studentcenter.weave.domain.user.vo.KakaoId 5 | import com.studentcenter.weave.support.common.vo.Email 6 | import java.util.* 7 | 8 | interface UserRepository { 9 | 10 | fun save(user: User) 11 | 12 | fun getById(id: UUID): User 13 | 14 | fun getAllByIds(ids: List): List 15 | 16 | fun findByKakaoId(kakaoId: KakaoId): User? 17 | 18 | fun deleteById(id: UUID) 19 | 20 | fun countAll(): Int 21 | 22 | fun isPreRegisteredEmail(email: Email): Boolean 23 | 24 | } 25 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/outbound/UserSilRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.UserSil 4 | import java.util.UUID 5 | 6 | interface UserSilRepository { 7 | 8 | fun save(userSil: UserSil) 9 | 10 | fun getByUserId(userId: UUID): UserSil 11 | 12 | } 13 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/outbound/UserUniversityVerificationInfoRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.UserUniversityVerificationInfo 4 | import com.studentcenter.weave.support.common.vo.Email 5 | import java.util.* 6 | 7 | interface UserUniversityVerificationInfoRepository { 8 | 9 | fun save(domain: UserUniversityVerificationInfo) 10 | 11 | fun existsByEmail(email: Email): Boolean 12 | 13 | fun existsByUserId(userId: UUID): Boolean 14 | 15 | } 16 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/outbound/UserVerificationNumberRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.application.user.vo.UserUniversityVerificationNumber 4 | import com.studentcenter.weave.support.common.vo.Email 5 | import java.util.* 6 | 7 | interface UserVerificationNumberRepository { 8 | 9 | fun save( 10 | userId: UUID, 11 | universityEmail: Email, 12 | verificationNumber: UserUniversityVerificationNumber, 13 | expirationSeconds: Long, 14 | ) 15 | 16 | fun findByUserId(userId: UUID): Pair? 17 | 18 | fun deleteByUserId(userId: UUID) 19 | 20 | } 21 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/port/outbound/VerificationNumberMailer.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.application.user.vo.UserUniversityVerificationNumber 4 | import com.studentcenter.weave.support.common.vo.Email 5 | import kotlin.time.Duration 6 | 7 | fun interface VerificationNumberMailer { 8 | 9 | fun send( 10 | to: Email, 11 | verificationNumber: UserUniversityVerificationNumber, 12 | expirationDuration: Duration, 13 | ) 14 | 15 | } 16 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/service/application/GetUserService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.service.application 2 | 3 | import com.studentcenter.weave.application.user.port.inbound.GetUser 4 | import com.studentcenter.weave.application.user.port.outbound.UserRepository 5 | import com.studentcenter.weave.domain.user.entity.User 6 | import org.springframework.stereotype.Service 7 | import java.util.* 8 | 9 | @Service 10 | class GetUserService( 11 | private val userRepository: UserRepository, 12 | ) : GetUser { 13 | 14 | override fun getById(id: UUID): User { 15 | return userRepository.getById(id) 16 | } 17 | 18 | override fun getAllByIds(ids: List): List { 19 | return userRepository.getAllByIds(ids) 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/service/application/UpdateMyMbtiService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.service.application 2 | 3 | import com.studentcenter.weave.application.common.security.context.getCurrentUserAuthentication 4 | import com.studentcenter.weave.application.user.port.inbound.UpdateMyMbti 5 | import com.studentcenter.weave.application.user.service.domain.UserDomainService 6 | import com.studentcenter.weave.domain.user.vo.Mbti 7 | import org.springframework.stereotype.Service 8 | 9 | @Service 10 | class UpdateMyMbtiService ( 11 | private val userDomainService: UserDomainService, 12 | ): UpdateMyMbti { 13 | 14 | override fun invoke(mbti: Mbti) { 15 | getCurrentUserAuthentication() 16 | .let { userDomainService.updateById(it.userId, mbti = mbti) } 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/service/domain/DeletedUserInfoService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.service.domain 2 | 3 | import com.studentcenter.weave.domain.user.entity.UserAuthInfo 4 | 5 | interface DeletedUserInfoService { 6 | 7 | fun create( 8 | userAuthInfo: UserAuthInfo, 9 | reason: String? = null, 10 | ) 11 | 12 | } 13 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/service/domain/UserAuthInfoDomainService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.service.domain 2 | 3 | import com.studentcenter.weave.domain.user.entity.User 4 | import com.studentcenter.weave.domain.user.entity.UserAuthInfo 5 | import com.studentcenter.weave.domain.user.enums.SocialLoginProvider 6 | import com.studentcenter.weave.support.common.vo.Email 7 | import java.util.* 8 | 9 | interface UserAuthInfoDomainService { 10 | 11 | fun findByEmail(email: Email): UserAuthInfo? 12 | 13 | fun getByUserId(userId: UUID): UserAuthInfo 14 | 15 | fun deleteById(id: UUID) 16 | 17 | fun create( 18 | user: User, 19 | socialLoginProvider: SocialLoginProvider, 20 | ): UserAuthInfo 21 | 22 | } 23 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/service/domain/UserSilDomainService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.service.domain 2 | 3 | import com.studentcenter.weave.domain.user.entity.UserSil 4 | import java.util.UUID 5 | 6 | interface UserSilDomainService { 7 | 8 | fun create(userId: UUID): UserSil 9 | 10 | fun incrementByUserId(userId: UUID, amount: Long): UserSil 11 | 12 | fun getByUserId(userId: UUID): UserSil 13 | 14 | fun save(userSil: UserSil) 15 | 16 | } 17 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/service/domain/UserUniversityVerificationInfoDomainService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.service.domain 2 | 3 | import com.studentcenter.weave.domain.user.entity.UserUniversityVerificationInfo 4 | import com.studentcenter.weave.support.common.vo.Email 5 | import java.util.* 6 | 7 | interface UserUniversityVerificationInfoDomainService { 8 | 9 | fun save(domain: UserUniversityVerificationInfo) 10 | 11 | fun existsByEmail(email: Email): Boolean 12 | 13 | fun existsByUserId(userId: UUID): Boolean 14 | 15 | } 16 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/service/domain/impl/DeletedUserInfoServiceImpl.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.service.domain.impl 2 | 3 | import com.studentcenter.weave.application.user.port.outbound.DeletedUserInfoRepository 4 | import com.studentcenter.weave.application.user.service.domain.DeletedUserInfoService 5 | import com.studentcenter.weave.domain.user.entity.DeletedUserInfo 6 | import com.studentcenter.weave.domain.user.entity.UserAuthInfo 7 | import org.springframework.stereotype.Service 8 | 9 | @Service 10 | class DeletedUserInfoServiceImpl( 11 | private val deletedUserInfoRepository: DeletedUserInfoRepository, 12 | ) : DeletedUserInfoService { 13 | 14 | override fun create( 15 | userAuthInfo: UserAuthInfo, 16 | reason: String? 17 | ) { 18 | DeletedUserInfo.create( 19 | userAuthInfo = userAuthInfo, 20 | reason = reason 21 | ).also { deletedUserInfoRepository.save(it) } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/service/util/UserTokenType.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.service.util 2 | 3 | enum class UserTokenType{ 4 | ACCESS_TOKEN, 5 | REFRESH_TOKEN, 6 | REGISTER_TOKEN, 7 | } 8 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/service/util/impl/strategy/OpenIdTokenResolveStrategy.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.service.util.impl.strategy 2 | 3 | import com.studentcenter.weave.application.user.vo.UserTokenClaims 4 | 5 | fun interface OpenIdTokenResolveStrategy { 6 | 7 | fun resolveIdToken(idToken: String): UserTokenClaims.IdToken 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/service/util/impl/strategy/OpenIdTokenResolveStrategyFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.service.util.impl.strategy 2 | 3 | import com.studentcenter.weave.domain.user.enums.SocialLoginProvider 4 | 5 | interface OpenIdTokenResolveStrategyFactory { 6 | 7 | fun getStrategy(socialLoginProvider: SocialLoginProvider): OpenIdTokenResolveStrategy 8 | 9 | } 10 | -------------------------------------------------------------------------------- /application/src/main/kotlin/com/studentcenter/weave/application/user/service/util/impl/strategy/OpenIdTokenResolveStrategyFactoryImpl.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.service.util.impl.strategy 2 | 3 | import com.studentcenter.weave.domain.user.enums.SocialLoginProvider 4 | import org.springframework.context.ApplicationContext 5 | import org.springframework.stereotype.Component 6 | 7 | @Component 8 | class OpenIdTokenResolveStrategyFactoryImpl ( 9 | private val applicationContext: ApplicationContext 10 | ): OpenIdTokenResolveStrategyFactory { 11 | 12 | override fun getStrategy(socialLoginProvider: SocialLoginProvider): OpenIdTokenResolveStrategy { 13 | return when (socialLoginProvider) { 14 | SocialLoginProvider.APPLE -> applicationContext.getBean(AppleOpenIdTokenResolveStrategy::class.java) 15 | SocialLoginProvider.KAKAO -> applicationContext.getBean(KakaoOpenIdTokenResolveStrategy::class.java) 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /application/src/main/resources/application-application.yaml: -------------------------------------------------------------------------------- 1 | auth: 2 | jwt: 3 | issuer: ${JWT_ISSUER:weave} 4 | access: 5 | expire-seconds: ${JWT_ACCESS_EXPIRE_SECONDS:3600} 6 | secret: ${JWT_ACCESS_SECRET:secret} 7 | refresh: 8 | expire-seconds: ${JWT_REFRESH_EXPIRE_SECONDS:604800} 9 | secret: ${JWT_REFRESH_SECRET:secret} 10 | register: 11 | expire-seconds: ${JWT_REGISTER_EXPIRE_SECONDS:300} 12 | secret: ${JWT_REGISTER_SECRET:secret} 13 | open-id: 14 | providers: 15 | apple: 16 | jwks-uri: ${APPLE_JWKS_URI:https://appleid.apple.com/auth/keys} 17 | kakao: 18 | jwks-uri: ${KAKAO_JWKS_URI:https://kauth.kakao.com/.well-known/jwks.json} 19 | 20 | meeting: 21 | team: 22 | invitation: 23 | url-prefix: ${INVITATION_URL_PREFIX} 24 | expire-seconds: ${INVITATION_EXPIRE_SECONDS:3600} 25 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/chat/outbound/ChatMessagePublisherSpy.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.chat.outbound 2 | 3 | import com.studentcenter.weave.application.chat.port.outbound.ChatMessagePublisher 4 | import com.studentcenter.weave.domain.chat.entity.ChatMessage 5 | 6 | class ChatMessagePublisherSpy: ChatMessagePublisher { 7 | 8 | private val bucket = mutableListOf() 9 | 10 | override fun publish(chatMessage: ChatMessage) { 11 | bucket.add(chatMessage) 12 | } 13 | 14 | fun count(): Int = bucket.size 15 | 16 | fun clear() = bucket.clear() 17 | 18 | } 19 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/chat/outbound/ChatRoomRepositorySpy.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.chat.outbound 2 | 3 | import com.studentcenter.weave.application.chat.port.outbound.ChatRoomRepository 4 | import com.studentcenter.weave.domain.chat.entity.ChatRoom 5 | import java.util.* 6 | import java.util.concurrent.ConcurrentHashMap 7 | 8 | class ChatRoomRepositorySpy: ChatRoomRepository { 9 | 10 | private val bucket = ConcurrentHashMap() 11 | 12 | override fun getById(id: UUID): ChatRoom { 13 | return bucket[id]!! 14 | } 15 | 16 | override fun save(chatRoom: ChatRoom) { 17 | bucket[chatRoom.id] = chatRoom 18 | } 19 | 20 | fun findAll(): List { 21 | return bucket.values.toList() 22 | } 23 | 24 | fun clear() { 25 | bucket.clear() 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/common/properties/MeetingTeamInvitationPropertiesFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.common.properties 2 | 3 | import kotlin.time.Duration.Companion.hours 4 | 5 | class MeetingTeamInvitationPropertiesFixtureFactory { 6 | 7 | companion object { 8 | private const val INVITATION_URL_PREFIX = "https://api.dev.team-weave.me?code=" 9 | private val DEFAULT_EXPIRE_DURATION = 1.hours.inWholeSeconds 10 | 11 | fun create(): MeetingTeamInvitationProperties { 12 | return MeetingTeamInvitationProperties( 13 | expireSeconds = DEFAULT_EXPIRE_DURATION, 14 | urlPrefix = INVITATION_URL_PREFIX, 15 | ) 16 | } 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/common/properties/OpenIdPropertiesFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.common.properties 2 | 3 | import com.studentcenter.weave.domain.user.enums.SocialLoginProvider 4 | 5 | class OpenIdPropertiesFixtureFactory { 6 | 7 | companion object { 8 | fun create( 9 | socialLoginProvider: SocialLoginProvider, 10 | providers: Map = mapOf( 11 | socialLoginProvider to createProperties(), 12 | ), 13 | ): OpenIdProperties { 14 | return OpenIdProperties( 15 | providers = providers, 16 | ) 17 | } 18 | 19 | fun createProperties( 20 | jwksUri: String = "https://test.com", 21 | ): OpenIdProperties.Properties { 22 | return OpenIdProperties.Properties( 23 | jwksUri = jwksUri, 24 | ) 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/meeting/outbound/MeetingEventMessagePortSpy.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meeting.outbound 2 | 3 | import com.studentcenter.weave.application.meeting.port.outbound.MeetingEventMessagePort 4 | import com.studentcenter.weave.application.meeting.vo.MeetingMatchingEvent 5 | 6 | class MeetingEventMessagePortSpy: MeetingEventMessagePort { 7 | 8 | private val meetingMatchingEvents = mutableListOf() 9 | 10 | override fun sendMeetingIsMatchedMessage(meetingMatchingEvent: MeetingMatchingEvent) { 11 | meetingMatchingEvents.add(meetingMatchingEvent) 12 | } 13 | 14 | fun count(): Int { 15 | return meetingMatchingEvents.size 16 | } 17 | 18 | fun clear() { 19 | meetingMatchingEvents.clear() 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/meetingTeam/outbound/MeetingTeamInvitationRepositorySpy.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.outbound 2 | 3 | import com.studentcenter.weave.application.meetingTeam.port.outbound.MeetingTeamInvitationRepository 4 | import com.studentcenter.weave.application.meetingTeam.vo.MeetingTeamInvitation 5 | import java.util.* 6 | import java.util.concurrent.ConcurrentHashMap 7 | 8 | class MeetingTeamInvitationRepositorySpy : MeetingTeamInvitationRepository { 9 | 10 | private val bucket = ConcurrentHashMap() 11 | 12 | override fun save(meetingTeamInvitation: MeetingTeamInvitation) { 13 | bucket[meetingTeamInvitation.invitationCode] = meetingTeamInvitation 14 | } 15 | 16 | override fun findByInvitationCode(invitationCode: UUID): MeetingTeamInvitation { 17 | return bucket[invitationCode] ?: throw NoSuchElementException() 18 | } 19 | 20 | fun clear() { 21 | bucket.clear() 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/meetingTeam/vo/MeetingTeamInvitationFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.meetingTeam.vo 2 | 3 | import com.studentcenter.weave.support.common.uuid.UuidCreator 4 | import com.studentcenter.weave.support.common.vo.Url 5 | import java.util.* 6 | import kotlin.time.Duration 7 | import kotlin.time.Duration.Companion.hours 8 | 9 | object MeetingTeamInvitationFixtureFactory { 10 | 11 | fun create( 12 | teamId: UUID = UuidCreator.create(), 13 | invitationCode: UUID = UuidCreator.create(), 14 | invitationLink: Url = Url("https://weave.com/invitation/$invitationCode"), 15 | expirationDuration: Duration = 1.hours, 16 | ): MeetingTeamInvitation { 17 | return MeetingTeamInvitation( 18 | teamId = teamId, 19 | invitationCode = invitationCode, 20 | invitationLink = invitationLink, 21 | expirationDuration = expirationDuration 22 | ) 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/suggestion/outbound/SuggestionRepositorySpy.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.suggestion.outbound 2 | 3 | import com.studentcenter.weave.application.suggestion.port.outbound.SuggestionRepository 4 | import com.studentcenter.weave.domain.suggestion.entity.Suggestion 5 | import java.util.* 6 | import java.util.concurrent.ConcurrentHashMap 7 | 8 | class SuggestionRepositorySpy : SuggestionRepository { 9 | 10 | private val bucket = ConcurrentHashMap() 11 | 12 | override fun save(suggestion: Suggestion) { 13 | bucket[suggestion.id] = suggestion 14 | } 15 | 16 | fun clear() { 17 | bucket.clear() 18 | } 19 | 20 | fun count() = bucket.size 21 | 22 | } 23 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/university/port/outbound/MajorRepositorySpy.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.university.port.outbound 2 | 3 | import com.studentcenter.weave.domain.university.entity.Major 4 | import java.util.* 5 | import java.util.concurrent.ConcurrentHashMap 6 | import kotlin.NoSuchElementException 7 | 8 | class MajorRepositorySpy: MajorRepository { 9 | 10 | private val bucket = ConcurrentHashMap() 11 | override fun getById(id: UUID): Major { 12 | return bucket[id] ?: throw NoSuchElementException() 13 | } 14 | 15 | override fun findAllByUnivId(univId: UUID): List { 16 | return bucket.values.filter { it.univId == univId }.toList() 17 | } 18 | 19 | fun clear() { 20 | bucket.clear() 21 | } 22 | 23 | fun saveAll(majors: List) { 24 | bucket.putAll(majors.associateBy { it.id }) 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/user/port/inbound/GetUserStub.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.inbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.User 4 | import com.studentcenter.weave.domain.user.entity.UserFixtureFactory 5 | import java.util.* 6 | 7 | class GetUserStub : GetUser { 8 | 9 | override fun getById(id: UUID): User { 10 | return UserFixtureFactory.create(id = id) 11 | } 12 | 13 | override fun getAllByIds(ids: List): List { 14 | return ids.map { UserFixtureFactory.create(id = it) } 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/user/port/outbound/DeletedUserInfoRepositorySpy.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.DeletedUserInfo 4 | import com.studentcenter.weave.domain.user.enums.SocialLoginProvider 5 | import com.studentcenter.weave.support.common.vo.Email 6 | import java.util.* 7 | import java.util.concurrent.ConcurrentHashMap 8 | 9 | class DeletedUserInfoRepositorySpy : DeletedUserInfoRepository { 10 | 11 | private val bucket = ConcurrentHashMap() 12 | 13 | override fun save(deletedUserInfo: DeletedUserInfo) { 14 | bucket[deletedUserInfo.id] = deletedUserInfo 15 | } 16 | 17 | fun findByEmailAndSocialLoginProvider( 18 | email: Email, 19 | socialLoginProvider: SocialLoginProvider 20 | ): DeletedUserInfo? { 21 | return bucket.values.find { it.email == email && it.socialLoginProvider == socialLoginProvider } 22 | } 23 | 24 | fun clear() { 25 | bucket.clear() 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/user/port/outbound/UserAuthInfoRepositorySpy.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.UserAuthInfo 4 | import com.studentcenter.weave.support.common.vo.Email 5 | import java.util.* 6 | import java.util.concurrent.ConcurrentHashMap 7 | 8 | class UserAuthInfoRepositorySpy : UserAuthInfoRepository { 9 | 10 | private val bucket = ConcurrentHashMap() 11 | 12 | override fun findByEmail(email: Email): UserAuthInfo? { 13 | return bucket.values.find { it.email == email } 14 | } 15 | 16 | override fun save(userAuthInfo: UserAuthInfo) { 17 | bucket[userAuthInfo.id] = userAuthInfo 18 | } 19 | 20 | override fun getByUserId(userId: UUID): UserAuthInfo { 21 | return bucket.values.find { it.userId == userId }!! 22 | } 23 | 24 | override fun deleteById(id: UUID) { 25 | bucket.remove(id) 26 | } 27 | 28 | fun clear() { 29 | bucket.clear() 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/user/port/outbound/UserEventPortStub.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.User 4 | 5 | open class UserEventPortStub : UserEventPort { 6 | 7 | override fun sendRegistrationMessage(user: User, userCount: Int) { 8 | TODO("Not yet implemented") 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/user/port/outbound/UserProfileImageUrlPortStub.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.UserProfileImage 4 | import com.studentcenter.weave.support.common.vo.Url 5 | import java.util.* 6 | 7 | open class UserProfileImageUrlPortStub : UserProfileImageUrlPort { 8 | 9 | override fun getUploadImageUrl( 10 | imageId: UUID, 11 | extension: UserProfileImage.Extension 12 | ): Url { 13 | TODO("Not yet implemented") 14 | } 15 | 16 | override fun findByIdAndExtension( 17 | imageId: UUID, 18 | extension: UserProfileImage.Extension 19 | ): Url { 20 | TODO("Not yet implemented") 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/user/port/outbound/UserRefreshTokenRepositorySpy.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import java.util.* 4 | import java.util.concurrent.ConcurrentHashMap 5 | 6 | class UserRefreshTokenRepositorySpy : UserRefreshTokenRepository { 7 | 8 | private val bucket = ConcurrentHashMap() 9 | 10 | override fun save( 11 | userId: UUID, 12 | refreshToken: String, 13 | expirationSeconds: Long 14 | ) { 15 | bucket[userId] = refreshToken 16 | } 17 | 18 | override fun existsByUserId(userId: UUID): Boolean { 19 | return bucket[userId] != null 20 | } 21 | 22 | override fun deleteByUserId(userId: UUID) { 23 | bucket.remove(userId) 24 | } 25 | 26 | fun clear() { 27 | bucket.clear() 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/user/port/outbound/UserSilRepositorySpy.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.port.outbound 2 | 3 | import com.studentcenter.weave.domain.user.entity.UserSil 4 | import java.util.* 5 | import java.util.concurrent.ConcurrentHashMap 6 | 7 | class UserSilRepositorySpy : UserSilRepository { 8 | 9 | private val bucket = ConcurrentHashMap() 10 | 11 | override fun save(userSil: UserSil) { 12 | bucket[userSil.userId] = userSil 13 | } 14 | 15 | override fun getByUserId(userId: UUID): UserSil { 16 | return bucket.values.firstOrNull { it.userId == userId } 17 | ?: throw NoSuchElementException("UserSil not found by userId: $userId") 18 | } 19 | 20 | fun clear() { 21 | bucket.clear() 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/user/service/util/impl/strategy/OpenIdTokenResolveStrategyFactoryStub.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.service.util.impl.strategy 2 | 3 | import com.studentcenter.weave.application.user.vo.UserTokenClaims 4 | import com.studentcenter.weave.domain.user.entity.UserFixtureFactory 5 | import com.studentcenter.weave.domain.user.enums.SocialLoginProvider 6 | 7 | class OpenIdTokenResolveStrategyFactoryStub : OpenIdTokenResolveStrategyFactory { 8 | 9 | private val user = UserFixtureFactory.create() 10 | 11 | override fun getStrategy(socialLoginProvider: SocialLoginProvider): OpenIdTokenResolveStrategy { 12 | return OpenIdTokenResolveStrategy { 13 | UserTokenClaims.IdToken( 14 | nickname = user.nickname, 15 | email = user.email, 16 | ) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/user/vo/UserAuthenticationFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.vo 2 | 3 | import com.studentcenter.weave.domain.user.entity.User 4 | 5 | object UserAuthenticationFixtureFactory { 6 | 7 | fun create(user: User) : UserAuthentication { 8 | return UserAuthentication( 9 | userId = user.id, 10 | nickname = user.nickname, 11 | email = user.email, 12 | avatar = user.avatar, 13 | gender = user.gender, 14 | ) 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /application/src/testFixtures/kotlin/com/studentcenter/weave/application/user/vo/UserTokenClaimsFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.application.user.vo 2 | 3 | import com.studentcenter.weave.domain.user.entity.User 4 | import com.studentcenter.weave.domain.user.entity.UserFixtureFactory 5 | 6 | object UserTokenClaimsFixtureFactory { 7 | 8 | fun createAccessTokenClaim( 9 | user: User = UserFixtureFactory.create() 10 | ): UserTokenClaims.AccessToken { 11 | return UserTokenClaims.AccessToken( 12 | userId = user.id, 13 | email = user.email, 14 | nickname = user.nickname, 15 | avatar = user.avatar, 16 | gender = user.gender, 17 | ) 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /bootstrap/http/compose-dev.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | spring: 4 | image: public.ecr.aws/${ECR_REGISTRY_ALIAS}/weave_server_dev_cr:${VERSION:-latest} 5 | volumes: 6 | - mysql-data:/var/lib/mysql 7 | environment: 8 | - VERSION=${VERSION:-latest} 9 | pull_policy: always 10 | env_file: 11 | - .env 12 | depends_on: 13 | - mysql 14 | ports: 15 | - "8080:8080" 16 | mysql: 17 | image: mysql:8.0.33 18 | environment: 19 | MYSQL_DATABASE: weave 20 | MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} 21 | TZ: Asia/Seoul 22 | ports: 23 | - "3306:3306" 24 | redis: 25 | image: redis:7.2.4 26 | ports: 27 | - "6379:6379" 28 | volumes: 29 | mysql-data: 30 | -------------------------------------------------------------------------------- /bootstrap/http/compose-local.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | mysql: 4 | image: mysql:8.0.33 5 | volumes: 6 | - mysql-data:/var/lib/mysql 7 | environment: 8 | MYSQL_DATABASE: weave 9 | MYSQL_ROOT_PASSWORD: secret 10 | TZ: Asia/Seoul 11 | ports: 12 | - "3306:3306" 13 | redis: 14 | image: redis:7.2.4 15 | ports: 16 | - "6379:6379" 17 | volumes: 18 | mysql-data: 19 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/auth/dto/RefreshLoginTokenResponse.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.auth.dto 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema 4 | 5 | @Schema( 6 | name = "RefreshLoginTokenResponse", 7 | description = "로그인 토큰 갱신 응답", 8 | ) 9 | data class RefreshLoginTokenResponse( 10 | @Schema(description = "access token") 11 | val accessToken: String, 12 | @Schema(description = "refresh token") 13 | val refreshToken: String, 14 | ) 15 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/auth/dto/RefreshTokenRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.auth.dto 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema 4 | 5 | @Schema( 6 | name = "Refresh Token Request", 7 | description = "Refresh Token 요청" 8 | ) 9 | data class RefreshTokenRequest( 10 | @Schema(description = "Refresh Token") 11 | val refreshToken: String, 12 | ) 13 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/auth/dto/SocialLoginRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.auth.dto 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema 4 | 5 | @Schema( 6 | name = "Social Login Request", 7 | description = "소셜 로그인 요청" 8 | ) 9 | data class SocialLoginRequest( 10 | @Schema(description = "OpenId Connect Id Token") 11 | val idToken: String, 12 | ) 13 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/chat/api/ChatMessageApi.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.chat.api 2 | 3 | import com.studentcenter.weave.bootstrap.chat.dto.GetChatMessagesRequest 4 | import com.studentcenter.weave.bootstrap.chat.dto.GetChatMessagesResponse 5 | import com.studentcenter.weave.bootstrap.common.security.annotation.Secured 6 | import io.swagger.v3.oas.annotations.Operation 7 | import io.swagger.v3.oas.annotations.tags.Tag 8 | import org.springframework.http.HttpStatus 9 | import org.springframework.web.bind.annotation.GetMapping 10 | import org.springframework.web.bind.annotation.RequestMapping 11 | import org.springframework.web.bind.annotation.ResponseStatus 12 | 13 | @Tag(name = "ChatMessage", description = "채팅 메시지 API") 14 | @RequestMapping("/api/chat-messages") 15 | interface ChatMessageApi { 16 | 17 | @Secured 18 | @Operation(summary = "채팅 메시지 조회") 19 | @GetMapping 20 | @ResponseStatus(HttpStatus.OK) 21 | fun getChatMessages(request: GetChatMessagesRequest): GetChatMessagesResponse 22 | 23 | } 24 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/chat/api/ChatRoomApi.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.chat.api 2 | 3 | import com.studentcenter.weave.bootstrap.chat.dto.ChatRoomDetailResponse 4 | import com.studentcenter.weave.bootstrap.common.security.annotation.Secured 5 | import io.swagger.v3.oas.annotations.Operation 6 | import io.swagger.v3.oas.annotations.tags.Tag 7 | import org.springframework.http.HttpStatus 8 | import org.springframework.web.bind.annotation.GetMapping 9 | import org.springframework.web.bind.annotation.PathVariable 10 | import org.springframework.web.bind.annotation.RequestMapping 11 | import org.springframework.web.bind.annotation.ResponseStatus 12 | import java.util.* 13 | 14 | @Tag(name = "ChatRoom", description = "채팅방 API") 15 | @RequestMapping("/api/chat-rooms") 16 | interface ChatRoomApi { 17 | 18 | @Secured 19 | @Operation(summary = "채팅방 정보 상세 조회") 20 | @GetMapping("/{chatRoomId}") 21 | @ResponseStatus(HttpStatus.OK) 22 | fun getChatRoomDetail(@PathVariable chatRoomId: UUID): ChatRoomDetailResponse 23 | 24 | } 25 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/chat/controller/ChatMessageHandler.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.chat.controller 2 | 3 | import com.studentcenter.weave.domain.chat.entity.ChatMessage 4 | import org.springframework.context.event.EventListener 5 | import org.springframework.messaging.simp.SimpMessageSendingOperations 6 | import org.springframework.stereotype.Controller 7 | 8 | @Controller 9 | class ChatMessageHandler( 10 | private val simpMessageSendingOperations: SimpMessageSendingOperations, 11 | ) { 12 | 13 | @EventListener 14 | fun handleChatMessage(chatMessage: ChatMessage) { 15 | simpMessageSendingOperations.convertAndSend( 16 | /* destination = */ "/topic/chat-rooms/${chatMessage.roomId}", 17 | /* payload = */ chatMessage, 18 | ) 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/chat/controller/ChatRoomRestController.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.chat.controller 2 | 3 | import com.studentcenter.weave.application.chat.port.inbound.GetChatRoom 4 | import com.studentcenter.weave.bootstrap.chat.api.ChatRoomApi 5 | import com.studentcenter.weave.bootstrap.chat.dto.ChatRoomDetailResponse 6 | import com.studentcenter.weave.bootstrap.chat.dto.ChatRoomDetailResponse.Companion.toResponse 7 | import org.springframework.web.bind.annotation.RestController 8 | import java.util.* 9 | 10 | @RestController 11 | class ChatRoomRestController( 12 | private val getChatRoom: GetChatRoom, 13 | ) : ChatRoomApi { 14 | 15 | override fun getChatRoomDetail(chatRoomId: UUID): ChatRoomDetailResponse { 16 | return getChatRoom 17 | .getDetailById(chatRoomId) 18 | .toResponse() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/chat/dto/GetChatMessagesResponse.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.chat.dto 2 | 3 | import com.studentcenter.weave.application.chat.port.inbound.GetChatMessage 4 | import com.studentcenter.weave.domain.chat.entity.ChatMessage 5 | import io.swagger.v3.oas.annotations.media.Schema 6 | import java.util.* 7 | 8 | @Schema(description = "채팅 메시지 목록 조회 응답") 9 | data class GetChatMessagesResponse( 10 | @Schema(description = "채팅 메시지 목록") 11 | val items: List, 12 | @Schema(description = "다음 메시지 ID") 13 | val next: UUID?, 14 | @Schema(description = "조회한 메시지 수") 15 | val total: Int, 16 | ) { 17 | companion object { 18 | fun GetChatMessage.ScrollListResult.toResponse(): GetChatMessagesResponse { 19 | return GetChatMessagesResponse( 20 | items = this.items, 21 | next = this.next, 22 | total = this.total, 23 | ) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/chat/dto/SendChatMessageRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.chat.dto 2 | 3 | import com.studentcenter.weave.domain.chat.entity.ChatMessage 4 | 5 | data class SendChatMessageRequest( 6 | val contents: List, 7 | ) { 8 | 9 | data class Content( 10 | val type: ChatMessage.Content.ContentType?, 11 | val value: String?, 12 | ) { 13 | 14 | fun toDomainContent(): ChatMessage.Content { 15 | requireNotNull(type) { "메시지 타입을 입력해 주세요" } 16 | requireNotNull(value) { "메시지를 입력해 주세요" } 17 | 18 | return ChatMessage.Content( 19 | type = type, 20 | value = value 21 | ) 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/common/exception/ApiException.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.common.exception 2 | 3 | import com.studentcenter.weave.support.common.exception.CustomException 4 | 5 | sealed class ApiException( 6 | codeNumber: Int, 7 | message: String, 8 | ) : CustomException(CODE_PREFIX, codeNumber, message) { 9 | 10 | class InvalidDateException(message: String = "") : 11 | ApiException(codeNumber = 1, message = message) 12 | 13 | class InvalidParameter(message: String = "") : 14 | ApiException(codeNumber = 2, message = message) 15 | 16 | class UnauthorizedRequest(message: String = "") : 17 | ApiException(codeNumber = 3, message = message) 18 | 19 | companion object { 20 | const val CODE_PREFIX = "API" 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/common/exception/ErrorResponse.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.common.exception 2 | 3 | import java.time.LocalDateTime 4 | 5 | data class ErrorResponse( 6 | val exceptionCode: String, 7 | val message: String, 8 | val timeStamp: LocalDateTime = LocalDateTime.now(), 9 | ) 10 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/common/security/annotation/RegisterTokenClaim.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.common.security.annotation 2 | 3 | @Target(AnnotationTarget.VALUE_PARAMETER) 4 | @Retention(AnnotationRetention.RUNTIME) 5 | annotation class RegisterTokenClaim() 6 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/common/security/annotation/Secured.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.common.security.annotation 2 | 3 | import io.swagger.v3.oas.annotations.security.SecurityRequirement 4 | 5 | /** 6 | * 인증된 사용자만 접근 가능한 API에 사용하는 어노테이션 7 | */ 8 | @SecurityRequirement(name = "AccessToken") 9 | @Retention(AnnotationRetention.RUNTIME) 10 | @Target(AnnotationTarget.FUNCTION) 11 | annotation class Secured 12 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/meeting/dto/KakaoIdResponse.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.meeting.dto 2 | 3 | import com.studentcenter.weave.application.meetingTeam.vo.MemberInfo 4 | import com.studentcenter.weave.domain.user.vo.KakaoId 5 | import java.util.* 6 | 7 | data class KakaoIdResponse(val members: List) { 8 | 9 | data class MemberKakaoIdDto( 10 | val memberId: UUID, 11 | val kakaoId: KakaoId?, 12 | ) { 13 | companion object { 14 | fun from(memberInfo: MemberInfo) = MemberKakaoIdDto( 15 | memberId = memberInfo.id, 16 | kakaoId = memberInfo.user.kakaoId, 17 | ) 18 | } 19 | } 20 | 21 | companion object { 22 | fun from(memberInfos: List) : KakaoIdResponse { 23 | return KakaoIdResponse(memberInfos.map(MemberKakaoIdDto::from)) 24 | 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/meeting/dto/MeetingAttendancesResponse.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.meeting.dto 2 | 3 | import com.studentcenter.weave.domain.meeting.entity.MeetingAttendance 4 | import java.util.* 5 | 6 | data class MeetingAttendancesResponse( 7 | val meetingAttendances: List, 8 | ) { 9 | 10 | data class MemberAttendanceDto( 11 | val memberId: UUID, 12 | val attendance: Boolean, 13 | ) { 14 | companion object { 15 | fun from(domain: MeetingAttendance) = MemberAttendanceDto( 16 | memberId = domain.meetingMemberId, 17 | attendance = domain.isAttend, 18 | ) 19 | } 20 | } 21 | 22 | companion object { 23 | fun from(meetingAttendances: List) : MeetingAttendancesResponse { 24 | return MeetingAttendancesResponse(meetingAttendances.map(MemberAttendanceDto::from)) 25 | 26 | } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/meeting/dto/MeetingRequestRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.meeting.dto 2 | 3 | import io.swagger.v3.oas.annotations.media.Schema 4 | import java.util.* 5 | 6 | @Schema(description = "Request meeting request") 7 | data class MeetingRequestRequest( 8 | @Schema(description = "미팅 요청 상대팀") 9 | val receivingMeetingTeamId: UUID, 10 | ) 11 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/meeting/dto/MeetingTeamDto.kt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Student-Center/weave-server/ce8307bdcd3c7a6dca9f9f084ed4dc7c669f544a/bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/meeting/dto/MeetingTeamDto.kt -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/meeting/dto/PreparedMeetingScrollRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.meeting.dto 2 | 3 | import com.studentcenter.weave.application.meeting.port.inbound.ScrollPreparedMeeting 4 | import com.studentcenter.weave.support.common.dto.ScrollRequest 5 | import io.swagger.v3.oas.annotations.Parameter 6 | import org.springdoc.core.annotations.ParameterObject 7 | import java.util.* 8 | 9 | @ParameterObject 10 | data class PreparedMeetingScrollRequest( 11 | @Parameter(required = false, description = "이전 요청의 마지막 item id, 최초 요청시 null") 12 | override val next: UUID? = null, 13 | @Parameter(required = false, description = "조회할 개수(Default 20)") 14 | override val limit: Int = 20, 15 | ) : ScrollRequest( 16 | next = next, 17 | limit = limit, 18 | ) { 19 | 20 | fun toQuery(): ScrollPreparedMeeting.Query { 21 | return ScrollPreparedMeeting.Query( 22 | next = this.next, 23 | limit = this.limit, 24 | ) 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/meetingTeam/dto/MeetingTeamCreateInvitationResponse.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.meetingTeam.dto 2 | 3 | import com.studentcenter.weave.support.common.vo.Url 4 | import io.swagger.v3.oas.annotations.media.Schema 5 | import java.util.* 6 | 7 | @Schema(description = "미팅 팀 초대 링크 생성 응답") 8 | data class MeetingTeamCreateInvitationResponse( 9 | @Schema(description = "초대 링크") 10 | val meetingTeamInvitationLink: Url, 11 | 12 | @Schema(description = "초대 코드") 13 | val meetingTeamInvitationCode: UUID, 14 | ) 15 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/meetingTeam/dto/MeetingTeamCreateRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.meetingTeam.dto 2 | 3 | import com.studentcenter.weave.domain.meetingTeam.enums.Location 4 | 5 | data class MeetingTeamCreateRequest( 6 | val teamIntroduce: String, 7 | val memberCount: Int, 8 | val location: Location 9 | ) 10 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/meetingTeam/dto/MeetingTeamEditRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.meetingTeam.dto 2 | 3 | import com.studentcenter.weave.domain.meetingTeam.enums.Location 4 | import io.swagger.v3.oas.annotations.media.Schema 5 | 6 | @Schema(description = "Edit meeting team request") 7 | data class MeetingTeamEditRequest( 8 | val location: Location?, 9 | val memberCount: Int?, 10 | val teamIntroduce: String?, 11 | ) 12 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/meetingTeam/dto/MeetingTeamGetByInvitationCodeResponse.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.meetingTeam.dto 2 | 3 | import com.studentcenter.weave.domain.meetingTeam.entity.MeetingTeam 4 | import com.studentcenter.weave.domain.meetingTeam.enums.MeetingTeamStatus 5 | import io.swagger.v3.oas.annotations.media.Schema 6 | import java.util.* 7 | 8 | @Schema(description = "초대 코드를 통해 미팅 팀 조회") 9 | data class MeetingTeamGetByInvitationCodeResponse( 10 | val teamId: UUID, 11 | val teamIntroduce: String, 12 | val status: MeetingTeamStatus, 13 | ) { 14 | 15 | companion object { 16 | 17 | fun of(meetingTeam: MeetingTeam) = MeetingTeamGetByInvitationCodeResponse( 18 | teamId = meetingTeam.id, 19 | teamIntroduce = meetingTeam.teamIntroduce.value, 20 | status = meetingTeam.status, 21 | ) 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/meetingTeam/dto/MeetingTeamGetLocationsResponse.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.meetingTeam.dto 2 | 3 | import com.studentcenter.weave.domain.meetingTeam.enums.Location 4 | 5 | data class MeetingTeamGetLocationsResponse( 6 | val locations: List 7 | ) { 8 | 9 | data class MeetingTeamLocationDto( 10 | val name: String, 11 | val displayName: String, 12 | val isCapitalArea: Boolean, 13 | ) 14 | 15 | companion object { 16 | private val instance: MeetingTeamGetLocationsResponse by lazy { 17 | MeetingTeamGetLocationsResponse( 18 | Location.entries.map { 19 | MeetingTeamLocationDto(it.name, it.value, it.isCapitalArea) 20 | } 21 | ) 22 | } 23 | 24 | @JvmStatic 25 | @JvmName("getLocationInstance") 26 | fun getInstance(): MeetingTeamGetLocationsResponse { 27 | return instance 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/meetingTeam/dto/MeetingTeamGetMyRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.meetingTeam.dto 2 | 3 | import com.studentcenter.weave.support.common.dto.ScrollRequest 4 | import io.swagger.v3.oas.annotations.media.Schema 5 | import java.util.* 6 | 7 | @Schema(description = "내 미팅 팀 목록 조회 요청") 8 | data class MeetingTeamGetMyRequest( 9 | @Schema(description = "이전 요청의 마지막 iteam id, 최초 요청시 null") 10 | override val next: UUID?, 11 | @Schema(description = "조회할 개수") 12 | override val limit: Int 13 | ) : ScrollRequest( 14 | next = next, 15 | limit = limit 16 | ) 17 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/scheduler/component/PendingMeetingExpireScheduler.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.scheduler.component 2 | 3 | import com.studentcenter.weave.application.meeting.port.inbound.CancelEndedPendingMeeting 4 | import org.springframework.scheduling.annotation.Scheduled 5 | import org.springframework.stereotype.Component 6 | 7 | @Component 8 | class PendingMeetingExpireScheduler( 9 | private val cancelEndedPendingMeeting: CancelEndedPendingMeeting, 10 | ) { 11 | 12 | // 1분마다 돌아감 13 | @Scheduled(cron = "0 * * * * *", zone = "Asia/Seoul") 14 | fun expireMeeting() = cancelEndedPendingMeeting.invoke() 15 | } 16 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/scheduler/config/SchedulerConfig.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.scheduler.config 2 | 3 | import org.springframework.context.annotation.Configuration 4 | import org.springframework.scheduling.annotation.EnableScheduling 5 | 6 | @EnableScheduling 7 | @Configuration 8 | class SchedulerConfig 9 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/suggestion/controller/SuggestionRestController.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.suggestion.controller 2 | 3 | import com.studentcenter.weave.application.common.security.context.getCurrentUserAuthentication 4 | import com.studentcenter.weave.application.suggestion.port.inbound.CreateSuggestion 5 | import com.studentcenter.weave.bootstrap.suggestion.api.SuggestionApi 6 | import com.studentcenter.weave.bootstrap.suggestion.dto.SuggestionCreateRequest 7 | import org.springframework.web.bind.annotation.RestController 8 | 9 | @RestController 10 | class SuggestionRestController( 11 | private val createSuggestion: CreateSuggestion, 12 | ) : SuggestionApi { 13 | 14 | override fun createSuggestion(request: SuggestionCreateRequest) { 15 | request 16 | .toCommand(getCurrentUserAuthentication()) 17 | .also { createSuggestion.invoke(it) } 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/suggestion/dto/SuggestionCreateRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.suggestion.dto 2 | 3 | import com.studentcenter.weave.application.suggestion.port.inbound.CreateSuggestion 4 | import com.studentcenter.weave.application.user.vo.UserAuthentication 5 | 6 | data class SuggestionCreateRequest( 7 | val contents: String?, 8 | ) { 9 | 10 | fun toCommand(userAuth: UserAuthentication): CreateSuggestion.Command { 11 | require(contents != null) { 12 | "내용을 입력해 주세요!" 13 | } 14 | 15 | return CreateSuggestion.Command( 16 | userId = userAuth.userId, 17 | contents = contents 18 | ) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/university/dto/MajorsResponse.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.university.dto 2 | 3 | import com.studentcenter.weave.domain.university.entity.Major 4 | import io.swagger.v3.oas.annotations.media.Schema 5 | import java.util.* 6 | 7 | 8 | @Schema( 9 | name = "All Major Response", 10 | description = "특정 대학교의 모든 학과 정보를 반환합니다", 11 | ) 12 | data class MajorsResponse( 13 | val majors: List 14 | ) { 15 | 16 | data class MajorDto(val id: UUID, val name: String) 17 | 18 | companion object { 19 | fun from(domains: List): MajorsResponse { 20 | return MajorsResponse(domains.map { MajorDto(it.id, it.name.value) }) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/university/dto/UniversityResponse.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.university.dto 2 | 3 | import com.studentcenter.weave.domain.university.entity.University 4 | import io.swagger.v3.oas.annotations.media.Schema 5 | import java.util.* 6 | 7 | 8 | @Schema( 9 | name = "University domain response", 10 | description = "특정 대학 정보를 반환합니다", 11 | ) 12 | data class UniversityResponse( 13 | val id: UUID, 14 | val name: String, 15 | val displayName: String, 16 | val domainAddress: String, 17 | val logoAddress: String?, 18 | ) { 19 | 20 | companion object { 21 | 22 | fun from(domain: University) = UniversityResponse( 23 | id = domain.id, 24 | name = domain.name.value, 25 | displayName = domain.displayName, 26 | domainAddress = domain.domainAddress, 27 | logoAddress = domain.logoAddress, 28 | ) 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/user/dto/UserCompleteProfileImageUploadRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.user.dto 2 | 3 | import com.studentcenter.weave.domain.user.entity.UserProfileImage 4 | import java.util.UUID 5 | 6 | data class UserCompleteProfileImageUploadRequest( 7 | val imageId: UUID, 8 | val extension: UserProfileImage.Extension, 9 | ) 10 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/user/dto/UserGetAvailableAnimalTypesResponse.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.user.dto 2 | 3 | import com.studentcenter.weave.domain.user.enums.AnimalType 4 | 5 | data class UserGetAvailableAnimalTypesResponse( 6 | val items: List 7 | ) { 8 | 9 | data class Item( 10 | val name: String, 11 | val description: String, 12 | ) 13 | 14 | companion object { 15 | 16 | fun create(): UserGetAvailableAnimalTypesResponse { 17 | return AnimalType.entries.map { 18 | Item( 19 | name = it.name, 20 | description = it.description 21 | ) 22 | }.let { 23 | UserGetAvailableAnimalTypesResponse(it) 24 | } 25 | } 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/user/dto/UserGetProfileImageUploadUrlResponse.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.user.dto 2 | 3 | import com.studentcenter.weave.application.user.port.inbound.GetProfileImageUploadUrl 4 | import com.studentcenter.weave.domain.user.entity.UserProfileImage 5 | import io.swagger.v3.oas.annotations.media.Schema 6 | import java.util.* 7 | 8 | @Schema(description = "유저 프로필 이미지 업로드 URL 응답") 9 | data class UserGetProfileImageUploadUrlResponse( 10 | @Schema(description = "업로드 URL") 11 | val uploadUrl: String, 12 | @Schema(description = "이미지 ID") 13 | val imageId: UUID, 14 | @Schema(description = "이미지 확장자") 15 | val extension: UserProfileImage.Extension, 16 | ) { 17 | 18 | companion object { 19 | 20 | fun from(result: GetProfileImageUploadUrl.Result) = 21 | UserGetProfileImageUploadUrlResponse( 22 | uploadUrl = result.uploadUrl.value, 23 | imageId = result.imageId, 24 | extension = result.extension, 25 | ) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/user/dto/UserModifyMyMbtiRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.user.dto 2 | 3 | data class UserModifyMyMbtiRequest ( 4 | val mbti: String 5 | ) 6 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/user/dto/UserRegisterRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.user.dto 2 | 3 | import com.studentcenter.weave.domain.user.enums.Gender 4 | import io.swagger.v3.oas.annotations.media.Schema 5 | import java.util.* 6 | 7 | @Schema( 8 | name = "Register User Request", 9 | description = "회원 가입 요청" 10 | ) 11 | data class UserRegisterRequest( 12 | val gender: Gender, 13 | val birthYear: Int, 14 | val mbti: String, 15 | @Schema(example = "018d7782-f105-7f0e-9ad9-a47e213037d0") 16 | val universityId: UUID, 17 | @Schema(example = "018d79c6-e9be-7149-806e-7c42a7cd6311") 18 | val majorId: UUID, 19 | ) 20 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/user/dto/UserSetMyAnimalTypeRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.user.dto 2 | 3 | import com.studentcenter.weave.domain.user.enums.AnimalType 4 | 5 | data class UserSetMyAnimalTypeRequest ( 6 | val animalType: AnimalType 7 | ) 8 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/user/dto/UserSetMyHeightRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.user.dto 2 | 3 | data class UserSetMyHeightRequest( 4 | val height: Int, 5 | ) 6 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/user/dto/UserSetMyKakaoIdRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.user.dto 2 | 3 | data class UserSetMyKakaoIdRequest( 4 | val kakaoId: String 5 | ) 6 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/user/dto/UserUnivVerificationSendRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.user.dto 2 | 3 | data class UserUnivVerificationSendRequest ( 4 | val universityEmail: String, 5 | ) 6 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/kotlin/com/studentcenter/weave/bootstrap/user/dto/UserUnivVerificationVerifyRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.user.dto 2 | 3 | data class UserUnivVerificationVerifyRequest ( 4 | val universityEmail: String, 5 | val verificationNumber: String, 6 | ) 7 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/resources/static/.well-known/apple-app-site-association: -------------------------------------------------------------------------------- 1 | { 2 | "applinks": { 3 | "apps": [], 4 | "details": [ 5 | { 6 | "appID": "8GXC7Q5W68.com.studentcenter.weaveios", 7 | "paths": [ 8 | "/team/*", 9 | "/invitation/*" 10 | ] 11 | } 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /bootstrap/http/src/main/resources/static/.well-known/assetlinks.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "relation": [ 4 | "delegate_permission/common.handle_all_urls" 5 | ], 6 | "target": { 7 | "namespace": "android_app", 8 | "package_name": "com.studentcenter.weave", 9 | "sha256_cert_fingerprints": [ 10 | "4C:9E:7E:3C:3F:E8:B7:41:B3:3B:5B:02:F3:26:22:95:DA:F5:94:64:EB:C8:67:13:1D:DB:60:34:8F:94:58:BA" 11 | ] 12 | } 13 | }, 14 | { 15 | "relation": [ 16 | "delegate_permission/common.handle_all_urls" 17 | ], 18 | "target": { 19 | "namespace": "android_app", 20 | "package_name": "com.studentcenter.weave", 21 | "sha256_cert_fingerprints": [ 22 | "FA:8E:1C:07:83:AC:FD:04:27:8E:D1:4C:EF:FF:69:76:56:99:CA:92:F2:6B:4A:DB:64:CD:AC:BD:47:A0:84:27" 23 | ] 24 | } 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /bootstrap/http/src/test/kotlin/com/studentcenter/weave/bootstrap/integration/IntegrationTestDescribeSpec.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.integration 2 | 3 | import io.kotest.core.spec.style.DescribeSpec 4 | import org.springframework.boot.test.context.SpringBootTest 5 | import org.springframework.test.context.ActiveProfiles 6 | import org.testcontainers.containers.ComposeContainer 7 | import java.io.File 8 | 9 | @SpringBootTest 10 | @ActiveProfiles("integration-test") 11 | abstract class IntegrationTestDescribeSpec(body: DescribeSpec.() -> Unit = {}) : 12 | DescribeSpec(body) { 13 | 14 | companion object { 15 | 16 | private val container: ComposeContainer = 17 | ComposeContainer(File("src/test/resources/compose-test.yaml")) 18 | .withExposedService("mysql", 3306) 19 | .withExposedService("redis", 6379) 20 | 21 | 22 | init { 23 | container.start() 24 | } 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /bootstrap/http/src/test/resources/compose-test.yaml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | mysql: 4 | image: mysql:8.0.33 5 | environment: 6 | MYSQL_DATABASE: test 7 | MYSQL_ROOT_PASSWORD: secret 8 | ports: 9 | - "3306:3306" 10 | redis: 11 | image: redis:7.2.4 12 | ports: 13 | - "6379:6379" 14 | -------------------------------------------------------------------------------- /bootstrap/http/src/testFixtures/kotlin/com/studentcenter/weave/bootstrap/controller/AuthorizationInterceptorTestController.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.bootstrap.controller 2 | 3 | import com.studentcenter.weave.bootstrap.common.security.annotation.Secured 4 | import org.springframework.http.HttpStatus 5 | import org.springframework.web.bind.annotation.GetMapping 6 | import org.springframework.web.bind.annotation.ResponseStatus 7 | import org.springframework.web.bind.annotation.RestController 8 | 9 | @RestController 10 | class AuthorizationInterceptorTestController { 11 | 12 | @Secured 13 | @GetMapping("/secured-method") 14 | @ResponseStatus(HttpStatus.OK) 15 | fun securedMethod() { 16 | /* secured method */ 17 | } 18 | 19 | @GetMapping("/unsecured-method") 20 | @ResponseStatus(HttpStatus.OK) 21 | fun unsecuredMethod() { 22 | /* unsecured method */ 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /docs/weave-infra.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Student-Center/weave-server/ce8307bdcd3c7a6dca9f9f084ed4dc7c669f544a/docs/weave-infra.jpg -------------------------------------------------------------------------------- /domain/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.tasks.bundling.BootJar 2 | 3 | val jar: Jar by tasks 4 | val bootJar: BootJar by tasks 5 | 6 | bootJar.enabled = false 7 | jar.enabled = true 8 | 9 | dependencies { 10 | implementation(project(":support:common")) 11 | } 12 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/chat/entity/ChatMember.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.chat.entity 2 | 3 | import com.studentcenter.weave.domain.common.DomainEntity 4 | import com.studentcenter.weave.support.common.uuid.UuidCreator 5 | import java.util.* 6 | 7 | data class ChatMember( 8 | override val id: UUID = UuidCreator.create(), 9 | val userId: UUID, 10 | val lastReadMessageId: UUID? = null, 11 | ) : DomainEntity { 12 | 13 | companion object { 14 | 15 | fun create(userId: UUID): ChatMember { 16 | return ChatMember(userId = userId) 17 | } 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/common/AggregateRoot.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.common 2 | 3 | interface AggregateRoot : DomainEntity 4 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/common/DomainEntity.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.common 2 | 3 | import java.util.* 4 | 5 | interface DomainEntity { 6 | 7 | val id: UUID 8 | 9 | } 10 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/common/DomainEvent.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.common 2 | 3 | interface DomainEvent { 4 | 5 | val entity: T 6 | 7 | } 8 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/meeting/entity/MeetingAttendance.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.meeting.entity 2 | 3 | import com.studentcenter.weave.domain.common.DomainEntity 4 | import com.studentcenter.weave.support.common.uuid.UuidCreator 5 | import java.time.LocalDateTime 6 | import java.util.* 7 | 8 | data class MeetingAttendance( 9 | override val id: UUID = UuidCreator.create(), 10 | val meetingId: UUID, 11 | val meetingMemberId: UUID, 12 | val isAttend: Boolean, 13 | val createdAt: LocalDateTime = LocalDateTime.now(), 14 | val updatedAt: LocalDateTime = createdAt, 15 | ) : DomainEntity { 16 | 17 | companion object { 18 | 19 | fun create( 20 | meetingId: UUID, 21 | meetingMemberId: UUID, 22 | isAttend: Boolean, 23 | ): MeetingAttendance { 24 | return MeetingAttendance( 25 | meetingId = meetingId, 26 | meetingMemberId = meetingMemberId, 27 | isAttend = isAttend, 28 | ) 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/meeting/enums/MeetingStatus.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.meeting.enums 2 | 3 | enum class MeetingStatus { 4 | PENDING, 5 | // FIXME: 현재 사용하지 않는 상태(MVP 스펙 X) 6 | // PREPARING, 7 | // SCHEDULED, 8 | // INSUFFICIENT, 9 | COMPLETED, 10 | CANCELED; 11 | } 12 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/meeting/enums/TeamType.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.meeting.enums 2 | 3 | enum class TeamType { 4 | REQUESTING, 5 | RECEIVING, 6 | } 7 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/meeting/event/MeetingCompletedEvent.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.meeting.event 2 | 3 | import com.studentcenter.weave.domain.common.DomainEvent 4 | import com.studentcenter.weave.domain.meeting.entity.Meeting 5 | 6 | data class MeetingCompletedEvent( 7 | override val entity: Meeting, 8 | ) : DomainEvent { 9 | 10 | companion object { 11 | 12 | fun Meeting.createCompletedEvent(): MeetingCompletedEvent { 13 | require(isCompleted()) { "미팅이 완료되지 않았습니다." } 14 | 15 | return MeetingCompletedEvent(this) 16 | } 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/meetingTeam/entity/MeetingMember.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.meetingTeam.entity 2 | 3 | import com.studentcenter.weave.domain.common.DomainEntity 4 | import com.studentcenter.weave.domain.meetingTeam.enums.MeetingMemberRole 5 | import com.studentcenter.weave.support.common.uuid.UuidCreator 6 | import java.util.* 7 | 8 | data class MeetingMember( 9 | override val id: UUID, 10 | val userId: UUID, 11 | val role: MeetingMemberRole, 12 | ) : DomainEntity { 13 | 14 | companion object { 15 | 16 | fun create( 17 | userId: UUID, 18 | role: MeetingMemberRole, 19 | ): MeetingMember { 20 | return MeetingMember( 21 | id = UuidCreator.create(), 22 | userId = userId, 23 | role = role, 24 | ) 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/meetingTeam/enums/Location.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.meetingTeam.enums 2 | 3 | enum class Location( 4 | val value: String, 5 | val isCapitalArea: Boolean, 6 | ) { 7 | // 수도권(서울) 8 | KONDAE_SEONGSU("건대•성수", true), 9 | HONGDAE_SINCHON("홍대•신촌", true), 10 | GANGNAM_JAMSIL("강남•잠실", true), 11 | NOWON_GONGREUNG("노원•공릉", true), 12 | DAEHANGNO_HYEHWA("대학로•혜화", true), 13 | // 수도권 (인천, 경기) 14 | INCHON("인천", true), 15 | SUWON("수원", true), 16 | YONGIN("용인", true), 17 | BUCHUN("부천", true), 18 | SIHEUNG("시흥", true), 19 | // 비수도권 20 | BUSAN("부산", false), 21 | DAEGU("대구", false), 22 | GWANGJU("광주", false), 23 | DAEJEON("대전", false), 24 | GANGWON("강원", false), 25 | CHUNGNAM("충남", false), 26 | CHUNGBUK("충북", false), 27 | } 28 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/meetingTeam/enums/MeetingMemberRole.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.meetingTeam.enums 2 | 3 | enum class MeetingMemberRole { 4 | LEADER, MEMBER 5 | } 6 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/meetingTeam/enums/MeetingTeamStatus.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.meetingTeam.enums 2 | 3 | enum class MeetingTeamStatus { 4 | WAITING, 5 | PUBLISHED, 6 | } 7 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/meetingTeam/vo/TeamIntroduce.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.meetingTeam.vo 2 | 3 | @JvmInline 4 | value class TeamIntroduce(val value: String) { 5 | 6 | init { 7 | require(value.length in 1..10) { 8 | "팀 한줄 소개는 1자 이상 10자 이하여야 합니다." 9 | } 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/university/entity/Major.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.university.entity 2 | 3 | import com.studentcenter.weave.domain.common.DomainEntity 4 | import com.studentcenter.weave.domain.university.vo.MajorName 5 | import com.studentcenter.weave.support.common.uuid.UuidCreator 6 | import java.time.LocalDateTime 7 | import java.util.* 8 | 9 | data class Major( 10 | override val id: UUID = UuidCreator.create(), 11 | val univId: UUID, 12 | val name: MajorName, 13 | val createdAt: LocalDateTime = LocalDateTime.now(), 14 | ) : DomainEntity { 15 | 16 | 17 | companion object { 18 | 19 | fun create( 20 | univId: UUID, 21 | name: MajorName, 22 | ): Major { 23 | return Major(univId = univId, name = name) 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/university/vo/MajorName.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.university.vo 2 | 3 | @JvmInline 4 | value class MajorName(val value: String) { 5 | 6 | init { 7 | require(value.isNotBlank()) { "전공명은 공백일 수 없습니다." } 8 | require(value.length <= 30) { "전공명은 30자 이하여야 합니다." } 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/university/vo/UniversityName.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.university.vo 2 | 3 | @JvmInline 4 | value class UniversityName(val value: String) { 5 | 6 | init { 7 | require(value.isNotBlank()) { "대학교 이름은 공백일 수 없습니다." } 8 | require(value.length <= 30) { "대학교 이름은 30자 이하여야 합니다." } 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/user/entity/UserSil.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.entity 2 | 3 | import com.studentcenter.weave.domain.common.DomainEntity 4 | import com.studentcenter.weave.support.common.uuid.UuidCreator 5 | import java.util.* 6 | 7 | /** 8 | * 유저의 실(재화) 정보 9 | */ 10 | data class UserSil( 11 | override val id: UUID = UuidCreator.create(), 12 | val userId: UUID, 13 | val amount: Long = 0, 14 | ) : DomainEntity { 15 | 16 | init { 17 | require(amount >= 0) { "amount는 0 이상이어야 합니다." } 18 | } 19 | 20 | fun increment(amount: Long): UserSil { 21 | return copy(amount = this.amount + amount) 22 | } 23 | 24 | companion object { 25 | 26 | fun create(userId: UUID): UserSil { 27 | return UserSil(userId = userId) 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/user/entity/UserUniversityVerificationInfo.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.entity 2 | 3 | import com.studentcenter.weave.domain.common.DomainEntity 4 | import com.studentcenter.weave.support.common.uuid.UuidCreator 5 | import com.studentcenter.weave.support.common.vo.Email 6 | import java.time.LocalDateTime 7 | import java.util.* 8 | 9 | data class UserUniversityVerificationInfo( 10 | override val id: UUID = UuidCreator.create(), 11 | val userId: UUID, 12 | val universityId: UUID, 13 | val universityEmail: Email, 14 | val verifiedAt: LocalDateTime, 15 | ) : DomainEntity { 16 | 17 | companion object { 18 | fun create(user: User, universityEmail: Email): UserUniversityVerificationInfo { 19 | return UserUniversityVerificationInfo( 20 | userId = user.id, 21 | universityId = user.universityId, 22 | universityEmail = universityEmail, 23 | verifiedAt = LocalDateTime.now(), 24 | ) 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/user/enums/AnimalType.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.enums 2 | 3 | enum class AnimalType(val description: String) { 4 | PUPPY("🐶 강아지상"), 5 | CAT("🐱 고양이상"), 6 | HEDGEHOG("🦔 고슴도치상"), 7 | FOX("🦊 여우상"), 8 | RABBIT("🐰 토끼상"), 9 | TIGER("🐯 호랑이상"), 10 | MONKEY("🐵 원숭이상"), 11 | TURTLE("🐢 꼬부기상"), 12 | DEER("🦌 사슴상"), 13 | HAMSTER("🐹 햄스터상"), 14 | WOLF("🐺 늑대상"), 15 | TEDDY_BEAR("🧸 곰돌이상"), 16 | PANDA("🐼 판다상"), 17 | SNAKE("🐍 뱀상"), 18 | OTTER("🦦 수달상"), 19 | FISH("🐠 물고기상"), 20 | CHICK("🐤 병아리상"), 21 | DINOSAUR("🦕 공룡상"), 22 | HORSE("🐴 말상"), 23 | SLOTH("🦥 나무늘보상"), 24 | LION("🦁 사자상"), 25 | CAMEL("🐪 낙타상"); 26 | } 27 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/user/enums/Gender.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.enums 2 | 3 | enum class Gender { 4 | MAN, 5 | WOMAN; 6 | 7 | fun getOppositeGender(): Gender { 8 | return if(this == MAN) WOMAN else MAN 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/user/enums/SocialLoginProvider.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.enums 2 | 3 | enum class SocialLoginProvider { 4 | KAKAO, 5 | APPLE 6 | } 7 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/user/exception/UserException.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.exception 2 | 3 | import com.studentcenter.weave.support.common.exception.CustomException 4 | 5 | sealed class UserException( 6 | codeNumber: Int, 7 | message: String, 8 | ) : CustomException(CODE_PREFIX, codeNumber, message) { 9 | 10 | class UserProfileImageUploadFailed(message: String = "프로필 이미지가 정상적으로 업로드 되지 않았습니다. 다시시도해주세요") : 11 | UserException(codeNumber = 1, message = message) 12 | 13 | companion object { 14 | const val CODE_PREFIX = "USER" 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/user/vo/BirthYear.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.vo 2 | 3 | import java.time.Year 4 | 5 | @JvmInline 6 | value class BirthYear(val value: Int) { 7 | 8 | init { 9 | require(value in 1900..Year.now().value) { 10 | "생년월일은 1900년 이후, 현재 년도 이전이어야 합니다" 11 | } 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/user/vo/Height.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.vo 2 | 3 | @JvmInline 4 | value class Height(val value: Int) { 5 | 6 | init { 7 | require(value in 1..300) { 8 | "키는 1cm 이상 300cm 이하여야 합니다." 9 | } 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/user/vo/KakaoId.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.vo 2 | 3 | @JvmInline 4 | value class KakaoId(val value: String) { 5 | 6 | init { 7 | require(value.matches(Regex(VALIDATION_REGEX))) { 8 | "KakaoId는 영문, 숫자, 특수문자 빼기(-), 밑줄(_), 마침표(.)로 구성된 4자 이상 20자 이하의 문자열이어야 합니다." 9 | } 10 | } 11 | 12 | companion object { 13 | const val VALIDATION_REGEX = "^[a-zA-Z0-9-_.]{4,20}\$" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /domain/src/main/kotlin/com/studentcenter/weave/domain/user/vo/Nickname.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.vo 2 | 3 | @JvmInline 4 | value class Nickname( 5 | val value: String 6 | ) { 7 | 8 | companion object { 9 | 10 | const val MIN_LENGTH = 1 11 | const val MAX_LENGTH = 10 12 | } 13 | 14 | init { 15 | require(value.length in MIN_LENGTH..MAX_LENGTH) { "닉네임은 ${MIN_LENGTH}글자 이상 ${MAX_LENGTH}자 이하여야 합니다." } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /domain/src/test/kotlin/com/studentcenter/weave/domain/meetingTeam/vo/TeamIntroduceTest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.meetingTeam.vo 2 | 3 | import io.kotest.assertions.throwables.shouldThrow 4 | import io.kotest.core.spec.style.FunSpec 5 | 6 | class TeamIntroduceTest : FunSpec({ 7 | 8 | test("팀 한줄 소개는 1자 이상 10자 이하여야 합니다.") { 9 | shouldThrow { 10 | TeamIntroduce("") 11 | } 12 | 13 | shouldThrow { 14 | TeamIntroduce("팀".repeat(11)) 15 | } 16 | } 17 | 18 | }) 19 | -------------------------------------------------------------------------------- /domain/src/test/kotlin/com/studentcenter/weave/domain/university/entity/MajorTest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.university.entity 2 | 3 | import com.studentcenter.weave.domain.university.vo.MajorName 4 | import com.studentcenter.weave.support.common.uuid.UuidCreator 5 | import io.kotest.core.spec.style.FunSpec 6 | import io.kotest.matchers.comparables.shouldBeLessThanOrEqualTo 7 | import io.kotest.matchers.shouldBe 8 | import java.time.LocalDateTime 9 | 10 | class MajorTest : FunSpec({ 11 | 12 | test("대학교 생성") { 13 | // arrange 14 | val name = MajorName(value = "컴퓨터공학과") 15 | 16 | // act 17 | val major = Major.create( 18 | univId = UuidCreator.create(), 19 | name = name 20 | ) 21 | 22 | // assert 23 | major.name shouldBe name 24 | major.createdAt shouldBeLessThanOrEqualTo LocalDateTime.now() 25 | } 26 | 27 | }) 28 | -------------------------------------------------------------------------------- /domain/src/test/kotlin/com/studentcenter/weave/domain/university/vo/MajorNameTest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.university.vo 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | 6 | class MajorNameTest : FunSpec({ 7 | 8 | test("전공명은 공백일 수 없습니다.") { 9 | runCatching { MajorName(" ") }.onFailure { 10 | it.message shouldBe "전공명은 공백일 수 없습니다." 11 | } 12 | } 13 | 14 | test("전공명은 30자 이하여야 합니다.") { 15 | runCatching { MajorName("a".repeat(31)) }.onFailure { 16 | it.message shouldBe "전공명은 30자 이하여야 합니다." 17 | } 18 | } 19 | 20 | }) 21 | -------------------------------------------------------------------------------- /domain/src/test/kotlin/com/studentcenter/weave/domain/university/vo/UniversityNameTest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.university.vo 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | 6 | class UniversityNameTest : FunSpec({ 7 | 8 | test("대학교 이름은 공백일 수 없습니다.") { 9 | runCatching { UniversityName(" ") }.onFailure { 10 | it.message shouldBe "대학교 이름은 공백일 수 없습니다." 11 | } 12 | } 13 | 14 | test("대학교 이름은 30자 이하여야 합니다.") { 15 | runCatching { UniversityName("a".repeat(31)) }.onFailure { 16 | it.message shouldBe "대학교 이름은 30자 이하여야 합니다." 17 | } 18 | } 19 | 20 | }) 21 | -------------------------------------------------------------------------------- /domain/src/test/kotlin/com/studentcenter/weave/domain/user/entity/UserAuthInfoTest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.entity 2 | 3 | import com.studentcenter.weave.domain.user.enums.SocialLoginProvider 4 | import io.kotest.core.spec.style.FunSpec 5 | import io.kotest.matchers.shouldBe 6 | 7 | class UserAuthInfoTest : FunSpec({ 8 | 9 | test("유저 인증 정보 생성") { 10 | // arrange 11 | val user = UserFixtureFactory.create() 12 | val socialLoginProvider = SocialLoginProvider.KAKAO 13 | 14 | // act 15 | val userAuthInfo = UserAuthInfo.create( 16 | user = user, 17 | socialLoginProvider = socialLoginProvider, 18 | ) 19 | 20 | // assert 21 | userAuthInfo.userId shouldBe user.id 22 | userAuthInfo.socialLoginProvider shouldBe socialLoginProvider 23 | } 24 | 25 | }) 26 | -------------------------------------------------------------------------------- /domain/src/test/kotlin/com/studentcenter/weave/domain/user/entity/UserSilTest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.entity 2 | 3 | import com.studentcenter.weave.support.common.uuid.UuidCreator 4 | import io.kotest.assertions.throwables.shouldThrow 5 | import io.kotest.core.spec.style.FunSpec 6 | import io.kotest.matchers.shouldBe 7 | 8 | class UserSilTest : FunSpec({ 9 | 10 | 11 | test("유저 실 생성") { 12 | val userId = UuidCreator.create() 13 | val userSil = UserSil.create(userId) 14 | 15 | userSil.userId shouldBe userId 16 | userSil.amount shouldBe 0 17 | } 18 | 19 | test("0 이하의 실을 생성할 수 없다") { 20 | val userId = UuidCreator.create() 21 | 22 | shouldThrow { 23 | UserSil(userId = userId, amount = -1) 24 | } 25 | } 26 | 27 | }) 28 | -------------------------------------------------------------------------------- /domain/src/test/kotlin/com/studentcenter/weave/domain/user/vo/BirthYearTest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.vo 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | import java.time.Year 6 | 7 | class BirthYearTest : FunSpec({ 8 | 9 | test("생년월일은 1900년 이후, 현재 년도 이전이어야 합니다") { 10 | BirthYear(1900) 11 | BirthYear(2021) 12 | } 13 | 14 | test("생년월일이 1900년 이후, 현재 년도 이전이 아니면 예외가 발생합니다") { 15 | runCatching { BirthYear(1899) }.isFailure shouldBe true 16 | runCatching { BirthYear(Year.now().value + 1) }.isFailure shouldBe true 17 | } 18 | 19 | }) 20 | -------------------------------------------------------------------------------- /domain/src/test/kotlin/com/studentcenter/weave/domain/user/vo/HeightTest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.vo 2 | 3 | import io.kotest.assertions.throwables.shouldThrow 4 | import io.kotest.core.spec.style.FunSpec 5 | 6 | class HeightTest : FunSpec({ 7 | 8 | context("생성") { 9 | 10 | test("키는 1cm 이상 300cm 미만이어야 한다.") { 11 | Height(1) 12 | Height(299) 13 | } 14 | 15 | test("키는 1cm 미만이면 예외가 발생한다.") { 16 | shouldThrow { 17 | Height(0) 18 | } 19 | } 20 | 21 | test("키는 300cm 초과면 예외가 발생한다.") { 22 | shouldThrow { 23 | Height(301) 24 | } 25 | } 26 | 27 | } 28 | 29 | }) 30 | -------------------------------------------------------------------------------- /domain/src/test/kotlin/com/studentcenter/weave/domain/user/vo/NicknameTest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.vo 2 | 3 | import io.kotest.assertions.throwables.shouldThrow 4 | import io.kotest.core.annotation.DisplayName 5 | import io.kotest.core.spec.style.FunSpec 6 | import io.kotest.matchers.shouldBe 7 | 8 | @DisplayName("NicknameTest") 9 | class NicknameTest : FunSpec ({ 10 | 11 | test("최대 글자수 기준(10) 보다 긴 닉네임을 생성하는 경우, 에러가 발생한다.") { 12 | 13 | shouldThrow { 14 | Nickname("닉".repeat(Nickname.MAX_LENGTH + 1)) 15 | } 16 | } 17 | 18 | test("최소 글자수 기준(1) 보다 짧은 길이의 닉네임을 생성하는 경우, 에러가 발생한다.") { 19 | 20 | shouldThrow { 21 | Nickname("") 22 | } 23 | } 24 | }) 25 | -------------------------------------------------------------------------------- /domain/src/testFixtures/kotlin/com/studentcenter/weave/domain/chat/entity/ChatMemberFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.chat.entity 2 | 3 | import com.studentcenter.weave.support.common.uuid.UuidCreator 4 | import java.util.* 5 | 6 | object ChatMemberFixtureFactory { 7 | 8 | fun create( 9 | id: UUID = UuidCreator.create(), 10 | userId: UUID = UuidCreator.create(), 11 | lastReadMessageId: UUID? = null, 12 | ): ChatMember { 13 | return ChatMember( 14 | id = id, 15 | userId = userId, 16 | lastReadMessageId = lastReadMessageId, 17 | ) 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /domain/src/testFixtures/kotlin/com/studentcenter/weave/domain/chat/entity/ChatMessageFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.chat.entity 2 | 3 | import com.studentcenter.weave.support.common.uuid.UuidCreator 4 | import java.util.UUID 5 | 6 | object ChatMessageFixtureFactory { 7 | 8 | fun create( 9 | id: UUID = UuidCreator.create(), 10 | roomId: UUID = UuidCreator.create(), 11 | senderId: UUID = UuidCreator.create(), 12 | senderType: ChatMessage.SenderType = ChatMessage.SenderType.USER, 13 | contents: List = listOf( 14 | ChatMessage.Content( 15 | type = ChatMessage.Content.ContentType.TEXT, 16 | value = "Hello, World!" 17 | ) 18 | ), 19 | ): ChatMessage { 20 | return ChatMessage( 21 | id = id, 22 | roomId = roomId, 23 | senderId = senderId, 24 | senderType = senderType, 25 | contents = contents, 26 | ) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /domain/src/testFixtures/kotlin/com/studentcenter/weave/domain/chat/entity/ChatRoomFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.chat.entity 2 | 3 | import com.studentcenter.weave.support.common.uuid.UuidCreator 4 | import java.time.LocalDateTime 5 | import java.util.* 6 | 7 | object ChatRoomFixtureFactory { 8 | 9 | fun create( 10 | id: UUID = UuidCreator.create(), 11 | meetingId: UUID = UuidCreator.create(), 12 | requestingTeamId: UUID = UuidCreator.create(), 13 | receivingTeamId: UUID = UuidCreator.create(), 14 | createdAt: LocalDateTime = LocalDateTime.now(), 15 | members: Set = emptySet(), 16 | ): ChatRoom { 17 | return ChatRoom( 18 | id = id, 19 | meetingId = meetingId, 20 | requestingTeamId = requestingTeamId, 21 | receivingTeamId = receivingTeamId, 22 | createdAt = createdAt, 23 | members = members 24 | ) 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /domain/src/testFixtures/kotlin/com/studentcenter/weave/domain/meeting/entity/MeetingAttendanceFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.meeting.entity 2 | 3 | import com.studentcenter.weave.support.common.uuid.UuidCreator 4 | import java.time.LocalDateTime 5 | import java.util.* 6 | 7 | object MeetingAttendanceFixtureFactory { 8 | 9 | fun create( 10 | id: UUID = UuidCreator.create(), 11 | meetingId: UUID = UuidCreator.create(), 12 | meetingMemberId: UUID = UuidCreator.create(), 13 | isAttend: Boolean = true, 14 | createdAt: LocalDateTime = LocalDateTime.now(), 15 | updatedAt: LocalDateTime = LocalDateTime.now(), 16 | ): MeetingAttendance { 17 | return MeetingAttendance( 18 | id = id, 19 | meetingId = meetingId, 20 | meetingMemberId = meetingMemberId, 21 | isAttend = isAttend, 22 | createdAt = createdAt, 23 | updatedAt = updatedAt, 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /domain/src/testFixtures/kotlin/com/studentcenter/weave/domain/meeting/entity/MeetingFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.meeting.entity 2 | 3 | import com.studentcenter.weave.domain.meeting.enums.MeetingStatus 4 | import com.studentcenter.weave.support.common.uuid.UuidCreator 5 | import java.time.LocalDateTime 6 | import java.util.* 7 | 8 | object MeetingFixtureFactory { 9 | 10 | fun create( 11 | id: UUID = UuidCreator.create(), 12 | requestingTeamId: UUID = UuidCreator.create(), 13 | receivingTeamId: UUID = UuidCreator.create(), 14 | status: MeetingStatus = MeetingStatus.PENDING, 15 | createdAt: LocalDateTime = LocalDateTime.now(), 16 | finishedAt: LocalDateTime? = null, 17 | ): Meeting { 18 | return Meeting( 19 | id = id, 20 | requestingTeamId = requestingTeamId, 21 | receivingTeamId = receivingTeamId, 22 | status = status, 23 | createdAt = createdAt, 24 | finishedAt = finishedAt, 25 | ) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /domain/src/testFixtures/kotlin/com/studentcenter/weave/domain/university/entity/MajorFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.entity 2 | 3 | import com.studentcenter.weave.domain.university.entity.Major 4 | import com.studentcenter.weave.domain.university.vo.MajorName 5 | import com.studentcenter.weave.support.common.uuid.UuidCreator 6 | import java.time.LocalDateTime 7 | import java.util.* 8 | 9 | object MajorFixtureFactory { 10 | 11 | fun create( 12 | id: UUID = UuidCreator.create(), 13 | univId: UUID = UuidCreator.create(), 14 | name: MajorName = MajorName("컴퓨터공학과"), 15 | createdAt: LocalDateTime = LocalDateTime.now(), 16 | ): Major { 17 | return Major( 18 | id = id, 19 | univId = univId, 20 | name = name, 21 | createdAt = createdAt, 22 | ) 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /domain/src/testFixtures/kotlin/com/studentcenter/weave/domain/user/entity/DeletedUserInfoFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.entity 2 | 3 | object DeletedUserInfoFixtureFactory { 4 | 5 | fun create( 6 | user: User = UserFixtureFactory.create(), 7 | userAuthInfo: UserAuthInfo = UserAuthInfoFixtureFactory.create(), 8 | reason: String? = null, 9 | ): DeletedUserInfo { 10 | return DeletedUserInfo( 11 | email = user.email, 12 | socialLoginProvider = userAuthInfo.socialLoginProvider, 13 | reason = reason, 14 | registeredAt = userAuthInfo.registeredAt, 15 | ) 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /domain/src/testFixtures/kotlin/com/studentcenter/weave/domain/user/entity/UserAuthInfoFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.entity 2 | 3 | import com.studentcenter.weave.domain.user.enums.SocialLoginProvider 4 | 5 | object UserAuthInfoFixtureFactory { 6 | 7 | fun create( 8 | user: User = UserFixtureFactory.create(), 9 | socialLoginProvider: SocialLoginProvider = SocialLoginProvider.KAKAO, 10 | ): UserAuthInfo { 11 | return UserAuthInfo( 12 | userId = user.id, 13 | email = user.email, 14 | socialLoginProvider = socialLoginProvider, 15 | registeredAt = user.registeredAt, 16 | ) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /domain/src/testFixtures/kotlin/com/studentcenter/weave/domain/user/entity/UserUniversityVerificationInfoFixtureFactory.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.domain.user.entity 2 | 3 | import com.studentcenter.weave.support.common.uuid.UuidCreator 4 | import com.studentcenter.weave.support.common.vo.Email 5 | import java.time.LocalDateTime 6 | import java.util.UUID 7 | 8 | object UserUniversityVerificationInfoFixtureFactory { 9 | 10 | fun create( 11 | id: UUID = UuidCreator.create(), 12 | user: User = UserFixtureFactory.create(), 13 | universityEmail: Email = Email("${UUID.randomUUID()}@weave.com"), 14 | verifiedAt: LocalDateTime = LocalDateTime.now().minusMinutes(1) 15 | ): UserUniversityVerificationInfo { 16 | return UserUniversityVerificationInfo( 17 | id = id, 18 | userId = user.id, 19 | universityId = user.universityId, 20 | universityEmail = universityEmail, 21 | verifiedAt = verifiedAt, 22 | ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Student-Center/weave-server/ce8307bdcd3c7a6dca9f9f084ed4dc7c669f544a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /infrastructure/aws/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.tasks.bundling.BootJar 2 | 3 | val jar: Jar by tasks 4 | val bootJar: BootJar by tasks 5 | 6 | bootJar.enabled = false 7 | jar.enabled = true 8 | 9 | dependencies { 10 | implementation(project(":support:common")) 11 | implementation(project(":domain")) 12 | implementation(project(":application")) 13 | 14 | implementation(libs.spring.boot.core) 15 | implementation(libs.spring.cloud.starter.aws.s3) 16 | } 17 | -------------------------------------------------------------------------------- /infrastructure/aws/src/main/kotlin/com/studentcenter/weave/infrastructure/aws/config/AwsConfig.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.aws.config 2 | 3 | import org.springframework.boot.context.properties.ConfigurationPropertiesScan 4 | import org.springframework.context.annotation.ComponentScan 5 | import org.springframework.context.annotation.Configuration 6 | 7 | @Configuration 8 | @ComponentScan(basePackages = ["com.studentcenter.weave.infrastructure.aws"]) 9 | @ConfigurationPropertiesScan(basePackages = ["com.studentcenter.weave.infrastructure.aws"]) 10 | class AwsConfig 11 | -------------------------------------------------------------------------------- /infrastructure/aws/src/main/kotlin/com/studentcenter/weave/infrastructure/aws/s3/config/S3BucketProperties.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.aws.s3.config 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties 4 | 5 | @ConfigurationProperties(prefix = "aws-bucket") 6 | data class S3BucketProperties( 7 | val userProfileImage: UserProfileImage, 8 | ) { 9 | 10 | data class UserProfileImage( 11 | val bucketName: String, 12 | val keyPrefix: String, 13 | val presignedUrlExpirationMin: Long, 14 | ) 15 | 16 | } 17 | -------------------------------------------------------------------------------- /infrastructure/aws/src/main/kotlin/com/studentcenter/weave/infrastructure/aws/s3/config/S3Config.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.aws.s3.config 2 | 3 | import org.springframework.context.annotation.Bean 4 | import org.springframework.context.annotation.Configuration 5 | import software.amazon.awssdk.services.s3.presigner.S3Presigner 6 | 7 | @Configuration 8 | class S3Config { 9 | 10 | @Bean 11 | fun s3PreSigner(): S3Presigner { 12 | return S3Presigner.create() 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /infrastructure/aws/src/main/resources/application-aws.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | aws: 4 | credentials: 5 | access-key: ${AWS_S3_ACCESS_KEY} 6 | secret-key: ${AWS_S3_SECRET_KEY} 7 | region: 8 | static: ${AWS_REGION:ap-northeast-2} 9 | aws-bucket: 10 | user-profile-image: 11 | bucket-name: ${AWS_S3_BUCKET_NAME:weave-server-dev-bucket} 12 | key-prefix: ${AWS_S3_PROFILE_IMAGE_BUCKET_KEY_PREFIX:user/profile-img/} 13 | presigned-url-expiration-min: 5 14 | -------------------------------------------------------------------------------- /infrastructure/client/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.tasks.bundling.BootJar 2 | 3 | val jar: Jar by tasks 4 | val bootJar: BootJar by tasks 5 | 6 | bootJar.enabled = false 7 | jar.enabled = true 8 | 9 | dependencies { 10 | implementation(project(":support:common")) 11 | implementation(project(":domain")) 12 | implementation(project(":application")) 13 | 14 | implementation(libs.spring.cloud.starter.openfeign) 15 | } 16 | -------------------------------------------------------------------------------- /infrastructure/client/src/main/kotlin/com/studentcenter/weave/infrastructure/client/common/config/ClientConfig.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.client.common.config 2 | 3 | import org.springframework.boot.context.properties.ConfigurationPropertiesScan 4 | import org.springframework.boot.context.properties.EnableConfigurationProperties 5 | import org.springframework.cloud.openfeign.EnableFeignClients 6 | import org.springframework.context.annotation.ComponentScan 7 | import org.springframework.context.annotation.Configuration 8 | 9 | @Configuration 10 | @ComponentScan(basePackages = ["com.studentcenter.weave.infrastructure.client"]) 11 | @EnableConfigurationProperties 12 | @EnableFeignClients(basePackages = ["com.studentcenter.weave.infrastructure.client"]) 13 | @ConfigurationPropertiesScan(basePackages = ["com.studentcenter.weave.infrastructure.client"]) 14 | class ClientConfig { 15 | } 16 | -------------------------------------------------------------------------------- /infrastructure/client/src/main/kotlin/com/studentcenter/weave/infrastructure/client/common/event/EventType.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.client.common.event 2 | 3 | enum class EventType { 4 | USER_REGISTRATION, 5 | MEETING_MATCHING, 6 | } 7 | -------------------------------------------------------------------------------- /infrastructure/client/src/main/kotlin/com/studentcenter/weave/infrastructure/client/common/properties/ClientProperties.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.client.common.properties 2 | 3 | import com.studentcenter.weave.infrastructure.client.common.event.EventType 4 | import org.springframework.boot.context.properties.ConfigurationProperties 5 | 6 | @ConfigurationProperties("client") 7 | class ClientProperties( 8 | val events: Map 9 | ) { 10 | data class Properties( 11 | val active: Boolean, 12 | val url: String, 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /infrastructure/client/src/main/kotlin/com/studentcenter/weave/infrastructure/client/discord/common/vo/DiscordMessage.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.client.discord.common.vo 2 | 3 | data class DiscordMessage( 4 | val content: String, 5 | ) 6 | -------------------------------------------------------------------------------- /infrastructure/client/src/main/kotlin/com/studentcenter/weave/infrastructure/client/discord/util/DiscordClient.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.client.discord.util 2 | 3 | import com.studentcenter.weave.infrastructure.client.discord.common.vo.DiscordMessage 4 | import org.springframework.cloud.openfeign.FeignClient 5 | import org.springframework.http.MediaType 6 | import org.springframework.web.bind.annotation.PostMapping 7 | import org.springframework.web.bind.annotation.RequestBody 8 | import java.net.URI 9 | 10 | 11 | @FeignClient( 12 | name = "discord-client", 13 | url = "weave-url", 14 | ) 15 | fun interface DiscordClient { 16 | 17 | @PostMapping(consumes = [MediaType.APPLICATION_JSON_VALUE]) 18 | fun send( 19 | uri: URI, 20 | @RequestBody 21 | message: DiscordMessage, 22 | ) 23 | 24 | } 25 | -------------------------------------------------------------------------------- /infrastructure/client/src/main/resources/application-client.yaml: -------------------------------------------------------------------------------- 1 | client: 2 | events: 3 | user-registration: 4 | active: false 5 | url: https://discord.com/api/webhooks/1219520018413260840/kUkwhG0DDTBTShr6-Cggr_0ShH8TUVMiYBRCXy0y8GMYNkmdQQ-JsOU31yH4QL7AQMhT 6 | meeting-matching: 7 | active: false 8 | url: https://discord.com/api/webhooks/1221026767246987274/49ptH5t5-skHUDlbb40qbquA26a06jueTdcFO-PePggdObegukLwB97uJ9FM-zerlfr0 9 | --- 10 | spring: 11 | config: 12 | activate: 13 | on-profile: prod 14 | 15 | client: 16 | events: 17 | user-registration: 18 | active: true 19 | url: https://discord.com/api/webhooks/1219520018413260840/kUkwhG0DDTBTShr6-Cggr_0ShH8TUVMiYBRCXy0y8GMYNkmdQQ-JsOU31yH4QL7AQMhT 20 | meeting-matching: 21 | active: true 22 | url: https://discord.com/api/webhooks/1221026767246987274/49ptH5t5-skHUDlbb40qbquA26a06jueTdcFO-PePggdObegukLwB97uJ9FM-zerlfr0 23 | -------------------------------------------------------------------------------- /infrastructure/mail/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.tasks.bundling.BootJar 2 | 3 | val jar: Jar by tasks 4 | val bootJar: BootJar by tasks 5 | 6 | bootJar.enabled = false 7 | jar.enabled = true 8 | 9 | dependencies { 10 | implementation(project(":support:common")) 11 | implementation(project(":application")) 12 | 13 | implementation(libs.spring.boot.starter.thymeleaf) 14 | implementation(libs.spring.boot.starter.mail) 15 | 16 | // TODO(SES Sandbox): SES Sandbox 해제시 적용 17 | // implementation(libs.aws.sdk.kotlin.ses) 18 | } 19 | -------------------------------------------------------------------------------- /infrastructure/mail/src/main/kotlin/com/studentcenter/weave/infrastructure/mail/common/config/MailConfig.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.mail.common.config 2 | 3 | import org.springframework.boot.context.properties.ConfigurationPropertiesScan 4 | import org.springframework.boot.context.properties.EnableConfigurationProperties 5 | import org.springframework.context.annotation.ComponentScan 6 | import org.springframework.context.annotation.Configuration 7 | 8 | 9 | 10 | @Configuration 11 | @ComponentScan(basePackages = ["com.studentcenter.weave.infrastructure.mail"]) 12 | @EnableConfigurationProperties 13 | @ConfigurationPropertiesScan(basePackages = ["com.studentcenter.weave.infrastructure.mail"]) 14 | class MailConfig 15 | -------------------------------------------------------------------------------- /infrastructure/mail/src/main/kotlin/com/studentcenter/weave/infrastructure/mail/common/exception/MailException.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.mail.common.exception 2 | 3 | import com.studentcenter.weave.support.common.exception.CustomException 4 | 5 | sealed class MailException( 6 | codeNumber: Int, 7 | message: String, 8 | ) : CustomException(CODE_PREFIX, codeNumber, message) { 9 | 10 | class ClientException(message: String = "") : 11 | MailException(codeNumber = 1, message = message) 12 | 13 | companion object { 14 | const val CODE_PREFIX = "MAIL" 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /infrastructure/mail/src/main/kotlin/com/studentcenter/weave/infrastructure/mail/ses/config/SesConfig.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.mail.ses.config 2 | 3 | // TODO(SES Sandbox): SES Sandbox 해제시 적용 4 | //@Configuration 5 | //@ComponentScan(basePackages = ["com.studentcenter.weave.support.email"]) 6 | //@ConfigurationPropertiesScan(basePackages = ["com.studentcenter.weave.support.email"]) 7 | //class SesConfig( 8 | // private val sesProperties: SesProperties, 9 | //) { 10 | // 11 | // @Bean 12 | // fun sesClient() = SesClient { 13 | // // region 설정 14 | // region = "ap-northeast-2" 15 | // 16 | // // aws 인증 17 | // credentialsProvider = StaticCredentialsProvider { 18 | // accessKeyId = sesProperties.accessKey 19 | // secretAccessKey = sesProperties.secretKey 20 | // } 21 | // 22 | // 23 | // } 24 | // 25 | //} 26 | -------------------------------------------------------------------------------- /infrastructure/mail/src/main/kotlin/com/studentcenter/weave/infrastructure/mail/ses/properties/SesProperties.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.mail.ses.properties 2 | 3 | // TODO(SES Sandbox): SES Sandbox 해제시 적용 4 | //@ConfigurationProperties(value = "aws.ses") 5 | //data class SesProperties( 6 | // val accessKey: String, 7 | // val secretKey: String, 8 | //) 9 | -------------------------------------------------------------------------------- /infrastructure/mail/src/main/kotlin/com/studentcenter/weave/infrastructure/mail/ses/service/AmazonSimpleEmailService.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.mail.ses.service 2 | 3 | // TODO(SES Sandbox): SES Sandbox 해제시 적용 4 | //@Service 5 | //class AmazonSimpleEmailService( 6 | // private val sesClient: SesClient, 7 | //) { 8 | // 9 | // suspend fun sendMailAsync(emailRequest: SendEmailRequest) = sesClient.use { 10 | // it.sendEmail(emailRequest) 11 | // } 12 | // 13 | // fun sendMail(emailRequest: SendEmailRequest) = runBlocking { sendMailAsync(emailRequest) } 14 | // 15 | //} 16 | -------------------------------------------------------------------------------- /infrastructure/mail/src/main/resources/application-mail.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | thymeleaf: 3 | prefix: classpath:/mail-templates/ 4 | suffix: .html 5 | mode: HTML 6 | encoding: UTF-8 7 | check-template-location: true 8 | cache: false 9 | mail: 10 | host: smtp.gmail.com 11 | port: 587 12 | username: ${EMAIL_USERNAME} 13 | password: ${EMAIL_PASSWORD} 14 | properties: 15 | mail: 16 | smtp: 17 | auth: true 18 | starttls.enable: true 19 | # TODO(SES Sandbox): SES Sandbox 해제시 적용 20 | #aws: 21 | # ses: 22 | # access-key: ${AWS_SES_ACCESS_KEY} 23 | # secret-key: ${AWS_SES_SECRET_KEY} 24 | -------------------------------------------------------------------------------- /infrastructure/persistence/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.tasks.bundling.BootJar 2 | 3 | val jar: Jar by tasks 4 | val bootJar: BootJar by tasks 5 | 6 | bootJar.enabled = false 7 | jar.enabled = true 8 | 9 | dependencies { 10 | implementation(project(":support:common")) 11 | implementation(project(":domain")) 12 | implementation(project(":application")) 13 | 14 | implementation(libs.spring.boot.starter.data.jpa) 15 | implementation(libs.flyway.core) 16 | implementation(libs.flyway.mysql) 17 | 18 | runtimeOnly(libs.mysql.connector.java) 19 | } 20 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/chat/repository/ChatMessageJpaRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.chat.repository 2 | 3 | import com.studentcenter.weave.infrastructure.persistence.chat.enitty.ChatMessageJpaEntity 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import org.springframework.data.jpa.repository.Query 6 | import org.springframework.stereotype.Repository 7 | import java.util.* 8 | 9 | @Repository 10 | interface ChatMessageJpaRepository : JpaRepository { 11 | 12 | @Query( 13 | value = 14 | """ 15 | select * from chat_message cm 16 | where cm.room_id = :chatRoomId 17 | and (:next is null or cm.id <= :next) 18 | order by cm.id desc 19 | limit :limit 20 | """, 21 | nativeQuery = true 22 | ) 23 | fun getScrollList( 24 | chatRoomId: UUID, 25 | next: UUID?, 26 | limit: Int, 27 | ): List 28 | 29 | } 30 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/chat/repository/ChatRoomJpaRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.chat.repository 2 | 3 | import com.studentcenter.weave.infrastructure.persistence.chat.enitty.ChatRoomJpaEntity 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import org.springframework.stereotype.Repository 6 | import java.util.UUID 7 | 8 | @Repository 9 | interface ChatRoomJpaRepository : JpaRepository 10 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/common/config/PersistenceConfig.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.common.config 2 | 3 | import org.springframework.boot.autoconfigure.domain.EntityScan 4 | import org.springframework.context.annotation.ComponentScan 5 | import org.springframework.context.annotation.Configuration 6 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories 7 | 8 | @Configuration 9 | @ComponentScan(basePackages = ["com.studentcenter.weave.infrastructure.persistence"]) 10 | @EntityScan(basePackages = ["com.studentcenter.weave.infrastructure.persistence"]) 11 | @EnableJpaRepositories(basePackages = ["com.studentcenter.weave.infrastructure.persistence"]) 12 | class PersistenceConfig 13 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/common/exception/PersistenceException.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.common.exception 2 | 3 | import com.studentcenter.weave.support.common.exception.CustomException 4 | 5 | sealed class PersistenceException( 6 | codeNumber: Int, 7 | message: String, 8 | ) : CustomException(CODE_PREFIX, codeNumber, message) { 9 | 10 | class ResourceNotFound(message: String = "") : 11 | PersistenceException(codeNumber = 1, message = message) 12 | 13 | companion object { 14 | const val CODE_PREFIX = "PERSISTENCE" 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/meeting/repository/MeetingAttendanceJpaRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.meeting.repository 2 | 3 | import com.studentcenter.weave.infrastructure.persistence.meeting.entity.MeetingAttendanceJpaEntity 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import org.springframework.stereotype.Repository 6 | import java.util.* 7 | 8 | @Repository 9 | interface MeetingAttendanceJpaRepository : JpaRepository { 10 | 11 | fun findAllByMeetingId(meetingId: UUID): List 12 | 13 | fun countByMeetingIdAndIsAttendIsTrue(meetingId: UUID): Int 14 | 15 | fun existsByMeetingIdAndMeetingMemberId(meetingId: UUID, meetingMemberId: UUID) : Boolean 16 | 17 | } 18 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/meetingTeam/repository/MeetingTeamMemberSummaryJpaRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.meetingTeam.repository 2 | 3 | import com.studentcenter.weave.infrastructure.persistence.meetingTeam.entity.MeetingTeamMemberSummaryJpaEntity 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import java.util.* 6 | 7 | interface MeetingTeamMemberSummaryJpaRepository : 8 | JpaRepository { 9 | 10 | fun findByMeetingTeamId(meetingTeamId: UUID): MeetingTeamMemberSummaryJpaEntity? 11 | 12 | } 13 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/suggestion/adapter/SuggestionJpaAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.suggestion.adapter 2 | 3 | import com.studentcenter.weave.application.suggestion.port.outbound.SuggestionRepository 4 | import com.studentcenter.weave.domain.suggestion.entity.Suggestion 5 | import com.studentcenter.weave.infrastructure.persistence.suggestion.entity.SuggestionJpaEntity.Companion.toJpaEntity 6 | import com.studentcenter.weave.infrastructure.persistence.suggestion.repository.SuggestionJpaRepository 7 | import org.springframework.stereotype.Component 8 | 9 | @Component 10 | class SuggestionJpaAdapter( 11 | private val suggestionJpaRepository: SuggestionJpaRepository, 12 | ) : SuggestionRepository { 13 | 14 | override fun save(suggestion: Suggestion) { 15 | suggestionJpaRepository.save(suggestion.toJpaEntity()) 16 | } 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/suggestion/repository/SuggestionJpaRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.suggestion.repository 2 | 3 | import com.studentcenter.weave.infrastructure.persistence.suggestion.entity.SuggestionJpaEntity 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import org.springframework.stereotype.Repository 6 | import java.util.* 7 | 8 | @Repository 9 | interface SuggestionJpaRepository : JpaRepository 10 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/university/repository/MajorJpaRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.university.repository 2 | 3 | import com.studentcenter.weave.infrastructure.persistence.university.entity.MajorJpaEntity 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import org.springframework.stereotype.Repository 6 | import java.util.* 7 | 8 | @Repository 9 | interface MajorJpaRepository : JpaRepository { 10 | 11 | fun findAllByUnivId(univId: UUID): List 12 | 13 | } 14 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/university/repository/UniversityJpaRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.university.repository 2 | 3 | import com.studentcenter.weave.infrastructure.persistence.university.entity.UniversityJpaEntity 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import org.springframework.stereotype.Repository 6 | import java.util.* 7 | 8 | @Repository 9 | interface UniversityJpaRepository : JpaRepository { 10 | 11 | fun findByName(value: String): UniversityJpaEntity? 12 | 13 | } 14 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/user/adapter/DeletedUserInfoJpaAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.user.adapter 2 | 3 | import com.studentcenter.weave.application.user.port.outbound.DeletedUserInfoRepository 4 | import com.studentcenter.weave.domain.user.entity.DeletedUserInfo 5 | import com.studentcenter.weave.infrastructure.persistence.user.entity.DeletedUserInfoJpaEntity.Companion.toJpaEntity 6 | import com.studentcenter.weave.infrastructure.persistence.user.repository.DeletedUserInfoJpaRepository 7 | import org.springframework.stereotype.Component 8 | 9 | @Component 10 | class DeletedUserInfoJpaAdapter ( 11 | private val deletedUserInfoJpaRepository: DeletedUserInfoJpaRepository 12 | ): DeletedUserInfoRepository { 13 | 14 | override fun save(deletedUserInfo: DeletedUserInfo) { 15 | deletedUserInfo 16 | .toJpaEntity() 17 | .let { deletedUserInfoJpaRepository.save(it) } 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/user/entity/PreRegisteredEmail.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.user.entity 2 | 3 | import jakarta.persistence.Entity 4 | import jakarta.persistence.Id 5 | import jakarta.persistence.Table 6 | 7 | @Entity 8 | @Table(name = "pre_registered_email") 9 | class PreRegisteredEmail( 10 | email: String, 11 | ) { 12 | 13 | @Id 14 | var email: String = email 15 | private set 16 | 17 | } 18 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/user/repository/DeletedUserInfoJpaRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.user.repository 2 | 3 | import com.studentcenter.weave.infrastructure.persistence.user.entity.DeletedUserInfoJpaEntity 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import org.springframework.stereotype.Repository 6 | import java.util.* 7 | 8 | @Repository 9 | interface DeletedUserInfoJpaRepository : JpaRepository 10 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/user/repository/PreRegisteredEmailRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.user.repository 2 | 3 | import com.studentcenter.weave.infrastructure.persistence.user.entity.PreRegisteredEmail 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import org.springframework.stereotype.Repository 6 | 7 | @Repository 8 | interface PreRegisteredEmailRepository: JpaRepository 9 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/user/repository/UserAuthInfoJpaRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.user.repository 2 | 3 | import com.studentcenter.weave.infrastructure.persistence.user.entity.UserAuthInfoJpaEntity 4 | import com.studentcenter.weave.support.common.vo.Email 5 | import org.springframework.data.jpa.repository.JpaRepository 6 | import org.springframework.stereotype.Repository 7 | import java.util.* 8 | 9 | @Repository 10 | interface UserAuthInfoJpaRepository : JpaRepository { 11 | 12 | fun findByEmail(email: Email): UserAuthInfoJpaEntity? 13 | 14 | fun findByUserId(userId: UUID): UserAuthInfoJpaEntity? 15 | 16 | } 17 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/user/repository/UserJpaRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.user.repository 2 | 3 | import com.studentcenter.weave.infrastructure.persistence.user.entity.UserJpaEntity 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import org.springframework.data.jpa.repository.Query 6 | import org.springframework.stereotype.Repository 7 | import java.util.* 8 | 9 | @Repository 10 | interface UserJpaRepository : JpaRepository { 11 | 12 | fun findByKakaoId(kakaoId: String): UserJpaEntity? 13 | 14 | @Query("select u from UserJpaEntity u where u.id in :ids") 15 | fun findAllByIds(ids: List): List 16 | 17 | override fun count(): Long 18 | 19 | } 20 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/user/repository/UserSilJpaRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.user.repository 2 | 3 | import com.studentcenter.weave.infrastructure.persistence.user.entity.UserSilJpaEntity 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import org.springframework.stereotype.Repository 6 | import java.util.UUID 7 | 8 | @Repository 9 | interface UserSilJpaRepository : JpaRepository { 10 | 11 | fun findByUserId(userId: UUID): UserSilJpaEntity? 12 | 13 | } 14 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/kotlin/com/studentcenter/weave/infrastructure/persistence/user/repository/UserUniversityVerificationInfoJpaRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.persistence.user.repository 2 | 3 | import com.studentcenter.weave.infrastructure.persistence.user.entity.UserUniveristyVerificationInfoJpaEntity 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | import org.springframework.stereotype.Repository 6 | import java.util.* 7 | 8 | @Repository 9 | interface UserUniversityVerificationInfoJpaRepository : JpaRepository { 10 | 11 | fun existsByUniversityEmail(email: String): Boolean 12 | 13 | fun existsByUserId(userId: UUID): Boolean 14 | 15 | } 16 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V10__update_universities.sql: -------------------------------------------------------------------------------- 1 | -- 대학 정보 -- 2 | ALTER TABLE university 3 | MODIFY logo_address VARCHAR(255) NULL; 4 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V11__change_meeting_team_add_gender.sql: -------------------------------------------------------------------------------- 1 | alter table meeting_team 2 | add column gender varchar(255) not null 3 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V12__create_user_university_verification_info.sql: -------------------------------------------------------------------------------- 1 | alter table user add column is_univ_verified BOOLEAN not null default false; 2 | 3 | create table user_university_verification_info 4 | ( 5 | id binary(16) not null, 6 | user_id binary(16) not null, 7 | university_id binary(16) not null, 8 | university_email varchar(255) not null collate utf8mb4_unicode_ci, 9 | verified_at datetime(6) not null, 10 | primary key (id), 11 | unique key user_university_verification_info_user_id_uindex (user_id), 12 | unique key user_university_verification_info_university_email_uindex (university_email) 13 | ) engine = InnoDB 14 | default charset = utf8mb4; 15 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V13__create_meeting_member.sql: -------------------------------------------------------------------------------- 1 | drop table weave.meeting_team_member; 2 | create table weave.meeting_member 3 | ( 4 | id binary(16) not null, 5 | meeting_team_id binary(16) not null, 6 | user_id binary(16) not null, 7 | role varchar(255) not null, 8 | primary key (id), 9 | index meeting_member_meeting_team_id_index (meeting_team_id), 10 | index meeting_member_user_id_index (user_id), 11 | unique unique_meeting_member (meeting_team_id, user_id) 12 | ); 13 | 14 | alter table weave.meeting_team 15 | drop column leader_user_id; 16 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V15__create_meeting_team_member_summary.sql: -------------------------------------------------------------------------------- 1 | create table meeting_team_member_summary 2 | ( 3 | id binary(16) not null, 4 | meeting_team_id binary(16) not null, 5 | team_mbti varchar(255) not null, 6 | youngest_member_birth_year int not null, 7 | oldest_member_birth_year int not null, 8 | created_at timestamp not null, 9 | primary key (id), 10 | unique meeting_team_id (meeting_team_id) 11 | ) engine = innodb 12 | default charset = utf8mb4; 13 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V16__add_user_kakao_id.sql: -------------------------------------------------------------------------------- 1 | alter table weave.user add column kakao_id varchar(255); 2 | alter table weave.user add unique (kakao_id); 3 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V17__add_university_display_name.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE weave.university ADD COLUMN display_name varchar(255); 2 | 3 | UPDATE weave.university 4 | SET weave.university.display_name = weave.university.name; 5 | 6 | ALTER TABLE weave.university MODIFY COLUMN display_name varchar(255) not null; 7 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V18__add_profile_image.sql: -------------------------------------------------------------------------------- 1 | alter table `user` 2 | drop column avatar; 3 | 4 | create table user_profile_image 5 | ( 6 | id binary(16) not null, 7 | user_id binary(16) not null, 8 | extension varchar(255) not null, 9 | image_url varchar(255) not null, 10 | primary key (id), 11 | index user_profile_image_user_id_index (user_id) 12 | ); 13 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V19__create_chat_room.sql: -------------------------------------------------------------------------------- 1 | create table chat_room 2 | ( 3 | id binary(16), 4 | meeting_id binary(16), 5 | receiving_team_id binary(16), 6 | requesting_team_id binary(16), 7 | created_at timestamp, 8 | primary key (id), 9 | index (meeting_id), 10 | index (receiving_team_id), 11 | index (requesting_team_id) 12 | ) engine = InnoDB 13 | default charset = utf8mb4; 14 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V1__init_user_auth_info.sql: -------------------------------------------------------------------------------- 1 | -- 유저 인증 정보 -- 2 | create table if not exists user_auth_info 3 | ( 4 | id binary(16) not null, 5 | user_id binary(16) not null, 6 | email varchar(255) not null collate utf8mb4_unicode_ci, 7 | social_login_provider varchar(255) not null, 8 | registered_at datetime(6) not null, 9 | primary key (id), 10 | unique key user_auth_info_user_id_uindex (user_id), 11 | unique key user_auth_info_email_uindex (email) 12 | ) engine = InnoDB 13 | default charset = utf8mb4; 14 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V20__create_chat_message.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE chat_message 2 | ( 3 | id BINARY(16) NOT NULL, 4 | room_id BINARY(16) NOT NULL, 5 | sender_id BINARY(16) NOT NULL, 6 | sender_type VARCHAR(255) NOT NULL, 7 | contents JSON NOT NULL, 8 | created_at DATETIME NOT NULL, 9 | PRIMARY KEY (id), 10 | INDEX (room_id), 11 | INDEX (sender_id), 12 | INDEX (created_at) 13 | ) ENGINE = InnoDB 14 | DEFAULT CHARSET = utf8mb4 15 | COLLATE = utf8mb4_unicode_ci; 16 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V21__create_pre_registered_user.sql: -------------------------------------------------------------------------------- 1 | create table pre_registered_email( 2 | email varchar(255) primary key 3 | ) 4 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V22__create_suggestion.sql: -------------------------------------------------------------------------------- 1 | create table suggestion 2 | ( 3 | id binary(16) primary key, 4 | user_id binary(16) not null, 5 | contents text not null 6 | ) engine = InnoDB, 7 | char set utf8mb4; 8 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V2__Create_universities_and_majors.sql: -------------------------------------------------------------------------------- 1 | -- 대학 정보 -- 2 | create table university 3 | ( 4 | id binary(16) not null, 5 | name varchar(255) not null, 6 | domain_address varchar(255) not null, 7 | logo_address varchar(255) not null, 8 | created_at datetime(6) not null, 9 | updated_at datetime(6) not null, 10 | primary key (id), 11 | unique key university_name_uindex (name) 12 | ) engine = InnoDB default charset = utf8mb4; 13 | 14 | -- 학과 정보 -- 15 | create table major 16 | ( 17 | id binary(16) not null, 18 | univ_id binary(16) not null, 19 | name varchar(255) not null, 20 | created_at datetime(6) not null, 21 | primary key (id), 22 | unique key major_univ_id_and_name_uindex (univ_id, name) 23 | ) engine = InnoDB default charset = utf8mb4; 24 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V3__create_user.sql: -------------------------------------------------------------------------------- 1 | -- 유저 -- 2 | create table `user` 3 | ( 4 | id binary(16) not null, 5 | nickname varchar(255) not null, 6 | email varchar(255) not null, 7 | gender varchar(255) not null, 8 | mbti varchar(255) not null, 9 | birth_year integer not null, 10 | university_id binary(16) not null, 11 | major_id binary(16) not null, 12 | avatar varchar(255), 13 | registered_at datetime(6) not null, 14 | updated_at datetime(6) not null, 15 | primary key (id), 16 | index idx_university_id (university_id), 17 | index idx_major_id (major_id) 18 | ) engine = InnoDB 19 | default charset = utf8mb4; 20 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V4__user_add_column.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `user` ADD COLUMN height integer; 2 | ALTER TABLE `user` ADD COLUMN animal_type varchar(255); 3 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V5__create_meeting_team.sql: -------------------------------------------------------------------------------- 1 | -- 미팅 팀 -- 2 | create table meeting_team 3 | ( 4 | id binary(16) not null, 5 | team_introduce varchar(255) not null, 6 | leader_user_id binary(16) not null, 7 | member_count int not null, 8 | location varchar(255) not null, 9 | primary key (id), 10 | index (leader_user_id) 11 | ); 12 | 13 | -- 미팅 팀 멤버 -- 14 | create table meeting_team_member 15 | ( 16 | id binary(16) not null, 17 | meeting_team_id binary(16) not null, 18 | user_id binary(16) not null, 19 | primary key (id), 20 | index (meeting_team_id), 21 | index (user_id) 22 | ); 23 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V6__create_deleted_user_info.sql: -------------------------------------------------------------------------------- 1 | -- 삭제된 유저 정보 -- 2 | create table deleted_user_info 3 | ( 4 | id binary(16) not null primary key, 5 | email varchar(255) not null, 6 | social_login_provider varchar(255) not null, 7 | reason varchar(255), 8 | registered_at datetime not null, 9 | deleted_at datetime not null 10 | ); 11 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V7__meeting_team_add_status_column.sql: -------------------------------------------------------------------------------- 1 | alter table meeting_team add column status varchar(255) not null 2 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V8__create_user_sil.sql: -------------------------------------------------------------------------------- 1 | create table user_sil 2 | ( 3 | id binary(16) not null, 4 | user_id binary(16) not null, 5 | amount bigint not null, 6 | primary key (id), 7 | index (user_id) 8 | ) 9 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/migration/V9__change_user_id_index_to_unique.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE user_sil 2 | DROP INDEX user_id; 3 | 4 | ALTER TABLE user_sil 5 | ADD UNIQUE INDEX user_id_unique (user_id); 6 | -------------------------------------------------------------------------------- /infrastructure/persistence/src/main/resources/db/seed/230408_insert_temp_university_major.sql: -------------------------------------------------------------------------------- 1 | -- university 2 | INSERT INTO university(id, name, display_name, domain_address, created_at, updated_at) 3 | VALUES 4 | (UNHEX(REPLACE('018d7782-f110-76d9-b27f-99a11f11b029','-','')),'위브대학교','위브대','gmail.com','2023-04-08T00:00', '2023-04-08T00:00'); 5 | 6 | -- major 7 | INSERT INTO major(id, univ_id, name, created_at) 8 | VALUES 9 | (UNHEX(REPLACE('018d7a0a-2af7-75de-9c79-0758d4be6156','-','')),UNHEX(REPLACE('018d7782-f110-76d9-b27f-99a11f11b029','-','')),'위브학과','2023-04-08T00:10'); 10 | -------------------------------------------------------------------------------- /infrastructure/redis/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.tasks.bundling.BootJar 2 | 3 | val jar: Jar by tasks 4 | val bootJar: BootJar by tasks 5 | 6 | bootJar.enabled = false 7 | jar.enabled = true 8 | 9 | dependencies { 10 | implementation(project(":support:common")) 11 | implementation(project(":domain")) 12 | implementation(project(":application")) 13 | implementation(libs.spring.boot.starter.data.redis) 14 | } 15 | -------------------------------------------------------------------------------- /infrastructure/redis/src/main/kotlin/com/studentcenter/weave/infrastructure/redis/chat/adapter/ChatMessageRedisPublisher.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.redis.chat.adapter 2 | 3 | import com.studentcenter.weave.application.chat.port.outbound.ChatMessagePublisher 4 | import com.studentcenter.weave.domain.chat.entity.ChatMessage 5 | import com.studentcenter.weave.infrastructure.redis.chat.config.ChatMessageRedisConfig 6 | import org.springframework.data.redis.core.RedisTemplate 7 | import org.springframework.stereotype.Component 8 | 9 | @Component 10 | class ChatMessageRedisPublisher( 11 | private val redisTemplate: RedisTemplate, 12 | ) : ChatMessagePublisher { 13 | 14 | override fun publish(chatMessage: ChatMessage) { 15 | redisTemplate.convertAndSend(ChatMessageRedisConfig.CHAT_MESSAGE, chatMessage) 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /infrastructure/redis/src/main/kotlin/com/studentcenter/weave/infrastructure/redis/common/properties/RedisProperties.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.redis.common.properties 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties 4 | 5 | @ConfigurationProperties(value = "spring.data.redis") 6 | data class RedisProperties( 7 | val host: String, 8 | val port: Int, 9 | ) 10 | -------------------------------------------------------------------------------- /infrastructure/redis/src/main/kotlin/com/studentcenter/weave/infrastructure/redis/meetingTeam/entity/MeetingTeamInvitationRedisHash.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.redis.meetingTeam.entity 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.redis.core.RedisHash 5 | import org.springframework.data.redis.core.TimeToLive 6 | import java.util.* 7 | 8 | @RedisHash("meeting_team_invitation") 9 | class MeetingTeamInvitationRedisHash( 10 | teamId: UUID, 11 | invitationCode: UUID, 12 | invitationLink: String, 13 | expirationDuration: Long, 14 | ) { 15 | 16 | @Id 17 | var invitationCode: UUID = invitationCode 18 | private set 19 | 20 | var teamId: UUID = teamId 21 | private set 22 | 23 | var invitationLink: String = invitationLink 24 | private set 25 | 26 | @TimeToLive 27 | var expirationDuration: Long = expirationDuration 28 | private set 29 | 30 | } 31 | -------------------------------------------------------------------------------- /infrastructure/redis/src/main/kotlin/com/studentcenter/weave/infrastructure/redis/meetingTeam/repository/MeetingTeamInvitationRedisRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.redis.meetingTeam.repository 2 | 3 | import com.studentcenter.weave.infrastructure.redis.meetingTeam.entity.MeetingTeamInvitationRedisHash 4 | import org.springframework.data.repository.CrudRepository 5 | import org.springframework.stereotype.Repository 6 | import java.util.* 7 | 8 | @Repository 9 | interface MeetingTeamInvitationRedisRepository : 10 | CrudRepository 11 | -------------------------------------------------------------------------------- /infrastructure/redis/src/main/kotlin/com/studentcenter/weave/infrastructure/redis/user/entity/UserRefreshTokenRedisHash.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.redis.user.entity 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.redis.core.RedisHash 5 | import org.springframework.data.redis.core.TimeToLive 6 | import java.util.* 7 | 8 | @RedisHash("user_refresh_token") 9 | class UserRefreshTokenRedisHash( 10 | id: UUID, 11 | refreshToken: String, 12 | expirationSeconds: Long 13 | ) { 14 | 15 | @Id 16 | var id: UUID = id 17 | private set 18 | 19 | var refreshToken: String = refreshToken 20 | private set 21 | 22 | @TimeToLive 23 | var expirationSeconds: Long = expirationSeconds 24 | private set 25 | 26 | } 27 | -------------------------------------------------------------------------------- /infrastructure/redis/src/main/kotlin/com/studentcenter/weave/infrastructure/redis/user/entity/UserVerificationNumberRedisHash.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.redis.user.entity 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.redis.core.RedisHash 5 | import org.springframework.data.redis.core.TimeToLive 6 | import java.util.* 7 | 8 | @RedisHash("user_univ_mail_verification_number") 9 | class UserVerificationNumberRedisHash( 10 | id: UUID, 11 | verifiedEmail: String, 12 | verificationNumber: String, 13 | expirationSeconds: Long 14 | ) { 15 | 16 | @Id 17 | var id: UUID = id 18 | private set 19 | 20 | var verifiedEmail: String = verifiedEmail 21 | private set 22 | 23 | var verificationNumber: String = verificationNumber 24 | private set 25 | 26 | @TimeToLive 27 | var expirationSeconds: Long = expirationSeconds 28 | private set 29 | 30 | } 31 | -------------------------------------------------------------------------------- /infrastructure/redis/src/main/kotlin/com/studentcenter/weave/infrastructure/redis/user/repository/UserRefreshTokenRedisRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.redis.user.repository 2 | 3 | import com.studentcenter.weave.infrastructure.redis.user.entity.UserRefreshTokenRedisHash 4 | import org.springframework.data.repository.CrudRepository 5 | import org.springframework.stereotype.Repository 6 | import java.util.* 7 | 8 | @Repository 9 | interface UserRefreshTokenRedisRepository : CrudRepository 10 | -------------------------------------------------------------------------------- /infrastructure/redis/src/main/kotlin/com/studentcenter/weave/infrastructure/redis/user/repository/UserVerificationNumberRedisRepository.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.infrastructure.redis.user.repository 2 | 3 | import com.studentcenter.weave.infrastructure.redis.user.entity.UserVerificationNumberRedisHash 4 | import org.springframework.data.repository.CrudRepository 5 | import org.springframework.stereotype.Repository 6 | import java.util.* 7 | 8 | @Repository 9 | interface UserVerificationNumberRedisRepository : CrudRepository 10 | -------------------------------------------------------------------------------- /infrastructure/redis/src/main/resources/application-redis.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | data: 3 | redis: 4 | host: ${REDIS_HOST:localhost} 5 | port: ${REDIS_PORT:6379} 6 | --- 7 | spring: 8 | config: 9 | activate: 10 | on-profile: integration-test 11 | data: 12 | redis: 13 | host: localhost 14 | port: 6379 15 | -------------------------------------------------------------------------------- /support/common/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.tasks.bundling.BootJar 2 | 3 | val jar: Jar by tasks 4 | val bootJar: BootJar by tasks 5 | 6 | bootJar.enabled = false 7 | jar.enabled = true 8 | 9 | dependencies { 10 | implementation(libs.uuid.creator) 11 | } 12 | -------------------------------------------------------------------------------- /support/common/src/main/kotlin/com/studentcenter/weave/support/common/dto/ScrollRequest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.common.dto 2 | 3 | abstract class ScrollRequest( 4 | open val next: N, 5 | open val limit: Int 6 | ) 7 | -------------------------------------------------------------------------------- /support/common/src/main/kotlin/com/studentcenter/weave/support/common/dto/ScrollResponse.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.common.dto 2 | 3 | abstract class ScrollResponse( 4 | open val items: List, 5 | open val next: N, 6 | open val total: Int, 7 | ) 8 | -------------------------------------------------------------------------------- /support/common/src/main/kotlin/com/studentcenter/weave/support/common/exception/CustomException.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.common.exception 2 | 3 | abstract class CustomException( 4 | codePrefix: String = DEFAULT_CODE_PREFIX, 5 | codeNumber: Int, 6 | override val message: String = DEFAULT_MESSAGE, 7 | ) : RuntimeException(message) { 8 | 9 | val code: String = "$codePrefix-${ 10 | codeNumber.toString().padStart(DEFAULT_CODE_NUMBER_LENGTH, DEFAULT_CODE_NUMBER_PAD_CHAR) 11 | }" 12 | 13 | companion object { 14 | 15 | const val DEFAULT_CODE_NUMBER_LENGTH = 3 16 | const val DEFAULT_CODE_NUMBER_PAD_CHAR = '0' 17 | const val DEFAULT_CODE_PREFIX = "UNKNOWN" 18 | const val DEFAULT_MESSAGE = "알 수 없는 오류가 발생했습니다." 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /support/common/src/main/kotlin/com/studentcenter/weave/support/common/exception/SystemException.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.common.exception 2 | 3 | sealed class SystemException( 4 | codeNumber: Int, 5 | message: String, 6 | ) : CustomException(CODE_PREFIX, codeNumber, message) { 7 | 8 | class InternalServerError(message: String = "") : 9 | SystemException(codeNumber = 1, message = message) 10 | 11 | class NotFound(message: String = "") : 12 | SystemException(codeNumber = 2, message = message) 13 | 14 | companion object { 15 | const val CODE_PREFIX = "SYSTEM" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /support/common/src/main/kotlin/com/studentcenter/weave/support/common/uuid/UuidCreator.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.common.uuid 2 | 3 | import java.util.* 4 | import com.github.f4b6a3.uuid.UuidCreator 5 | 6 | object UuidCreator { 7 | 8 | /** 9 | * uuid version 7 기반으로 uuid 를 생성합니다. 10 | * millisecond 단위로 정렬된 uuid 를 생성하며, 11 | * 동일한 시간에 생성될 경우 단조 증가 counter를 활용해, unique 하게 생성됩니다. 12 | * 13 | * @return uuid version 7 type 2 14 | * @see Universally Unique IDentifiers (UUID) 15 | * @see UuidCreator.getTimeOrdered() 16 | * @author San Kim 17 | */ 18 | fun create(): UUID { 19 | return UuidCreator.getTimeOrderedEpochPlus1() 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /support/common/src/main/kotlin/com/studentcenter/weave/support/common/vo/Email.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.common.vo 2 | 3 | /** 4 | * @param value 이메일 주소 문자열 5 | * @throws IllegalArgumentException 이메일 주소가 올바른 형식이 아닌 경우 6 | */ 7 | @JvmInline 8 | value class Email(val value: String) { 9 | 10 | companion object { 11 | const val VALIDATION_REGEX = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}\$" 12 | const val VALIDATION_MESSAGE = "잘못된 Email 형식 입니다." 13 | } 14 | 15 | init { 16 | require(value.matches(VALIDATION_REGEX.toRegex())) { VALIDATION_MESSAGE } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /support/common/src/main/kotlin/com/studentcenter/weave/support/common/vo/UpdateParam.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.common.vo 2 | 3 | data class UpdateParam( 4 | val value: T?, 5 | ) 6 | 7 | fun UpdateParam?.getUpdateValue(oldValue: T?): T? { 8 | return if(this == null) oldValue else this.value 9 | } 10 | fun T?.toUpdateParam() = UpdateParam(this) 11 | -------------------------------------------------------------------------------- /support/common/src/main/kotlin/com/studentcenter/weave/support/common/vo/Url.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.common.vo 2 | 3 | /** 4 | * @property value URL 형식 문자열 5 | * @throws IllegalArgumentException URL 형식이 아닌 경우 6 | */ 7 | @JvmInline 8 | value class Url(val value: String) { 9 | 10 | companion object { 11 | const val VALIDATION_REGEX = "^(http|https)://.*" 12 | const val VALIDATION_MESSAGE = "잘못된 URL 형식입니다." 13 | } 14 | 15 | init { 16 | require(value.matches(VALIDATION_REGEX.toRegex())) { VALIDATION_MESSAGE } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /support/common/src/test/kotlin/com/studentcenter/weave/support/common/vo/EmailTest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.common.vo 2 | 3 | import io.kotest.assertions.throwables.shouldThrow 4 | import io.kotest.core.spec.style.FunSpec 5 | 6 | class EmailTest: FunSpec({ 7 | 8 | test("이메일 주소가 올바른 형식이 아닌 경우 예외가 발생한다.") { 9 | val invalidEmail = "invalid_email" 10 | shouldThrow { 11 | Email(invalidEmail) 12 | } 13 | } 14 | 15 | test("이메일 주소가 올바른 형식인 경우 객체가 생성된다.") { 16 | val validEmail = "test1234@test.com" 17 | Email(validEmail) 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /support/common/src/test/kotlin/com/studentcenter/weave/support/common/vo/UrlTest.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.common.vo 2 | 3 | import io.kotest.assertions.throwables.shouldThrow 4 | import io.kotest.core.spec.style.FunSpec 5 | 6 | class UrlTest : FunSpec({ 7 | 8 | test("URL 형식이 아닌 경우 예외가 발생한다.") { 9 | val invalidUrl = "invalid_url" 10 | shouldThrow { 11 | Url(invalidUrl) 12 | } 13 | } 14 | 15 | test("URL 형식인 경우 객체가 생성된다.") { 16 | val validUrl = "https://test.com" 17 | Url(validUrl) 18 | } 19 | 20 | }) 21 | -------------------------------------------------------------------------------- /support/jacoco/build.gradle.kts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Student-Center/weave-server/ce8307bdcd3c7a6dca9f9f084ed4dc7c669f544a/support/jacoco/build.gradle.kts -------------------------------------------------------------------------------- /support/lock/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.tasks.bundling.BootJar 2 | 3 | val jar: Jar by tasks 4 | val bootJar: BootJar by tasks 5 | 6 | bootJar.enabled = false 7 | jar.enabled = true 8 | 9 | dependencies { 10 | implementation(libs.redisson.spring.boot.starter) 11 | testFixturesImplementation(libs.mockk) 12 | } 13 | -------------------------------------------------------------------------------- /support/lock/src/main/kotlin/com/studentcenter/weave/support/lock/DistributedLockAspect.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.lock 2 | 3 | import io.github.oshai.kotlinlogging.KotlinLogging 4 | import org.redisson.api.RedissonClient 5 | import org.springframework.stereotype.Component 6 | 7 | @Component 8 | class DistributedLockAspect( 9 | innerRedissonClient: RedissonClient, 10 | innerDistributedLockTransactionProcessor: DistributedLockTransactionProcessor, 11 | ) { 12 | 13 | init { 14 | redissonClient = innerRedissonClient 15 | distributedLockTransactionProcessor = innerDistributedLockTransactionProcessor 16 | } 17 | 18 | companion object { 19 | 20 | val logger = KotlinLogging.logger { } 21 | 22 | lateinit var redissonClient: RedissonClient 23 | private set 24 | 25 | lateinit var distributedLockTransactionProcessor: DistributedLockTransactionProcessor 26 | private set 27 | 28 | const val REDISSON_LOCK_PREFIX = "LOCK:" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /support/lock/src/main/kotlin/com/studentcenter/weave/support/lock/DistributedLockConfig.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.lock 2 | 3 | import org.redisson.Redisson 4 | import org.redisson.api.RedissonClient 5 | import org.redisson.config.Config 6 | import org.springframework.boot.autoconfigure.data.redis.RedisProperties 7 | import org.springframework.context.annotation.Bean 8 | import org.springframework.context.annotation.ComponentScan 9 | import org.springframework.context.annotation.Configuration 10 | 11 | 12 | @Configuration 13 | @ComponentScan(basePackages = ["com.studentcenter.weave.support.lock"]) 14 | class DistributedLockConfig ( 15 | private val redisProperties: RedisProperties 16 | ){ 17 | 18 | @Bean 19 | fun redissonClient(): RedissonClient { 20 | val redisConfig = Config() 21 | redisConfig 22 | .useSingleServer() 23 | .apply { 24 | address = "redis://${redisProperties.host}:${redisProperties.port}" 25 | } 26 | return Redisson.create(redisConfig) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /support/lock/src/main/kotlin/com/studentcenter/weave/support/lock/DistributedLockTransactionProcessor.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.lock 2 | 3 | import org.springframework.stereotype.Component 4 | import org.springframework.transaction.annotation.Propagation 5 | import org.springframework.transaction.annotation.Transactional 6 | 7 | 8 | @Component 9 | class DistributedLockTransactionProcessor { 10 | 11 | @Transactional(propagation = Propagation.REQUIRES_NEW) 12 | fun proceed(function: () -> T): T { 13 | return function() 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /support/lock/src/testFixtures/kotlin/com/studentcetner/weave/support/lock/DistributedLockTestInitializer.kt: -------------------------------------------------------------------------------- 1 | package com.studentcetner.weave.support.lock 2 | 3 | import com.studentcenter.weave.support.lock.distributedLock 4 | import io.mockk.every 5 | import io.mockk.mockkStatic 6 | 7 | object DistributedLockTestInitializer { 8 | 9 | 10 | fun mockExecutionByStatic() { 11 | mockkStatic("com.studentcenter.weave.support.lock.DistributedLockKt") 12 | every { 13 | distributedLock(any(), any(), any(), captureLambda()) 14 | } answers { 15 | val lambda: () -> Any? = arg<(() -> Any?)>(3) 16 | lambda() 17 | } 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /support/logger/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.springframework.boot.gradle.tasks.bundling.BootJar 2 | 3 | val jar: Jar by tasks 4 | val bootJar: BootJar by tasks 5 | 6 | bootJar.enabled = false 7 | jar.enabled = true 8 | -------------------------------------------------------------------------------- /support/security/build.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencies { 2 | implementation(project(":support:common")) 3 | implementation(libs.java.jwt) 4 | implementation(libs.jwks.rsa) 5 | } 6 | -------------------------------------------------------------------------------- /support/security/src/main/kotlin/com/studentcenter/weave/support/security/authority/Authentication.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.security.authority 2 | 3 | import java.security.Principal 4 | 5 | interface Authentication : Principal 6 | -------------------------------------------------------------------------------- /support/security/src/main/kotlin/com/studentcenter/weave/support/security/context/SecurityContext.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.security.context 2 | 3 | import com.studentcenter.weave.support.security.authority.Authentication 4 | 5 | interface SecurityContext { 6 | 7 | fun getAuthentication(): T 8 | 9 | fun setAuthentication(authentication: T) 10 | 11 | } 12 | -------------------------------------------------------------------------------- /support/security/src/main/kotlin/com/studentcenter/weave/support/security/context/SecurityContextHolder.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.security.context 2 | 3 | import com.studentcenter.weave.support.security.authority.Authentication 4 | 5 | object SecurityContextHolder { 6 | 7 | private val contextHolder = ThreadLocal>() 8 | 9 | @Suppress("UNCHECKED_CAST") 10 | fun getContext(): SecurityContext? { 11 | return contextHolder.get() as SecurityContext? 12 | } 13 | 14 | fun setContext(context: SecurityContext) { 15 | contextHolder.set(context) 16 | } 17 | 18 | fun clearContext() { 19 | contextHolder.remove() 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /support/security/src/main/kotlin/com/studentcenter/weave/support/security/jwt/exception/JwtException.kt: -------------------------------------------------------------------------------- 1 | package com.studentcenter.weave.support.security.jwt.exception 2 | 3 | import com.studentcenter.weave.support.common.exception.CustomException 4 | 5 | 6 | sealed class JwtException( 7 | codeNumber: Int, 8 | message: String, 9 | ) : CustomException(CODE_PREFIX, codeNumber, message) { 10 | 11 | class DecodeException(message: String = "유효하지 않은 토큰입니다.") : 12 | JwtException(codeNumber = 1, message = message) 13 | 14 | class Expired(message: String = "토큰이 만료되었습니다.") : 15 | JwtException(codeNumber = 2, message = message) 16 | 17 | class VerificationException(message: String = "유효하지 않은 토큰입니다.") : 18 | JwtException(codeNumber = 3, message = message) 19 | 20 | companion object { 21 | const val CODE_PREFIX = "JWT" 22 | } 23 | 24 | } 25 | --------------------------------------------------------------------------------