API Spec - PIC-2-team/PIC-2-team-project GitHub Wiki

API ๋ช…์„ธ์„œ

๊ธฐ์ค€: PRD, User-Flow, Wireframe, Glossary, ERD, Architecture, Dev-Schedule ๊ณตํ†ต ์„ฑ๊ณตยท์˜ค๋ฅ˜ ์‘๋‹ต๊ณผ ํŽ˜์ด์ง€ ํ˜•์‹: API-Response-Convention ์ƒํƒœ: ํŒ€ ๊ฒ€ํ† ์šฉ v1 API ๊ณ„์•ฝ

๊ณตํ†ต ๊ณ„์•ฝ

ํ•ญ๋ชฉ v1 ๊ทœ์น™
๊ฒฝ๋กœยท๋ณธ๋ฌธ ๊ธฐ๋ณธ ๊ฒฝ๋กœ /api, JSON UTF-8, ์—…๋กœ๋“œ๋Š” multipart/form-data
์‘๋‹ต ์„ฑ๊ณต success=true + data(๊ฐ์ฒดยท๋ฐฐ์—ดยทnull), ์˜ค๋ฅ˜ { "success": false, "error": { "code": "ERROR_CODE", "message": "์˜ค๋ฅ˜ ์„ค๋ช…" } }, ์ƒ์„ฑ 201, ๊ทธ ์™ธ ์„ฑ๊ณต 200
์ธ์ฆ ๋ณดํ˜ธ API๋Š” Authorization: Bearer {accessToken}, access token 15๋ถ„, refresh token 30์ผยทHttpOnly; Secure; SameSite=None ์ฟ ํ‚ค
์‹๋ณ„์ž ๊ฒฝ๋กœ ID๋Š” ์ˆซ์ž, ๋‹น์‚ฌ์ž ๊ณต๊ฐœ ๋ฒˆํ˜ธ P- + ๋Œ€๋ฌธ์žยท์ˆซ์ž 8์ž, ์ง€์›์‚ฌ ๊ณต๊ฐœ ๋ฒˆํ˜ธ S- + ๋Œ€๋ฌธ์žยท์ˆซ์ž 8์ž, ๊ธฐ๊ด€ ์ฝ”๋“œ AA-999
๋‚ ์งœยท๋ชฉ๋ก ์‹œ๊ฐ ์ž…๋ ฅ์€ ์‹œ๊ฐ„๋Œ€ ํฌํ•จ ISO 8601, ์‘๋‹ต์€ UTC ISO 8601, ๋‚ ์งœ๋Š” YYYY-MM-DD, ์˜ค๋Š˜ยท์›”๋ณ„ ์กฐํšŒ์™€ ๋ฐฐ์ • ๊ธฐ๊ฐ„์€ Asia/Seoul ๊ธฐ์ค€
ํŽ˜์ด์ง€ page ๊ธฐ๋ณธ 1, pageSize ๊ธฐ๋ณธ 20ยท์ตœ๋Œ€ 100, ์ตœ์‹ ์ˆœยท๋™๋ฅ ์ผ ๋•Œ ID ์—ญ์ˆœ
์žฌ์‹œ๋„ ๋ฐฐ์ •ยท๋„์ „ํ–‰๋™ ๊ธฐ๋ก ์š”์ฒญ ์ƒ์„ฑ์— Idempotency-Key ํ•„์ˆ˜, ๊ฐ™์€ ํ‚คยท๋ณธ๋ฌธ์€ 24์‹œ๊ฐ„ ๋™์•ˆ ์ตœ์ดˆ ์‘๋‹ต, ๊ฐ™์€ ํ‚คยท๋‹ค๋ฅธ ๋ณธ๋ฌธ์€ 409
์˜ค๋ฅ˜ ํ˜•์‹ 400, ์ธ์ฆ 401, ๊ถŒํ•œ 403, ๋ฆฌ์†Œ์Šค 404, ์ถฉ๋Œ 409, ํฌ๊ธฐ 413, ํŒŒ์ผ ํ˜•์‹ 415, ํ•„๋“œ ๊ฒ€์ฆ 422, ์„œ๋ฒ„ 500

์—ญํ• ยท๊ด€๊ณ„

์ฃผ์ฒด ์—ด๋žŒยท์ž‘์„ฑ ๊ด€๋ฆฌยท์ œํ•œ
์ฃผ ๋ณดํ˜ธ์ž GUARDIAN ๋ณธ์ธ ๋‹น์‚ฌ์ž์˜ ๊ธฐ๋กยท๋Œ๋ด„์ •๋ณด ์—ด๋žŒยท์ž‘์„ฑยท์ˆ˜์ •ยท์‚ญ์ œ ๋‹น์‚ฌ์ž ๋“ฑ๋กยทํ”„๋กœํ•„, ๊ธฐ๊ด€ ์—ฐ๊ฒฐยท์ด์ „, ๋ฐฐ์ • ์ข…๋ฃŒ, ์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž ์ง€์ •, ์ˆ˜์ • ์ œ์•ˆ ์Šน์ธ
์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž ๋‹น์‚ฌ์ž๋ณ„ ACTIVE ์ƒํƒœ์—์„œ ๊ธฐ๋กยท๋Œ๋ด„์ •๋ณด ์—ด๋žŒยท์ž‘์„ฑยท์ˆ˜์ •ยท์‚ญ์ œ ํ”„๋กœํ•„ยท๊ธฐ๊ด€ยท๋ฐฐ์ •ยท์œ„์ž„ ๊ด€๊ณ„ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€
ํ™œ๋™ ์ง€์›์‚ฌ SUPPORT_WORKER ์œ ํšจ ๋ฐฐ์ •๋œ ๋‹น์‚ฌ์ž ์—ด๋žŒยท๊ธฐ๋ก ์ž‘์„ฑ, ๋ณธ์ธ ๊ธฐ๋ก ์ˆ˜์ •ยท์‚ญ์ œ ํƒ€์ธ ๊ธฐ๋ก์€ ์ˆ˜์ • ์ œ์•ˆ๋งŒ ๊ฐ€๋Šฅ
๊ธฐ๊ด€ INSTITUTION ์—ฐ๊ฒฐ๋œ ๋‹น์‚ฌ์ž ์—ด๋žŒยท์ˆ˜์ • ์ œ์•ˆยท๊ธฐ๋ก ์š”์ฒญยท์ •๋ณด ์š”์ฒญ ์ค‘๊ณ„ ์†Œ์† ์ง€์›์‚ฌยท๋ฐฐ์ • ๊ด€๋ฆฌ, ์ƒํ™œ๊ธฐ๋ก ์ง์ ‘ ์ž‘์„ฑ ๋ถˆ๊ฐ€
  • ํ•œ ๋ณดํ˜ธ์ž์˜ ๋ณต์ˆ˜ ๋‹น์‚ฌ์ž ๋“ฑ๋ก, ๋‹น์‚ฌ์ž๋‹น ๊ธฐ๊ด€ ํ•œ ๊ณณ, ๊ฐ™์€ ๊ธฐ๊ฐ„ ๋ณต์ˆ˜ ์ง€์›์‚ฌ ๋ฐฐ์ • ํ—ˆ์šฉ
  • ์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž๋Š” ์ฃผ ๋ณดํ˜ธ์ž๊ฐ€ ACTIVE๋กœ ์ „ํ™˜ํ•œ ๋™์•ˆ์—๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ

