Skip to content

피드 자유 기록 카드 — 자유 기록만 있는 세션이 피드에서 빈 줄로 보이던 문제 (2026-08-22)

  • 기간: 2026-08-22 (오너 보고 → 같은 날 수리)
  • 랜딩: PR 1건 — 마이그레이션 20260821440000(get_profile_feed_v2_enginenotes[]·notes_truncated 추가, 추가 전용) + 클라이언트(어댑터·매퍼·모바일 FdPost·데스크톱 DkH3SessionPost·CSS 2줄) + pgTAP 1파일·계약/매퍼/렌더 테스트 4건. Production 적용은 마이그레이션 1건, 클라이언트는 main 배포로 반영
  • 정본: docs/data/app-screen-rpc-contract.md(+ docs/ko/…) get_profile_feed 응답 형태·items[].notes 행 — 카드는 자유 기록 항목을 싣는다; docs/contracts/feed-props.md posts[].notes; tests/react/screenRpcContracts.test.mjs 피드 픽스처(notes 포함) · pgTAP profile_feed_note_entries.test.sql

1. 증상

자유 기록(entry_kind = 'note', 예: WOD 설명)만 적고 저장한 세션이 피드에서 첨부 카드 없이 "운동 세션 · 0kg · 0세트 · 0종목" 한 줄로만 보였다. 사용자가 적은 제목·내용이 피드 어디에도 없었다.

2. 원인

get_profile_feed의 카드는 get_session_presentation_mains_json이 만든 mains만 싣는데, 이 함수는 main/top 세트를 가진 session_exercises만 고른다. 자유 기록 항목은 세트가 없으니 항상 빠지고, 클라이언트 (FdPost·DkH3SessionPost)는 mains가 비면 첨부 카드를 열지 않고 KPI 한 줄(볼륨·세트·종목 모두 0)만 그렸다.

3. 수리

  • 서버(추가 전용): get_profile_feed_v2_engine을 베이스라인 정의 그대로 다시 내면서 세션마다 lateral 하나를 보탰다 — notes: [{ id, title(120 B), note(240 B), presentation_truncated }](entry position asc, 최대 4개) + notes_truncated(5번째가 있으면 true). contract_version은 3 유지: 키가 추가 전용이고 클라이언트 어댑터는 있을 때만 검증하므로 구 번들도 그대로 읽는다. get_session_presentation_mains_json· get_session_search는 무변경.
  • 클라이언트: 어댑터가 notes/notes_truncated를 있을 때만 검증(4개 상한·바이트 상한·절단 불변식) → buildProfileFeedItems·lgDesktopProfileFeed·buildMobileFeedPostsnotes를 나른다 → 모바일 FdPost· 데스크톱 DkH3SessionPostmains가 없어도 notes가 있으면 첨부 카드를 열고, 종목 행 뒤에 레터를 이어 "제목(없으면 '자유 기록') + 메모 앞 2줄" 행을 그린다. 세트 KPI 토큰은 main 카드가 있을 때만 단다(자유 기록만 있는 세션에 "0세트"를 붙이지 않음). 볼륨 토큰은 원래부터 load·reps 프로필일 때만.
  • 테스트: pgTAP(자유 기록만 있는 세션 → notes 1개·mains []; 5개 → 4개+notes_truncated; 없음 → []), 어댑터(있을 때 검증·없을 때 통과·상한·절단 불변식·바이트), 매퍼(데스크톱·모바일), 렌더(피드·홈이 제목과 앞 2줄을 그리고 0kg/0세트/0종목을 내지 않음).

4. 배포 순서

클라이언트는 notes가 없어도 동작하고 서버는 구 번들이 모르는 키만 더하므로 순서 제약이 없다. 기록은 "main 머지 → Vercel 배포 → supabase db push" 순.