refactor(domain): introduce the Feed aggregate as the write-path API

Add a Feed aggregate class owning config + the email index, with create,
ingest, removeEmails, isExpired and accepts delegating to the existing
pure invariant functions. FeedRepository gains load/save/saveMetadata
that reconstitute and persist the aggregate.

All write paths now go through it: createFeedRecord (Feed.create),
email ingestion (feed.ingest), and every email deletion in the admin UI
and REST API (feed.removeEmails) — no route mutates metadata.emails
directly anymore. KV key strings unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Julien Herr
2026-05-24 00:33:14 +02:00
parent a31ff42f59
commit c45f6677fe
8 changed files with 415 additions and 131 deletions
+4
View File
@@ -815,6 +815,10 @@ describe("Admin Routes", () => {
"feeds:list",
JSON.stringify({ feeds: [{ id: feedId, title: "F" }] }),
);
await r2Env.EMAIL_STORAGE.put(
`feed:${feedId}:config`,
JSON.stringify({ title: "F", language: "en", created_at: 1 }),
);
const emailKey = `feed:${feedId}:1`;
await r2Env.EMAIL_STORAGE.put(
emailKey,