Skip to content

biz-scan/bizscan-fe

Repository files navigation

Bizscan Frontend

λΉ„μ¦ˆμŠ€μΊ” ν”„λ‘ νŠΈμ—”λ“œ ν”„λ‘œμ νŠΈμž…λ‹ˆλ‹€.

기술 μŠ€νƒ

μΉ΄ν…Œκ³ λ¦¬ 기술 버전 μ„€λͺ…
ν”„λ ˆμž„μ›Œν¬ React 19.2.0 UI 라이브러리
μ–Έμ–΄ TypeScript 5.9.3 νƒ€μž… μ•ˆμ •μ„±
λ²ˆλ“€λŸ¬ Vite 7.2.4 λΉ λ₯Έ 개발 μ„œλ²„ & λΉŒλ“œ
λΌμš°νŒ… React Router DOM 7.12.0 SPA λΌμš°νŒ…
μƒνƒœ 관리 Zustand 5.0.9 ν΄λΌμ΄μ–ΈνŠΈ μƒνƒœ 관리
μ„œλ²„ μƒνƒœ TanStack React Query 5.90.16 API 데이터 캐싱 & 동기화
폼 React Hook Form 7.70.0 폼 μƒνƒœ 관리
HTTP Axios 1.13.2 API 톡신
μŠ€νƒ€μΌλ§ TailwindCSS 4.1.18 μœ ν‹Έλ¦¬ν‹° 기반 CSS
μ•Œλ¦Ό Sonner 2.0.7 ν† μŠ€νŠΈ μ•Œλ¦Ό

μ‹œμž‘ν•˜κΈ°

Note: 이 ν”„λ‘œμ νŠΈλŠ” pnpm을 νŒ¨ν‚€μ§€ λ§€λ‹ˆμ €λ‘œ μ‚¬μš©ν•©λ‹ˆλ‹€.

0. pnpm μ„€μΉ˜ (μ—†λŠ” 경우)

npm install -g pnpm

1. νŒ¨ν‚€μ§€ μ„€μΉ˜

pnpm install

2. ν™˜κ²½ λ³€μˆ˜ μ„€μ •

ν”„λ‘œμ νŠΈ λ£¨νŠΈμ— .env νŒŒμΌμ„ μƒμ„±ν•˜μ„Έμš”:

VITE_API_URL=http://localhost:3000

3. 개발 μ„œλ²„ μ‹€ν–‰

pnpm run dev

λΈŒλΌμš°μ €μ—μ„œ http://localhost:5173으둜 μ ‘μ†ν•˜μ„Έμš”.


슀크립트 λͺ…λ Ήμ–΄

λͺ…λ Ήμ–΄ μ„€λͺ…
pnpm run dev 개발 μ„œλ²„ μ‹€ν–‰ (HMR 지원)
pnpm run build ν”„λ‘œλ•μ…˜ λΉŒλ“œ 생성
pnpm run preview λΉŒλ“œλœ κ²°κ³Όλ¬Ό 미리보기
pnpm run lint ESLint μ½”λ“œ 검사
pnpm run lint:fix ESLint μžλ™ μˆ˜μ •

ν”„λ‘œμ νŠΈ ꡬ쑰