๊ณตํ†ต ๋ฐ์ดํ„ฐ

๋ฐ์ดํ„ฐ ํ•„๋“œยท๊ฐ’
์„ฑ๋ณ„ FEMALE, MALE, NOT_SPECIFIED
์žฅ์•  ์œ ํ˜• INTELLECTUAL, AUTISM, OTHER ๋ณต์ˆ˜ ์„ ํƒ, OTHER ์„ ํƒ ์‹œ otherDisabilityType ํ•„์ˆ˜
์ƒํ™œ๊ธฐ๋ก ๋ถ„๋ฅ˜ COMMUNICATION, LIFESTYLE, MEAL, PREFERENCE, CHALLENGING_BEHAVIOR, HEALTH, EMERGENCY, OTHER
๋Œ๋ด„์ •๋ณด ๋ถ„๋ฅ˜ COMMUNICATION, PREFERENCE, LIFESTYLE, HEALTH_MEDICATION, PRECAUTION, EMERGENCY
๊ธฐ๋ก ์‘๋‹ต id, careRecipientId, author(id/name/role/publicCode), content, category, recordedAt, createdAt, updatedAt, pinned, media[](๋ฏธ๋””์–ด ์‘๋‹ต)
๋‹น์‚ฌ์ž ์‘๋‹ต id, careRecipientNumber, name, birthDate, gender, disabilityTypes, otherDisabilityType, disabilityGrade, latestRecordAt, createdAt
๋ชฉ๋ก ์‘๋‹ต data.items[], data.pagination(page/pageSize/totalItems/totalPages)
ํ•„๋“œ ํ‘œ๊ธฐ ํ•„์ˆ˜๋Š” ๋ฐ˜๋“œ์‹œ ์ „์†ก, ์„ ํƒ์€ ์ƒ๋žต ๊ฐ€๋Šฅ, ๋ณ„๋„ ํ‘œ๊ธฐ๊ฐ€ ์—†๋Š” ์ˆ˜์ • ์š”์ฒญ์€ ๋ช…์‹œํ•œ ํ•„๋“œ ์ค‘ ํ•˜๋‚˜ ์ด์ƒ ์ „์†ก
์ž…๋ ฅ ์œ„์น˜ ๊ฒฝ๋กœ ๋ณ€์ˆ˜๋Š” Endpoint์— ํ‘œ์‹œ, GET์˜ ์ž…๋ ฅ์€ ์ฟผ๋ฆฌ, Idempotency-Key๋Š” ํ—ค๋”, ๋‚˜๋จธ์ง€๋Š” JSON ๋ณธ๋ฌธ
nullable ์‘๋‹ต ์‚ฌ์šฉ์ž phone/publicCode/organization, ๋‹น์‚ฌ์ž latestRecordAt/gender/otherDisabilityType/disabilityGrade, ๋ฐฐ์ • endDate/endedAt, ์ •๋ณด ์š”์ฒญ reply, ๊ธฐ๋ก ์š”์ฒญ completedRecordId, ๋Œ๋ด„์ •๋ณด updatedAt์€ ๊ฐ’์ด ์—†์œผ๋ฉด null

์ธ์ฆยท๋‚ด ์ •๋ณด

