Skip to content

oh1marin/fs9team3-snack-be

Repository files navigation

🍿 Snack - κΈ°μ—…μš© 간식 λ§ˆμΌ“ν”Œλ ˆμ΄μŠ€

Snack은 κΈ°μ—… λ‹΄λ‹Ήμžκ°€ 사내 간식 및 음료λ₯Ό κ΄€λ¦¬ν•˜κ³  μ£Όλ¬Έν•  수 μžˆλŠ” λ§ˆμΌ“ν”Œλ ˆμ΄μŠ€ ν”Œλž«νΌμž…λ‹ˆλ‹€!

μ΅œκ³ κ΄€λ¦¬μžλŠ” 이메일 μ΄ˆλŒ€λ‘œ 직원듀을 ν”Œλž«νΌμ— κ°€μž…μ‹œν‚€κ³ , μœ μ € κΆŒν•œμ„ μΌλ°˜Β·κ΄€λ¦¬μžλ‘œ λ³€κ²½ν•˜κ±°λ‚˜ μœ μ €μ˜ 계정을 μ‚­μ œν•  수 μžˆμŠ΅λ‹ˆλ‹€. 월별 μ˜ˆμ‚°μ„ μ„€μ •ν•΄ νšŒμ‚¬μ˜ 간식 μ§€μΆœμ„ κ΄€λ¦¬ν•˜λ©°, μ˜ˆμ‚°μ€ λ§€μ›” μžλ™μœΌλ‘œ μ΄ˆκΈ°ν™”λ©λ‹ˆλ‹€.

직원듀은 μ›ν•˜λŠ” μƒν’ˆμ„ 직접 등둝할 수 있으며, μž₯λ°”κ΅¬λ‹ˆμ— λ‹΄μ•„ ꡬ맀λ₯Ό μš”μ²­ν•©λ‹ˆλ‹€. κ΄€λ¦¬μžλŠ” 이λ₯Ό μŠΉμΈν•˜κ±°λ‚˜ λ°˜λ €ν•©λ‹ˆλ‹€. κ΄€λ¦¬μžλŠ” μ¦‰μ‹œ ꡬ맀가 κ°€λŠ₯ν•˜λ©°, μž₯λ°”κ΅¬λ‹ˆμ—μ„œ μž”μ—¬ μ˜ˆμ‚°μ„ μ‹€μ‹œκ°„μœΌλ‘œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. 승인된 주문은 ꡬ맀 내역에 κΈ°λ‘λ˜μ–΄ κ΄€λ¦¬μžκ°€ 전체 내역을 μ‘°νšŒν•  수 μžˆμŠ΅λ‹ˆλ‹€.


πŸ”— 링크

μ„œλΉ„μŠ€ URL
🌐 배포 μ‚¬μ΄νŠΈ https://marin-snack.store/
πŸ“„ API λ¬Έμ„œ http://13.209.35.172/api-docs/
πŸ–₯️ FE μ €μž₯μ†Œ github.com/oh1marin/fs9team3-snack-fe
βš™οΈ BE μ €μž₯μ†Œ github.com/oh1marin/fs9team3-snack-be

πŸ“Έ ν™”λ©΄ 미리보기

ν™ˆ 둜그인 μƒν’ˆ λͺ©λ‘
μƒν’ˆ 상세 μƒν’ˆ 등둝 λͺ¨λ‹¬ μž₯λ°”κ΅¬λ‹ˆ
μ£Όλ¬Έ λ‚΄μ—­ κ΄€λ¦¬μž κ΄€λ¦¬μž 승인/반렀

πŸ— μ‹œμŠ€ν…œ μ•„ν‚€ν…μ²˜


πŸ›  기술 μŠ€νƒ

Frontend

Next.js React TypeScript TailwindCSS

Backend

Node.js Express.js TypeScript JWT Nodemailer node-cron

Database & Storage

PostgreSQL Prisma AWS S3

Deploy & Infra

Vercel AWS EC2 AWS RDS Cloudflare


πŸ—„ DB μŠ€ν‚€λ§ˆ


πŸ”Œ API λ¬Έμ„œ

http://13.209.35.172/api-docs/


