Skip to content

[#489] Set up Farcaster notification system#498

Merged
realproject7 merged 2 commits intomainfrom
task/489-farcaster-notifications
Mar 24, 2026
Merged

[#489] Set up Farcaster notification system#498
realproject7 merged 2 commits intomainfrom
task/489-farcaster-notifications

Conversation

@realproject7
Copy link
Copy Markdown
Owner

Summary

  • Supabase migration (00021_notification_tokens.sql): notification_tokens table with FID primary key, token, URL, enabled flag
  • Server lib (lib/notifications.server.ts): Token CRUD + sendNotification() with batching (100/request), URL grouping, invalid token cleanup. Includes notifyNewPlot() trigger.
  • Webhook route (/api/webhook/notifications): Handles miniapp_added, miniapp_removed, notifications_enabled, notifications_disabled events with @farcaster/miniapp-node signature verification via Neynar
  • Save-token endpoint (/api/notifications/save-token): Client-side belt-and-suspenders token save from addMiniApp() result
  • FarcasterMiniApp update: Saves notification details from addMiniApp() result and from existing context for returning users
  • Manifest: Added webhookUrl to farcaster.json

Fixes #489

Operator items

  • Run migration 00021_notification_tokens.sql on Supabase
  • Set NEYNAR_API_KEY in Vercel env vars for webhook signature verification
  • Wire notifyNewPlot() into the backfill cron when new plots are indexed

Test plan

  • Build passes
  • Webhook receives events from Farcaster (test with Warpcast)
  • Token saved on miniapp_added / notifications_enabled
  • Token disabled on miniapp_removed / notifications_disabled
  • notifyNewPlot() sends notification to all enabled users
  • Invalid tokens cleaned up on send failure

🤖 Generated with Claude Code

- Add notification_tokens Supabase migration (fid, token, url, enabled)
- Add notifications.server.ts with token management + sendNotification
  (batches up to 100, groups by URL, cleans invalid tokens)
- Add webhook route for Farcaster miniapp events (added/removed/enabled/disabled)
  with parseWebhookEvent + Neynar signature verification
- Add save-token API for client-side belt-and-suspenders token save
- Update FarcasterMiniApp to save notification details from addMiniApp() result
  and from existing context for returning users
- Add webhookUrl to farcaster.json manifest
- Add notifyNewPlot() trigger for new plot published notifications

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
plotlink Ignored Ignored Mar 24, 2026 11:36am

Request Review

Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

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

LGTM. Full notification pipeline: clean migration (FID PK, partial index on enabled), server lib with batching/URL grouping/invalid token cleanup, webhook with Neynar signature verification, client-side belt-and-suspenders save, and notifyNewPlot() trigger. Matches Dropcast pattern.

Security note (non-blocking): /api/notifications/save-token is unauthenticated — an attacker could overwrite a user's notification token by POSTing an arbitrary FID. Since the webhook is the primary verified path and will correct tokens on subsequent events, the window is narrow. Consider adding authentication (e.g. verify Farcaster context or rate-limit by IP) in a follow-up.

Minor: The webhook falls back to no-verification when NEYNAR_API_KEY is unset — the console.warn is appropriate, but ensure the key is set before going live.

Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

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

Verdict: REQUEST CHANGES

Summary

The notification pipeline covers a lot of ground, but it currently ships with a fail-open verification path and still does not wire any notification trigger into live PlotLink flows.

Findings

  • high src/app/api/webhook/notifications/route.ts:22 falls back to valid: true parsing when NEYNAR_API_KEY is unset, which means anyone who can hit the webhook can forge miniapp_added / notifications_enabled events and write arbitrary notification tokens into the database. This needs to fail closed, not silently disable signature verification.
    • File: src/app/api/webhook/notifications/route.ts:22
    • Suggestion: reject webhook requests when NEYNAR_API_KEY is missing, or otherwise require real signature verification in all environments that can receive external traffic.
  • medium lib/notifications.server.ts:164 defines notifyNewPlot(), but nothing in the PR actually calls it. The PR description even lists wiring it into the backfill cron as an operator follow-up, so #489's acceptance criterion of "at least one notification trigger implemented" is not met yet.
    • File: lib/notifications.server.ts:164
    • Suggestion: invoke notifyNewPlot() from the actual new-plot indexing/publish path in this PR, so there is one end-to-end trigger implemented rather than just a helper left unused.

Decision

Request changes because the webhook currently accepts unsigned events when misconfigured and the PR does not yet implement a live notification trigger.

…to backfill

- Webhook now returns 503 when NEYNAR_API_KEY is missing instead of
  accepting unverified events
- notifyNewPlot() called from backfill cron after StorylineCreated
  (genesis) and PlotChained events are indexed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@project7-interns project7-interns left a comment

Choose a reason for hiding this comment

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

Verdict: APPROVE

Summary

The follow-up revision closes the two blocking gaps: the webhook now fails closed when signature verification cannot run, and the new-plot notification helper is wired into the live backfill/indexing flow.

Findings

  • None.

Decision

Approve because the previously requested security and trigger-implementation fixes are now in place, so #489 is complete from code review.

@realproject7 realproject7 merged commit 713b230 into main Mar 24, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Set up Farcaster notification system — review Dropcast pattern

2 participants