diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml new file mode 100644 index 0000000..5d35d2c --- /dev/null +++ b/.github/workflows/autofix.yml @@ -0,0 +1,43 @@ +name: autofix.ci # needed to securely identify the workflow + +on: + pull_request: + push: + branches: ["main"] + +defaults: + run: + working-directory: backend + +permissions: + contents: read + +jobs: + autofix: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: pnpm 설치 + uses: pnpm/action-setup@v4 + with: + version: 9 + package_json_file: "backend/package.json" + + - name: Node.js 22 설치 + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: "pnpm" + cache-dependency-path: backend/pnpm-lock.yaml + + - name: 의존성 설치 + run: pnpm install --frozen-lockfile + + - name: 포매팅 + run: pnpm format + + - name: 린트 + run: pnpm lint || true + + - uses: autofix-ci/action@dd55f44df8f7cdb7a6bf74c78677eb8acd40cd0a diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..afaefe3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,46 @@ +name: CI +on: + push: + branches: [main] + pull_request: + branches: [main] + +defaults: + run: + working-directory: backend + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20, 22] + steps: + - uses: actions/checkout@v4 + + - name: pnpm 설치 + uses: pnpm/action-setup@v4 + with: + version: 9 + package_json_file: "backend/package.json" + + - name: Node.js ${{ matrix.node-version }} 설치 + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: "pnpm" + cache-dependency-path: backend/pnpm-lock.yaml + + - name: 의존성 설치 + run: pnpm install --frozen-lockfile + + - name: 테스트 + run: | + pnpm lint:ci + pnpm typecheck + pnpm test:cov + + - name: Codecov에 커버리지 결과 배포 + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index 259de13..a6fa1fd 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -21,5 +21,6 @@ module.exports = { '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': 'warn' }, }; diff --git a/backend/pnpm-lock.yaml b/backend/pnpm-lock.yaml index 1867c84..989d7ea 100644 --- a/backend/pnpm-lock.yaml +++ b/backend/pnpm-lock.yaml @@ -20,6 +20,15 @@ importers: '@nestjs/swagger': specifier: ^7.4.0 version: 7.4.0(@nestjs/common@10.4.1(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.1(@nestjs/common@10.4.1(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2) + '@nestjs/typeorm': + specifier: ^10.0.2 + version: 10.0.2(@nestjs/common@10.4.1(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.1(@nestjs/common@10.4.1(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(rxjs@7.8.1)(typeorm@0.3.20(mysql2@3.11.3)(ts-node@10.9.2(@types/node@20.16.3)(typescript@5.5.4))) + dotenv: + specifier: ^16.4.5 + version: 16.4.5 + mysql2: + specifier: ^3.11.0 + version: 3.11.3 nestjs-zod: specifier: ^3.0.0 version: 3.0.0(@nestjs/common@10.4.1(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.1(@nestjs/common@10.4.1(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/swagger@7.4.0(@nestjs/common@10.4.1(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.1(@nestjs/common@10.4.1(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2))(zod@3.23.8) @@ -31,16 +40,7 @@ importers: version: 7.8.1 typeorm: specifier: ^0.3.20 - version: 0.3.20(mysql2@3.11.0)(ts-node@10.9.2) - '@nestjs/typeorm': - specifier: ^10.0.2 - version: 10.0.2(@nestjs/common@10.4.1)(@nestjs/core@10.4.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)(typeorm@0.3.20) - dotenv: - specifier: ^16.4.5 - version: 16.4.5 - mysql2: - specifier: ^3.11.0 - version: 3.11.0 + version: 0.3.20(mysql2@3.11.3)(ts-node@10.9.2(@types/node@20.16.3)(typescript@5.5.4)) devDependencies: '@nestjs/cli': specifier: ^10.0.0 @@ -548,6 +548,15 @@ packages: '@nestjs/platform-express': optional: true + '@nestjs/typeorm@10.0.2': + resolution: {integrity: sha512-H738bJyydK4SQkRCTeh1aFBxoO1E9xdL/HaLGThwrqN95os5mEyAtK7BLADOS+vldP4jDZ2VQPLj4epWwRqCeQ==} + peerDependencies: + '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 + '@nestjs/core': ^8.0.0 || ^9.0.0 || ^10.0.0 + reflect-metadata: ^0.1.13 || ^0.2.0 + rxjs: ^7.2.0 + typeorm: ^0.3.0 + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -911,6 +920,10 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} + babel-jest@29.7.0: resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1228,6 +1241,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -1533,6 +1550,9 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -1639,6 +1659,10 @@ packages: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -1728,6 +1752,9 @@ packages: resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} engines: {node: '>=0.10.0'} + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -2019,12 +2046,23 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + long@5.2.3: + resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + + lru.min@1.1.0: + resolution: {integrity: sha512-86xXMB6DiuKrTqkE/lRL0drlNh568awttBPJ7D66fzDHpy6NC5r3N+Ly/lKCS2zjmeGyvFDx670z0cD0PVBwGA==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + magic-string@0.30.8: resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} engines: {node: '>=12'} @@ -2142,9 +2180,17 @@ packages: resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + mysql2@3.11.3: + resolution: {integrity: sha512-Qpu2ADfbKzyLdwC/5d4W7+5Yz7yBzCU05YWt5npWzACST37wJsB23wgOSo00qi043urkiRwXtEvJc9UnuLX/MQ==} + engines: {node: '>= 8.0'} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + named-placeholders@1.1.3: + resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} + engines: {node: '>=12.0.0'} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -2486,6 +2532,9 @@ packages: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} + seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} @@ -2551,6 +2600,10 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -3069,7 +3122,7 @@ snapshots: '@babel/traverse': 7.25.6 '@babel/types': 7.25.6 convert-source-map: 2.0.0 - debug: 4.3.7 + debug: 4.3.6 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -3237,7 +3290,7 @@ snapshots: '@babel/parser': 7.25.6 '@babel/template': 7.25.0 '@babel/types': 7.25.6 - debug: 4.3.7 + debug: 4.3.6 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -3267,7 +3320,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.7 + debug: 4.3.6 espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -3283,7 +3336,7 @@ snapshots: '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.7 + debug: 4.3.6 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -3314,7 +3367,7 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 20.16.5 + '@types/node': 20.16.3 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -3327,7 +3380,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.16.5 + '@types/node': 20.16.3 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 @@ -3359,7 +3412,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.16.5 + '@types/node': 20.16.3 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -3377,7 +3430,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.16.5 + '@types/node': 20.16.3 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -3399,7 +3452,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 20.16.5 + '@types/node': 20.16.3 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -3469,7 +3522,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.16.5 + '@types/node': 20.16.3 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -3593,7 +3646,7 @@ snapshots: comment-json: 4.2.3 jsonc-parser: 3.3.1 pluralize: 8.0.0 - typescript: 5.6.2 + typescript: 5.5.4 transitivePeerDependencies: - chokidar @@ -3617,6 +3670,15 @@ snapshots: optionalDependencies: '@nestjs/platform-express': 10.4.1(@nestjs/common@10.4.1(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.1) + '@nestjs/typeorm@10.0.2(@nestjs/common@10.4.1(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.1(@nestjs/common@10.4.1(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(rxjs@7.8.1)(typeorm@0.3.20(mysql2@3.11.3)(ts-node@10.9.2(@types/node@20.16.3)(typescript@5.5.4)))': + dependencies: + '@nestjs/common': 10.4.1(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.1(@nestjs/common@10.4.1(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + reflect-metadata: 0.2.2 + rxjs: 7.8.1 + typeorm: 0.3.20(mysql2@3.11.3)(ts-node@10.9.2(@types/node@20.16.3)(typescript@5.5.4)) + uuid: 9.0.1 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -3698,7 +3760,7 @@ snapshots: '@types/express-serve-static-core@4.19.5': dependencies: - '@types/node': 20.16.5 + '@types/node': 20.16.3 '@types/qs': 6.9.15 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -3753,7 +3815,7 @@ snapshots: '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/node': 20.16.5 + '@types/node': 20.16.3 '@types/send': 0.17.4 '@types/stack-utils@2.0.3': {} @@ -3762,7 +3824,7 @@ snapshots: dependencies: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 - '@types/node': 20.16.5 + '@types/node': 20.16.3 form-data: 4.0.0 '@types/supertest@6.0.2': @@ -3779,11 +3841,11 @@ snapshots: '@typescript-eslint/eslint-plugin@8.3.0(@typescript-eslint/parser@8.3.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)': dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 8.5.0(eslint@8.57.0)(typescript@5.6.2) - '@typescript-eslint/scope-manager': 8.5.0 - '@typescript-eslint/type-utils': 8.5.0(eslint@8.57.0)(typescript@5.6.2) - '@typescript-eslint/utils': 8.5.0(eslint@8.57.0)(typescript@5.6.2) - '@typescript-eslint/visitor-keys': 8.5.0 + '@typescript-eslint/parser': 8.3.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/scope-manager': 8.3.0 + '@typescript-eslint/type-utils': 8.3.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/utils': 8.3.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 8.3.0 eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.2 @@ -3796,11 +3858,11 @@ snapshots: '@typescript-eslint/parser@8.3.0(eslint@8.57.0)(typescript@5.5.4)': dependencies: - '@typescript-eslint/scope-manager': 8.5.0 - '@typescript-eslint/types': 8.5.0 - '@typescript-eslint/typescript-estree': 8.5.0(typescript@5.6.2) - '@typescript-eslint/visitor-keys': 8.5.0 - debug: 4.3.7 + '@typescript-eslint/scope-manager': 8.3.0 + '@typescript-eslint/types': 8.3.0 + '@typescript-eslint/typescript-estree': 8.3.0(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 8.3.0 + debug: 4.3.6 eslint: 8.57.0 optionalDependencies: typescript: 5.5.4 @@ -3828,9 +3890,9 @@ snapshots: '@typescript-eslint/typescript-estree@8.3.0(typescript@5.5.4)': dependencies: - '@typescript-eslint/types': 8.5.0 - '@typescript-eslint/visitor-keys': 8.5.0 - debug: 4.3.7 + '@typescript-eslint/types': 8.3.0 + '@typescript-eslint/visitor-keys': 8.3.0 + debug: 4.3.6 fast-glob: 3.3.2 is-glob: 4.0.3 minimatch: 9.0.5 @@ -3844,9 +3906,9 @@ snapshots: '@typescript-eslint/utils@8.3.0(eslint@8.57.0)(typescript@5.5.4)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 8.5.0 - '@typescript-eslint/types': 8.5.0 - '@typescript-eslint/typescript-estree': 8.5.0(typescript@5.6.2) + '@typescript-eslint/scope-manager': 8.3.0 + '@typescript-eslint/types': 8.3.0 + '@typescript-eslint/typescript-estree': 8.3.0(typescript@5.5.4) eslint: 8.57.0 transitivePeerDependencies: - supports-color @@ -3854,7 +3916,7 @@ snapshots: '@typescript-eslint/visitor-keys@8.3.0': dependencies: - '@typescript-eslint/types': 8.5.0 + '@typescript-eslint/types': 8.3.0 eslint-visitor-keys: 3.4.3 '@ungap/structured-clone@1.2.0': {} @@ -4033,6 +4095,8 @@ snapshots: asynckit@0.4.0: {} + aws-ssl-profiles@1.1.2: {} + babel-jest@29.7.0(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -4132,8 +4196,8 @@ snapshots: browserslist@4.23.3: dependencies: - caniuse-lite: 1.0.30001660 - electron-to-chromium: 1.5.18 + caniuse-lite: 1.0.30001655 + electron-to-chromium: 1.5.13 node-releases: 2.0.18 update-browserslist-db: 1.1.0(browserslist@4.23.3) @@ -4387,6 +4451,8 @@ snapshots: delayed-stream@1.0.0: {} + denque@2.1.0: {} + depd@2.0.0: {} destroy@1.2.0: {} @@ -4491,7 +4557,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.7 + debug: 4.3.6 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -4744,6 +4810,10 @@ snapshots: function-bind@1.1.2: {} + generate-function@2.3.1: + dependencies: + is-property: 1.0.2 + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} @@ -4840,6 +4910,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} ignore@5.3.2: {} @@ -4935,6 +5009,8 @@ snapshots: dependencies: isobject: 3.0.1 + is-property@1.0.2: {} + is-stream@2.0.1: {} is-unicode-supported@0.1.0: {} @@ -4975,7 +5051,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.3.7 + debug: 4.3.6 istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -5013,7 +5089,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.16.5 + '@types/node': 20.16.3 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.3 @@ -5107,7 +5183,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.16.5 + '@types/node': 20.16.3 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -5117,7 +5193,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 20.16.5 + '@types/node': 20.16.3 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -5156,7 +5232,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.16.5 + '@types/node': 20.16.3 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -5191,7 +5267,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.16.5 + '@types/node': 20.16.3 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -5219,9 +5295,9 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.16.5 + '@types/node': 20.16.3 chalk: 4.1.2 - cjs-module-lexer: 1.4.1 + cjs-module-lexer: 1.4.0 collect-v8-coverage: 1.0.2 glob: 7.2.3 graceful-fs: 4.2.11 @@ -5265,7 +5341,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.16.5 + '@types/node': 20.16.3 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -5284,7 +5360,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.16.5 + '@types/node': 20.16.3 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -5293,13 +5369,13 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 20.16.5 + '@types/node': 20.16.3 merge-stream: 2.0.0 supports-color: 8.1.1 jest-worker@29.7.0: dependencies: - '@types/node': 20.16.5 + '@types/node': 20.16.3 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -5399,12 +5475,18 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + long@5.2.3: {} + lru-cache@10.4.3: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 + lru-cache@7.18.3: {} + + lru.min@1.1.0: {} + magic-string@0.30.8: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -5503,12 +5585,28 @@ snapshots: mute-stream@1.0.0: {} + mysql2@3.11.3: + dependencies: + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.6.3 + long: 5.2.3 + lru.min: 1.1.0 + named-placeholders: 1.1.3 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + mz@2.7.0: dependencies: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 + named-placeholders@1.1.3: + dependencies: + lru-cache: 7.18.3 + natural-compare@1.4.0: {} negotiator@0.6.3: {} @@ -5813,6 +5911,8 @@ snapshots: transitivePeerDependencies: - supports-color + seq-queue@0.0.5: {} + serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 @@ -5886,6 +5986,8 @@ snapshots: sprintf-js@1.0.3: {} + sqlstring@2.3.3: {} + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -5925,7 +6027,7 @@ snapshots: strip-ansi@7.1.0: dependencies: - ansi-regex: 6.1.0 + ansi-regex: 6.0.1 strip-bom@3.0.0: {} @@ -5939,7 +6041,7 @@ snapshots: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.3.7 + debug: 4.3.6 fast-safe-stringify: 2.1.1 form-data: 4.0.0 formidable: 3.5.1 @@ -5987,7 +6089,7 @@ snapshots: jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 - terser: 5.32.0 + terser: 5.31.6 webpack: 5.94.0 terser@5.31.6: @@ -6048,7 +6150,7 @@ snapshots: lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.6.3 - typescript: 5.6.2 + typescript: 5.5.4 yargs-parser: 21.1.1 optionalDependencies: '@babel/core': 7.25.2 @@ -6063,7 +6165,7 @@ snapshots: micromatch: 4.0.8 semver: 7.6.3 source-map: 0.7.4 - typescript: 5.6.2 + typescript: 5.5.4 webpack: 5.94.0 ts-node@10.9.2(@types/node@20.16.3)(typescript@5.5.4): @@ -6073,14 +6175,14 @@ snapshots: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.16.5 + '@types/node': 20.16.3 acorn: 8.12.1 - acorn-walk: 8.3.4 + acorn-walk: 8.3.3 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.6.2 + typescript: 5.5.4 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 @@ -6117,7 +6219,7 @@ snapshots: typedarray@0.0.6: {} - typeorm@0.3.20(ts-node@10.9.2(@types/node@20.16.3)(typescript@5.5.4)): + typeorm@0.3.20(mysql2@3.11.3)(ts-node@10.9.2(@types/node@20.16.3)(typescript@5.5.4)): dependencies: '@sqltools/formatter': 1.2.5 app-root-path: 3.1.0 @@ -6125,17 +6227,17 @@ snapshots: chalk: 4.1.2 cli-highlight: 2.1.11 dayjs: 1.11.13 - debug: 4.3.7 + debug: 4.3.6 dotenv: 16.4.5 - glob: 10.4.5 + glob: 10.4.2 mkdirp: 2.1.6 - mysql2: 3.11.0 reflect-metadata: 0.2.2 sha.js: 2.4.11 tslib: 2.7.0 uuid: 9.0.1 yargs: 17.7.2 optionalDependencies: + mysql2: 3.11.3 ts-node: 10.9.2(@types/node@20.16.3)(typescript@5.5.4) transitivePeerDependencies: - supports-color diff --git a/backend/src/app.controller.spec.ts b/backend/src/app.controller.spec.ts index d22f389..6d6bf97 100644 --- a/backend/src/app.controller.spec.ts +++ b/backend/src/app.controller.spec.ts @@ -19,4 +19,10 @@ describe('AppController', () => { expect(appController.getHello()).toBe('Hello World!'); }); }); + + describe('hello/:name', () => { + it('should return "Hello Nest!"', () => { + expect(appController.getHelloWithName('Nest')).toBe('Hello Nest!'); + }); + }); }); diff --git a/backend/src/app.controller.ts b/backend/src/app.controller.ts index cce879e..dfdff83 100644 --- a/backend/src/app.controller.ts +++ b/backend/src/app.controller.ts @@ -1,5 +1,6 @@ -import { Controller, Get } from '@nestjs/common'; +import { Controller, Get, Param } from '@nestjs/common'; import { AppService } from './app.service'; +import { ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger'; @Controller() export class AppController { @@ -9,4 +10,15 @@ export class AppController { getHello(): string { return this.appService.getHello(); } + + @Get('hello/:name') + @ApiOperation({ + summary: '인사말을 반환합니다.', + description: '이름을 입력하면 그 이름을 포함한 인사말을 반환합니다.', + }) + @ApiParam({ name: 'name', description: '이름', example: 'Nest' }) + @ApiResponse({ status: 200, description: '성공', example: 'Hello Nest!' }) + getHelloWithName(@Param('name') name: string): string { + return this.appService.getHello(name); + } } diff --git a/backend/src/app.service.ts b/backend/src/app.service.ts index 927d7cc..0329b72 100644 --- a/backend/src/app.service.ts +++ b/backend/src/app.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; @Injectable() export class AppService { - getHello(): string { - return 'Hello World!'; + getHello(name?: string): string { + return `Hello ${name ?? 'World'}!`; } } diff --git a/backend/src/entities/BookInfo.ts b/backend/src/entities/BookInfo.ts index a0c19bc..c5e1a01 100644 --- a/backend/src/entities/BookInfo.ts +++ b/backend/src/entities/BookInfo.ts @@ -77,6 +77,9 @@ export class BookInfo { @OneToMany(() => SuperTag, (superTags) => superTags.userId) superTags?: SuperTag[]; - @OneToOne(() => BookInfoSearchKeywords, (bookInfoSearchKeyword) => bookInfoSearchKeyword.bookInfo) + @OneToOne( + () => BookInfoSearchKeywords, + (bookInfoSearchKeyword) => bookInfoSearchKeyword.bookInfo, + ) bookInfoSearchKeyword?: BookInfoSearchKeywords; } diff --git a/backend/src/entities/BookInfoSearchKeywords.ts b/backend/src/entities/BookInfoSearchKeywords.ts index a51b03e..44be542 100644 --- a/backend/src/entities/BookInfoSearchKeywords.ts +++ b/backend/src/entities/BookInfoSearchKeywords.ts @@ -1,4 +1,11 @@ -import { Column, Entity, Index, JoinColumn, OneToOne, PrimaryGeneratedColumn } from 'typeorm'; +import { + Column, + Entity, + Index, + JoinColumn, + OneToOne, + PrimaryGeneratedColumn, +} from 'typeorm'; import { BookInfo } from './BookInfo'; @Index('FK_bookInfoId', ['bookInfoId'], {}) diff --git a/backend/src/entities/Category.ts b/backend/src/entities/Category.ts index cd6cca5..9ae73e9 100644 --- a/backend/src/entities/Category.ts +++ b/backend/src/entities/Category.ts @@ -1,4 +1,10 @@ -import { Column, Entity, Index, OneToMany, PrimaryGeneratedColumn } from 'typeorm'; +import { + Column, + Entity, + Index, + OneToMany, + PrimaryGeneratedColumn, +} from 'typeorm'; import { BookInfo } from './BookInfo'; @Index('id', ['id'], { unique: true }) diff --git a/backend/src/entities/Lending.ts b/backend/src/entities/Lending.ts index 4a321f4..5f9c31c 100644 --- a/backend/src/entities/Lending.ts +++ b/backend/src/entities/Lending.ts @@ -1,4 +1,11 @@ -import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; +import { + Column, + Entity, + Index, + JoinColumn, + ManyToOne, + PrimaryGeneratedColumn, +} from 'typeorm'; import { Book } from './Book'; import { User } from './User'; diff --git a/backend/src/entities/Likes.ts b/backend/src/entities/Likes.ts index 86a147c..70e17a2 100644 --- a/backend/src/entities/Likes.ts +++ b/backend/src/entities/Likes.ts @@ -1,4 +1,11 @@ -import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; +import { + Column, + Entity, + Index, + JoinColumn, + ManyToOne, + PrimaryGeneratedColumn, +} from 'typeorm'; import { User } from './User'; import { BookInfo } from './BookInfo'; diff --git a/backend/src/entities/Reservation.ts b/backend/src/entities/Reservation.ts index d829214..0b16360 100644 --- a/backend/src/entities/Reservation.ts +++ b/backend/src/entities/Reservation.ts @@ -1,4 +1,11 @@ -import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; +import { + Column, + Entity, + Index, + JoinColumn, + ManyToOne, + PrimaryGeneratedColumn, +} from 'typeorm'; import { User } from './User'; import { BookInfo } from './BookInfo'; import { Book } from './Book'; diff --git a/backend/src/entities/Reviews.ts b/backend/src/entities/Reviews.ts index 62b1e75..3ce738d 100644 --- a/backend/src/entities/Reviews.ts +++ b/backend/src/entities/Reviews.ts @@ -1,4 +1,11 @@ -import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; +import { + Column, + Entity, + Index, + JoinColumn, + ManyToOne, + PrimaryGeneratedColumn, +} from 'typeorm'; import { User } from './User'; import { BookInfo } from './BookInfo'; diff --git a/backend/src/entities/SearchLogs.ts b/backend/src/entities/SearchLogs.ts index 35249e8..6599933 100644 --- a/backend/src/entities/SearchLogs.ts +++ b/backend/src/entities/SearchLogs.ts @@ -1,4 +1,11 @@ -import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; +import { + Column, + Entity, + Index, + JoinColumn, + ManyToOne, + PrimaryGeneratedColumn, +} from 'typeorm'; import { SearchKeywords } from './SearchKeywords'; @Index('FK_searchKeywordId', ['searchKeywordId'], {}) diff --git a/backend/src/entities/SubTag.ts b/backend/src/entities/SubTag.ts index 2124b39..d006849 100644 --- a/backend/src/entities/SubTag.ts +++ b/backend/src/entities/SubTag.ts @@ -1,4 +1,11 @@ -import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; +import { + Column, + Entity, + Index, + JoinColumn, + ManyToOne, + PrimaryGeneratedColumn, +} from 'typeorm'; import { User } from './User'; import { SuperTag } from './SuperTag'; diff --git a/backend/src/entities/User.ts b/backend/src/entities/User.ts index 6d7bf39..d1c8659 100644 --- a/backend/src/entities/User.ts +++ b/backend/src/entities/User.ts @@ -1,4 +1,10 @@ -import { Column, Entity, Index, OneToMany, PrimaryGeneratedColumn } from 'typeorm'; +import { + Column, + Entity, + Index, + OneToMany, + PrimaryGeneratedColumn, +} from 'typeorm'; import { Book } from './Book'; import { Lending } from './Lending'; import { Likes } from './Likes'; diff --git a/backend/src/entities/VHistories.ts b/backend/src/entities/VHistories.ts index a7c5e4e..9b47c21 100644 --- a/backend/src/entities/VHistories.ts +++ b/backend/src/entities/VHistories.ts @@ -22,7 +22,10 @@ import { DataSource, ViewColumn, ViewEntity } from 'typeorm'; .addSelect('DATE_FORMAT(l.createdAt, "%Y-%m-%d")', 'createdAt') .addSelect('DATE_FORMAT(l.returnedAt, "%Y-%m-%d")', 'returnedAt') .addSelect('DATE_FORMAT(l.updatedAt, "%Y-%m-%d")', 'updatedAt') - .addSelect("DATE_FORMAT(DATE_ADD(l.createdAt, interval 14 day), '%Y-%m-%d')", 'dueDate') + .addSelect( + "DATE_FORMAT(DATE_ADD(l.createdAt, interval 14 day), '%Y-%m-%d')", + 'dueDate', + ) .addSelect( '(SELECT nickname FROM user WHERE user.id = lendingLibrarianId)', 'lendingLibrarianNickName', diff --git a/backend/src/entities/VLending.ts b/backend/src/entities/VLending.ts index 71f086c..7e9c2be 100644 --- a/backend/src/entities/VLending.ts +++ b/backend/src/entities/VLending.ts @@ -16,7 +16,10 @@ import { DataSource, ViewColumn, ViewEntity } from 'typeorm'; .addSelect('bi.image', 'image') .addSelect("date_format(l.createdAt, '%Y-%m-%d')", 'createdAt') .addSelect("date_format(l.returnedAt, '%Y-%m-%d')", 'returnedAt') - .addSelect("date_format(DATE_ADD(l.createdAt, INTERVAL 14 DAY), '%Y-%m-%d')", 'dueDate') + .addSelect( + "date_format(DATE_ADD(l.createdAt, INTERVAL 14 DAY), '%Y-%m-%d')", + 'dueDate', + ) .from('lending', 'l') .innerJoin('user', 'u', 'l.userId = u.id') .leftJoin('book', 'b', 'l.bookId = b.id') diff --git a/backend/src/entities/VTagsSubDefault.ts b/backend/src/entities/VTagsSubDefault.ts index ca3ad9d..2dd66fa 100644 --- a/backend/src/entities/VTagsSubDefault.ts +++ b/backend/src/entities/VTagsSubDefault.ts @@ -17,7 +17,10 @@ import { User } from './User'; .addSelect('sp.content', 'superContent') .addSelect('sb.isPublic', 'isPublic') .addSelect('sb.isDeleted', 'isDeleted') - .addSelect("CASE WHEN sb.isPublic = 1 THEN 'public' ELSE 1 'private' END", 'visibility') + .addSelect( + "CASE WHEN sb.isPublic = 1 THEN 'public' ELSE 1 'private' END", + 'visibility', + ) .from(SuperTag, 'sp') .innerJoin(SubTag, 'sb', 'sb.superTagId = sp.id') .innerJoin(BookInfo, 'bi', 'bi.id = sp.bookInfoId') diff --git a/backend/src/entities/VUserLending.ts b/backend/src/entities/VUserLending.ts index 39f6046..2dd6f67 100644 --- a/backend/src/entities/VUserLending.ts +++ b/backend/src/entities/VUserLending.ts @@ -8,7 +8,10 @@ import { DataSource, ViewColumn, ViewEntity } from 'typeorm'; .addSelect('l.lendingCondition', 'lendingCondition') .addSelect('bi.id', 'bookInfoId') .addSelect('bi.title', 'title') - .addSelect("date_format(DATE_ADD(l.createdAt, INTERVAL 14 DAY), '%Y-%m-%d')", 'duedate') + .addSelect( + "date_format(DATE_ADD(l.createdAt, INTERVAL 14 DAY), '%Y-%m-%d')", + 'duedate', + ) .addSelect('bi.image', 'image') .addSelect( 'CASE WHEN DATEDIFF(now(), DATE_ADD(l.createdAt, INTERVAL 14 DAY)) < 0 THEN 0 ELSE DATEDIFF(now(), DATE_ADD(l.createdAt, INTERVAL 14 DAY)) END', diff --git a/backend/src/main.ts b/backend/src/main.ts index 13cad38..e1eafb4 100644 --- a/backend/src/main.ts +++ b/backend/src/main.ts @@ -1,8 +1,25 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; +import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; +import { patchNestJsSwagger } from 'nestjs-zod'; async function bootstrap() { const app = await NestFactory.create(AppModule); + + const config = new DocumentBuilder() + .setTitle('집현전 백엔드 6차') + .setDescription('집현전 백엔드 6차 API 명세') + .setVersion('0.0.1') + .setExternalDoc('JSON 명세', 'json') + .build(); + + const document = SwaggerModule.createDocument(app, config); + SwaggerModule.setup('api', app, document, { + jsonDocumentUrl: 'api/json', + }); + await app.listen(3000); } + +patchNestJsSwagger(); bootstrap(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..9b60ae1 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,9 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: {}