From 5770bd7c7a5428b42d96132084c4c4017a470bda Mon Sep 17 00:00:00 2001 From: Jjoobob123 <273hur4747@gmail.com> Date: Tue, 4 Apr 2023 01:49:16 +0900 Subject: [PATCH 01/10] =?UTF-8?q?chore:=20review=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/reviews/reviews.resolver.ts | 28 ++++++++++++++++------------ src/apis/reviews/reviews.service.ts | 2 -- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/apis/reviews/reviews.resolver.ts b/src/apis/reviews/reviews.resolver.ts index 56619ff..5e5a2b0 100644 --- a/src/apis/reviews/reviews.resolver.ts +++ b/src/apis/reviews/reviews.resolver.ts @@ -12,18 +12,20 @@ export class ReviewsResolver { private readonly reviewsService: ReviewsService, // ) {} - @Query(() => Review, { - description: 'Return: 리뷰ID 기준으로 1개 불러오기', - }) + @Query( + () => Review, // + { description: 'Return: 리뷰ID 기준으로 1개 불러오기' }, + ) fetchReview( @Args('reviewId') reviewId: string, // ): Promise { return this.reviewsService.find({ reviewId }); } - @Query(() => [Review], { - description: 'Return: 가게ID 기준으로 모든 리뷰 불러오기', - }) + @Query( + () => [Review], // + { description: 'Return: 가게ID 기준으로 모든 리뷰 불러오기' }, + ) async fetchReviewsByShopId( @Args({ name: 'page', defaultValue: 1, nullable: true }) page: number, // @@ -40,9 +42,10 @@ export class ReviewsResolver { } @UseGuards(GqlAuthGuard('access')) - @Mutation(() => Review, { - description: 'Return: 신규 생성된 리뷰 데이터', - }) + @Mutation( + () => Review, // + { description: 'Return: 신규 생성된 리뷰 데이터' }, + ) createReview( @Args('createReviewInput') createReviewInput: CreateReviewInput, // @Context() context: IContext, @@ -54,9 +57,10 @@ export class ReviewsResolver { }); } - @Mutation(() => Boolean, { - description: 'Return: 리뷰 삭제 후 true 반환', - }) + @Mutation( + () => Boolean, // + { description: 'Return: 리뷰 삭제 후 true 반환' }, + ) deleteReview( @Args('reviewId') id: string, // ): Promise { diff --git a/src/apis/reviews/reviews.service.ts b/src/apis/reviews/reviews.service.ts index ca96de7..5e57d8b 100644 --- a/src/apis/reviews/reviews.service.ts +++ b/src/apis/reviews/reviews.service.ts @@ -23,7 +23,6 @@ export class ReviewsService { private readonly shopsService: ShopsService, ) {} - // 리뷰 가져오기 async find({ reviewId }: IReviewServiceFindById): Promise { const result = await this.reviewsRepository.findOne({ where: { id: reviewId }, @@ -37,7 +36,6 @@ export class ReviewsService { return result; } - // 가게의 모든 리뷰 가져오기 async findByShopIdWithPage({ page, count, // From cf4d179114993c03d403c84f321efc892ef5b4b1 Mon Sep 17 00:00:00 2001 From: Jjoobob123 <273hur4747@gmail.com> Date: Tue, 4 Apr 2023 10:04:07 +0900 Subject: [PATCH 02/10] =?UTF-8?q?shopImage=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/shopImages/shopImage.resolver.ts | 41 ++++++++++++++--------- src/apis/shopImages/shopImage.service.ts | 15 ++------- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/apis/shopImages/shopImage.resolver.ts b/src/apis/shopImages/shopImage.resolver.ts index aa5bc39..e41cce5 100644 --- a/src/apis/shopImages/shopImage.resolver.ts +++ b/src/apis/shopImages/shopImage.resolver.ts @@ -9,47 +9,56 @@ export class ShopImagesResolver { private readonly shopImagesService: ShopImagesService, // ) {} - @Query(() => ShopImage, { - description: 'Return: 입력한 가게의 썸네일 가게이미지(1개)', - }) + @Query( + () => ShopImage, // + { description: 'Return: 입력한 가게의 썸네일 가게이미지(1개)' }, + ) fetchThumbnailByShop( @Args('shopId') shopId: string, // ): Promise { return this.shopImagesService.findThumbnailByShopId({ shopId }); } - @Query(() => [ShopImage], { - description: 'Return: 입력한 가게의 모든 가게이미지', - }) + @Query( + () => [ShopImage], // + { description: 'Return: 입력한 가게의 모든 가게이미지' }, + ) fetchShopImagesByShop( @Args('shopId') shopId: string, // ): Promise { return this.shopImagesService.findByShopId({ shopId }); } - @Mutation(() => ShopImage, { - description: 'Return: 신규 생성된 가게이미지 데이터', - }) + @Mutation( + () => ShopImage, // + { description: 'Return: 신규 생성된 가게이미지 데이터' }, + ) async createShopImage( @Args('imageUrl') imageUrl: string, @Args('isThumbnail') isThumbnail: boolean, @Args('shopId') shopId: string, ): Promise { - return await this.shopImagesService.save({ imageUrl, isThumbnail, shopId }); + return await this.shopImagesService.create({ + imageUrl, + isThumbnail, + shopId, + }); } - @Mutation(() => ShopImage, { - description: 'Return: 업데이트된 가게이미지 데이터', - }) + @Mutation( + () => ShopImage, // + { description: 'Return: 업데이트된 가게이미지 데이터' }, + ) async updateShopImage( @Args('updateShopImageInput') updateShopImageInput: UpdateShopImageInput, ): Promise { return await this.shopImagesService.update({ updateShopImageInput }); } - @Mutation(() => Boolean, { - description: 'Return: 가게 이미지 삭제 완료 시, true', - }) + @Mutation( + () => Boolean, // + { description: 'Return: 가게 이미지 삭제 완료 시, true' }, + ) deleteShopImage( @Args('shopImageId') shopImageId: string, // ): Promise { diff --git a/src/apis/shopImages/shopImage.service.ts b/src/apis/shopImages/shopImage.service.ts index cff94d0..67c9508 100644 --- a/src/apis/shopImages/shopImage.service.ts +++ b/src/apis/shopImages/shopImage.service.ts @@ -1,7 +1,6 @@ import { ConflictException, Injectable, - NotFoundException, UnprocessableEntityException, } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; @@ -24,7 +23,6 @@ export class ShopImagesService { private readonly shopsService: ShopsService, ) {} - // 가게ID로 썸네일 찾기 async findThumbnailByShopId({ shopId, }: IShopImagesServiceFindThumbnail): Promise { @@ -44,7 +42,6 @@ export class ShopImagesService { }); } - // 가게ID로 해당 이미지 찾기 async findByShopId({ shopId, }: IShopImagesServiceFindByShopId): Promise { @@ -61,8 +58,7 @@ export class ShopImagesService { }); } - // DB테이블에 신규 이미지 저장 - async save({ + async create({ imageUrl, isThumbnail, shopId, @@ -81,7 +77,6 @@ export class ShopImagesService { }); } - // DB테이블에서 이미지 업데이트 async update({ updateShopImageInput, }: IShopImagesServiceUpdate): Promise { @@ -90,14 +85,10 @@ export class ShopImagesService { imageUrl: updateShopImageInput.imageUrl, }); return await this.shopImageRepository.save({ - id: updateShopImageInput.id, - imageUrl: updateShopImageInput.imageUrl, - isThumbnail: updateShopImageInput.isThumbnail, - shop: { id: updateShopImageInput.shopId }, + ...updateShopImageInput, }); } - // DB테이블에서 이미지 삭제 async delete({ shopImageId }: IShopImagesServiceDelete): Promise { const checkImage = await this.shopImageRepository.findOne({ where: { id: shopImageId }, @@ -108,12 +99,10 @@ export class ShopImagesService { `가게이미지ID가 ${shopImageId}인 이미지를 찾을 수 없습니다`, ); } - console.log('찾았음'); const result = await this.shopImageRepository.delete({ id: shopImageId, }); - console.log('✨✨✨ 삭제 완료 ✨✨✨'); return result.affected ? true : false; } From a4682aa9f741534ee13f5154c6a4d926445f1d89 Mon Sep 17 00:00:00 2001 From: Jjoobob123 <273hur4747@gmail.com> Date: Tue, 4 Apr 2023 10:15:13 +0900 Subject: [PATCH 03/10] =?UTF-8?q?chore:=20shop=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shopImages/dto/save-shopImage.input.ts | 16 ---- src/apis/shops/shops.resolver.ts | 95 ++++++++----------- src/apis/shops/shops.service.ts | 85 ----------------- 3 files changed, 41 insertions(+), 155 deletions(-) delete mode 100644 src/apis/shopImages/dto/save-shopImage.input.ts diff --git a/src/apis/shopImages/dto/save-shopImage.input.ts b/src/apis/shopImages/dto/save-shopImage.input.ts deleted file mode 100644 index bb19ab4..0000000 --- a/src/apis/shopImages/dto/save-shopImage.input.ts +++ /dev/null @@ -1,16 +0,0 @@ -// import { Field, InputType } from '@nestjs/graphql'; - -// @InputType() -// export class SaveShopImageInput { -// @Field(() => String) -// imageUrl: string; - -// @Field(() => Boolean) -// isThumbnail: boolean; - -// @Field(() => String) -// shopId: string; -// } - -// service.ts의 로직에서 가독성 향상을 위해 input 파일 대신 서비스에서 직접 정의함 -// 인자가 3개밖에 없어서. diff --git a/src/apis/shops/shops.resolver.ts b/src/apis/shops/shops.resolver.ts index 11f09a5..c910db3 100644 --- a/src/apis/shops/shops.resolver.ts +++ b/src/apis/shops/shops.resolver.ts @@ -1,10 +1,7 @@ import { ElasticsearchService } from '@nestjs/elasticsearch'; import { Args, Mutation, Resolver, Query } from '@nestjs/graphql'; import { CreateShopInput } from './dto/create-shop.input'; -import { - AutocompleteShopsOutput, - ReturnShopOutput, -} from './dto/return-shop.output'; +import { AutocompleteShopsOutput } from './dto/return-shop.output'; import { UpdateShopInput } from './dto/update-shop.input'; import { Shop } from './entities/shop.entity'; import { ShopsService } from './shops.service'; @@ -16,11 +13,14 @@ export class ShopsResolver { private readonly elasticsearchService: ElasticsearchService, // ) {} - @Query(() => [AutocompleteShopsOutput], { - nullable: true, - description: - 'Return : 검색값(주소: 구, 동 검색 가능)을 포함한 데이터 배열(리뷰 점수 높은 순 정렬). 주소를 포함하는 데이터가 없는 경우 null.', - }) + @Query( + () => [AutocompleteShopsOutput], // + { + nullable: true, + description: + 'Return : 검색값(주소: 구, 동 검색 가능)을 포함한 데이터 배열(리뷰 점수 높은 순 정렬). 주소를 포함하는 데이터가 없는 경우 null.', + }, + ) async autocompleteShops( @Args({ name: 'search', @@ -46,10 +46,13 @@ export class ShopsResolver { }); } - @Query(() => [Shop], { - description: - 'Return : DB에 등록된 가게 중 검색값을 포함한 데이터(검색값이 Null인 경우 모든 가게). 이미지는 썸네일만 불러오며, 등록된 이미지가 있더라도 썸네일로 지정한 이미지가 없는 경우 Null(빈 배열)', - }) + @Query( + () => [Shop], // + { + description: + 'Return : DB에 등록된 가게 중 검색값을 포함한 데이터(검색값이 Null인 경우 모든 가게). 이미지는 썸네일만 불러오며, 등록된 이미지가 있더라도 썸네일로 지정한 이미지가 없는 경우 Null(빈 배열)', + }, + ) async fetchShops( @Args('page') page: number, @Args('count') count: number, @@ -57,28 +60,37 @@ export class ShopsResolver { return this.shopsService.findAll({ page, count }); } - @Query(() => Shop, { - description: - 'Return : 입력한 shopId와 일치하는 가게 데이터. 리뷰 작성 권한 확인 안 해줌 ', - }) + @Query( + () => Shop, // + { + description: + 'Return : 입력한 shopId와 일치하는 가게 데이터. 리뷰 작성 권한 확인 안 해줌 ', + }, + ) async fetchShop( @Args('shopId') shopId: string, // ): Promise { return this.shopsService.findById({ shopId }); } - @Mutation(() => Shop, { - description: 'Return : 신규 가게 데이터', - }) + @Mutation( + () => Shop, // + { + description: 'Return : 신규 가게 데이터', + }, + ) createShop( @Args('createShopInput') createShopInput: CreateShopInput, ): Promise { return this.shopsService.create({ createShopInput }); } - @Mutation(() => Shop, { - description: 'Return : 수정 후 가게 데이터', - }) + @Mutation( + () => Shop, // + { + description: 'Return : 수정 후 가게 데이터', + }, + ) updateShop( @Args('shopId') shopId: string, @Args('updateShopInput') updateShopInput: UpdateShopInput, @@ -86,40 +98,15 @@ export class ShopsResolver { return this.shopsService.update({ shopId, updateShopInput }); } - //가게 삭제 - @Mutation(() => Boolean, { - description: 'Return : 가게 정보 삭제 완료 시 true', - }) + @Mutation( + () => Boolean, // + { + description: 'Return : 가게 정보 삭제 완료 시 true', + }, + ) deleteShop( @Args('shopId') shopId: string, // ): Promise { return this.shopsService.delete({ shopId }); } - - // // <--- 기능 필요하면 주석 해제 ---> - // //삭제된 가게 리스트 불러오기 - // @Query(() => [Shop], { - // description: 'Return : 모든 삭제된 가게 목록', - // }) - // fetchShopsWithDeleted(): Promise { - // return this.shopsService.findAllDeleted(); - // } - - // @Query(() => Shop, { - // description: 'Return : 삭제된 가게 1개', - // }) - // fetchShopWithDeleted( - // @Args('shopId') shopId: string, // - // ): Promise { - // return this.shopsService.findDeleted({ shopId }); - // } - - // @Mutation(() => Boolean, { - // description: 'Return : 가게 정보 복구 완료 시 true', - // }) - // restoreShop( - // @Args('shopId') shopId: string, // - // ): Promise { - // return this.shopsService.restore({ shopId }); - // } } diff --git a/src/apis/shops/shops.service.ts b/src/apis/shops/shops.service.ts index a97ff27..784e24d 100644 --- a/src/apis/shops/shops.service.ts +++ b/src/apis/shops/shops.service.ts @@ -27,7 +27,6 @@ export class ShopsService { private readonly shopsRepository: Repository, // ) {} - // 리뷰 평점 순으로 검색 결과 반환 sortByAvgStar({ hits: _hits }): AutocompleteShopsOutput[] { if (_hits.length === 0) { return null; @@ -40,7 +39,6 @@ export class ShopsService { return hits; } - // DB의 모든 가게 정보 불러오기 + 페이징 추가 async findAll({ page, count }: IShopsServiceFindAll): Promise { const allShops = await this.shopsRepository.find({ relations: [ @@ -54,9 +52,6 @@ export class ShopsService { take: count, }); - // <---------- 썸네일 이미지 관련 로직 ----------> - // 썸네일 이미지가 있는지 확인 - // 썸네일이 있으면 각 가게의 image = 썸네일 이미지 let checkThumbnail = 0; allShops.forEach((el) => { const idx = el.image.findIndex((el) => el.isThumbnail === true); @@ -66,13 +61,10 @@ export class ShopsService { } }); - // 썸네일 이미지가 없으면 각 가게의 image = null if (checkThumbnail < 0) { allShops.forEach((el) => (el.image = null)); } - // <---------- 별점 관련 로직 ----------> - // 별점평균이 Null인 경우, 리턴 타입이 number 이므로 0으로 변환하기 allShops.forEach((el) => { el.averageStar === null ? (el.averageStar = 0) @@ -90,7 +82,6 @@ export class ShopsService { ); } - // 가게 데이터 찾기 async findById({ shopId }: IShopsServiceFindById): Promise { const myShop = await this.shopsRepository.findOne({ where: { id: shopId }, @@ -126,7 +117,6 @@ export class ShopsService { }; } - // 가게 신규 생성 async create({ createShopInput }: IShopsServiceCreate): Promise { const { address } = createShopInput; const checkShop = await this.shopsRepository.findOne({ @@ -139,11 +129,9 @@ export class ShopsService { ); } - // 지역구를 지역코드로 변환하기 const district = address.split(' ')[1]; const code = districtCode({ district }); - // 주소에 대한 위도, 경도 가져오기 const [lat, lng] = await this.getLatLngByAddress({ address }); const result = await this.shopsRepository.save({ @@ -174,7 +162,6 @@ export class ShopsService { } } - // 가게 업데이트 async update({ shopId, updateShopInput, @@ -200,7 +187,6 @@ export class ShopsService { return result; } - // 가게 삭제 async delete({ shopId }: IShopsServiceDelete): Promise { const checkShop = await this.shopsRepository.findOne({ where: { id: shopId }, @@ -216,75 +202,4 @@ export class ShopsService { return result.affected ? true : false; } - - // // <--- 기능 필요하면 주석 해제 ---> - // // 삭제된 가게 리스트 불러오기 - // async findAllDeleted(): Promise { - // return await this.shopsRepository.find({ - // withDeleted: true, - // relations: ['reservation'], - // }); - // } - - // // 가게 연락처(phone)로 해당 가게 정보 찾기 - // async findByPhone({ phone }: IShopsServiceFindByPhone): Promise { - // const result = await this.shopsRepository.findOne({ - // where: { phone: phone }, - // relations: ['reservation', 'image', 'review'], - // }); - - // if (!result) { - // throw new UnprocessableEntityException( - // `연락처가 ${phone}인 가게를 찾을 수 없습니다`, - // ); - // } - - // return result; - // } - - // // 가게 주소(address)로 해당 가게 정보 찾기 - // async findByAddress({ address }: IShopsServiceFindByAddress): Promise { - // const result = await this.shopsRepository.findOne({ - // where: { address: address }, - // relations: ['reservation', 'image', 'review'], - // }); - - // if (!result) { - // throw new UnprocessableEntityException( - // `주소가 ${address}인 가게를 찾을 수 없습니다`, - // ); - // } - - // return result; - // } - - // // 삭제된 가게ID로 해당 가게 정보 가져오기 - // async findDeleted({ shopId }: IShopsServiceFindDeleted): Promise { - // const result = await this.shopsRepository.findOne({ - // where: { id: shopId }, - // withDeleted: true, - // // relations: ['reservation'], - // }); - - // if (!result) { - // throw new NotFoundException( - // `삭제된 목록에서 ID가 ${shopId}인 가게를 찾을 수 없습니다`, - // ); - // } - - // return result; - // } - - // // 삭제된 가게 정보 복원 - // async restore({ shopId }: IShopsServiceRestore): Promise { - // const checkDeletedShop = await this.findDeleted({ shopId }); - - // if (!checkDeletedShop) { - // throw new NotFoundException(`ID가 ${shopId}인 가게를 찾을 수 없습니다`); - // } - - // const result = await this.shopsRepository.restore({ id: shopId }); - - // return result.affected ? true : false; - // } } From 937dafca003c224624b4cba74eac6afbcad663ec Mon Sep 17 00:00:00 2001 From: Jjoobob123 <273hur4747@gmail.com> Date: Tue, 4 Apr 2023 12:03:40 +0900 Subject: [PATCH 04/10] =?UTF-8?q?user=20=EC=BD=94=EB=93=9C=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/users/user.resolver.ts | 10 ---------- src/apis/users/user.service.ts | 28 +++------------------------- 2 files changed, 3 insertions(+), 35 deletions(-) diff --git a/src/apis/users/user.resolver.ts b/src/apis/users/user.resolver.ts index 62e929f..b670679 100644 --- a/src/apis/users/user.resolver.ts +++ b/src/apis/users/user.resolver.ts @@ -12,13 +12,11 @@ export class UsersResolver { private readonly usersService: UsersService, // ) {} - // 전체 조회하기 @Query(() => [User], { description: ' Return: 전체 유저 정보 ' }) fetchUsers(): Promise { return this.usersService.findAll(); } - // 하나 조회하기 @Query(() => User, { description: ' Return: 유저 정보 ' }) fetchUser( @Args('userId') userId: string, // @@ -26,7 +24,6 @@ export class UsersResolver { return this.usersService.findOne({ userId }); } - // 삭제된 유저 조회하기 @Query(() => [User]) fetchUserWithDeleted(): Promise { return this.usersService.findAllWithDeleted(); @@ -39,7 +36,6 @@ export class UsersResolver { return this.usersService.duplicationEmail({ email }); } - // 로그인 된 유저 조회하기 (마이페이지가 들어가기 위함) @UseGuards(GqlAuthGuard('access')) @Query(() => User, { description: ' Return : 로그인한 유저, 유저 댕댕이 프로필', @@ -50,7 +46,6 @@ export class UsersResolver { return this.usersService.findUserDog({ email: context.req.user.email }); } - // 회원가입 @Mutation(() => User, { description: ' Return: 유저 회원가입 ' }) createUser( @Args('name') name: string, @@ -66,7 +61,6 @@ export class UsersResolver { }); } - // 회원 수정하기 @UseGuards(GqlAuthGuard('access')) @Mutation(() => User, { description: ' Return: 회원정보 업데이트 ' }) updateUser( @@ -77,7 +71,6 @@ export class UsersResolver { return this.usersService.update({ userId, updateUserInput }); } - // 비밀번호 찾기(초기화하기) @Mutation(() => User, { description: 'Return: 비밀번호 초기화하기(찾기)' }) resetPwd( @Args('email') email: string, // @@ -86,7 +79,6 @@ export class UsersResolver { return this.usersService.resetPassword({ email, newPassword }); } - // 이메일 인증번호 전송 @Mutation(() => String, { description: ' Return: 이메일 인증번호 전송 ' }) getTokenEmail( @Args('email') email: string, // @@ -94,7 +86,6 @@ export class UsersResolver { return this.usersService.sendTokenEmail({ email }); } - // 이메일 인증번호 검증 @Mutation(() => Boolean, { description: 'Return: 인증번호 검증' }) checkValidToken( @Args('email') email: string, // @@ -103,7 +94,6 @@ export class UsersResolver { return this.usersService.checkToken({ email, token }); } - // 유저 삭제하기 @Mutation(() => Boolean, { description: ' Return: 유저 정보 삭제하기 ' }) deleteUser( @Args('userId') userId: string, // diff --git a/src/apis/users/user.service.ts b/src/apis/users/user.service.ts index 5783661..9d665f3 100644 --- a/src/apis/users/user.service.ts +++ b/src/apis/users/user.service.ts @@ -24,7 +24,6 @@ import { IUsersServiceSendEmail, IUsersServiceSendTokenEmail, IUsersServiceUpdate, - IUsersServiceUpdatePwd, } from './interface/users.interface'; import { MailerService } from '@nestjs-modules/mailer'; import { sendTokenTemplate, welcomeTemplate } from 'src/commons/utils/utils'; @@ -40,12 +39,10 @@ export class UsersService { private readonly mailerService: MailerService, ) {} - // 전체 조회하기 async findAll(): Promise { return await this.userRepository.find({}); } - // 하나 조회하기 async findOne({ userId }: IUsersServiceFindOne): Promise { const myUser = await this.userRepository.findOne({ where: { id: userId }, @@ -57,27 +54,23 @@ export class UsersService { return myUser; } - // 중복 계정 체크를 위한 이메일 조회 findOneByEmail({ email }: IUsersServiceFindOneByEmail): Promise { return this.userRepository.findOne({ where: { email } }); } - // 삭제된 유저 조회하기 findAllWithDeleted(): Promise { return this.userRepository.find({ withDeleted: true, }); } - // 이메일 인증번호 전송 async sendTokenEmail({ email, }: IUsersServiceSendTokenEmail): Promise { const token = String(Math.floor(Math.random() * 1000000)).padStart(6, '0'); - // 이메일 정상인지 확인 + this.checkValidationEmail({ email }); - console.log(token); - // 이메일 인증번호 토큰 보내주기. + await this.mailerService.sendMail({ to: email, from: process.env.EMAIL_USER, @@ -96,7 +89,6 @@ export class UsersService { return token; } - // 이메일이 정상인지 확인 checkValidationEmail({ email }: IUsersServiceCheckValidationEmail) { if ( email === undefined || @@ -109,7 +101,6 @@ export class UsersService { } } - // 이메일 중복검사 async duplicationEmail({ email, }: IUsersServiceDuplicationEmail): Promise { @@ -121,24 +112,18 @@ export class UsersService { } } - // 회원가입 async create({ name, // email, password, phone, - }: // image, - IUsersServiceCreate): Promise { - //이메일 정상인지 확인 + }: IUsersServiceCreate): Promise { await this.checkValidationEmail({ email }); - // 비밀번호 암호화해주기 const hasedPassword = await bcrypt.hash(password, 10); - // 이메일 가입환영 템플릿 보내주기 await this.sendEmail({ email, name }); - // 다시 리졸버로 값을 보내준다. return this.userRepository.save({ name, email, @@ -147,16 +132,13 @@ export class UsersService { }); } - // 로그인한 유저와 유저 댕댕이 프로필 async findUserDog({ email }: IUsersServiceFindUserDog): Promise { const result = await this.userRepository.findOne({ where: { email }, - // relations: {dog:true}, }); return result; } - // 가입환영 템플릿 만들어주기 async sendEmail({ email, name }: IUsersServiceSendEmail) { const EMAIL_USER = process.env.EMAIL_USER; @@ -175,7 +157,6 @@ export class UsersService { return true; } - // 회원 수정하기 async update({ userId, // updateUserInput, @@ -195,7 +176,6 @@ export class UsersService { return result; } - // 비밀번호 찾기(초기화하기) async resetPassword({ email, newPassword, @@ -209,7 +189,6 @@ export class UsersService { return await this.userRepository.save(theUser); } - // 유저 삭제하기(삭제는 나중에) async delete({ userId, // }: IUsersServiceDelete) { @@ -217,7 +196,6 @@ export class UsersService { return result.affected ? true : false; } - // 이메일 인증번호 검증 async checkToken({ email, token }: IUsersServiceCheckToken) { const myToken = await this.cacheManager.get(email); return myToken === token ? true : false; From db545e4296302e6406660bff121ecb067ffb69bd Mon Sep 17 00:00:00 2001 From: cabbage556 Date: Tue, 4 Apr 2023 15:40:21 +0900 Subject: [PATCH 05/10] =?UTF-8?q?release:=20logstash=20schedule=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 30분 -> 5분 release-#232 --- cloudbuild.yaml | 2 +- docker-compose.prod.yaml | 2 +- elk/logstash/logstash.prod.conf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 4314931..8f9308c 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -26,7 +26,7 @@ steps: - set - image - deployment/groomeong-logstash - - logstash-sha256-1=asia.gcr.io/project-groomeong/logstash:1.2 + - logstash-sha256-1=asia.gcr.io/project-groomeong/logstash:1.3 env: - CLOUDSDK_COMPUTE_ZONE=asia-northeast3 - CLOUDSDK_CONTAINER_CLUSTER=autopilot-cluster-5 diff --git a/docker-compose.prod.yaml b/docker-compose.prod.yaml index 0b9c4ad..55f97cd 100644 --- a/docker-compose.prod.yaml +++ b/docker-compose.prod.yaml @@ -9,7 +9,7 @@ services: dockerfile: Dockerfile.prod logstash: - image: asia.gcr.io/project-groomeong/logstash:1.2 + image: asia.gcr.io/project-groomeong/logstash:1.3 platform: linux/x86_64 build: context: . diff --git a/elk/logstash/logstash.prod.conf b/elk/logstash/logstash.prod.conf index 84adb20..f850e4f 100644 --- a/elk/logstash/logstash.prod.conf +++ b/elk/logstash/logstash.prod.conf @@ -5,7 +5,7 @@ input { jdbc_connection_string => "jdbc:mysql://10.42.208.3:3306/prod" # jdbc:mysql://SQL인스턴스비공개IP주소:포트번호/db이름 jdbc_user => "root" jdbc_password => "root" - schedule => "*/30 * * * *" + schedule => "*/5 * * * *" use_column_value => true tracking_column => "updatedat" tracking_column_type => "numeric" From f46735a8c569bbb9b5472cae62246533bcafc8f1 Mon Sep 17 00:00:00 2001 From: cabbage556 Date: Tue, 4 Apr 2023 15:57:47 +0900 Subject: [PATCH 06/10] =?UTF-8?q?release:=20=EC=84=9C=EB=B2=84=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC=20=EB=B2=84=EC=A0=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit release-#233 --- cloudbuild.yaml | 2 +- docker-compose.prod.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 5f2265f..561b8a8 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -16,7 +16,7 @@ steps: - set - image - deployment/groomeong-backend - - backend-sha256-1=asia.gcr.io/project-groomeong/backend:2.5 + - backend-sha256-1=asia.gcr.io/project-groomeong/backend:2.6 env: - CLOUDSDK_COMPUTE_ZONE=asia-northeast3 - CLOUDSDK_CONTAINER_CLUSTER=autopilot-cluster-5 diff --git a/docker-compose.prod.yaml b/docker-compose.prod.yaml index 63031c6..786cd28 100644 --- a/docker-compose.prod.yaml +++ b/docker-compose.prod.yaml @@ -2,7 +2,7 @@ version: '3.7' services: my-backend: - image: asia.gcr.io/project-groomeong/backend:2.5 + image: asia.gcr.io/project-groomeong/backend:2.6 platform: linux/x86_64 build: context: . From dc2a1a7bad3c77f4298e672d6256b797a4cba0d8 Mon Sep 17 00:00:00 2001 From: cabbage556 Date: Wed, 5 Apr 2023 08:15:30 +0900 Subject: [PATCH 07/10] =?UTF-8?q?test:=20updateDog=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updateDog API가 삭제되어 updateDog 테스트코드도 삭제 test-#235 --- src/apis/dogs/__test__/dogs.mocking.ts | 14 ----- src/apis/dogs/__test__/dogs.resolver.spec.ts | 62 +------------------- 2 files changed, 1 insertion(+), 75 deletions(-) diff --git a/src/apis/dogs/__test__/dogs.mocking.ts b/src/apis/dogs/__test__/dogs.mocking.ts index 27ae5af..8061e56 100644 --- a/src/apis/dogs/__test__/dogs.mocking.ts +++ b/src/apis/dogs/__test__/dogs.mocking.ts @@ -26,17 +26,3 @@ export const MOCK_DOG = { deletedAt: null, userId: 'c84fa63e-7a05-4cd5-b015-d4db9a262b18', }; - -export const UPDATED_MOCK_DOG = { - id: '3ce6246c-f37a-426e-b95a-b38ec6d55f4e', - name: '댕댕이', - age: 5, - weight: 10.5, - breed: DOG_TYPE.LARGE, - specifics: '성격이 착해요', - image: - 'https://storage.cloud.google.com/groomeong-storage/origin/dog/a6c16f50-2946-4dfb-9785-a782cea6c570/%03b%EF%BF%BD2.jpeg', - createdAt: '2023-03-21 12:13:02.011088', - deletedAt: null, - userId: 'c84fa63e-7a05-4cd5-b015-d4db9a262b18', -}; diff --git a/src/apis/dogs/__test__/dogs.resolver.spec.ts b/src/apis/dogs/__test__/dogs.resolver.spec.ts index f6634df..24c828b 100644 --- a/src/apis/dogs/__test__/dogs.resolver.spec.ts +++ b/src/apis/dogs/__test__/dogs.resolver.spec.ts @@ -7,11 +7,9 @@ import * as httpMocks from 'node-mocks-http'; import { IContext } from 'src/commons/interface/context'; import { User } from 'src/apis/users/entities/user.entity'; import { CreateDogInput } from '../dto/create-dog.input'; -import { UpdateDogInput } from '../dto/update-dog.input'; -import { MOCK_DOG, MOCK_USER, UPDATED_MOCK_DOG } from './dogs.mocking'; +import { MOCK_DOG, MOCK_USER } from './dogs.mocking'; import { getRepositoryToken } from '@nestjs/typeorm'; import { Dog } from '../entities/dog.entity'; -import { DOG_TYPE } from '../enum/dog-type.enum'; describe('DogsResolver', () => { let dogsResolver: DogsResolver; @@ -146,64 +144,6 @@ describe('DogsResolver', () => { }); }); - describe('updateDog', () => { - const updateDogInput: UpdateDogInput = { - weight: UPDATED_MOCK_DOG.weight, - breed: UPDATED_MOCK_DOG.breed, - }; - - it('업데이트한 강아지 정보를 리턴해야 함', async () => { - mockDogsRepository.findOne.mockImplementation( - (where: { id: string }, relations: { user: true }) => MOCK_DOG, - ); - mockDogsService.findOneById.mockImplementation((id: string) => MOCK_DOG); - mockDogsRepository.save.mockImplementation( - ( - id: string, - name: string, - age: number, - weight: number, - breed: DOG_TYPE, - specifics: string, - image: string, - createdAt: Date, - deleledAt: Date, - userId: string, - ) => UPDATED_MOCK_DOG, - ); - mockDogsService.updateOneById.mockImplementation( - (id: string, updateDogInput: UpdateDogInput) => UPDATED_MOCK_DOG, - ); - - const result = await dogsResolver.updateDog(MOCK_DOG.id, updateDogInput); - expect(result).toEqual(UPDATED_MOCK_DOG); - expect(mockDogsService.updateOneById).toHaveBeenCalledWith({ - id: MOCK_DOG.id, - updateDogInput, - }); - }); - - it('NotFoundException을 던져야 함', () => { - const invalidMockId = '3ce6246c-f37a-426e-b95a-b38ec6d55f4f'; - mockDogsRepository.findOne.mockImplementation( - (where: { id: string }) => null, - ); - - try { - dogsResolver.updateDog(invalidMockId, updateDogInput); - } catch (error) { - expect(error).toBeInstanceOf(NotFoundException); - expect(error.message).toBe( - `id ${invalidMockId}를 갖는 강아지를 찾을 수 없음`, - ); - } - expect(mockDogsService.updateOneById).toHaveBeenCalledWith({ - id: invalidMockId, - updateDogInput, - }); - }); - }); - describe('deleteDog', () => { it('삭제 여부 true를 반환해야 함', async () => { mockDogsRepository.findOne.mockImplementation( From b27942054e12fa0af7c9c2a068d0ce2714a51cc1 Mon Sep 17 00:00:00 2001 From: cabbage556 Date: Wed, 5 Apr 2023 14:36:19 +0900 Subject: [PATCH 08/10] =?UTF-8?q?fix:=20findOne,=20findUserDog=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix-#237 --- src/apis/users/user.service.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/apis/users/user.service.ts b/src/apis/users/user.service.ts index 9d665f3..5099478 100644 --- a/src/apis/users/user.service.ts +++ b/src/apis/users/user.service.ts @@ -46,7 +46,12 @@ export class UsersService { async findOne({ userId }: IUsersServiceFindOne): Promise { const myUser = await this.userRepository.findOne({ where: { id: userId }, - relations: { reservation: true }, + relations: [ + 'reservation', + 'reservation.shop', + 'dogs', + 'reservation.review', + ], }); if (!myUser) { throw new NotFoundException(`ID가 ${userId}인 회원을 찾을 수 없습니다`); @@ -135,6 +140,7 @@ export class UsersService { async findUserDog({ email }: IUsersServiceFindUserDog): Promise { const result = await this.userRepository.findOne({ where: { email }, + relations: ['reservation', 'reservation.shop', 'reservation.review'], }); return result; } From d467400a7d15ebcb79d41df310acaf52fd30edbf Mon Sep 17 00:00:00 2001 From: cabbage556 Date: Wed, 5 Apr 2023 14:40:30 +0900 Subject: [PATCH 09/10] =?UTF-8?q?release:=20=EC=9C=A0=EC=A0=80=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=20findOne,=20fetchUserDog=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=B0=B0=ED=8F=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit release-#239 --- cloudbuild.yaml | 2 +- docker-compose.prod.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cloudbuild.yaml b/cloudbuild.yaml index 561b8a8..3a233a7 100644 --- a/cloudbuild.yaml +++ b/cloudbuild.yaml @@ -16,7 +16,7 @@ steps: - set - image - deployment/groomeong-backend - - backend-sha256-1=asia.gcr.io/project-groomeong/backend:2.6 + - backend-sha256-1=asia.gcr.io/project-groomeong/backend:2.7 env: - CLOUDSDK_COMPUTE_ZONE=asia-northeast3 - CLOUDSDK_CONTAINER_CLUSTER=autopilot-cluster-5 diff --git a/docker-compose.prod.yaml b/docker-compose.prod.yaml index 786cd28..6963a74 100644 --- a/docker-compose.prod.yaml +++ b/docker-compose.prod.yaml @@ -2,7 +2,7 @@ version: '3.7' services: my-backend: - image: asia.gcr.io/project-groomeong/backend:2.6 + image: asia.gcr.io/project-groomeong/backend:2.7 platform: linux/x86_64 build: context: . From af0b0536548db7eb5878dada04de4bcb6e84b1d6 Mon Sep 17 00:00:00 2001 From: cabbage556 Date: Sun, 9 Apr 2023 01:02:28 +0900 Subject: [PATCH 10/10] =?UTF-8?q?readme:=20readme=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit readme-#240 --- README.md | 426 +++++++++++++++++++++++++++--------------------------- 1 file changed, 216 insertions(+), 210 deletions(-) diff --git a/README.md b/README.md index ff7c914..022cf0f 100644 --- a/README.md +++ b/README.md @@ -1,247 +1,253 @@ -# TEAM VIEWPOINT +# 팀 **깍까오독**의 **GROOMEONG** 서비스 소개 페이지입니다. + +# 서비스 기획의도 ![Logo-120-120](https://user-images.githubusercontent.com/120294031/228166925-5d147b8b-6ce2-4b06-a51a-bfb017f5180a.png) -

+1인 가구 증가, 인구 고령화에 따라 반려동물로 강아지를 키우는 사람들이 많아지면서 강아지를 위한 다양한 서비스들이 늘어나고 있습니다. 저희는 강아지를 위한 다양한 서비스 중에서 **강아지 미용샵**에 주목했습니다. 강아지 미용샵 검색 시 소비자가 원하는 **미용샵 정보**가 아닌 광고 사이트가 많아 비공식적인 커뮤니티 사이트에 의지해 미용샵을 찾아야 하는 불편함이 있었습니다. + +따라서 저희는 이런 불편함을 해소하고자 _우리 동네 반려견 미용샵, 한 눈에 볼 수 없을까?_ 기획 의도에 따라 '**GROOMEONG**' 서비스를 계획하고 개발하였습니다. -# GROOMEONG +> '**GROOMEONG**'은 특정 지역의 반려견 미용샵 목록을 조회하고 예약할 수 있는 서비스로, 견주들이 강아지 미용샵을 지금보다 편리하게 이용할 수 있게 하였습니다. -동네 공원을 나가면 강아지 산책하시는 분들이 대다수이고, 반려동물들을 많이 키우는 트랜드에 맞춰서 -강아지 호텔, 강아지 수영장, 강아지 펫샵 ,강아지 미용샵 등등 다양한 서비스들이 늘어나고 있습니다. -강아지 미용샵 검색 시 , 소비자가 원하는 '샵 정보' 보다는 홍보 사이트가 많아 비공식적인 커뮤니티 사이트에 의지해 업체를 찾아야 한다. 그래서 저희가 개발을 한 웹 어플리케이션이 있다!!! -저희 '**GROOMENOG**' 강아지 미용샵을 견주들이 더 편리하게 이용 할 수 있도록 하기 위한 특정 지역들에 반려견 미용업체 목록을 한 번에 볼 수 있는 서비스입니다. 🐶 +
+ +# 팀원 소개 -### 반짝이는 별 같은 댕댕이 🐶🧡 +![백엔드팀원](https://user-images.githubusercontent.com/56855262/230724437-9b2e02e8-0494-4d67-9618-5279f211ad83.png) -반려견의 뷰티를 위한 웹 게더🐶 '**그루멍**' +![프론트엔드팀원](https://user-images.githubusercontent.com/56855262/230724445-95c0345e-ea42-4186-b14d-1fec18b93ca0.png)

-# 팀원 소개 +# 시연 GIF + +## 랜딩 페이지 + +![랜딩페이지](https://user-images.githubusercontent.com/56855262/230727337-ea1b9559-1a25-4f1e-929b-09716419b5be.gif) + +
+ +## 메인 페이지 + +![메인페이지](https://user-images.githubusercontent.com/56855262/230727459-67f873c0-ad23-46d8-be80-0e84fe5a973a.png) + +
+ +## 로그인 & 회원가입 페이지 + +![로그인,회원가입페이지](https://user-images.githubusercontent.com/56855262/230727921-5e6deb4e-bbb3-4e15-848a-0a2a4542383a.gif) + +
+ +## 마이 페이지 + +![마이페이지](https://user-images.githubusercontent.com/56855262/230728141-8543c82e-7304-4c6b-8d84-64c7b966eb67.gif) + +
-| 이름 | 역할 | 담당 부분 | -| ---------- | ------------ | --------- | -| **홍예림** | 팀장, 백엔드 | | -| 김태윤 | 백엔드 | | -| 조주현 | 백엔드 | | -| 허광기 | 프론트엔드 | | -| 길재훈 | 프론트엔드 | | -| 권현재 | 프론트엔드 | | -| 김하은 | 프론트엔드 | | +## 강아지 페이지 + +![강아지페이지](https://user-images.githubusercontent.com/56855262/230728313-65d087c1-8c43-49a2-ba77-b9180120d245.gif) + +
+ +## 지도 페이지 + +![지도페이지](https://user-images.githubusercontent.com/56855262/230729774-d378f2a6-fb21-482e-a8ef-c52ed09c50ef.gif) + +
+ +## 예약 페이지 + +![예약페이지](https://user-images.githubusercontent.com/56855262/230730680-10e4caeb-4747-4b57-b355-66893bfa86c0.gif) + +
+ +## 리뷰 페이지 + +![리뷰페이지](https://user-images.githubusercontent.com/56855262/230731020-bdb3d72d-aa9c-4c25-8aae-ce7a7471140b.gif)

-# 기술 스텍 +# 기술 스택 -![기술스텍](https://user-images.githubusercontent.com/120294031/228167268-0cd1a98d-4568-4dac-ab82-673c94c2b982.png) +![기술스텍](https://user-images.githubusercontent.com/56855262/230725266-4e02ddeb-fbc5-4979-8495-14fe02bb7f21.png)

-# Flow Chart +# 플로우 차트 -![DBflowChart](https://user-images.githubusercontent.com/120294031/228220540-12e5d386-68f5-46b0-bce8-3d92ba8d380a.png) +![flowChart](https://user-images.githubusercontent.com/56855262/230725563-e0a9ee53-c547-41e6-8320-c72a8852d929.png)

# ERD -![ERD](https://user-images.githubusercontent.com/120294031/228168194-e25c95fa-189b-406f-9a65-962326300e0d.png) +![ERD](https://user-images.githubusercontent.com/56855262/230725343-8f257f73-5325-4185-9d09-ff847031d0fd.png)

# API 명세서 -기능명세서 +![API 명세서](https://user-images.githubusercontent.com/56855262/230725468-0d128b66-54c1-4c2c-a173-f32e65f5b3cb.png)

# 서버 폴더 구조 -``` +```md . └── 📂 backend / - ├── 📂 .vscode/ - │ └── 🧸 settings.json - ├── 📂 elk/ - │ └── 📂 logstash/ - │ ├── 🧸 auto-template copy.json - │ ├── 🧸 auto-template.json - │ ├── 🧸 auto-template2.json - │ ├── ⚙️ logstash.conf - │ └── 🫕 mysql-connector-java-8.0.28.jar - ├── 📂 src/ - │ ├── 📂 apis/ - │ │ ├── 📂 auth/ - │ │ │ ├── 📂 __test__/ - │ │ │ │ ├── 📝 auth.mocking.dummy.ts - │ │ │ │ ├── 🛎️ auth.resolver.spec.ts - │ │ │ │ └── 🛎️ auth.service.spec.ts - │ │ │ ├── 📂 guards/ - │ │ │ │ ├── 📝 dynamic-auth.guard-02.ts - │ │ │ │ └── 🔐 gql-auth.guard.ts - │ │ │ ├── 📂 interface/ - │ │ │ │ └── 📝 auth.interface.ts - │ │ │ ├── 📂 streategies/ - │ │ │ │ ├── 📝 jwt-access.strategy.ts - │ │ │ │ ├── 📝 jwt-refresh.stratehy.ts - │ │ │ │ ├── 📝 jwt-social-google.strategy.ts - │ │ │ │ └── 📝 jwt-social-kakao.strategy.ts - │ │ │ ├── 📝 auth.controller.ts - │ │ │ ├── 📝 auth.module.ts - │ │ │ ├── 📝 auth.resovler.ts - │ │ │ └── 📝 auth.service.ts - │ │ ├── 📂 dogs/ - │ │ │ ├── 📂 __test/ - │ │ │ │ └── 🛎️ dogs.resolver.spec.ts - │ │ │ ├── 📂 dto/ - │ │ │ │ ├── 📝 create-dog.input - │ │ │ │ └── 📝 update-dog.input - │ │ │ ├── 📂 entities/ - │ │ │ │ └── 📝 dog.entity.ts - │ │ │ ├── 📂 enum/ - │ │ │ │ └── 📝 dog-type.enum.ts - │ │ │ ├── 📂 interfaces/ - │ │ │ │ └── 📝 dogs-service.interface.ts - │ │ │ ├── 📝 dogs.module.ts - │ │ │ ├── 📝 dogs.resolver.ts - │ │ │ └── 📝 dogs.service.ts - │ │ ├── 📂 files/ - │ │ │ ├── 📂 interfaces/ - │ │ │ │ └── 📝 files-service.interface - │ │ │ ├── 📝 files.module.ts - │ │ │ ├── 📝 files.resolver.ts - │ │ │ └── 📝 files.service.ts - │ │ ├── 📂 reservations/ - │ │ │ ├── 📂 dto/ - │ │ │ │ └── 📝 create-reservation.input.ts - │ │ │ ├── 📂 entities/ - │ │ │ │ └── 📝 reservation.entity.ts - │ │ │ ├── 📂 interfaces - │ │ │ ├── 📝 reservation.module.ts - │ │ │ ├── 📝 reservation.resolver.ts - │ │ │ └── 📝 reservation.service.ts - │ │ ├── 📂 reviews/ - │ │ │ ├── 📂 dto/ - │ │ │ │ └── 📝 create-review.input.ts - │ │ │ ├── 📂 entities/ - │ │ │ │ └── 📝 review.entity.ts - │ │ │ ├── 📂 interfaces/ - │ │ │ │ └── 📝 reviews-service.interface.ts - │ │ │ ├── 📝 reviews.module.ts - │ │ │ ├── 📝 reviews.resolver.ts - │ │ │ └── 📝 reviews.service.ts - │ │ ├── 📂 shop-review/ - │ │ │ ├── 📂 dto/ - │ │ │ │ └── 📝 return-shop-review.output - │ │ │ ├── 📝 shop-review.module.ts - │ │ │ ├── 📝 shop-review.resolver.ts - │ │ │ └── 📝 shop-review.service.ts - │ │ ├── 📂 shopImages/ - │ │ │ ├── 📂 __test__/ - │ │ │ │ ├── 📝 shopImage.moking.dummy.ts - │ │ │ │ ├── 🛎️ shopImage.resolver.spec.ts - │ │ │ │ └── 🛎️ shopImage.service.spec.ts - │ │ │ ├── 📂 dto/ - │ │ │ │ ├── 📝 save-shopImage.input.ts - │ │ │ │ └── 📝 update-shopImage.input.ts - │ │ │ ├── 📂 entities/ - │ │ │ │ └── 📝 shopImages.entity.ts - │ │ │ ├── 📂 interfaces/ - │ │ │ │ └── 📝 shopImages-service.interface.ts - │ │ │ ├── 📝 shopImage.module.ts - │ │ │ ├── 📝 shopImage.resolver.ts - │ │ │ └── 📝 shopImage.service.ts - │ │ ├── 📂 shops/ - │ │ │ ├── 📂 __test__/ - │ │ │ │ └── 🛎️ shops.service.spec.ts - │ │ │ ├── 📂 dto/ - │ │ │ │ ├── 📝 create-shop.input.ts - │ │ │ │ ├── 📝 return-shop.output.ts - │ │ │ │ └── 📝 update-shop.input.ts - │ │ │ ├── 📂 entities/ - │ │ │ │ └── 📝 shop.entity.ts - │ │ │ ├── 📂 interfaces/ - │ │ │ │ └── 📝 shops-service.interface.ts - │ │ │ ├── 📝 shops.module.ts - │ │ │ ├── 📝 shops.resolver.ts - │ │ │ └── 📝 shops.service.ts - │ │ └── 📂 users/ - │ │ ├── 📂 __test__/ - │ │ │ └── 🛎️ users.service.spec.ts - │ │ ├── 📂 dto/ - │ │ │ ├── 📝 create-users.input.ts - │ │ │ └── 📝 update-users.input.ts - │ │ ├── 📂 entities/ - │ │ │ └── 📝 user.entity.ts - │ │ ├── 📂 interface/ - │ │ │ └── 📝 users.interface.ts - │ │ ├── 📝 user.module.ts - │ │ ├── 📝 user.resolver.ts - │ │ └── 📝 user.service.ts - │ ├── 📂 commons/ - │ │ ├── 📂 filter/ - │ │ │ └── 📝 http-exception.filter.ts - │ │ ├── 📂 interface/ - │ │ │ └── 📝 context.ts - │ │ └── 📂 utils/ - │ │ ├── 📝 addresscode.ts - │ │ └── 📝 utils.ts - │ ├── 📂 test/ - │ │ ├── 🛎️ app.e2e-spec.ts - │ │ └── 🧸 jest-e2e.json - │ ├── 📝 app.controller.ts - │ ├── 📝 app.module.ts - │ └── 📝 main.ts - ├── 🐳 .dockerignore - ├── 📝 .env.docker - ├── 📝 .env.prod - ├── 📝 .eslintrc.js - ├── 📝 .gitignore - ├── 📝 .prettierrc - ├── 🐳 docker-compose.prod.yaml - ├── 🐳 docker-compose.yaml - ├── 🐳 Dockerfile - ├── 🐳 Dockerfile.elasticsearch - ├── 🐳 Dockerfile.logstash - ├── 🐳 Dockerfile.prod - ├── 🧸 nest-cli.json - ├── 🧸 package.json - ├── 🧸 project-groomeong-34231f48bd14.json - ├── 📝 README.md - ├── 🧸 settings.json - ├── 🧸 tsconfig.build.json - ├── 🧸 tsconfig.json - ├── 📝 yarn-error.log - └── 📝 yarn.lock -``` - -

- -# .env - -``` -DATABASE_TYPE -DATABASE_HOST -DATABASE_PORT -DATABASE_USERNAME -DATABASE_PASSWORD -DATABASE_DATABASE -JWT_ACCESS_KEY -JWT_REFRESH_KEY -GOOGLE_CLIENT_ID -GOOGLE_CLIENT_SECRET -KAKAO_CLIENT_ID -KAKAO_CLIENT_SECRET -EMAIL_USER -EMAIL_PASS -EMAIL_HOST -EMAIL_FROM_USER_NAME -GCP_BUCKET_NAME -GCP_PROJECT_ID -GCP_KEY_FILENAME -GOOGLE_MAP_API_KEY -REDIS_URL -OPENSEARCH_ID -OPENSEARCH_PWD - +├── 📂 .vscode/ +│ └── 🧸 settings.json +├── 📂 elk/ +│ └── 📂 logstash/ +│ ├── 🧸 auto-template.json +│ ├── ⚙️ logstash.conf +│ └── 🫕 mysql-connector-java-8.0.28.jar +├── 📂 src/ +│ ├── 📂 apis/ +│ │ ├── 📂 auth/ +│ │ │ ├── 📂 **test**/ +│ │ │ │ ├── 📝 auth.mocking.dummy.ts +│ │ │ │ ├── 🛎️ auth.resolver.spec.ts +│ │ │ │ └── 🛎️ auth.service.spec.ts +│ │ │ ├── 📂 guards/ +│ │ │ │ ├── 📝 dynamic-auth.guard-02.ts +│ │ │ │ └── 🔐 gql-auth.guard.ts +│ │ │ ├── 📂 interface/ +│ │ │ │ └── 📝 auth.interface.ts +│ │ │ ├── 📂 streategies/ +│ │ │ │ ├── 📝 jwt-access.strategy.ts +│ │ │ │ ├── 📝 jwt-refresh.stratehy.ts +│ │ │ │ ├── 📝 jwt-social-google.strategy.ts +│ │ │ │ └── 📝 jwt-social-kakao.strategy.ts +│ │ │ ├── 📝 auth.controller.ts +│ │ │ ├── 📝 auth.module.ts +│ │ │ ├── 📝 auth.resovler.ts +│ │ │ └── 📝 auth.service.ts +│ │ ├── 📂 dogs/ +│ │ │ ├── 📂 **test/ +│ │ │ │ └── 🛎️ dogs.resolver.spec.ts +│ │ │ ├── 📂 dto/ +│ │ │ │ ├── 📝 create-dog.input +│ │ │ │ └── 📝 update-dog.input +│ │ │ ├── 📂 entities/ +│ │ │ │ └── 📝 dog.entity.ts +│ │ │ ├── 📂 enum/ +│ │ │ │ └── 📝 dog-type.enum.ts +│ │ │ ├── 📂 interfaces/ +│ │ │ │ └── 📝 dogs-service.interface.ts +│ │ │ ├── 📝 dogs.module.ts +│ │ │ ├── 📝 dogs.resolver.ts +│ │ │ └── 📝 dogs.service.ts +│ │ ├── 📂 files/ +│ │ │ ├── 📂 interfaces/ +│ │ │ │ └── 📝 files-service.interface +│ │ │ ├── 📝 files.module.ts +│ │ │ ├── 📝 files.resolver.ts +│ │ │ └── 📝 files.service.ts +│ │ ├── 📂 reservations/ +│ │ │ ├── 📂 dto/ +│ │ │ │ └── 📝 create-reservation.input.ts +│ │ │ ├── 📂 entities/ +│ │ │ │ └── 📝 reservation.entity.ts +│ │ │ ├── 📂 interfaces +│ │ │ ├── 📝 reservation.module.ts +│ │ │ ├── 📝 reservation.resolver.ts +│ │ │ └── 📝 reservation.service.ts +│ │ ├── 📂 reviews/ +│ │ │ ├── 📂 dto/ +│ │ │ │ └── 📝 create-review.input.ts +│ │ │ ├── 📂 entities/ +│ │ │ │ └── 📝 review.entity.ts +│ │ │ ├── 📂 interfaces/ +│ │ │ │ └── 📝 reviews-service.interface.ts +│ │ │ ├── 📝 reviews.module.ts +│ │ │ ├── 📝 reviews.resolver.ts +│ │ │ └── 📝 reviews.service.ts +│ │ ├── 📂 shop-review/ +│ │ │ ├── 📂 dto/ +│ │ │ │ └── 📝 return-shop-review.output +│ │ │ ├── 📝 shop-review.module.ts +│ │ │ ├── 📝 shop-review.resolver.ts +│ │ │ └── 📝 shop-review.service.ts +│ │ ├── 📂 shopImages/ +│ │ │ ├── 📂 **test**/ +│ │ │ │ ├── 📝 shopImage.moking.dummy.ts +│ │ │ │ ├── 🛎️ shopImage.resolver.spec.ts +│ │ │ │ └── 🛎️ shopImage.service.spec.ts +│ │ │ ├── 📂 dto/ +│ │ │ │ ├── 📝 save-shopImage.input.ts +│ │ │ │ └── 📝 update-shopImage.input.ts +│ │ │ ├── 📂 entities/ +│ │ │ │ └── 📝 shopImages.entity.ts +│ │ │ ├── 📂 interfaces/ +│ │ │ │ └── 📝 shopImages-service.interface.ts +│ │ │ ├── 📝 shopImage.module.ts +│ │ │ ├── 📝 shopImage.resolver.ts +│ │ │ └── 📝 shopImage.service.ts +│ │ ├── 📂 shops/ +│ │ │ ├── 📂 **test**/ +│ │ │ │ └── 🛎️ shops.service.spec.ts +│ │ │ ├── 📂 dto/ +│ │ │ │ ├── 📝 create-shop.input.ts +│ │ │ │ ├── 📝 return-shop.output.ts +│ │ │ │ └── 📝 update-shop.input.ts +│ │ │ ├── 📂 entities/ +│ │ │ │ └── 📝 shop.entity.ts +│ │ │ ├── 📂 interfaces/ +│ │ │ │ └── 📝 shops-service.interface.ts +│ │ │ ├── 📝 shops.module.ts +│ │ │ ├── 📝 shops.resolver.ts +│ │ │ └── 📝 shops.service.ts +│ │ └── 📂 users/ +│ │ ├── 📂 **test\_\_/ +│ │ │ └── 🛎️ users.service.spec.ts +│ │ ├── 📂 dto/ +│ │ │ ├── 📝 create-users.input.ts +│ │ │ └── 📝 update-users.input.ts +│ │ ├── 📂 entities/ +│ │ │ └── 📝 user.entity.ts +│ │ ├── 📂 interface/ +│ │ │ └── 📝 users.interface.ts +│ │ ├── 📝 user.module.ts +│ │ ├── 📝 user.resolver.ts +│ │ └── 📝 user.service.ts +│ ├── 📂 commons/ +│ │ ├── 📂 filter/ +│ │ │ └── 📝 http-exception.filter.ts +│ │ ├── 📂 interface/ +│ │ │ └── 📝 context.ts +│ │ └── 📂 utils/ +│ │ ├── 📝 addresscode.ts +│ │ └── 📝 utils.ts +│ ├── 📂 test/ +│ │ ├── 🛎️ app.e2e-spec.ts +│ │ └── 🧸 jest-e2e.json +│ ├── 📝 app.controller.ts +│ ├── 📝 app.module.ts +│ └── 📝 main.ts +├── 🐳 .dockerignore +├── 📝 .env.docker +├── 📝 .env.prod +├── 📝 .eslintrc.js +├── 📝 .gitignore +├── 📝 .prettierrc +├── 🐳 docker-compose.prod.yaml +├── 🐳 docker-compose.yaml +├── 🐳 Dockerfile +├── 🐳 Dockerfile.elasticsearch +├── 🐳 Dockerfile.logstash +├── 🐳 Dockerfile.prod +├── 🧸 nest-cli.json +├── 🧸 package.json +├── 🧸 project-groomeong-34231f48bd14.json +├── 📝 README.md +├── 🧸 settings.json +├── 🧸 tsconfig.build.json +├── 🧸 tsconfig.json +├── 📝 yarn-error.log +└── 📝 yarn.lock ```