You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
enhancement(receiver): 카카오 초대 생성·수락·계정 연결 계약을 확정하고 검증한다 #1948
#944의 수신자 등록 화면 구현에서 서버 선행 계약·통합 검증을 분리한다. 카톡 초대 방향이 정해졌고, 초대 링크·토큰·수락·랜딩·가입 후 수신자 매핑 계약은 BE#227이 PR Afternote/Afternote-BE#289로 끝내 2026-09-08에 배포됐다. 배포된 계약 전문은 2026-09-13 코멘트에 옮겨 적었고, BE가 쓴 안드로이드 연동 가이드가 팀 노션에 있다. 이 이슈에 남은 것은 그 계약의 앱 검증과 이행 기준 결정이다.
완료 조건:
초대 생성·조회·수락 API와 토큰 수명, 만료·중복 수락·다른 계정 수락의 결과를 문서화한다. 2026-09-13 코멘트로 끝났다. 거절 상태와 거절 API는 서버에 없다.
설치 전/후 랜딩·카카오 가입·로그인 이후 초대 복원과 발신자-수신자 계정 연결 기준을 확정한다. 서버 몫은 확정됐고, 커스텀 스킴 수신·토큰 임시 보관·가입 후 재개의 앱 설계가 남는다. 설치 직후 자동 복구는 백엔드 범위 밖이다.
기존 이메일 등록 수신자의 유지/이행과 초대 대기·완료 UI 상태를 확정한다. PM 결정 대기이며 이 이슈에 남은 유일한 결정이다.
배포된 계약을 테스트 계정으로 검증하고 #944에 구현 가능한 요청·응답·시안 근거를 인계한다.
blocked_by: 계정 승계·BE 준비 #1947. BE#227은 2026-09-08에 종료돼 서버 선행은 풀렸다. #944는 이 이슈가 끝난 뒤 화면·공유·상태 배선을 구현한다. 현행 등록 실패 처리나 목록 표시 개선까지 일괄 중단하는 의미는 아니다.
참고
분리 원본: #944. 사용자 요청에 따른 수신자 블로킹 범위 분리(2026-09-08). 원본의 구현 책임은 유지하며 본 이슈는 선행 계약·결정 범위만 소유한다.
BE 계약은 배포됐다. 이 이슈가 기다리던 서버 선행은 끝났다 (2026-09-13 확인)
Afternote/Afternote-BE#227 은 PR Afternote/Afternote-BE#289 가 2026-09-08T05:57:54Z 에 머지되면서 같은 초에 닫혔다. 그 이슈 본문에는 2026-09-13T04:30:31Z 에 완료 확인 절이 붙어 main3593aa30 기준으로 토큰 해시·만료, 조회·수락, 회원 연결, 테스트 7건 통과가 적혀 있다. 2026-09-13 11:00 회의록에도 "서버 - QA 진행 중, 카카오 서버 완 → 프론트 확인 필요" 로 남아 있다.
아래는 오늘 BE main3593aa30 소스를 직접 읽어 옮긴 것이다. BE 가 안드로이드용 연동 가이드도 따로 써 두었다: 카카오톡 수신자 초대 Android 연동 가이드 (API 기본 명세서 하위, 0913 회의록에 걸려 있다).
엔드포인트 3개
POST /api/v1/receiver-invitations (인증 필요, 요청 바디 없음)
응답 invitationId, invitationToken, invitationUrl, expiresAt. 토큰은 32바이트 난수를 base64url 로 인코딩한 값이고 서버는 SHA-256 해시만 저장한다. 만료는 생성 시각 더하기 RECEIVER_INVITATION_EXPIRATION_DAYS(기본 7일). invitationUrl 은 RECEIVER_INVITATION_BASE_URL(기본 https://afternote.kro.kr/invitations) 뒤에 토큰을 붙인 값이다. 카카오 템플릿에는 URL 이 아니라 invitationToken 을 inviteToken 인자로 넘긴다.
GET /api/v1/receiver-invitations/{token} (비로그인 호출 가능)
응답 inviterName, status, expired, expiresAt. 로그인 전 랜딩에서 초대자 이름과 만료를 보여줄 수 있다.
POST /api/v1/receiver-invitations/{token}/accept (인증 필요, 요청 바디 없음)
응답 receiverId, inviterName. 수락 즉시 수신자로 등록되며 relation 과 message 는 null 로 저장되고 나중에 초대자가 채운다. 같은 사용자가 같은 초대를 다시 수락하면 같은 결과를 돌려주는 멱등 처리다. 가입만으로는 수락되지 않는다. 서비스 JWT 를 받은 뒤 이 API 를 따로 불러야 한다.
실패 코드
code
HTTP
의미
1000
401
서비스 인증 없음
1905
404
초대 없음 또는 잘못된 토큰
1906
410
초대 만료
1907
409
다른 사용자가 이미 수락
1908
400
초대한 본인이 수락 시도
1909
409
이미 그 초대자의 수신자로 등록됨
1608
404
현재 회원 소유가 아닌 receiverId
거절은 서버에 없다. ReceiverInvitationStatus 는 PENDING 과 ACCEPTED 둘뿐이고 거절 API 도 없다. 본문 완료 조건 1 의 거절 항목은 이렇게 닫힌다.
사라진 경로와 남은 경로
POST /api/v1/users/receivers 직접 등록은 제거됐다(가이드 6.5 도 같은 말을 한다). 이메일 인증번호 API 도 함께 제거됐고, 받은 기록 조회는 X-Auth-Code 에서 JWT 로 전환됐다. users/receivers 의 GET·PATCH·DELETE 는 남아 있고, 수락으로 비어 있게 된 관계는 PATCH /api/v1/users/receivers/{receiverId}/relation 로 채운다.
본문 완료 조건 대조
문서화. 이 코멘트로 끝났다.
랜딩과 가입 후 복원. 서버 몫은 정해졌다(조회를 비로그인으로 열어 두었고 초대 URL base 도 확정). 앱 몫인 커스텀 스킴 kakao{NATIVE_APP_KEY}://kakaolink?inviteToken=... 수신, 토큰 임시 보관, 로그인·가입 후 재개는 가이드 2·4·5절에 설계가 있고 구현은 수신자 등록 카톡 초대 전환 — 이메일 등록·인증 대체 #944 다. 설치 직후 자동 복구(Deferred Deep Link)는 현재 백엔드 범위 밖이라고 가이드 8절이 못 박았다. 필요하면 Play Install Referrer 같은 별도 설계가 든다.
계약은 코드와 가이드로 다 나왔다. 남은 협의는 질문이 아니라 값 전달이다. 가이드 10절이 배포 전 확정값으로 운영·개발 API Base URL, 카카오 네이티브 앱 키, 사용자 정의 템플릿 ID, 패키지명, 키 해시(Debug·Release·Play App Signing), Play 스토어 URL, 토큰 파라미터 이름 inviteToken 을 꼽아 두었다.
PM 몫으로 남은 결정 하나
이미 이메일로 등록된 기존 수신자를 카카오 초대로 다시 받아야 하는가, 받아야 한다면 발신자에게 언제 어떻게 알리는가. 서버가 직접 등록 경로를 지운 뒤라 기존 레코드를 그대로 둘지 초대 재발송으로 계정에 붙일지는 코드로 정해지지 않는다.
FE 는 아직 삭제된 경로를 부른다
origin/develop86ab2238c 의 core/network/src/main/kotlin/com/afternote/core/network/service/UserApiService.kt:39 가 @POST("users/receivers") 를 그대로 들고 있다. 저장소 전체에서 receiver-invitations, inviteToken, ShareClient 는 0건이고 gradle/libs.versions.toml 에는 kakao v2-user 와 v2-auth 만 있고 공유용 v2-share 가 없다.
이 죽은 경로를 지우거나 대체하는 것을 완료 조건으로 가진 이슈는 없다. #1586 은 오늘 코멘트에 같은 사실을 기록해 두었지만 이슈 자체는 등록 응답의 receiverId 를 버리는 문제다. #944 는 전환 구현을 소유하되 2026-09-08 범위 분리 때 구현 체크리스트를 철회해 이 호출을 다루는 완료 조건이 없다. #709 는 이 POST 가 성공한 뒤의 처리 문제라 경로의 존재를 전제한다. 추적되고 있지 않다는 사실만 적어 둔다. 새 이슈는 만들지 않았다.
원격 브랜치에 초대·공유·딥링크를 여는 것 0건. 이름만 걸리는 fix/1871-debug-kakao-diagnostics 는 debug 서명 폴백 진단(PR fix(platform): debug 카카오 서명 폴백 진단 추가 (#1871) #2014)이고 바뀐 파일이 README.md, app/build.gradle.kts, build-logic/src/main/kotlin/DebugSigningDiagnostics.kt, 그 테스트 넷뿐이다. 그 브랜치에서도 초대 관련 심볼은 0건이다.
gradle/libs.versions.toml:31kakaoSdk = "2.24.0", :112v2-user, :113v2-auth. 공유용 v2-share 는 없다.
앞 코멘트 이후 develop 이 86ab2238c 에서 7d87aa3f4 로 움직였지만 위 다섯은 그대로다.
계약은 살아 있다
앱이 쓰는 서버 https://afternote.kro.kr/api/v1/(core/network/build.gradle.kts:13)에 2026-09-13 21:53 KST 에 로그인 없이 호출했다.
GET /receiver-invitations/zzzz-not-a-real-token 404 {"code":1905,"message":"수신자 초대를 찾을 수 없습니다."}
POST /receiver-invitations 401 {"code":1000,"message":"인증되지 않은 요청입니다."}
POST /receiver-invitations/zzzz-not-a-real-token/accept 401 {"code":1000,"message":"인증되지 않은 요청입니다."}
GET /receiver-invitations-nope/x (대조군) 404 {"code":1003,"message":"존재하지 않는 엔드포인트입니다."}
세 경로 다 매핑돼 있다. 조회는 비로그인으로 열려 있고(인증 부재 1000 이 아니라 초대 없음 1905 가 온다), 생성과 수락은 인증에서 먼저 막힌다. 없는 경로는 1003 이 오므로 1905 는 라우팅이 아니라 도메인 판정이다. 로그인 전 랜딩에서 초대자 이름과 만료를 읽을 수 있다는 계약이 배포본으로 확인됐다.
소스 근거는 BE main3593aa30 의 src/main/java/com/afternote/domain/receiver/controller/ReceiverInvitationController.java 다. 17번 줄 @RequestMapping("/api/v1/receiver-invitations"), 27번 줄 @PostMapping, 38번 줄 @GetMapping("/{token}"), 47번 줄 @PostMapping("/{token}/accept").
앱이 아직 부르는 등록 경로는 405 를 돌려준다
GET /users/receivers 401 {"code":1000,"message":"인증되지 않은 요청입니다."}
POST /users/receivers 405 {"code":1005,"message":"허용되지 않은 HTTP 메서드입니다."}
GET /users/receivers/1 401 {"code":1000,"message":"인증되지 않은 요청입니다."}
POST /users/receivers-nope (대조군) 404 {"code":1003,"message":"존재하지 않는 엔드포인트입니다."}
컬렉션 경로 자체는 살아 있다. GET 이 인증에서 막히니 매핑은 있고, 없는 것은 POST 핸들러 하나다. 경로가 통째로 없으면 대조군처럼 1003 이 왔을 텐데 1005 가 왔다.
origin/develop7d87aa3f4 의 core/network/src/main/kotlin/com/afternote/core/network/service/UserApiService.kt:39 이 @POST("users/receivers") 로 createReceiver 를 그대로 들고 있다. 인증을 통과해도 매핑이 없으니 성공할 수 없다. 앞 코멘트가 이 호출을 완료 조건으로 가진 이슈가 없다고 적어 두었는데, 지금 서버가 실제로 돌려주는 값까지 여기 붙여 둔다.
실패 코드는 앱까지 오지만 받는 자리가 없다
core/network/src/main/kotlin/com/afternote/core/network/calladapter/ApiErrorCallAdapterFactory.kt:125 가 봉투의 code 를 꺼내 ApiException 에 싣는다. 그런데 origin/develop 전체에서 1905·1906·1907·1908·1909·1608 을 분기하는 곳은 0건이다. 만료, 중복 수락, 본인 수락, 이미 등록됨을 화면에서 갈라 주려면 #944 가 이 코드를 받는 자리를 새로 만들어야 한다.
완료 조건 현황
초대 생성·조회·수락 API 와 토큰 수명, 만료·중복 수락·다른 계정 수락의 결과 문서화. 채웠다. 앞 코멘트가 본체이고, 오늘 배포본 실측으로 조회의 비로그인 개방과 세 경로의 실재까지 확인했다.
랜딩·가입 후 복원·계정 연결 기준 확정. 서버 몫은 위 실측으로 확인됐다. 앱 몫인 커스텀 스킴 수신, 토큰 임시 보관, 로그인·가입 후 재개는 저장소에 설계도 코드도 0건이라 남는다.
기존 이메일 등록 수신자의 유지·이행과 초대 대기·완료 UI 상태 확정. 남았다. PM 결정 대기이고 코드로 정해지지 않는다.
테스트 계정 검증과 수신자 등록 카톡 초대 전환 — 이메일 등록·인증 대체 #944 인계. 부분만 채웠다. 자격 없이 확인 가능한 것(라우팅, 인증 경계, 1905·1000·1005·1003)은 위에 적었다. 토큰 수명 7일, 만료 1906, 다른 사용자 수락 1907, 본인 수락 1908, 이미 등록 1909, 멱등 재수락은 로그인 계정 둘이 있어야 재현되므로 하지 못했다. 시안도 이번에는 열지 못해 시안 근거 인계는 미확인으로 남긴다.
200. QA823 의 GET /users/receivers 에 receiverId 19, name "Admin", relation null 이 생겼고, admin 의 GET /received-records 에 senderName "QA823", viewStatus REQUESTABLE 로 나타났다
재수락
admin 같은 토큰 accept
200 (멱등)
새 초대를 다시 수락
QA823 이 새로 만든 토큰을 admin 이 accept
409 code 1909
잘못된 토큰
not-a-token accept
404 code 1905
못 한 것은 둘이다. 1906(만료)은 7일을 기다려야 하고, 1907(다른 사용자가 이미 수락)은 세 번째 계정이 있어야 한다. 서버 코드로는 분기가 확인돼 있어(앞 코멘트) 앱 쪽 매핑은 코드로 잠근다.
실측으로 QA823 과 admin 이 서로의 수신자로 등록된 상태가 남아 있다(receiverId 19 포함). 앱 검증에 그대로 쓴다.
시안이 올라와 있다
2026-09-17 에 "설정 > 카카오톡 수신자 등록" 구역이 정본 페이지에 추가됐다: 4996:40220. 프레임 6장이고 류하늬 님이 전건호 님에게 확인을 요청한 댓글 하나가 달려 있다. 아직 확인 답은 없다.
4996:39735 수신자 등록 폼: 이름·연락처·관계·이메일(선택)·마지막 인삿말 + "카카오톡으로 초대 보내기"
폼 값이 갈 곳이 없다. 시안은 초대를 보내기 전에 이름·연락처·관계·인삿말을 다 받는다. 서버 초대 생성은 바디가 없고, 수락 시 수신자 레코드에는 가입자 계정의 이름·이메일·전화가 들어가며 relation·message 는 null 이다. 시안 문구 "수락하기 전에는 연락처가 저장되지 않습니다" 대로라면 폼 값은 앱이 초안으로 들고 있다가 수락 뒤 PATCH users/receivers/{id}/relation·/message 로 채워야 하는데, 발신자의 수신자 목록 응답에 invitationId 가 없어 어느 초안이 어느 수신자로 붙었는지 앱이 알 길이 없다. BE 에 초대와 수신자를 잇는 값이 필요하다.
대기 중 초대 목록이 없다. "초대를 보냈어요" 뒤의 "초대 링크 다시 보내기" 와 7일 안내는 발신자가 자기 초대 상태를 다시 볼 수 있어야 성립한다. 서버에 내 초대 목록 조회 API 가 없다. 화면을 떠나면 토큰은 앱에만 남는다.
랜딩의 "관계" 줄. 수신자 쪽 랜딩이 "관계: 아들" 을 보여 주는데 비로그인 조회 응답에는 inviterName·status·expired·expiresAt 뿐이다.
이 셋은 코드로 정해지지 않아 앞 코멘트의 PM 결정(기존 이메일 수신자 이행)과 함께 묶어 둔다.
계약이 확정된 층은 시안 확인을 기다리지 않는다. 스킴 수신과 토큰 보관, 초대 API 와 실패 매핑, 수신자 쪽 랜딩·수락·완료 화면, 발신자 쪽 초대 생성·카카오톡 공유·"초대를 보냈어요" 화면까지다. 위 세 가지에 걸리는 폼 값 처리와 대기 목록은 넣지 않는다. 설정·수신자·앱 루트가 #1962 로 Nav3 로 옮겨지는 중이라 그 위에 스택으로 얹는다.
카카오 사용자 정의 템플릿 ID 는 아직 코드에 없다. 가이드 3.2 는 만들어져 있다고 하는데 값은 카카오디벨로퍼스 콘솔에만 있다.
#944 의 계약 확정 층을 PR #2109 로 올렸다(base develop). 스킴 수신·토큰 보관·초대 API·실패 매핑·수신자 랜딩/수락/완료·발신자 초대 발급/카카오톡 공유/보냈어요 화면까지다. 카카오 콘솔 템플릿은 136940 이고 사용자 인자가 inviteToken 과 senderName 둘이라 가이드(inviteToken 만)와 다르다. 콘솔에 Android 스토어 링크가 미등록이라 앱 미설치 폴백은 아직 동작하지 않는다. 앞 코멘트의 갈리는 곳 셋(폼 값의 행방·대기 목록·랜딩 관계 줄)은 그대로 남는다.
Activity
OnlyReadOneBook commentedon Sep 13, 2026
BE 계약은 배포됐다. 이 이슈가 기다리던 서버 선행은 끝났다 (2026-09-13 확인)
Afternote/Afternote-BE#227 은 PR Afternote/Afternote-BE#289 가 2026-09-08T05:57:54Z 에 머지되면서 같은 초에 닫혔다. 그 이슈 본문에는 2026-09-13T04:30:31Z 에 완료 확인 절이 붙어
main3593aa30기준으로 토큰 해시·만료, 조회·수락, 회원 연결, 테스트 7건 통과가 적혀 있다. 2026-09-13 11:00 회의록에도 "서버 - QA 진행 중, 카카오 서버 완 → 프론트 확인 필요" 로 남아 있다.아래는 오늘 BE
main3593aa30소스를 직접 읽어 옮긴 것이다. BE 가 안드로이드용 연동 가이드도 따로 써 두었다: 카카오톡 수신자 초대 Android 연동 가이드 (API 기본 명세서 하위, 0913 회의록에 걸려 있다).엔드포인트 3개
POST /api/v1/receiver-invitations(인증 필요, 요청 바디 없음)응답
invitationId,invitationToken,invitationUrl,expiresAt. 토큰은 32바이트 난수를 base64url 로 인코딩한 값이고 서버는 SHA-256 해시만 저장한다. 만료는 생성 시각 더하기RECEIVER_INVITATION_EXPIRATION_DAYS(기본 7일).invitationUrl은RECEIVER_INVITATION_BASE_URL(기본https://afternote.kro.kr/invitations) 뒤에 토큰을 붙인 값이다. 카카오 템플릿에는 URL 이 아니라invitationToken을inviteToken인자로 넘긴다.GET /api/v1/receiver-invitations/{token}(비로그인 호출 가능)응답
inviterName,status,expired,expiresAt. 로그인 전 랜딩에서 초대자 이름과 만료를 보여줄 수 있다.POST /api/v1/receiver-invitations/{token}/accept(인증 필요, 요청 바디 없음)응답
receiverId,inviterName. 수락 즉시 수신자로 등록되며relation과message는 null 로 저장되고 나중에 초대자가 채운다. 같은 사용자가 같은 초대를 다시 수락하면 같은 결과를 돌려주는 멱등 처리다. 가입만으로는 수락되지 않는다. 서비스 JWT 를 받은 뒤 이 API 를 따로 불러야 한다.실패 코드
거절은 서버에 없다.
ReceiverInvitationStatus는PENDING과ACCEPTED둘뿐이고 거절 API 도 없다. 본문 완료 조건 1 의 거절 항목은 이렇게 닫힌다.사라진 경로와 남은 경로
POST /api/v1/users/receivers직접 등록은 제거됐다(가이드 6.5 도 같은 말을 한다). 이메일 인증번호 API 도 함께 제거됐고, 받은 기록 조회는X-Auth-Code에서 JWT 로 전환됐다.users/receivers의 GET·PATCH·DELETE 는 남아 있고, 수락으로 비어 있게 된 관계는PATCH /api/v1/users/receivers/{receiverId}/relation로 채운다.본문 완료 조건 대조
kakao{NATIVE_APP_KEY}://kakaolink?inviteToken=...수신, 토큰 임시 보관, 로그인·가입 후 재개는 가이드 2·4·5절에 설계가 있고 구현은 수신자 등록 카톡 초대 전환 — 이메일 등록·인증 대체 #944 다. 설치 직후 자동 복구(Deferred Deep Link)는 현재 백엔드 범위 밖이라고 가이드 8절이 못 박았다. 필요하면 Play Install Referrer 같은 별도 설계가 든다.BE 에 다시 물을 것은 없다
계약은 코드와 가이드로 다 나왔다. 남은 협의는 질문이 아니라 값 전달이다. 가이드 10절이 배포 전 확정값으로 운영·개발 API Base URL, 카카오 네이티브 앱 키, 사용자 정의 템플릿 ID, 패키지명, 키 해시(Debug·Release·Play App Signing), Play 스토어 URL, 토큰 파라미터 이름
inviteToken을 꼽아 두었다.PM 몫으로 남은 결정 하나
이미 이메일로 등록된 기존 수신자를 카카오 초대로 다시 받아야 하는가, 받아야 한다면 발신자에게 언제 어떻게 알리는가. 서버가 직접 등록 경로를 지운 뒤라 기존 레코드를 그대로 둘지 초대 재발송으로 계정에 붙일지는 코드로 정해지지 않는다.
FE 는 아직 삭제된 경로를 부른다
origin/develop86ab2238c의core/network/src/main/kotlin/com/afternote/core/network/service/UserApiService.kt:39가@POST("users/receivers")를 그대로 들고 있다. 저장소 전체에서receiver-invitations,inviteToken,ShareClient는 0건이고gradle/libs.versions.toml에는 kakaov2-user와v2-auth만 있고 공유용v2-share가 없다.이 죽은 경로를 지우거나 대체하는 것을 완료 조건으로 가진 이슈는 없다. #1586 은 오늘 코멘트에 같은 사실을 기록해 두었지만 이슈 자체는 등록 응답의
receiverId를 버리는 문제다. #944 는 전환 구현을 소유하되 2026-09-08 범위 분리 때 구현 체크리스트를 철회해 이 호출을 다루는 완료 조건이 없다. #709 는 이 POST 가 성공한 뒤의 처리 문제라 경로의 존재를 전제한다. 추적되고 있지 않다는 사실만 적어 둔다. 새 이슈는 만들지 않았다.OnlyReadOneBook commentedon Sep 13, 2026
배포본을 직접 찔러 본 실측. 착수 흔적은 여전히 0건이다 (2026-09-13 저녁)
계약 전문과 완료 조건 대조는 앞 코멘트에 있다. 여기는 겹치지 않는 것만 적는다. 저장소 실측을 게시 시점
origin/develop7d87aa3f4로 다시 뜨고, 배포된 계약을 자격 없이 실제로 호출한 결과다.착수 흔적 0건
git log origin/develop --grep="#1948"0건,--grep="#944"0건.fix/1871-debug-kakao-diagnostics는 debug 서명 폴백 진단(PR fix(platform): debug 카카오 서명 폴백 진단 추가 (#1871) #2014)이고 바뀐 파일이README.md,app/build.gradle.kts,build-logic/src/main/kotlin/DebugSigningDiagnostics.kt, 그 테스트 넷뿐이다. 그 브랜치에서도 초대 관련 심볼은 0건이다.git grep -ril -E "receiver-invitations|inviteToken|invitationToken|ShareClient|kakaolink" origin/develop0건.gradle/libs.versions.toml:31kakaoSdk = "2.24.0",:112v2-user,:113v2-auth. 공유용v2-share는 없다.앞 코멘트 이후
develop이86ab2238c에서7d87aa3f4로 움직였지만 위 다섯은 그대로다.계약은 살아 있다
앱이 쓰는 서버
https://afternote.kro.kr/api/v1/(core/network/build.gradle.kts:13)에 2026-09-13 21:53 KST 에 로그인 없이 호출했다.세 경로 다 매핑돼 있다. 조회는 비로그인으로 열려 있고(인증 부재 1000 이 아니라 초대 없음 1905 가 온다), 생성과 수락은 인증에서 먼저 막힌다. 없는 경로는 1003 이 오므로 1905 는 라우팅이 아니라 도메인 판정이다. 로그인 전 랜딩에서 초대자 이름과 만료를 읽을 수 있다는 계약이 배포본으로 확인됐다.
소스 근거는 BE
main3593aa30의src/main/java/com/afternote/domain/receiver/controller/ReceiverInvitationController.java다. 17번 줄@RequestMapping("/api/v1/receiver-invitations"), 27번 줄@PostMapping, 38번 줄@GetMapping("/{token}"), 47번 줄@PostMapping("/{token}/accept").앱이 아직 부르는 등록 경로는 405 를 돌려준다
컬렉션 경로 자체는 살아 있다. GET 이 인증에서 막히니 매핑은 있고, 없는 것은 POST 핸들러 하나다. 경로가 통째로 없으면 대조군처럼 1003 이 왔을 텐데 1005 가 왔다.
origin/develop7d87aa3f4의core/network/src/main/kotlin/com/afternote/core/network/service/UserApiService.kt:39이@POST("users/receivers")로createReceiver를 그대로 들고 있다. 인증을 통과해도 매핑이 없으니 성공할 수 없다. 앞 코멘트가 이 호출을 완료 조건으로 가진 이슈가 없다고 적어 두었는데, 지금 서버가 실제로 돌려주는 값까지 여기 붙여 둔다.실패 코드는 앱까지 오지만 받는 자리가 없다
core/network/src/main/kotlin/com/afternote/core/network/calladapter/ApiErrorCallAdapterFactory.kt:125가 봉투의code를 꺼내ApiException에 싣는다. 그런데origin/develop전체에서 1905·1906·1907·1908·1909·1608 을 분기하는 곳은 0건이다. 만료, 중복 수락, 본인 수락, 이미 등록됨을 화면에서 갈라 주려면 #944 가 이 코드를 받는 자리를 새로 만들어야 한다.완료 조건 현황
남은 것과 무엇이 풀려야 하나
OnlyReadOneBook commentedon Sep 18, 2026
테스트 계정 둘로 계약을 실측했고, 시안이 올라와 있어 계약과 대조했다 (2026-09-18)
기준은 BE
main3593aa30, 서버https://afternote.kro.kr/api/v1, 계정은 QA823(초대자)과 admin(수신자). 두 계정 다 일반 회원이라 초대·수락 양쪽에 쓸 수 있다.실측 결과
POST /receiver-invitationsGET /receiver-invitations/{token}inviterName: "QA823", status: PENDING, expired: falseGET /users/receivers에receiverId 19, name "Admin", relation null이 생겼고, admin 의GET /received-records에senderName "QA823", viewStatus REQUESTABLE로 나타났다not-a-tokenaccept못 한 것은 둘이다. 1906(만료)은 7일을 기다려야 하고, 1907(다른 사용자가 이미 수락)은 세 번째 계정이 있어야 한다. 서버 코드로는 분기가 확인돼 있어(앞 코멘트) 앱 쪽 매핑은 코드로 잠근다.
실측으로 QA823 과 admin 이 서로의 수신자로 등록된 상태가 남아 있다(receiverId 19 포함). 앱 검증에 그대로 쓴다.
시안이 올라와 있다
2026-09-17 에 "설정 > 카카오톡 수신자 등록" 구역이 정본 페이지에 추가됐다: 4996:40220. 프레임 6장이고 류하늬 님이 전건호 님에게 확인을 요청한 댓글 하나가 달려 있다. 아직 확인 답은 없다.
시안과 서버 계약이 갈리는 곳 세 가지
PATCH users/receivers/{id}/relation·/message로 채워야 하는데, 발신자의 수신자 목록 응답에 invitationId 가 없어 어느 초안이 어느 수신자로 붙었는지 앱이 알 길이 없다. BE 에 초대와 수신자를 잇는 값이 필요하다.이 셋은 코드로 정해지지 않아 앞 코멘트의 PM 결정(기존 이메일 수신자 이행)과 함께 묶어 둔다.
지금 착수한 범위 (#944)
계약이 확정된 층은 시안 확인을 기다리지 않는다. 스킴 수신과 토큰 보관, 초대 API 와 실패 매핑, 수신자 쪽 랜딩·수락·완료 화면, 발신자 쪽 초대 생성·카카오톡 공유·"초대를 보냈어요" 화면까지다. 위 세 가지에 걸리는 폼 값 처리와 대기 목록은 넣지 않는다. 설정·수신자·앱 루트가 #1962 로 Nav3 로 옮겨지는 중이라 그 위에 스택으로 얹는다.
카카오 사용자 정의 템플릿 ID 는 아직 코드에 없다. 가이드 3.2 는 만들어져 있다고 하는데 값은 카카오디벨로퍼스 콘솔에만 있다.
OnlyReadOneBook commentedon Sep 18, 2026
#944 의 계약 확정 층을 PR #2109 로 올렸다(base develop). 스킴 수신·토큰 보관·초대 API·실패 매핑·수신자 랜딩/수락/완료·발신자 초대 발급/카카오톡 공유/보냈어요 화면까지다. 카카오 콘솔 템플릿은 136940 이고 사용자 인자가 inviteToken 과 senderName 둘이라 가이드(inviteToken 만)와 다르다. 콘솔에 Android 스토어 링크가 미등록이라 앱 미설치 폴백은 아직 동작하지 않는다. 앞 코멘트의 갈리는 곳 셋(폼 값의 행방·대기 목록·랜딩 관계 줄)은 그대로 남는다.
OnlyReadOneBook commentedon Sep 18, 2026
PM 결정 대기 항목은 깃허브 이슈로 두지 않고 피그마 질문 한 자리에만 둔다(2026-09-18 결정). 이 이슈에 남아 있던 넷(초대 전 폼 값의 행방과 BE 매칭 값, 발신자 대기 초대 목록, 랜딩 관계 줄, 기존 이메일 수신자 이행)은 시안 4996:39735 에 전건호 님 앞으로 걸었다: https://www.figma.com/design/UP9ZR186jHvRBicjA2SOea/?node-id=4996-39735#1932688071 답이 오면 그 답을 근거로 FE·BE 구현 이슈를 새로 만든다. 계약 실측과 앱 검증은 앞 코멘트와 PR #2109 에 있다.