{"id":28002910,"url":"https://github.com/narcisource/pre-onboarding-challenge-be-31","last_synced_at":"2025-05-09T01:44:20.544Z","repository":{"id":291794986,"uuid":"978812149","full_name":"NarciSource/Pre-Onboarding-Challenge-BE-31","owner":"NarciSource","description":"CQRS 시스템 설계/구축 챌린지 - 원티드 프리온보딩 챌린지 백엔드 31차 ","archived":false,"fork":false,"pushed_at":"2025-05-06T15:00:53.000Z","size":1556,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-06T15:55:47.045Z","etag":null,"topics":["nestjs"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NarciSource.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-06T14:44:12.000Z","updated_at":"2025-05-06T15:35:33.000Z","dependencies_parsed_at":"2025-05-06T15:56:03.523Z","dependency_job_id":"e4b4629d-c5c5-44dd-9d0c-e1fad942dc25","html_url":"https://github.com/NarciSource/Pre-Onboarding-Challenge-BE-31","commit_stats":null,"previous_names":["narcisource/pre-onboarding-challenge-be-31"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NarciSource%2FPre-Onboarding-Challenge-BE-31","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NarciSource%2FPre-Onboarding-Challenge-BE-31/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NarciSource%2FPre-Onboarding-Challenge-BE-31/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NarciSource%2FPre-Onboarding-Challenge-BE-31/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NarciSource","download_url":"https://codeload.github.com/NarciSource/Pre-Onboarding-Challenge-BE-31/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253176444,"owners_count":21866141,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["nestjs"],"created_at":"2025-05-09T01:44:19.929Z","updated_at":"2025-05-09T01:44:20.534Z","avatar_url":"https://github.com/NarciSource.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CQRS 시스템 설계/구축 챌린지\r\n\r\n\u003e 원티드 프리온보딩 챌린지 백엔드 31차\r\n\r\n[![GitHub release](https://img.shields.io/github/v/release/narcisource/wanted-preonboarding-challenge-backend-31)](https://github.com/narcisource/wanted-preonboarding-challenge-backend-31/releases) [![openapi](https://github.com/narcisource/wanted-preonboarding-challenge-backend-31/actions/workflows/deploy-openapi.yml/badge.svg)](https://github.com/narcisource/wanted-preonboarding-challenge-backend-31/actions/workflows/deploy-openapi.yml) [![test](https://github.com/narcisource/wanted-preonboarding-challenge-backend-31/actions/workflows/deploy-test-report.yml/badge.svg)](https://github.com/narcisource/wanted-preonboarding-challenge-backend-31/actions/workflows/deploy-test-report.yml)\r\n\r\n## 기술 스택\r\n\r\n[![NestJS](https://img.shields.io/badge/NestJS-E0234E?style=flat\u0026logo=nestjs\u0026logoColor=white)](https://nestjs.com/) [![NodeJS](https://img.shields.io/badge/Node.js-6DA55F?style=flat\u0026logo=node.js\u0026logoColor=white)](https://nodejs.org/ko) [![TypesSript](https://img.shields.io/badge/TypesSript-3178C6?style=flat\u0026logo=typescript\u0026logoColor=white)](https://www.typescriptlang.org/)  \r\n[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1?style=flat\u0026logo=postgresql\u0026logoColor=white)](https://www.postgresql.org/) [![TypeORM](https://img.shields.io/badge/TypeORM-FE0803?style=flat\u0026logo=typeorm\u0026logoColor=white)](https://typeorm.io/)  \r\n[![Codecov](https://img.shields.io/badge/Codecov-F01F7A?style=flat\u0026logo=codecov\u0026logoColor=white)](https://about.codecov.io/) [![Jest](https://img.shields.io/badge/Jest-C21325?style=flat\u0026logo=jest\u0026logoColor=white)](https://jestjs.io/) [![Swagger](https://img.shields.io/badge/Swagger-85EA2D?style=flat\u0026logo=swagger\u0026logoColor=black)](https://swagger.io/)  \r\n[![Github Actions](https://img.shields.io/badge/Github_Actions-2088FF?style=flat\u0026logo=githubactions\u0026logoColor=white)](https://github.com/features/actions) [![ESLint](https://img.shields.io/badge/ESLint-4B32C3?style=flat\u0026logo=eslint\u0026logoColor=white)](https://eslint.org/) [![Prettier](https://img.shields.io/badge/Prettier-F7B93E?style=flat\u0026logo=prettier\u0026logoColor=black)](https://prettier.io/)  \r\n[![Docker Compose](https://img.shields.io/badge/Docker_Compose-2AB4FF.svg?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MjMgNjY1Ij4KICA8cGF0aCBmaWxsPSIjZmNmY2ZjIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00MTggMWMtNiAxLTkgMy0xMyA4LTQgMy00IDMtMTAgMS0xMi02LTYwIDAtNjYgOC01IDYtMTEgNDQtOCA1MGwyMyAxN2M3IDQgNyA2IDIgNy0yMyAzLTM3IDI5LTI5IDUyIDMgOSAzIDktMTAgNi0xOS01LTI0LTYtNDUtNS00NyAwLTg2IDE4LTEwOSA1MGExMzUgMTM1IDAgMCAwLTI0IDY0Yy0zIDI4IDIgNDggMTcgNzJsMjIgMjdjNDAgNDQgNDEgNjYgMyA5MS00NSAzMC0xMDQgMTktMTA2LTIwLTEtMTYgNC0yOSAxNy01MiAxMy0yNCAxNC0zMyAzLTUybDEzLThjMjQtMTIgMjItOSAyMy0zNCAwLTIyIDItMjAtMjMtMzAtMTgtNi0yMC02LTQwLTEtMjggOS00MCAxNC00MSAxOCAwIDItMSAzLTIgMy03IDAtMTQgMTItMTUgMjUtMSAyMSA2IDI5IDMwIDM2IDMwIDkgMzUgMjQgMTkgNDktMzYgNTMtMzIgMTAyIDExIDEyMSAzNSAxNiA3NCAxMyAxMTktOWwxMS01IDMgMzJjMCAzNC00MCAzOC04OSA4bC0xNi0xMGMtNTEtMjktMTAyIDI0LTY2IDcwIDE1IDIwIDQyIDIxIDQ2IDIgMi04IDAtMTEtMTAtMTktMTYtMTItMTctMjQtMi0yNyA1LTEgMjYgOCAyOCAxMmwzNCAyOSAyMCAxMiAyMCA4YzM2IDEzIDgyLTE1IDgyLTUwIDAtMTAgMC0xMCA2LTUgMTAgMTAgMTggMTYgMjMgMTkgNiAzIDYgNCAxIDctNSAyLTUgMi01IDctMSA4IDEgMjkgNCAzMyA0IDcgNjMgNDYgNjkgNDYgMyAwIDQ4LTI1IDUxLTI5IDItMSAzLTM0IDEtMzZsLTE2LTljLTE2LTgtMTYtOC05LTEwIDE5LTcgMzctMjcgNDMtNDdsNS0xYTE2NSAxNjUgMCAwIDAgNjAtMTNjOSAwIDM0LTIyIDQwLTM0bDQtOGM0LTcgNi0yNiA2LTU2IDAtMjkgMS0yNy0xMC0yOS02LTItOC0zLTEzLTgtMzAtMjktNzktMjMtOTYgMTAtMyA3LTMgNy04IDlzLTYgNS01IDE3djE1YzEgMTQgNCAxNiAzNCAyOGwxMiA2YzcgMyA3IDMgMzAtNyA4LTMgOS0zIDkgMS02IDIyLTY0IDQyLTczIDI0YTg3IDg3IDAgMCAwLTYzLTQyYy04IDAtOCAwIDYtMTFhNzM2IDczNiAwIDAgMCA4NS04OWwzLTVjMTktMzEgMjEtNzMgMy0xMDctNy0xNS0yMy0zNS0zNi00OC0zOS0zNi00Ni00Ny0zOC02MiA0LTggMTUtMTcgMjAtMTVhNDUyIDQ1MiAwIDAgMCA1NS0xMmMxMS00IDEzLTUgMTQtMTAgMC00IDItNyA5LTE0IDI0LTI2LTgtODAtNDMtNzFNMjI4IDMzNGMxIDEgMCAxLTEgMS0yMCAwLTI4IDMyLTEyIDQyIDE3IDkgMzctMyAzNy0yMiAwLTctNy0xNy0xMS0xN3YtMWMzLTIgMC0zLTctNGwtNiAxbTU0IDgtNCAxYy0yMiAzLTI1IDM5LTMgNDQgMjQgNSA0MS0yMSAyNS0zOGwtNS0zdi0zYy0xLTItMTQtMy0xMy0xbS00OSAxMjBjLTYgNy05IDE0LTkgMjQgMCA4IDEgMTIgMyA2IDItMTIgOC0yOCAxMy0zM3YtM2MtMSAwLTQgMi03IDZtOTcgNGMwIDIgMjMgMTcgMjcgMTcgMiAwIDEtMy00LTctOS03LTIzLTEzLTIzLTEwbS01NCA2Yy0yMSA1MSAyOSA5NiA3MyA2NyA4LTYgOC03LTEtOC0zOS0zLTYzLTIzLTY2LTU0LTItMTItMy0xMy02LTUiLz4KPC9zdmc+Cg==\u0026style=flat\u0026logoColor=black)](https://docs.docker.com/compose/) [![Docker](https://img.shields.io/badge/Docker-2496ED?style=flat\u0026logo=Docker\u0026logoColor=white)](https://www.docker.com/)\r\n\r\n## API 명세서\r\n\r\n본 프로젝트의 API 명세서는 GitHub Pages을 통해 Swagger UI로 제공됩니다.\r\n\r\n| [![Swagger](https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/swagger/swagger-original.svg)](https://narcisource.github.io/wanted-preonboarding-challenge-backend-31/) |\r\n| --- |\r\n| \u0026nbsp;\u0026nbsp;\u0026nbsp;[API 명세서 바로가기](https://narcisource.github.io/wanted-preonboarding-challenge-backend-31/)\u0026nbsp;\u0026nbsp;\u0026nbsp; |\r\n\r\n- GitHub Pages에 게시된 Swagger 문서는 **정적 문서용**으로 제공되며,  \r\n  백엔드 서버 및 데이터베이스가 연결되어 있지 않기 때문에 실제 요청은 처리되지 않습니다.\r\n\r\n- API 요청을 정상적으로 테스트하려면,  \r\n  로컬 환경에서 Docker Compose를 사용해 서버와 데이터베이스를 실행한 후 Swagger UI에 접속합니다.\r\n\r\n## 테스트 리포트\r\n\r\n테스트 통과 여부와 커버리지 현황은 시각적으로 제공됩니다.\r\n\r\n| [![Jest](https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/jest/jest-plain.svg)](https://narcisource.github.io/wanted-preonboarding-challenge-backend-31/test-report) | [![Codecov](https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/codecov/codecov-plain.svg)](https://codecov.io/gh/narcisource/wanted-preonboarding-challenge-backend-31) |\r\n| --- | --- |\r\n| [테스트 리포트 바로가기](https://narcisource.github.io/wanted-preonboarding-challenge-backend-31/test-report) | [커버리지 대시보드 바로가기](https://codecov.io/gh/narcisource/wanted-preonboarding-challenge-backend-31) |\r\n\r\n커버리지는 Codecov를 통해 분석됩니다.  \r\n[![codecov](https://codecov.io/gh/NarciSource/wanted-preonboarding-challenge-backend-31/branch/challenge/NarciSource/graph/badge.svg)](https://codecov.io/gh/NarciSource/test)\r\n\r\n![Sunburst-graph](https://codecov.io/gh/narcisource/wanted-preonboarding-challenge-backend-31/graphs/sunburst.svg)\r\n\r\n## 폴더 구조\r\n\r\n\u003cdetails\u003e\r\n\u003csummary\u003e열기\u003c/summary\u003e\r\n\r\n```\r\nwanted-preonboarding-challenge-backend-31\r\n├─ data\r\n│  ├─ 01.ddl.sql\r\n│  ├─ 02.sellers.sql\r\n│  ├─ 03.brands.sql\r\n│  ├─ 04.categories.sql\r\n│  ├─ 05.tags.sql\r\n│  ├─ 06.products.sql\r\n│  ├─ 07.product_options.sql\r\n│  ├─ 08.product_extended.sql\r\n│  ├─ 09.users.sql\r\n│  └─ 10.reviews.sql\r\n├─ src\r\n│  ├─ domain\r\n│  │  ├─ entities\r\n│  │  │  └─ index.ts\r\n│  │  │     ├─ Product.ts\r\n│  │  │     ├─ Product_Detail.ts\r\n│  │  │     ├─ Product_Image.ts\r\n│  │  │     ├─ Product_Option.ts\r\n│  │  │     ├─ Product_Price.ts\r\n│  │  │     ├─ Brand.ts\r\n│  │  │     ├─ Category.ts\r\n│  │  │     ├─ Review.ts\r\n│  │  │     ├─ Seller.ts\r\n│  │  │     ├─ Tag.ts\r\n│  │  │     └─ User.ts\r\n│  │  └─ repositories\r\n│  │     └─ index.ts\r\n│  │        ├─ IMainRepository.ts\r\n│  │        └─ IRepository.ts\r\n│  ├─ application\r\n│  │  ├─ dto\r\n│  │  │  └─ index.ts\r\n│  │  │     ├─ Filter.dto.ts\r\n│  │  │     ├─ ProductCatalog.dto.ts\r\n│  │  │     ├─ ProductCategory.dto.ts\r\n│  │  │     ├─ ProductInput.dto.ts\r\n│  │  │     ├─ ProductOptionGroup.dto.ts\r\n│  │  │     ├─ ProductSummary.dto.ts\r\n│  │  │     └─ ProductTag.dto.ts\r\n│  │  └─ services\r\n│  │     └─ index.ts\r\n│  │        ├─ Product.service.ts\r\n│  │        │  └─ Product.service.test.ts\r\n│  │        ├─ Product_Options.service.ts\r\n│  │        │  └─ Product_Options.service.test.ts\r\n│  │        ├─ Main.service.ts\r\n│  │        │  └─ Main.service.test.ts\r\n│  │        ├─ Category.service.ts\r\n│  │        │  └─ Category.service.test.ts\r\n│  │        └─ Review.service.ts\r\n│  │           └─ Review.service.test.ts\r\n│  ├─ infrastructure\r\n│  │  ├─ auth\r\n│  │  │  ├─ jwtInterceptor.ts\r\n│  │  │  └─ verifier.ts\r\n│  │  ├─ entities\r\n│  │  │  └─ index.ts\r\n│  │  │     ├─ Product.entity.ts\r\n│  │  │     │  └─ Product.entity.test.ts\r\n│  │  │     ├─ Product_Category.entity.ts\r\n│  │  │     │  └─ Product_Category.entity.test.ts\r\n│  │  │     ├─ Product_Detail.entity.ts\r\n│  │  │     │  └─ Product_Detail.entity.test.ts\r\n│  │  │     ├─ Product_Image.entity.ts\r\n│  │  │     │  └─ Product_Image.entity.test.ts\r\n│  │  │     ├─ Product_Option.entity.ts\r\n│  │  │     │  └─ Product_Option.entity.test.ts\r\n│  │  │     ├─ Product_Option_Group.entity.ts\r\n│  │  │     │  └─ Product_Option_Group.entity.test.ts\r\n│  │  │     ├─ Product_Price.entity.ts\r\n│  │  │     │  └─ Product_Price.entity.test.ts\r\n│  │  │     ├─ Product_Tag.entity.ts\r\n│  │  │     │  └─ Product_Tag.entity.test.ts\r\n│  │  │     ├─ Brand.entity.ts\r\n│  │  │     │  └─ Brand.entity.test.ts\r\n│  │  │     ├─ Category.entity.ts\r\n│  │  │     │  └─ Category.entity.test.ts\r\n│  │  │     ├─ Review.entity.ts\r\n│  │  │     │  └─ Review.entity.test.ts\r\n│  │  │     ├─ Seller.entity.ts\r\n│  │  │     │  └─ Seller.entity.test.ts\r\n│  │  │     ├─ Tag.entity.ts\r\n│  │  │     │  └─ Tag.entity.test.ts\r\n│  │  │     └─ User.entity.ts\r\n│  │  │        └─ User.entity.test.ts\r\n│  │  ├─ repositories\r\n│  │  │  └─ index.ts\r\n│  │  │     ├─ BaseRepository.ts\r\n│  │  │     ├─ Product.repository.ts\r\n│  │  │     │  └─ Product.repository.test.ts\r\n│  │  │     ├─ Product_Category.repository.ts\r\n│  │  │     │  └─ Product_Category.repository.test.ts\r\n│  │  │     ├─ Product_Detail.repository.ts\r\n│  │  │     │  └─ Product_Detail.repository.test.ts\r\n│  │  │     ├─ Product_Image.repository.ts\r\n│  │  │     │  └─ Product_Image.repository.test.ts\r\n│  │  │     ├─ Product_Options.repository.ts\r\n│  │  │     │  └─ Product_Options.repository.test.ts\r\n│  │  │     ├─ Product_Option_Group.repository.ts\r\n│  │  │     │  └─ Product_Option_Group.repository.test.ts\r\n│  │  │     ├─ Product_Price.repository.ts\r\n│  │  │     │  └─ Product_Price.repository.test.ts\r\n│  │  │     ├─ Product_Tag.repository.ts\r\n│  │  │     │  └─ Product_Tag.repository.test.ts\r\n│  │  │     ├─ Main.repository.ts\r\n│  │  │     │  └─ Main.repository.test.ts\r\n│  │  │     ├─ Category.repository.ts\r\n│  │  │     │  └─ Category.repository.test.ts\r\n│  │  │     └─ Review.repository.ts\r\n│  │  │        └─ Review.repository.test.ts\r\n│  │  ├─ views\r\n│  │  │  └─ index.ts\r\n│  │  │     ├─ ProductCatalog.view.ts\r\n│  │  │     │  └─ ProductCatalog.view.test.ts\r\n│  │  │     └─ ProductSummary.view.ts\r\n│  │  │        └─ ProductSummary.view.test.ts\r\n│  │  └─ provider.ts\r\n│  ├─ presentation\r\n│  │  ├─ controllers\r\n│  │  │  └─ index.ts\r\n│  │  │     ├─ Product.controller.ts\r\n│  │  │     │  └─ Product.controller.test.ts\r\n│  │  │     ├─ Product_Options.controller.ts\r\n│  │  │     │  └─ Product_Options.controller.test.ts\r\n│  │  │     ├─ Main.controller.ts\r\n│  │  │     │  └─ Main.controller.test.ts\r\n│  │  │     ├─ Category.controller.ts\r\n│  │  │     │  └─ Category.controller.test.ts\r\n│  │  │     └─ Review.controller.ts\r\n│  │  │        └─ Review.controller.test.ts\r\n│  │  ├─ decorators\r\n│  │  │  └─ index.ts\r\n│  │  │     ├─ ApiErrorResponse.ts\r\n│  │  │     └─ ApiStandardResponse.ts\r\n│  │  ├─ dto\r\n│  │  │  └─ index.ts\r\n│  │  │     ├─ model\r\n│  │  │     │  ├─ Brand.dto.ts\r\n│  │  │     │  │  └─ Brand.dto.test.ts\r\n│  │  │     │  ├─ Category.dto.ts\r\n│  │  │     │  │  └─ Category.dto.test.ts\r\n│  │  │     │  ├─ Image.dto.ts\r\n│  │  │     │  │  └─ Image.dto.test.ts\r\n│  │  │     │  ├─ ProductDetail.dto.ts\r\n│  │  │     │  │  └─ ProductDetail.dto.test.ts\r\n│  │  │     │  ├─ ProductOption.dto.ts\r\n│  │  │     │  │  └─ ProductOption.dto.test.ts\r\n│  │  │     │  ├─ ProductOptionGroup.dto.ts\r\n│  │  │     │  │  └─ ProductOptionGroup.dto.test.ts\r\n│  │  │     │  ├─ ProductPrice.dto.ts\r\n│  │  │     │  │  └─ ProductPrice.dto.test.ts\r\n│  │  │     │  ├─ Review.dto.ts\r\n│  │  │     │  │  └─ Review.dto.test.ts\r\n│  │  │     │  ├─ Seller.dto.ts\r\n│  │  │     │  │  └─ Seller.dto.test.ts\r\n│  │  │     │  └─ Tag.dto.ts\r\n│  │  │     │     └─ Tag.dto.test.ts\r\n│  │  │     ├─ request\r\n│  │  │     │  ├─ CategoryQuery.dto.ts\r\n│  │  │     │  │  └─ CategoryQuery.dto.test.ts\r\n│  │  │     │  ├─ Param.dto.ts\r\n│  │  │     │  │  └─ Param.dto.test.ts\r\n│  │  │     │  ├─ ProductBody.dto.ts\r\n│  │  │     │  │  └─ ProductBody.dto.test.ts\r\n│  │  │     │  ├─ ProductQuery.dto.ts\r\n│  │  │     │  │  └─ ProductQuery.dto.test.ts\r\n│  │  │     │  ├─ ReviewBody.dto.ts\r\n│  │  │     │  │  └─ ReviewBody.dto.test.ts\r\n│  │  │     │  └─ ReviewQuery.dto.ts\r\n│  │  │     │     └─ ReviewQuery.dto.test.ts\r\n│  │  │     ├─ response\r\n│  │  │     │  ├─ CategoryResponseBundle.dto.ts\r\n│  │  │     │  │  └─ CategoryResponseBundle.dto.test.ts\r\n│  │  │     │  ├─ MainResponseBundle.dto.ts\r\n│  │  │     │  │  └─ MainResponseBundle.dto.test.ts\r\n│  │  │     │  ├─ NestedCategory.dto.ts\r\n│  │  │     │  │  └─ NestedCategory.dto.test.ts\r\n│  │  │     │  ├─ PaginationSummary.dto.ts\r\n│  │  │     │  │  └─ PaginationSummary.dto.test.ts\r\n│  │  │     │  ├─ ProductCatalog.dto.ts\r\n│  │  │     │  │  └─ ProductCatalog.dto.test.ts\r\n│  │  │     │  ├─ ProductResponse.dto.ts\r\n│  │  │     │  │  └─ ProductResponse.dto.test.ts\r\n│  │  │     │  ├─ ProductResponseBundle.dto.ts\r\n│  │  │     │  │  └─ ProductResponseBundle.dto.test.ts\r\n│  │  │     │  ├─ ProductSummary.dto.ts\r\n│  │  │     │  │  └─ ProductSummary.dto.test.ts\r\n│  │  │     │  ├─ Rating.dto.ts\r\n│  │  │     │  │  └─ Rating.dto.test.ts\r\n│  │  │     │  ├─ ReviewResponse.dto.ts\r\n│  │  │     │  │  └─ ReviewResponse.dto.test.ts\r\n│  │  │     │  ├─ ReviewResponseBundle.dto.ts\r\n│  │  │     │  │  └─ ReviewResponseBundle.dto.test.ts\r\n│  │  │     │  └─ ReviewSummary.dto.ts\r\n│  │  │     │     └─ ReviewSummary.dto.test.ts\r\n│  │  │     ├─ Error.dto.ts\r\n│  │  │     │  └─ Error.dto.test.ts\r\n│  │  │     └─ Response.dto.ts\r\n│  │  │        └─ Response.dto.test.ts\r\n│  │  ├─ filters\r\n│  │  │  └─ index.ts\r\n│  │  │     ├─ BadRequestExceptionFilter.ts\r\n│  │  │     ├─ ConflictExceptionFilter.ts\r\n│  │  │     ├─ ForbiddenExceptionFilter.ts\r\n│  │  │     ├─ InternalServerErrorExceptionFilter.ts\r\n│  │  │     ├─ NotFoundExceptionFilter.ts\r\n│  │  │     ├─ QueryFailedExceptionFilter.ts\r\n│  │  │     └─ UnauthorizedExceptionFilter.ts\r\n│  │  └─ mappers\r\n│  │     └─ index.ts\r\n│  │        └─ to_FilterDTO.ts\r\n│  ├─ utility\r\n│  │  ├─ downloadOpenAPI.ts\r\n│  │  ├─ generatorSwagger.ts\r\n│  │  └─ extractDTOExample.ts\r\n│  ├─ __mocks__\r\n│  │  ├─ entityManagerMock.ts\r\n│  │  └─ repositoryMock.ts\r\n│  ├─ __test-utils__\r\n│  │  └─ test-module.ts\r\n│  ├─ main.ts\r\n│  └─ module.ts\r\n├─ .env\r\n├─ docker-compose.yml\r\n│  └─ Dockerfile\r\n├─ jest.config.ts\r\n│  └─ jest.setup.ts\r\n├─ package.json\r\n│  ├─ package-lock.json\r\n│  ├─ .prettierrc\r\n│  ├─ eslint.config.mjs\r\n│  └─ nest-cli.json\r\n├─ README.md\r\n└─ tsconfig.json\r\n   └─ tsconfig.build.json\r\n```\r\n\r\n\u003c/details\u003e\r\n\r\n## 실행 방법\r\n\r\n### 도커환경\r\n\r\nDocker Compose를 활용하여 서버와 데이터베이스를 각각 별도의 컨테이너로 구성하고, 공통 네트워크 환경에서 실행되도록 설정합니다.  \r\n이를 통해 개발 및 테스트 환경에서의 서비스 간 통신을 간편하게 구성합니다.\r\n\r\n```sh\r\n# build\r\n$ docker-compose build\r\n\r\n# run\r\n$ docker-compose up -d\r\n```\r\n\r\n### 서버 접근\r\n\r\n서버는 환경변수 파일(.env)에 정의된 `PORT` 번호를 통해 외부 호스트에서 접근할 수 있습니다.  \r\n기본 포트는 `3000`으로 설정되어 있으며, 로컬 환경에서 서버에 접속하려면 다음 주소를 이용합니다.\r\n\r\n- 애플리케이션 접속: http://localhost:3000\r\n- Swagger 문서 페이지: http://localhost:3000/swagger-ui/index.html\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnarcisource%2Fpre-onboarding-challenge-be-31","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnarcisource%2Fpre-onboarding-challenge-be-31","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnarcisource%2Fpre-onboarding-challenge-be-31/lists"}