Method Endpoint ์ž…๋ ฅ ์ถœ๋ ฅ dataยท๊ถŒํ•œ
POST /api/auth/consent ํ•„์ˆ˜ basicInfo=true, sensitiveInfo=true, caregiverShare=true, termsVersion=2026-10-09์„ ํƒ marketing ๊ธฐ๋ณธ false consentTicket, 30๋ถ„ ์œ ํšจยท1ํšŒ ์‚ฌ์šฉ, ํ•„์ˆ˜ ๋™์˜ ๊ฑฐ๋ถ€ยท๋ฒ„์ „ ๋ถˆ์ผ์น˜ 422
POST /api/auth/register ํ•„์ˆ˜ name, email, password(10~72์ž), role, consentTicket์ง€์›์‚ฌ organizationCode ํ•„์ˆ˜, ๊ธฐ๊ด€ organizationName ํ•„์ˆ˜ 201 ๋กœ๊ทธ์ธ ์‘๋‹ต์ด๋ฉ”์ผ ์ค‘๋ณต 409
POST /api/auth/google ํ•„์ˆ˜ idToken์‹ ๊ทœ ๊ฐ€์ž… ์‹œ role, consentTicket, ์—ญํ• ๋ณ„ ๊ธฐ๊ด€ ์ •๋ณด ํ•„์ˆ˜ ๊ธฐ์กด ๊ณ„์ • 200 ๋กœ๊ทธ์ธ ์‘๋‹ต, ์‹ ๊ทœ ๊ณ„์ • 201 ๋กœ๊ทธ์ธ ์‘๋‹ต
POST /api/auth/login ํ•„์ˆ˜ email, password ๋กœ๊ทธ์ธ ์‘๋‹ต, ์ธ์ฆ ์‹คํŒจ 401
POST /api/auth/refresh refresh ์ฟ ํ‚ค ๋กœ๊ทธ์ธ ์‘๋‹ต, ๊ฐฑ์‹ ๋œ refresh ์ฟ ํ‚ค
POST /api/auth/logout refresh ์ฟ ํ‚ค loggedOut=true, refresh ์ฟ ํ‚ค ๋งŒ๋ฃŒ
POST /api/auth/invitations/accept ํ•„์ˆ˜ invitationToken, ๋กœ๊ทธ์ธํ•œ ๋ณดํ˜ธ์ž ๊ณ„์ • careRecipientId, status=READY, ์ดˆ๋Œ€ ์ด๋ฉ”์ผ๊ณผ ๊ณ„์ • ์ด๋ฉ”์ผ์ด ๋‹ฌ๋ผ์ง€๋ฉด 403
GET /api/users/me ์—†์Œ ์‚ฌ์šฉ์ž ์‘๋‹ต
PATCH /api/users/me name(1~50์ž), phone(E.164) ์ค‘ ํ•˜๋‚˜ ์ด์ƒ ์‚ฌ์šฉ์ž ์‘๋‹ต
PATCH /api/users/me/password ํ•„์ˆ˜ currentPassword, newPassword(10~72์ž) changed=true, ์ด๋ฉ”์ผ ๊ฐ€์ž… ๊ณ„์ •๋งŒ
DELETE /api/users/me ์—†์Œ deletedAt, ํ™œ์„ฑ ์„ธ์…˜ ์ฆ‰์‹œ ๋งŒ๋ฃŒ. ๋ณดํ˜ธ์ž๊ฐ€ ์œ ์ผ ๋ณดํ˜ธ์ž์ธ ๋‹น์‚ฌ์ž๊ฐ€ ์žˆ์œผ๋ฉด ํƒˆํ‡ด ์ „ ์ด๊ด€ยท์‚ญ์ œ ์„ ํƒ ํ•„์ˆ˜(409๋กœ ์ฐจ๋‹จ) โ€” ADR-012 ์ฐธ๊ณ 
GET /api/users/me/notification-settings ์—†์Œ ์•Œ๋ฆผ ์„ค์ • ์‘๋‹ต
PUT /api/users/me/notification-settings ์•Œ๋ฆผ ์„ค์ • ์—ฌ์„ฏ boolean ๋ชจ๋‘ ํ•„์ˆ˜, ์ „์ฒด ๊ต์ฒด ์•Œ๋ฆผ ์„ค์ • ์‘๋‹ต
์‘๋‹ต data ํ•„๋“œ
๋กœ๊ทธ์ธ ์‘๋‹ต accessToken, tokenType=Bearer, expiresInSeconds=900, user(id/name/email/role), refresh token์€ Set-Cookie ์‘๋‹ต ํ—ค๋”
์‚ฌ์šฉ์ž ์‘๋‹ต id, name, email, role, phone, publicCode, organization(id/name/organizationCode ๋˜๋Š” null)
์•Œ๋ฆผ ์„ค์ • ์‘๋‹ต recordCreated, recordUpdated, assignmentChanged, suggestionReceived, informationRequestReceived, recordRequestReceived, ๊ธฐ๋ณธ๊ฐ’ ๋ชจ๋‘ true

๋‹น์‚ฌ์žยท๊ธฐ๊ด€ยท๋Œ๋ด„ ๊ด€๊ณ„

