跳至主要内容

ADR-029: Headless 報表引擎與中介文件模型

ADR 編號: 029 狀態: 已接受 (Accepted) 決策日期: 2026-08-06 決策者: Framework Team + AI Assistant

摘要

AppFuse 將提供面向開發者與 AI 的 headless 報表能力:應用先建立與渲染器無關的 ReportDocument 中介模型,再由 ReportRenderer 產生 PDF。報表採文件流式排版,統計圖表 在 Figure 區塊內擁有局部座標系;固定座標的證書、申請書與既有表單則屬於獨立的 PDF 套版能力,不共用報表 authoring model。

背景 (Context)

問題陳述

框架需要產生資料量與頁數都可能很大的報表,並讓前端按需預覽、選擇頁面後呼叫瀏覽器 列印。報表的設計者實際上是開發者與 AI,而不是使用圖形化設計器的 power user,因此核心 契約必須適合程式產生、版本控制、測試與重構。

既有 Word 文件模組以 DOCX 範本與 Apache POI handle 為中心,適合公文與套版文件,但它不是渲染器中立的文件模型。HTML/CSS 則是瀏覽器渲染語言;其分頁、頁首頁尾與列印結果受瀏覽器引擎影響,不適合作為框架報表的 核心語言。PDF 能穩定保存最終版面,但若直接拿 PDF 操作指令當 authoring API,資料群組、 表格跨頁、重複表頭與 keep-together 等報表語意會散落在座標計算中。

限制條件

  • 公開 API 不得洩漏 PDFBox、JasperReports、SVG library 或其他渲染後端型別。
  • 主要輸出是可保存、下載與列印的 PDF;瀏覽器原生列印對話框仍由使用者控制。
  • 大型 PDF 不應要求前端先下載完整 Blob 才能顯示第一頁。
  • 圖表需要向量圖、文字、座標軸與圖例,但任意座標不能污染整份報表的流式排版。
  • 框架不得為報表工作佇列或產物宣告業務 @Entity;持久化與權限仍由應用擁有。
  • 固定表單與資料驅動報表的版面語意不同,不能只因輸出都是 PDF 就合併模型。

名詞邊界

名詞定義
Report由資料集合、群組、彙總與條件內容驅動,依文件流自動分頁的輸出
Fixed-layout PDF template以既有頁面為底,在固定座標填字、勾選、蓋章或放圖的文件
ReportDocument完成資料綁定後、尚未分頁成 PDF 的渲染器中立文件樹
Figure報表流中的單一區塊;區塊內可使用局部座標描述向量圖形
ReportArtifact渲染後產物的描述與串流存取契約,不代表資料庫 Entity

考量的方案 (Options Considered)

方案 A: HTML/CSS 為核心,再轉成 PDF

優點:

  • 開發者熟悉,文字與一般版面工具多。
  • 可直接使用瀏覽器或 HTML-to-PDF 引擎。

缺點:

  • paged media 支援與輸出一致性依賴特定引擎。
  • 報表語意會退化成 DOM/CSS 細節,難以替換後端或做結構測試。
  • 後端仍需固定並維護一套瀏覽器或 HTML renderer。

評分: 2/5

方案 B: 直接以 PDF drawing API 撰寫報表

優點:

  • 最接近輸出格式,可精確控制每一個繪圖指令。
  • 不需要額外的中介模型。

缺點:

  • 應用必須自行處理測量、換行、表格跨頁、孤行寡行與重複區塊。
  • authoring code 與 PDF library 綁死,難以測試及替換實作。
  • AI 產生的低階座標程式脆弱,無法清楚表達報表意圖。

評分: 2/5

方案 C: JasperReports/JRXML 作為框架報表模型

優點:

  • 已有成熟的 group、band、subreport、chart 與 PDF 輸出能力。
  • 可 headless 執行,且有完整生態系。

缺點:

  • 框架 API 與 JRXML/Jasper 的 band、expression 和 pagination model 綁定。
  • 圖形化設計器不是本次 developer/AI-first 使用情境的必要能力。
  • 應用需承擔另一套模板語言、編譯流程與相依版本。

評分: 3/5;可作為未來 renderer/adapter 的候選,不作 canonical model。

方案 D: DOCX 作為中介格式,再轉 PDF

