跳至主要内容

報表產生開發計畫

狀態: 實作中(REP-P0 Web Prototype slice 已完成;REP-01 完成,已確認採用 PDFBox+AppFuse 自有排版層;REP-02 已實作,模型以實驗性 API 提供;REP-03 PDF renderer 已實作並通過程式碼審閱;REP-04 Figure 與圖表已實作並通過程式碼審閱;REP-05 ReportArtifact 與交付已實作並通過程式碼審閱;REP-06 ranged read 已實作並通過程式碼審閱;REP-07 大型 PDF 按需預覽已實作並通過程式碼審閱;REP-08 選頁 subset 與瀏覽器列印已實作並通過程式碼審閱;REP-09 進行中:實驗性 API 已發布於 appfuse-server 4.0.0-alpha.21,尚待實際 consuming reports、跨瀏覽器與 benchmark 驗證) 依據: ADR-029: Headless 報表引擎與中介文件模型
更新日期: 2026-10-01

目標與成功條件​

建立 developer/AI-first 的 headless 報表管線,使應用可以用 Java 建立 ReportDocument、在 server 直接產生 PDF,並讓 appfuse-web 對大型 PDF 做 range-based 預覽、選頁與瀏覽器列印。

第一個可用版本完成時,必須能用同一組公開契約產生至少三類代表性報表:

  1. 多頁明細表:群組、彙總、重複表頭與頁碼。
  2. 含中文長文、圖片與跨頁區塊的版面報表。
  3. 含長條圖或折線圖的統計報表。

固定座標證書、申請書及政府 PDF 表單不屬於本計畫的 MVP;另案建立 fixed-layout PDF capability。

現況與缺口​

範圍現況缺口
Server 文件能力document 以 XWPF handle 操作 DOCX沒有 renderer-neutral report IR 與直接 PDF renderer
Server 檔案下載FileResponseBuilder 有 HTTP Range 行為FileStorage 缺少原生 ranged-read 契約,部分 backend 可能仍讀取/略過前綴
Web PDF 預覽PdfViewer 使用 PDF.js,並延遲繪製鄰近頁面authenticated URL 先經 axios 下載完整 Blob,無法利用 PDF.js range loading;頁面資源回收無界
Web 列印以新視窗開啟 PDF尚無可靠的 ready handshake、subset PDF 流程與可測試列印契約
圖表應用可各自輸出圖片沒有 Figure/向量交換邊界與 server-side chart adapter

交付架構​

domain/query data
│
▼
ReportTemplate<T> ──► ReportDocument (flow IR)
│
┌─────────┴─────────┐
▼ ▼
Chart adapter PDF renderer
ChartSpec→Figure │
▼
ReportArtifact/PDF
│
storage + authorized URL
│
┌────────────────────┴────────────────────┐
▼ ▼
PDF.js range preview subset PDF → print()

工作包與依賴​

ID工作包依賴主要產物
REP-P0Web Prototype contract sliceADR-029ReportViewer、lifecycle state、page selection、mockable adapter
REP-01代表性報表 corpus 與 renderer spikeADR-029測試資料、版面基準、backend 選型證據
REP-02ReportDocument 核心契約REP-01immutable IR、builder、style/measure、validation
REP-03PDF renderer 基線REP-02文字、表格、圖片、分頁、頁首頁尾、diagnostics
REP-04Figure 與統計圖表REP-02、REP-03Figure、SVG policy、至少一個 chart adapter
REP-05ReportArtifact 與 server deliveryREP-03產物契約、同步/非同步 seam、授權下載整合
REP-06真正的 ranged readREP-05FileStorage range SPI、backend contract tests、CORS headers
REP-07大型 PDF 按需預覽REP-06URL-based PDF.js 載入、page LRU、取消與錯誤處理
REP-08選頁 subset 與瀏覽器列印REP-05、REP-07page selection、subset service、print lifecycle
REP-09hardening 與發布REP-03~08conformance、benchmark、安全、指南、changelog