Method Endpoint ์ž…๋ ฅ ์ถœ๋ ฅ dataยท๊ถŒํ•œ
GET /api/care-recipients ์„ ํƒ query(์ด๋ฆ„ยท๊ณต๊ฐœ ๋ฒˆํ˜ธ), page, pageSize ๋‹น์‚ฌ์ž ์‘๋‹ต ๋ชฉ๋ก, ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๋‹น์‚ฌ์ž๋งŒ
POST /api/care-recipients ํ•„์ˆ˜ name(150์ž), birthDate(๊ณผ๊ฑฐ ๋‚ ์งœ), disabilityTypes(13๊ฐœ)์„ ํƒ gender, disabilityGrade(์ตœ๋Œ€ 20์ž), OTHER ์„ ํƒ ์‹œ otherDisabilityType(1~50์ž) ํ•„์ˆ˜ 201 ๋‹น์‚ฌ์ž ์‘๋‹ต, ์ฃผ ๋ณดํ˜ธ์ž๋งŒ
GET /api/care-recipients/{careRecipientId} ์—†์Œ ๋‹น์‚ฌ์ž ์‘๋‹ต
PATCH /api/care-recipients/{careRecipientId} ๋‹น์‚ฌ์ž ๋“ฑ๋ก ํ•„๋“œ ์ค‘ ํ•˜๋‚˜ ์ด์ƒ ๋‹น์‚ฌ์ž ์‘๋‹ต, ์ฃผ ๋ณดํ˜ธ์ž๋งŒ
GET /api/organizations/me ์—†์Œ id, name, organizationCode, ๊ธฐ๊ด€๋งŒ
GET /api/organizations/me/members ์„ ํƒ query(์ด๋ฆ„ยท๊ณต๊ฐœ ๋ฒˆํ˜ธ), page, pageSize ํšŒ์› ์‘๋‹ต ๋ชฉ๋ก, ๊ธฐ๊ด€๋งŒ
PATCH /api/organizations/me/members/{memberId} ํ•„์ˆ˜ status=ACTIVE ๋˜๋Š” INACTIVE ํšŒ์› ์‘๋‹ต, ๊ธฐ๊ด€๋งŒ, INACTIVE๋ฉด ์ง„ํ–‰ ์ค‘ ๋ฐฐ์ • ์ข…๋ฃŒ
POST /api/organizations/me/recipient-links ํ•„์ˆ˜ careRecipientNumber 201 ๊ธฐ๊ด€ ์—ฐ๊ฒฐ ์š”์ฒญ ์‘๋‹ต, status=PENDING, ๊ธฐ๊ด€๋งŒ, ์ด๋ฏธ ์—ฐ๊ฒฐ๋์œผ๋ฉด 409
GET /api/organizations/me/link-requests ์„ ํƒ status, page, pageSize ๊ธฐ๊ด€ ์—ฐ๊ฒฐ ์š”์ฒญ ์‘๋‹ต ๋ชฉ๋ก, ๊ธฐ๊ด€๋งŒ
GET /api/care-recipients/{careRecipientId}/organization-link-requests ์„ ํƒ status ๊ธฐ๊ด€ ์—ฐ๊ฒฐ ์š”์ฒญ ์‘๋‹ต ๋ฐฐ์—ด, ์ฃผ ๋ณดํ˜ธ์ž๋งŒ
POST /api/care-recipients/{careRecipientId}/organization-link-requests/{requestId}/accept ์—†์Œ ๊ธฐ๊ด€ ์—ฐ๊ฒฐ ์š”์ฒญ ์‘๋‹ต, status=ACCEPTED, ์ฃผ ๋ณดํ˜ธ์ž๋งŒ
POST /api/care-recipients/{careRecipientId}/organization-link-requests/{requestId}/reject ์—†์Œ ๊ธฐ๊ด€ ์—ฐ๊ฒฐ ์š”์ฒญ ์‘๋‹ต, status=REJECTED, ์ฃผ ๋ณดํ˜ธ์ž๋งŒ
DELETE /api/care-recipients/{careRecipientId}/organization-link-requests/{linkId} ์—†์Œ unlinked=true, ์ฃผ ๋ณดํ˜ธ์ž๋งŒ, ์—ฐ๊ฒฐ ํ•ด์ œ ์‹œ ํ•ด๋‹น ๊ธฐ๊ด€ ์ง€์›์‚ฌ ๋ฐฐ์ • ์ „์ฒด ์ข…๋ฃŒยท๋ฏธ์™„๋ฃŒ ์ •๋ณด ์š”์ฒญ CLOSEDยท๊ธฐ๋ก ์š”์ฒญ CANCELLED
POST /api/care-recipients/{careRecipientId}/institution-transfer ํ•„์ˆ˜ organizationCode careRecipientId, organization(id/name/organizationCode), ์ฃผ ๋ณดํ˜ธ์ž๋งŒ, ๊ธฐ์กด ๋ฐฐ์ • ์ข…๋ฃŒ
GET /api/care-recipients/{careRecipientId}/assignments ์„ ํƒ activeOnly, page, pageSize ๋ฐฐ์ • ์‘๋‹ต ๋ชฉ๋ก
POST /api/organizations/me/assignments ํ•„์ˆ˜ Idempotency-Key, careRecipientId, supportWorkerId, startDate์„ ํƒ endDate, notify ๊ธฐ๋ณธ true 201 ๋ฐฐ์ • ์‘๋‹ต, ๊ธฐ๊ด€๋งŒ, ๊ธฐ๊ฐ„ ์ค‘๋ณต 409
PATCH /api/care-assignments/{assignmentId} ํ•„์ˆ˜ endDate(๋‚ ์งœ ๋˜๋Š” null) ๋ฐฐ์ • ์‘๋‹ต, ๊ธฐ๊ด€๋งŒ
DELETE /api/care-assignments/{assignmentId} ์—†์Œ ๋ฐฐ์ • ์‘๋‹ต, ๊ธฐ๊ด€ยท์ฃผ ๋ณดํ˜ธ์ž๋งŒ, ์ค‘๋ณต ์ข…๋ฃŒ 409
GET /api/care-recipients/{careRecipientId}/secondary-guardian ์—†์Œ ์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž ์‘๋‹ต ๋˜๋Š” null, ์ฃผ ๋ณดํ˜ธ์ž๋งŒ
PUT /api/care-recipients/{careRecipientId}/secondary-guardian ํ•„์ˆ˜ name, email, phone ์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž ์‘๋‹ต, status=INVITED, ์ฃผ ๋ณดํ˜ธ์ž๋งŒ
PATCH /api/care-recipients/{careRecipientId}/secondary-guardian ํ•„์ˆ˜ active boolean ์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž ์‘๋‹ต, READY โ†” ACTIVE, ์ฃผ ๋ณดํ˜ธ์ž๋งŒ
DELETE /api/care-recipients/{careRecipientId}/secondary-guardian ์—†์Œ revoked=true, ์ฃผ ๋ณดํ˜ธ์ž๋งŒ
์‘๋‹ต data ํ•„๋“œ
ํšŒ์› ์‘๋‹ต id, name, publicCode, status, assignedRecipientCount
๊ธฐ๊ด€ ์—ฐ๊ฒฐ ์š”์ฒญ ์‘๋‹ต id, careRecipientId, organization(id/name/organizationCode), status
๋ฐฐ์ • ์‘๋‹ต id, careRecipientId, supportWorker(id/name/publicCode), organization(id/name/organizationCode), startDate, endDate, endedAt
์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž ์‘๋‹ต name, email, phone, status(INVITED/READY/ACTIVE), expiresAt
๊ธฐ๊ด€ ์—ฐ๊ฒฐ ์ƒํƒœ PENDING, ACCEPTED, REJECTED
  • ๋ฐฐ์ •ยท๊ธฐ๊ด€ ์—ฐ๊ฒฐ ์ข…๋ฃŒ ์‹œ ํ•ด๋‹น ์ง€์›์‚ฌ์˜ ๋‹น์‚ฌ์ž ์ ‘๊ทผ ํšŒ์ˆ˜
  • ๋ฐฐ์ •ยท๊ธฐ๊ด€ ์—ฐ๊ฒฐ ์ข…๋ฃŒ ์‹œ ๋ฏธ์™„๋ฃŒ ๊ธฐ๋ก ์š”์ฒญ CANCELLED
  • ๊ธฐ๊ด€ ์ด์ „ ์‹œ ๋ฏธ์™„๋ฃŒ ์ •๋ณด ์š”์ฒญ CLOSED, ๊ธฐ๋ก ์š”์ฒญ CANCELLED