優點:

  • 可重用既有範本與 Word 文件能力。
  • 使用者可用 Word 檢視或修改中間文件。

缺點:

  • 轉檔結果依賴 Office/LibreOffice 或第三方 converter,PDF 不是直接產物。
  • DOCX 的文件與套版語意不能完整代表報表分組、圖表及可預測分頁。
  • 大型報表增加一次完整文件建立與轉換成本。

評分: 2/5;保留為文件匯出流程,不作報表核心。

方案 E: AppFuse 擁有 ReportDocument IR,由可替換 renderer 產生 PDF

優點:

  • authoring API 直接表達章節、段落、表格、群組、彙總、圖形與分頁意圖。
  • 模型可由 Java、AI 或日後其他 DSL 產生,且能做結構測試。
  • PDF library、chart library 與 HTML rich-text parser 都留在 adapter 邊界。
  • 能把流式排版與局部座標繪圖放在不同層次處理。

缺點:

  • 必須自行定義模型、pagination contract 與 renderer conformance suite。
  • v1 需克制功能範圍,不能一次複製成熟商用報表引擎的全部能力。

評分: 5/5

決策 (Decision)

選擇方案: E

1. canonical authoring model

框架擁有 backend-neutral 的 ReportDocument。第一個 authoring surface 是 type-safe Java builder;應用可用 ReportTemplate<T> 把 domain/query model 轉成文件樹。IR 不等同 PDF object model,也不以 HTML、JRXML 或 DOCX 作為內部事實來源。

概念契約如下;名稱可在 API design review 中微調,但責任邊界不可反轉:

public interface ReportTemplate<T> {
ReportDocument create(T data, ReportContext context);
}

public interface ReportRenderer {
boolean supports(ReportFormat format);
ReportArtifact render(ReportDocument document, RenderOptions options);
}

ReportDocument 的結構與樣式以 immutable value/object tree 為基線。公開節點至少能表達 document metadata、section、paragraph、table、image、figure、page break、header/footer、 group、aggregate 與 keep-together/page-break hint。大型重複資料可由有明確 ownership、關閉與 單次消費語意的 row source 提供,不要求先展開成完整記憶體樹。renderer 可以忽略無法實現的 soft hint,但必須透過 capability 或 diagnostic 明確回報,不得默默產生語意錯誤的輸出。

2. 兩層排版模型

報表最外層採 flow layout,由 renderer 決定測量、換行與分頁。任意座標只存在於有界的 Figure 內;Figure 本身仍像圖片或表格一樣參與文件流。如此可以產生折線圖、長條圖、 散佈圖與自訂統計圖形,又不讓 page/table layout 退化為整頁座標程式。

圖表語意放在 optional chart adapter,例如 ChartSpec -> Figure。核心只認得 Figure 的 尺寸、替代文字與向量/點陣內容;優先使用 SVG 作為 renderer 間的局部向量交換格式,必要時 允許 raster fallback。輸入 SVG 必須套用安全 policy,禁止外部資源與可執行內容。

3. PDF 是主要輸出,不是 authoring model

首個 ReportRenderer 直接產生 PDF,負責字型嵌入、文字 shaping、表格跨頁、重複表頭、 頁首頁尾、頁碼與圖形輸出。PDF backend 為內部實作細節;若採用 PDFBox、OpenPDF、 JasperReports 或其他 library,其型別不得出現在公開簽章。

HTML 只可作為受限 rich-text 輸入 adapter,轉成既有 IR 節點;不接受任意 HTML/CSS 控制 整份報表。DOCX 仍由既有 document 能力負責,報表引擎不以 DOCX-to-PDF 實作 PDF renderer。

4. 固定格式 PDF 套版是獨立能力

證書、申請書、政府表單與既有 PDF 底稿採 fixed-layout authoring model,其核心操作是 「選頁/定位/覆寫/填表/合併」。它可與報表共用底層 PDF runtime、字型、影像、安全與 binary/PDF artifact 基礎設施,但不得重用 ReportDocumentReportArtifact 或 flow nodes 來假裝固定座標版面。

5. 預覽與列印是交付通道,不進入 IR

大型 PDF 以支援 HTTP byte-range 的受權 URL 交給 PDF.js,前端只渲染可視頁並以有界快取 回收離開視窗的 canvas/page resources。選頁列印由後端從已產生的原始 PDF 建立 subset PDF, 前端載入 subset 後呼叫瀏覽器列印介面。

