← 回作品列表

晶片商 B 議題追蹤平台

Chip Vendor B Issue Tracker

把供應商那種「合併儲存格、一格內含換行與圖片」的複雜 Excel 搬上 web 平台,核心是搬運過程不破壞來源語意,並以可逆的匯入流程保護資料。

data-platform ETLMySQLFlaskExceldata fidelity 原始碼:私有

問題現場

這家供應商的 issue Excel 排版很複雜:合併儲存格、一格內好幾行、夾圖片、還有列與列的對應。要把它搬上 web 查詢,聽起來只是「匯入」而已。

難就難在「只是匯入」這四個字。直接匯,原本的語意很容易被弄壞——多行被壓成一行、合併格對錯、列對應跑掉。更麻煩的是這種破壞看起來不像 bug:頁面照樣顯示,內容卻悄悄失真,等到有人對不上才爆出來。

最小技術背景

  • 資料保真(data fidelity):搬運過程中,資料原本的意思不被弄壞、不走樣。
  • 換行(\n:一格內的多行,是承載語意的一部分,不是可隨意壓掉的空白。
  • source of truth:同一份資料存在多個地方(Excel、資料庫、前端畫面)時,被認定為「正確基準」的那一份。抓 bug 要先確認它。

系統架構與資料流

換行在後端完整保留;只有列表 preview 為了好看才壓平,詳情仍還原原樣:

flowchart LR
  XL["複雜 Excel|合併儲存格 / 換行 / 圖片"] --> IMP["importer|保留語意 + 列對位"]
  IMP --> DB["MySQL|完整保留換行"]
  DB --> WEB["Flask web"]
  WEB --> LIST["列表 preview|壓平,只為好讀"]
  WEB --> DRAWER["詳情 drawer / tooltip|還原原始換行"]

關鍵設計決策(含取捨)

決策選了什麼否決的替代為什麼
對待 Excel 語意當成資料模型的一部分保留匯入前先抹平成「乾淨」純文字否決:抹平就等於把語意當雜訊丟掉
除錯起點先確認 source of truth(DB 是否仍有換行)直接在看到問題的前端修否決:在錯的那層修,只會生出新 bug
顯示策略後端保留、列表壓平、詳情還原後端就壓平,前端只能拿到壓平結果否決:壓平之後,語意就再也救不回來了
匯入安全權限 + 備份 + 可重跑不出錯 + 可還原直接覆寫否決:一個不小心,「修資料」就變成「毀資料」

代表性技術證據

後端保留、前端才壓平(pseudo-code,示意)

# 後端:原樣存,換行本來就是資料的一部分
db.save(issue_id, status_update=raw_text)   # 完整保留 \n

# 前端列表:只在「顯示」這一層壓平,絕不回頭動來源
def preview(text):
    return text.replace("\n", " ")          # 純粹為了列表好讀
# 詳情 drawer / tooltip 就直接顯示 raw_text,換行原封不動

合成範例(示意):來源 "步驟1\n步驟2\n步驟3" 進 DB 後仍是三行;列表顯示 步驟1 步驟2 步驟3,但點開詳情仍是三行。

踩過的坑

欄位內容
症狀詳情頁顯示的 status_update 換行和 Excel 對不上
初判(猜錯)第一個念頭是 ETL 匯入時把換行壓平了
驗證直接查資料庫,確認 \n 其實還在
根因前端有段日期 regex 嘗試「重新切行」,把來源換行覆蓋掉了
修法列表 preview 壓平、詳情 / tooltip 保留原始換行;移除前端誤切
預防新增含多行文字的合成列做 regression,換行被動到就失敗

驗證方式

  • 保真:含多行、合併格的合成列,匯入後 DB 仍保留換行與對位。
  • 顯示:列表壓平、詳情還原,兩者來自同一份未失真的後端資料。
  • 可逆匯入:匯入先 dry-run、再備份、最後交易式套用;重跑不重複。
  • 驗收標準:來源、DB、詳情三者語意一致;換行不被任何一層悄悄破壞。

可複製 SOP:把帶語意的複雜資料安全上線

適用情境:來源格式本身承載語意(換行、合併格、列對應),不能當純文字隨意清洗。

不適用情境:來源是已正規化的純資料,無排版語意時可簡化。

前置條件

  • 準備一組「最難的合成列」(多行 + 合併格 + 對位),當保真基準。
  • 匯入工具具備備份與還原能力。

步驟

  1. 語意當資料:先認出哪些排版其實是語意(這裡是換行跟列對位),然後明確留住它。
  2. 後端原樣存:來源語意原封不動進 DB,別在入庫的時候順手壓平。
  3. 顯示才變形:想好看,就在前端顯示這層處理,而且絕不回寫來源。
  4. 可逆匯入:dry-run 看 diff → 備份 → 交易式套用 → 可還原。
  5. 先確認真相再修:出問題先查 source of truth 在哪一層,別在「看到問題的地方」就動手亂修。

停損點

  • 合成列匯入後換行 / 對位跑掉 → 停,先修保真再上真資料。
  • 無法備份 / 還原 → 停,先補可逆能力。

驗收標準

  • 來源、DB、詳情語意一致;重跑不重複、可還原。

回滾:匯入前的備份即還原點;以交易為單位,失敗整批退回。

可複製到:任何「Excel / 文件帶排版語意、要搬上系統」的場景。

決策回放(三個月後回讀用)

  • 背景:複雜 Excel 上 web 容易失真,且失真不易察覺。
  • 限制:不可外流真實 issue 內容與供應商名;匯入不可破壞或不可逆地覆寫。
  • 考慮過但放棄:匯入前先把文字「清乾淨」壓平——被「會破壞語意」否決。
  • 證據:DB 仍含換行的查驗、前端 preview/詳情分離、多行合成列 regression。
  • 未解:圖片引用要怎麼長期存;要不要跟晶片商 A 的 tracker 整併。

作者備註: 這案最大的教訓:bug 不一定在你看到它的地方。我差點在前端硬改顯示,幸好先去問「DB 裡到底還有沒有換行」,才發現真正的兇手是前端那段多事的 regex。