πŸ‘€ λ‹΄λ‹Ή μ—­ν• 

개인 ν”„λ‘œμ νŠΈλ‘œ, κΈ°νšλΆ€ν„° λ°°ν¬κΉŒμ§€ λ‹¨λ…μœΌλ‘œ μ§„ν–‰ν–ˆμŠ΅λ‹ˆλ‹€.

λΆ„μ•Ό λ‚΄μš©
Frontend μ „ νŽ˜μ΄μ§€ UI κ΅¬ν˜„, μƒνƒœ 관리, 인증 흐름, μ„±λŠ₯ μ΅œμ ν™”
Backend REST API 섀계 및 κ΅¬ν˜„, JWT μΈμ¦Β·κΆŒν•œ 미듀웨어, 이메일 λ°œμ†‘
Database Prisma μŠ€ν‚€λ§ˆ 섀계, PostgreSQL λ§ˆμ΄κ·Έλ ˆμ΄μ…˜Β·μ‹œλ“œ
Infra AWS EC2 배포, S3 이미지 μ—…λ‘œλ“œ, Vercel, Cloudflare 도메인 μ—°κ²°

✨ μ£Όμš” κΈ°λŠ₯

1. 인증

  • 이메일 기반 νšŒμ›κ°€μž… / 둜그인 / λ‘œκ·Έμ•„μ›ƒ
  • JWT 토큰 기반 인증 (μΏ ν‚€)
  • μ΅œκ³ κ΄€λ¦¬μž μ΄ˆλŒ€ 메일 λ°œμ†‘

2. μƒν’ˆ

  • μƒν’ˆ λͺ©λ‘ (μΉ΄ν…Œκ³ λ¦¬ ν•„ν„°, μ •λ ¬: μ΅œμ‹ μˆœ / 판맀순 / κ°€κ²©μˆœ)
  • μƒν’ˆ 등둝 Β· μˆ˜μ • Β· μ‚­μ œ
  • AWS S3 이미지 μ—…λ‘œλ“œ
  • λˆ„μ  ꡬ맀 횟수 λ°°μ§€

3. μž₯λ°”κ΅¬λ‹ˆ Β· μ£Όλ¬Έ

  • μž₯λ°”κ΅¬λ‹ˆ λ‹΄κΈ° Β· μˆ˜λŸ‰ λ³€κ²½ Β· μ‚­μ œ
  • ꡬ맀 μš”μ²­ (일반) / μ¦‰μ‹œ ꡬ맀 (κ΄€λ¦¬μž)
  • μ£Όλ¬Έ λͺ©λ‘ Β· 상세 쑰회 Β· μ·¨μ†Œ

4. κ΄€λ¦¬μž

  • νšŒμ› 관리: μ΄ˆλŒ€, κΆŒν•œ λ³€κ²½ (일반 / κ΄€λ¦¬μž / μ΅œκ³ κ΄€λ¦¬μž)
  • μ˜ˆμ‚° 관리: 월별 μ˜ˆμ‚° μ„€μ • (node-cron μžλ™ μ΄ˆκΈ°ν™”)
  • 승인 λŒ€κΈ°: ꡬ맀 μš”μ²­ 승인 Β· 반렀
  • μƒν’ˆ 관리: 등둝 μƒν’ˆ λͺ©λ‘ Β· μˆ˜μ •
  • ꡬ맀 λ‚΄μ—­: 승인 μ™„λ£Œ μ£Όλ¬Έ 쑰회

πŸ“ ν”„λ‘œμ νŠΈ ꡬ쑰

