diff --git a/.DS_Store b/.github/.DS_Store similarity index 73% rename from .DS_Store rename to .github/.DS_Store index 7e9c4e8..dd1430c 100644 Binary files a/.DS_Store and b/.github/.DS_Store differ diff --git a/.github/workflows/.DS_Store b/.github/workflows/.DS_Store new file mode 100644 index 0000000..abebbe6 Binary files /dev/null and b/.github/workflows/.DS_Store differ diff --git a/.github/workflows/assign-issue-creator.yml b/.github/workflows/assign-issue-creator.yml new file mode 100644 index 0000000..6dde730 --- /dev/null +++ b/.github/workflows/assign-issue-creator.yml @@ -0,0 +1,14 @@ +# 각 레포지토리의 .github/workflows/assign-issue-creator.yml + +name: Assign issue creator + +on: + issues: + types: [opened] + +jobs: + call-reusable-workflow: + # @main 은 .github 레포지토리의 main 브랜치를 사용한다는 의미입니다. 버전을 위해 @v1과 같이 태그를 사용하는 것을 권장합니다. + uses: 33-Auto/.github/.github/workflows/reusable-assign-issue-creator.yml@main + # 이 워크플로우는 secrets를 전달할 필요가 없지만, 필요 시 아래와 같이 전달합니다. + # secrets: inherit \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b042f78..18dcd38 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,4 +77,26 @@ jobs: provenance: false tags: | ${{ steps.vars.outputs.IMAGE }}:${{ steps.vars.outputs.TAG_VERSION }} - ${{ steps.vars.outputs.IMAGE }}:${{ steps.vars.outputs.TAG_LATEST }} \ No newline at end of file + ${{ steps.vars.outputs.IMAGE }}:${{ steps.vars.outputs.TAG_LATEST }} + + + # EC2 자동 배포 + - name: Deploy to EC2 (Part) + uses: appleboy/ssh-action@master + with: + host: 3.38.218.173 + username: ubuntu + key: ${{ secrets.SAMPOOM_KEY }} + script: | + echo "배포 시작..." + sudo docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ secrets.DOCKERHUB_PASSWORD }} + sudo docker pull hysungzzang/sampoom:part-latest + sudo docker stop part-service || true + sudo docker rm part-service || true + sudo docker run -d --name part-service -p 8080:8080 \ + -e SPRING_APPLICATION_JSON='{"server":{"address":"0.0.0.0","port":8080}}' \ + -e SPRING_DATASOURCE_URL=jdbc:postgresql://3.38.218.173:5432/mydb \ + -e SPRING_DATASOURCE_USERNAME=myuser \ + -e SPRING_DATASOURCE_PASSWORD=mypassword \ + hysungzzang/sampoom:part-latest + echo "배포 완료!" \ No newline at end of file diff --git a/.github/workflows/close-issues-on-dev-merge.yml b/.github/workflows/close-issues-on-dev-merge.yml new file mode 100644 index 0000000..325a846 --- /dev/null +++ b/.github/workflows/close-issues-on-dev-merge.yml @@ -0,0 +1,19 @@ +# 각 레포지토리의 .github/workflows/close-issues-on-dev-merge.yml + +name: Auto Close Issues on dev merge + +on: + pull_request: + types: [closed] + +jobs: + call-reusable-workflow: + if: > + github.event.pull_request.merged == true && + github.event.pull_request.base.ref == 'dev' + uses: 33-Auto/.github/.github/workflows/reusable-close-linked-issues.yml@main + # with를 통해 재사용 워크플로우의 inputs에 값을 전달합니다. + with: + pr-body: ${{ github.event.pull_request.body }} + issue-number: ${{ github.event.pull_request.number }} + secrets: inherit # 재사용 워크플로우가 GITHUB_TOKEN을 사용할 수 있도록 전달 \ No newline at end of file diff --git a/.github/workflows/pr-reminder.yml b/.github/workflows/pr-reminder.yml index 9190e01..007e757 100644 --- a/.github/workflows/pr-reminder.yml +++ b/.github/workflows/pr-reminder.yml @@ -1,13 +1,15 @@ -name: PR Reminder + name: PR Reminder -on: - schedule: - - cron: "0 0,5,8 * * *" # 아침 9시, 오후 2시, 오후 5시에 실행 (UTC 기준으로 설정해서 한국 시간에 맞춤) - workflow_dispatch: + on: + schedule: + - cron: "47 23,4,7,8,10 * * *" # 아침 8시 47분, 오후 2시 47분, 오후 4시 47분, 오후 5시 47분, 오후 7시 47분 에 실행 (UTC 기준으로 설정해서 한국 시간에 맞춤) + workflow_dispatch: -jobs: - call-reusable-reminder: - uses: 33-Auto/.github/.github/workflows/reusable-pr-reminder.yml@main - secrets: - # 해당 시크릿은 조직의 시크릿에 저장되어 있음 - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + jobs: + call-reusable-reminder: + uses: 33-Auto/.github/.github/workflows/reusable-pr-reminder.yml@main + secrets: + # 해당 시크릿은 조직의 시크릿에 저장되어 있음 + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + with: + SLACK_USER_MAP: ${{ vars.SLACK_USER_MAP }} \ No newline at end of file diff --git a/.github/workflows/request-pr-review.yml b/.github/workflows/request-pr-review.yml new file mode 100644 index 0000000..66a31b9 --- /dev/null +++ b/.github/workflows/request-pr-review.yml @@ -0,0 +1,17 @@ +# 각 레포지토리의 .github/workflows/request-pr-review.yml + +name: PR Assignee & Team Review Request + +on: + pull_request: + types: [opened, reopened, ready_for_review] + +jobs: + call-reusable-workflow: + uses: 33-Auto/.github/.github/workflows/reusable-pr-assign-and-review.yml@main + with: + team-slug-for-review: "review_avengers" # 여기에 리뷰를 요청할 팀의 slug를 입력합니다. + pr-author: ${{ github.event.pull_request.user.login }} + pr-number: ${{ github.event.pull_request.number }} + secrets: + ORGANIZATION_TOKEN: ${{ secrets.ORGANIZATION_TOKEN }} # 재사용 워크플로우가 ORGANIZATION_TOKEN을 사용할 수 있도록 전달 diff --git a/.github/workflows/trigger_infra.yml b/.github/workflows/trigger_infra.yml new file mode 100644 index 0000000..37bbb92 --- /dev/null +++ b/.github/workflows/trigger_infra.yml @@ -0,0 +1,20 @@ +name: Trigger Infra CD + +on: + push: + branches: + - main + +jobs: + trigger-infra: + runs-on: ubuntu-latest + steps: + - name: Trigger infra repo deploy workflow + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{ secrets.ORGANIZATION_TOKEN }} + # [중요] 아래 repository 값은 모든 앱이 공유하는 '중앙 인프라 리포지토리' 주소이다. + repository: 33-Auto/Sampoom-Management-Infra + event-type: deploy + # 'Sampoom-Management-Backend-Part'은 스크립트가 동적으로 치환할 자리표시자(placeholder)이다. + client-payload: '{"service":"Sampoom-Management-Backend-Part","branch":"main"}' \ No newline at end of file diff --git a/.gitignore b/.gitignore index c2065bc..ae96a77 100644 --- a/.gitignore +++ b/.gitignore @@ -1,37 +1,684 @@ -HELP.md -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ +# Created by https://www.toptal.com/developers/gitignore/api/windows,macos,linux,visualstudiocode,jetbrains,intellij,node,java,gradle,maven,python,go +# Edit at https://www.toptal.com/developers/gitignore?templates=windows,macos,linux,visualstudiocode,jetbrains,intellij,node,java,gradle,maven,python,go -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### IntelliJ IDEA ### -.idea +### Go ### +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format *.iws -*.iml -*.ipr + +# IntelliJ out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +### JetBrains ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# AWS User-specific + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# SonarLint plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### JetBrains Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Maven ### +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/takari/maven-wrapper#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar + +# Eclipse m2e generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +### Node ### +# Logs +logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Gradle ### +.gradle +**/build/ +!src/**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Avoid ignore Gradle wrappper properties +!gradle-wrapper.properties + +# Cache of project +.gradletasknamecache + +# Eclipse Gradle plugin generated files +# Eclipse Core +# JDT-specific (Eclipse Java Development Tools) + +### Gradle Patch ### +# Java heap dump +*.hprof + +# End of https://www.toptal.com/developers/gitignore/api/windows,macos,linux,visualstudiocode,jetbrains,intellij,node,java,gradle,maven,python,go diff --git a/build.gradle b/build.gradle index 96f2f84..a0cfd7a 100644 --- a/build.gradle +++ b/build.gradle @@ -39,6 +39,8 @@ dependencies { // PostgreSQL 드라이버 runtimeOnly 'org.postgresql:postgresql' + + implementation 'com.opencsv:opencsv:5.7.1' } tasks.named('test') { diff --git a/src/main/java/com/sampoom/backend/BackendApplication.java b/src/main/java/com/sampoom/backend/BackendApplication.java index fe7b8a0..e075d46 100644 --- a/src/main/java/com/sampoom/backend/BackendApplication.java +++ b/src/main/java/com/sampoom/backend/BackendApplication.java @@ -1,8 +1,11 @@ package com.sampoom.backend; import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +@EnableJpaAuditing @SpringBootApplication public class BackendApplication { diff --git a/src/main/java/com/sampoom/backend/api/controller/PartController.java b/src/main/java/com/sampoom/backend/api/controller/PartController.java new file mode 100644 index 0000000..6cef376 --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/controller/PartController.java @@ -0,0 +1,99 @@ +package com.sampoom.backend.api.controller; + +import com.sampoom.backend.api.dto.*; +import com.sampoom.backend.api.service.PartService; +import com.sampoom.backend.common.response.ApiResponse; +import com.sampoom.backend.common.response.SuccessStatus; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Tag(name = "Part", description = "부품 API") +@Slf4j +@RestController +@RequestMapping() +@RequiredArgsConstructor +public class PartController { + + private final PartService partService; + + @Operation(summary = "카테고리 목록 조회", description = "카테고리 목록 조회") + @GetMapping("/categories") + public ResponseEntity>> getCategories() { + + List categoryList = partService.findAllCategories(); + + return ApiResponse.success(SuccessStatus.CATEGORY_LIST_SUCCESS, categoryList); + } + + @Operation(summary = "그룹 목록 조회", description = "카테고리에 속한 그룹 목록 조회") + @GetMapping("/categories/{categoryId}/groups") + public ResponseEntity>> getGroups(@PathVariable Long categoryId) { + + List groupList = partService.findGroupsByCategoryId(categoryId); + + return ApiResponse.success(SuccessStatus.GROUP_LIST_SUCCESS, groupList); + } + + @Operation(summary = "부품 목록 조회", description = "특정 그룹에 속한 부품 목록 조회") + @GetMapping + public ResponseEntity>> getPartsByGroup(@RequestParam Long groupId) { + + List partList = partService.findPartsByGroupId(groupId); + + return ApiResponse.success(SuccessStatus.PART_LIST_SUCCESS, partList); + } + + @Operation(summary = "부품 등록", description = "새로운 부품을 등록") + @PostMapping + public ResponseEntity> createPart( + @Valid @RequestBody PartCreateRequestDTO partCreateRequestDTO + ) { + PartResponseDTO partResponse = partService.createPart(partCreateRequestDTO); + + return ApiResponse.success(SuccessStatus.PART_CREATE_SUCCESS, partResponse); + } + + @Operation(summary = "부품 수정", description = "부품을 수정") + @PutMapping("/{partId}") + public ResponseEntity> updatePart( + @PathVariable Long partId, + @Valid @RequestBody PartUpdateRequestDTO partUpdateRequestDTO + ) { + PartResponseDTO partResponse = partService.updatePart(partId, partUpdateRequestDTO); + + return ApiResponse.success(SuccessStatus.PART_UPDATE_SUCCESS, partResponse); + } + + @Operation(summary = "부품 삭제", description = "부품 삭제") + @DeleteMapping("/{partId}") + public ResponseEntity> deletePart(@PathVariable Long partId) { + + partService.deletePart(partId); + + return ApiResponse.success(SuccessStatus.PART_DELETE_SUCCESS, null); + } + + @Operation(summary = "부품 검색", description = "부품 검색 (부품코드, 부품명)") + @GetMapping("/search") + public ResponseEntity>> searchParts(@RequestParam String keyword) { + + List partList = partService.searchParts(keyword); + + return ApiResponse.success(SuccessStatus.PART_SEARCH_SUCCESS, partList); + } + + @Operation(summary = "단일 부품 조회", description = "부품 ID로 부품 상세 정보를 조회합니다.") + @GetMapping("/{partId}") + public ResponseEntity> getPartById(@PathVariable Long partId) { + PartResponseDTO partResponse = partService.findPartById(partId); + return ApiResponse.success(SuccessStatus.PART_DETAIL_SUCCESS, partResponse); + } + +} diff --git a/src/main/java/com/sampoom/backend/api/domain/Category.java b/src/main/java/com/sampoom/backend/api/domain/Category.java new file mode 100644 index 0000000..00f1bc6 --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/domain/Category.java @@ -0,0 +1,27 @@ +package com.sampoom.backend.api.domain; + +import com.sampoom.backend.common.entitiy.BaseTimeEntity; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor +@Table(name = "category") +public class Category extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + private String code; + + // CSV 로더가 사용할 생성자 + public Category(String code, String name) { + this.code = code; + this.name = name; + } +} diff --git a/src/main/java/com/sampoom/backend/api/domain/CategoryRepository.java b/src/main/java/com/sampoom/backend/api/domain/CategoryRepository.java new file mode 100644 index 0000000..a8756f5 --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/domain/CategoryRepository.java @@ -0,0 +1,11 @@ +package com.sampoom.backend.api.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface CategoryRepository extends JpaRepository { + + // 코드로 카테고리를 찾기 위한 메서드 + Optional findByCode(String code); +} diff --git a/src/main/java/com/sampoom/backend/api/domain/Part.java b/src/main/java/com/sampoom/backend/api/domain/Part.java new file mode 100644 index 0000000..4d12ff9 --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/domain/Part.java @@ -0,0 +1,64 @@ +package com.sampoom.backend.api.domain; + +import com.sampoom.backend.api.dto.PartCreateRequestDTO; +import com.sampoom.backend.api.dto.PartUpdateRequestDTO; +import com.sampoom.backend.common.entitiy.BaseTimeEntity; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor +@Table(name = "part") +public class Part extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, unique = true) + private String code; // 부품 코드 + + private String name; // 부품명 + + + @Enumerated(EnumType.STRING) + private PartStatus status; // 단종 + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "group_id", nullable = false) + private PartGroup partGroup; // PartGroup 엔티티와 N:1 관계 + + // CSV 로더가 사용할 생성자 + public Part(String code, String name, PartGroup partGroup) { + this.code = code; + this.name = name; + this.partGroup = partGroup; + this.status = PartStatus.ACTIVE; + } + + // 생성 메서드 + public static Part create(PartCreateRequestDTO partCreateRequestDTO, PartGroup partGroup) { + Part part = new Part(); + part.code = partCreateRequestDTO.getCode(); + part.name = partCreateRequestDTO.getName(); + part.partGroup = partGroup; // 연관관계 설정 + part.status = PartStatus.ACTIVE; + + return part; + } + + // 수정 메서드 + public void update(PartUpdateRequestDTO partUpdateRequestDTO) { + // 이름이 null이 아닐 경우에만 수정 + if (partUpdateRequestDTO.getName() != null) { + this.name = partUpdateRequestDTO.getName(); + } + } + + // 단종 메서드 + public void delete() { + this.status = PartStatus.DISCONTINUED; + } +} diff --git a/src/main/java/com/sampoom/backend/api/domain/PartGroup.java b/src/main/java/com/sampoom/backend/api/domain/PartGroup.java new file mode 100644 index 0000000..7a84082 --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/domain/PartGroup.java @@ -0,0 +1,32 @@ +package com.sampoom.backend.api.domain; + +import com.sampoom.backend.common.entitiy.BaseTimeEntity; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor +@Table(name = "part_group") +public class PartGroup extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + private String code; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "category_id", nullable = false) + private Category category; // Category 엔티티와 N:1 관계 + + // CSV 로더가 사용할 생성자 + public PartGroup(String code, String name, Category category) { + this.code = code; + this.name = name; + this.category = category; + } +} diff --git a/src/main/java/com/sampoom/backend/api/domain/PartGroupRepository.java b/src/main/java/com/sampoom/backend/api/domain/PartGroupRepository.java new file mode 100644 index 0000000..40116f9 --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/domain/PartGroupRepository.java @@ -0,0 +1,15 @@ +package com.sampoom.backend.api.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Optional; + +public interface PartGroupRepository extends JpaRepository { + + // 카테고리 id로 모든 그룹 찾는 메서드 + List findByCategoryId(Long categoryId); + + // 카테고리와 코드로 그룹을 찾기 위한 메서드 + Optional findByCodeAndCategory(String code, Category category); +} diff --git a/src/main/java/com/sampoom/backend/api/domain/PartRepository.java b/src/main/java/com/sampoom/backend/api/domain/PartRepository.java new file mode 100644 index 0000000..dc27055 --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/domain/PartRepository.java @@ -0,0 +1,18 @@ +package com.sampoom.backend.api.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +public interface PartRepository extends JpaRepository { + + // 그룹 ID로 모든 부품을 찾는 메서드 + List findByPartGroupId(Long groupId); + + List findByPartGroupIdAndStatus(Long groupId, PartStatus status); + + @Query("SELECT p FROM Part p WHERE (p.code LIKE %:keyword% OR p.name LIKE %:keyword%) AND p.status = 'ACTIVE'") + List searchByKeyword(@Param("keyword") String keyword); +} diff --git a/src/main/java/com/sampoom/backend/api/domain/PartStatus.java b/src/main/java/com/sampoom/backend/api/domain/PartStatus.java new file mode 100644 index 0000000..5d66ceb --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/domain/PartStatus.java @@ -0,0 +1,6 @@ +package com.sampoom.backend.api.domain; + +public enum PartStatus { + ACTIVE, // 판매중 + DISCONTINUED, // 단종 +} diff --git a/src/main/java/com/sampoom/backend/api/dto/CategoryResponseDTO.java b/src/main/java/com/sampoom/backend/api/dto/CategoryResponseDTO.java new file mode 100644 index 0000000..7d379be --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/dto/CategoryResponseDTO.java @@ -0,0 +1,16 @@ +package com.sampoom.backend.api.dto; + +import com.sampoom.backend.api.domain.Category; +import lombok.Getter; + +@Getter +public class CategoryResponseDTO { + + private Long categoryId; + private String name; + + public CategoryResponseDTO(Category category) { + this.categoryId = category.getId(); + this.name = category.getName(); + } +} diff --git a/src/main/java/com/sampoom/backend/api/dto/PartCreateRequestDTO.java b/src/main/java/com/sampoom/backend/api/dto/PartCreateRequestDTO.java new file mode 100644 index 0000000..5ef323a --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/dto/PartCreateRequestDTO.java @@ -0,0 +1,22 @@ +package com.sampoom.backend.api.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class PartCreateRequestDTO { + + @NotNull(message = "소속될 그룹 ID는 필수입니다.") + private Long groupId; + + @NotBlank(message = "부품 코드는 필수입니다.") + private String code; + + @NotBlank(message = "부품 이름은 필수입니다.") + private String name; +} diff --git a/src/main/java/com/sampoom/backend/api/dto/PartGroupResponseDTO.java b/src/main/java/com/sampoom/backend/api/dto/PartGroupResponseDTO.java new file mode 100644 index 0000000..606dfa7 --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/dto/PartGroupResponseDTO.java @@ -0,0 +1,18 @@ +package com.sampoom.backend.api.dto; + +import com.sampoom.backend.api.domain.PartGroup; +import lombok.Getter; + +@Getter +public class PartGroupResponseDTO { + + private Long groupId; + private String name; + private Long categoryId; + + public PartGroupResponseDTO(PartGroup partGroup) { + this.groupId = partGroup.getId(); + this.name = partGroup.getName(); + this.categoryId = partGroup.getCategory().getId(); + } +} diff --git a/src/main/java/com/sampoom/backend/api/dto/PartResponseDTO.java b/src/main/java/com/sampoom/backend/api/dto/PartResponseDTO.java new file mode 100644 index 0000000..61fadf0 --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/dto/PartResponseDTO.java @@ -0,0 +1,21 @@ +package com.sampoom.backend.api.dto; + +import com.sampoom.backend.api.domain.Part; +import com.sampoom.backend.api.domain.PartGroup; +import lombok.Getter; + +@Getter +public class PartResponseDTO { + + private Long partId; + private String name; + private String code; + private Long groupId; + + public PartResponseDTO(Part part) { + this.partId = part.getId(); + this.name = part.getName(); + this.code = part.getCode(); + this.groupId = part.getPartGroup().getId(); + } +} diff --git a/src/main/java/com/sampoom/backend/api/dto/PartUpdateRequestDTO.java b/src/main/java/com/sampoom/backend/api/dto/PartUpdateRequestDTO.java new file mode 100644 index 0000000..81038ec --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/dto/PartUpdateRequestDTO.java @@ -0,0 +1,22 @@ +package com.sampoom.backend.api.dto; + +import com.sampoom.backend.api.domain.PartStatus; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class PartUpdateRequestDTO { + + private String name; + private PartStatus status; + + public void update(PartUpdateRequestDTO partUpdateRequestDTO) { + + if (partUpdateRequestDTO.getStatus() != null) { + this.status = partUpdateRequestDTO.getStatus(); + } + } +} diff --git a/src/main/java/com/sampoom/backend/api/service/PartService.java b/src/main/java/com/sampoom/backend/api/service/PartService.java new file mode 100644 index 0000000..26f8d61 --- /dev/null +++ b/src/main/java/com/sampoom/backend/api/service/PartService.java @@ -0,0 +1,112 @@ +package com.sampoom.backend.api.service; + +import com.sampoom.backend.api.domain.*; +import com.sampoom.backend.api.dto.*; +import com.sampoom.backend.common.exception.NotFoundException; +import com.sampoom.backend.common.response.ErrorStatus; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class PartService { + + private final PartRepository partRepository; + private final PartGroupRepository partGroupRepository; + private final CategoryRepository categoryRepository; + + // 카테고리 목록 조회 + @Transactional + public List findAllCategories() { + + List categories = categoryRepository.findAll(); + + return categories.stream() + .map(CategoryResponseDTO::new) + .collect(Collectors.toList()); + } + + // 카테고리에 속한 그룹 목록 조회 + @Transactional + public List findGroupsByCategoryId(Long categoryId) { + + List partGroups = partGroupRepository.findByCategoryId(categoryId); + + return partGroups.stream() + .map(PartGroupResponseDTO::new) + .collect(Collectors.toList()); + } + + + // 특정 그룹에 속한 부품 목록 조회 + @Transactional + public List findPartsByGroupId(Long groupId) { + + List parts = partRepository.findByPartGroupIdAndStatus(groupId, PartStatus.ACTIVE); + + return parts.stream() + .map(PartResponseDTO::new) + .collect(Collectors.toList()); + } + + // 신규 부품 생성 + @Transactional + public PartResponseDTO createPart(PartCreateRequestDTO partCreateRequestDTO) { + + // DTO에 담겨온 groupId로 PartGroup 엔티티 조회 + PartGroup partGroup = partGroupRepository.findById(partCreateRequestDTO.getGroupId()) + .orElseThrow(() -> new NotFoundException(ErrorStatus.GROUP_NOT_FOUND.getMessage())); + + Part newPart = Part.create(partCreateRequestDTO, partGroup); + partRepository.save(newPart); + + return new PartResponseDTO(newPart); + } + + // 부품 수정 + @Transactional + public PartResponseDTO updatePart(Long partId, PartUpdateRequestDTO partUpdateRequestDTO) { + // 수정할 부품을 조회 + Part part = partRepository.findById(partId) + .orElseThrow(() -> new NotFoundException(ErrorStatus.PART_NOT_FOUND.getMessage())); + + part.update(partUpdateRequestDTO); + + return new PartResponseDTO(part); + } + + // 부품 삭제 + @Transactional + public void deletePart(Long partId) { + + // 삭제할 부품 조회 + Part part = partRepository.findById(partId) + .orElseThrow(() -> new NotFoundException(ErrorStatus.PART_NOT_FOUND.getMessage())); + + part.delete(); + } + + // 부품 검색 + @Transactional + public List searchParts(String keyword) { + + List parts = partRepository.searchByKeyword(keyword); + + return parts.stream() + .map(PartResponseDTO::new) + .collect(Collectors.toList()); + } + + // 단일 부품 조회 + @Transactional + public PartResponseDTO findPartById(Long partId) { + Part part = partRepository.findById(partId) + .orElseThrow(() -> new NotFoundException(ErrorStatus.PART_NOT_FOUND.getMessage())); + + return new PartResponseDTO(part); + } +} diff --git a/src/main/java/com/sampoom/backend/common/config/CsvDataLoader.java b/src/main/java/com/sampoom/backend/common/config/CsvDataLoader.java new file mode 100644 index 0000000..e0c0c5b --- /dev/null +++ b/src/main/java/com/sampoom/backend/common/config/CsvDataLoader.java @@ -0,0 +1,77 @@ +package com.sampoom.backend.common.config; + +import com.sampoom.backend.api.domain.*; +import com.opencsv.CSVReader; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.CommandLineRunner; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + + +@Component +@RequiredArgsConstructor +public class CsvDataLoader implements CommandLineRunner { + + private final CategoryRepository categoryRepository; + private final PartGroupRepository partGroupRepository; + private final PartRepository partRepository; + + @Override + @Transactional + public void run(String... args) throws Exception { + if (partRepository.count() > 0) { // 데이터 이미 존재하면 건너뜀 + return; + } + + // 데이터 임포트 시작 + + final int CATEGORY_CODE = 1; + final int CATEGORY_NAME = 2; + final int GROUP_CODE = 3; + final int GROUP_NAME = 4; + final int PART_CODE = 5; + final int PART_NAME = 6; + + ClassPathResource resource = new ClassPathResource("data/parts.csv"); + + try (CSVReader reader = new CSVReader(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))) { + reader.readNext(); // 헤더 행 건너뛰기 + + String[] line; + Map categoryCache = new HashMap<>(); + Map groupCache = new HashMap<>(); + + while ((line = reader.readNext()) != null) { + final String[] currentLine = line; + + String categoryCode = currentLine[CATEGORY_CODE]; + Category category = categoryCache.computeIfAbsent(categoryCode, code -> + categoryRepository.findByCode(code).orElseGet(() -> + categoryRepository.save(new Category(code, currentLine[CATEGORY_NAME])) + ) + ); + + String groupCode = currentLine[GROUP_CODE]; + + String compositeGroupKey = categoryCode + "-" + groupCode; // 그룹코드만 하면 중복되니깐 '카테고리코드-그룹코드' + + PartGroup partGroup = groupCache.computeIfAbsent(compositeGroupKey, key -> + partGroupRepository.findByCodeAndCategory(groupCode, category).orElseGet(() -> + partGroupRepository.save(new PartGroup(groupCode, currentLine[GROUP_NAME], category)) + ) + ); + + Part part = new Part(currentLine[PART_CODE], currentLine[PART_NAME], partGroup); + partRepository.save(part); + } + } + + System.out.println(">>>> CSV 데이터 임포트 완료. " + partRepository.count() + "개의 부품이 생성"); + } +} \ No newline at end of file diff --git a/src/main/java/com/sampoom/backend/common/exception/BadRequestException.java b/src/main/java/com/sampoom/backend/common/exception/BadRequestException.java index c3a1ef1..fb224fa 100644 --- a/src/main/java/com/sampoom/backend/common/exception/BadRequestException.java +++ b/src/main/java/com/sampoom/backend/common/exception/BadRequestException.java @@ -1,5 +1,6 @@ package com.sampoom.backend.common.exception; +import com.sampoom.backend.common.response.ErrorStatus; import org.springframework.http.HttpStatus; public class BadRequestException extends BaseException { @@ -11,4 +12,8 @@ public BadRequestException(String message) { super(HttpStatus.BAD_REQUEST, message); } + public BadRequestException(ErrorStatus errorStatus) { + super(errorStatus.getHttpStatus(), errorStatus.getMessage(), errorStatus.getCode()); + } + } diff --git a/src/main/java/com/sampoom/backend/common/exception/BaseException.java b/src/main/java/com/sampoom/backend/common/exception/BaseException.java index 27a4bac..6ce9e93 100644 --- a/src/main/java/com/sampoom/backend/common/exception/BaseException.java +++ b/src/main/java/com/sampoom/backend/common/exception/BaseException.java @@ -10,6 +10,14 @@ public class BaseException extends RuntimeException { HttpStatus statusCode; String responseMessage; + int errorCode; + + public BaseException(HttpStatus statusCode, String responseMessage, int errorCode) { + super(responseMessage); + this.statusCode = statusCode; + this.responseMessage = responseMessage; + this.errorCode = errorCode; + } public BaseException(HttpStatus statusCode) { super(); diff --git a/src/main/java/com/sampoom/backend/common/exception/ForbiddenException.java b/src/main/java/com/sampoom/backend/common/exception/ForbiddenException.java index 6d9b147..ea13e0b 100644 --- a/src/main/java/com/sampoom/backend/common/exception/ForbiddenException.java +++ b/src/main/java/com/sampoom/backend/common/exception/ForbiddenException.java @@ -1,5 +1,6 @@ package com.sampoom.backend.common.exception; +import com.sampoom.backend.common.response.ErrorStatus; import org.springframework.http.HttpStatus; public class ForbiddenException extends BaseException { @@ -10,4 +11,8 @@ public ForbiddenException() { public ForbiddenException(String message) { super(HttpStatus.FORBIDDEN, message); } + + public ForbiddenException(ErrorStatus errorStatus) { + super(errorStatus.getHttpStatus(), errorStatus.getMessage(), errorStatus.getCode()); + } } diff --git a/src/main/java/com/sampoom/backend/common/exception/GlobalExceptionHandler.java b/src/main/java/com/sampoom/backend/common/exception/GlobalExceptionHandler.java index 47ed32a..fe99c2e 100644 --- a/src/main/java/com/sampoom/backend/common/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/sampoom/backend/common/exception/GlobalExceptionHandler.java @@ -15,7 +15,7 @@ public class GlobalExceptionHandler { @ExceptionHandler(BaseException.class) public ResponseEntity> handleBaseException(BaseException e) { return ResponseEntity.status(e.getStatusCode()) - .body(ApiResponse.fail(e.getStatusCode(), e.getResponseMessage())); + .body(ApiResponse.errorWithCode(e.getErrorCode(), e.getResponseMessage())); } @ExceptionHandler(RuntimeException.class) @@ -23,7 +23,7 @@ public ResponseEntity> handleRuntimeException(RuntimeException log.error(e.getMessage(), e); return ResponseEntity .status(HttpStatus.INTERNAL_SERVER_ERROR) - .body(ApiResponse.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), "런타임 오류가 발생했습니다.")); + .body(ApiResponse.errorWithCode(20500, "런타임 오류가 발생했습니다.")); } @ExceptionHandler(MethodArgumentNotValidException.class) @@ -31,7 +31,7 @@ public ResponseEntity> handleValidationException(MethodArgumen String errorMessage = e.getBindingResult().getAllErrors().get(0).getDefaultMessage(); return ResponseEntity .status(HttpStatus.BAD_REQUEST) - .body(ApiResponse.fail(HttpStatus.BAD_REQUEST.value(), errorMessage)); + .body(ApiResponse.errorWithCode(20000, errorMessage)); } } diff --git a/src/main/java/com/sampoom/backend/common/exception/NotFoundException.java b/src/main/java/com/sampoom/backend/common/exception/NotFoundException.java index 050b964..47de643 100644 --- a/src/main/java/com/sampoom/backend/common/exception/NotFoundException.java +++ b/src/main/java/com/sampoom/backend/common/exception/NotFoundException.java @@ -1,5 +1,6 @@ package com.sampoom.backend.common.exception; +import com.sampoom.backend.common.response.ErrorStatus; import org.springframework.http.HttpStatus; public class NotFoundException extends BaseException { @@ -10,4 +11,8 @@ public NotFoundException() { public NotFoundException(String message) { super(HttpStatus.NOT_FOUND, message); } + + public NotFoundException(ErrorStatus errorStatus) { + super(errorStatus.getHttpStatus(), errorStatus.getMessage(), errorStatus.getCode()); + } } diff --git a/src/main/java/com/sampoom/backend/common/exception/UnauthorizedException.java b/src/main/java/com/sampoom/backend/common/exception/UnauthorizedException.java index d514e49..cab220b 100644 --- a/src/main/java/com/sampoom/backend/common/exception/UnauthorizedException.java +++ b/src/main/java/com/sampoom/backend/common/exception/UnauthorizedException.java @@ -1,5 +1,6 @@ package com.sampoom.backend.common.exception; +import com.sampoom.backend.common.response.ErrorStatus; import org.springframework.http.HttpStatus; public class UnauthorizedException extends BaseException { @@ -10,4 +11,8 @@ public UnauthorizedException() { public UnauthorizedException(String message) { super(HttpStatus.UNAUTHORIZED, message); } + + public UnauthorizedException(ErrorStatus errorStatus) { + super(errorStatus.getHttpStatus(), errorStatus.getMessage(), errorStatus.getCode()); + } } diff --git a/src/main/java/com/sampoom/backend/common/response/ApiResponse.java b/src/main/java/com/sampoom/backend/common/response/ApiResponse.java index f48adc2..2723119 100644 --- a/src/main/java/com/sampoom/backend/common/response/ApiResponse.java +++ b/src/main/java/com/sampoom/backend/common/response/ApiResponse.java @@ -10,8 +10,9 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public class ApiResponse { - private final int status; - private final boolean success; + private final Integer status; + private final Boolean success; + private final Integer code; private final String message; private T data; @@ -50,4 +51,12 @@ public static ApiResponse fail(int status, String message) { .build(); } + // 새로운 에러 응답 형식을 위한 메서드 추가 + public static ApiResponse errorWithCode(int code, String message) { + return ApiResponse.builder() + .code(code) + .message(message) + .build(); + } + } diff --git a/src/main/java/com/sampoom/backend/common/response/ErrorStatus.java b/src/main/java/com/sampoom/backend/common/response/ErrorStatus.java index b65ade7..e17884a 100644 --- a/src/main/java/com/sampoom/backend/common/response/ErrorStatus.java +++ b/src/main/java/com/sampoom/backend/common/response/ErrorStatus.java @@ -10,30 +10,30 @@ public enum ErrorStatus { // 400 BAD_REQUEST - BAD_REQUEST(HttpStatus.BAD_REQUEST, "잘못된 요청입니다."), - MISSING_EMAIL_VERIFICATION_EXCEPTION(HttpStatus.BAD_REQUEST, "이메일 인증을 진행해주세요."), - ALREADY_REGISTER_EMAIL_EXCEPETION(HttpStatus.BAD_REQUEST, "이미 가입된 이메일 입니다."), - + BAD_REQUEST(HttpStatus.BAD_REQUEST, "잘못된 요청입니다.", 30000), // 401 UNAUTHORIZED - UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "인증이 필요합니다."), + UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "인증이 필요합니다.", 10401), // 403 FORBIDDEN - FORBIDDEN(HttpStatus.FORBIDDEN, "접근 권한이 없습니다."), + FORBIDDEN(HttpStatus.FORBIDDEN, "접근 권한이 없습니다.",10406), // 404 NOT_FOUND - NOT_FOUND(HttpStatus.NOT_FOUND, "요청한 리소스를 찾을 수 없습니다."), - - + NOT_FOUND(HttpStatus.NOT_FOUND, "요청한 리소스를 찾을 수 없습니다.", 30400), + CATEGORY_NOT_FOUND(HttpStatus.NOT_FOUND, "카테고리를 찾을 수 없습니다.", 30401), + GROUP_NOT_FOUND(HttpStatus.NOT_FOUND, "그룹을 찾을 수 없습니다.", 30402), + PART_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 부품을 찾을 수 없습니다.", 30403), // 409 CONFLICT - CONFLICT(HttpStatus.CONFLICT, "충돌이 발생했습니다."), + CONFLICT(HttpStatus.CONFLICT, "충돌이 발생했습니다.",30900), + PART_CODE_DUPLICATED(HttpStatus.CONFLICT, "이미 존재하는 부품 코드입니다.", 30901), // 500 INTERNAL_SERVER_ERROR - INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류가 발생했습니다."); + INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "서버 오류가 발생했습니다.", 10500); private final HttpStatus httpStatus; private final String message; + private final int code; public int getStatusCode() { return this.httpStatus.value(); diff --git a/src/main/java/com/sampoom/backend/common/response/SuccessStatus.java b/src/main/java/com/sampoom/backend/common/response/SuccessStatus.java index c640fb7..286ac4c 100644 --- a/src/main/java/com/sampoom/backend/common/response/SuccessStatus.java +++ b/src/main/java/com/sampoom/backend/common/response/SuccessStatus.java @@ -11,7 +11,20 @@ public enum SuccessStatus { // 공통 성공 메시지 OK(HttpStatus.OK, "요청이 성공적으로 처리되었습니다."), - CREATED(HttpStatus.CREATED, "리소스가 성공적으로 생성되었습니다.") + CREATED(HttpStatus.CREATED, "리소스가 성공적으로 생성되었습니다."), + + /** + * 200 + */ + CATEGORY_LIST_SUCCESS(HttpStatus.OK, "카테고리 목록 조회 성공"), + GROUP_LIST_SUCCESS(HttpStatus.OK, "그룹 목록 조회 성공"), + PART_LIST_SUCCESS(HttpStatus.OK, "부품 목록 조회 성공"), + PART_CREATE_SUCCESS(HttpStatus.OK, "부품 생성 성공"), + PART_UPDATE_SUCCESS(HttpStatus.OK, "부품 수정 성공"), + PART_DELETE_SUCCESS(HttpStatus.OK, "부품 삭제 성공"), + PART_SEARCH_SUCCESS(HttpStatus.OK, "부품 검색 성공"), + PART_DETAIL_SUCCESS(HttpStatus.OK, "부품 상세 조회 성공"), + ; diff --git a/src/main/resources/data/parts.csv b/src/main/resources/data/parts.csv new file mode 100644 index 0000000..540d23f --- /dev/null +++ b/src/main/resources/data/parts.csv @@ -0,0 +1,701 @@ +id,category_code,category_name,group_code,group_name,part_no,name +1,ENG,엔진,1,흡기,ENG-01-001,인테이크 매니폴드 +2,ENG,엔진,2,배기,ENG-02-001,배기관 +3,ENG,엔진,3,연료,ENG-03-001,연료레일 +4,ENG,엔진,4,냉각,ENG-04-001,리저버탱크 +5,ENG,엔진,5,윤활,ENG-05-001,오일펌프 +6,ENG,엔진,6,점화,ENG-06-001,점화코일 +7,ENG,엔진,1,흡기,ENG-01-002,매스에어플로우센서 +8,ENG,엔진,2,배기,ENG-02-002,머플러 +9,ENG,엔진,3,연료,ENG-03-002,인젝터 +10,ENG,엔진,4,냉각,ENG-04-002,라디에이터호스 +11,ENG,엔진,5,윤활,ENG-05-002,오일펌프 +12,ENG,엔진,6,점화,ENG-06-002,이그니션스위치 +13,ENG,엔진,1,흡기,ENG-01-003,스로틀바디 +14,ENG,엔진,2,배기,ENG-02-003,머플러 +15,ENG,엔진,3,연료,ENG-03-003,연료펌프 +16,ENG,엔진,4,냉각,ENG-04-003,냉각팬모터 +17,ENG,엔진,5,윤활,ENG-05-003,오일게이지 +18,ENG,엔진,6,점화,ENG-06-003,점화코일 +19,ENG,엔진,1,흡기,ENG-01-004,스로틀바디 +20,ENG,엔진,2,배기,ENG-02-004,머플러 +21,ENG,엔진,3,연료,ENG-03-004,연료차단밸브 +22,ENG,엔진,4,냉각,ENG-04-004,냉각팬모터 +23,ENG,엔진,5,윤활,ENG-05-004,오일펌프 +24,ENG,엔진,6,점화,ENG-06-004,이그니션스위치 +25,ENG,엔진,1,흡기,ENG-01-005,에어필터 +26,ENG,엔진,2,배기,ENG-02-005,배기관 +27,ENG,엔진,3,연료,ENG-03-005,고압펌프 +28,ENG,엔진,4,냉각,ENG-04-005,리저버탱크 +29,ENG,엔진,5,윤활,ENG-05-005,오일쿨러 +30,ENG,엔진,6,점화,ENG-06-005,점화코일 +31,ENG,엔진,1,흡기,ENG-01-006,매스에어플로우센서 +32,ENG,엔진,2,배기,ENG-02-006,플렉시블조인트 +33,ENG,엔진,3,연료,ENG-03-006,연료레일 +34,ENG,엔진,4,냉각,ENG-04-006,라디에이터 +35,ENG,엔진,5,윤활,ENG-05-006,오일필터 +36,ENG,엔진,6,점화,ENG-06-006,점화코일 +37,ENG,엔진,1,흡기,ENG-01-007,매스에어플로우센서 +38,ENG,엔진,2,배기,ENG-02-007,배기관 +39,ENG,엔진,3,연료,ENG-03-007,인젝터 +40,ENG,엔진,4,냉각,ENG-04-007,냉각팬모터 +41,ENG,엔진,5,윤활,ENG-05-007,오일필터 +42,ENG,엔진,6,점화,ENG-06-007,이그니션스위치 +43,ENG,엔진,1,흡기,ENG-01-008,에어필터 +44,ENG,엔진,2,배기,ENG-02-008,플렉시블조인트 +45,ENG,엔진,3,연료,ENG-03-008,인젝터 +46,ENG,엔진,4,냉각,ENG-04-008,라디에이터호스 +47,ENG,엔진,5,윤활,ENG-05-008,오일필터 +48,ENG,엔진,6,점화,ENG-06-008,점화코일 +49,ENG,엔진,1,흡기,ENG-01-009,매스에어플로우센서 +50,ENG,엔진,2,배기,ENG-02-009,플렉시블조인트 +51,ENG,엔진,3,연료,ENG-03-009,고압펌프 +52,ENG,엔진,4,냉각,ENG-04-009,워터펌프 +53,ENG,엔진,5,윤활,ENG-05-009,오일팬 +54,ENG,엔진,6,점화,ENG-06-009,점화코일 +55,ENG,엔진,1,흡기,ENG-01-010,매스에어플로우센서 +56,ENG,엔진,2,배기,ENG-02-010,산소센서 +57,ENG,엔진,3,연료,ENG-03-010,연료펌프 +58,ENG,엔진,4,냉각,ENG-04-010,라디에이터호스 +59,ENG,엔진,5,윤활,ENG-05-010,오일펌프 +60,ENG,엔진,6,점화,ENG-06-010,이그니션스위치 +61,ENG,엔진,1,흡기,ENG-01-011,스로틀바디 +62,ENG,엔진,2,배기,ENG-02-011,가스켓 +63,ENG,엔진,3,연료,ENG-03-011,고압펌프 +64,ENG,엔진,4,냉각,ENG-04-011,라디에이터호스 +65,ENG,엔진,5,윤활,ENG-05-011,오일게이지 +66,ENG,엔진,6,점화,ENG-06-011,플러그와이어 +67,ENG,엔진,1,흡기,ENG-01-012,흡기호스 +68,ENG,엔진,2,배기,ENG-02-012,플렉시블조인트 +69,ENG,엔진,3,연료,ENG-03-012,연료레일 +70,ENG,엔진,4,냉각,ENG-04-012,써모스탯 +71,ENG,엔진,5,윤활,ENG-05-012,오일팬 +72,ENG,엔진,6,점화,ENG-06-012,스파크플러그 +73,ENG,엔진,1,흡기,ENG-01-013,스로틀바디 +74,ENG,엔진,2,배기,ENG-02-013,산소센서 +75,ENG,엔진,3,연료,ENG-03-013,연료필터 +76,ENG,엔진,4,냉각,ENG-04-013,라디에이터 +77,ENG,엔진,5,윤활,ENG-05-013,오일쿨러 +78,ENG,엔진,6,점화,ENG-06-013,플러그와이어 +79,ENG,엔진,1,흡기,ENG-01-014,매스에어플로우센서 +80,ENG,엔진,2,배기,ENG-02-014,가스켓 +81,ENG,엔진,3,연료,ENG-03-014,인젝터 +82,ENG,엔진,4,냉각,ENG-04-014,리저버탱크 +83,ENG,엔진,5,윤활,ENG-05-014,오일게이지 +84,ENG,엔진,6,점화,ENG-06-014,플러그와이어 +85,ENG,엔진,1,흡기,ENG-01-015,매스에어플로우센서 +86,ENG,엔진,2,배기,ENG-02-015,머플러 +87,ENG,엔진,3,연료,ENG-03-015,연료펌프 +88,ENG,엔진,4,냉각,ENG-04-015,라디에이터호스 +89,ENG,엔진,5,윤활,ENG-05-015,오일게이지 +90,ENG,엔진,6,점화,ENG-06-015,스파크플러그 +91,ENG,엔진,1,흡기,ENG-01-016,인테이크 매니폴드 +92,ENG,엔진,2,배기,ENG-02-016,배기관 +93,ENG,엔진,3,연료,ENG-03-016,연료레일 +94,ENG,엔진,4,냉각,ENG-04-016,냉각팬모터 +95,ENG,엔진,5,윤활,ENG-05-016,오일펌프 +96,ENG,엔진,6,점화,ENG-06-016,점화코일 +97,ENG,엔진,1,흡기,ENG-01-017,매스에어플로우센서 +98,ENG,엔진,2,배기,ENG-02-017,플렉시블조인트 +99,ENG,엔진,3,연료,ENG-03-017,인젝터 +100,ENG,엔진,4,냉각,ENG-04-017,써모스탯 +101,ENG,엔진,5,윤활,ENG-05-017,오일팬 +102,ENG,엔진,6,점화,ENG-06-017,이그니션스위치 +103,ENG,엔진,1,흡기,ENG-01-018,흡기호스 +104,ENG,엔진,2,배기,ENG-02-018,플렉시블조인트 +105,ENG,엔진,3,연료,ENG-03-018,연료레일 +106,ENG,엔진,4,냉각,ENG-04-018,라디에이터 +107,ENG,엔진,5,윤활,ENG-05-018,오일펌프 +108,ENG,엔진,6,점화,ENG-06-018,플러그와이어 +109,ENG,엔진,1,흡기,ENG-01-019,흡기호스 +110,ENG,엔진,2,배기,ENG-02-019,산소센서 +111,ENG,엔진,3,연료,ENG-03-019,고압펌프 +112,ENG,엔진,4,냉각,ENG-04-019,라디에이터 +113,ENG,엔진,5,윤활,ENG-05-019,오일펌프 +114,ENG,엔진,6,점화,ENG-06-019,플러그와이어 +115,ENG,엔진,1,흡기,ENG-01-020,인터쿨러 +116,ENG,엔진,2,배기,ENG-02-020,플렉시블조인트 +117,ENG,엔진,3,연료,ENG-03-020,고압펌프 +118,ENG,엔진,4,냉각,ENG-04-020,냉각팬모터 +119,ENG,엔진,5,윤활,ENG-05-020,오일팬 +120,ENG,엔진,6,점화,ENG-06-020,점화모듈 +121,ENG,엔진,1,흡기,ENG-01-021,인터쿨러 +122,ENG,엔진,2,배기,ENG-02-021,촉매변환기 +123,ENG,엔진,3,연료,ENG-03-021,연료펌프 +124,ENG,엔진,4,냉각,ENG-04-021,냉각팬모터 +125,ENG,엔진,5,윤활,ENG-05-021,오일팬 +126,ENG,엔진,6,점화,ENG-06-021,스파크플러그 +127,ENG,엔진,1,흡기,ENG-01-022,매스에어플로우센서 +128,ENG,엔진,2,배기,ENG-02-022,머플러 +129,ENG,엔진,3,연료,ENG-03-022,연료레일 +130,ENG,엔진,4,냉각,ENG-04-022,라디에이터 +131,ENG,엔진,5,윤활,ENG-05-022,오일필터 +132,ENG,엔진,6,점화,ENG-06-022,플러그와이어 +133,ENG,엔진,1,흡기,ENG-01-023,스로틀바디 +134,ENG,엔진,2,배기,ENG-02-023,산소센서 +135,ENG,엔진,3,연료,ENG-03-023,연료필터 +136,ENG,엔진,4,냉각,ENG-04-023,냉각팬모터 +137,ENG,엔진,5,윤활,ENG-05-023,오일게이지 +138,ENG,엔진,6,점화,ENG-06-023,점화모듈 +139,ENG,엔진,1,흡기,ENG-01-024,에어필터 +140,ENG,엔진,2,배기,ENG-02-024,배기관 +141,TRN,트랜스미션,1,기어셋,TRN-01-001,베어링세트 +142,TRN,트랜스미션,2,클러치,TRN-02-001,클러치마스터 +143,TRN,트랜스미션,3,윤활,TRN-03-001,오일씰 +144,TRN,트랜스미션,4,변속제어,TRN-04-001,셀렉터레버 +145,TRN,트랜스미션,1,기어셋,TRN-01-002,메인샤프트 +146,TRN,트랜스미션,2,클러치,TRN-02-002,클러치마스터 +147,TRN,트랜스미션,3,윤활,TRN-03-002,오일씰 +148,TRN,트랜스미션,4,변속제어,TRN-04-002,셀렉터레버 +149,TRN,트랜스미션,1,기어셋,TRN-01-003,피니언기어 +150,TRN,트랜스미션,2,클러치,TRN-02-003,클러치마스터 +151,TRN,트랜스미션,3,윤활,TRN-03-003,가스켓세트 +152,TRN,트랜스미션,4,변속제어,TRN-04-003,시프트케이블 +153,TRN,트랜스미션,1,기어셋,TRN-01-004,메인샤프트 +154,TRN,트랜스미션,2,클러치,TRN-02-004,클러치커버 +155,TRN,트랜스미션,3,윤활,TRN-03-004,ATF오일쿨러 +156,TRN,트랜스미션,4,변속제어,TRN-04-004,밸브바디 +157,TRN,트랜스미션,1,기어셋,TRN-01-005,메인샤프트 +158,TRN,트랜스미션,2,클러치,TRN-02-005,클러치커버 +159,TRN,트랜스미션,3,윤활,TRN-03-005,오일펌프(미션) +160,TRN,트랜스미션,4,변속제어,TRN-04-005,변속솔레노이드 +161,TRN,트랜스미션,1,기어셋,TRN-01-006,베어링세트 +162,TRN,트랜스미션,2,클러치,TRN-02-006,클러치슬레이브 +163,TRN,트랜스미션,3,윤활,TRN-03-006,오일펌프(미션) +164,TRN,트랜스미션,4,변속제어,TRN-04-006,셀렉터레버 +165,TRN,트랜스미션,1,기어셋,TRN-01-007,카운터샤프트 +166,TRN,트랜스미션,2,클러치,TRN-02-007,클러치디스크 +167,TRN,트랜스미션,3,윤활,TRN-03-007,오일펌프(미션) +168,TRN,트랜스미션,4,변속제어,TRN-04-007,시프트케이블 +169,TRN,트랜스미션,1,기어셋,TRN-01-008,동기링 +170,TRN,트랜스미션,2,클러치,TRN-02-008,릴리스베어링 +171,TRN,트랜스미션,3,윤활,TRN-03-008,오일씰 +172,TRN,트랜스미션,4,변속제어,TRN-04-008,포지션센서 +173,TRN,트랜스미션,1,기어셋,TRN-01-009,카운터샤프트 +174,TRN,트랜스미션,2,클러치,TRN-02-009,클러치커버 +175,TRN,트랜스미션,3,윤활,TRN-03-009,오일씰 +176,TRN,트랜스미션,4,변속제어,TRN-04-009,포지션센서 +177,TRN,트랜스미션,1,기어셋,TRN-01-010,피니언기어 +178,TRN,트랜스미션,2,클러치,TRN-02-010,클러치디스크 +179,TRN,트랜스미션,3,윤활,TRN-03-010,오일필터(미션) +180,TRN,트랜스미션,4,변속제어,TRN-04-010,포지션센서 +181,TRN,트랜스미션,1,기어셋,TRN-01-011,베어링세트 +182,TRN,트랜스미션,2,클러치,TRN-02-011,클러치마스터 +183,TRN,트랜스미션,3,윤활,TRN-03-011,오일필터(미션) +184,TRN,트랜스미션,4,변속제어,TRN-04-011,시프트케이블 +185,TRN,트랜스미션,1,기어셋,TRN-01-012,기어세트 +186,TRN,트랜스미션,2,클러치,TRN-02-012,클러치마스터 +187,TRN,트랜스미션,3,윤활,TRN-03-012,오일필터(미션) +188,TRN,트랜스미션,4,변속제어,TRN-04-012,변속솔레노이드 +189,TRN,트랜스미션,1,기어셋,TRN-01-013,메인샤프트 +190,TRN,트랜스미션,2,클러치,TRN-02-013,클러치디스크 +191,TRN,트랜스미션,3,윤활,TRN-03-013,오일펌프(미션) +192,TRN,트랜스미션,4,변속제어,TRN-04-013,시프트케이블 +193,TRN,트랜스미션,1,기어셋,TRN-01-014,메인샤프트 +194,TRN,트랜스미션,2,클러치,TRN-02-014,클러치디스크 +195,TRN,트랜스미션,3,윤활,TRN-03-014,가스켓세트 +196,TRN,트랜스미션,4,변속제어,TRN-04-014,포지션센서 +197,TRN,트랜스미션,1,기어셋,TRN-01-015,기어세트 +198,TRN,트랜스미션,2,클러치,TRN-02-015,클러치디스크 +199,TRN,트랜스미션,3,윤활,TRN-03-015,ATF오일쿨러 +200,TRN,트랜스미션,4,변속제어,TRN-04-015,포지션센서 +201,TRN,트랜스미션,1,기어셋,TRN-01-016,메인샤프트 +202,TRN,트랜스미션,2,클러치,TRN-02-016,클러치슬레이브 +203,TRN,트랜스미션,3,윤활,TRN-03-016,ATF오일쿨러 +204,TRN,트랜스미션,4,변속제어,TRN-04-016,셀렉터레버 +205,TRN,트랜스미션,1,기어셋,TRN-01-017,동기링 +206,TRN,트랜스미션,2,클러치,TRN-02-017,클러치디스크 +207,TRN,트랜스미션,3,윤활,TRN-03-017,ATF오일쿨러 +208,TRN,트랜스미션,4,변속제어,TRN-04-017,밸브바디 +209,TRN,트랜스미션,1,기어셋,TRN-01-018,동기링 +210,TRN,트랜스미션,2,클러치,TRN-02-018,클러치마스터 +211,TRN,트랜스미션,3,윤활,TRN-03-018,오일펌프(미션) +212,TRN,트랜스미션,4,변속제어,TRN-04-018,셀렉터레버 +213,TRN,트랜스미션,1,기어셋,TRN-01-019,카운터샤프트 +214,TRN,트랜스미션,2,클러치,TRN-02-019,클러치슬레이브 +215,TRN,트랜스미션,3,윤활,TRN-03-019,가스켓세트 +216,TRN,트랜스미션,4,변속제어,TRN-04-019,시프트케이블 +217,TRN,트랜스미션,1,기어셋,TRN-01-020,기어세트 +218,TRN,트랜스미션,2,클러치,TRN-02-020,클러치디스크 +219,TRN,트랜스미션,3,윤활,TRN-03-020,오일필터(미션) +220,TRN,트랜스미션,4,변속제어,TRN-04-020,시프트케이블 +221,TRN,트랜스미션,1,기어셋,TRN-01-021,베어링세트 +222,TRN,트랜스미션,2,클러치,TRN-02-021,클러치마스터 +223,TRN,트랜스미션,3,윤활,TRN-03-021,가스켓세트 +224,TRN,트랜스미션,4,변속제어,TRN-04-021,변속솔레노이드 +225,TRN,트랜스미션,1,기어셋,TRN-01-022,메인샤프트 +226,TRN,트랜스미션,2,클러치,TRN-02-022,클러치디스크 +227,TRN,트랜스미션,3,윤활,TRN-03-022,가스켓세트 +228,TRN,트랜스미션,4,변속제어,TRN-04-022,셀렉터레버 +229,TRN,트랜스미션,1,기어셋,TRN-01-023,베어링세트 +230,TRN,트랜스미션,2,클러치,TRN-02-023,클러치커버 +231,TRN,트랜스미션,3,윤활,TRN-03-023,오일씰 +232,TRN,트랜스미션,4,변속제어,TRN-04-023,변속솔레노이드 +233,TRN,트랜스미션,1,기어셋,TRN-01-024,메인샤프트 +234,TRN,트랜스미션,2,클러치,TRN-02-024,클러치슬레이브 +235,TRN,트랜스미션,3,윤활,TRN-03-024,가스켓세트 +236,TRN,트랜스미션,4,변속제어,TRN-04-024,밸브바디 +237,TRN,트랜스미션,1,기어셋,TRN-01-025,피니언기어 +238,TRN,트랜스미션,2,클러치,TRN-02-025,클러치슬레이브 +239,TRN,트랜스미션,3,윤활,TRN-03-025,ATF오일쿨러 +240,TRN,트랜스미션,4,변속제어,TRN-04-025,포지션센서 +241,CHS,샤시,1,서스펜션,CHS-01-001,로워암 +242,CHS,샤시,2,제동,CHS-02-001,브레이크패드 +243,CHS,샤시,3,조향,CHS-03-001,스티어링기어 +244,CHS,샤시,4,휠/허브,CHS-04-001,스페이서 +245,CHS,샤시,1,서스펜션,CHS-01-002,로워암 +246,CHS,샤시,2,제동,CHS-02-002,브레이크디스크 +247,CHS,샤시,3,조향,CHS-03-002,스티어링기어 +248,CHS,샤시,4,휠/허브,CHS-04-002,허브베어링 +249,CHS,샤시,1,서스펜션,CHS-01-003,부싱세트 +250,CHS,샤시,2,제동,CHS-02-003,브레이크마스터 +251,CHS,샤시,3,조향,CHS-03-003,아이들러암 +252,CHS,샤시,4,휠/허브,CHS-04-003,휠너트 +253,CHS,샤시,1,서스펜션,CHS-01-004,어퍼암 +254,CHS,샤시,2,제동,CHS-02-004,브레이크디스크 +255,CHS,샤시,3,조향,CHS-03-004,아이들러암 +256,CHS,샤시,4,휠/허브,CHS-04-004,허브베어링 +257,CHS,샤시,1,서스펜션,CHS-01-005,스프링 +258,CHS,샤시,2,제동,CHS-02-005,브레이크호스 +259,CHS,샤시,3,조향,CHS-03-005,랙앤피니언 +260,CHS,샤시,4,휠/허브,CHS-04-005,허브베어링 +261,CHS,샤시,1,서스펜션,CHS-01-006,부싱세트 +262,CHS,샤시,2,제동,CHS-02-006,브레이크호스 +263,CHS,샤시,3,조향,CHS-03-006,스티어링기어 +264,CHS,샤시,4,휠/허브,CHS-04-006,휠허브 +265,CHS,샤시,1,서스펜션,CHS-01-007,쇽업소버 +266,CHS,샤시,2,제동,CHS-02-007,브레이크캘리퍼 +267,CHS,샤시,3,조향,CHS-03-007,파워스티어링펌프 +268,CHS,샤시,4,휠/허브,CHS-04-007,휠너트 +269,CHS,샤시,1,서스펜션,CHS-01-008,스프링 +270,CHS,샤시,2,제동,CHS-02-008,브레이크마스터 +271,CHS,샤시,3,조향,CHS-03-008,스티어링기어 +272,CHS,샤시,4,휠/허브,CHS-04-008,허브캡 +273,CHS,샤시,1,서스펜션,CHS-01-009,어퍼암 +274,CHS,샤시,2,제동,CHS-02-009,브레이크캘리퍼 +275,CHS,샤시,3,조향,CHS-03-009,스티어링기어 +276,CHS,샤시,4,휠/허브,CHS-04-009,휠허브 +277,CHS,샤시,1,서스펜션,CHS-01-010,스프링 +278,CHS,샤시,2,제동,CHS-02-010,브레이크패드 +279,CHS,샤시,3,조향,CHS-03-010,랙앤피니언 +280,CHS,샤시,4,휠/허브,CHS-04-010,허브캡 +281,CHS,샤시,1,서스펜션,CHS-01-011,스프링 +282,CHS,샤시,2,제동,CHS-02-011,브레이크캘리퍼 +283,CHS,샤시,3,조향,CHS-03-011,랙앤피니언 +284,CHS,샤시,4,휠/허브,CHS-04-011,허브캡 +285,CHS,샤시,1,서스펜션,CHS-01-012,부싱세트 +286,CHS,샤시,2,제동,CHS-02-012,브레이크마스터 +287,CHS,샤시,3,조향,CHS-03-012,타이로드엔드 +288,CHS,샤시,4,휠/허브,CHS-04-012,허브캡 +289,CHS,샤시,1,서스펜션,CHS-01-013,어퍼암 +290,CHS,샤시,2,제동,CHS-02-013,브레이크캘리퍼 +291,CHS,샤시,3,조향,CHS-03-013,타이로드엔드 +292,CHS,샤시,4,휠/허브,CHS-04-013,휠허브 +293,CHS,샤시,1,서스펜션,CHS-01-014,스태빌라이저링크 +294,CHS,샤시,2,제동,CHS-02-014,브레이크디스크 +295,CHS,샤시,3,조향,CHS-03-014,파워스티어링펌프 +296,CHS,샤시,4,휠/허브,CHS-04-014,허브베어링 +297,CHS,샤시,1,서스펜션,CHS-01-015,스태빌라이저링크 +298,CHS,샤시,2,제동,CHS-02-015,브레이크캘리퍼 +299,CHS,샤시,3,조향,CHS-03-015,타이로드엔드 +300,CHS,샤시,4,휠/허브,CHS-04-015,허브캡 +301,CHS,샤시,1,서스펜션,CHS-01-016,스태빌라이저링크 +302,CHS,샤시,2,제동,CHS-02-016,브레이크호스 +303,CHS,샤시,3,조향,CHS-03-016,타이로드엔드 +304,CHS,샤시,4,휠/허브,CHS-04-016,허브베어링 +305,CHS,샤시,1,서스펜션,CHS-01-017,스프링 +306,CHS,샤시,2,제동,CHS-02-017,브레이크디스크 +307,CHS,샤시,3,조향,CHS-03-017,타이로드엔드 +308,CHS,샤시,4,휠/허브,CHS-04-017,허브베어링 +309,CHS,샤시,1,서스펜션,CHS-01-018,부싱세트 +310,CHS,샤시,2,제동,CHS-02-018,브레이크호스 +311,CHS,샤시,3,조향,CHS-03-018,랙앤피니언 +312,CHS,샤시,4,휠/허브,CHS-04-018,스페이서 +313,CHS,샤시,1,서스펜션,CHS-01-019,부싱세트 +314,CHS,샤시,2,제동,CHS-02-019,브레이크호스 +315,CHS,샤시,3,조향,CHS-03-019,스티어링기어 +316,CHS,샤시,4,휠/허브,CHS-04-019,허브베어링 +317,CHS,샤시,1,서스펜션,CHS-01-020,부싱세트 +318,CHS,샤시,2,제동,CHS-02-020,브레이크마스터 +319,CHS,샤시,3,조향,CHS-03-020,랙앤피니언 +320,CHS,샤시,4,휠/허브,CHS-04-020,휠허브 +321,CHS,샤시,1,서스펜션,CHS-01-021,쇽업소버 +322,CHS,샤시,2,제동,CHS-02-021,브레이크패드 +323,CHS,샤시,3,조향,CHS-03-021,아이들러암 +324,CHS,샤시,4,휠/허브,CHS-04-021,허브베어링 +325,CHS,샤시,1,서스펜션,CHS-01-022,스태빌라이저링크 +326,CHS,샤시,2,제동,CHS-02-022,브레이크디스크 +327,CHS,샤시,3,조향,CHS-03-022,랙앤피니언 +328,CHS,샤시,4,휠/허브,CHS-04-022,휠허브 +329,CHS,샤시,1,서스펜션,CHS-01-023,로워암 +330,CHS,샤시,2,제동,CHS-02-023,브레이크디스크 +331,CHS,샤시,3,조향,CHS-03-023,스티어링기어 +332,CHS,샤시,4,휠/허브,CHS-04-023,스페이서 +333,CHS,샤시,1,서스펜션,CHS-01-024,스프링 +334,CHS,샤시,2,제동,CHS-02-024,브레이크마스터 +335,CHS,샤시,3,조향,CHS-03-024,스티어링기어 +336,CHS,샤시,4,휠/허브,CHS-04-024,휠너트 +337,CHS,샤시,1,서스펜션,CHS-01-025,부싱세트 +338,CHS,샤시,2,제동,CHS-02-025,브레이크호스 +339,CHS,샤시,3,조향,CHS-03-025,랙앤피니언 +340,CHS,샤시,4,휠/허브,CHS-04-025,휠허브 +341,CHS,샤시,1,서스펜션,CHS-01-026,어퍼암 +342,CHS,샤시,2,제동,CHS-02-026,브레이크캘리퍼 +343,CHS,샤시,3,조향,CHS-03-026,파워스티어링펌프 +344,CHS,샤시,4,휠/허브,CHS-04-026,스페이서 +345,CHS,샤시,1,서스펜션,CHS-01-027,부싱세트 +346,CHS,샤시,2,제동,CHS-02-027,브레이크호스 +347,CHS,샤시,3,조향,CHS-03-027,아이들러암 +348,CHS,샤시,4,휠/허브,CHS-04-027,허브베어링 +349,CHS,샤시,1,서스펜션,CHS-01-028,부싱세트 +350,CHS,샤시,2,제동,CHS-02-028,브레이크디스크 +351,CHS,샤시,3,조향,CHS-03-028,아이들러암 +352,CHS,샤시,4,휠/허브,CHS-04-028,스페이서 +353,CHS,샤시,1,서스펜션,CHS-01-029,쇽업소버 +354,CHS,샤시,2,제동,CHS-02-029,브레이크호스 +355,CHS,샤시,3,조향,CHS-03-029,랙앤피니언 +356,CHS,샤시,4,휠/허브,CHS-04-029,스페이서 +357,CHS,샤시,1,서스펜션,CHS-01-030,쇽업소버 +358,CHS,샤시,2,제동,CHS-02-030,브레이크디스크 +359,CHS,샤시,3,조향,CHS-03-030,랙앤피니언 +360,CHS,샤시,4,휠/허브,CHS-04-030,허브베어링 +361,BDY,바디,1,외판,BDY-01-001,트렁크리드 +362,BDY,바디,2,범퍼/그릴,BDY-02-001,토우아이커버 +363,BDY,바디,3,도어/윈도우,BDY-03-001,도어핸들 +364,BDY,바디,4,유리,BDY-04-001,와이퍼암 +365,BDY,바디,1,외판,BDY-01-002,후드패널 +366,BDY,바디,2,범퍼/그릴,BDY-02-002,라디에이터그릴 +367,BDY,바디,3,도어/윈도우,BDY-03-002,도어힌지 +368,BDY,바디,4,유리,BDY-04-002,와이퍼암 +369,BDY,바디,1,외판,BDY-01-003,도어패널 +370,BDY,바디,2,범퍼/그릴,BDY-02-003,범퍼보강빔 +371,BDY,바디,3,도어/윈도우,BDY-03-003,도어핸들 +372,BDY,바디,4,유리,BDY-04-003,와이퍼암 +373,BDY,바디,1,외판,BDY-01-004,후드패널 +374,BDY,바디,2,범퍼/그릴,BDY-02-004,리어범퍼 +375,BDY,바디,3,도어/윈도우,BDY-03-004,윈도우레귤레이터 +376,BDY,바디,4,유리,BDY-04-004,리어글래스 +377,BDY,바디,1,외판,BDY-01-005,후드패널 +378,BDY,바디,2,범퍼/그릴,BDY-02-005,프론트범퍼 +379,BDY,바디,3,도어/윈도우,BDY-03-005,도어힌지 +380,BDY,바디,4,유리,BDY-04-005,글래스몰딩 +381,BDY,바디,1,외판,BDY-01-006,도어패널 +382,BDY,바디,2,범퍼/그릴,BDY-02-006,프론트범퍼 +383,BDY,바디,3,도어/윈도우,BDY-03-006,도어핸들 +384,BDY,바디,4,유리,BDY-04-006,글래스몰딩 +385,BDY,바디,1,외판,BDY-01-007,리어펜더 +386,BDY,바디,2,범퍼/그릴,BDY-02-007,토우아이커버 +387,BDY,바디,3,도어/윈도우,BDY-03-007,도어힌지 +388,BDY,바디,4,유리,BDY-04-007,와이퍼암 +389,BDY,바디,1,외판,BDY-01-008,도어패널 +390,BDY,바디,2,범퍼/그릴,BDY-02-008,리어범퍼 +391,BDY,바디,3,도어/윈도우,BDY-03-008,윈도우모터 +392,BDY,바디,4,유리,BDY-04-008,글래스몰딩 +393,BDY,바디,1,외판,BDY-01-009,도어패널 +394,BDY,바디,2,범퍼/그릴,BDY-02-009,토우아이커버 +395,BDY,바디,3,도어/윈도우,BDY-03-009,웨더스트립 +396,BDY,바디,4,유리,BDY-04-009,와이퍼암 +397,BDY,바디,1,외판,BDY-01-010,프론트펜더 +398,BDY,바디,2,범퍼/그릴,BDY-02-010,포그램프커버 +399,BDY,바디,3,도어/윈도우,BDY-03-010,도어힌지 +400,BDY,바디,4,유리,BDY-04-010,리어글래스 +401,BDY,바디,1,외판,BDY-01-011,도어패널 +402,BDY,바디,2,범퍼/그릴,BDY-02-011,리어범퍼 +403,BDY,바디,3,도어/윈도우,BDY-03-011,웨더스트립 +404,BDY,바디,4,유리,BDY-04-011,사이드글래스 +405,BDY,바디,1,외판,BDY-01-012,트렁크리드 +406,BDY,바디,2,범퍼/그릴,BDY-02-012,프론트범퍼 +407,BDY,바디,3,도어/윈도우,BDY-03-012,웨더스트립 +408,BDY,바디,4,유리,BDY-04-012,글래스몰딩 +409,BDY,바디,1,외판,BDY-01-013,리어펜더 +410,BDY,바디,2,범퍼/그릴,BDY-02-013,프론트범퍼 +411,BDY,바디,3,도어/윈도우,BDY-03-013,윈도우레귤레이터 +412,BDY,바디,4,유리,BDY-04-013,글래스몰딩 +413,BDY,바디,1,외판,BDY-01-014,후드패널 +414,BDY,바디,2,범퍼/그릴,BDY-02-014,리어범퍼 +415,BDY,바디,3,도어/윈도우,BDY-03-014,윈도우모터 +416,BDY,바디,4,유리,BDY-04-014,윈드실드글래스 +417,BDY,바디,1,외판,BDY-01-015,프론트펜더 +418,BDY,바디,2,범퍼/그릴,BDY-02-015,포그램프커버 +419,BDY,바디,3,도어/윈도우,BDY-03-015,윈도우모터 +420,BDY,바디,4,유리,BDY-04-015,사이드글래스 +421,BDY,바디,1,외판,BDY-01-016,리어펜더 +422,BDY,바디,2,범퍼/그릴,BDY-02-016,리어범퍼 +423,BDY,바디,3,도어/윈도우,BDY-03-016,웨더스트립 +424,BDY,바디,4,유리,BDY-04-016,사이드글래스 +425,BDY,바디,1,외판,BDY-01-017,사이드실패널 +426,BDY,바디,2,범퍼/그릴,BDY-02-017,프론트범퍼 +427,BDY,바디,3,도어/윈도우,BDY-03-017,웨더스트립 +428,BDY,바디,4,유리,BDY-04-017,글래스몰딩 +429,BDY,바디,1,외판,BDY-01-018,프론트펜더 +430,BDY,바디,2,범퍼/그릴,BDY-02-018,포그램프커버 +431,BDY,바디,3,도어/윈도우,BDY-03-018,윈도우레귤레이터 +432,BDY,바디,4,유리,BDY-04-018,사이드글래스 +433,BDY,바디,1,외판,BDY-01-019,사이드실패널 +434,BDY,바디,2,범퍼/그릴,BDY-02-019,범퍼보강빔 +435,BDY,바디,3,도어/윈도우,BDY-03-019,도어힌지 +436,BDY,바디,4,유리,BDY-04-019,글래스몰딩 +437,BDY,바디,1,외판,BDY-01-020,리어펜더 +438,BDY,바디,2,범퍼/그릴,BDY-02-020,범퍼보강빔 +439,BDY,바디,3,도어/윈도우,BDY-03-020,윈도우레귤레이터 +440,BDY,바디,4,유리,BDY-04-020,리어글래스 +441,BDY,바디,1,외판,BDY-01-021,리어펜더 +442,BDY,바디,2,범퍼/그릴,BDY-02-021,프론트범퍼 +443,BDY,바디,3,도어/윈도우,BDY-03-021,윈도우모터 +444,BDY,바디,4,유리,BDY-04-021,윈드실드글래스 +445,BDY,바디,1,외판,BDY-01-022,리어펜더 +446,BDY,바디,2,범퍼/그릴,BDY-02-022,토우아이커버 +447,BDY,바디,3,도어/윈도우,BDY-03-022,웨더스트립 +448,BDY,바디,4,유리,BDY-04-022,글래스몰딩 +449,BDY,바디,1,외판,BDY-01-023,사이드실패널 +450,BDY,바디,2,범퍼/그릴,BDY-02-023,프론트범퍼 +451,BDY,바디,3,도어/윈도우,BDY-03-023,웨더스트립 +452,BDY,바디,4,유리,BDY-04-023,리어글래스 +453,BDY,바디,1,외판,BDY-01-024,도어패널 +454,BDY,바디,2,범퍼/그릴,BDY-02-024,토우아이커버 +455,BDY,바디,3,도어/윈도우,BDY-03-024,윈도우모터 +456,BDY,바디,4,유리,BDY-04-024,와이퍼암 +457,BDY,바디,1,외판,BDY-01-025,후드패널 +458,BDY,바디,2,범퍼/그릴,BDY-02-025,프론트범퍼 +459,BDY,바디,3,도어/윈도우,BDY-03-025,윈도우레귤레이터 +460,BDY,바디,4,유리,BDY-04-025,윈드실드글래스 +461,TRM,트림,1,시트,TRM-01-001,시트프레임 +462,TRM,트림,2,내장재,TRM-02-001,도어트림 +463,TRM,트림,3,소음진동,TRM-03-001,플로어매트 +464,TRM,트림,4,익스테리어트림,TRM-04-001,사이드몰딩 +465,TRM,트림,1,시트,TRM-01-002,시트쿠션 +466,TRM,트림,2,내장재,TRM-02-002,도어트림 +467,TRM,트림,3,소음진동,TRM-03-002,방진패드 +468,TRM,트림,4,익스테리어트림,TRM-04-002,엠블럼 +469,TRM,트림,1,시트,TRM-01-003,시트트랙 +470,TRM,트림,2,내장재,TRM-02-003,필러트림 +471,TRM,트림,3,소음진동,TRM-03-003,방진패드 +472,TRM,트림,4,익스테리어트림,TRM-04-003,머드가드 +473,TRM,트림,1,시트,TRM-01-004,헤드레스트 +474,TRM,트림,2,내장재,TRM-02-004,루프라이너 +475,TRM,트림,3,소음진동,TRM-03-004,트렁크매트 +476,TRM,트림,4,익스테리어트림,TRM-04-004,스포일러 +477,TRM,트림,1,시트,TRM-01-005,시트프레임 +478,TRM,트림,2,내장재,TRM-02-005,도어트림 +479,TRM,트림,3,소음진동,TRM-03-005,흡음재 +480,TRM,트림,4,익스테리어트림,TRM-04-005,크롬가니쉬 +481,TRM,트림,1,시트,TRM-01-006,시트레버 +482,TRM,트림,2,내장재,TRM-02-006,대시보드패널 +483,TRM,트림,3,소음진동,TRM-03-006,플로어매트 +484,TRM,트림,4,익스테리어트림,TRM-04-006,사이드몰딩 +485,TRM,트림,1,시트,TRM-01-007,시트프레임 +486,TRM,트림,2,내장재,TRM-02-007,도어트림 +487,TRM,트림,3,소음진동,TRM-03-007,흡음재 +488,TRM,트림,4,익스테리어트림,TRM-04-007,머드가드 +489,TRM,트림,1,시트,TRM-01-008,시트쿠션 +490,TRM,트림,2,내장재,TRM-02-008,대시보드패널 +491,TRM,트림,3,소음진동,TRM-03-008,플로어매트 +492,TRM,트림,4,익스테리어트림,TRM-04-008,사이드몰딩 +493,TRM,트림,1,시트,TRM-01-009,시트레버 +494,TRM,트림,2,내장재,TRM-02-009,대시보드패널 +495,TRM,트림,3,소음진동,TRM-03-009,플로어매트 +496,TRM,트림,4,익스테리어트림,TRM-04-009,머드가드 +497,TRM,트림,1,시트,TRM-01-010,시트레버 +498,TRM,트림,2,내장재,TRM-02-010,도어트림 +499,TRM,트림,3,소음진동,TRM-03-010,방진매트 +500,TRM,트림,4,익스테리어트림,TRM-04-010,크롬가니쉬 +501,TRM,트림,1,시트,TRM-01-011,시트프레임 +502,TRM,트림,2,내장재,TRM-02-011,루프라이너 +503,TRM,트림,3,소음진동,TRM-03-011,방진패드 +504,TRM,트림,4,익스테리어트림,TRM-04-011,사이드몰딩 +505,TRM,트림,1,시트,TRM-01-012,시트쿠션 +506,TRM,트림,2,내장재,TRM-02-012,도어트림 +507,TRM,트림,3,소음진동,TRM-03-012,흡음재 +508,TRM,트림,4,익스테리어트림,TRM-04-012,크롬가니쉬 +509,TRM,트림,1,시트,TRM-01-013,시트쿠션 +510,TRM,트림,2,내장재,TRM-02-013,도어트림 +511,TRM,트림,3,소음진동,TRM-03-013,플로어매트 +512,TRM,트림,4,익스테리어트림,TRM-04-013,머드가드 +513,TRM,트림,1,시트,TRM-01-014,시트쿠션 +514,TRM,트림,2,내장재,TRM-02-014,도어트림 +515,TRM,트림,3,소음진동,TRM-03-014,트렁크매트 +516,TRM,트림,4,익스테리어트림,TRM-04-014,머드가드 +517,TRM,트림,1,시트,TRM-01-015,시트쿠션 +518,TRM,트림,2,내장재,TRM-02-015,도어트림 +519,TRM,트림,3,소음진동,TRM-03-015,플로어매트 +520,TRM,트림,4,익스테리어트림,TRM-04-015,사이드몰딩 +521,TRM,트림,1,시트,TRM-01-016,시트트랙 +522,TRM,트림,2,내장재,TRM-02-016,대시보드패널 +523,TRM,트림,3,소음진동,TRM-03-016,흡음재 +524,TRM,트림,4,익스테리어트림,TRM-04-016,사이드몰딩 +525,TRM,트림,1,시트,TRM-01-017,헤드레스트 +526,TRM,트림,2,내장재,TRM-02-017,루프라이너 +527,TRM,트림,3,소음진동,TRM-03-017,방진패드 +528,TRM,트림,4,익스테리어트림,TRM-04-017,머드가드 +529,TRM,트림,1,시트,TRM-01-018,시트레버 +530,TRM,트림,2,내장재,TRM-02-018,콘솔박스 +531,TRM,트림,3,소음진동,TRM-03-018,트렁크매트 +532,TRM,트림,4,익스테리어트림,TRM-04-018,사이드몰딩 +533,TRM,트림,1,시트,TRM-01-019,시트레버 +534,TRM,트림,2,내장재,TRM-02-019,카펫트림 +535,TRM,트림,3,소음진동,TRM-03-019,트렁크매트 +536,TRM,트림,4,익스테리어트림,TRM-04-019,머드가드 +537,TRM,트림,1,시트,TRM-01-020,시트레버 +538,TRM,트림,2,내장재,TRM-02-020,루프라이너 +539,TRM,트림,3,소음진동,TRM-03-020,플로어매트 +540,TRM,트림,4,익스테리어트림,TRM-04-020,크롬가니쉬 +541,ELE,일렉트릭,1,전원,ELE-01-001,알터네이터 +542,ELE,일렉트릭,2,제어,ELE-02-001,퓨즈세트 +543,ELE,일렉트릭,3,조명,ELE-03-001,테일램프 +544,ELE,일렉트릭,4,배선,ELE-04-001,배선클립 +545,ELE,일렉트릭,1,전원,ELE-01-002,퓨즈박스 +546,ELE,일렉트릭,2,제어,ELE-02-002,퓨즈세트 +547,ELE,일렉트릭,3,조명,ELE-03-002,헤드램프 +548,ELE,일렉트릭,4,배선,ELE-04-002,배선클립 +549,ELE,일렉트릭,1,전원,ELE-01-003,배터리 +550,ELE,일렉트릭,2,제어,ELE-02-003,ECU +551,ELE,일렉트릭,3,조명,ELE-03-003,턴시그널램프 +552,ELE,일렉트릭,4,배선,ELE-04-003,케이블타이 +553,ELE,일렉트릭,1,전원,ELE-01-004,퓨즈박스 +554,ELE,일렉트릭,2,제어,ELE-02-004,릴레이 +555,ELE,일렉트릭,3,조명,ELE-03-004,헤드램프 +556,ELE,일렉트릭,4,배선,ELE-04-004,와이어하네스 +557,ELE,일렉트릭,1,전원,ELE-01-005,전압레귤레이터 +558,ELE,일렉트릭,2,제어,ELE-02-005,스로틀포지션센서 +559,ELE,일렉트릭,3,조명,ELE-03-005,실내등 +560,ELE,일렉트릭,4,배선,ELE-04-005,분배커넥터 +561,ELE,일렉트릭,1,전원,ELE-01-006,전압레귤레이터 +562,ELE,일렉트릭,2,제어,ELE-02-006,퓨즈세트 +563,ELE,일렉트릭,3,조명,ELE-03-006,브레이크등 +564,ELE,일렉트릭,4,배선,ELE-04-006,배선클립 +565,ELE,일렉트릭,1,전원,ELE-01-007,전압레귤레이터 +566,ELE,일렉트릭,2,제어,ELE-02-007,퓨즈세트 +567,ELE,일렉트릭,3,조명,ELE-03-007,헤드램프 +568,ELE,일렉트릭,4,배선,ELE-04-007,전선가이드 +569,ELE,일렉트릭,1,전원,ELE-01-008,알터네이터 +570,ELE,일렉트릭,2,제어,ELE-02-008,릴레이 +571,ELE,일렉트릭,3,조명,ELE-03-008,안개등 +572,ELE,일렉트릭,4,배선,ELE-04-008,전선가이드 +573,ELE,일렉트릭,1,전원,ELE-01-009,배터리 +574,ELE,일렉트릭,2,제어,ELE-02-009,퓨즈세트 +575,ELE,일렉트릭,3,조명,ELE-03-009,안개등 +576,ELE,일렉트릭,4,배선,ELE-04-009,케이블타이 +577,ELE,일렉트릭,1,전원,ELE-01-010,접지스트랩 +578,ELE,일렉트릭,2,제어,ELE-02-010,퓨즈세트 +579,ELE,일렉트릭,3,조명,ELE-03-010,테일램프 +580,ELE,일렉트릭,4,배선,ELE-04-010,와이어하네스 +581,ELE,일렉트릭,1,전원,ELE-01-011,시동모터 +582,ELE,일렉트릭,2,제어,ELE-02-011,릴레이 +583,ELE,일렉트릭,3,조명,ELE-03-011,안개등 +584,ELE,일렉트릭,4,배선,ELE-04-011,배선클립 +585,ELE,일렉트릭,1,전원,ELE-01-012,배터리 +586,ELE,일렉트릭,2,제어,ELE-02-012,퓨즈세트 +587,ELE,일렉트릭,3,조명,ELE-03-012,실내등 +588,ELE,일렉트릭,4,배선,ELE-04-012,와이어하네스 +589,ELE,일렉트릭,1,전원,ELE-01-013,퓨즈박스 +590,ELE,일렉트릭,2,제어,ELE-02-013,퓨즈세트 +591,ELE,일렉트릭,3,조명,ELE-03-013,브레이크등 +592,ELE,일렉트릭,4,배선,ELE-04-013,배선클립 +593,ELE,일렉트릭,1,전원,ELE-01-014,알터네이터 +594,ELE,일렉트릭,2,제어,ELE-02-014,노크센서 +595,ELE,일렉트릭,3,조명,ELE-03-014,헤드램프 +596,ELE,일렉트릭,4,배선,ELE-04-014,와이어하네스 +597,ELE,일렉트릭,1,전원,ELE-01-015,시동모터 +598,ELE,일렉트릭,2,제어,ELE-02-015,스로틀포지션센서 +599,ELE,일렉트릭,3,조명,ELE-03-015,헤드램프 +600,ELE,일렉트릭,4,배선,ELE-04-015,배선클립 +601,ELE,일렉트릭,1,전원,ELE-01-016,퓨즈박스 +602,ELE,일렉트릭,2,제어,ELE-02-016,노크센서 +603,ELE,일렉트릭,3,조명,ELE-03-016,헤드램프 +604,ELE,일렉트릭,4,배선,ELE-04-016,전선가이드 +605,ELE,일렉트릭,1,전원,ELE-01-017,배터리 +606,ELE,일렉트릭,2,제어,ELE-02-017,퓨즈세트 +607,ELE,일렉트릭,3,조명,ELE-03-017,안개등 +608,ELE,일렉트릭,4,배선,ELE-04-017,배선클립 +609,ELE,일렉트릭,1,전원,ELE-01-018,배터리 +610,ELE,일렉트릭,2,제어,ELE-02-018,노크센서 +611,ELE,일렉트릭,3,조명,ELE-03-018,브레이크등 +612,ELE,일렉트릭,4,배선,ELE-04-018,배선클립 +613,ELE,일렉트릭,1,전원,ELE-01-019,전압레귤레이터 +614,ELE,일렉트릭,2,제어,ELE-02-019,맵센서 +615,ELE,일렉트릭,3,조명,ELE-03-019,브레이크등 +616,ELE,일렉트릭,4,배선,ELE-04-019,전선가이드 +617,ELE,일렉트릭,1,전원,ELE-01-020,시동모터 +618,ELE,일렉트릭,2,제어,ELE-02-020,맵센서 +619,ELE,일렉트릭,3,조명,ELE-03-020,실내등 +620,ELE,일렉트릭,4,배선,ELE-04-020,배선클립 +621,ELE,일렉트릭,1,전원,ELE-01-021,시동모터 +622,ELE,일렉트릭,2,제어,ELE-02-021,맵센서 +623,ELE,일렉트릭,3,조명,ELE-03-021,브레이크등 +624,ELE,일렉트릭,4,배선,ELE-04-021,배선클립 +625,ELE,일렉트릭,1,전원,ELE-01-022,배터리 +626,ELE,일렉트릭,2,제어,ELE-02-022,스로틀포지션센서 +627,ELE,일렉트릭,3,조명,ELE-03-022,턴시그널램프 +628,ELE,일렉트릭,4,배선,ELE-04-022,분배커넥터 +629,ELE,일렉트릭,1,전원,ELE-01-023,전압레귤레이터 +630,ELE,일렉트릭,2,제어,ELE-02-023,온도센서 +631,ELE,일렉트릭,3,조명,ELE-03-023,턴시그널램프 +632,ELE,일렉트릭,4,배선,ELE-04-023,분배커넥터 +633,ELE,일렉트릭,1,전원,ELE-01-024,알터네이터 +634,ELE,일렉트릭,2,제어,ELE-02-024,노크센서 +635,ELE,일렉트릭,3,조명,ELE-03-024,브레이크등 +636,ELE,일렉트릭,4,배선,ELE-04-024,분배커넥터 +637,ELE,일렉트릭,1,전원,ELE-01-025,배터리 +638,ELE,일렉트릭,2,제어,ELE-02-025,스로틀포지션센서 +639,ELE,일렉트릭,3,조명,ELE-03-025,턴시그널램프 +640,ELE,일렉트릭,4,배선,ELE-04-025,분배커넥터 +641,ELE,일렉트릭,1,전원,ELE-01-026,전압레귤레이터 +642,ELE,일렉트릭,2,제어,ELE-02-026,맵센서 +643,ELE,일렉트릭,3,조명,ELE-03-026,턴시그널램프 +644,ELE,일렉트릭,4,배선,ELE-04-026,배선클립 +645,ELE,일렉트릭,1,전원,ELE-01-027,배터리 +646,ELE,일렉트릭,2,제어,ELE-02-027,ECU +647,ELE,일렉트릭,3,조명,ELE-03-027,헤드램프 +648,ELE,일렉트릭,4,배선,ELE-04-027,배선클립 +649,ELE,일렉트릭,1,전원,ELE-01-028,전압레귤레이터 +650,ELE,일렉트릭,2,제어,ELE-02-028,퓨즈세트 +651,ELE,일렉트릭,3,조명,ELE-03-028,헤드램프 +652,ELE,일렉트릭,4,배선,ELE-04-028,전선가이드 +653,ELE,일렉트릭,1,전원,ELE-01-029,퓨즈박스 +654,ELE,일렉트릭,2,제어,ELE-02-029,노크센서 +655,ELE,일렉트릭,3,조명,ELE-03-029,헤드램프 +656,ELE,일렉트릭,4,배선,ELE-04-029,와이어하네스 +657,ELE,일렉트릭,1,전원,ELE-01-030,전압레귤레이터 +658,ELE,일렉트릭,2,제어,ELE-02-030,노크센서 +659,ELE,일렉트릭,3,조명,ELE-03-030,턴시그널램프 +660,ELE,일렉트릭,4,배선,ELE-04-030,배선클립 +661,CON,커넥터,1,단자,CON-01-001,러그단자 +662,CON,커넥터,2,하우징,CON-02-001,락레버 +663,CON,커넥터,3,실링/고정,CON-03-001,실링플러그 +664,CON,커넥터,4,케이블/클립,CON-04-001,하네스클립 +665,CON,커넥터,1,단자,CON-01-002,핀터미널 +666,CON,커넥터,2,하우징,CON-02-002,커넥터하우징 +667,CON,커넥터,3,실링/고정,CON-03-002,실링플러그 +668,CON,커넥터,4,케이블/클립,CON-04-002,하네스클립 +669,CON,커넥터,1,단자,CON-01-003,링단자 +670,CON,커넥터,2,하우징,CON-02-003,커넥터하우징 +671,CON,커넥터,3,실링/고정,CON-03-003,리테이너 +672,CON,커넥터,4,케이블/클립,CON-04-003,와이어 +673,CON,커넥터,1,단자,CON-01-004,소켓터미널 +674,CON,커넥터,2,하우징,CON-02-004,하우징캡 +675,CON,커넥터,3,실링/고정,CON-03-004,방수캡 +676,CON,커넥터,4,케이블/클립,CON-04-004,하네스클립 +677,CON,커넥터,1,단자,CON-01-005,러그단자 +678,CON,커넥터,2,하우징,CON-02-005,커넥터하우징 +679,CON,커넥터,3,실링/고정,CON-03-005,방수캡 +680,CON,커넥터,4,케이블/클립,CON-04-005,케이블클립 +681,CON,커넥터,1,단자,CON-01-006,핀터미널 +682,CON,커넥터,2,하우징,CON-02-006,하우징캡 +683,CON,커넥터,3,실링/고정,CON-03-006,실링플러그 +684,CON,커넥터,4,케이블/클립,CON-04-006,와이어 +685,CON,커넥터,1,단자,CON-01-007,링단자 +686,CON,커넥터,2,하우징,CON-02-007,락레버 +687,CON,커넥터,3,실링/고정,CON-03-007,리테이너 +688,CON,커넥터,4,케이블/클립,CON-04-007,와이어 +689,CON,커넥터,1,단자,CON-01-008,핀터미널 +690,CON,커넥터,2,하우징,CON-02-008,터미널블록 +691,CON,커넥터,3,실링/고정,CON-03-008,실링플러그 +692,CON,커넥터,4,케이블/클립,CON-04-008,하네스클립 +693,CON,커넥터,1,단자,CON-01-009,링단자 +694,CON,커넥터,2,하우징,CON-02-009,커넥터하우징 +695,CON,커넥터,3,실링/고정,CON-03-009,고무씰 +696,CON,커넥터,4,케이블/클립,CON-04-009,하네스클립 +697,CON,커넥터,1,단자,CON-01-010,링단자 +698,CON,커넥터,2,하우징,CON-02-010,락레버 +699,CON,커넥터,3,실링/고정,CON-03-010,방수캡 +700,CON,커넥터,4,케이블/클립,CON-04-010,하네스클립