src/
β”œβ”€β”€ apis/                    # API 톡신 κ΄€λ ¨
β”‚   β”œβ”€β”€ auth/               # 인증 κ΄€λ ¨ API
β”‚   β”‚   └── auth.ts         # login, signup, logout, getMe, refreshToken ν•¨μˆ˜
β”‚   β”œβ”€β”€ axiosInstance.ts    # Axios μ„€μ • (인터셉터, 토큰 μžλ™ κ°±μ‹ )
β”‚   β”œβ”€β”€ apiHooks.ts         # useAppQuery, useAppMutation μ»€μŠ€ν…€ ν›…
β”‚   └── queryClient.ts      # React Query ν΄λΌμ΄μ–ΈνŠΈ μ„€μ •
β”‚
β”œβ”€β”€ components/              # μž¬μ‚¬μš© κ°€λŠ₯ν•œ μ»΄ν¬λ„ŒνŠΈ
β”‚   β”œβ”€β”€ Button.tsx          # λ²„νŠΌ μ»΄ν¬λ„ŒνŠΈ
β”‚   └── HomePage/           # νŽ˜μ΄μ§€λ³„ μ»΄ν¬λ„ŒνŠΈ 폴더
β”‚       └── HomeInput.tsx   # Input μ»΄ν¬λ„ŒνŠΈ
β”‚
β”œβ”€β”€ hooks/                   # μ»€μŠ€ν…€ ν›…
β”‚   └── auth/               # 인증 κ΄€λ ¨ ν›…
β”‚       β”œβ”€β”€ index.ts        # barrel export
β”‚       β”œβ”€β”€ useLogin.ts     # 둜그인
β”‚       β”œβ”€β”€ useSignup.ts    # νšŒμ›κ°€μž…
β”‚       β”œβ”€β”€ useLogout.ts    # λ‘œκ·Έμ•„μ›ƒ
β”‚       β”œβ”€β”€ useMe.ts        # λ‚΄ 정보 쑰회
β”‚       └── useUpdateMe.ts  # λ‚΄ 정보 μˆ˜μ •
β”‚
β”œβ”€β”€ lib/                     # μœ ν‹Έλ¦¬ν‹° 라이브러리
β”‚   β”œβ”€β”€ tokenStorage.ts     # 토큰 μ €μž₯μ†Œ (localStorage/sessionStorage)
β”‚   └── utils.ts            # 곡톡 μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜
β”‚
β”œβ”€β”€ providers/               # React Provider μ»΄ν¬λ„ŒνŠΈ
β”‚   └── AuthProvider.tsx    # 인증 μƒνƒœ μ΄ˆκΈ°ν™” (μ•± μ‹œμž‘ μ‹œ 토큰 검증)
β”‚
β”œβ”€β”€ pages/                   # νŽ˜μ΄μ§€ μ»΄ν¬λ„ŒνŠΈ
β”‚   β”œβ”€β”€ HomePage.tsx        # ν™ˆνŽ˜μ΄μ§€ (/)
β”‚   └── LoginPage.tsx       # 둜그인 νŽ˜μ΄μ§€ (/login)
β”‚
β”œβ”€β”€ layouts/                 # λ ˆμ΄μ•„μ›ƒ μ»΄ν¬λ„ŒνŠΈ
β”‚   └── MainLayout.tsx      # Header/Footer 포함 λ ˆμ΄μ•„μ›ƒ
β”‚
β”œβ”€β”€ routes/                  # λΌμš°νŒ… μ„€μ •
β”‚   └── index.tsx           # React Router μ„€μ •
β”‚
β”œβ”€β”€ store/                   # Zustand μƒνƒœ 관리
β”‚   └── useAuthStore.ts     # 인증 μƒνƒœ (user, isAuthenticated)
β”‚
β”œβ”€β”€ types/                   # TypeScript νƒ€μž… μ •μ˜
β”‚   └── auth.type.ts        # 인증 κ΄€λ ¨ νƒ€μž…
β”‚
β”œβ”€β”€ styles/                  # μ „μ—­ μŠ€νƒ€μΌ
β”‚   └── theme.css           # CSS λ³€μˆ˜ (색상, 폰트, 간격 λ“±)
β”‚
β”œβ”€β”€ assets/                  # 정적 파일 (이미지, μ•„μ΄μ½˜ λ“±)
β”œβ”€β”€ constants/               # μƒμˆ˜ μ •μ˜
β”‚
β”œβ”€β”€ main.tsx                 # μ•± μ§„μž…μ 
└── index.css                # μ „μ—­ CSS (Tailwind import)

μ£Όμš” μ„€μ • 파일 μ„€λͺ…

eslint.config.mjs - μ½”λ“œ ν’ˆμ§ˆ 검사

ESLint μ„€μ • νŒŒμΌμž…λ‹ˆλ‹€. λ‹€μŒ κ·œμΉ™λ“€μ΄ μ μš©λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€:

  • Import μžλ™ μ •λ ¬: simple-import-sort ν”ŒλŸ¬κ·ΈμΈ μ‚¬μš©
    1μˆœμœ„: react, react-dom
    2μˆœμœ„: @둜 μ‹œμž‘ν•˜λŠ” μ™ΈλΆ€ νŒ¨ν‚€μ§€
    3μˆœμœ„: @/둜 μ‹œμž‘ν•˜λŠ” λ‚΄λΆ€ 경둜 (μ ˆλŒ€ 경둜)
    4μˆœμœ„: ./λ‚˜ ../둜 μ‹œμž‘ν•˜λŠ” μƒλŒ€ 경둜
    5μˆœμœ„: CSS 파일
    
  • λ―Έμ‚¬μš© import μžλ™ 제거: unused-imports ν”ŒλŸ¬κ·ΈμΈ
  • νƒ€μž… import κ°•μ œ: import type { ... } ν˜•μ‹ μ‚¬μš©
  • Prettier 톡합: μ½”λ“œ ν¬λ§·νŒ…κ³Ό λ¦°νŒ… 톡합

.prettierrc - μ½”λ“œ ν¬λ§·νŒ…

{
  "semi": true,           // μ„Έλ―Έμ½œλ‘  μ‚¬μš©
  "singleQuote": true,    // μž‘μ€λ”°μ˜΄ν‘œ μ‚¬μš©
  "tabWidth": 2,          // λ“€μ—¬μ“°κΈ° 2μΉΈ
  "trailingComma": "es5", // ν›„ν–‰ μ‰Όν‘œ
  "printWidth": 100       // ν•œ 쀄 μ΅œλŒ€ 100자
}

tsconfig.json - TypeScript μ„€μ •

  • 경둜 별칭: @/λ₯Ό src/둜 λ§€ν•‘
    // μ‚¬μš© μ˜ˆμ‹œ
    import { Button } from '@/components/Button';
    import { useLogin, useMe } from '@/hooks/auth';
    import { tokenStorage } from '@/lib/tokenStorage';
  • 엄격 λͺ¨λ“œ: strict: true둜 νƒ€μž… μ•ˆμ •μ„± κ°•ν™”

vite.config.ts - λΉŒλ“œ μ„€μ •

  • React ν”ŒλŸ¬κ·ΈμΈ: Fast Refresh 지원
  • SVGR ν”ŒλŸ¬κ·ΈμΈ: SVGλ₯Ό React μ»΄ν¬λ„ŒνŠΈλ‘œ import κ°€λŠ₯
    import { ReactComponent as Logo } from '@/assets/icons/logo.svg';
    // λ˜λŠ”
    import Logo from '@/assets/icons/logo.svg?react';

postcss.config.js - CSS 처리

  • TailwindCSS v4: μƒˆλ‘œμš΄ μ—”μ§„ μ‚¬μš© (@tailwindcss/postcss)
  • Autoprefixer: λΈŒλΌμš°μ € ν˜Έν™˜μ„± μžλ™ 처리

μ•„ν‚€ν…μ²˜ κ°€μ΄λ“œ

인증 μ‹œμŠ€ν…œ ꡬ쑰

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                           μ•± μ‹œμž‘ (main.tsx)                         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚
                                    v
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         AuthProvider                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ 1. tokenStorage.get() β†’ μ €μž₯된 토큰 확인                      β”‚    β”‚
β”‚  β”‚ 2. getMe() β†’ 토큰 μœ νš¨μ„± 검증                                 β”‚    β”‚
β”‚  β”‚ 3. μ‹€νŒ¨ μ‹œ β†’ refreshToken() β†’ 토큰 κ°±μ‹  μ‹œλ„                  β”‚    β”‚
β”‚  β”‚ 4. 성곡 β†’ useAuthStore에 user 정보 μ €μž₯                       β”‚    β”‚
β”‚  β”‚ 5. μ‹€νŒ¨ β†’ logout() 처리                                       β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                                                      β”‚
β”‚  isInitialized = false λ™μ•ˆ λ‘œλ”© μŠ€ν”Όλ„ˆ ν‘œμ‹œ                         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚
                                    v
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         RouterProvider                               β”‚
β”‚                      (νŽ˜μ΄μ§€ λ Œλ”λ§ μ‹œμž‘)                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