πŸ–₯️ fs9team3-snack-fe/          # ν”„λ‘ νŠΈμ—”λ“œ
β”œβ”€β”€ πŸ“ src/
β”‚   β”œβ”€β”€ πŸ“ app/
β”‚   β”‚   β”œβ”€β”€ πŸ” (auth)/              # 둜그인, νšŒμ›κ°€μž…
β”‚   β”‚   β”œβ”€β”€ πŸ”’ (protected)/         # 인증 ν•„μš” νŽ˜μ΄μ§€
β”‚   β”‚   β”‚   β”œβ”€β”€ πŸ“¦ items/           # μƒν’ˆ λͺ©λ‘Β·μƒμ„Έ
β”‚   β”‚   β”‚   β”‚   └── register/       # μƒν’ˆ 등둝
β”‚   β”‚   β”‚   β”œβ”€β”€ πŸ›’ cart/            # μž₯λ°”κ΅¬λ‹ˆ
β”‚   β”‚   β”‚   β”‚   └── complete/       # ꡬ맀 μ™„λ£Œ
β”‚   β”‚   β”‚   β”œβ”€β”€ πŸ“‹ orders/          # μ£Όλ¬Έ λͺ©λ‘Β·μƒμ„Έ
β”‚   β”‚   β”‚   β”œβ”€β”€ πŸ‘€ profile/         # ν”„λ‘œν•„
β”‚   β”‚   β”‚   └── βš™οΈ admin/           # κ΄€λ¦¬μž
β”‚   β”‚   β”‚       β”œβ”€β”€ items/          # μƒν’ˆ 관리
β”‚   β”‚   β”‚       β”œβ”€β”€ orders/         # 승인 λŒ€κΈ°
β”‚   β”‚   β”‚       β”œβ”€β”€ purchase-history/ # ꡬ맀 λ‚΄μ—­
β”‚   β”‚   β”‚       └── users/          # νšŒμ› 관리
β”‚   β”‚   β”œβ”€β”€ πŸ“„ page.tsx             # λžœλ”©
β”‚   β”‚   └── ui/                     # AddProductBtn, SortButton λ“±
β”‚   β”œβ”€β”€ 🧩 components/              # 곡톡 μ»΄ν¬λ„ŒνŠΈ
β”‚   β”‚   └── icons/
β”‚   β”œβ”€β”€ 🌐 contexts/                # AuthContext, CartContext, ModalContext
β”‚   β”œβ”€β”€ πŸ”§ lib/
β”‚   β”‚   β”œβ”€β”€ api/                    # apiClient, auth, cart, items, orders, superAdmin
β”‚   β”‚   β”œβ”€β”€ actions/                # Server Actions
β”‚   β”‚   β”œβ”€β”€ service/                # authService, userService
β”‚   β”‚   └── utils/                  # image, purchaseBadge
β”‚   └── layout/                     # NavBar

βš™οΈ fs9team3-snack-be/          # λ°±μ—”λ“œ
β”œβ”€β”€ πŸ“ src/
β”‚   β”œβ”€β”€ πŸ“„ app.ts                   # Express μ•± μ§„μž…μ 
β”‚   β”œβ”€β”€ πŸ›£οΈ routes/                  # auth, items, cart, orders, users, admin, super-admin
β”‚   β”œβ”€β”€ πŸ“‹ controllers/             # 각 도메인 λΉ„μ¦ˆλ‹ˆμŠ€ 둜직
β”‚   β”œβ”€β”€ πŸ›‘οΈ middleware/              # JWT 인증, κΆŒν•œ 체크, μ—λŸ¬ ν•Έλ“€λŸ¬
β”‚   β”œβ”€β”€ πŸ—„οΈ prisma/                  # schema.prisma, migrations, seed
β”‚   β”œβ”€β”€ ⏰ cron/                    # 월별 μ˜ˆμ‚° μ΄ˆκΈ°ν™” μŠ€μΌ€μ€„λŸ¬
β”‚   β”œβ”€β”€ πŸ”§ config/                  # Swagger, S3 μ—…λ‘œλ“œ μ„€μ •
β”‚   β”œβ”€β”€ πŸ“ types/                   # 곡톡 νƒ€μž… μ •μ˜
β”‚   └── πŸ”¨ utils/                   # μ—λŸ¬ 클래슀, 이메일, 이미지 URL, Prisma 싱글톀

πŸ› νŠΈλŸ¬λΈ”μŠˆνŒ…

1. 헀더 둜그인 μƒνƒœ λΆˆμ•ˆμ • 문제

둜그인 μƒνƒœμž„μ—λ„ μƒˆλ‘œκ³ μΉ¨ν•˜λ©΄ λΉ„λ‘œκ·ΈμΈ 헀더가 κΉœλΉ‘μ΄κ±°λ‚˜, 토큰이 μžˆλŠ”λ°λ„ λΉ„λ‘œκ·ΈμΈμœΌλ‘œ ν‘œμ‹œλ˜λŠ” ν˜„μƒμ΄ λ³΅ν•©μ μœΌλ‘œ λ°œμƒν–ˆλ‹€.

