36 KiB
리포트 컴포넌트화 (Phase 3 확장) — 실행 계획서
작성일: 2026-03-10 | 최종 업데이트: 2026-03-10 (v5) 목표: 리포트 디자이너에서 만든 리포트를 화면관리의 V2 컴포넌트(
v2-report-viewer)에서 reportId를 직접 지정하여 배치하고, 인라인 또는 모달로 렌더링하는 것.
참조 문서
| 순서 | 문서 | 경로 | 반영 내용 |
|---|---|---|---|
| 1 | V2 컴포넌트 분석 가이드 | docs/V2_컴포넌트_분석_가이드.md |
파일 구조, v2- 접두사, Definition 네이밍 |
| 2 | V2 컴포넌트 연동 가이드 | docs/V2_컴포넌트_연동_가이드.md |
ScreenContext, V2 이벤트 시스템, formData 공유 |
| 3 | 화면개발 표준 가이드 | docs/screen-implementation-guide/화면개발_표준_가이드.md |
V2 컴포넌트 목록, screen_layouts_v2 저장 구조 |
| 4 | CLAUDE.md | CLAUDE.md |
네이밍 규칙, 표준 파일 구조, 코딩 규칙 |
완성 후 동작 플로우
플로우 A: 관리자가 화면에 리포트를 배치하는 과정 (설정 시점)
[1] 관리자가 화면 디자이너에 접속
URL: /admin/screenMng/screenMngList
→ 화면 목록에서 "견적 관리" 화면을 더블클릭
→ 화면 디자이너 진입 (URL 변화 없음, ScreenDesigner.tsx 렌더링)
[2] 좌측 컴포넌트 패널에서 "리포트 뷰어" (v2-report-viewer)를 캔버스에 드래그&드롭
┌──────────────────────────────────────────────────────────────────┐
│ [좌측 패널] [캔버스] [우측 패널] │
│ │
│ ▸ 입력 ┌────────────────────────┐ │
│ ▸ 버튼 │ v2-input: 주문번호 │ │
│ ▸ 테이블 ├────────────────────────┤ │
│ ▸ 표시 │ v2-table-list │ │
│ ├ 리포트 뷰어 ◀ │ (주문 목록 테이블) │ │
│ ├ 텍스트 ├────────────────────────┤ │
│ └ ... │ ┌──────────────────┐ │ │
│ │ │ 📄 리포트 (뷰어) │ │ ← 방금 배치 │
│ │ │ │ │ │
│ │ └──────────────────┘ │ │
│ └────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
[3] 배치한 리포트 뷰어 컴포넌트를 클릭 → 우측 설정 패널이 열림
┌─────────────────────────────────────────────┐
│ 리포트 뷰어 설정 │
│ │
│ 컴포넌트 제목 │
│ [견적서 미리보기] ___________________ │
│ │
│ 리포트 선택 │
│ ┌─────────────────────────────────────┐ │
│ │ 리포트를 선택해주세요 [선택] │ │
│ └─────────────────────────────────────┘ │
│ │
│ 표시 모드 │
│ [모달 (클릭 시 팝업) ▼] │
│ │
│ 파라미터 매핑 │
│ 매핑 없음 — 폼 데이터가 자동 주입됩니다 │
│ [+ 추가] │
└─────────────────────────────────────────────┘
[4] "선택" 버튼 클릭 → 리포트 선택 모달이 열림
┌──────────────────────────────────────────────────────┐
│ 리포트 선택 [×] │
│ ┌──────────────────────────────────────────────┐ │
│ │ 🔍 견적... │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ ┌──────┬──────────────┬──────────┬─────────────┐ │
│ │ ID │ 리포트명 │ 유형 │ 사용여부 │ │
│ ├──────┼──────────────┼──────────┼─────────────┤ │
│ │ 12 │ ▶ 견적서 ◀ │ 견적 │ Y │ ← 클릭!
│ │ 15 │ 발주서 │ 발주 │ Y │ │
│ │ 18 │ 검수 보고서 │ 검사 │ Y │ │
│ └──────┴──────────────┴──────────┴─────────────┘ │
│ │
│ * 리포트 관리에서 만든 리포트 목록이 표시됩니다 │
│ * 리포트 관리 URL: /admin/screenMng/reportList │
└──────────────────────────────────────────────────────┘
[5] "견적서" 행 클릭 → 모달 닫히고 설정 패널에 선택 결과 표시
┌─────────────────────────────────────────────┐
│ 리포트 뷰어 설정 │
│ │
│ 컴포넌트 제목 │
│ [견적서 미리보기] ___________________ │
│ │
│ 리포트 선택 │
│ ┌─────────────────────────────────────┐ │
│ │ 📄 견적서 [변경] [×] │ │
│ │ ID: 12 | 유형: 견적 │ │
│ └─────────────────────────────────────┘ │
│ │
│ 표시 모드 │
│ [인라인 (화면 내 직접 표시) ▼] │ ← "인라인"으로 변경
│ │
│ 파라미터 매핑 │
│ ┌─────────────────────────────────────┐ │
│ │ $1 ← order_no [×] │ │ ← 매핑 추가
│ │ [+ 추가] │ │
│ └─────────────────────────────────────┘ │
│ 쿼리의 $1에 폼 데이터의 order_no 값 전달 │
└─────────────────────────────────────────────┘
[6] 화면 저장 → screen_layouts_v2 테이블에 JSONB로 저장됨
저장되는 componentConfig:
{
"title": "견적서 미리보기",
"reportId": 12,
"reportName": "견적서",
"displayMode": "inline",
"paramMappings": [{ "param": "$1", "formField": "order_no" }]
}
플로우 B: 사용자가 화면에서 리포트를 보는 과정 (실행 시점 — 인라인 모드)
[1] 사용자가 "견적 관리" 화면에 접속
URL: /screens/45?menuObjid=789
→ DynamicComponentRenderer가 screen_layouts_v2에서 레이아웃 로드
→ v2-report-viewer 컴포넌트 렌더링 시작
[2] 화면 초기 상태 (formData에 order_no 없음)
┌──────────────────────────────────────────────────────────────┐
│ 견적 관리 │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ 주문번호: [_______________] [조회] │ │
│ ├────────────────────────────────────────────────────────┤ │
│ │ 주문 목록 테이블 │ │
│ │ ┌──────┬──────────┬──────────┬──────────┐ │ │
│ │ │ 번호 │ 주문번호 │ 고객명 │ 금액 │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ (데이터 없음) │ │ │
│ │ └──────┴──────────┴──────────┴──────────┘ │ │
│ ├────────────────────────────────────────────────────────┤ │
│ │ 견적서 미리보기 [↻ 새로고침] [↗ 전체보기] │ │
│ │ ┌──────────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ │ 파라미터가 없어 리포트를 표시할 수 없습니다 │ │ │
│ │ │ │ │ │
│ │ └──────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
[3] 사용자가 주문번호 입력 후 조회 → 테이블에 데이터 표시 → 행 선택
→ formData가 변경됨: { order_no: "ORD-2026-001", ... }
→ v2-report-viewer가 ScreenContext.formData 변경 감지
→ buildContextParams: { "$1": "ORD-2026-001" }
→ useReportExecution 훅이 즉시 쿼리 실행
→ reportApi.executeQuery(12, queryId, { "$1": "ORD-2026-001" })
[4] 리포트가 인라인으로 렌더링됨 (축소 표시)
┌──────────────────────────────────────────────────────────────┐
│ 견적 관리 │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ 주문번호: [ORD-2026-001] [조회] │ │
│ ├────────────────────────────────────────────────────────┤ │
│ │ 주문 목록 테이블 │ │
│ │ ┌──────┬──────────────┬──────────┬──────────┐ │ │
│ │ │ 번호 │ 주문번호 │ 고객명 │ 금액 │ │ │
│ │ │ 1 │ ORD-2026-001 │ (주)가나 │ 1,500만 │ ← 선택 │ │
│ │ │ 2 │ ORD-2026-002 │ (주)다라 │ 800만 │ │ │
│ │ └──────┴──────────────┴──────────┴──────────┘ │ │
│ ├────────────────────────────────────────────────────────┤ │
│ │ 견적서 미리보기 [↻ 새로고침] [↗ 전체보기] │ │
│ │ ┌──────────────────────────────────────────────────┐ │ │
│ │ │ ╔══════════════════════════════════════════╗ │ │ │
│ │ │ ║ 견 적 서 ║ │ │ │
│ │ │ ║──────────────────────────────────────────║ │ │ │
│ │ │ ║ 수신: (주)가나 ║ │ │ │
│ │ │ ║ 주문번호: ORD-2026-001 ║ │ │ │
│ │ │ ║ ┌────┬──────────┬────┬──────────┐ ║ │ │ │
│ │ │ ║ │ No │ 품목명 │ 수량│ 단가 │ ║ │ │ │
│ │ │ ║ │ 1 │ 부품A │ 100│ 50,000 │ ║ │ │ │
│ │ │ ║ │ 2 │ 부품B │ 50 │ 100,000 │ ║ │ │ │
│ │ │ ║ └────┴──────────┴────┴──────────┘ ║ │ │ │
│ │ │ ║ 합계: 15,000,000원 ║ │ │ │
│ │ │ ╚══════════════════════════════════════════╝ │ │ │
│ │ └──────────────────────────────────────────────────┘ │ │
│ │ * 컴포넌트 크기에 맞게 축소(scale) 렌더링 │ │
│ │ * 클릭하면 전체 보기 모달 열림 │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
[5] "전체보기" 버튼 또는 인라인 리포트 클릭 → 모달로 전체 크기 표시
┌──────────────────────────────────────────────────────────────┐
│ 견적서 — ORD-2026-001 [PDF] [×] │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ (A4 크기 리포트 전체 표시) │ │
│ │ ReportListPreviewModal 사용 │ │
│ │ (기존 모달 그대로) │ │
│ │ │ │
│ └──────────────────────────────────────────────────────┘ │
│ 페이지: [< 1 / 1 >] │
└──────────────────────────────────────────────────────────────┘
플로우 C: 모달 모드로 설정한 경우 (실행 시점 — 모달 모드)
[1] 관리자가 설정 패널에서 displayMode = "모달" 선택 + reportId = 12 (견적서) 설정
[2] 사용자가 화면 접속 시 → 리포트 이름 + "보기" 버튼만 표시
┌────────────────────────────────────────────────────────┐
│ 견적서 미리보기 │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 📄 견적서 [보기] │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────┘
[3] "보기" 버튼 클릭 → ReportListPreviewModal 모달 열림 (기존과 동일)
→ formData의 order_no 값이 $1 파라미터로 자동 바인딩
→ 모달 안에서 리포트 렌더링 + PDF 다운로드 가능
플로우 D: reportId 미지정 시 (하위 호환 — 기존 menuObjid 기반)
[1] 관리자가 설정 패널에서 reportId를 선택하지 않음 (또는 선택 해제)
[2] 사용자가 /screens/45?menuObjid=789 로 접속
→ menuObjid=789에 연결된 리포트 목록 자동 조회
→ 기존과 동일하게 리포트 버튼 목록 표시
┌────────────────────────────────────────────────────────┐
│ 리포트 │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 📄 견적서 │ │
│ │ 📄 발주서 │ │
│ │ 📄 거래명세서 │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────┘
[3] 버튼 클릭 → 해당 리포트의 ReportListPreviewModal 모달 열림
(현재 동작과 100% 동일)
데이터 흐름 요약
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────────┐
│ 화면 디자이너 │ │ 화면 뷰어 │ │ 백엔드 API │
│ (설정 시점) │ │ (실행 시점) │ │ │
├─────────────────┤ ├──────────────────┤ ├─────────────────────┤
│ │ │ │ │ │
│ ConfigPanel │ │ ReportViewer │ │ GET /admin/reports │
│ ↓ reportId │ 저장 │ Component │ │ → 리포트 목록 │
│ ↓ displayMode │ ──→ │ ↓ │ │ │
│ ↓ paramMappings │ ↓ config 로드 │ │ GET /admin/reports │
│ │ │ ↓ │ │ /:reportId │
│ ReportSelect │ │ reportId 있음? │ │ → 리포트 상세 │
│ Modal │ │ ├─ Yes │ │ │
│ ↓ │ │ │ displayMode?│ │ POST /admin/reports │
│ reportApi │ │ │ ├─ inline │ │ /:reportId/queries│
│ .getReports() │ │ │ │ → Inline │ │ /:queryId/execute │
│ │ │ │ │ Renderer │ ──→ │ → 쿼리 실행 │
│ │ │ │ └─ modal │ │ params: { $1: ... }│
│ │ │ │ → 버튼 │ │ │
│ │ │ │ → 클릭시 │ │ │
│ │ │ │ 모달 │ │ │
│ │ │ │ │ │ │
│ │ │ └─ No (fallback) │ GET /admin/reports │
│ │ │ → menuObjid │ │ /by-menu/:objid │
│ │ │ 기반 목록 │ │ → 메뉴별 리포트 │
│ │ │ │ │ │
│ │ │ formData 변경 │ │ │
│ │ │ → 즉시 재실행 │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────────┘
관련 URL 정리
| 화면 | URL | 역할 |
|---|---|---|
| 화면 목록 (관리자) | /admin/screenMng/screenMngList |
화면 목록 + 더블클릭 시 디자이너 진입 |
| 화면 디자이너 (관리자) | (URL 변화 없음, 같은 페이지 내 ScreenDesigner 렌더링) | 컴포넌트 배치 + 설정 |
| 리포트 관리 (관리자) | /admin/screenMng/reportList |
리포트 CRUD + 디자이너 진입 |
| 리포트 디자이너 (관리자) | /admin/screenMng/reportList/designer/{reportId} |
SQL + 레이아웃 + 바인딩 설정 |
| 화면 뷰어 (사용자) | /screens/{screenId}?menuObjid={menuObjid} |
실제 화면 사용 |
| POP 화면 뷰어 (사용자) | /pop/screens/{screenId} |
POP 화면 사용 |
확정된 결정 사항
| # | 결정 항목 | 확정 내용 |
|---|---|---|
| 1 | 리포트 선택 방식 | reportId 직접 지정 — 설정 패널에서 "리포트 선택" 버튼 → 리포트 목록 모달 → 선택하면 reportId 저장. menuObjid 기반은 fallback으로 유지 |
| 2 | 표시 모드 | 모달 + 인라인 선택 가능 — 설정에서 displayMode 선택 (modal / inline) |
| 3 | 파라미터 바인딩 | 단순 키만 — formData['order_no'] 같은 1단계 키만 지원 (현재 방식 유지) |
| 4 | 자동 갱신 | 즉시 자동 갱신 — formData 변경 시 즉시 리포트 재실행 |
| 5 | 버그 수정 범위 | screens + pop/screens 모두 수정 — menuObjid 미전달 버그 |
1. 현재 코드 현황
v2-report-viewer 현재 파일 구조
frontend/lib/registry/components/v2-report-viewer/
├── index.ts # V2ReportViewerDefinition (28줄)
├── types.ts # ReportViewerConfig, ReportParamMapping (18줄)
├── ReportViewerComponent.tsx # 메인 컴포넌트 (133줄)
├── ReportViewerConfigPanel.tsx # 설정 패널 (115줄)
└── ReportViewerRenderer.tsx # ComponentRegistry 등록 (12줄)
현재 문제점
| 문제 | 원인 |
|---|---|
| reportId를 직접 지정할 수 없음 | 설정 패널에 리포트 선택 UI 없음 |
| menuObjid 없으면 아무것도 안 보임 | reportId fallback 없음 |
| 인라인 렌더링 불가 | 모달만 지원 |
| formData 변경 시 자동 갱신 없음 | 감지 로직 없음 |
/screens/ 페이지에서 menuObjid 전달 안 됨 |
ScreenContextProvider에 props 미전달 |
2. 구현 단계 (7 Steps)
Step 1: menuObjid 미전달 버그 수정 [난이도: 낮음]
수정 파일 (2개):
| 파일 | 현재 | 변경 |
|---|---|---|
frontend/app/(main)/screens/[screenId]/page.tsx |
<ScreenContextProvider> (props 없음, 1377행) |
Wrapper에서 useSearchParams로 menuObjid 파싱 후 전달 |
frontend/app/(pop)/pop/screens/[screenId]/page.tsx |
<ScreenContextProvider> (props 없음, 348행) |
동일 |
검증:
/screens/{screenId}?menuObjid=123접속 →screenContext.menuObjid === 123확인
Step 2: ReportViewerConfig 타입 확장 [난이도: 낮음]
수정 파일: frontend/lib/registry/components/v2-report-viewer/types.ts
export interface ReportViewerConfig extends ComponentConfig {
title?: string;
paramMappings?: ReportParamMapping[];
reportId?: number; // 리포트 목록 모달에서 선택한 리포트 ID
reportName?: string; // 선택한 리포트명 (설정 패널 표시용)
displayMode?: "modal" | "inline"; // 기본: "modal"
}
Step 3: ConfigPanel에 리포트 선택 UI 추가 [난이도: 중간]
수정 파일: frontend/lib/registry/components/v2-report-viewer/ReportViewerConfigPanel.tsx
추가되는 UI 섹션:
- 리포트 선택 영역 (선택 버튼 → 리포트 목록 모달 → 선택 결과 표시 + 해제 버튼)
- 표시 모드 Select (모달 / 인라인)
리포트 선택 모달: reportApi.getReports({ limit: 100, useYn: 'Y' }) → 검색 + 테이블 → 행 클릭 시 선택 완료.
Step 4: ReportInlineRenderer + useReportExecution 추출 [난이도: 높음]
신규 파일 (2개):
| 파일 | 역할 | 위치 근거 |
|---|---|---|
frontend/hooks/useReportExecution.ts |
리포트 로드 + 쿼리 실행 공용 훅 (~120줄) | CLAUDE.md 네이밍 규칙: 훅은 frontend/hooks/에 배치. ReportListPreviewModal과 ReportInlineRenderer 양쪽에서 공유하므로 특정 컴포넌트 폴더가 아닌 공용 위치가 적합 |
frontend/components/report/ReportInlineRenderer.tsx |
모달 없이 인라인 렌더링 (~200줄) | ReportListPreviewModal과 동일 레벨에 배치. v2-report-viewer 전용이 아니라 향후 다른 컨텍스트(예: 대시보드 위젯)에서도 재사용 가능한 범용 렌더러이므로 components/report/가 적합 |
useReportExecution: ReportListPreviewModal에서 리포트 로드 + 쿼리 실행 로직을 추출한 공용 훅.
ReportInlineRenderer: useReportExecution 훅 사용 + ResizeObserver로 scale 축소 렌더링 + 첫 페이지만 표시.
Step 5: ReportViewerComponent에 reportId 직접 지정 + displayMode 분기 [난이도: 중간]
수정 파일: frontend/lib/registry/components/v2-report-viewer/ReportViewerComponent.tsx
렌더링 분기:
config.reportId 있음:
├─ displayMode === "inline" → ReportInlineRenderer + 헤더(제목, 새로고침, 전체보기)
└─ displayMode === "modal" → 리포트명 + "보기" 버튼 → 클릭 시 모달
config.reportId 없음 (fallback):
→ menuObjid 기반 리포트 목록 (기존 동작 100% 유지)
Step 6: formData 변경 시 즉시 자동 갱신 [난이도: 중간]
수정 파일: ReportViewerComponent.tsx
ScreenContext.formData 변경 감지 → contextParams 재계산 → refreshKey 증가 → ReportInlineRenderer에 전달하여 즉시 재실행.
Step 7: 통합 테스트 + 가이드 문서 업데이트 [난이도: 낮음]
검증 시나리오: 플로우 A~D 전체 검증 + npx tsc --noEmit 오류 없음.
가이드 문서 업데이트:
docs/V2_컴포넌트_분석_가이드.md— V2 컴포넌트 목록에v2-report-viewer추가 (18개 → 19개)docs/V2_컴포넌트_연동_가이드.md— 6.1 연동 능력 매트릭스에v2-report-viewer행 추가docs/screen-implementation-guide/화면개발_표준_가이드.md— V2 컴포넌트 목록에v2-report-viewer추가 (23개 → 24개)
3. 파일 변경 요약
수정 파일 (5개)
| 파일 | Step | 핵심 변경 |
|---|---|---|
frontend/app/(main)/screens/[screenId]/page.tsx |
1 | ScreenContextProvider에 menuObjid 전달 |
frontend/app/(pop)/pop/screens/[screenId]/page.tsx |
1 | 동일 |
frontend/lib/registry/components/v2-report-viewer/types.ts |
2 | reportId, reportName, displayMode 필드 추가 |
frontend/lib/registry/components/v2-report-viewer/ReportViewerConfigPanel.tsx |
3 | 리포트 선택 모달 + displayMode Select |
frontend/lib/registry/components/v2-report-viewer/ReportViewerComponent.tsx |
5,6 | reportId 분기 + displayMode 분기 + 자동 갱신 |
신규 파일 (2개)
| 파일 | Step | 역할 |
|---|---|---|
frontend/hooks/useReportExecution.ts |
4 | 리포트 로드 + 쿼리 실행 공용 훅 |
frontend/components/report/ReportInlineRenderer.tsx |
4 | 모달 없이 인라인 리포트 렌더링 |
수정 대상 (리팩토링, 선택적)
| 파일 | Step | 변경 |
|---|---|---|
frontend/components/report/ReportListPreviewModal.tsx |
4 | 내부 로드/실행 로직을 useReportExecution으로 교체 (기능 변경 없음) |
가이드 문서 업데이트 (3개)
| 파일 | Step | 변경 |
|---|---|---|
docs/V2_컴포넌트_분석_가이드.md |
7 | V2 컴포넌트 목록에 v2-report-viewer 추가 |
docs/V2_컴포넌트_연동_가이드.md |
7 | 연동 능력 매트릭스에 v2-report-viewer 행 추가 |
docs/screen-implementation-guide/화면개발_표준_가이드.md |
7 | V2 컴포넌트 목록에 v2-report-viewer 추가 |
4. 구현 순서 및 의존성
Step 1 menuObjid 버그 수정 ─────────────────── (독립)
↓
Step 2 types.ts 확장 ───────────────────────── (Step 3, 5의 기반)
↓
Step 3 ConfigPanel 리포트 선택 UI ──────────── (Step 2 의존)
↓
Step 4 useReportExecution + ReportInlineRenderer (가장 큰 작업)
↓
Step 5 ReportViewerComponent 분기 렌더링 ───── (Step 2, 4 의존)
↓
Step 6 즉시 자동 갱신 ──────────────────────── (Step 5 의존)
↓
Step 7 통합 테스트 + 가이드 문서 업데이트
병렬 가능:
- Step 1 + Step 2: 동시 진행 가능
- Step 3 + Step 4: Step 2 완료 후 동시 진행 가능
5. V2 이벤트 시스템과의 관계
V2_컴포넌트_연동_가이드.md에서 정의한 V2 표준 이벤트 시스템(V2_EVENTS, dispatchV2Event, subscribeV2Event)과의 관계를 정리합니다.
현재 v2-report-viewer가 사용하지 않는 이유
| V2 이벤트 | 사용 여부 | 이유 |
|---|---|---|
tableListDataChange |
구독 안 함 | 리포트 뷰어는 테이블 데이터 변경이 아닌 ScreenContext.formData를 통해 파라미터를 받음 |
beforeFormSave / afterFormSave |
구독 안 함 | 리포트 뷰어는 데이터를 저장하지 않음 (읽기 전용 표시 컴포넌트) |
refreshTable |
구독 안 함 | 리포트 갱신은 refreshKey prop으로 처리. 테이블 갱신 이벤트와는 무관 |
componentDataTransfer |
구독 안 함 | 리포트 뷰어는 DataReceivable이 아님 (데이터를 수신하여 편집하는 컴포넌트가 아님) |
formData 공유 방식
v2-report-viewer는 ScreenContext의 formData를 통해 다른 컴포넌트와 통신합니다:
v2-input (order_no 입력)
→ ScreenContext.formData 업데이트
→ v2-report-viewer가 formData 변경 감지
→ buildContextParams로 쿼리 파라미터 생성
→ useReportExecution으로 쿼리 실행
이 방식은 V2_컴포넌트_연동_가이드.md 4.3절 ScreenContext의 formData 공유 패턴과 일치합니다.
향후 확장 시 이벤트 도입 가능성
리포트 실행 완료 후 다른 컴포넌트에 알림이 필요한 경우(예: 리포트 로드 완료 시 집계 위젯 갱신), V2 이벤트를 추가할 수 있습니다. 현재 Phase에서는 불필요합니다.
6. 충돌 사전 검사 대상
구현 시작 전 아래 이름들이 현재 코드베이스에 0건인지 Grep 확인 필수:
ReportInlineRenderer, useReportExecution,
ReportSelectModal, displayMode (v2-report-viewer 내),
reportName (v2-report-viewer/types.ts 내)
7. 주의사항
- 하위 호환 필수: 모든 신규 필드는 optional.
reportId없으면 기존 menuObjid 기반 동작 그대로 유지. - reportId 타입:
ReportMaster.report_id는string이지만 실제 값은 숫자 문자열. API 호출 시String(reportId)로 변환. - 멀티테넌시:
reportApi.getReports()호출 시 백엔드에서 자동으로 company_code 필터링됨. - 디자인 모드 보호:
isDesignMode일 때 API 호출, 자동 갱신 모두 스킵. - ReportListPreviewModal 수정 최소화: 기존 모달은 그대로 유지. 공통 로직만 훅으로 추출.
- 인라인 렌더링 스케일:
ResizeObserver로 컨테이너 크기 감지 →transform: scale(containerWidth / canvasWidth). - V2 컴포넌트 규칙 준수:
v2-접두사,V2ReportViewerDefinition네이밍,screen_layouts_v2JSONB 저장. - 각 Step 완료 시 필수:
cd frontend && npx tsc --noEmit
8. 핵심 원칙
| 역할 | 담당 |
|---|---|
| SQL 작성, 컴포넌트 레이아웃, queryId+field 연결, 숫자 포맷/합계 | 리포트 디자이너 (기존, 수정 없음) |
| 어떤 리포트를 보여줄지 (reportId), 언제 실행할지 (자동 갱신), 어디에 표시할지 (displayMode) | 화면관리 v2-report-viewer (이번 구현) |
리포트 디자이너의 코드는 이번 작업에서 수정하지 않는다.
9. 연동 능력 매트릭스 (Step 7에서 가이드 문서에 추가할 내용)
| 컴포넌트 | 이벤트 발행 | 이벤트 구독 | DataProvider | DataReceiver | Context 사용 |
|---|---|---|---|---|---|
v2-report-viewer |
- | - | - | - | Screen (formData, menuObjid) |
| 소스 컴포넌트 | 타겟 컴포넌트 | 연동 방식 | 용도 |
|---|---|---|---|
v2-input / v2-table-list |
v2-report-viewer |
ScreenContext.formData | 파라미터 바인딩 |
v2-report-viewer |
ReportListPreviewModal |
props (report, contextParams) | 전체 보기 모달 |