REP-P0 可在 server 尚未實作時先供下游 Prototype 使用;它固定的是 artifact delivery 與使用者 操作接縫,不是 server ReportDocument。REP-01~03 是 server 報表核心的最小縱切;REP-04 可在 核心穩定後平行發展。REP-05~08 組成實際交付與整合體驗,不應反向污染 ReportDocument。

REP-P0 — Web Prototype contract slice​

工作內容​

  • 在 appfuse-web 提供 ReportViewer,以高階報表語意組合既有 PdfViewer。
  • 以 discriminated state 表達 generating、ready、failed 與 expired;application 仍擁有 job 與 artifact lifecycle。
  • 提供全部、目前頁、連續範圍與指定頁碼的 physical-page selection;送入 adapter 前完成驗證、 排序與去重。
  • 定義 ReportViewerAdapter;Prototype 使用 mock adapter,整合期再換成 subset PDF/print adapter。
  • 元件不認識 ReportDocument、renderer vendor、API route 或 persistence Entity。

完成條件​

  • Storybook 可操作 ready 報表及四種選頁模式,並可查看 generating/failed/expired 狀態。
  • component tests 驗證完整 lifecycle、四種選頁、callback identity、權威頁數、adapter failure/成功及 cancellation/unmount abort。
  • 公開 export、README 與 changelog 完整;TypeScript、ESLint、Vitest 與 framework build 通過。
  • REP-07/REP-08 整合時沿用此契約,不要求 Prototype 改寫畫面流程。

REP-01 — 報表 corpus 與 renderer spike​

結果:見 REP-01 報表 renderer spike。已確認採用 PDFBox 3.0.x 加上 AppFuse 自有排版層;三份 corpus 已在 macOS 與 Linux headless(arm64、amd64)重現,輸出除 /ID 外位元組一致。

工作內容​

  • 把三類代表性報表轉成固定測試資料與預期 PDF 頁面。
  • 針對候選 PDF backend 驗證中文字型、fallback、文字 shaping、表格跨頁、SVG 與逐頁輸出。
  • 記錄 license、維護狀態、Java 25 相容性、模組大小與公開 API 隔離方式。
  • 建立 page raster diff、文字擷取、頁數與 metadata 的測試 harness。

完成條件​

  • 至少一個 backend 能在 CI 環境重現三份 corpus 的基線。
  • 選型結果記錄為 ADR-029 的 implementation note 或另立技術選型 ADR。
  • 所有基線字型具明確授權,CI 與正式環境可重現。

REP-02 — ReportDocument 核心契約​

設計:見 REP-02 ReportDocument 核心契約設計,2026-09-29 通過設計審閱。 實作:2026-09-29 通過程式碼審閱(2 輪);io.leandev.appfuse.report、report.node 以 @ExperimentalApi 提供, 完成條件的測試已實作(架構、建構與讀取兩階段驗證、列來源生命週期、樣式合併、三份 corpus、64MB heap 記憶體測試)。

工作內容​

  • 建立 ReportTemplate<T>、ReportDocument、ReportContext、style、measure 與 validation。
  • 定義 section、paragraph、table、image、figure、group、aggregate、header/footer、page break 與 keep-together/page-break hint。
  • 為大型重複資料定義 single-use row source 與 batch/close contract;文件結構 immutable,runtime data source 的 ownership 另行明定。
  • 區分 hard constraint、soft hint 與 diagnostic;拒絕互相矛盾或無界的模型。
  • 先提供 Java builder;序列化 schema 只做可行性評估,不承諾 v1 wire compatibility。

完成條件​

  • 公開 API architecture test 證明沒有 PDF/chart vendor 型別洩漏。
  • builder 可建立三份 corpus 的完整文件樹,且有 snapshot/structural tests。
  • 文件結構與 style immutable,重用 token 不會因 renderer 修改而產生共享狀態;row source 不能被無意重複消費或遺漏關閉。

REP-03 — PDF renderer 基線​

設計:見 REP-03 PDF renderer 基線契約設計,2026-09-29 通過設計審閱(3 輪); 狀態:已實作並通過程式碼審閱(3 輪,2026-09-29)。三份 corpus 與 golden、-Xmx128m 記憶體 gate、Linux arm64/amd64 跨平台驗證皆通過;REP-01 spike 已移除(FU-100)。

