feat: admin-customizable social share messages and share image#340
feat: admin-customizable social share messages and share image#340tnrdd wants to merge 2 commits into
Conversation
Add a Social tab to the Flow Council admin panel (between Communications
and UI) where round admins configure share posts for voters and donors:
- Named social accounts with per-platform X/Farcaster handles (URL or bare
handle, normalized; up to 10 per round)
- Vote and donation message templates with @[Account]/{round name}/{round
link} tokens, resolved per platform at draft time (tokens are references)
- Live per-platform counters (X 280 with links as 23 chars; Farcaster 320
with the link as an embed) and save blocking when over limit
- Preview on X / Cast to Farcaster buttons opening the real composers
- Per-round share image overriding the OpenGraph card everywhere links
unfurl, with best-effort replacement of the prior object in S3
- Remove the Post on Lens share option from both surfaces
- Copyright Complaints section on /terms and a public-content disclosure
on /privacy
Config lives under Round.details JSON (no migration); saving uses the
existing round-admin authorization.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Gaston Review
Verdict: Approved
Score: ████████░░ 8/10
Pull Request Summary
This PR adds an admin-facing "Social" tab to the Flow Council launchpad, letting round operators customize post-vote and post-donation share messages (with @mention tokens, {round name}, {round link}), configure per-platform handles (X + Farcaster), and upload a custom OG share image. It removes the Lens share option, adds server-side character-limit enforcement per platform, wires up OG metadata on the round page, updates privacy/terms for the new UGC, and includes thorough integration and unit tests.
Review Summary
🟡 Warning — Double error swallowing on S3 delete hides failures
deleteObjectByPublicUrl (s3.ts:26-29) catches and logs S3 errors internally without re-throwing. The outer try/catch in route.ts:273-276 is therefore dead code — it can never fire. This means any non-S3 errors thrown between retrieving previousShareImageUrl and calling deleteObjectByPublicUrl would also be silently swallowed. Either remove the inner catch and let the outer one handle it, or remove the outer catch since the inner one already handles it. The test 'succeeds when the old-image S3 delete fails' passes only because it mocks the entire function to reject, bypassing the inner try/catch.
🔵 Suggestion — generateMetadata imports db directly from API layer
The round page (page.tsx) imports db from @/app/api/flow-council/db to power generateMetadata. This works in Next.js Server Components, but it couples the page layer directly to the API's internal database module. If the round metadata fetching logic (already implemented in fetchRoundMetadata.ts) were extended with a server-side variant, you'd avoid this cross-layer dependency. Not blocking since it works, but worth noting for future maintainability.
Solid, well-structured feature. Security considerations are handled properly — S3 deletes scoped to the caller's own prefix, admin auth reused from existing infra, server-side character-limit enforcement, Zod schema validation. Test coverage is excellent, especially the edge cases around handle normalization, image lifecycle, and cross-platform mention resolution. A few minor items below but nothing blocking.
📌 5 inline comments
🟡 Warning: 2 · 🔵 Suggestion: 2 · ⚪ Nitpick: 1
🔍 Reviewed by Gaston
…thorized round PATCH - s3.ts deleteObjectByPublicUrl no longer swallows errors internally; the rounds PATCH is the single best-effort catch site (removes the dead double-catch flagged in review) - return HTTP 403 instead of 200 for the not-found/not-authorized round PATCH response so res.ok reflects the failure
There was a problem hiding this comment.
Gaston Review
Verdict: Approved
Score: ████████░░ 8/10
Pull Request Summary
This PR adds an admin-facing "Social" tab for customizing post-vote and post-donation share messages with @mention tokens, per-platform handles (X + Farcaster), and a custom OG share image. It removes the Lens share option, adds server-side character-limit enforcement, wires up OG metadata on the round page, updates privacy/terms for the new UGC, and includes thorough tests. The latest commit addresses my two prior review findings: the double error-swallowing on S3 deletes (now a single try/catch in the route) and the missing 403 status on unauthorized PATCH responses.
Both fixes from my prior review are clean and correct. deleteObjectByPublicUrl now throws naturally and the route's single try/catch handles it as best-effort — exactly what I asked for. The 403 on the "not found or not authorized" response is in place. The remaining prior items (cross-layer db import, orphan-on-PATCH-failure, module-level regex) were suggestions/nitpicks and don't block. This is production-ready.
🔍 Reviewed by Gaston
What this does
Adds a Social tab to the Flow Council admin panel (between Communications and UI) so round admins can put their own voice and @Handles into the share posts voters and donors see, replace the default link-preview image per round, and drop the Post-on-Lens option.
Config lives under
Round.detailsJSON, so existing rounds need zero migration and unconfigured rounds keep today's behavior (minus Lens). Saving uses the same round-admin authorization as the other tabs.Admin capabilities
@[Account],{round name},{round link}resolved per platform at draft time. Tokens are references, so editing a handle later updates future posts. Clearing a message reverts to the default.Voter/donor surface
Post to X and Cast to Farcaster after voting or opening a donation stream, with the admin's message and per-platform handles. Lens is removed from both surfaces for all rounds.
Legal
/terms: Copyright Complaints section (report → review → remove, repeat-infringer clause) plus an explicit content-removal right./privacy: "Content you publish through the Services" disclosure. Both re-dated. (Counsel review is a separate ops step per the spec.)Testing
socialShare,validation,images/routesuites cover token resolution per platform, char counting, handle normalization, theshare-imageupload cap).Review + hardening
Full multi-dimension review (correctness, perf, security, design, spec-compliance). Findings fixed and re-verified by the raising reviewer:
share-images/<caller-address>/keys; re-verified closed against both exploit variants.shareImageUrl, scheme-less URL pastes, upload/PATCH sequencing, zod kept out of the client bundle, object-URL memo/revoke, the Next button and disabled-state consistency).Ops
s3-uploadsIAM user was missings3:DeleteObject; the grant was added (scoped toflow-councils/share-images/*) and verified with a real put/delete round-trip, so replaced images are actually cleaned up.