# 資料匯入貼標程式——需求書(技術規格・v1) > 文件性質:業務端原始需求描述+技術端已展開之技術規格(資料表、流程、技術棧已確認,仍保留少量待確認事項與一筆已知邏輯缺陷)。 > 用途:作為 Day 10~Day 16 系列文章的共用案例素材,示範 Codex 沙箱環境與代理迴圈、AGENTS.md 專案慣例設計、第一個 Codex 任務(issue 描述到修 bug)、測試執行與結果回報、權限與安全邊界、Git 工作流整合。 > 版本:v1(技術端已完成初步規格化,保留可作為後續 Codex 實戰任務的已知問題) ## 一、專案基本資料 - **專案名稱**:資料匯入貼標程式(Data Import & Tagging Job) - **系統性質**:新建定時批次程式,獨立服務執行,不對外提供 API - **需求提出單位**:資料工程團隊(內部工具需求) - **提出日期**:2026-08-05 - **狀態**:技術規格已完成初稿,尚未實作,待排入開發並以 Codex 輔助建置 ## 二、背景與目標 > 原始需求(業務端/資料工程團隊原話):「會先從 A 資料庫讀取資料後,再經過程式貼標後匯入到 B 資料庫。」 資料庫 A 是上游業務系統持續累積原始資料的地方,內容量大、欄位偏原始,下游的報表與分析需求則需要「已分類、已加上標籤」的資料,這份加工後的結果要存放在資料庫 B 供後續系統讀取。過去這個貼標動作是工程師依需求手動寫一次性腳本執行,沒有固定排程,也沒有留下處理紀錄,曾發生忘記重跑導致下游報表資料延遲一週才被發現的情形。 這次要建置一支排程程式,定時從資料庫 A 讀取新增或異動的資料,依既定規則貼上標籤後寫入資料庫 B,並且留下每次執行的紀錄,讓貼標流程從「工程師手動跑腳本」變成「系統自動化、可追蹤、可重跑」。 ## 三、名詞定義 - **來源資料庫 A(Source DB)**:存放原始未分類資料的既有資料庫,本程式僅讀取,不寫入。 - **目的資料庫 B(Target DB)**:存放貼標後結果的資料庫,本程式的寫入對象。 - **貼標(Tagging)**:依貼標規則,為每筆原始資料加上一個或多個分類標籤的處理動作。 - **貼標規則(Tagging Rule)**:定義「符合什麼條件的資料要加上什麼標籤」的設定,可能有多筆規則同時套用在同一筆資料上。 - **匯入批次(Import Batch)**:一次排程觸發所處理的資料範圍,有明確的開始與結束時間、成功與失敗筆數。 - **水位(Watermark)**:記錄上一次成功處理到來源資料庫 A 的哪個時間點或流水號,下次批次以此為起點往後撈取,避免重複匯入整份資料。 ## 四、關係人與角色 - **資料工程團隊**:本程式的需求提出者與維護者,負責定義與調整貼標規則。 - **下游系統/報表使用者**:讀取資料庫 B 的貼標結果,不直接操作本程式,但關心資料的即時性與正確性。 - **維運/DevOps**:負責本程式的部署、排程設定、資料庫連線的網路權限(VPN、白名單)與告警機制。 - **系統本身(排程服務)**:無人工觸發,依 cron 設定定時執行,失敗時需要有紀錄可供人工事後排查。 ## 五、系統範圍與流程 1. **排程觸發**:依 cron 設定的週期(例如每小時一次)自動觸發,觸發時間與頻率須可透過設定檔調整,不寫死在程式碼中。 2. **讀取來源資料庫 A**:依水位撈取水位時間點之後新增或異動的資料,採分頁方式讀取,避免單次撈取全部資料造成記憶體壓力。 3. **貼標處理**:逐筆資料比對貼標規則(依欄位值、關鍵字或條件式比對),符合條件者加上對應標籤;同一筆資料可能同時符合多筆規則、被加上多個標籤。 4. **寫入目的資料庫 B**:將貼標後的資料寫入資料庫 B,需處理「同一筆來源資料被處理兩次」的情況(採 upsert,以來源資料 id 為鍵,覆寫既有紀錄而非新增重複列)。 5. **更新水位與寫入執行紀錄**:批次結束後更新水位,並記錄本次批次的起訖時間、讀取筆數、成功貼標筆數、失敗筆數與失敗原因摘要。 6. **失敗處理**:單筆資料貼標或寫入失敗時,記錄該筆失敗原因並繼續處理下一筆,不中斷整批;若整批連線失敗(資料庫 A 或 B 無法連線),則整批標記失敗、水位不前進,等待下次排程重試。 ## 六、資料規格(技術端初步定義) ### 6.1 來源資料庫 A:資料表 `raw_records`(範例欄位) | 欄位 | 型別 | 說明 | |---|---|---| | id | BIGINT | 主鍵 | | source_type | VARCHAR | 資料來源類型 | | content | TEXT | 原始內容 | | created_at | TIMESTAMP | 建立時間 | | updated_at | TIMESTAMP | 最後異動時間,作為水位比對依據 | ### 6.2 目的資料庫 B:資料表 `tagged_records`(範例欄位) | 欄位 | 型別 | 說明 | |---|---|---| | id | BIGINT | 主鍵 | | source_id | BIGINT | 對應 `raw_records.id`,唯一索引,作為 upsert 依據 | | content | TEXT | 原始內容(可能與來源相同或經過清理,未確認) | | tags | VARCHAR / JSON | 貼上的標籤清單 | | imported_at | TIMESTAMP | 本筆寫入或更新的時間 | ### 6.3 貼標規則表 `tagging_rules`(可設定化,範例欄位) | 欄位 | 型別 | 說明 | |---|---|---| | rule_id | BIGINT | 主鍵 | | match_field | VARCHAR | 比對的來源欄位名稱 | | match_pattern | VARCHAR | 比對條件(關鍵字或樣式) | | tag_name | VARCHAR | 符合條件時加上的標籤 | | priority | INT | 多規則同時符合時的套用順序 | | enabled | BOOLEAN | 規則是否啟用 | ## 七、非功能性需求 - **冪等性**:同一筆來源資料因排程重疊或批次重跑而被處理多次,寫入資料庫 B 的結果不應產生重複紀錄。 - **可觀測性**:每次批次執行需留下可查詢的執行紀錄(開始/結束時間、讀取筆數、成功/失敗筆數、失敗清單摘要),供事後追蹤。 - **效能**:單次批次資料量可能達數萬筆,讀取與寫入都須採分頁或批次處理,避免一次性載入全部資料到記憶體。 - **例外處理與重試**:資料庫 A 或 B 連線中斷時,該批次標記失敗並保留水位不前進,等待下次排程自動重試,不需要額外的人工介入機制(v1 階段)。 - **環境隔離**:資料庫 A、B 的連線帳號密碼採環境變數或外部設定檔管理,不可寫死在程式碼或提交進版本控制。 ## 八、技術棧(配合系列程式碼慣例) - **語言與框架**:Java 21、Spring Boot - **排程**:Spring Scheduler(`@Scheduled`),cron 表達式由設定檔提供 - **建置工具**:Maven - **測試**:JUnit 5,涵蓋貼標規則比對邏輯與水位計算的單元測試 - **資料存取**:Spring Data JPA 或 JdbcTemplate,需設定雙資料來源(來源 A、目的 B 各自獨立的 DataSource 設定) ## 九、已知問題與待確認事項(可作為後續 Codex 任務素材) - 現有雛型程式的貼標規則比對邏輯,遇到 `match_pattern` 含全形符號(例如全形括號、全形逗號)時比對會失敗,目前沒有對應的單元測試涵蓋這個案例。 - 排程重疊執行時(前一批次尚未跑完,下一次排程又被觸發)目前沒有鎖定機制,可能造成同一筆資料被兩個批次同時讀取與寫入。 - 貼標規則表 `tagging_rules` 由誰維護、多久更新一次、是否需要介面讓資料工程團隊自行調整,尚未確認,v1 階段暫時直接以資料表紀錄管理。 - 正式環境中資料庫 A、B 之間的網路存取是否有 VPN 或白名單限制,尚未與維運團隊確認。 - 資料庫 B 寫入完成後,是否需要主動通知下游系統資料已更新,尚未確認,v1 階段先不處理。 ## 十、附註 本文件的系統流程、資料規格與技術棧段落已由技術端初步規格化,可直接作為開發起點;同時刻意保留一筆已知邏輯缺陷(全形符號比對失敗)與數項待確認事項,供後續系列文章使用。Day 10~16 會以本案例示範:如何撰寫 AGENTS.md 讓 Codex 讀懂這個雙資料庫批次程式的專案慣例、如何把「全形符號比對失敗」包裝成 issue 交給 Codex 執行第一個修 bug 任務、如何解讀 Codex 執行測試後的紀錄與 diff、資料庫存取涉及的網路與權限邊界如何在 Codex 的沙箱環境中設計,以及 Codex 如何自動建立分支、commit 並產出 PR 草稿。