Skip to content

관리자 미리보기와 유저 레슨 상세 Markdown 렌더링 정책 동기화 필요 #705

@Hyeonjun0527

Description

@Hyeonjun0527

배경

리뷰에서 제기된 내용처럼, 현재 관리자 미리보기와 실제 유저 화면의 Markdown 렌더링 경로가 분리되어 있습니다. 코드 확인 결과 리뷰 방향은 타당합니다.

  • 관리자 레슨 본문 미리보기: MarkdownContent
    • src/components/admin/courses/admin-lesson-management-page-client.tsx:1142
  • 관리자 코스 상세 미리보기: MarkdownContent
    • src/components/admin/courses/admin-course-detail-page-client.tsx:196
  • 유저 레슨 상세/피드 상세: MarkdownContentCore
    • src/app/(class-lesson)/class/[slug]/lesson/[id]/page.tsx:252
    • src/app/(class-lesson)/class/[slug]/lesson/[id]/_components/lesson-builder-feed-detail-modal.tsx:123
    • src/app/(landing)/class/[slug]/(learning)/feed/[id]/page.tsx:371

확인된 문제

두 컴포넌트가 단순 스타일 래퍼만 다른 것이 아니라, 렌더링 정책 일부를 각자 들고 있습니다.

  • MarkdownContent
    • normalizeMarkdownContent()로 입력 정규화
    • shouldRenderMarkdownAsMarkdown()로 HTML/Markdown 분기 보정
    • markdown-sanitizer.tsSANITIZE_OPTIONS, applyPostSanitizeAttributes() 사용
    • HTML 테이블 보정(renderMarkdownTablesInHtml)과 Mermaid 렌더링 처리 포함
    • effect에서 innerHTML 주입 후 code highlight / mermaid render 실행
  • MarkdownContentCore
    • 별도 inline SANITIZE_OPTIONS, applyPostSanitizeAttributes(), 이미지 width clamp 정책 보유
    • isHtmlContent(contentWithEmbeds)만으로 HTML/Markdown 분기
    • Mermaid 처리 없음
    • dangerouslySetInnerHTML로 렌더링
    • 유저 화면용 typography / image constraint 별도 보유

이미 markdown-content-shared.ts, markdown-rendering-utils.ts, youtube-utils.ts처럼 일부 공통 유틸은 존재하지만, 최종 렌더링/정화/후처리 정책은 아직 두 군데에 남아 있어 한쪽 수정이 다른 화면에 반영되지 않을 수 있습니다.

체크리스트

  • 관리자 미리보기와 유저 레슨 상세가 같은 본문 데이터에서 동일한 렌더링 정책을 타는지 확인한다.
  • HTML/Markdown 판별, YouTube embed, 이미지 src/width 복원, 링크 속성, sanitizer 허용 태그/URI 정책을 한 곳에서 관리한다.
  • 표, 코드블록, HTML 예제 코드펜스, TipTap이 만든 paragraph HTML, signed image URL 같은 회귀 케이스를 양쪽 화면 기준으로 검증한다.
  • 의도적으로 달라야 하는 부분은 typography/spacing 같은 presentation variant로만 남긴다.

제안 해결 방향

1안: 공통 렌더링 코어 추출

MarkdownContentMarkdownContentCore가 공통으로 사용할 렌더링 파이프라인을 추출합니다.

예시:

  • renderMarkdownHtml(content, options)
  • sanitizeMarkdownHtml(html, options)
  • applyMarkdownPostSanitizeAttributes(html, originalHtml)
  • MarkdownRenderer + variant="admin-preview" | "lesson-detail"

이때 variant는 폰트 크기, margin, max image size 같은 스타일 차이만 담당하고, HTML/Markdown 판별과 sanitizer/post-processing 정책은 공유하는 것이 좋습니다.

2안: 즉시 통합이 부담되면 parity harness 먼저 추가

전면 통합 전이라도 아래 fixture를 기반으로 양쪽 renderer의 정책 동등성을 검증하는 테스트를 추가합니다.

  • Markdown 이미지: ![alt](...)
  • raw HTML 이미지: <img src="..." width="...">
  • signed image URL / /images/... / blob URL
  • YouTube 단독 링크
  • Markdown table
  • fenced code block 안의 HTML 예제
  • TipTap degraded paragraph HTML: <p>![image.png](...)</p>
  • Mermaid 코드블록: 지원 여부를 명시적으로 결정
  • 빈 문자열 / 공백 문자열

완료 기준

  • 관리자 미리보기와 유저 상세가 공통 렌더링 정책 또는 동등성 테스트를 가진다.
  • 공통으로 맞아야 하는 동작은 한쪽만 수정해도 양쪽에 반영된다.
  • intentional difference는 스타일 variant로 문서화된다.
  • 위 fixture 중 최소 이미지/테이블/코드블록/YouTube/HTML recovery 케이스가 테스트로 고정된다.

기대 효과

관리자 화면에서 정상으로 보였는데 실제 유저 화면에서 이미지, 표, 링크, 코드블록, YouTube embed가 다르게 보이는 회귀를 사전에 막을 수 있습니다.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions