feat(blog): prune posts removed or renamed upstream

the blog repo is the source of truth for the full set of posts, but
upserts alone never delete: removing a file or changing a slug or
filename left the old row serving forever. each poll now reconciles —
after upserting the current tree, events under source='blog' whose id
is not in the parsed set are deleted via a new EventWriter::prune_events
port. nothing is lost: git still has every post, and restoring or
fixing a file re-ingests it on the next tip change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 22:56:54 +03:00
parent cd3dc2d82d
commit 37c44906bb
4 changed files with 33 additions and 1 deletions

View File

@@ -73,7 +73,7 @@ PostgreSQL with three migrations in `crates/moments-data/migrations/`. Two roles
All under `/v1/`: `healthz`, `events`, `sources`, `projects`, `blog`, `blog/{slug}`, `activity/daily`, `forge/{source}/*`, `og/contributions.png`.
Blog posts are markdown files with YAML frontmatter (`title`, `slug`, `date`; optional `draft`/`public`) in the `grenade/blog` Gitea repo. The worker's `BlogSource` polls the repo (branch-tip sha as change detection) and upserts posts into `events` with `source='blog'` and `occurred_at` from the frontmatter date, so imported posts keep their original publish dates. Publishing or editing a post = pushing to that repo.
Blog posts are markdown files with YAML frontmatter (`title`, `slug`, `date`; optional `draft`/`public`) in the `grenade/blog` Gitea repo. The worker's `BlogSource` polls the repo (branch-tip sha as change detection) and upserts posts into `events` with `source='blog'` and `occurred_at` from the frontmatter date, so imported posts keep their original publish dates. The repo is the source of truth for the full set of posts: publishing, editing, renaming, and deleting are all just pushes — each poll upserts the current tree and prunes `source='blog'` rows that are no longer in it.
## Deployment