E5 — Engagement#110
Conversation
Add /inbox page surfacing subscription_inbox feed and an unseen-count badge in the header so subscribed viewers see new uploads from creators they follow. Closes the visible gap in the E5 engagement loop — backend (comments, likes, subscriptions DO fan-out, og-meta share, reports) were already in place; this wires the in-app notification surface. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR. |
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (14)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3ca1b1e43f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return () => { | ||
| cancelled = true; | ||
| }; | ||
| }, []); |
There was a problem hiding this comment.
Refresh inbox badge after seen-state changes
The badge count is fetched only once on initial mount (useEffect(..., [])), but AppHeader/HeaderNav stay mounted while users navigate routes, so actions like Mark all seen on /inbox do not update the badge. In practice, a user can clear their inbox and still see a stale unseen count until a full page reload, which makes the new notification surface inconsistent with backend state.
Useful? React with 👍 / 👎.
…ALO-124) Layered on top of the prior 3ca1b1e inbox UI commit. Closes the rest of the E5 done criterion: subscribed viewers now also receive a daily digest email, and the OG share preview never falls back to the static icon.png even when a video has no thumbnail. Email digest - inbox-digest.ts groups unseen rows per recipient, renders an HTML digest, and sends via the existing Resend client. Stamping digest_sent_at keeps the sweep idempotent across retries; seen rows are never re-mailed. - Hooks into the existing daily cron in index.ts; admin-only manual trigger at POST /api/admin/inbox/digest/run for catch-up. - 0019_inbox_email_digest.sql adds digest_sent_at + a partial index over pending rows; schema.sql mirrors subscription_inbox so fresh setups don't need the prior migration replay. OG share card - /api/og/video/:id.svg renders a 1200×630 SVG card with the title + channel name; cached in KV and at the edge. - og-meta.ts now falls back to this card when a video has no thumbnail (still encoding, very old upload), so social previews always surface the video's title + channel. Header badge polish - InboxLink uses the dedicated /api/users/me/inbox/unseen-count endpoint instead of fetching the full feed for the count, polls only when the tab is visible, and styles the badge with the accent token to match the rest of the header. Inbox page - All / Unseen filter tabs, mark-all-seen action, and an empty state that's distinct between filters. 528 tests passing, lint + type-check clean.
|
ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR. |
Closes ALO-124.
The E5 engagement loop's backend pieces were already shipped piecewise across earlier tickets:
src/workers/comments.tssrc/workers/likes.tssrc/workers/{subscriptions,channel-do}.ts+subscription_inboxtablesrc/workers/og-meta.tssrc/workers/moderation.ts+reportstableThis PR closes the remaining gaps so the done criterion holds end-to-end ("a subscribed viewer is notified when a creator they follow uploads, can comment, like, and share").
In-app inbox UI
/inboxpage (auth-required) listing uploads from subscribed channels, with All / Unseen filter tabs and a "mark all seen" action.Inboxlink with a live unseen-count badge backed by a dedicated/api/users/me/inbox/unseen-countendpoint; polls only while the tab is visible so we're not hammering D1 from background tabs.Email digest
src/workers/inbox-digest.tsrolls up unseensubscription_inboxrows per recipient and sends a branded HTML digest via the existing Resend client.digest_sent_atkeeps the sweep idempotent across re-runs; seen rows are never re-mailed.src/workers/index.ts. Admin-only manual trigger atPOST /api/admin/inbox/digest/runfor catch-up.0019_inbox_email_digest.sqladdsdigest_sent_at+ a partial index over pending rows;schema.sqlmirrorssubscription_inboxso fresh setups don't need the prior migration replay.OG share card
/api/og/video/:id.svgrenders a 1200×630 SVG card with the title + channel name; cached in KV and at the edge.og-meta.tsnow falls back to this card when a video has no thumbnail (still encoding, very old upload), so social previews always surface the video's title + channel instead of the static/icon.png.Test plan
npm test— 528 passing (47 files)npm run lint— 0 findings (oxlint + AI Gateway guard)npm run type-checknpm run build/inbox./api/og/video/<id>.svgfor a known video and confirm SVG renders with correct title + channel.POST /api/admin/inbox/digest/run; confirm Resend delivery and thatdigest_sent_atwas stamped.🤖 Generated with Claude Code