API 톡신 ꡬ쑰

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  μ»΄ν¬λ„ŒνŠΈ    β”‚ -> β”‚ Custom Hook β”‚ -> β”‚  API ν•¨μˆ˜   β”‚ -> β”‚   Axios     β”‚
β”‚ (LoginPage) β”‚    β”‚ (useLogin)  β”‚    β”‚ (auth.ts)   β”‚    β”‚ Instance    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚                                     β”‚
                          v                                     v
                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                   β”‚ React Query β”‚                      β”‚ Interceptor β”‚
                   β”‚ (캐싱/μƒνƒœ) β”‚                      β”‚ (토큰 처리) β”‚
                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

μ‚¬μš© μ˜ˆμ‹œ:

// νŽ˜μ΄μ§€μ—μ„œ ν›… μ‚¬μš©
import { useLogin } from '@/hooks/auth';

const { mutate: login, isPending } = useLogin({ rememberMe: true });

login({ email: 'test@test.com', password: '1234' });

Axios 인터셉터 (토큰 μžλ™ κ°±μ‹ )

apis/axiosInstance.tsμ—μ„œ λ‹€μŒ κΈ°λŠ₯을 μžλ™ μ²˜λ¦¬ν•©λ‹ˆλ‹€:

1. μš”μ²­ 인터셉터

λͺ¨λ“  μš”μ²­ β†’ tokenStorageμ—μ„œ 토큰 쑰회 β†’ Authorization 헀더에 μžλ™ μΆ”κ°€

2. 응닡 인터셉터 (401 μžλ™ 처리)

API μš”μ²­ μ‹€νŒ¨ (401 Unauthorized)
        β”‚
        v
refresh μš”μ²­ μžμ²΄κ°€ 401? ──Yes──> λ‘œκ·Έμ•„μ›ƒ β†’ /auth둜 이동
        β”‚
        No
        v
이미 refresh 쀑? ──Yes──> λŒ€κΈ°μ—΄(Queue)에 μΆ”κ°€ β†’ refresh μ™„λ£Œ ν›„ μž¬μ‹œλ„
        β”‚
        No
        v
refresh ν† ν°μœΌλ‘œ μƒˆ access 토큰 λ°œκΈ‰
        β”‚
        v
μ›λž˜ μš”μ²­ μž¬μ‹œλ„ (μƒˆ 토큰 μ‚¬μš©)

λ™μ‹œ μš”μ²­ 처리:

μš”μ²­1 ─── 401 ─── refresh μ‹œμž‘ ════════ 성곡! ─── μž¬μ‹œλ„ ─── μ™„λ£Œ
μš”μ²­2 ─── 401 ─── λŒ€κΈ°μ—΄ μΆ”κ°€ ── λŒ€κΈ°μ€‘... ─── μž¬μ‹œλ„ ─── μ™„λ£Œ
μš”μ²­3 ─── 401 ─── λŒ€κΈ°μ—΄ μΆ”κ°€ ── λŒ€κΈ°μ€‘... ─── μž¬μ‹œλ„ ─── μ™„λ£Œ
                                    ↑
                              processQueue()κ°€
                              λŒ€κΈ°μ—΄ μ „λΆ€ 깨움

토큰 μ €μž₯μ†Œ (tokenStorage)

lib/tokenStorage.tsμ—μ„œ 토큰을 κ΄€λ¦¬ν•©λ‹ˆλ‹€:

μ˜΅μ…˜ μ €μž₯μ†Œ μ„€λͺ…
persist: true localStorage λΈŒλΌμš°μ € 닫아도 μœ μ§€ (둜그인 μœ μ§€ O)
persist: false sessionStorage νƒ­ λ‹«μœΌλ©΄ μ‚­μ œ (둜그인 μœ μ§€ X)
// 둜그인 μ‹œ
tokenStorage.set(accessToken, rememberMe);  // rememberMe 체크 여뢀에 따라 μ €μž₯μ†Œ κ²°μ •