์ƒํ™œ๊ธฐ๋กยท์ˆ˜์ • ์ œ์•ˆ

Method Endpoint ์ž…๋ ฅ ์ถœ๋ ฅ dataยท๊ถŒํ•œ
GET /api/care-recipients/{careRecipientId}/records ์„ ํƒ date ๋˜๋Š” year+month, page, pageSize ๊ธฐ๋ก ์‘๋‹ต ๋ชฉ๋ก, ์‚ญ์ œ ๊ธฐ๋ก ์ œ์™ธ, ๋‚ ์งœ ํ•„ํ„ฐ ๋™์‹œ ์‚ฌ์šฉ ๋ถˆ๊ฐ€
GET /api/care-recipients/{careRecipientId}/records/today ์—†์Œ ์˜ค๋Š˜ ๊ธฐ๋ก ์‘๋‹ต ๋ฐฐ์—ด
POST /api/care-recipients/{careRecipientId}/records ํ•„์ˆ˜ content(trim ํ›„ 1~500์ž), category, recordedAt์„ ํƒ mediaIds(์ตœ๋Œ€ 5๊ฐœ), recordRequestId, pinned ๊ธฐ๋ณธ false 201 ๊ธฐ๋ก ์‘๋‹ต, ๋ณดํ˜ธ์žยทํ™œ์„ฑ ์„ธ์ปจ๋“œ ๋ณดํ˜ธ์žยท๋ฐฐ์ • ์ง€์›์‚ฌ๋งŒ, pinned=true๋Š” ๋ณดํ˜ธ์žยทํ™œ์„ฑ ์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž๋งŒ
GET /api/care-recipients/{careRecipientId}/records/{recordId} ์—†์Œ ๊ธฐ๋ก ์‘๋‹ต
PATCH /api/care-recipients/{careRecipientId}/records/{recordId} content, category, recordedAt, mediaIds ์ค‘ ํ•˜๋‚˜ ์ด์ƒmediaIds๋Š” ์ฒจ๋ถ€ ์ „์ฒด ๊ต์ฒด ๊ธฐ๋ก ์‘๋‹ต, ๋ณดํ˜ธ์ž ๋˜๋Š” ๋ฐฐ์ • ์ค‘์ธ ์ž‘์„ฑ ์ง€์›์‚ฌ๋งŒ
DELETE /api/care-recipients/{careRecipientId}/records/{recordId} ์—†์Œ deletedAt, restoreUntil, ์ž‘์„ฑ์žยท๋ณดํ˜ธ์ž๋งŒ
POST /api/care-recipients/{careRecipientId}/records/{recordId}/restore ์—†์Œ ๊ธฐ๋ก ์‘๋‹ต, ์‚ญ์ œ ํ›„ 30์ผ ์ด๋‚ดยท์‚ญ์ œ ๊ถŒํ•œ์ž๋งŒ
GET /api/care-recipients/{careRecipientId}/records/{recordId}/revisions ์„ ํƒ page, pageSize ์ˆ˜์ • ์ด๋ ฅ ์‘๋‹ต ๋ชฉ๋ก
PATCH /api/care-recipients/{careRecipientId}/records/{recordId}/pin ํ•„์ˆ˜ pinned boolean ๊ธฐ๋ก ์‘๋‹ต, ๋ณดํ˜ธ์žยทํ™œ์„ฑ ์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž๋งŒ
POST /api/care-recipients/{careRecipientId}/records/{recordId}/suggestions ํ•„์ˆ˜ content, ์„ ํƒ category, reason 201 ์ˆ˜์ • ์ œ์•ˆ ์‘๋‹ต, status=PENDING, ์ง€์›์‚ฌยท๊ธฐ๊ด€๋งŒ
GET /api/care-recipients/{careRecipientId}/record-suggestions ์„ ํƒ status ๊ธฐ๋ณธ PENDING, page, pageSize ์ˆ˜์ • ์ œ์•ˆ ์‘๋‹ต ๋ชฉ๋ก, ๋ณดํ˜ธ์žยทํ™œ์„ฑ ์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž๋งŒ
GET /api/record-suggestions/mine ์„ ํƒ careRecipientId, status, page, pageSize ์ˆ˜์ • ์ œ์•ˆ ์‘๋‹ต ๋ชฉ๋ก, ์ง€์›์‚ฌ๋งŒ (๋ณธ์ธ์ด ์ œ์ถœํ•œ ์ œ์•ˆ ์ด๋ ฅ)
POST /api/care-recipients/{careRecipientId}/record-suggestions/{suggestionId}/decision ํ•„์ˆ˜ decision=APPROVE ๋˜๋Š” REJECT ์ˆ˜์ • ์ œ์•ˆ ์‘๋‹ต, status=APPROVED/REJECTED, ์›๋ณธ ๋ณ€๊ฒฝ ์‹œ 409
POST /api/care-recipients/{careRecipientId}/records/{recordId}/forward-to-guardian ์—†์Œ recordId, forwardedAt, notificationId, ๊ธฐ๊ด€๋งŒ, ๋„์ „ํ–‰๋™ ๊ธฐ๋ก๋งŒ, ์ค‘๋ณต ์ „๋‹ฌ 409
์‘๋‹ต data ํ•„๋“œ
์ˆ˜์ • ์ด๋ ฅ ์‘๋‹ต revision, changedBy(id/name/role), changedAt, content, category, recordedAt
์ˆ˜์ • ์ œ์•ˆ ์‘๋‹ต id, recordId, original(content/category), proposed(content/category), reason(์—†์œผ๋ฉด null), suggestedBy(id/name/role), status, createdAt
์ˆ˜์ • ์ œ์•ˆ ์ƒํƒœ PENDING, APPROVED, REJECTED
  • recordRequestId๋ฅผ ์‚ฌ์šฉํ•œ ๊ธฐ๋ก์€ ํ•ด๋‹น ๋‹น์‚ฌ์žยท์ง€์›์‚ฌยทOPEN ์š”์ฒญ๊ณผ ์ผ์น˜ํ•˜๊ณ  category=CHALLENGING_BEHAVIOR ํ•„์ˆ˜, ์ €์žฅ ์‹œ ์š”์ฒญ COMPLETED
  • ์ˆ˜์ • ์ œ์•ˆ ์Šน์ธ ์‹œ ๊ธฐ๋ก ๊ฐฑ์‹ ยท์ˆ˜์ • ์ด๋ ฅ ์ถ”๊ฐ€
  • ๋„์ „ํ–‰๋™ ๊ธฐ๋ก์€ ์ƒ์„ฑ ์ฆ‰์‹œ ๋ณดํ˜ธ์ž์—๊ฒŒ ์กฐํšŒ ๊ฐ€๋Šฅ, ๊ธฐ๊ด€์˜ ์ „๋‹ฌ ํ˜ธ์ถœ์€ ๋ณดํ˜ธ์ž์—๊ฒŒ ์•Œ๋ฆผ ์ƒ์„ฑ

