Summary
The community has no way to know when interesting things happen. Add a lightweight notification system covering the two highest-value events — invite usage and new community events — surfaced as an in-app badge plus an opt-in email digest.
Depends on #20 (Resend) for the email side.
Expected Behavior
- New table
notifications(id, recipient, type, payload, created_at, read_at).
- Notifications generated server-side when:
- Someone registers using your invite token (notify the inviter).
- A community event is created (notify all members).
- AppBar gets a bell icon with an unread count badge.
- Clicking it opens a dropdown listing recent notifications with click-through links (e.g. to the event).
- Profile page exposes a "Daily digest email" toggle — when on, Resend job sends a once-a-day summary of unread notifications.
Proposed Approach
- Add
notifications table and helper createNotification(recipient, type, payload).
- Wire
createNotification into the register handler (server/index.js:209) and event-create handler (server/index.js:1076).
- Add
GET /api/notifications (auth) and POST /api/notifications/:id/read.
- Frontend: bell icon in
Layout.jsx, dropdown component, polling every 60s while tab is focused.
- Daily digest: cron-style scheduled task on the server (or external cron hitting an admin endpoint), iterate users with
digest_enabled = 1 and unread notifications, send via Resend.
Acceptance Criteria
Summary
The community has no way to know when interesting things happen. Add a lightweight notification system covering the two highest-value events — invite usage and new community events — surfaced as an in-app badge plus an opt-in email digest.
Depends on #20 (Resend) for the email side.
Expected Behavior
notifications(id, recipient, type, payload, created_at, read_at).Proposed Approach
notificationstable and helpercreateNotification(recipient, type, payload).createNotificationinto the register handler (server/index.js:209) and event-create handler (server/index.js:1076).GET /api/notifications(auth) andPOST /api/notifications/:id/read.Layout.jsx, dropdown component, polling every 60s while tab is focused.digest_enabled = 1and unread notifications, send via Resend.Acceptance Criteria