Skip to content

f-lab-edu/Ticketing-System-MVP

Β 
Β 

Repository files navigation

이 μ €μž₯μ†Œμ˜ READMEλŠ” ν”„λ‘œμ νŠΈ μ‹€ν–‰ 방법과 전체 ꡬ쑰λ₯Ό λΉ λ₯΄κ²Œ νŒŒμ•…ν•˜κΈ° μœ„ν•œ λ¬Έμ„œμž…λ‹ˆλ‹€. 과제 μš”κ΅¬μ‚¬ν•­μ„ μ–΄λ–»κ²Œ ν•΄μ„ν–ˆκ³ , μ–΄λ–€ κΈ°μ€€μœΌλ‘œ κ΅¬ν˜„ν–ˆλŠ”μ§€μ— λŒ€ν•œ λ‚΄μš©μ€ ASSIGNMENT.md에 μ •λ¦¬λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

과제 μ„€λͺ…

ν‹°μΌ“νŒ… λŒ€κΈ°μ—΄ + 결제 ν”Œλ‘œμš°λ₯Ό λ§Œλ“œλŠ” κ³Όμ œμž…λ‹ˆλ‹€. μ‚¬μš©μžλŠ” 이벀트 티켓을 μ˜ˆλ§€ν•©λ‹ˆλ‹€. (24μ‹œκ°„ 이내 κ΅¬ν˜„)

ν•„μˆ˜ μš”κ΅¬μ‚¬ν•­

ν‹°μΌ“ λͺ©λ‘ β†’ ν‹°μΌ“ 상세 β†’ λŒ€κΈ°μ—΄ (ν•„μš” μ‹œ) β†’ μ’Œμ„ 선택 β†’ μ™„λ£Œμ˜ ν”Œλ‘œμš°λ‘œ κ΅¬μ„±λ©λ‹ˆλ‹€.

ν‹°μΌ“ λͺ©λ‘ νŽ˜μ΄μ§€

  • ν‹°μΌ“ λͺ©λ‘λ“€μ„ 좜λ ₯ν•©λ‹ˆλ‹€.
  • ν‹°μΌ“ ν•­λͺ©μ„ ν΄λ¦­ν•˜λ©΄ ν•΄λ‹Ή ν‹°μΌ“ 상세 νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•©λ‹ˆλ‹€.

ν‹°μΌ“ 상세 νŽ˜μ΄μ§€

  • ν‹°μΌ“μ˜ 상세 이미지, 상세 μ„€λͺ…, μ’Œμ„ 가격 등을 좜λ ₯ν•©λ‹ˆλ‹€.
  • μž…μž₯ λ²„νŠΌμ΄ μ‘΄μž¬ν•˜λ©°, 이λ₯Ό ν΄λ¦­ν•˜λ©΄
    • μž…μž₯ 토큰을 λ°œκΈ‰λ°›μŠ΅λ‹ˆλ‹€.
    • λŒ€κΈ°μ—΄μ΄ μžˆμ„ 경우 λŒ€κΈ°μ—΄ μž…μž₯ νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•©λ‹ˆλ‹€. κ·Έλ ‡μ§€ μ•Šμ„ 경우 λ°”λ‘œ μ’Œμ„ 선택 νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•©λ‹ˆλ‹€.

λŒ€κΈ°μ—΄ νŽ˜μ΄μ§€

  • λŒ€κΈ°μ—΄ μ§„ν–‰λ₯ (0–100%)을 λ³΄μ—¬μ€λ‹ˆλ‹€.
  • λŒ€κΈ°μ—΄μ΄ ν•΄μ†Œλ˜μ—ˆμ„ 경우 μ’Œμ„ 선택 νŽ˜μ΄μ§€λ‘œ μ΄λ™ν•©λ‹ˆλ‹€.

μ’Œμ„ 선택 νŽ˜μ΄μ§€

  • λ§Œμ•½ λ°œκΈ‰λœ μž…μž₯ 토큰을 μ‘°νšŒν–ˆμ„ λ•Œ, λŒ€κΈ°μ—΄μ— μžˆλŠ” 토큰이라면 λŒ€κΈ°μ—΄ μž…μž₯ νŽ˜μ΄μ§€λ‘œ λ¦¬λ‹€μ΄λ ‰μ…˜ν•©λ‹ˆλ‹€.
  • λŒ€κΈ°μ—΄ 톡과 ν›„ μ œν•œ μ‹œκ°„ 1λΆ„ 내에 λ‚΄ μ’Œμ„μ„ μ„ νƒν•˜μ§€ μ•ŠμœΌλ©΄ 만료 μ²˜λ¦¬ν•©λ‹ˆλ‹€.

μ˜ˆμ•½ μ™„λ£Œ νŽ˜μ΄μ§€

μ„ νƒν•œ μ’Œμ„, 가격을 좜λ ₯ν•˜κ³  λλƒ…λ‹ˆλ‹€.

API

APIλŠ” MSW(Mock Service Worker)λ₯Ό μ΄μš©ν•˜μ—¬ λͺ¨ν‚Ήλ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. μ•„λž˜μ— μ •λ¦¬λœ API λͺ…μ„Έλ₯Ό μ°Έκ³ ν•΄ κΈ°λŠ₯을 κ΅¬ν˜„ν•΄μ£Όμ„Έμš”.

μ •ν™•ν•œ MSW λͺ¨ν‚Ή λ™μž‘μ„ 확인할 ν•„μš”κ°€ μžˆλ‹€λ©΄, src/mocks/handlers.tsλ₯Ό μ°Έκ³ ν•΄μ£Όμ„Έμš”.

ν‹°μΌ“ λͺ©λ‘