๋Œ๋ด„์ •๋ณดยท๋ฏธ๋””์–ดยทAI

Method Endpoint ์ž…๋ ฅ ์ถœ๋ ฅ dataยท๊ถŒํ•œ
GET /api/care-recipients/{careRecipientId}/care-info ์—†์Œ categories[](6๊ฐœ ๋Œ๋ด„์ •๋ณด ์‘๋‹ต), pinnedRecords[](๊ธฐ๋ก ์‘๋‹ต)
GET /api/care-recipients/{careRecipientId}/care-info/{category} ๊ฒฝ๋กœ category ๋Œ๋ด„์ •๋ณด ์‘๋‹ต
PUT /api/care-recipients/{careRecipientId}/care-info/{category} ํ•„์ˆ˜ content(0~3000์ž, ๋นˆ ๋ฌธ์ž์—ด๋กœ ๋น„์šฐ๊ธฐ) ๋Œ๋ด„์ •๋ณด ์‘๋‹ต, ๋ณดํ˜ธ์žยทํ™œ์„ฑ ์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž๋งŒ
POST /api/care-recipients/{careRecipientId}/media ํ•„์ˆ˜ file, JPEG/PNG/WebP/MP4/MP3/M4A/WAV/WebM, ์ตœ๋Œ€ 50MB 201 ๋ฏธ๋””์–ด ์‘๋‹ต, ๊ธฐ๋ก ์ž‘์„ฑ ๊ถŒํ•œ์ž๋งŒ
GET /api/care-recipients/{careRecipientId}/media/{mediaId}/download-url ์—†์Œ url, expiresAt, ๋‹น์‚ฌ์ž ์ ‘๊ทผ ๊ถŒํ•œ ํ•„์š”
DELETE /api/care-recipients/{careRecipientId}/media/{mediaId} ์—†์Œ deleted=true, ๋ฏธ์—ฐ๊ฒฐ ํŒŒ์ผ์€ ์—…๋กœ๋”ยท์—ฐ๊ฒฐ ํŒŒ์ผ์€ ๊ธฐ๋ก ์ˆ˜์ • ๊ถŒํ•œ์ž๋งŒ
POST /api/ai/record-drafts ํ•„์ˆ˜ careRecipientId, inputType=TEXT + text(1~3000์ž) ๋˜๋Š” inputType=AUDIO + mediaId(์ตœ๋Œ€ 10๋ถ„) transcript, content, category, ๊ธฐ๋ก์€ ์ƒ์„ฑ๋˜์ง€ ์•Š์Œ
์‘๋‹ต data ํ•„๋“œ
๋Œ๋ด„์ •๋ณด ์‘๋‹ต category, content, updatedAt, ๋ฏธ์ž‘์„ฑ ๋‚ด์šฉ์€ ๋นˆ ๋ฌธ์ž์—ด
๋ฏธ๋””์–ด ์‘๋‹ต mediaId, fileName, mediaType, sizeBytes
  • ๋ฏธ๋””์–ด๋Š” ๊ฐ™์€ ๋‹น์‚ฌ์ž์˜ ๊ธฐ๋ก์—๋งŒ ์—ฐ๊ฒฐ ๊ฐ€๋Šฅ, ๊ธฐ๋ก๋‹น ์ตœ๋Œ€ 5๊ฐœ
  • ๋‹ค์šด๋กœ๋“œ URL ์œ ํšจ ๊ธฐ๊ฐ„ 5๋ถ„

์š”์ฒญยท์•Œ๋ฆผยท์ ‘๊ทผ ์ด๋ ฅ

