/Concert-Booking

🎸 μ½˜μ„œνŠΈ μ˜ˆμ•½ μ„œλΉ„μŠ€

Primary LanguageJava

🎸 μ½˜μ„œνŠΈ μ˜ˆμ•½ μ„œλΉ„μŠ€

πŸ“„ Documents

✏️ Description

  • λŒ€κΈ°μ—΄ μ‹œμŠ€ν…œμ„ 톡해 μœ μž… νŠΈλž˜ν”½μ„ 관리할 수 μžˆλ‹€.
  • μ˜ˆμ•½ μ„œλΉ„μŠ€λŠ” 토큰이 μžˆλŠ” μœ μ €λ§Œ μˆ˜ν–‰ν•  수 μžˆλ‹€.
  • μ’Œμ„ μ˜ˆμ•½ μš”μ²­ μ‹œ, κ²°μ œκ°€ 이루어지지 μ•Šλ”λΌλ„ 일정 μ‹œκ°„λ™μ•ˆ λ‹€λ₯Έ μœ μ €κ°€ ν•΄λ‹Ή μ’Œμ„μ— μ ‘κ·Όν•  수 없도둝 ν•œλ‹€.
  • 결제 μ‹œ, μ‚¬μš©μžλŠ” 미리 μΆ©μ „ν•œ μž”μ•‘μ„ μ΄μš©ν•œλ‹€.

πŸ“ API

  • λŒ€κΈ°μ—΄ 토큰 등둝 및 쑰회 API
  • μ½˜μ„œνŠΈ λͺ©λ‘ 쑰회 API
  • μ½˜μ„œνŠΈ 일정 λͺ©λ‘ 쑰회 API
  • μ½˜μ„œνŠΈ μ’Œμ„ λͺ©λ‘ 쑰회 API
  • μ½˜μ„œνŠΈ μ˜ˆμ•½ μš”μ²­ API
  • μ½˜μ„œνŠΈ μ’Œμ„ 결제 API

πŸ”‘ API Specs

1️⃣ μœ μ € λŒ€κΈ°μ—΄ 토큰 κΈ°λŠ₯

  • μ„œλΉ„μŠ€λ₯Ό μ΄μš©ν•  토큰을 λ°œκΈ‰λ°›λŠ” API λ₯Ό μž‘μ„±ν•œλ‹€.
  • 토큰은 μœ μ €μ˜ UUID 와 ν•΄λ‹Ή μœ μ €μ˜ λŒ€κΈ°μ—΄μ„ 관리할 수 μžˆλŠ” 정보 ( λŒ€κΈ° μˆœμ„œ or μž”μ—¬ μ‹œκ°„ λ“± ) λ₯Ό ν¬ν•¨ν•œλ‹€.
  • 이후 λͺ¨λ“  API λŠ” μœ„ 토큰을 μ΄μš©ν•΄ λŒ€κΈ°μ—΄ 검증을 톡과해야 이용 κ°€λŠ₯ν•˜λ‹€.

기본적으둜 폴링으둜 본인의 λŒ€κΈ°μ—΄μ„ ν™•μΈν•œλ‹€κ³  κ°€μ •ν•œλ‹€.

2️⃣ μ½˜μ„œνŠΈ λ‚ μ§œ / μ’Œμ„ API

  • μ½˜μ„œνŠΈ λ‚ μ§œμ™€ ν•΄λ‹Ή λ‚ μ§œμ˜ μ’Œμ„μ„ μ‘°νšŒν•˜λŠ” API λ₯Ό 각각 μž‘μ„±ν•œλ‹€.
  • μ½˜μ„œνŠΈ λ‚ μ§œ λͺ©λ‘μ„ μ‘°νšŒν•  수 μžˆλ‹€.
  • λ‚ μ§œ 정보λ₯Ό μž…λ ₯λ°›μ•„ μ˜ˆμ•½ κ°€λŠ₯ν•œ μ’Œμ„ 정보λ₯Ό μ‘°νšŒν•  수 μžˆλ‹€.

μ’Œμ„ μ •λ³΄λŠ” 1 ~ 50 κΉŒμ§€μ˜ μ’Œμ„ 번호둜 κ΄€λ¦¬λœλ‹€.

