Skip to content

[edit] 공동편집 연결이 연달아 실패하면 저장할 수 없는 이유를 알린다 - #56

Merged
yeondon125 merged 3 commits into
mainfrom
fix/collaboration-connection-notice
Nov 12, 2026
Merged

yeondon125 merged 3 commits into
mainfrom
fix/collaboration-connection-notice

Conversation

@yeondon125

@yeondon125 yeondon125 commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

개요

편집 화면에서 공동편집 연결이 로그인 문제가 아닌 이유로 계속 실패하면 상단 바에 '연결 중…'만 보이고, 본문이 잠기고 저장이 막힌 이유를 알 수 없었습니다. Vercel 배포본에서 rewrites가 Upgrade 헤더를 떼어 핸드셰이크가 매번 400이던 때 "문서 수정이 안 된다"로만 보였던 원인입니다.

연속 실패 횟수를 세어, bootstrap까지 가지 못한 연결이 3번 이어지면 이유를 Alert로 알립니다. 재연결은 지금처럼 계속하고, 연결되면 안내를 지웁니다.

Closes #55

변경 사항

  • provider.ts: bootstrap 전에 닫힌 연결을 failedAttempts로 세고, 3번(UNREACHABLE_AFTER_FAILURES)이 되면 스냅샷의 unreachable을 켭니다. 연결되면 0으로 돌리고 끕니다.
    • 안내는 scheduleReconnect에서 켭니다. 로그인 풀림(unauthorized)과 거절된 계정(rejected)을 가른 뒤에만 이리 오므로, 그 안내 자리에 이 안내가 먼저 비치지 않습니다.
    • 백오프와 재시도 방식은 바꾸지 않았습니다.
  • provider.ts: student가 없는 계정은 unreachable을 켜지 않습니다. 연결되어도 고칠 수 없어 처음부터 보이는 계정 안내를 그대로 둡니다.
  • connection-problem.ts: 우선순위는 unauthorized 안내(기존), rejected는 안내 없음(계정 안내가 이미 있음), 그다음 unreachable 안내입니다. 한 번도 연결하지 못했을 때는 본문이 읽기 전용이라 "쓴 내용이 남는다"는 말을 빼고, 연결된 적이 있을 때만 넣습니다.
  • CLAUDE.md 실시간 공동편집 절에 규칙을 한 줄 더했습니다.

기준을 3번으로 정한 이유: 브라우저가 핸드셰이크 실패 사유를 알려 주지 않아(닫힘 코드 1006) 원인으로는 가를 수 없습니다. 서버 재시작 같은 잠깐의 끊김은 한두 번 안에 풀리고, 바로 거절되는 경우 세 번째 실패가 백오프 1초 · 2초를 지나 약 3초 뒤라 이유 없이 기다리는 시간이 짧습니다.

확인 사항

핸드셰이크를 400으로 거절하거나 허용하도록 바꿀 수 있는 가짜 백엔드에 next dev를 붙이고, Chrome(CDP)으로 편집 화면을 구동해 확인했습니다.

상황 결과
처음부터 계속 거절 몇 초 안에 "공동편집 서버에 연결할 수 없습니다. 지금은 서버에 닿지 않아 본문을 고치거나 저장할 수 없습니다. …" 안내. 본문 읽기 전용, 저장 막힘
허용으로 전환 자동으로 다시 연결되어 '실시간 연결됨', 안내 사라짐
연결된 뒤 끊고 계속 거절 처음 몇 초는 상단 바만 '연결 끊김 · 다시 연결하는 중', 약 9초 뒤 "… 그동안 쓴 내용은 이 브라우저에 남아 있다가 다시 연결되면 합쳐집니다." 안내. 본문은 계속 입력 가능
다시 허용 안내 사라짐. 끊기기 전 · 끊긴 동안 입력한 줄이 모두 합쳐지고 저장 성공
  • npx eslint --ignore-pattern ".claude/**", npm run typecheck, npm run build 통과. 로컬에서 npm run lint를 그대로 돌리면 .git/info/exclude로 빠진 .claude/worktrees/ 안의 빌드 결과물까지 검사해 끝나지 않아서 그 폴더만 뺐습니다. CI 검사 범위와 같습니다.
  • 리뷰 반영(057e761): student가 없는 계정은 unreachable을 켜지 않습니다. 이 계정으로 핸드셰이크를 계속 거절해 보니, 5번 실패하는 동안 "학생 계정만 문서를 고칠 수 있습니다." 안내가 그대로 남았습니다. 연결된 적이 있을 때의 문구는 "…다시 연결되면 합쳐지고, 합치지 못하면 따로 알려 드립니다."로 바꿨습니다.
  • 로그인 풀림(unauthorized) 경로는 다시 구동해 보지 않았습니다. 코드상 scheduleReconnect 전에 끝나 새 안내가 켜지지 않고, 켜져 있더라도 failure가 있으면 기존 안내가 우선합니다.
  • 화면 요소는 기존 Alert를 그대로 써서 새 스타일이 없습니다. 라이트 모드는 따로 보지 않았습니다.

체크리스트

  • CLAUDE.md의 구조·스타일 규칙을 지켰습니다.
  • npm run lint, npm run typecheck, npm run build가 통과합니다.
  • 화면이 바뀌었다면 라이트 · 다크 모드를 모두 확인했습니다. (기존 Alert 재사용, 다크 모드만 확인)
  • 구조나 규칙이 바뀌었다면 CLAUDE.md와 README.md를 고쳤습니다.

🤖 Generated with Claude Code

yeondon125 and others added 2 commits November 12, 2026 10:47
로그인 문제가 아닌 핸드셰이크 실패(400 · 403 · 502 등)는 재연결만 반복해, 편집 화면에는 '연결 중…'만 보이고
본문이 잠기고 저장이 막힌 이유를 알 수 없었다. bootstrap까지 못 간 연결이 3번 이어지면 unreachable로 보고
Alert로 알린다. 재연결은 그대로 계속하고, 연결되면 안내를 지운다.

Closes #55

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yeondon125 yeondon125 added the bug Something isn't working label Nov 12, 2026
@vercel

vercel Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
frontend Ready Ready Preview Nov 12, 2026 1:56am UTC

Comment on lines +470 to +475
if (
this.failedAttempts >= UNREACHABLE_AFTER_FAILURES &&
!this.snapshot.unreachable
) {
this.update({ unreachable: true });
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[버그] student가 없는 계정(교사 등)에서 계정 안내가 이 안내로 바뀌고, 틀린 말이 보입니다.

재현: student가 없는 계정으로 편집 화면에 들어왔는데 핸드셰이크가 계속 실패하는 경우(이 PR이 겨냥한 rewrites 400 상황 그대로).

  • 소켓이 열리지 않으므로 handleClose가 1011 → rejected 분기까지 가지 않고 retryUnlessSignedOut → scheduleReconnect로 옵니다. 세 번째에 unreachable: true가 켜집니다.
  • EditWorkspace의 notice는 problem ?? describeConnectionProblem(snapshot) ?? findAccountProblem(target) 순서라, 처음부터 보이던 "학생 계정만 문서를 고칠 수 있습니다." 안내가 사라지고
  • 대신 ready: false 문구인 "…연결되면 바로 편집할 수 있습니다."가 보입니다. 이 계정은 연결되어도 백엔드가 1011로 닫아 편집할 수 없으므로 사실과 다릅니다.

이 계정은 어차피 고칠 수 없어 서버에 닿는지가 의미 없으니, 여기서 켜지 않는 것이 가장 간단합니다.

Suggested change
if (
this.failedAttempts >= UNREACHABLE_AFTER_FAILURES &&
!this.snapshot.unreachable
) {
this.update({ unreachable: true });
}
if (
this.options.studentAccount &&
this.failedAttempts >= UNREACHABLE_AFTER_FAILURES &&
!this.snapshot.unreachable
) {
this.update({ unreachable: true });
}

(또는 EditWorkspace에서 unreachable 안내보다 findAccountProblem을 앞에 두되 unauthorized 안내는 계속 가장 앞에 오도록 순서를 나누는 방법도 있습니다.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

반영했습니다 (057e761). scheduleReconnect에서 this.options.studentAccount일 때만 unreachable을 켭니다. student가 없는 계정으로 핸드셰이크를 계속 거절하는 상황을 가짜 백엔드로 재현해, 5번 실패하는 동안 "학생 계정만 문서를 고칠 수 있습니다." 안내가 그대로 남는 것을 확인했습니다. CLAUDE.md 규칙 줄에도 이 예외를 적었습니다.

needsSignin: true,
title: "공동편집 서버에 연결할 수 없습니다.",
message: snapshot.ready
? "지금은 서버에 닿지 않아 저장할 수 없습니다. 연결은 자동으로 계속 다시 시도합니다. 그동안 쓴 내용은 이 브라우저에 남아 있다가 다시 연결되면 합쳐집니다."

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[제안] "다시 연결되면 합쳐집니다"라고 단정하지만, 이 안내가 오래 떠 있는 경우일수록 합쳐지지 않을 수 있습니다.

연결이 길게 안 되는 동안 방이 비면 백엔드가 자동 저장하고 진행 중 상태를 지웁니다. 다시 연결했을 때 뿌리가 다르면 switchToServerState로 가는데, 서버 본문이 내가 마지막으로 올린 본문과 다르면(그사이 다른 사람이 저장함) 내 편집은 합치지 않고 unmergedDraft로 빼 둡니다(provider.ts 724~727행). 이 경우 사용자는 "합쳐진다"는 말을 믿고 기다렸다가 본문에서 자기 편집이 빠진 것을 보게 됩니다. CollaborationNotices가 따로 안내하긴 하지만 이 문구와 어긋납니다.

Suggested change
? "지금은 서버에 닿지 않아 저장할 수 없습니다. 연결은 자동으로 계속 다시 시도합니다. 그동안 쓴 내용은 이 브라우저에 남아 있다가 다시 연결되면 합쳐집니다."
? "지금은 서버에 닿지 않아 저장할 수 없습니다. 연결은 자동으로 계속 다시 시도합니다. 그동안 쓴 내용은 이 브라우저에 남아 있다가 다시 연결되면 합쳐집니다. 그사이 다른 사람이 저장했다면 합치지 못한 내용을 따로 보여 드립니다."

또는 더 짧게 "다시 연결되면 서버로 보냅니다" 정도로 단정을 피해도 됩니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

반영했습니다 (057e761). "…다시 연결되면 합쳐지고, 합치지 못하면 따로 알려 드립니다."로 단정을 피했고, 이유(unmergedDraft)를 주석으로 남겼습니다.

@claude

claude Bot commented Nov 12, 2026

Copy link
Copy Markdown

공동편집 연결이 `bootstrap` 전에 3번 연달아 실패하면 `unreachable`을 켜고, 저장할 수 없는 이유를 `Alert`로 알리는 변경입니다. 재연결과 백오프는 그대로입니다.

지적: [버그] 1 · [제안] 1

  • 머지 전에 꼭 고칠 것: [버그] `student`가 없는 계정에서 핸드셰이크가 계속 실패하면 `unreachable` 안내가 계정 안내("학생 계정만 문서를 고칠 수 있습니다.")를 덮습니다. 이때 "연결되면 바로 편집할 수 있습니다"라는 틀린 문구가 보입니다 (`provider.ts` `scheduleReconnect`).
  • [제안] 연결된 적이 있을 때의 문구가 "다시 연결되면 합쳐집니다"라고 단정합니다. 그런데 오래 끊긴 뒤 뿌리가 다르면 `unmergedDraft`로 빠질 수 있습니다.

리뷰 범위: 바뀐 파일 5개를 모두 리뷰했습니다 (`CLAUDE.md`, `connection-problem.ts`, `provider.ts`, `use-collaboration.ts`, `EditWorkspace.tsx`). 건너뛴 파일은 없습니다.

핸드셰이크부터 실패하면 1011 거절까지 가지 못해 rejected가 되지 않아, student가 없는 계정에서 처음부터 보이던
계정 안내가 unreachable 안내로 바뀌고 "연결되면 바로 편집할 수 있습니다"라는 틀린 말이 보였다.
이 계정은 연결되어도 고칠 수 없으므로 unreachable을 켜지 않는다.

연결된 적이 있을 때의 문구도 "다시 연결되면 합쳐집니다"로 단정하지 않는다. 오래 끊긴 사이 다른 사람이 저장했으면
합치지 못하고 unmergedDraft로 따로 빼 둔다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@jyuuuuu0 jyuuuuu0 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

연속 실패 카운트가 bootstrap에서만 0이 되고, 안내를 켜는 곳이 unauthorized·rejected 판정 뒤의 scheduleReconnect라 기존 안내와 겹치지 않는 것 확인했습니다. 스톨 감지(handleClose(0))와 reconnectNow 경로도 같은 카운트를 타서 빠지는 곳이 없습니다. LGTM

@yeondon125
yeondon125 merged commit bb860b7 into main Nov 12, 2026
3 checks passed

This branch was successfully deployed

1 active deployment
Preview — 057e7613 Deployed Nov 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[edit] 공동편집 연결이 계속 실패해도 '연결 중…'만 보이고 이유를 알려 주지 않는다

2 participants