// 쑰회
tokenStorage.get();  // μžλ™μœΌλ‘œ μ˜¬λ°”λ₯Έ μ €μž₯μ†Œμ—μ„œ 쑰회

// λ‘œκ·Έμ•„μ›ƒ μ‹œ
tokenStorage.remove();  // λͺ¨λ“  μ €μž₯μ†Œμ—μ„œ μ‚­μ œ

Zustand μƒνƒœ 관리

store/useAuthStore.tsμ—μ„œ 인증 μƒνƒœλ₯Ό κ΄€λ¦¬ν•©λ‹ˆλ‹€:

interface AuthState {
  user: User | null;           // μ‚¬μš©μž 정보
  isAuthenticated: boolean;    // 둜그인 μ—¬λΆ€
  isInitialized: boolean;      // μ•± μ΄ˆκΈ°ν™” μ™„λ£Œ μ—¬λΆ€

  setAuth: (user, token, persist?) => void;  // 둜그인 처리
  setUser: (user) => void;                   // μœ μ € 정보 μ—…λ°μ΄νŠΈ
  logout: () => void;                        // λ‘œκ·Έμ•„μ›ƒ 처리
}

zustand persist μ‚¬μš© μ‹œ 주의:

// λΆˆν•„μš”ν•œ λ¦¬λ Œλ”λ§ λ°©μ§€λ₯Ό μœ„ν•΄ useShallow μ‚¬μš© ꢌμž₯
import { useShallow } from 'zustand/react/shallow';

const { user, isAuthenticated } = useAuthStore(
  useShallow((state) => ({
    user: state.user,
    isAuthenticated: state.isAuthenticated,
  }))
);

React Query μ„€μ •

apis/queryClient.tsμ—μ„œ κΈ°λ³Έ μ„€μ •:

  • staleTime: 5λΆ„ - 데이터가 5λΆ„κ°„ fresh μƒνƒœ μœ μ§€
  • μ—λŸ¬ λ°œμƒ μ‹œ Sonner ν† μŠ€νŠΈλ‘œ μžλ™ μ•Œλ¦Ό
  • React Query Devtools: 개발 ν™˜κ²½μ—μ„œ 우츑 ν•˜λ‹¨ λ²„νŠΌμœΌλ‘œ μΊμ‹œ μƒνƒœ 확인 κ°€λŠ₯

CSS ν…Œλ§ˆ λ³€μˆ˜

styles/theme.css에 μ •μ˜λœ CSS λ³€μˆ˜λ“€μž…λ‹ˆλ‹€. Tailwind와 ν•¨κ»˜ μ‚¬μš©ν•˜μ„Έμš”.

/* 색상 */
--color-primary: #3B82F6;      /* 메인 컬러 */
--color-secondary: #6B7280;    /* 보쑰 컬러 */
--color-success: #22C55E;      /* 성곡 */
--color-warning: #F59E0B;      /* κ²½κ³  */
--color-error: #EF4444;        /* μ—λŸ¬ */

/* 폰트 크기 */
--font-size-xs ~ --font-size-4xl

/* 간격 */
--spacing-1 ~ --spacing-20

/* ν…Œλ‘λ¦¬ 반경 */
--radius-sm ~ --radius-full

GitHub ν…œν”Œλ¦Ώ

PR ν…œν”Œλ¦Ώ

PR 생성 μ‹œ μžλ™μœΌλ‘œ μ²΄ν¬λ¦¬μŠ€νŠΈκ°€ μ œκ³΅λ©λ‹ˆλ‹€:

  • 버그 μˆ˜μ •
  • 크둜슀 λΈŒλΌμš°μ§• ν…ŒμŠ€νŠΈ
  • λ””μžμΈ/λ§ˆν¬μ—…
  • κΈ°λŠ₯ μΆ”κ°€
  • λ¦¬νŒ©ν† λ§ λ“±

Issue ν…œν”Œλ¦Ώ

