Skip to content

advertise publish time, not create time, for published drafts

jedmund requested to merge jedmund/publish-time into main

Created by: jedmund

Summary

A draft post held for two months and then published was advertising the February create time, not the May publish time, on the public site and in RSS. Two underlying bugs:

  • Posts — the draft → published handler had an !existing.publishedAt guard that silently kept any stale value. There was also a footgun in PATCH where a request-body publishedAt could override the status-driven assignment.
  • Albums — no publishedAt transition logic in the PUT handler at all. The universe feed and /rss + /rss/photos hard-coded createdAt as the public timestamp.

This PR brings everything in line with the existing Garden pattern: every draft → published transition stamps publishedAt = now; revert to draft clears it. Display side now reads publishedAt (with a createdAt fallback for legacy rows).

Changes

  • posts/[id] PUT + PATCH: drop the !existing.publishedAt guard, add clear-on-revert in PUT, remove the publishedAt override in PATCH.
  • albums/[id] PUT: add the missing publishedAt transition logic.
  • /api/universe: select album publishedAt, use album.publishedAt ?? album.createdAt, order by [publishedAt, createdAt].
  • /rss + /rss/photos: same album fallback + order.
  • New migration 20260501000000_backfill_album_published_at: adds the Album.publishedAt column (it was in schema.prisma but never had an ADD COLUMN migration) and backfills publishedAt = createdAt for existing published albums so they keep their currently-displayed date.

One thing to handle manually

The specific Feb-drafted post that triggered this still has the wrong publishedAt in the DB. Once this ships, easiest fix is to revert it to draft in admin and republish — the new logic will stamp a fresh time. Or run a one-off UPDATE "Post" SET "publishedAt" = ... WHERE id = ....

Test plan

  • npm run check — no new errors in touched files
  • Draft a post, leave it for a moment, publish via StatusDropdown — publishedAt is now, distinct from createdAt. Public page + /rss show the publish time.
  • Revert the post to draft — publishedAt clears in admin metadata. Republish — fresh timestamp (not the previous publish, not create).
  • Edit a published post without changing status — updatedAt bumps, publishedAt unchanged.
  • Same flow for an Album — universe card + /rss + /rss/photos reflect publish time.
  • Run npx prisma migrate deploy against a fresh DB to confirm the migration applies cleanly (column add + backfill).

Merge request reports

Loading