diff --git "a/.github/ISSUE_TEMPLATE/\352\270\260\353\263\270-\355\203\254\355\224\214\353\246\277.md" "b/.github/ISSUE_TEMPLATE/\352\270\260\353\263\270-\355\203\254\355\224\214\353\246\277.md" index a10f64c..b6db260 100644 --- "a/.github/ISSUE_TEMPLATE/\352\270\260\353\263\270-\355\203\254\355\224\214\353\246\277.md" +++ "b/.github/ISSUE_TEMPLATE/\352\270\260\353\263\270-\355\203\254\355\224\214\353\246\277.md" @@ -1,16 +1,14 @@ --- name: 기본 탬플릿 about: 이 탬플릿을 이용해 주세요 -title: '' -labels: '' -assignees: '' - +title: "" +labels: "" +assignees: "" --- -## (제목) +## 작업 내용 -### 작업 내용 - 작업내용 1 - 작업내용 2 -### 기타 +## 기타 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ea6e835..89d2020 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,6 +1,6 @@ # 개요 -- Fixes # (이슈 번호) +- Closes # (이슈 번호) - 페이지 || 컴포넌트 변경 시 이미지 첨부 (기존과 다를 경우) @@ -12,4 +12,4 @@ - [ ] Docs updated required - [ ] Chore -# 상세 내용 +## 상세 내용 diff --git a/.github/workflows/build-check.yaml b/.github/workflows/build-check.yaml new file mode 100644 index 0000000..75a777b --- /dev/null +++ b/.github/workflows/build-check.yaml @@ -0,0 +1,32 @@ +name: lint & build check + +on: + pull_request: + branches: + - develop + - main + +jobs: + build: + name: build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "22.18.0" + cache: npm + + - name: Install dependencies + run: npm ci + + - name: ESLint Check + run: npm run lint + + - name: Stylelint Check + run: npm run stylelint + + - name: Build React + run: npm run build --profile diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 0000000..52cff2b --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,32 @@ +name: Deploy Release to Vercel + +on: + release: + types: [published] + +jobs: + deploy: + name: deploy + runs-on: ubuntu-latest + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + steps: + - uses: actions/checkout@v4 + with: + ref: main + fetch-depth: 0 + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "22.18.0" + cache: "npm" + - name: Install Vercel CLI + run: npm i -g vercel@latest + - name: Pull Vercel env (production) + run: vercel pull --yes --environment=production --token "${VERCEL_TOKEN}" + - name: Vercel build (production) + run: vercel build --prod --token "${VERCEL_TOKEN}" + - name: Deploy to Vercel (Production, prebuilt) + run: vercel deploy --prebuilt --prod --token "${VERCEL_TOKEN}" diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml new file mode 100644 index 0000000..3ad9eff --- /dev/null +++ b/.github/workflows/preview.yaml @@ -0,0 +1,33 @@ +name: Deploy Preview to Vercel + +on: + push: + branches: + - develop + +jobs: + deploy: + name: deploy Preview + runs-on: ubuntu-latest + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + steps: + - uses: actions/checkout@v4 + with: + ref: develop + fetch-depth: 0 + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "22.18.0" + cache: "npm" + - name: Install Vercel CLI + run: npm i -g vercel@latest + - name: Pull Vercel env (production) + run: vercel pull --yes --environment=production --token "${VERCEL_TOKEN}" + - name: Vercel build (production) + run: vercel build --token "${VERCEL_TOKEN}" + - name: Deploy to Vercel (Production, prebuilt) + run: vercel deploy --prebuilt --token "${VERCEL_TOKEN}" diff --git a/.github/workflows/version.yaml b/.github/workflows/version.yaml new file mode 100644 index 0000000..6863d72 --- /dev/null +++ b/.github/workflows/version.yaml @@ -0,0 +1,30 @@ +name: Create release & tag +on: + push: + branches: + - main + +permissions: + contents: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 22.18.0 + cache: "npm" + - name: Bump version and push tag + id: tag_version + uses: mathieudutour/github-tag-action@v6.2 + with: + github_token: ${{ secrets.TOKEN }} + - name: Create a GitHub release + uses: ncipollo/release-action@v1 + with: + tag: ${{ steps.tag_version.outputs.new_tag }} + name: Release ${{ steps.tag_version.outputs.new_tag }} + body: ${{ steps.tag_version.outputs.changelog }} diff --git a/.gitignore b/.gitignore index a547bf3..d879e24 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,17 @@ dist-ssr *.njsproj *.sln *.sw? + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +venv/ +ENV/ +env/ +.venv + +# AI API (별도 Git 저장소로 관리) +recommendation-api/ \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..12ed950 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npm run lint-front diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..b6f27f1 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 0000000..fcb335d --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["stylelint-config-standard", "stylelint-config-recommended"], + "plugins": ["stylelint-order"], + "customSyntax": "postcss-styled-syntax", + "rules": { + "media-query-no-invalid": null, + "declaration-empty-line-before": [ + "always", + { + "ignore": ["first-nested", "after-comment", "after-declaration", "inside-single-line-block"] + } + ], + "order/order": ["custom-properties", "declarations"], + + "order/properties-order": null, + "nesting-selector-no-missing-scoping-root": null + } +} diff --git a/check-node-version.cjs b/check-node-version.cjs new file mode 100644 index 0000000..f398194 --- /dev/null +++ b/check-node-version.cjs @@ -0,0 +1,7 @@ +const required = "22.18.0"; +const current = process.versions.node; + +if (current !== required) { + console.error(`❌ Node ${required} 버전이 필요합니다. 현재 버전: ${current}`); + process.exit(1); +} diff --git a/eslint.config.js b/eslint.config.js index cee1e2c..a4b8a96 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,29 +1,57 @@ -import js from '@eslint/js' -import globals from 'globals' -import reactHooks from 'eslint-plugin-react-hooks' -import reactRefresh from 'eslint-plugin-react-refresh' -import { defineConfig, globalIgnores } from 'eslint/config' +import js from "@eslint/js"; +import importPlugin from "eslint-plugin-import"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import { defineConfig, globalIgnores } from "eslint/config"; + +import globals from "globals"; export default defineConfig([ - globalIgnores(['dist']), + globalIgnores(["dist"]), { - files: ['**/*.{js,jsx}'], + plugins: { + import: importPlugin, + }, + files: ["**/*.{js,jsx}"], extends: [ js.configs.recommended, - reactHooks.configs['recommended-latest'], + reactHooks.configs["recommended-latest"], reactRefresh.configs.vite, ], languageOptions: { ecmaVersion: 2020, globals: globals.browser, parserOptions: { - ecmaVersion: 'latest', + ecmaVersion: "latest", ecmaFeatures: { jsx: true }, - sourceType: 'module', + sourceType: "module", }, }, rules: { - 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + // 파일 뒤에 js, jsx 사용 금지 + "import/extensions": [ + "error", + "ignorePackages", + { + js: "never", + jsx: "never", + ts: "never", + tsx: "never", + }, + ], + "react-refresh/only-export-components": "off", + "no-unused-vars": ["error", { varsIgnorePattern: "^[A-Z_]" }], + }, + settings: { + "import/resolver": { + alias: { + map: [["@", "./src"]], + extensions: [".js", ".jsx"], + }, + node: { + extensions: [".js", ".jsx"], + }, + }, }, }, -]) +]); diff --git a/index.html b/index.html index 0ab3cef..6578b2b 100644 --- a/index.html +++ b/index.html @@ -8,6 +8,8 @@
+ +