두 κ°€μ§€ 이슈 νƒ€μž…μ΄ μ€€λΉ„λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€:

  • Feature: μƒˆλ‘œμš΄ κΈ°λŠ₯ μš”μ²­
  • Fix: 버그 리포트

개발 μ»¨λ²€μ…˜

Commit μ»¨λ²€μ…˜

[νƒ€μž…] : 컀밋 λ©”μ‹œμ§€
νƒ€μž… μ„€λͺ…
[Feat] μƒˆλ‘œμš΄ κΈ°λŠ₯ μΆ”κ°€
[Fix] 버그 μˆ˜μ •
[Refactor] μ½”λ“œ λ¦¬νŒ©ν† λ§ (κΈ°λŠ₯ λ³€κ²½ μ—†μŒ)
[Style] μ½”λ“œ ν¬λ§·νŒ…, μ„Έλ―Έμ½œλ‘  λˆ„λ½ λ“±
[Design] UI/UX λ””μžμΈ λ³€κ²½
[Chore] λΉŒλ“œ, μ„€μ • 파일 μˆ˜μ •
[Docs] λ¬Έμ„œ μˆ˜μ •
[Test] ν…ŒμŠ€νŠΈ μ½”λ“œ μΆ”κ°€/μˆ˜μ •

μ˜ˆμ‹œ:

[Feat] : 둜그인 νŽ˜μ΄μ§€ κ΅¬ν˜„
[Fix] : 토큰 만료 μ‹œ λ¦¬λ‹€μ΄λ ‰νŠΈ 였λ₯˜ μˆ˜μ •
[Refactor] : API 호좜 둜직 뢄리
[Chore] : ESLint μ„€μ • μΆ”κ°€

파일/폴더 넀이밍

  • μ»΄ν¬λ„ŒνŠΈ: PascalCase (Button.tsx, HomePage.tsx)
  • ν›…: use + camelCase (useLogin.ts, useAuthQueries.ts)
  • zustand μŠ€ν† μ–΄: use + camelCase + Store (useAuthStore.ts)
  • νƒ€μž…: camelCase + .type 접미사 (auth.type.ts)
  • μœ ν‹Έ: camelCase (formatDate.ts)

Import μˆœμ„œ (μžλ™ μ •λ ¬)

// 1. React
import { useState } from 'react';

// 2. μ™ΈλΆ€ 라이브러리
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

// 3. λ‚΄λΆ€ μ ˆλŒ€ 경둜 (@/)
import { Button } from '@/components/Button';
import { useLogin, useMe } from '@/hooks/auth';
import { tokenStorage } from '@/lib/tokenStorage';
import useAuthStore from '@/store/useAuthStore';

// 4. μƒλŒ€ 경둜
import { HomeInput } from './HomeInput';

// 5. CSS
import './styles.css';

νƒ€μž… Import

// νƒ€μž…λ§Œ importν•  λ•ŒλŠ” λ°˜λ“œμ‹œ type ν‚€μ›Œλ“œ μ‚¬μš©
import type { User, LoginRequest } from '@/types/auth.type';

// κ°’κ³Ό νƒ€μž…μ„ ν•¨κ»˜ importν•  λ•Œ
import { login, type LoginResponse } from '@/apis/auth/auth';

문제 ν•΄κ²°

@/ κ²½λ‘œκ°€ μΈμ‹λ˜μ§€ μ•Šμ•„μš”

IDEμ—μ„œ tsconfig.json을 λ‹€μ‹œ λ‘œλ“œν•˜μ„Έμš”:

  • VSCode: Cmd/Ctrl + Shift + P -> TypeScript: Restart TS Server

ESLint μ—λŸ¬κ°€ μžλ™μœΌλ‘œ μ•ˆ κ³ μ³μ Έμš”

npm run lint:fix

λ˜λŠ” VSCode μ„€μ •μ—μ„œ μ €μž₯ μ‹œ μžλ™ μˆ˜μ • ν™œμ„±ν™”:

{
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}

Releases

No releases published

Packages

 
 
 

Contributors