원인은 μ„Έ κ°€μ§€μ˜€λ‹€.

  • getMe() 호좜 쀑 setUser()와 setIsLoading(false)κ°€ μ„œλ‘œ λ‹€λ₯Έ 타이밍에 λ°˜μ˜λ˜μ–΄, user === nullμ΄λ©΄μ„œ isLoading === false인 ν”„λ ˆμž„μ΄ ν•œ μˆœκ°„ λ Œλ”λ§λ¨
  • 헀더가 user κ°’λ§ŒμœΌλ‘œ 둜그인 μ—¬λΆ€λ₯Ό νŒλ‹¨ν•΄, /api/auth/me νŒŒμ‹± μ‹€νŒ¨ μ‹œ 토큰이 μžˆμ–΄λ„ λΉ„λ‘œκ·ΈμΈμœΌλ‘œ 인식
  • ν”„λ‘ νŠΈΒ·API ν¬νŠΈκ°€ 달라 Access-Control-Allow-Origin이 λͺ…ν™•ν•˜μ§€ μ•Šμ•„ λΈŒλΌμš°μ €κ°€ μΏ ν‚€λ₯Ό μ „μ†‘ν•˜μ§€ μ•ŠμŒ

ν•΄κ²°

  • setUser()와 λ‘œλ”© μƒνƒœ 변경을 같은 νλ¦„μ—μ„œ μ²˜λ¦¬ν•˜κ³ , finallyμ—μ„œ 무쑰건 setIsLoading(false)λ₯Ό ν˜ΈμΆœν•˜λ˜ ꡬ쑰λ₯Ό 제거
  • μ„œλ²„μ—μ„œ 토큰 검증 κ²°κ³Όλ₯Ό hasToken으둜 헀더에 전달해 둜그인 νŒλ‹¨ κΈ°μ€€ μΆ”κ°€, AuthInitializer둜 userλ₯Ό context에 미리 μ£Όμž…
  • λ°±μ—”λ“œ CORS origin을 λͺ…ν™•νžˆ μ§€μ •ν•˜κ³  credentials: true μœ μ§€

2. λͺ¨λ‹¬ μ»΄ν¬λ„ŒνŠΈ μ§€μ—° λ‘œλ“œ (Dynamic Import)

items/page.tsx, items/[id]/page.tsxμ—μ„œ ProductModal, DeleteModal, AddToCartModal을 상단 import둜 뢈러였고 μžˆμ—ˆλ‹€. λͺ¨λ‹¬μ€ λ²„νŠΌμ„ λˆŒλŸ¬μ•Όλ§Œ μ—΄λ¦¬λŠ” μ»΄ν¬λ„ŒνŠΈμΈλ°, νŽ˜μ΄μ§€ μ§„μž… μ‹œμ λΆ€ν„° λ²ˆλ“€μ— ν¬ν•¨λ˜μ–΄ 초기 λ‘œλ”©μ— 영ν–₯을 μ£Όκ³  μžˆμ—ˆλ‹€.

ν•΄κ²° λͺ¨λ‹¬μ„ μ—¬λŠ” μ‹œμ μ— await import()둜 동적 λ‘œλ“œν•˜λ„λ‘ λ³€κ²½ν–ˆλ‹€.

const { default: ProductModal } = await import("@/components/ProductModal");
const { default: DeleteModal } = await import("@/components/DeleteModal");
const { default: AddToCartModal } = await import("@/components/AddToCartModal");

초기 λ²ˆλ“€ 크기가 μ€„μ—ˆκ³ , λͺ¨λ‹¬μ²˜λŸΌ μ‘°κ±΄λΆ€λ‘œλ§Œ ν•„μš”ν•œ μ»΄ν¬λ„ŒνŠΈλŠ” dynamic importκ°€ μ ν•©ν•˜λ‹€λŠ” 것을 ν™•μΈν–ˆλ‹€.

About

be

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors