푸터 콘텐츠로 바로가기
IRONPDF 사용하기

IronPDF로 Azure PDF 생성기 생성 (.NET 10 가이드)

티켓 시스템에만 존재하는 사례 기록의 문제점

IronPDF 홈페이지 규제 조사 요청이 도착하거나 고객 분쟁이 법적 문제로 확대되면 첫 번째로 요구되는 것은 전체 통신 기록입니다. 실제로 존재하는 것은 티켓 시스템 로그인이 필요한 웹 UI, 여러 페이지로 나뉜 스레드 및 고객 대면 답장과 섞인 내부 노트입니다. 이 중 어느 것도 규제 기관에 제출하거나 분쟁에서 수락될 수 없습니다.

수동 처리 방법은 느리며 오류가 발생하기 쉽습니다. 지원 관리자는 스레드의 각 페이지를 캡처하여 Word 문서로 컴파일합니다. 에이전트는 메시지를 시간순으로 정렬된 이메일에 복사하고 붙여넣습니다. 개발자는 티켓 API에서 원시 JSON을 내보내고 변호사에게 해석하지 못하는 자료를 제공한다. 장기 사례, 즉 6개월 간의 청구 분쟁, 20번의 메시지 교환이 있는 3명의 에이전트와의 보증 청구는 항목의 순서를 잘못 잡거나 첨부 파일을 잃지 않고 수작업으로 완전히 재구성하기 거의 불가능합니다.

통합 관점은 댓가를 진짜로 만듭니다. 규제 조사에 응답하는 금융 서비스 회사는 모든 고객 통신을 순서대로 시간 표기하며, 불변의 상태로 두어야 합니다. SaaS 회사는 계약 분쟁에서 언제 무엇을 말했는지를 입증해야 합니다. 감사받고 있는 헬스케어 헬프데스크는 시스템 설명 없이 감사자가 읽을 수 있는 형식으로 환자 상호 작용 로그를 포함해야 합니다. GDPR 데이터 주체 접근 요청을 이행하는 전자 상거래 플랫폼은 해당 고객의 모든 지원 대화를 내보내야 합니다. 그들이 생각했던 것만이 아니라.

티켓 시스템의 웹 UI는 아카이브 형식이 아닙니다. 그것은 아카이브 형식이 되어야 합니다.

해결책: 전체 스레드에서 생성된 서식화된 사례 기록

IronPDF를 사용하면 .NET 애플리케이션이 모든 메시지, 내부 노트, 상태 변경 및 타임스탬프를 서식화된 자체 PDF 기록으로 렌더링할 수 있습니다. 애플리케이션은 데이터베이스에서 티켓의 전체 스레드를 조회하고, 명확한 발신자 레이블 및 타임스탬프와 함께 대화를 시간순으로 표시하는 새 HTML 파일 또는 기존 HTML 파일 템플릿을 채우며, ChromePdfRenderer는 PDF를 생성합니다.

결과는 티켓 시스템에 대한 액세스나 데이터 구조에 대한 설명 없이도 변호사, 감사자 또는 고객이 해석할 수 있는 문서로, 인쇄된 대화 기록처럼 읽을 수 있습니다. 스크린샷, 복사 및 붙여넣기, 원시 데이터 덤프가 없습니다. 렌더링은 외부 프로세스 없이 기존 .NET 애플리케이션 내에서 단일 NuGet 패키지로 실행됩니다.

실제 적용 사례

1. 내보내기를 시작하는 트리거

내보내기는 세 가지 방법으로 시작할 수 있습니다. 법적 팀 구성원이 특정 케이스 ID를 참조하여 내부 관리자 도구에서 "사례를 PDF 형식으로 내보내기"를 클릭합니다. 컴플라이언스 워크플로우는 설정된 보유 기간 후에 닫힌 사례를 자동으로 아카이브합니다. 데이터 주체 접근 요청에 따라 특정 고객 계정과 연결된 모든 사례를 대량 내보냅니다.

