ํ๋ก์ ํธ ํํธ๋ ๋งค์นญ ํ๋ซํผ
| ๋ถ๋ฅ | ๊ธฐ์ | ๋ฒ์ | ์ฉ๋ |
|---|---|---|---|
| Language | Java | 21 | ๊ฐ๋ฐ ์ธ์ด |
| Framework | Spring Boot | 3.5.9 | ์ ํ๋ฆฌ์ผ์ด์ ํ๋ ์์ํฌ |
| Build Tool | Gradle | - | ๋น๋ ๋ฐ ์์กด์ฑ ๊ด๋ฆฌ |
| ORM | Spring Data JPA | - | ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ทผ |
| Database | PostgreSQL | - | ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค (AWS RDS) |
| Security | JWT (JJWT) | 0.12.5 | ์ธ์ฆ/์ธ๊ฐ |
| Spring Security Crypto | - | ๋น๋ฐ๋ฒํธ ์ํธํ (BCrypt) | |
| Validation | Jakarta Validation | - | ์์ฒญ ๋ฐ์ดํฐ ๊ฒ์ฆ |
| Real-time | WebSocket (STOMP) | - | ์ค์๊ฐ ์ฑํ |
| Documentation | Swagger (Springdoc) | 2.8.5 | API ๋ฌธ์ํ |
| ๋ถ๋ฅ | ๊ธฐ์ | ์ฉ๋ |
|---|---|---|
| Cloud | AWS EC2 | ์ ํ๋ฆฌ์ผ์ด์ ์๋ฒ |
| AWS RDS (PostgreSQL) | ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋ฒ | |
| CI/CD | GitHub Actions | ์๋ ๋น๋ ๋ฐ ๋ฐฐํฌ |
| VCS | Git / GitHub | ๋ฒ์ ๊ด๋ฆฌ |
| API | ์ฉ๋ | ๋ฒ์ |
|---|---|---|
| Google Gemini API | AI ๊ธฐ๋ฐ ํ๋ก์ ํธ ๊ฒฌ์ ๋ฐ Task ์๋ ์์ฑ | - |
| Toss Payments API | ํํธ๋ ๋งค์นญ ๊ฒฐ์ | - |
// Core
- Spring Boot Starter Web
- Spring Boot Starter Data JPA
- Spring Boot Starter Validation
- Spring Boot Starter WebSocket
// Security
- JJWT (JWT ์ธ์ฆ)
- Spring Security Crypto (๋น๋ฐ๋ฒํธ ์ํธํ)
// Database
- PostgreSQL Driver
- H2 Database (ํ
์คํธ์ฉ)
// Documentation
- Springdoc OpenAPI (Swagger)
// External Integration
- WebFlux (Toss Payments, Gemini API ์ฐ๋)
// Utilities
- Lombok (๋ณด์ผ๋ฌํ๋ ์ดํธ ์ฝ๋ ์ ๊ฑฐ)
- Jackson (JSON ์ง๋ ฌํ/์ญ์ง๋ ฌํ)โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Client Layer โ
โ (Web / Mobile App) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ HTTP/HTTPS
โ WebSocket
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Presentation Layer โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ REST API Controllers โ โ
โ โ - MemberController - ProjectController โ โ
โ โ - ChatController - PayController โ โ
โ โ - PartnerMatchingController โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ JWT Authentication Filter โ โ
โ โ (JwtAuthenticationFilter) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Business Layer โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Service Components โ โ
โ โ - MemberService - ProjectService โ โ
โ โ - ChatService - PayFacade/PayLogService โ โ
โ โ - PartnerMatchingService โ โ
โ โ - NotificationService โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Persistence Layer โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ JPA Repositories โ โ
โ โ - MemberRepository - ProjectRepository โ โ
โ โ - ChatRoomRepository โ โ
โ โ - PartnerApplicationRepository โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ JPA Entities โ โ
โ โ - Member - Project - ChatRoom - PayLog โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Database Layer โ
โ PostgreSQL (AWS RDS) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ External Services โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โ Gemini API โ โToss Paymentsโ โ AWS Services โ โ
โ โ (AI ๊ฒฌ์ ) โ โ (๊ฒฐ์ ) โ โ (EC2/RDS) โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
com.example.off
โ
โโโ common/ # ๊ณตํต ๋ชจ๋
โ โโโ config/ # ์ค์ (PasswordConfig, FilterConfig)
โ โโโ exception/ # ์์ธ ์ฒ๋ฆฌ (OffException, OffControllerAdvice)
โ โโโ response/ # ํตํฉ ์๋ต ํ์ (BaseResponse, ResponseCode)
โ โโโ jwt/ # JWT ์ธ์ฆ (JwtTokenProvider, Filter)
โ โโโ gemini/ # Gemini API ์ฐ๋
โ โโโ infra/ # ์ธ๋ถ ์ธํ๋ผ (TossPaymentsClient)
โ โโโ swagger/ # Swagger ์ค์
โ
โโโ domain/ # ๋๋ฉ์ธ ๊ณ์ธต (DDD)
โ โโโ member/ # ํ์ ๋๋ฉ์ธ
โ โ โโโ Member.java # ์ํฐํฐ
โ โ โโโ controller/ # API ์ปจํธ๋กค๋ฌ
โ โ โโโ service/ # ๋น์ฆ๋์ค ๋ก์ง
โ โ โโโ repository/ # ๋ฐ์ดํฐ ์ ๊ทผ
โ โ โโโ dto/ # ๋ฐ์ดํฐ ์ ์ก ๊ฐ์ฒด
โ โ
โ โโโ project/ # ํ๋ก์ ํธ ๋๋ฉ์ธ
โ โ โโโ Project.java
โ โ โโโ controller/
โ โ โโโ service/ # ๊ฒฌ์ , ํ์ , Task ์์ฑ
โ โ โโโ repository/
โ โ โโโ dto/
โ โ
โ โโโ partnerRecruit/ # ํํธ๋ ๋ชจ์ง/๋งค์นญ ๋๋ฉ์ธ
โ โ โโโ PartnerRecruit.java
โ โ โโโ PartnerApplication.java
โ โ โโโ controller/
โ โ โโโ service/
โ โ โโโ dto/
โ โ
โ โโโ chat/ # ์ฑํ
๋๋ฉ์ธ (WebSocket)
โ โ โโโ ChatRoom.java
โ โ โโโ Message.java
โ โ โโโ controller/
โ โ โโโ service/
โ โ โโโ dto/
โ โ
โ โโโ pay/ # ๊ฒฐ์ ๋๋ฉ์ธ
โ โ โโโ PayLog.java
โ โ โโโ controller/
โ โ โโโ service/ # PayLogService, PayFacade
โ โ โโโ dto/
โ โ
โ โโโ notification/ # ์๋ฆผ ๋๋ฉ์ธ
โ โโโ task/ # Task ๊ด๋ฆฌ ๋๋ฉ์ธ
โ โโโ projectMember/ # ํ๋ก์ ํธ ๋ฉค๋ฒ ๋๋ฉ์ธ
โ โโโ role/ # ์ญํ ๋๋ฉ์ธ (PM, DEV, DES, MAR)
โ
โโโ OffApplication.java # ๋ฉ์ธ ์ ํ๋ฆฌ์ผ์ด์
1. Client Request
โ
2. JwtAuthenticationFilter (JWT ๊ฒ์ฆ โ memberId ์ถ์ถ)
โ
3. Controller (์์ฒญ ์์ , Validation)
โ
4. Service (๋น์ฆ๋์ค ๋ก์ง ์ฒ๋ฆฌ)
โ
5. Repository (๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ทผ)
โ
6. Entity (JPA ์์์ฑ ๊ด๋ฆฌ)
โ
7. Database (PostgreSQL)
โ
8. Response (BaseResponse<T> ํ์)
โ
9. Client
- Presentation Layer: REST API, WebSocket
- Business Layer: ๋๋ฉ์ธ๋ณ Service
- Persistence Layer: JPA Repository
- Database Layer: PostgreSQL
@Entity
@Getter
@NoArgsConstructor
public class Member {
@Id @GeneratedValue
private Long id;
// Private constructor
private Member(...) { ... }
// Static factory method
public static Member of(...) { ... }
// Business logic methods
public void updateNickname(...) { ... }
}- Request DTO:
@NotNull,@NotBlank๋ฑ Validation - Response DTO:
static of()factory method - ํตํฉ ์๋ต:
BaseResponse<T>
throw new OffException(ResponseCode.MEMBER_NOT_FOUND);
โ
@RestControllerAdvice
public class OffControllerAdvice {
@ExceptionHandler(OffException.class)
public ResponseEntity<BaseResponse<Void>> handle(...) { ... }
}erDiagram
MEMBER ||--o{ PROJECT : creates
MEMBER ||--o{ PROJECT_MEMBER : participates
MEMBER ||--o{ PARTNER_APPLICATION : applies
MEMBER ||--o{ CHAT_ROOM_MEMBER : joins
MEMBER ||--o{ MESSAGE : sends
MEMBER ||--o{ NOTIFICATION : receives
MEMBER ||--o{ PORTFOLIO : has
MEMBER }o--|| MEMBER_ROLE : has
PROJECT ||--o{ PROJECT_MEMBER : has
PROJECT ||--o{ PARTNER_RECRUIT : posts
PROJECT ||--o{ CHAT_ROOM : belongs_to
PROJECT ||--o{ TASK : contains
PARTNER_RECRUIT ||--o{ PARTNER_APPLICATION : receives
PARTNER_APPLICATION ||--o| PAY_LOG : payment_for
CHAT_ROOM ||--o{ CHAT_ROOM_MEMBER : has
CHAT_ROOM ||--o{ MESSAGE : contains
TASK ||--o{ TO_DO : has
PROJECT_MEMBER ||--o{ TASK : assigned_to
member
id(PK): ํ์ ๊ณ ์ IDemail: ์ด๋ฉ์ผ (๋ก๊ทธ์ธ ID)password: ์ํธํ๋ ๋น๋ฐ๋ฒํธ (BCrypt)nickname: ๋๋ค์phone: ์ ํ๋ฒํธprofile_image: ํ๋กํ ์ด๋ฏธ์ง URLself_introduction: ์๊ธฐ์๊ฐrole: ์ญํ (PM, DEV, DES, MAR)project_count: ํ๋ก์ ํธ ๊ฒฝํ ํ์is_working: ํ์ฌ ํ๋ก์ ํธ ์งํ ์ค ์ฌ๋ถcreated_at,updated_at: ์์ฑ/์์ ์๊ฐ
portfolio
portfolio_id(PK)member_id(FK โ member)title: ํฌํธํด๋ฆฌ์ค ์ ๋ชฉdescription: ์ค๋ชurl: ํฌํธํด๋ฆฌ์ค ๋งํฌ
project
project_id(PK)creator_id(FK โ member): ํ๋ก์ ํธ ์์ฑ์ (๊ธฐํ์)name: ํ๋ก์ ํธ๋ชdescription: ์ค๋ชrequirement: ์๊ตฌ์ฌํญintroduction: ํ๋ก์ ํธ ์๊ฐtotal_estimate: ์ด ์์ ๋น์ฉstart_date,end_date: ์์/์ข ๋ฃ์ผproject_type: ํ๋ก์ ํธ ํ์status: ์ํ (IN_PROGRESS, COMPLETED)
project_member
project_member_id(PK)project_id(FK โ project)member_id(FK โ member)role: ํ๋ก์ ํธ ๋ด ์ญํ
partner_recruit
partner_recruit_id(PK)project_id(FK โ project)role: ๋ชจ์ง ์ญํ (DEV, DES, MAR)number_of_person: ๋ชจ์ง ์ธ์cost: 1์ธ๋น ๋น์ฉrecruit_status: ๋ชจ์ง ์ํ (OPEN, CLOSED)
partner_application
partner_application_id(PK)partner_recruit_id(FK โ partner_recruit)member_id(FK โ member): ์ง์์application_status: ์ง์ ์ํ (WAITING, ACCEPT, REJECT)is_from_project: ๊ธฐํ์ ์ ์ ์ฌ๋ถ (true: ์ด๋, false: ์ง์)
chat_room
chat_room_id(PK)project_id(FK โ project, nullable): ํ๋ก์ ํธ ์ฑํ ๋ฐฉ์ธ ๊ฒฝ์ฐchat_type: ์ฑํ ํ์ (CONTACT: 1:1, PROJECT: ํ๋ก์ ํธ)
chat_room_member
chat_room_member_id(PK)chat_room_id(FK โ chat_room)member_id(FK โ member)last_read_at: ๋ง์ง๋ง ์ฝ์ ์๊ฐ
message
message_id(PK)chat_room_id(FK โ chat_room)member_id(FK โ member): ๋ฐ์ ์content: ๋ฉ์์ง ๋ด์ฉis_read: ์ฝ์ ์ฌ๋ถ
pay_log
pay_log_id(PK)order_id: Toss ์ฃผ๋ฌธ ID (UUID)amount: ๊ฒฐ์ ๊ธ์กstatus: ๊ฒฐ์ ์ํ (READY, PAID, FAILED, CANCELED)payment_key: Toss ๊ฒฐ์ ํคpayer_id(FK โ member): ๊ฒฐ์ ์ (๊ธฐํ์)partner_application_id(FK โ partner_application)project_member_id(FK โ project_member): ๋งค์นญ ์๋ฃ ์ ์์ฑ
notification
notification_id(PK)member_id(FK โ member): ์์ ์message: ์๋ฆผ ๋ฉ์์งurl: ์๋ฆผ ํด๋ฆญ ์ ์ด๋ URLnotification_type: ์๋ฆผ ํ์ (INVITE, APPLICATION, PAY, PROJECT_COMPLETE)is_read: ์ฝ์ ์ฌ๋ถ
task
task_id(PK)project_id(FK โ project)project_member_id(FK โ project_member): ๋ด๋น์name: Task ์ด๋ฆdescription: Task ์ค๋ช
to_do
to_do_id(PK)task_id(FK โ task)content: ToDo ๋ด์ฉis_done: ์๋ฃ ์ฌ๋ถ
1. ๊ธฐํ์: ํ๋ก์ ํธ ๊ฒฌ์ ์์ฒญ (POST /projects/estimate)
โ
2. Gemini API ํธ์ถ
- ํ๋ก์ ํธ ์ค๋ช
/์๊ตฌ์ฌํญ ๋ถ์
- ์ญํ ๋ณ ๋น์ฉ ์ฐ์
- ์์ ์ข
๋ฃ์ผ ๊ณ์ฐ
- ํํธ๋ ์ถ์ฒ
- ์๋น์ค ์์ฝ ์์ฑ
โ
3. ๊ฒฌ์ ๊ฒฐ๊ณผ ๋ฐํ (EstimateResponse)
โ
4. ๊ธฐํ์: ํ๋ก์ ํธ ํ์ (POST /projects/confirm)
โ
5. Project ์์ฑ + PartnerRecruit ์์ฑ + Task ์๋ ์์ฑ (Gemini)
์๋๋ฆฌ์ค A: ํํธ๋ ์ง์
1. ํํธ๋: ํ๋ก์ ํธ ์ง์ (POST /projects/{id}/applications)
โ
2. PartnerApplication ์์ฑ (status=WAITING)
โ
3. ๊ธฐํ์์๊ฒ ์๋ฆผ ์ ์ก
โ
4. ๊ธฐํ์: ๊ฒฐ์ ์งํ (prepare โ confirm)
โ
5. ProjectMember ์์ฑ + ๋งค์นญ ์๋ฃ
์๋๋ฆฌ์ค B: ๊ธฐํ์ ์ด๋
1. ๊ธฐํ์: ํํธ๋ ์ด๋ (POST /projects/{id}/invitations)
โ
2. PartnerApplication ์์ฑ (isFromProject=true)
โ
3. ํํธ๋์๊ฒ ์๋ฆผ ์ ์ก
โ
4. ํํธ๋: ์๋ฝ (POST /invitations/{id}/accept)
โ
5. ๊ธฐํ์์๊ฒ ๊ฒฐ์ ์๋ฆผ
โ
6. ๊ธฐํ์: ๊ฒฐ์ ์งํ
โ
7. ProjectMember ์์ฑ + ๋งค์นญ ์๋ฃ
1. ์ฒซ ๋ฉ์์ง ์ ์ก (POST /chat/rooms/first)
- ChatRoom ์์ฑ
- ChatRoomMember 2๋ช
์ถ๊ฐ
- ChatType ์๋ ๊ฒฐ์ (CONTACT or PROJECT)
โ
2. WebSocket ์ฐ๊ฒฐ (/ws-stomp)
โ
3. ๋ฉ์์ง ๋ฐํ (/pub/chat/message)
โ
4. ๊ตฌ๋
์์๊ฒ ๋ธ๋ก๋์บ์คํธ (/sub/chat/room/{roomId})
โ
5. ์ ์ฝ์ ๋ฉ์์ง ์๋ฆผ (/queue/unread-status)
1. ๊ธฐํ์: ๊ฒฐ์ ์ค๋น (POST /payments/prepare)
- PayLog ์์ฑ (status=READY)
- orderId, amount ๋ฐํ
โ
2. ํ๋ก ํธ: Toss ์์ ฏ ์ด๊ธฐํ (clientKey)
โ
3. ์ฌ์ฉ์ ๊ฒฐ์ ์งํ
โ
4. Toss: successUrl๋ก ๋ฆฌ๋ค์ด๋ ํธ (paymentKey ์ ๋ฌ)
โ
5. ํ๋ก ํธ: ๊ฒฐ์ ํ์ธ (POST /payments/confirm)
- Toss API ์ต์ข
์น์ธ ์์ฒญ
- PayLog ์ํ ์
๋ฐ์ดํธ (PAID)
- ProjectMember ์์ฑ
- ํํธ๋์๊ฒ ์๋ฆผ
1. ๋ก๊ทธ์ธ (POST /members/login)
โ
2. JWT ํ ํฐ ๋ฐ๊ธ (accessToken, refreshToken)
โ
3. API ์์ฒญ ์ Header: Authorization: Bearer {token}
โ
4. JwtAuthenticationFilter
- ํ ํฐ ๊ฒ์ฆ
- memberId ์ถ์ถ
- HttpServletRequest์ ์ ์ฅ
โ
5. Controller์์ memberId ์ฌ์ฉ
์ฉ๋:
- ํ๋ก์ ํธ ๊ฒฌ์ ์๋ ์ฐ์
- ํํธ๋ ์ถ์ฒ ๋ฐ ๋น์ฉ ์ฐจ๋ฑ ์ฐ์
- Task ๋ฐ ToDo ์๋ ์์ฑ
- ์๋น์ค ์์ธ ๊ธฐํ์ ์์ฑ
๊ตฌํ:
@Service
public class GeminiService {
private final WebClient geminiWebClient;
public String generateText(String prompt) {
// Gemini API ํธ์ถ
// JSON ์๋ต ํ์ฑ
// ๊ฒฐ๊ณผ ๋ฐํ
}
}์ฉ๋: ํํธ๋ ๋งค์นญ ๊ฒฐ์
ํ๋ก์ฐ:
- ์ค๋น ๋จ๊ณ: PayLog ์์ฑ (READY)
- ๊ฒฐ์ ๋จ๊ณ: Toss ์์ ฏ (ํด๋ผ์ด์ธํธ)
- ์น์ธ ๋จ๊ณ: Toss API ํธ์ถ (์๋ฒ) โ PAID
๊ตฌํ:
@Component
public class TossPaymentsClient {
private final WebClient tossWebClient;
public TossPaymentConfirmResponse confirm(
String paymentKey, String orderId, Long amount
) {
// Toss API ์น์ธ ์์ฒญ
// Basic Auth (secretKey)
}
}@Query("SELECT m FROM Member m " +
"JOIN FETCH m.portfolios " +
"WHERE m.id = :id")
Optional<Member> findByIdWithPortfolios(@Param("id") Long id);@Query("SELECT crm FROM ChatRoomMember crm " +
"JOIN FETCH crm.chatRoom cr " +
"LEFT JOIN FETCH cr.project " +
"JOIN FETCH crm.member " +
"WHERE crm.member.id = :memberId")
List<ChatRoomMember> findAllByMember_IdAndChatRoom_ChatType(...);on:
push:
branches: [ develop ]
jobs:
build:
- Gradle build
- JAR ์์ฑ
deploy:
- EC2์ JAR ๋ฐฐํฌ
- ํ๊ฒฝ ๋ณ์ ์ค์ (.env)
- systemd๋ก ์ฑ ์ฌ์์- ๋ก์ปฌ:
.envํ์ผ - ๋ฐฐํฌ: GitHub Secrets โ EC2
.env์๋ ์์ฑ
Swagger UI: /swagger-ui/index.html
ํตํฉ ์๋ต ํ์:
{
"success": true,
"code": 200,
"message": "์์ฒญ์ ์ฑ๊ณตํ์์ต๋๋ค.",
"data": { ... }
}