開發紀錄
`authoredAt`、`publishedAt` 和 `updatedAt` 為什麼要分開
從目前的 Markdown schema、發布查詢與文章版型,說明撰稿、正式發布和後續更新三種日期各自回答什麼問題,以及為什麼不能互相代替。
- 內容工程
- Astro
- Markdown
- 發布流程
一篇文章至少會有三種時間:文字何時形成目前這個版本、何時可以公開、何時又被修訂。把它們全部寫進同一個日期,短期看起來比較簡單,後面卻無法區分草稿、正式文章和後續更新。
這個網站把 authoredAt、publishedAt 和 updatedAt 拆開,不是為了增加欄位,而是讓內容狀態有不同的工程邊界。主要判斷很直接:日期欄位應該描述不同的內容事件,不能拿一個日期去假裝完成另外兩種責任;而 authoredAt 也不能機械地等於檔案建立時間。
三個欄位各自回答什麼問題
目前的 schema 對三個欄位有不同責任:
| 欄位 | 它回答的問題 | 目前的使用方式 |
|---|---|---|
authoredAt |
這個撰稿版本在什麼情境下形成? | 可選;依可確認的寫作時間填寫,不用檔案 mtime 自動推定 |
publishedAt |
這篇文章從哪一個時間點開始符合正式輸出條件? | 正式文章必須填寫,發布查詢會用它判斷日期與排序 |
updatedAt |
這篇正式文章什麼時候被後續更新? | 可選;必須先有 publishedAt,而且不能早於發布日期 |
publishedAt 和 updatedAt 有值時使用 YYYY-MM-DDTHH:mm:ss+08:00;既有文章的 authoredAt 可以只記錄有證據支持的 YYYY-MM-DD 日期,之後由助手新寫的文章則在初稿完成時記錄實際台北時間到秒。三者實際上對應不同的流程節點,不代表可以互相替換;網頁上的可讀文字仍只顯示到日。
authoredAt 要跟著寫作情境走
authoredAt 應該描述文章撰稿版本形成的時間,不是作業系統替檔案留下的建立時間,也不是文章正在談的那段歷史事件時間。
這裡要分清楚三種日期:
- 如果文章是之後根據目前 repository 新寫的,
authoredAt在初稿完成時填實際台北日期時間到秒;這一批既有文章沒有可靠的秒級紀錄,因此仍保留日期。 - 如果文章原本就是較早完成的歷史稿,而且有舊草稿、對話或其他可確認紀錄,可以保留那個實際撰稿日期,讓文章留下長期寫作歷程。
- 如果只是今天重新整理一段很久以前發生的開發事件,不能把事件日期冒充成文章撰稿日期。事件時間應該寫在正文或證據說明裡;若沒有可靠的原始撰稿時間,就不要為了製造時間線而回填一個看似合理的日期。
因此,檔案建立日只能是線索,不能自動成為 authoredAt。日期是否適合公開,要看它代表的事件、證據和文章當時的寫作情境。
authoredAt 是編輯紀錄,不是公開資格
草稿可以先記錄 authoredAt,並預留 publishedAt: ''。空字串會被內容 schema 視為尚未填入發布日期,讓文章能在本機預覽裡顯示撰稿日期,同時不會因為 frontmatter 已經有這個 key 就被正式首頁、筆記列表或 sitemap 當成可發布內容。
目前 schema 對草稿的要求很小:只要 metadata 合法,draft 預設為 true,publishedAt 可以保持空白。這符合實際寫作流程,因為「文字已經有一個版本」和「內容已經獲准公開」不是同一件事。
如果把 authoredAt 當成發布日期,會出現一個危險的 fallback:文章只要寫完就像已經上線。這個網站刻意不做這件事。正式文章要把 draft 設為 false,同時填入真正的 publishedAt;schema 會拒絕只有前者、沒有後者的資料。
publishedAt 是公開查詢的邊界
正式輸出不是看到 Markdown 檔案就全部產生。getPublishedNotes 會交給同一個發布選擇器,只有同時符合以下條件的文章才會進入公開集合:
draft必須是false。publishedAt必須存在。publishedAt不得晚於以台北時區計算的今天。- 如果指定語言,文章的
locale必須相符。
符合條件後,文章依 publishedAt 的秒級時間由新到舊排序;只有時間完全相同時才用 stableId 維持穩定順序。這代表 publishedAt 不只是文章頁上顯示的一行日期,它同時影響首頁排序、列表內容、文章詳頁是否生成,以及 sitemap 是否列出網址。
未來日期也不是自動排程。靜態網站要在符合日期後重新建置,新的文章才會進入該次輸出。日期只提供判斷依據,不會自己觸發部署。
updatedAt 告訴讀者最近更新,不代表更新幅度
updatedAt 的責任比較窄:文章已經有正式發布日期,後來又需要記錄一次更新。schema 不允許沒有 publishedAt 的 updatedAt,也不允許更新日期早於發布日期。
文章版型會把 publishedAt 和 updatedAt 分開顯示。這讓讀者可以知道文章不是第一次發布,卻不會把更新日期誤認成原始發布日。
目前的 metadata 沒有另外記錄「改了哪些段落」或「這次更新是否改變主要判斷」。因此,updatedAt 能證明的是日期,不是更新內容的規模、影響或品質。若讀者需要知道改動原因,仍要在正文或其他公開紀錄中交代,不能由日期自行推導。
版型也要保留日期的差異
日期契約如果只停留在 schema,讀者仍可能在頁面上看到混在一起的資訊。目前文章版型依照狀態分開處理:
- 正式文章顯示
publishedAt。 - 有後續更新時,再另外顯示
updatedAt。 - 本機預覽的草稿沒有
publishedAt時,顯示authoredAt,並標示這是預覽日期。
同一個日期欄位不應該因為頁面不同就換一個意思。預覽是在幫作者校稿,正式頁是在告訴讀者公開狀態;兩者使用的日期來源可以不同,但標籤和責任要保持清楚。
寫稿時可以照這個順序檢查
- 先判斷
authoredAt要代表哪一次撰稿:目前新寫的文章填實際起草日期;歷史稿只在有證據時保留原始日期;不要讀檔案 mtime 猜日期。 - 需要本機校稿時,使用預覽路由查看正文,不把草稿日期當成公開日期。
- 取得正式發布授權後,把
publishedAt: ''改成真正的YYYY-MM-DDTHH:mm:ss+08:00日期時間,再將draft改為false。 - 文章已發布後若再次修改,才考慮填寫不早於
publishedAt的updatedAt。 - 主題事件的日期另外放在正文或來源說明,不要拿它代替文章的撰稿日期。
- 不要從日期推論流量、搜尋排名、讀者反應或商業結果。
這樣拆分的好處不是讓 metadata 看起來更完整,而是讓每個日期都能回答一個明確問題。撰稿時間屬於編輯紀錄,發布時間決定公開資格,更新時間補充文章的新鮮度;三者分開,也才能分辨「文章何時寫成」和「文章正在描述哪一段歷史」。
紀錄範圍
本文根據目前的 note schema、發布選擇器、文章版型、既有測試與撰寫規範整理。它說明欄位契約與公開輸出邊界,不代表任何文章已經獲得發布授權,也沒有把日期欄位解讀成 SEO、流量或讀者成效指標。