세 경로 모두 동일한 생성 논리에 도달하며, 트리거 메커니즘은 어떤 케이스 ID를 입력으로 사용하는지만 결정합니다.

2. 데이터베이스에서 조회된 전체 사례 기록

응용 프로그램은 전체 사례 기록: 사례 ID, 주제, 우선순위, 상태 기록, 생성 및 해결 날짜, 전체 메시지 스레드를 조회합니다. 스레드는 고객 메시지, 에이전트 답변, 내부 노트, 상태 전환에 대한 시스템 생성 항목을 포함하며, 타임스탬프 오름차순으로 정렬되어 대화가 시간순서대로 읽히게 됩니다.

외부 내보내기(GDPR 고객 요청, 규제 제출)의 경우 렌더링이 이루어지기 전에 내부 노트가 쿼리 수준에서 제외됩니다. 법적 발견 및 내부 검토의 경우 내부 노트가 포함되며, 시각적으로 고객 대면 콘텐츠와 구분됩니다.

3. ChromePdfRenderer를 사용한 HTML에서 PDF로의 변환

using IronPdf;

var renderer = new ChromePdfRenderer();

renderer.RenderingOptions.MarginTop = 25;
renderer.RenderingOptions.MarginBottom = 25;

var messageHtml = string.Concat(caseRecord.Messages.Select(m => $@"
    <div class='message {m.SenderRole.ToLower()}' style='
        background:{(m.SenderRole == "Agent" ? "#f0f4ff" : m.SenderRole == "Internal" ? "#fff8e1" : "#fff")};
        border-left: 4px solid {(m.SenderRole == "Internal" ? "#f59e0b" : "#3b82f6")};
        margin-bottom:12px; padding:10px;'>
        <p style='margin:0; font-size:11px; color:#555;'>
            <strong>{m.SenderName}</strong> ({m.SenderRole}) — {m.SentAt:f}
        </p>
        <p style='margin-top:6px;'>{m.Body}</p>
    </div>"));

string html = $@"
    <h1 style='font-size:16px;'>Case #{caseRecord.CaseId}: {caseRecord.Subject}</h1>
    <p>Status: {caseRecord.Status} &nbsp;|&nbsp; Priority: {caseRecord.Priority}</p>
    <p>Opened: {caseRecord.CreatedAt:f} &nbsp;|&nbsp; Resolved: {caseRecord.ResolvedAt:f}</p>
    <hr/>
    {messageHtml}";

PdfDocument transcript = renderer.RenderHtmlAsPdf(html);

transcript.SaveAs($"transcripts/case-{caseRecord.CaseId}.pdf");
using IronPdf;

var renderer = new ChromePdfRenderer();

renderer.RenderingOptions.MarginTop = 25;
renderer.RenderingOptions.MarginBottom = 25;

var messageHtml = string.Concat(caseRecord.Messages.Select(m => $@"
    <div class='message {m.SenderRole.ToLower()}' style='
        background:{(m.SenderRole == "Agent" ? "#f0f4ff" : m.SenderRole == "Internal" ? "#fff8e1" : "#fff")};
        border-left: 4px solid {(m.SenderRole == "Internal" ? "#f59e0b" : "#3b82f6")};
        margin-bottom:12px; padding:10px;'>
        <p style='margin:0; font-size:11px; color:#555;'>
            <strong>{m.SenderName}</strong> ({m.SenderRole}) — {m.SentAt:f}
        </p>
        <p style='margin-top:6px;'>{m.Body}</p>
    </div>"));

string html = $@"
    <h1 style='font-size:16px;'>Case #{caseRecord.CaseId}: {caseRecord.Subject}</h1>
    <p>Status: {caseRecord.Status} &nbsp;|&nbsp; Priority: {caseRecord.Priority}</p>
    <p>Opened: {caseRecord.CreatedAt:f} &nbsp;|&nbsp; Resolved: {caseRecord.ResolvedAt:f}</p>
    <hr/>
    {messageHtml}";

PdfDocument transcript = renderer.RenderHtmlAsPdf(html);

transcript.SaveAs($"transcripts/case-{caseRecord.CaseId}.pdf");
Imports IronPdf

Dim renderer As New ChromePdfRenderer()

renderer.RenderingOptions.MarginTop = 25
renderer.RenderingOptions.MarginBottom = 25

Dim messageHtml = String.Concat(caseRecord.Messages.Select(Function(m) $"
    <div class='message {m.SenderRole.ToLower()}' style='
        background:{If(m.SenderRole = ""Agent"", ""#f0f4ff"", If(m.SenderRole = ""Internal"", ""#fff8e1"", ""#fff""))};
        border-left: 4px solid {If(m.SenderRole = ""Internal"", ""#f59e0b"", ""#3b82f6"")};
        margin-bottom:12px; padding:10px;'>
        <p style='margin:0; font-size:11px; color:#555;'>
            <strong>{m.SenderName}</strong> ({m.SenderRole}) — {m.SentAt:f}
        </p>
        <p style='margin-top:6px;'>{m.Body}</p>
    </div>"))

Dim html As String = $"
    <h1 style='font-size:16px;'>Case #{caseRecord.CaseId}: {caseRecord.Subject}</h1>
    <p>Status: {caseRecord.Status} &nbsp;|&nbsp; Priority: {caseRecord.Priority}</p>
    <p>Opened: {caseRecord.CreatedAt:f} &nbsp;|&nbsp; Resolved: {caseRecord.ResolvedAt:f}</p>
    <hr/>
    {messageHtml}"

Dim transcript As PdfDocument = renderer.RenderHtmlAsPdf(html)

transcript.SaveAs($"transcripts/case-{caseRecord.CaseId}.pdf")
$vbLabelText   $csharpLabel

IronPDF 예시 출력 PDF 문서

IronPDF 예제 출력 많은 메시지를 포함하는 긴 사례는 여러 페이지에 자연스럽게 흐르며, 페이지 제한이나 레이아웃을 깨뜨리는 메시지 수 제한이 없습니다.

4. 모든 페이지에 출처를 확립하는 헤더 및 푸터

renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
    HtmlFragment = $@"
        <div style='font-size:9px; color:#555; width:100%; border-bottom:1px solid #ddd; padding-bottom:4px;'>
            Case #{caseRecord.CaseId} — Exported: {DateTime.UtcNow:u} UTC
        </div>",
};

renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = @"
        <div style='font-size:9px; color:#555; text-align:center; width:100%;'>
            CONFIDENTIAL — Page {page} of {total-pages}
        </div>",
    DrawDividerLine = true
};
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
    HtmlFragment = $@"
        <div style='font-size:9px; color:#555; width:100%; border-bottom:1px solid #ddd; padding-bottom:4px;'>
            Case #{caseRecord.CaseId} — Exported: {DateTime.UtcNow:u} UTC
        </div>",
};

renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = @"
        <div style='font-size:9px; color:#555; text-align:center; width:100%;'>
            CONFIDENTIAL — Page {page} of {total-pages}
        </div>",
    DrawDividerLine = true
};
HTML

헤더 및 푸터가 있는 출력 PDF 문서

머리글/바닥글이 있는 PDF 파일 모든 페이지의 헤더는 사례 ID와 내보내기 타임스탬프를 식별하여 단일 페이지가 다른 페이지와 분리된 경우에도 그 출처가 명확합니다. 푸터의 페이지 수는 문서를 검토자에게 전달할 때 완전한지 여부를 명확히 합니다.

GDPR 데이터 주체 요청에 따른 대량 내보내기의 경우, 동일한 생성 루프가 각 사례를 실행하고 PdfDocument.Merge()는 해당 고객에 대한 모든 사례를 단일 문서로 통합하거나 요청 처리에 필요한 경우 개별 파일로 ZIP에 보관합니다.

실제 이점

법적 준비성. 완전한 사례 기록은 몇 초 만에 생성됩니다. 법무팀 또는 규제 기관이 의사 소통 기록을 요청할 때 응답은 여러 날이 걸리는 스크린샷 컴파일 및 메시지를 Word에 붙여넣는 작업이 아니라 문서입니다.

불변의 기록. 생성된 PDF 문서는 내보내기 시점에 사례가 존재했던 순간의 스냅샷입니다. 생성 후 수정할 수 없으므로 발견 또는 컴플라이언스 감사에서 증거로 적합합니다.

읽기 쉬운 형식. 서식화된 대화 기록은 설명이 필요 없습니다. 변호사, 감사자 및 고객은 티켓 시스템 설명 없이, 원시 데이터 해석 없이 발신자, 타임스탬프, 메시지를 읽는 것과 같은 방식으로 읽습니다.

편집 제어. 내부 노트는 HTML이 생성되기 전에 쿼리 수준에서 포함되거나 제외됩니다. 동일한 내보내기 파이프라인은 법적 발견(내부 노트를 포함한 전체 기록) 및 고객 대상 GDPR 내보내기(고객이 볼 수 있는 메시지) 모두에 사용되며 템플릿 복제는 없습니다.

대량 내보내기. 데이터 주체 접근 요청은 프로그램적으로 처리되며, 특정 고객에 대한 모든 사례가 하나의 배치로 조회, 생성 및 전달됩니다. 사례별 수동 내보내기, 사례 누락의 위험, 케이스 수에 비례한 개발자 노력이 필요하지 않습니다.

내보내기당 비용 없음. 렌더링은 프로세스 내에서 실행됩니다. 서드 파티 내보내기 API 계량도 없고, 도큐멘트당 요금도 없으며, 대규모 발견 요청을 불균형하게 비싸게 만드는 가격 모델도 없습니다.

마무리

티켓 UI의 내부에만 존재하는 지원 사례 기록은 법적, 준수, 또는 고객이 요청할 때 즉시 책임이 됩니다. 요청 시점에 서식화된 PDF 대본을 생성하거나 사례 종료 시 자동화하여 그 책임을 조직이 실제로 제공하고 지원할 수 있는 서식화된 문서로 변환합니다.

파이프라인은 간단합니다: 전체 스레드를 조회하고, 읽기 쉬운 HTML 레이아웃으로 렌더링하고, 출처에 대한 헤더와 푸터를 추가하고, 파일을 반환합니다. IronPDF는 C#에서 ironpdf.com에서 PDF 생성의 전체 수명주기를 처리합니다. HTML 템플릿 렌더링부터 저장, 스트리밍, 문서 조작까지 가능합니다. 사례 내보내기 기능을 구축 중이거나 기존 기능을 강화하고 있다면, 무료 30일 체험을 시작하여 다음 법적 요청이 도착하기 전에 자신의 티켓 데이터를 통해 출력을 확인하십시오.

Curtis Chau
기술 문서 작성자

커티스 차우는 칼턴 대학교에서 컴퓨터 과학 학사 학위를 취득했으며, Node.js, TypeScript, JavaScript, React를 전문으로 하는 프론트엔드 개발자입니다. 직관적이고 미적으로 뛰어난 사용자 인터페이스를 만드는 데 열정을 가진 그는 최신 프레임워크를 활용하고, 잘 구성되고 시각적으로 매력적인 매뉴얼을 제작하는 것을 즐깁니다.

커티스는 개발 분야 외에도 사물 인터넷(IoT)에 깊은 관심을 가지고 있으며, 하드웨어와 소프트웨어를 통합하는 혁신적인 방법을 연구합니다. 여가 시간에는 게임을 즐기거나 디스코드 봇을 만들면서 기술에 대한 애정과 창의성을 결합합니다.

아이언 서포트 팀

저희는 주 5일, 24시간 온라인으로 운영합니다.
채팅
이메일
전화해