Method Endpoint ์ž…๋ ฅ ์ถœ๋ ฅ dataยท๊ถŒํ•œ
POST /api/care-recipients/{careRecipientId}/information-requests ํ•„์ˆ˜ message(1~1000์ž) 201 ์ •๋ณด ์š”์ฒญ ์‘๋‹ต, status=SUBMITTED, ๋ฐฐ์ • ์ง€์›์‚ฌ๋งŒ
GET /api/information-requests ์„ ํƒ status, page, pageSize ์ •๋ณด ์š”์ฒญ ์‘๋‹ต ๋ชฉ๋ก, ์š”์ฒญํ•œ ์ง€์›์‚ฌ๋งŒ
GET /api/organizations/me/information-requests ์„ ํƒ status, page, pageSize ์ •๋ณด ์š”์ฒญ ์‘๋‹ต ๋ชฉ๋ก, ๊ธฐ๊ด€๋งŒ
POST /api/organizations/me/information-requests/{requestId}/forward ์—†์Œ ์ •๋ณด ์š”์ฒญ ์‘๋‹ต, status=FORWARDED, ๊ธฐ๊ด€๋งŒ
GET /api/care-recipients/{careRecipientId}/information-requests ์„ ํƒ status, page, pageSize ์ •๋ณด ์š”์ฒญ ์‘๋‹ต ๋ชฉ๋ก, ๋ณดํ˜ธ์žยทํ™œ์„ฑ ์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž๋งŒ
POST /api/care-recipients/{careRecipientId}/information-requests/{requestId}/reply ํ•„์ˆ˜ message(1~1000์ž) ์ •๋ณด ์š”์ฒญ ์‘๋‹ต, status=ANSWERED, ๋ณดํ˜ธ์žยทํ™œ์„ฑ ์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž๋งŒ
POST /api/organizations/me/information-requests/{requestId}/close ์—†์Œ ์ •๋ณด ์š”์ฒญ ์‘๋‹ต, status=CLOSED, ๊ธฐ๊ด€๋งŒ
POST /api/care-recipients/{careRecipientId}/record-requests ํ•„์ˆ˜ Idempotency-Key, supportWorkerId์„ ํƒ message(์ตœ๋Œ€ 1000์ž) 201 ๊ธฐ๋ก ์š”์ฒญ ์‘๋‹ต, status=OPEN, ๊ธฐ๊ด€๋งŒ, ์œ ํšจ ๋ฐฐ์ •์ด ์—†์œผ๋ฉด 409
GET /api/care-recipients/{careRecipientId}/record-requests ์„ ํƒ status, page, pageSize ๊ธฐ๋ก ์š”์ฒญ ์‘๋‹ต ๋ชฉ๋ก, ๊ธฐ๊ด€๋งŒ
GET /api/record-requests ์„ ํƒ status, page, pageSize ๊ธฐ๋ก ์š”์ฒญ ์‘๋‹ต ๋ชฉ๋ก, ์ˆ˜์‹  ์ง€์›์‚ฌ๋งŒ
POST /api/record-requests/{requestId}/cancel ์—†์Œ ๊ธฐ๋ก ์š”์ฒญ ์‘๋‹ต, status=CANCELLED, ์š”์ฒญ ๊ธฐ๊ด€๋งŒยทOPEN ์ƒํƒœ๋งŒ
GET /api/notifications ์„ ํƒ read, page, pageSize ์•Œ๋ฆผ ์‘๋‹ต ๋ชฉ๋ก, ๋ณธ์ธ๋งŒ
GET /api/notifications/unread-count ์—†์Œ count (๋ฏธํ™•์ธ ์•Œ๋ฆผ ์ˆ˜ ์ •์ˆ˜), ๋ณธ์ธ๋งŒ
PATCH /api/notifications/{notificationId} ํ•„์ˆ˜ read boolean ์•Œ๋ฆผ ์‘๋‹ต, ๋ณธ์ธ๋งŒ
GET /api/care-recipients/{careRecipientId}/access-logs ์„ ํƒ page, pageSize ์ ‘๊ทผ ์ด๋ ฅ ์‘๋‹ต ๋ชฉ๋ก, ๋ณดํ˜ธ์žยทํ™œ์„ฑ ์„ธ์ปจ๋“œ ๋ณดํ˜ธ์ž๋งŒ
์‘๋‹ต data ํ•„๋“œ
์ •๋ณด ์š”์ฒญ ์‘๋‹ต id, careRecipientId, requestedBy(id/name/role), message, status, reply, createdAt, updatedAt
๊ธฐ๋ก ์š”์ฒญ ์‘๋‹ต id, careRecipientId, supportWorker(id/name/publicCode), requestedBy(id/name/role), message, status, completedRecordId, createdAt
์•Œ๋ฆผ ์‘๋‹ต id, type, message, read, createdAt
์ ‘๊ทผ ์ด๋ ฅ ์‘๋‹ต actor(id/name/role), action, resourceType, resourceId, occurredAt
์ •๋ณด ์š”์ฒญ ์ƒํƒœ SUBMITTED, FORWARDED, ANSWERED, CLOSED
๊ธฐ๋ก ์š”์ฒญ ์ƒํƒœ OPEN, COMPLETED, CANCELLED
์•Œ๋ฆผ ์œ ํ˜• RECORD_CREATED, RECORD_UPDATED, ASSIGNMENT_CHANGED, SUGGESTION_RECEIVED, SUGGESTION_DECIDED, INFORMATION_REQUEST_RECEIVED, INFORMATION_REQUEST_REPLIED, RECORD_REQUEST_RECEIVED, RECORD_REQUEST_COMPLETED, RECORD_FORWARDED, ORGANIZATION_LINK_REQUESTED, ORGANIZATION_LINK_ACCEPTED, ORGANIZATION_LINK_REJECTED
์ ‘๊ทผ ๋™์ž‘ READ, CREATE, UPDATE, DELETE
  • ์ •๋ณด ์š”์ฒญ ์ƒํƒœ SUBMITTED โ†’ FORWARDED โ†’ ANSWERED โ†’ CLOSED
  • ์‘๋‹ต ๊ธฐ๋ก ์ €์žฅ ์‹œ ํ•ด๋‹น ๊ธฐ๋ก ์š”์ฒญ COMPLETED

์–ด๋“œ๋ฏผ