3️⃣ μ½˜μ„œνŠΈ μ’Œμ„ μ˜ˆμ•½ μš”μ²­ API

  • λ‚ μ§œμ™€ μ’Œμ„ 정보λ₯Ό μž…λ ₯ λ°›μ•„ μ’Œμ„μ„ μ˜ˆμ•½ μ²˜λ¦¬ν•˜λŠ” API λ₯Ό μž‘μ„±ν•œλ‹€.
  • μ’Œμ„ μ˜ˆμ•½κ³Ό λ™μ‹œμ— ν•΄λ‹Ή μ’Œμ„μ€ κ·Έ μœ μ €μ—κ²Œ μ•½ 5λΆ„κ°„ μž„μ‹œ λ°°μ •λœλ‹€.
  • λ§Œμ•½ λ°°μ • μ‹œκ°„ 내에 κ²°μ œκ°€ μ™„λ£Œλ˜μ§€ μ•ŠλŠ”λ‹€λ©΄, μ’Œμ„μ— λŒ€ν•œ μž„μ‹œ 배정은 ν•΄μ œλ˜μ–΄μ•Ό ν•˜λ©° λ‹€λ₯Έ μ‚¬μš©μžλŠ” μ˜ˆμ•½ν•  수 μžˆμ–΄μ•Ό ν•œλ‹€.

4️⃣ μœ μ € μž”μ•‘ μΆ©μ „ / 쑰회 API

  • κ²°μ œμ— μ‚¬μš©λ  κΈˆμ•‘μ„ API λ₯Ό 톡해 μΆ©μ „ν•˜λŠ” API λ₯Ό μž‘μ„±ν•œλ‹€.
  • μ‚¬μš©μž μ‹λ³„μž 및 μΆ©μ „ν•  κΈˆμ•‘μ„ λ°›μ•„ μž”μ•‘μ„ μΆ©μ „ν•œλ‹€.
  • μ‚¬μš©μž μ‹λ³„μžλ₯Ό 톡해 ν•΄λ‹Ή μ‚¬μš©μžμ˜ μž”μ•‘μ„ μ‘°νšŒν•œλ‹€.

5️⃣ κ²°μ œ API

  • 결제 μ²˜λ¦¬ν•˜κ³  결제 내역을 μƒμ„±ν•˜λŠ” API λ₯Ό μž‘μ„±ν•œλ‹€.
  • κ²°μ œκ°€ μ™„λ£Œλ˜λ©΄ ν•΄λ‹Ή μ’Œμ„μ˜ μ†Œμœ κΆŒμ„ μœ μ €μ—κ²Œ λ°°μ •ν•˜κ³  λŒ€κΈ°μ—΄ 토큰을 λ§Œλ£Œμ‹œν‚¨λ‹€.

πŸ’‘ KEY POINT

  • μœ μ € κ°„ λŒ€κΈ°μ—΄ μš”μ²­μ„ μˆœμ„œλŒ€λ‘œ μ •ν™•ν•˜κ²Œ μ–΄λ–»κ²Œ μ œκ³΅ν•  것인가?
  • λ™μ‹œμ— μ—¬λŸ¬ μ‚¬μš©μžκ°€ μ˜ˆμ•½ μš”μ²­μ„ ν–ˆμ„ λ•Œ, μ’Œμ„μ΄ μ€‘λ³΅μœΌλ‘œ λ°°μ • κ°€λŠ₯ν•˜μ§€ μ•Šλ„λ‘ ν•΄μ•Ό ν•œλ‹€.

πŸ“† Milestone

https://github.com/users/kdelay/projects/7/views/4

πŸ“Š ERD Diagram

