Skip to content

feat(core): 공통 URI 검증과 비수신자 App Link 계약을 세운다 (#1857) - #1859

Closed
1hyok wants to merge 3 commits into
developfrom
feat/924-app-links
Closed

1hyok wants to merge 3 commits into
developfrom
feat/924-app-links

Conversation

@1hyok

@1hyok 1hyok commented Sep 3, 2026 •

Copy link
Copy Markdown
Collaborator

변경

공통 URI 입력 검증과 비수신자 목적지 6개를 엔진 중립 NavigationTarget으로 해석한다. 지원하는 경로는 홈, 작성자 애프터노트 홈·상세, 타임레터 상세, 데일리질문 작성, 알림 설정이다. 정규 URL·ID·로그인/생체인증 관문과 거절 사유를 함께 정의한다.

수신자 경로는 서버 식별자·접근 정책이 미정이므로 #1951로 분리했다. 해당 목적지 3개, 로컬 SenderRegistry UUID 형식, 수신자 인증 관문, 그 성공 계약 테스트를 이 PR의 코드에서 제거했다. 현재 /received 계열은 지원하지 않는 경로로 거절한다. #1951이 확정되면 그 결과 위에서 추가한다.

이 PR은 #1951을 기다리지 않고 완료할 수 있다. 실제 Intent 수신과 인증 후 목적지 재개는 #924에서 구현한다.

검증

  • 최신 develop 8ef216417 통합.
  • :core:common:testDebugUnitTest: 65개 통과. 미확정 수신자 경로 3종 거절 회귀 포함.
  • :core:common:ktlintCheck, :konsist:test(54개) 통과.
  • Android intent-filter와 실제 링크 진입은 이번 범위에 포함하지 않는다.

연결 이슈

Closes #1857
Refs #924, #1951

CI Test Plan

{"androidTest":{"mode":"none","reason":"core common의 엔진 중립 URI 파서·목적지 계약과 JVM 테스트·konsist 계약 목록만 변경한다. Android Intent 수신과 런타임 라우팅은 #924 범위다.","tests":[]}}

브라우저 App Link 와 FCM data.link 가 같은 파서를 지나도록 입력을 String 으로
받는다. 목적지는 Nav2 Route 도 Navigation 3 NavKey 도 아닌 sealed
NavigationTarget 이다 — 링크는 서버·브라우저·알림이 공유하는 외부 계약이라
앱 안의 navigation 엔진 교체(#1698·#1702)와 수명이 다르다.

계약 밖 입력은 전부 거절이다. 링크는 앱 밖에서 오는 입력이라 관대하게 받는
만큼이 공격면이다 — 커스텀 scheme 은 Digital Asset Links 검증을 못 받아 아무
앱이나 선점할 수 있고, https://evil@afternote.kro.kr/ 같은 userinfo 는 눈으로
우리 도메인처럼 보인다. 거절은 null 이 아니라 사유와 안전한 기본 진입을 함께
든 값이라, 호출부마다 폴백이 갈리거나 「왜 홈으로 왔는지」가 사라지지 않는다.

ID 자릿수 판정에 정규식 \d 를 쓰지 않는다. Android 의 \d 는 아라비아-인도
숫자까지 물어 서버 JVM 과 다르게 판정하므로 '0'..'9' 로 직접 좁혔고, 그
경계를 테스트로 잠갔다.

파서 진입점은 아직 프로덕션 소비처가 없어 konsist 의 의도된 계약 목록에
넣는다. intent 수신 배선은 #924 가 붙인다.
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🚧 리뷰 적체 가드 — 이 PR 을 닫습니다

팀 리뷰 응답 대기 · 2건

PR 열린 날 경과 제목
#1723 2026-09-02 1일 fix(core-ui): 다크 팔레트 확정 전까지 라이트로 잠근다 (#1719)
#1670 2026-08-31 3일 fix(mindrecord): 작성 툴바 클릭 타깃의 이름·역할·선택 상태를 채운다 (#1179)

이 저장소는 팀 리뷰 응답 또는 자기 PR 의 변경요청 대응을 기다리는 PR 이 1건이라도 남아 있으면 새 PR 을 열 수 없습니다 (#1136, #1679).

각 PR 에 필요한 리뷰는 한 건입니다 — 누구든 먼저 판정을 내면 그 PR 은 모두의 목록에서 빠집니다. 승인 뒤 변경을 다시 볼 의무는 없고, 변경요청도 작성자가 같은 리뷰어에게 재요청한 뒤 실질 커밋·응답·본문 편집을 남긴 경우에만 다시 리뷰어의 몫이 됩니다.
자기 PR 이 최신 변경요청 뒤 실질 커밋·응답·작성자 본문 편집 없이 남아 있으면 작성자의 몫입니다. 조치를 남기면 다음 검사에서 작성자 빚이 해소됩니다.

되살리는 법

위 PR 에 필요한 리뷰나 작성자 조치를 끝낸 뒤 이 PR 을 다시 여세요. 브랜치는 지워지지 않았고 커밋도 그대로입니다.

gh pr reopen 1859

@github-actions github-actions Bot closed this Sep 3, 2026
@1hyok 1hyok reopened this Sep 3, 2026
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🚧 리뷰 적체 가드 — 이 PR 을 닫습니다

작성자 응답 대기 · 2건

PR 열린 날 변경요청자 제목
#1816 2026-09-03 @Sadturtleman fix(core-ui): 나눔바른고딕 Bold 획 비대칭을 없애 시안대로 Regular 로 맞춘다 (#1815)
#1799 2026-09-03 @Sadturtleman fix(core-ui): 라이트 테마 본문 대비를 4.89:1 로 올린다 (#1798)

이 저장소는 팀 리뷰 응답 또는 자기 PR 의 변경요청 대응을 기다리는 PR 이 1건이라도 남아 있으면 새 PR 을 열 수 없습니다 (#1136, #1679).

각 PR 에 필요한 리뷰는 한 건입니다 — 누구든 먼저 판정을 내면 그 PR 은 모두의 목록에서 빠집니다. 승인 뒤 변경을 다시 볼 의무는 없고, 변경요청도 작성자가 같은 리뷰어에게 재요청한 뒤 실질 커밋·응답·본문 편집을 남긴 경우에만 다시 리뷰어의 몫이 됩니다.
자기 PR 이 최신 변경요청 뒤 실질 커밋·응답·작성자 본문 편집 없이 남아 있으면 작성자의 몫입니다. 조치를 남기면 다음 검사에서 작성자 빚이 해소됩니다.

되살리는 법

위 PR 에 필요한 리뷰나 작성자 조치를 끝낸 뒤 이 PR 을 다시 여세요. 브랜치는 지워지지 않았고 커밋도 그대로입니다.

gh pr reopen 1859

@Sadturtleman Sadturtleman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

경계가 실제로 fail-closed 인 것을 확인했습니다. java.net.URI 가 생성 시 정규화하지 않는다는 점에 기대어 rawPath 로 읽은 덕에 ..·%2F·빈 세그먼트·끝 슬래시·대문자가 전부 SEGMENT_FORMAT 에서 걸리고, 떨어지는 곳이 조용한 기본값이 아니라 사유가 붙은 Rejected(reason, Home) 라 나중에 왜 막혔는지 읽을 수 있습니다. fallback 도 LOGIN 관문을 지납니다. NavigationTargetContractTest 가 목적지 전량을 parse(canonicalUrl(t)) 로 왕복시키고 관문 불변식을 when exhaustive 로 잠근 것이 특히 좋습니다 — 목적지가 늘 때 자동으로 걸립니다. 승인합니다.

한 줄만 적어 둡니다.

[nit] 숫자 좁힘을 잠근다는 테스트가 실제로는 그 좁힘을 지나지 않는다

toResourceIdOrNull 의 「\d 대신 '0'..'9' 로 좁힌다」 주석과 「아라비아-인도 숫자는 ID 가 아니다」 테스트 이야기입니다. ١٢ 는 SEGMENT_FORMAT 에서 먼저 걸려(기대값도 UNKNOWN_PATH 라 통과합니다) 그 함수에 닿지 않습니다. 그 줄을 \d 로 되돌려도 테스트는 초록입니다. 본문의 변이 검사가 SEGMENT_FORMAT 을 푼 것이라 같은 사실을 가리킵니다. 방어적 중복 자체는 그대로 두는 게 맞고, 그 테스트가 무엇을 잠그는지만 한 줄 고쳐 두면 다음 사람이 오해하지 않습니다.

@github-actions github-actions Bot added the sibling-conflict 열린 형제 PR 과 같은 파일에서 충돌 — 나중에 머지되는 쪽이 base 를 병합해야 한다. 해소되면 자동으로 떨어진다 label Sep 6, 2026
@github-actions

github-actions Bot commented Sep 6, 2026 •

Copy link
Copy Markdown
Contributor

형제 충돌이 해소됐다 — 지금은 이 PR 과 같은 파일을 서로 다르게 고친 열린 PR 이 없다 (#1750).
다시 생기면 이 코멘트를 현재 상태로 고쳐 쓴다.

@1hyok
1hyok added this pull request to the merge queue Sep 7, 2026
@1hyok
1hyok removed this pull request from the merge queue due to a manual request Sep 7, 2026
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

merge queue 방출 — merge group CI 실패

사유 MANUAL · head 41c8781. 재투입하지 않았다.

실패한 job:

고친 뒤 gh pr merge 1859 --repo Afternote/Afternote-FE 로 다시 투입한다.

@github-actions github-actions Bot added the conflict base 와 충돌 — CI 가 트리거되지 않는다. base 를 병합하면 자동으로 떨어진다 label Sep 7, 2026
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

이 PR 은 develop 와 충돌 상태이고, 그래서 CI 가 돌지 않는다.

pull_request 워크플로는 base 와 head 를 합친 가상 머지 커밋(refs/pull/<N>/merge)에서
실행되는데, 충돌이면 GitHub 이 그 ref 를 만들지 못해 워크플로가 트리거조차 되지 않는다.
체크가 실패하는 것이 아니라 아예 생성되지 않으므로, 새 커밋을 올려도 no checks reported
인 채 최신 커밋이 한 번도 검증되지 않은 상태로 남는다 (#1028).

develop 를 병합해 충돌을 풀면 검증이 다시 돈다. 해소되면 이 라벨은 자동으로 떨어진다.

@github-actions github-actions Bot added sibling-conflict 열린 형제 PR 과 같은 파일에서 충돌 — 나중에 머지되는 쪽이 base 를 병합해야 한다. 해소되면 자동으로 떨어진다 and removed sibling-conflict 열린 형제 PR 과 같은 파일에서 충돌 — 나중에 머지되는 쪽이 base 를 병합해야 한다. 해소되면 자동으로 떨어진다 labels Sep 7, 2026
@github-actions github-actions Bot removed the sibling-conflict 열린 형제 PR 과 같은 파일에서 충돌 — 나중에 머지되는 쪽이 base 를 병합해야 한다. 해소되면 자동으로 떨어진다 label Sep 7, 2026
@1hyok
1hyok marked this pull request as draft September 7, 2026 20:09
@1hyok
1hyok marked this pull request as ready for review September 7, 2026 21:08
@github-actions github-actions Bot added the sibling-conflict 열린 형제 PR 과 같은 파일에서 충돌 — 나중에 머지되는 쪽이 base 를 병합해야 한다. 해소되면 자동으로 떨어진다 label Sep 8, 2026
@github-actions github-actions Bot removed the conflict base 와 충돌 — CI 가 트리거되지 않는다. base 를 병합하면 자동으로 떨어진다 label Sep 8, 2026
@1hyok 1hyok changed the title feat(core): App Link URI 계약과 엔진 중립 목적지 파서를 세운다 (#1857) feat(core): 공통 URI 검증과 비수신자 App Link 계약을 세운다 (#1857) Sep 8, 2026
@github-actions github-actions Bot removed the sibling-conflict 열린 형제 PR 과 같은 파일에서 충돌 — 나중에 머지되는 쪽이 base 를 병합해야 한다. 해소되면 자동으로 떨어진다 label Sep 8, 2026
@1hyok
1hyok marked this pull request as draft September 11, 2026 07:07
@1hyok

1hyok commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator Author

드래프트로 돌린다. 이 파서를 호출하는 소비처가 아직 하나도 없다. MainActivity 인텐트 필터(#924), 알림 목적지 배선(#1111), 서버 FCM 링크 계약 모두 미착수라, 여기서 고정한 정규 URL 규칙과 거절 사유가 실제 발송 링크와 맞는지 검증할 길이 없다.

파서 코드는 버리지 않고 #924 브랜치의 첫 커밋으로 가져가, 인텐트 필터와 홈 진입까지 한 PR 로 닫는다. 링크를 누르면 앱이 그 화면을 여는 동작이 머지 단위가 돼야 한다. #1857 은 #924 로 흡수해 닫는다.

@1hyok

1hyok commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator Author

닫는다. 코드는 feat 브랜치에 남아 있고 #924 착수 때 첫 커밋으로 가져온다. 파서 단독으로는 머지하지 않기로 했으니 열어 둘 이유가 없다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(core): App Link URI 계약과 엔진 중립 목적지 파서를 세운다

2 participants