๋ชจ๋“  ์—”๋“œํฌ์ธํŠธ๋Š” ADMIN ์—ญํ•  ์ „์šฉ. ์ผ๋ฐ˜ ์‚ฌ์šฉ์ž ์ ‘๊ทผ ์‹œ 403.

Method Endpoint ์ž…๋ ฅ ์ถœ๋ ฅ data
GET /api/admin/stats ์—†์Œ totalUsers, guardians, supportWorkers, institutions, totalOrganizations, totalCareRecipients, totalRecords
GET /api/admin/users ์„ ํƒ role, organizationId, page, size ์‚ฌ์šฉ์ž ์š”์•ฝ ์‘๋‹ต ๋ชฉ๋ก
POST /api/admin/users ํ•„์ˆ˜ name, email, password(6์ž ์ด์ƒ), role์„ ํƒ phone, organizationId 201 ์‚ฌ์šฉ์ž ์š”์•ฝ ์‘๋‹ต
PATCH /api/admin/users/{id} ํ•„์ˆ˜ name, email, role์„ ํƒ phone, organizationId ์‚ฌ์šฉ์ž ์š”์•ฝ ์‘๋‹ต
DELETE /api/admin/users/{id} ์—†์Œ null (204), ๋ณธ์ธ ๊ณ„์ • ์‚ญ์ œ ๋ถˆ๊ฐ€
GET /api/admin/users/{id}/records ์—†์Œ ๊ธฐ๋ก ์š”์•ฝ ์‘๋‹ต ๋ชฉ๋ก
GET /api/admin/organizations ์—†์Œ ๊ธฐ๊ด€ ์–ด๋“œ๋ฏผ ์‘๋‹ต ๋ชฉ๋ก
POST /api/admin/organizations ํ•„์ˆ˜ name์„ ํƒ ownerId 201 ๊ธฐ๊ด€ ์–ด๋“œ๋ฏผ ์‘๋‹ต, 6์ž๋ฆฌ organizationCode ์ž๋™ ๋ฐœ๊ธ‰
PATCH /api/admin/organizations/{id} ํ•„์ˆ˜ name ๊ธฐ๊ด€ ์–ด๋“œ๋ฏผ ์‘๋‹ต
DELETE /api/admin/organizations/{id} ์—†์Œ null (204)
GET /api/admin/organizations/{id}/records ์—†์Œ ๊ธฐ๋ก ์š”์•ฝ ์‘๋‹ต ๋ชฉ๋ก
GET /api/admin/care-recipients ์„ ํƒ search(์ด๋ฆ„ยท๊ณต๊ฐœ ๋ฒˆํ˜ธ) ๋‹น์‚ฌ์ž ์–ด๋“œ๋ฏผ ์‘๋‹ต ๋ชฉ๋ก
POST /api/admin/care-recipients ํ•„์ˆ˜ name(150์ž), birthDate, disabilityTypes(13๊ฐœ)์„ ํƒ gender, disabilityGrade, otherDisabilityType, guardianId 201 ๋‹น์‚ฌ์ž ์–ด๋“œ๋ฏผ ์‘๋‹ต, careRecipientNumber ์ž๋™ ๋ฐœ๊ธ‰
์‘๋‹ต data ํ•„๋“œ
์‚ฌ์šฉ์ž ์š”์•ฝ ์‘๋‹ต id, name, email, role, phone, publicCode, organizationId
๊ธฐ๊ด€ ์–ด๋“œ๋ฏผ ์‘๋‹ต id, name, organizationCode, ownerId, ownerName, createdAt
๋‹น์‚ฌ์ž ์–ด๋“œ๋ฏผ ์‘๋‹ต id, careRecipientNumber, name, birthDate, gender, disabilityTypes, disabilityGrade, otherDisabilityType, guardianName, guardianEmail, organizationName, createdAt
๊ธฐ๋ก ์š”์•ฝ ์‘๋‹ต (AdminRecordSummaryResponse โ€” ์ƒ์„ธ ํ•„๋“œ๋Š” Swagger ์ฐธ๊ณ )
  • careRecipientNumber(P-XXXXXXXX)๋Š” ์–ด๋“œ๋ฏผ ๋˜๋Š” ๋ณดํ˜ธ์ž ์ง์ ‘ ๋“ฑ๋ก ์‹œ ์ž๋™ ๋ฐœ๊ธ‰. ๊ธฐ๊ด€์ด ์—ฐ๊ฒฐ ์š”์ฒญ(POST /api/organizations/me/recipient-links) ์‹œ ์ด ๋ฒˆํ˜ธ๋ฅผ ๋ณดํ˜ธ์ž๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›์•„ ์ž…๋ ฅํ•จ.

๋ณ€๊ฒฝ ์ด๋ ฅ

๋‚ ์งœ ๋‚ด์šฉ ์ž‘์„ฑ์ž
2026-10-08 ์ตœ์ดˆ API ๊ฒฝ๋กœยท์‘๋‹ต ์ดˆ์•ˆ
2026-10-09 PRDยทUser-FlowยทWireframe ๊ธฐ์ค€ API v1 ์ž…๋ ฅยท์ถœ๋ ฅ ๊ณ„์•ฝ ์ •๋ฆฌ Codex
2026-10-22 ๋ˆ„๋ฝ ์—”๋“œํฌ์ธํŠธ 5๊ฐœ ์ถ”๊ฐ€, ์–ด๋“œ๋ฏผ ์„น์…˜ ์ถ”๊ฐ€, ์•Œ๋ฆผ ํƒ€์ž… 3๊ฐœ ์ถ”๊ฐ€(INFORMATION_REQUEST_REPLIED, RECORD_REQUEST_COMPLETED, ORGANIZATION_LINK_ACCEPTED/REJECTED), DELETE .../organization-link-requests/{linkId} ์‚ฌ์ด๋“œ์ดํŽ™ํŠธ ๋ณด์™„, GET /api/record-suggestions/mine careRecipientId ํ•„ํ„ฐ ์ถ”๊ฐ€ Claude Code