瀏覽器原生列印對話框不能由 Web API 安全地預填使用者的 page range,也不保證 silent print; 框架只保證開啟正確的完整或 subset 文件並觸發 print。silent/kiosk printing 屬於另外的桌面、 瀏覽器管理政策或原生整合能力。

6. ownership 與持久化

純 renderer 是同步、無狀態 library。長時間產生、排程、重試、進度、授權與 retention 是 application orchestration。框架可提供 SPI、狀態 value types 與參考 adapter,但不宣告 report job/report artifact Entity,遵循框架 jar 不擁有 Entity

v1 範圍

v1 必須提供延後或獨立處理
Java builder、immutable IR、樣式與量測單位JSON/YAML 報表 DSL 與 GUI designer
段落、表格、圖片、群組、彙總、頁首頁尾、頁碼與分頁 hintscrosstab、互動式 drill-down、任意 script/expression engine
直接 PDF renderer 與字型設定PDF 以外 renderer 的完整實作
Figure、SVG/raster graphic 與至少一條 chart adapter 路徑全套商業圖表元件
PDF metadata、頁數與 diagnosticsPDF/A、數位簽章、加密與無障礙標記完整支援
Range-friendly delivery、選頁 subset、瀏覽器列印整合契約silent/kiosk printing

Fixed-layout PDF template 不在 report v1 內;它應另立 capability/ADR 與交付計畫。

權衡分析 (Trade-offs)

我們獲得什麼 (Gains)

  • 報表意圖與 PDF library 分離,開發者與 AI 可產生可讀、可測的高階模型。
  • 同一份 IR 可在不改應用 authoring code 的前提下更換 renderer 或增加輸出格式。
  • 圖表擁有必要的座標能力,同時保住一般報表的 flow/pagination 語意。
  • 大型報表的產生、儲存、按需預覽與選頁列印形成清楚但可分階段交付的管線。

我們放棄什麼 (Losses)

  • 不直接取得 JasperReports 的完整功能面與 designer 生態。
  • 不承諾任意 HTML/CSS 都能像瀏覽器一樣渲染。
  • v1 不提供整頁任意座標 DSL,也不把固定表單混入報表 API。

風險與緩解措施 (Risks & Mitigations)

風險嚴重性機率緩解措施
自建 pagination scope 膨脹鎖定 v1 節點與排版規則;以代表性報表 corpus 驗收
中文字型、fallback 與 shaping 結果不一致明確 font registry、嵌入政策與跨平台 golden tests
大型表格造成記憶體壓力renderer 採逐頁輸出;資料來源與節點引入受控 streaming/batching contract
SVG 帶入外部資源或 scriptsanitize/allowlist、禁止 network/file resolver、限制尺寸與複雜度
subset PDF 破壞 outline、link 或 metadata定義保留規則並以 PDF 結構與視覺測試驗證
IR 過早凍結v1 保持 Java API;序列化 schema 另立版本契約後才承諾相容性

實作不變量與驗證

  1. 公開 API 不出現 renderer vendor 型別或 raw PDF drawing object。
  2. 一般 flow node 不接受絕對頁面座標;局部座標只存在 Figure/fixed-layout capability。
  3. 同一輸入、字型組合與 renderer 版本必須產生等價的頁數、文字與版面。
  4. renderer diagnostics 能指出不支援的節點、遺失字型、overflow 與被降級的圖形。
  5. PDF renderer 以結構 assertion、文字擷取、頁面 raster golden diff 及記憶體 benchmark 驗證。
  6. Range delivery 必須驗證 Accept-RangesContent-Range206、條件式請求及各 storage backend 的實際 ranged read,不能只在完整 InputStream 上呼叫 skip()
  7. 前端必須驗證第一頁可在完整檔案下載前顯示、頁面資源會回收、授權失效可處理,且列印的 subset 頁序與使用者選擇一致。

具體交付順序與完成條件見 報表產生開發計畫

相關文檔 (References)

變更歷史 (Change Log)

日期變更內容變更者
2026-08-06初版;確立 ReportDocument IR、兩層排版、PDF renderer 與 fixed-layout 邊界Framework Team + AI

文檔維護者: Development Team + AI Assistant
最後審閱: 2026-08-06