Skip to content

화이트보드 완료 인원·날짜 이동 수리 — 사람 단위 집계와 스켈레톤 전환 (2026-08-27)

  • 기간: 2026-08-27 (1세션, 오너 보고 원문: "완료한사람 2명인데 3명이 완료했다고 뜸 … 날짜 움직였는데 완료 메세지는 그대로 … 날짜이동이 너무 느려" + 추가 지시 "로딩 스켈레톤 적용, 넘기면 빨리빨리, 데이터는 도착하는대로 표시")
  • 랜딩: PR #876 (Phase 1~3, c83acd8a) — Vercel Production success 실측(GroupScreen-NVceIi6C.js에 스켈레톤 마커 "화이트보드 불러오는 중"·gb-skel 각 1회)
  • 설계서: 없음 — 계획서 = 이슈 #875(예상 효과·개선사항 표 포함, 오너 승인 08-27)
  • 정본: src/react/controllers/groupStore.ts(loadBoard 소거→독립 도착·openBoard swr·날짜 캐시) · src/react/ui/mobile/screens/GroupScreen.tsx(gpDoneByMember·loading 스켈레톤) · docs/contracts/group-props.md §4
  • 도구: Management API read-only 프로브(원인 실측 — Production 세션 원자료)
  • 게이트: tests/react/groupBoardDateNav.test.mjs(신설 6) · groupScreens.test.mjs 사람 단위·스켈레톤 앵커 · profileHandle.test.mjs 서명 캐시 앵커
  • 버그리포트: BUG-033
  • 계약: group-props.md §4 개정(완료 행 = 사람 단위 표시·loading 스켈레톤) · src/react/ui/CHANGE-NOTES.md 재싱크 규칙 등재

Phase 현황

Phase내용상태
Phase 1완료 행·카운트 사람 단위(gpDoneByMember, 오너 D1=a)✅ PR #876
Phase 2날짜 전환 즉시 스켈레톤 + RPC 독립 도착 표시 + 재진입 swr(오너 D2=a)✅ PR #876
Phase 3아바타 서명 캐시 + (그룹,날짜) 보드 캐시✅ PR #876
Phase 4서버 병합 RPC(contract v3)⬜ 보류 — Phase 3까지로 부족할 때만

1. 배경

