FR-121 子卡 .6,.1~.5 已全部驗收通過後的最後一張。決策者裁「這次就修」(進 b4)。來源:CM-2254/CM-2257 首腦裁示——api_logs/system_logs 的 act_time 是月分割鍵,PostgreSQL 不准改型別,要重建母表。
全庫只剩兩張操作紀錄表的「操作時間」還是沒帶時區的欄位,因為它是按月分割的分割鍵,資料庫不讓直接改型別。本卡照六月那支分割表 migration 的手法,建一張帶時區的新母表、依既有分區範圍建月分區、把資料搬過去、換名字、更新自動建分區的函式,最後把守衛測試的例外拿掉。做完全庫沒有任何一欄要猜時區。
public.api_logs RANGE (act_time) timestamp without time zone;DEV 7 分區(2026_06~2026_08+default),20,479 列;190 5,400 列
public.system_logs RANGE (act_time) 同上;DEV 3,154 列;190 91 列
函式 public.maintain_log_partitions() 自動建下月分區(pg_cron 未接,留著給排程接)
前例:BE scripts/sql/2026-06-03-log-tables-partitioning.sql(建 _p 新母表 → DO 迴圈建分區 → INSERT SELECT → RENAME swap → 舊表留 _old)
act_time 舊值:本地寫入(Asia/Taipei),與 created_at 同源
守衛:BE test/test_no_naive_timestamp_columns.py 例外清單目前放行這兩欄(含分區);第二條測試會在母表改好時要求拿掉例外
序列化:act_time 相關 serializer 仍是舊格式,CM-2257 刻意保留
scripts/sql/2026-09-27-fr121-log-act-time-timestamptz.sql(照 sql-migration 規範,只套 DEV):對兩張表各做——① CREATE TABLE public.api_logs_p (LIKE public.api_logs INCLUDING ALL) 後 ALTER COLUMN act_time TYPE timestamptz(或直接宣告欄位)並 PARTITION BY RANGE (act_time);② 依 pg_inherits 讀既有分區的範圍,用台北月初建對應分區(FROM '2026-06-01 00:00+08' TO '2026-07-01 00:00+08')+ DEFAULT;③ INSERT INTO api_logs_p SELECT ... , act_time AT TIME ZONE 'Asia/Taipei' ...(逐欄列名,act_time 轉、created_at 已是 timestamptz 直接搬);④ 序列/索引/GRANT 比照前例補齊(GRANT ... TO cm_app);⑤ RENAME swap,舊表留 _old 一版;⑥ 重寫 maintain_log_partitions() 用 timestamptz 邊界(台北月初);⑦ INSERT schema_migrations。整支 --single-transaction。api_log.py/system_log.py 的 act_time 改 DateTime(timezone=True)、寫入端改 aware UTC;相關 serializer 的 act_time 改 DisplayDateTime(CM-2257 保留的那幾支,git grep act_time -- '*serializer*')。test_no_naive_timestamp_columns.py 例外清單清空(第二條測試應轉綠)。maintain_log_partitions、保存期限清理(若有)——git grep act_time 全 BE+jedi-log 逐處確認比較語意不變。_old 的處理:本卡留著;回寫註明「b4 上 190 驗過操作紀錄頁後,下一版 migration 刪 _old」。pg_get_partkeydef 顯示 act_time 為 timestamptz;分區數與套前相同+筆數逐表相等(20,479/3,154);抽三筆同 id 對照 act_time 台北顯示與套前相同;連線改 UTC 讀同瞬間。守衛兩條全綠;突變:在例外清單放回 api_logs → 第二條「例外過期」必紅。maintain_log_partitions() 手動呼叫一次,建出的下月分區邊界是台北月初(\d+ api_logs_2026_10 看 FOR VALUES)。/Users/chouraymond/Projects/Jedicogy/module/jedi-python-package/.claude/worktrees/jedi-wt-fix-security/jedi-integrity:/Users/chouraymond/Projects/Jedicogy/module/jedi-python-package/.claude/worktrees/jedi-wt-fix-security/jedi-compliance-audit:/Users/chouraymond/Projects/Jedicogy/module/jedi-python-package/.claude/worktrees/jedi-wt-fix-security/jedi-common:/Users/chouraymond/Projects/Jedicogy/module/jedi-python-package/.claude/worktrees/jedi-wt-fix-security/jedi-log。.env。190 只讀。