GET /api/tickets

  • Request: (none)
  • Response 200
{
  "success": true,
  "data": [
    {
      "id": "string",
      "title": "string",
      "description": "string",
      "image": "string",
      "price": 0,
      "totalSeats": 0,
      "availableSeats": 0,
      "eventDate": "YYYY-MM-DD",
      "venue": "string"
    }
  ]
}

ν‹°μΌ“ 상세

GET /api/tickets/:id

  • Request Params: id: string
  • Response 200
{ "success": true, "data": { /_ Ticket _/ } }
  • Response 404
{ "success": false, "message": "티켓을 찾을 수 μ—†μŠ΅λ‹ˆλ‹€." }

토큰 λ°œκΈ‰

POST /api/tickets/:id/enter

  • Request Params: id: string
  • Request Body: (none)
  • Response 200
{
  "success": true,
  "data": {
    "tokenId": "string",
    "hasQueue": true,
    "expiresAt": 1730000000000
  }
}
  • Response 404
{ "success": false, "message": "티켓을 찾을 수 μ—†μŠ΅λ‹ˆλ‹€." }

λŒ€κΈ°μ—΄ μƒνƒœ 쑰회

GET /api/queue/:tokenId

  • Request Params: tokenId: string
  • Response 200
{
  "success": true,
  "data": {
    "token": {
      "id": "string",
      "ticketId": "string",
      "status": "waiting|ready|expired",
      "position": 0,
      "totalInQueue": 0,
      "expiresAt": 1730000000000,
      "createdAt": 1730000000000
    },
    "queueStatus": {
      "position": 0,
      "totalInQueue": 0,
      "progress": 0,
      "estimatedWaitTime": 0
    }
  }
}
  • Response 404
{ "success": false, "message": "μœ νš¨ν•˜μ§€ μ•Šμ€ ν† ν°μž…λ‹ˆλ‹€." }
  • Response 410
{ "success": false, "message": "토큰이 λ§Œλ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€." }

μ’Œμ„ λͺ©λ‘

GET /api/tickets/:id/seats

  • Request Params: id: string
  • Response 200
{
  "success": true,
  "data": [
    {
      "id": "string",
      "row": "A",
      "number": 1,
      "price": 0,
      "isAvailable": true
    }
  ]
}

μ’Œμ„ ν™•μ • (μ˜ˆμ•½ ν™•μ •)

POST /api/reservations

  • Request Body
{ "tokenId": "string", "seatId": "string" }
  • Response 200
{
  "success": true,
  "data": {
    "id": "string",
    "ticketId": "string",
    "seatId": "string",
    "price": 0,
    "status": "completed",
    "expiresAt": 1730000000000,
    "createdAt": 1730000000000
  }
}
  • Response 404
{ "success": false, "message": "μœ νš¨ν•˜μ§€ μ•Šμ€ ν† ν°μž…λ‹ˆλ‹€." }

// or

{ "success": false, "message": "μ’Œμ„μ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€." }
  • Response 410 (토큰 만료)
{ "success": false, "message": "토큰이 λ§Œλ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€." }
  • Response 400 (λŒ€κΈ°μ€‘/이미 μ˜ˆμ•½λ¨)
{ "success": false, "message": "아직 λŒ€κΈ°μ—΄μ— μžˆμŠ΅λ‹ˆλ‹€." }

// or

{ "success": false, "message": "이미 μ˜ˆμ•½λœ μ’Œμ„μž…λ‹ˆλ‹€." }

μ˜ˆμ•½ 상세 (ν•„μš”ν•œ κ²½μš°μ—λ§Œ μ“°μ„Έμš”)

GET /api/reservations/:id

  • Request Params: id: string
  • Response 200
{
  "success": true,
  "data": {
    "reservation": { /_ Reservation _/ },
    "ticket": { /_ Ticket _/ },
    "seat": { /_ Seat _/ }
  }
}
  • Response 404
{ "success": false, "message": "μ˜ˆμ•½μ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€." }

κ΅¬ν˜„ μ‹œ μœ μ˜μ‚¬ν•­

  • shadcnκ³Ό 같은 UI 라이브러리λ₯Ό μ‚¬μš©ν•˜κ±°λ‚˜ κΈ°λ³Έ HTML νƒœκ·Έλ§Œμ„ μ΄μš©ν•΄ κ°œλ°œν•΄μ£Όμ„Έμš”.
  • μ—λŸ¬ λ©”μ‹œμ§€, λ²„νŠΌ ν™œμ„±ν™” μ—¬λΆ€ 등은 μ‹€μ‹œκ°„μœΌλ‘œ λ°˜μ‘ν•˜λ„λ‘ ν•΄μ£Όμ„Έμš”.
  • μ‹œκ°„ μ ˆμ•½μ„ μœ„ν•΄ ν•„μš”μ— 따라 자주 μ‚¬μš©ν•˜λ˜ μ¨λ“œνŒŒν‹° 라이브러리λ₯Ό μ„€μΉ˜ν•˜μ—¬ μ‚¬μš©ν•˜λŠ” 것을 ꢌμž₯ν•©λ‹ˆλ‹€.
  • TypeScript 기반의 ν”„λ‘œμ νŠΈλ‘œ, νƒ€μž… 건전성을 μ§€ν‚€λŠ” λ°©ν–₯으둜 μ½”λ“œλ₯Ό μž‘μ„±ν•΄μ£Όμ„Έμš”.

About

🎫 ν‹°μΌ“νŒ… λŒ€κΈ°μ—΄ 및 μ’Œμ„ μ˜ˆμ•½ μ‹œμŠ€ν…œ κ΅¬ν˜„ 과제 (24H)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • TypeScript 79.4%
  • JavaScript 19.9%
  • Other 0.7%