그룹 v2(#847)가 보드 아래 "완료한 멤버" 행과 완료 인원 배지를 신설했다. 완료 행의 소스는 get_group_board_day_sessions_v1 — 그날 그룹 멤버들의 완료 세션 목록이다. 날짜 이동은 v1(#822)부터 매번 RPC 2개를 새로 부르는 구조였다.

2. 문제 제기

오너 보고 3건(08-27). ① 완료 2명이 3명으로, 그것도 운동 한참 전 시각과 함께 표시. ② 날짜를 옮겨도 하단 완료 행이 그대로. ③ 이동이 너무 느림. Production 프로브로 ①을 실측 확정: 마블오후반 08-26에 acetuna가 완료 세션 2개(아침 러닝 08:30 완료 + 오후 스트렝스)·chewie_park 1개 = 3행 2명 — 행·배지가 세션 단위였다. ②는 코드로 2경로 확정: 전환 중 이전 날짜 데이터 유지(로딩 표시 전무·실패 시 무기한) + 재진입 시 재로드 생략. ③은 이동 1회당 직렬 2홉(RPC 2 병렬 + 아바타 재서명 최대 2회)·캐시 전무.

3. 해결 방안

원칙 (오너 결정, 2026-08-27)

  • D1 = a안: 완료 행·카운트는 사람 단위 1줄, 시각은 그 멤버의 최신 완료 세션.
  • D2 = a안 + 강화: 전환 즉시 스켈레톤, 보드·완료 세션 RPC는 도착하는 대로 개별 표시.

접근

대안판단
표시층 dedupe(gpDoneByMember)채택 — 서버 계약 불변, 종목 기록 뷰는 원본 전 세션 유지
서버 RPC 멤버 단위 개편기각 — 종목 기록 뷰 데이터 소실·계약 개정 비용
이전 데이터 유지 + 로딩 바기각 — 날짜 불일치 잔존
캐시 2층(서명 경로→URL·(그룹,날짜) 보드 swr)채택 — 왕복 절감, 정합은 백그라운드 재검증
서버 병합 RPC(contract v3)보류(Phase 4)

4. 적용한 내용

Phase 1 — 사람 단위 (#876)

gpDoneByMember(GroupScreen export): member.id당 최신 completedAt 1건, completedAt 오름차순. 완료 행·배지가 이걸 쓰고, exerciseRecords 집계는 원본 daySessions 전 세션 그대로. 계약문 §4에 "표시는 사람 단위" 명시.

Phase 2 — 전환 즉시 반응 (#876)

  • loadBoard: 전환 즉시 보드·완료 행·댓글 소거(달력 워시 마크는 같은 그룹이면 유지) → loading 상태. 같은 그룹·날짜가 ready면 소거 없이 재검증(swr).
  • 보드 RPC·완료 세션 RPC를 Promise.all에서 분리 — 각자 도착 즉시 set(완료 세션이 먼저 오면 로딩 중에도 먼저 그림). 늦은 응답은 단조 토큰으로 폐기.
  • openBoard = 항상 오늘로 재검증. 부수 행동 변경: 과거 날짜를 보다 나갔다 재진입하면 오늘 보드로 복귀.
  • 화면: loading prop 신설 — 보드 자리 gb-skel 3행 셔머 + 완료 행 fd-cmrow 셔머 1줄(기존 primitives 문법 재사용), 빈 상태 문구("화이트보드가 없어요")는 로드 완료 후에만, 날짜 내비는 스켈레톤 중에도 연타 가능.

Phase 3 — 캐시 (#876)

  • signProfileImagePaths 모듈 캐시: 경로→URL, 유효 7일 중 6일 재사용, 실패 경로 미캐시(다음 로드 재시도). 사진 교체는 avatar_path 자체가 바뀌므로 경로 키가 낡은 사진을 서빙할 일 없음. 피드·친구·그룹 공용 효과.
  • groupStore (그룹,날짜) 캐시 30건: 재방문 = 캐시 즉시 ready + 백그라운드 재검증 교체. 보드 저장 = 키 무효화, 댓글·좋아요 = 캐시 동기 갱신, 오너 전환 = clear.

주요 결정과 그 근거

  • dedupe는 서버가 아니라 표시층 — 같은 payload를 종목 기록 뷰(전 세션 필요)와 완료 행(사람 단위)이 나눠 쓰므로, 접는 쪽이 소비자다.
  • 재진입은 무조건 오늘 — "운동하러 가기" 진입 의미와 일치, 낡은 날짜 고정 구멍을 재검증 생략 케이스 자체를 없애 봉쇄.

작업 중 드러난 것

  • 화면 카운트 결함은 실데이터의 중복 케이스로만 드러난다 — 기존 테스트 픽스처가 전부 1인 1세션이라 세션/사람 구분 결함이 통과해 왔다. 신규 앵커는 실사례(3세션 2명)를 그대로 고정.
  • sessions에 완료 시각 컬럼이 없다 — RPC completed_at = created_at 근사(라이브 플로우는 저장 = 완료라 근사 성립, 수정 재저장·인입에서 어긋날 수 있음). 이번 범위 밖, 필요 시 별도 트랙.
  • Production 프로브(Management API read-only)가 "3명"의 정체를 쿼리 한 번으로 확정 — 증상 재현 대신 원자료 실측이 빨랐다.

5. 적용 결과

항목
마블오후반 08-26 완료 표시3명(행 3줄, 아침 시각 노출)2명(사람 단위, 최신 시각) — 테스트 고정
전환 직후 이전 날짜 완료 행 노출응답까지 수 초(실패 시 무기한)0초(즉시 스켈레톤) — 스토어 스냅샷 테스트 고정
재진입 최신성재로드 생략(낡은 데이터 고정)항상 재검증(swr)
이동 1회 직렬 왕복2홉·요청 4개1홉(서명 캐시 적중)·재방문 날짜 0홉(캐시 즉시 표시)
완료 세션 표시 시점보드 응답까지 동반 대기도착 즉시 개별 표시
  • 미검증: 오너 실기기 체감(완료 3→2·이동 속도).

6. 이번 개선으로 향상된 것

  • 완료 인원이 사람 수와 일치 — 그룹 표면의 신뢰 회복.
  • 날짜 이동이 즉답(스켈레톤) + 도착 순 표시 — 연타 이동 가능, 날짜 불일치 잔상 소멸.
  • 아바타 서명 캐시는 그룹 밖(피드·친구)에도 왕복을 줄이는 구조적 이득.

남은 것

  • 오너 실기기 확인(완료 인원·이동 체감) → 이슈 #875 종결.
  • (보류) Phase 4 서버 병합 RPC — Phase 3까지로 부족할 때만.
  • (범위 밖 관찰) sessions 완료 시각 컬럼 부재 — completed_at 근사가 어긋나는 사례가 보고되면 별도 트랙.