工作內容​

  • 實作測量、換行、分頁與逐頁輸出 pipeline。
  • 支援中文與 fallback font、字型嵌入、段落、表格跨頁、重複表頭、圖片、頁首頁尾與頁碼。
  • 實作 group、aggregate 與基本 keep-together 行為。
  • 產生 PDF metadata、頁數與 diagnostics;確保資源在成功、失敗與取消時都會關閉。

完成條件​

  • 三份 corpus 的頁數、文字內容與 visual golden 都通過。
  • 大型明細基準不以「完整文件節點+完整 PDF bytes 各保留一份」為必要條件;峰值記憶體有 benchmark 與 regression gate。
  • 不支援或被降級的 layout request 會產生 diagnostic,而不是靜默忽略。

REP-04 — Figure 與統計圖表​

設計:見 REP-04 Figure 與圖表契約設計,2026-09-29 通過設計審閱(3 輪); 狀態:已實作並通過程式碼審閱(3 輪,2026-09-30)。受限 SVG 子集與安全政策(FU-105)、點陣 Figure、長條圖與折線圖 adapter; corpus 統計報表改用實際圖表,macOS 與 Linux arm64/amd64 輸出除 /ID 外位元組相同。 已決定自寫受限 SVG 子集(不採用 Batik+pdfbox-graphics2d),圖表 adapter 提供長條圖與折線圖。

工作內容​

  • 建立 Figure 的尺寸、替代文字、overflow 與 flow-layout 契約。
  • 在 Figure 內提供局部座標系;禁止一般 report node 指定絕對頁面座標。
  • 定義受限 SVG 輸入與 raster fallback,禁止 script、外部 URL、file URL 與未受控 resolver。
  • 提供至少 bar 或 line chart 的 ChartSpec -> Figure adapter,涵蓋座標軸、圖例、標籤與 無資料狀態。

完成條件​

  • 同一 Figure 可放在段落間、table cell 與跨頁前後,且不破壞 flow pagination。
  • 圖表的文字、顏色、單位與 accessibility alt text 可由應用控制。
  • 惡意 SVG、過大 viewBox、極端 path 數量與外部資源都有拒絕或限制測試。

REP-05 — ReportArtifact 與 server delivery​

設計:見 REP-05 ReportArtifact 與交付契約設計,2026-09-30 通過設計審閱(3 輪); 已實作並通過程式碼審閱(2 輪,2026-09-30);裁決與實作偏離見契約設計的「程式碼審閱裁決」與「實作註記」。 已決定:非同步 seam 只到值型別與保存 helper、tenant/tenantless 以框架測試與指南示範、renderer 提供頁數進度回呼。

工作內容​

  • 定義 ReportArtifact 的 MIME type、filename、size/page count、metadata 與 stream/resource ownership。
  • 提供同步產生能力;為 application-owned 非同步 job、進度、取消、重試與 retention 定義 seam。
  • 與 FileStorage/FileResponseBuilder 整合,但不在框架建立 report job Entity 或固定 API route。
  • 定義原始 PDF 與 subset PDF 的 authorization、ETag 與稽核責任。

完成條件​

  • 應用可選擇直接串流短報表,或把大型報表保存後再提供下載。
  • renderer failure 不留下未關閉 stream 或誤認為成功的 artifact。
  • tenant/tenantless 參考實作都能由 application adapter 接線,框架無 tenant 假設。

REP-06 — 真正的 ranged read​

設計:見 REP-06 Ranged read 契約設計,2026-09-30 通過設計審閱(3 輪); 已實作並通過程式碼審閱(2 輪,2026-09-30);裁決與實作偏離見契約設計的「程式碼審閱裁決」與「實作註記」。 已決定:FileStorage 以 default 方法宣告能力、不支援時忽略 Range 回完整內容、mock client+容器兩層 contract test、 CORS 由框架提供常數與文件(參考伺服器併入 FU-103)。

工作內容​

  • 在 storage capability 增加 offset/length 或等價的 ranged-read 契約。
  • Local、Database、S3/MinIO、Azure Blob 與 SFTP 分別實作或明確宣告降級策略。
  • FileResponseBuilder 正確處理 Range、If-Range、If-None-Match、單一合法 range、206 與 416;回應暴露 Accept-Ranges、Content-Range、Content-Length 與 ETag。
  • 驗證前端跨來源設定可以讀取 PDF.js 所需 headers。

完成條件​

  • backend contract test 證明 ranged request 不必讀取完整物件或從 byte 0 線性略過至 offset。
  • 合法、超界、格式錯誤與條件式 range 都有整合測試。
  • 不支援 efficient range 的 backend 會被 capability/diagnostic 清楚識別。

REP-07 — 大型 PDF 按需預覽​

設計:見 REP-07 大型 PDF 按需預覽設計,2026-09-30 通過設計審閱(3 輪); 已實作並通過程式碼審閱(2 輪,2026-09-30);裁決與實作註記見設計文檔的「程式碼審閱裁決」與「實作註記」。 已決定:經 HttpClient 的 PDF.js range transport、搜尋漸進且可取消、順手修正列印、測試資料於 Playwright 動態產生。

工作內容​

  • PdfViewer 以受權 URL 和 PDF.js HTTP 設定載入,不先透過 axios 取得完整 Blob。
  • 支援 bearer header 或同源 cookie;處理 token 失效、取消、重試與文件替換。
  • 只渲染 viewport 鄰近頁面;以 LRU/上限回收 canvas、page proxy、render task 與 object URL。
  • 在不載入所有 page object 的前提下取得頁數與漸進式頁面尺寸。
  • 顯示 loading、下載進度(可取得時)、錯誤與 fallback download action。

完成條件​

  • 第一頁可在完整 PDF 下載前顯示,network test 可觀察到 206 與分段請求。
  • 連續瀏覽大量頁面後,DOM/canvas/page cache 維持設定上限。
  • zoom、跳頁、搜尋或快速捲動不留下未取消的 render task,且可安全卸載 viewer。

REP-08 — 選頁 subset 與瀏覽器列印​

設計:見 REP-08 選頁 subset 與瀏覽器列印設計,2026-09-30 通過設計審閱(3 輪); 已實作並通過程式碼審閱(2 輪,2026-09-30);裁決與實作註記見設計文檔的「程式碼審閱裁決」與「實作註記」。 已決定:subset 每次請求即時產生並串流(不保存)、選頁以 GET query pages=1-3,5 傳遞、框架提供前端 adapter 工廠、 保守的保留規則(移除導覽結構、保留外觀,並以原頁碼設定頁碼標籤)。

工作內容​

  • 前端支援全部、目前頁、連續範圍與明確頁碼集合;先正規化、排序、去重與驗證。
  • server 從已授權的原始 artifact 擷取頁面,產生短效 subset PDF;定義 outline、link、form、 metadata 與頁碼語意的保留/捨棄規則。
  • 用受控 iframe/新視窗載入可列印 PDF,收到 ready signal 後呼叫 print();避免在需要取得 window handle 時使用使回傳值為 null 的開窗設定。
  • 明確顯示「系統選的是輸出文件頁面」;原報表頁碼與 PDF physical page 不同時要可辨識。

完成條件​

  • subset 的 physical page 順序與選擇完全一致,無權限或過期 artifact 無法擷取。
  • Playwright 可用 print stub 驗證只觸發一次、觸發前文件已就緒;native dialog 本身不做自動化斷言。
  • popup 被封鎖、載入失敗、使用者取消列印與 subset 過期都有可理解的回復路徑。
  • 文檔清楚聲明 Web 無法預填原生列印對話框的 page range,也不提供 silent print。

REP-09 — hardening 與發布​

測試矩陣​

  • IR validation、builder 與 renderer unit tests。
  • corpus PDF 的 page/text/metadata assertions 與 raster golden diff。
  • 字型缺失、超長不可斷文字、表格列高超頁、損壞圖片與 SVG 攻擊測試。
  • storage backend range contract tests 與 server integration tests。
  • Chromium、Firefox、WebKit 的預覽生命週期與列印觸發測試。
  • 大頁數、大表格、高解析圖片與複雜圖表的時間、記憶體與輸出大小 benchmark。

發布條件​

  • 先發布 experimental API;在至少兩個實際 consuming reports 驗證後再承諾 stable API。
  • 補齊 server 使用指南、web PdfViewer 指南、Javadoc/API docs、範例與 changelog。
  • 所有 optional renderer/chart dependencies 都是隔離相依,未使用報表能力的應用不必載入。
  • 記錄已知限制、相容性政策、字型部署方式與大型報表容量規劃方法。

明確不在本計畫內​

  • GUI/WYSIWYG report designer 與 power-user 自訂 expression。
  • 以 HTML/CSS、JRXML、DOCX 或 raw PDF drawing commands 作為 canonical authoring language。
  • 固定格式 PDF 套版與 AcroForm 填寫的 authoring API;固定版面另由 固定表單能力 承接,不納入 flow 模型。
  • 瀏覽器 silent print、預設印表機選擇或強制原生 page range。
  • 應用專屬 report job Entity、排程政策、保存期限與權限規則。
  • 在需求尚未出現前承諾完整 JasperReports 等價功能。

後續產品規格如何接軌​

本計畫是框架工程清單,不是終端使用者 Epic。採用端可先以 RPT 報表規格 描述欄位、資料來源、篩選、排序、群組、圖表、版面、資料截止時間與驗收例,獨立完成範本與合成資料驗證,不以 US 為前置條件。 產品操作入口、權限、job/下載/重印流程則由引用 RPT 的 US/SBE 承接;既有業務 Epic/US 可引用同一份 RPT,避免重複描述欄位與版面。 產品依賴已發布的框架版本,不依賴本文件的內部 REP 工作包;固定資料樣張不能充作實際 consuming report。

固定表單與 RPT 支援的發布順序(2026-10-01 審閱結論)​

第 1~4 步已於 2026-10-01 完成,第 5 步待各下游執行(見下方「交付紀錄」)。為避免主線出現新版 ReportJobWorker 搭配舊框架 pin 的編譯空窗,按下列順序交付:

  1. 精確分組框架、參考實作與方法論變更;先從可建置基線建立隔離 release worktree,只帶框架 API、測試及必要文件,保留舊版參考實作。
  2. 確认乾淨工作樹及實際版號,依框架 publish 流程執行完整測試、不可變 alpha 發布、文件站部署及線上版本驗證。候選版號不等於已發布版號。
  3. 框架發布成功後,將參考實作新碼、兩個 server 的實際發布版號 pin 與 FEATURE_CHANGELOG Requires 放在同一 commit;以 registry 相依重驗,不使用 useLocalFramework,再提交。
  4. 切參考實作 CalVer;方法論另作可審閱提交並發布,同步下游 adapters。方法論同步不會自動更新應用程式碼。
  5. 下游升級框架、採用 report feature 更新,再依各自 RPT 實作資料 adapter,驗證真實資料、權限、實紙套印與代收掃讀。

交付紀錄(2026-10-01)​

步驟結果
1–2 框架發布appfuse-server 4.0.0-alpha.21 以隔離 release worktree 完整建置(1534 tests 通過)後發布至 releases repo;文件站 /actuator/info 與 /server/changelog 線上驗證通過
3 參考實作兩個 server 的固定表單接線、4.0.0-alpha.21 pin 與 FEATURE_CHANGELOG Requires 同一 commit 落地;以 registry 相依重驗通過(2026-10-01 強制重跑:tenant 833、tenantless 555 tests;先前記載的 845/567 誤計入過時的測試結果檔)
4 切版與方法論參考實作切版 app-v2026.1.22;方法論 publish 至 8 個下游,fleet 對齊無在地漂移
5 下游採用未開始:各下游自行 /upgrade-appfuse-server 4.0.0-alpha.21 並依 RPT 實作 adapter

審閱通過不取代 REP-09 的實際 consuming reports 條件;RPT-001 仍為獨立範本試行,歷史本機接受不當作目前帳本證據。