Skip to content

E5 — Engagement#110

Open
aloewright wants to merge 2 commits into
mainfrom
conductor/alo-124-e5-engagement
Open

E5 — Engagement#110
aloewright wants to merge 2 commits into
mainfrom
conductor/alo-124-e5-engagement

Conversation

@aloewright
Copy link
Copy Markdown
Owner

@aloewright aloewright commented May 8, 2026

Closes ALO-124.

The E5 engagement loop's backend pieces were already shipped piecewise across earlier tickets:

  • Comments + nested replies (D1, moderation hooks): src/workers/comments.ts
  • Likes / reactions: src/workers/likes.ts
  • Channel subscriptions with Durable Object fan-out: src/workers/{subscriptions,channel-do}.ts + subscription_inbox table
  • OG meta tags for share-to-social: src/workers/og-meta.ts
  • Report / flag content: src/workers/moderation.ts + reports table

This 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

  • New /inbox page (auth-required) listing uploads from subscribed channels, with All / Unseen filter tabs and a "mark all seen" action.
  • Header Inbox link with a live unseen-count badge backed by a dedicated /api/users/me/inbox/unseen-count endpoint; polls only while the tab is visible so we're not hammering D1 from background tabs.

Email digest

  • src/workers/inbox-digest.ts rolls up unseen subscription_inbox rows per recipient and sends a branded HTML digest via the existing Resend client.
  • Stamping digest_sent_at keeps the sweep idempotent across re-runs; seen rows are never re-mailed.
  • Hooks into the existing daily cron in src/workers/index.ts. Admin-only manual trigger at POST /api/admin/inbox/digest/run for catch-up.
  • Migration 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 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-check
  • npm run build
  • Manual: subscribe to a channel, upload a video as that channel, confirm inbox badge increments and item appears at /inbox.
  • Manual: hit /api/og/video/<id>.svg for a known video and confirm SVG renders with correct title + channel.
  • Manual: as admin, POST /api/admin/inbox/digest/run; confirm Resend delivery and that digest_sent_at was stamped.

🤖 Generated with Claude Code

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>
Copilot AI review requested due to automatic review settings May 8, 2026 14:58
@aloewright aloewright added the conductor Conductor-managed PR label May 8, 2026
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 8, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Warning

Rate limit exceeded

@aloewright has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 31 minutes and 9 seconds before requesting another review.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 046aa529-c03e-4f2b-9b73-7d421ae7161a

📥 Commits

Reviewing files that changed from the base of the PR and between 4d3c13f and e3ea817.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (14)
  • src/db/migrations.test.ts
  • src/db/migrations/0019_inbox_email_digest.sql
  • src/db/schema.sql
  • src/frontend/App.tsx
  • src/frontend/pages/Inbox.tsx
  • src/workers/inbox-digest.test.ts
  • src/workers/inbox-digest.ts
  • src/workers/index.ts
  • src/workers/og-image.test.ts
  • src/workers/og-image.ts
  • src/workers/og-meta.test.ts
  • src/workers/og-meta.ts
  • src/workers/subscriptions.test.ts
  • src/workers/subscriptions.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch conductor/alo-124-e5-engagement

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread src/frontend/App.tsx
return () => {
cancelled = true;
};
}, []);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

…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-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 9, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conductor Conductor-managed PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants