Resolve each feed's most recent sender domain and serve its favicon at
GET /favicon/:feedId, falling back to the project icon. Icons are fetched
in the background on ingestion (direct /favicon.ico then a DuckDuckGo
fallback), cached base64 in KV keyed by domain with a 1-week TTL so the
fetch only fires when absent. Exposed via RSS <image> / Atom <icon>/<logo>
and rendered in the admin feed list, plus a landing-page feature card.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Serve an inline SVG icon at /favicon.svg and /favicon.ico and link it
from the shared Layout and the standalone entry view, so the admin UI,
status page, and entry pages stop emitting /favicon.ico 404s. Doubles
as the fallback for the upcoming per-feed favicon feature.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add backlog items for a project favicon (also used as the per-feed
fallback), per-feed favicons resolved from the last sender's domain with
aggressive caching, and RFC 8058 one-click unsubscribe on feed deletion.
Include a detailed design breakdown for the per-feed favicon feature.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- docs/index.html: nav links (Features/How it works/Install), hero CTAs
(Try demo primary, Self-host, GitHub), demo banner with credentials,
full 7-step installation section with WAF rate limiting guide (dashboard
+ Terraform) integrated as step 7
- wrangler-example.toml: cron trigger on demo env for nightly KV reset at 03:00 UTC
- src/index.ts: scheduled handler that wipes all EMAIL_STORAGE KV keys
- TODO.md: mark WAF rate limiting as done
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
P1-4, P2-10, P2-11 marked DONE in TECH_DEBT.md.
P1-5 (rate limiting) is infrastructure-only — documented in TODO.md with
the recommended Cloudflare WAF rule targets and thresholds.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The race condition is an accepted limitation of KV; the DO migration
is a future feature rather than active tech debt to remediate.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Attachments from incoming emails are uploaded to an optional Cloudflare R2
bucket and exposed as <enclosure> elements in RSS and <link rel="enclosure">
in Atom feeds, served at /files/{id}/{filename} with immutable caching.
R2 is opt-in: if ATTACHMENT_BUCKET is not bound the feature is a no-op.
Attachments are cleaned up from R2 on email/feed deletion and during
size-based feed trimming. Adds MockR2 to the test setup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>