erDiagram
    %% μ‚¬μš©μž
    user {
        bigint id PK "μœ μ € PK"
        decimal amount "μž”μ•‘"
    }
    
    %% λŒ€κΈ°μ—΄ 토큰 정보
    %% user(1) : waiting_slot(N)
    waiting_token {
        bigint id PK "λŒ€κΈ°μ—΄ PK"
        bigint user_id FK "μœ μ € PK"
        string token UK "토큰 정보(UUID)"
        %% DEACTIVATE(λΉ„ν™œμ„±ν™”), ACTIVATE(ν™œμ„±ν™”), EXPIRED(만료됨)
        string waiting_token_status "λŒ€κΈ°μ—΄ 토큰 μƒνƒœ(enum)"
        timestamp created_at "λŒ€κΈ°μ—΄ 토큰 μš”μ²­ μ‹œκ°„"
        timestamp modified_at "λŒ€κΈ°μ—΄ 토큰 μƒνƒœ λ³€κ²½ μ‹œκ°„"
    }

    %% μ½˜μ„œνŠΈ
    concert {
        bigint id PK "μ½˜μ„œνŠΈ PK"
        string name "μ½˜μ„œνŠΈ 이름"
        string host "μ½˜μ„œνŠΈ 주졜자"
    }

    %% μ½˜μ„œνŠΈ λ‚ μ§œ
    %% concert(1) : concert_schedule(N)
    concert_schedule {
        bigint id PK "μ½˜μ„œνŠΈ λ‚ μ§œ PK"
        bigint concert_id FK "μ½˜μ„œνŠΈ PK"
        date concert_date "μ½˜μ„œνŠΈ λ‚ μ§œ"
    }

    %% μ½˜μ„œνŠΈ μ’Œμ„
    %% concert_schedule(1) : concert_seat(N)
    concert_seat {
        bigint id PK "μ½˜μ„œνŠΈ μ’Œμ„ PK"
        bigint concert_id FK "μ½˜μ„œνŠΈ PK"
        bigint concert_schedule_id FK "μ½˜μ„œνŠΈ λ‚ μ§œ PK"
        bigint user_id FK "μœ μ € PK"
        int seat_number "μ½˜μ„œνŠΈ μ’Œμ„ 번호"
        decimal seat_price "μ½˜μ„œνŠΈ μ’Œμ„ κΈˆμ•‘"
        %% AVAILABLE(μ˜ˆμ•½ κ°€λŠ₯), TEMPORARY(μž„μ‹œ μ’Œμ„ 배정쀑), RESERVED(μ˜ˆμ•½λ¨)
        string seat_status "μ½˜μ„œνŠΈ μ’Œμ„ 번호 μƒνƒœ(enum)"
        timestamp modified_at "μ½˜μ„œνŠΈ μ’Œμ„ μƒνƒœ λ³€κ²½ μ‹œκ°„"
        timestamp expired_at "μž„μ‹œ λ°°μ • 만료 μ‹œκ°„"
    }
    
    %% μ˜ˆμ•½
    %% user(1) : reservation(N)
    reservation {
        bigint id PK "μ½˜μ„œνŠΈ μ˜ˆμ•½ PK"
        bigint concert_seat_id FK "μ½˜μ„œνŠΈ μ’Œμ„ PK"
        bigint user_id FK "μœ μ € PK"
        string concert_name "μ½˜μ„œνŠΈ 이름"
        date concert_date "μ½˜μ„œνŠΈ λ‚ μ§œ"
        %% RESERVING(μ˜ˆμ•½μ€‘), RESERVED(μ˜ˆμ•½λ¨), CANCELED(μ˜ˆμ•½ μ·¨μ†Œ)
        string reservation_status "μ˜ˆμ•½ μƒνƒœ(enum)"
        timestamp created_at "μ½˜μ„œνŠΈ μ˜ˆμ•½ μš”μ²­ μ‹œκ°„"
        timestamp modified_at "μ½˜μ„œνŠΈ μ˜ˆμ•½ μƒνƒœ λ³€κ²½ μ‹œκ°„"
    }
    
    %% 결제
    %% reservation(1) : payment(0 or 1)
    payment {
        bigint id PK "μ½˜μ„œνŠΈ 결제 PK"
        bigint reservation_id FK "μ½˜μ„œνŠΈ μ˜ˆμ•½ PK"
        decimal price "결제 κΈˆμ•‘"
        %% COMPLETED(결제 μ™„λ£Œ), CANCELED(결제 μ·¨μ†Œ)
        string payment_state "결제 μƒνƒœ(enum)"
        timestamp created_at "μ½˜μ„œνŠΈ 결제 μš”μ²­ μ‹œκ°„"
        timestamp modified_at "μ½˜μ„œνŠΈ 결제 μƒνƒœ λ³€κ²½ μ‹œκ°„"
    }

    user ||--|{ waiting_token : has
    concert ||--|{ concert_schedule : contains
    concert_schedule ||--|{ concert_seat : contains
    reservation ||--o| payment : has
    
Loading

πŸ‘€ Sequence Diagram

토큰 λ°œκΈ‰ API

sequenceDiagram
    autonumber
    actor μ‚¬μš©μž
    μ‚¬μš©μž ->>+ λŒ€κΈ°μ—΄: 토큰 μš”μ²­
    Note over μ‚¬μš©μž, λŒ€κΈ°μ—΄: μ‚¬μš©μž μ‹λ³„μž(pk)
    λŒ€κΈ°μ—΄ ->> λŒ€κΈ°μ—΄: λŒ€κΈ°μ€‘μΈ 토큰이 μ—†λŠ” 경우 μƒˆλ‘œ λ°œκΈ‰, μžˆλŠ” 경우 λ°˜ν™˜
    λŒ€κΈ°μ—΄ -->>- μ‚¬μš©μž: 토큰, λŒ€κΈ°μ—΄ 정보
Loading

μ˜ˆμ•½ κ°€λŠ₯ λ‚ μ§œ 쑰회 API

sequenceDiagram
    autonumber
    actor μ‚¬μš©μž

    μ‚¬μš©μž ->>+ λŒ€κΈ°μ—΄: λŒ€κΈ°μ—΄ μš”μ²­
    break λŒ€κΈ°μ—΄ 검증 μ‹€νŒ¨
      λŒ€κΈ°μ—΄ -->> μ‚¬μš©μž: 400 Error λ°˜ν™˜
    end
  
    μ‚¬μš©μž ->>+ μ˜ˆμ•½ κ°€λŠ₯ λ‚ μ§œ: μ½˜μ„œνŠΈ λ‚ μ§œ 쑰회 μš”μ²­
    Note over μ‚¬μš©μž, μ˜ˆμ•½ κ°€λŠ₯ λ‚ μ§œ: Active 토큰, μ½˜μ„œνŠΈ 정보
    μ˜ˆμ•½ κ°€λŠ₯ λ‚ μ§œ -->>- μ‚¬μš©μž: 응닡
    Note over μ‚¬μš©μž, μ˜ˆμ•½ κ°€λŠ₯ λ‚ μ§œ: μ˜ˆμ•½ κ°€λŠ₯ν•œ λ‚ μ§œ
Loading

μ’Œμ„ 쑰회 API

sequenceDiagram
    autonumber
    actor μ‚¬μš©μž

    μ‚¬μš©μž ->>+ λŒ€κΈ°μ—΄: λŒ€κΈ°μ—΄ μš”μ²­
    break λŒ€κΈ°μ—΄ 검증 μ‹€νŒ¨
        λŒ€κΈ°μ—΄ -->> μ‚¬μš©μž: 400 Error λ°˜ν™˜
    end
  
    μ‚¬μš©μž ->>+ μ˜ˆμ•½ κ°€λŠ₯ μ’Œμ„: μ½˜μ„œνŠΈ μ’Œμ„ 쑰회 μš”μ²­
    Note over μ‚¬μš©μž, μ˜ˆμ•½ κ°€λŠ₯ μ’Œμ„: Active 토큰, μ½˜μ„œνŠΈ λ‚ μ§œ 정보
    μ˜ˆμ•½ κ°€λŠ₯ μ’Œμ„ -->>- μ‚¬μš©μž: 응닡
    Note over μ‚¬μš©μž, μ˜ˆμ•½ κ°€λŠ₯ μ’Œμ„: ν•΄λ‹Ή λ‚ μ§œμ˜ μ˜ˆμ•½ κ°€λŠ₯ν•œ μ’Œμ„λ²ˆν˜Έ
    Note over μ‚¬μš©μž: μ’Œμ„ 번호: 1~50
Loading

μ’Œμ„ μ˜ˆμ•½ μš”μ²­ API

sequenceDiagram
    autonumber
    actor μ‚¬μš©μž

    μ‚¬μš©μž ->>+ λŒ€κΈ°μ—΄: λŒ€κΈ°μ—΄ μš”μ²­
    break λŒ€κΈ°μ—΄ 검증 μ‹€νŒ¨
      λŒ€κΈ°μ—΄ -->> μ‚¬μš©μž: 400 Error λ°˜ν™˜
    end
  
    μ‚¬μš©μž ->>+ μ’Œμ„ μ˜ˆμ•½: Active 토큰, μ’Œμ„ μ˜ˆμ•½ μš”μ²­
    Note over μ‚¬μš©μž, μ’Œμ„ μ˜ˆμ•½: μ½˜μ„œνŠΈ λ‚ μ§œ, μ’Œμ„ 정보
    μ’Œμ„ μ˜ˆμ•½ ->> μ’Œμ„ μ˜ˆμ•½: μ’Œμ„ μ˜ˆμ•½ μƒνƒœ(lock) λ³€κ²½
    μ’Œμ„ μ˜ˆμ•½ -->>- μ‚¬μš©μž: μ’Œμ„ μž„μ‹œ λ°°μ • μ™„λ£Œ
    Note over μ‚¬μš©μž, μ’Œμ„ μ˜ˆμ•½: 결제 정보, μž„μ‹œ λ°°μ • 유효 μ‹œκ°„
Loading

μž”μ•‘ μΆ©μ „ API

sequenceDiagram
    autonumber
    actor μ‚¬μš©μž
    
    μ‚¬μš©μž ->>+ μž”μ•‘ μΆ©μ „: μž”μ•‘ μΆ©μ „ μš”μ²­
    Note over μ‚¬μš©μž, μž”μ•‘ μΆ©μ „: μ‚¬μš©μž μ‹λ³„μž(pk), μΆ©μ „ν•  κΈˆμ•‘
    
    μž”μ•‘ μΆ©μ „ -->>- μ‚¬μš©μž: μž”μ•‘ λ°˜ν™˜
Loading

μž”μ•‘ 쑰회 API

sequenceDiagram
    autonumber
    actor μ‚¬μš©μž
    
    μ‚¬μš©μž ->>+ μž”μ•‘ 쑰회: μž”μ•‘ 쑰회 μš”μ²­
    Note over μ‚¬μš©μž, μž”μ•‘ 쑰회: μ‚¬μš©μž μ‹λ³„μž(pk)
  
    μž”μ•‘ 쑰회 -->>- μ‚¬μš©μž: μž”μ•‘ λ°˜ν™˜
Loading

결제 API

sequenceDiagram
    autonumber
    actor μ‚¬μš©μž

    μ‚¬μš©μž ->>+ λŒ€κΈ°μ—΄: λŒ€κΈ°μ—΄ μš”μ²­
    break λŒ€κΈ°μ—΄ 검증 μ‹€νŒ¨
      λŒ€κΈ°μ—΄ -->> μ‚¬μš©μž: 400 Error λ°˜ν™˜
    end
    
    μ‚¬μš©μž ->>+ 결제: 결제 μš”μ²­
    Note over μ‚¬μš©μž, 결제: Active 토큰, 결제 정보, μ’Œμ„ λ°°μ • 번호
    결제 ->>+ μ’Œμ„ μ˜ˆμ•½: μž„μ‹œ λ°°μ • 체크
    Note over 결제, μ’Œμ„ μ˜ˆμ•½: μ’Œμ„ λ°°μ • 번호
    μ’Œμ„ μ˜ˆμ•½ -->>- 결제: μž„μ‹œ λ°°μ • μ—¬λΆ€
    
    break μ’Œμ„ μž„μ‹œ λ°°μ • μ•ˆλ¨ (or 만료 5λΆ„)
        결제 -->> μ‚¬μš©μž: μ’Œμ„ μž„μ‹œ λ°°μ • μ•ˆλ¨
    end
    
    alt μž”μ•‘ 있음
        결제 ->>+ μž”μ•‘ 쑰회: μž”μ•‘ 차감
        Note over 결제, μž”μ•‘ 쑰회: μ‚¬μš©μž μ‹λ³„μž(pk)
        μž”μ•‘ 쑰회 -->> 결제: 결제 성곡
        결제 ->> μ’Œμ„ μ˜ˆμ•½: 결제 μ™„λ£Œ
        Note over 결제, μ’Œμ„ μ˜ˆμ•½: μ’Œμ„ λ°°μ • 번호
        결제 ->> λŒ€κΈ°μ—΄: λŒ€κΈ°μ—΄ 토큰 만료
        μ’Œμ„ μ˜ˆμ•½ -->> μ‚¬μš©μž: μ˜ˆμ•½ μ™„λ£Œ
        Note over μ‚¬μš©μž, μ’Œμ„ μ˜ˆμ•½: μ’Œμ„ λ°°μ • 번호
    else μž”μ•‘ μ—†μŒ
        결제 ->>+ μž”μ•‘ 쑰회: μž”μ•‘ 차감
        Note over 결제, μž”μ•‘ 쑰회: μ‚¬μš©μž μ‹λ³„μž(pk)
        μž”μ•‘ 쑰회 -->>- 결제: μž”μ•‘ λΆ€μ‘±
        결제 -->>- μ‚¬μš©μž: μž”μ•‘ λΆ€μ‘±
    end
Loading

🌲 Tree

β”œβ”€β”€ api
β”‚   β”œβ”€β”€ concert
β”‚   β”‚   β”œβ”€β”€ application
β”‚   β”‚   β”‚   └── DataPlatformSendService.java
β”‚   β”‚   β”œβ”€β”€ domain
β”‚   β”‚   β”‚   β”œβ”€β”€ Concert.java
β”‚   β”‚   β”‚   β”œβ”€β”€ ConcertRepository.java
β”‚   β”‚   β”‚   β”œβ”€β”€ ConcertSchedule.java
β”‚   β”‚   β”‚   β”œβ”€β”€ ConcertSeat.java
β”‚   β”‚   β”‚   β”œβ”€β”€ ConcertService.java
β”‚   β”‚   β”‚   β”œβ”€β”€ MockApiClient.java
β”‚   β”‚   β”‚   β”œβ”€β”€ Payment.java
β”‚   β”‚   β”‚   β”œβ”€β”€ PaymentOutbox.java
β”‚   β”‚   β”‚   β”œβ”€β”€ Reservation.java
β”‚   β”‚   β”‚   β”œβ”€β”€ enums
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ ConcertSeatStatus.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ PaymentOutboxState.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ PaymentState.java
β”‚   β”‚   β”‚   β”‚   └── ReservationStatus.java
β”‚   β”‚   β”‚   β”œβ”€β”€ event
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ PaymentEventPublisher.java
β”‚   β”‚   β”‚   β”‚   └── PaymentSuccessEvent.java
β”‚   β”‚   β”‚   └── message
β”‚   β”‚   β”‚       β”œβ”€β”€ PaymentMessageOutboxManager.java
β”‚   β”‚   β”‚       └── PaymentMessageSender.java
β”‚   β”‚   β”œβ”€β”€ infrastructure
β”‚   β”‚   β”‚   β”œβ”€β”€ ConcertMapper.java
β”‚   β”‚   β”‚   β”œβ”€β”€ MockApiClientImpl.java
β”‚   β”‚   β”‚   β”œβ”€β”€ db
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ ConcertEntity.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ ConcertScheduleEntity.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ ConcertSeatEntity.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ PaymentEntity.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ PaymentOutboxEntity.java
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ ReservationEntity.java
β”‚   β”‚   β”‚   β”‚   └── repository
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ ConcertRepositoryImpl.java
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ JpaConcertRepository.java
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ JpaConcertScheduleRepository.java
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ JpaConcertSeatRepository.java
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ JpaPaymentOutboxRepository.java
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ JpaPaymentRepository.java
β”‚   β”‚   β”‚   β”‚       β”œβ”€β”€ JpaReservationRepository.java
β”‚   β”‚   β”‚   β”‚       └── PaymentMessageOutboxManagerImpl.java
β”‚   β”‚   β”‚   β”œβ”€β”€ kafka
β”‚   β”‚   β”‚   β”‚   └── PaymentKafkaMessageSender.java
β”‚   β”‚   β”‚   └── spring
β”‚   β”‚   β”‚       └── PaymentSpringEventPublisher.java
β”‚   β”‚   └── interfaces
β”‚   β”‚       β”œβ”€β”€ ConcertController.java
β”‚   β”‚       β”œβ”€β”€ consumer
β”‚   β”‚       β”‚   └── PaymentMessageConsumer.java
β”‚   β”‚       β”œβ”€β”€ event
β”‚   β”‚       β”‚   └── PaymentEventListener.java
β”‚   β”‚       β”œβ”€β”€ request
β”‚   β”‚       β”‚   β”œβ”€β”€ BookingSeatsRequest.java
β”‚   β”‚       β”‚   └── PayRequest.java
β”‚   β”‚       └── response
β”‚   β”‚           β”œβ”€β”€ BookingSeatsResponse.java
β”‚   β”‚           β”œβ”€β”€ PayResponse.java
β”‚   β”‚           β”œβ”€β”€ SearchPaymentResponse.java
β”‚   β”‚           β”œβ”€β”€ SearchScheduleResponse.java
β”‚   β”‚           └── SearchSeatsResponse.java
β”‚   β”œβ”€β”€ user
β”‚   β”‚   β”œβ”€β”€ domain
β”‚   β”‚   β”‚   β”œβ”€β”€ User.java
β”‚   β”‚   β”‚   β”œβ”€β”€ UserRepository.java
β”‚   β”‚   β”‚   └── UserService.java
β”‚   β”‚   β”œβ”€β”€ infrastructure
β”‚   β”‚   β”‚   β”œβ”€β”€ JpaUserRepository.java
β”‚   β”‚   β”‚   β”œβ”€β”€ UserEntity.java
β”‚   β”‚   β”‚   └── UserRepositoryImpl.java
β”‚   β”‚   └── interfaces
β”‚   β”‚       β”œβ”€β”€ ChargeRequest.java
β”‚   β”‚       β”œβ”€β”€ ChargeResponse.java
β”‚   β”‚       β”œβ”€β”€ SearchAmountResponse.java
β”‚   β”‚       └── UserController.java
β”‚   └── waiting
β”‚       β”œβ”€β”€ domain
β”‚       β”‚   β”œβ”€β”€ WaitingService.java
β”‚       β”‚   β”œβ”€β”€ WaitingToken.java
β”‚       β”‚   β”œβ”€β”€ WaitingTokenRepository.java
β”‚       β”‚   └── enums
β”‚       β”‚       └── WaitingTokenStatus.java
β”‚       β”œβ”€β”€ infrastructure
β”‚       β”‚   β”œβ”€β”€ RedisLockRepository.java
β”‚       β”‚   └── WaitingTokenRepositoryImpl.java
β”‚       └── interfaces
β”‚           β”œβ”€β”€ TokenResponse.java
β”‚           β”œβ”€β”€ WaitingController.java
β”‚           └── event
└── support
    β”œβ”€β”€ JsonUtil.java
    β”œβ”€β”€ LoggingFilter.java
    β”œβ”€β”€ WaitingInterceptor.java
    β”œβ”€β”€ config
    β”‚   β”œβ”€β”€ AsyncConfig.java
    β”‚   β”œβ”€β”€ FilterConfig.java
    β”‚   β”œβ”€β”€ KafkaConfig.java
    β”‚   β”œβ”€β”€ RedisCacheConfig.java
    β”‚   β”œβ”€β”€ RedisConfig.java
    β”‚   └── WebMvcConfig.java
    β”œβ”€β”€ exception
    β”‚   β”œβ”€β”€ BaseException.java
    β”‚   β”œβ”€β”€ CustomBadRequestException.java
    β”‚   β”œβ”€β”€ CustomNotFoundException.java
    β”‚   β”œβ”€β”€ ErrorCode.java
    β”‚   └── Exception.java
    β”œβ”€β”€ handler
    β”‚   β”œβ”€β”€ ApiControllerAdvice.java
    β”‚   β”œβ”€β”€ ApiResultResponse.java
    β”‚   β”œβ”€β”€ ErrorResponse.java
    β”‚   β”œβ”€β”€ LockHandler.java
    β”‚   └── TransactionHandler.java
    └── scheduler
        β”œβ”€β”€ ConcertSeatScheduler.java
        β”œβ”€β”€ KafkaRepublishScheduler.java
        └── WaitingTokenScheduler.java