Overview
Complete implementation of activity feed and in-app notifications system, including notification button in header, dedicated activity page, weekly digest emails, and all supporting infrastructure.
Features Implemented
1. Notifications Database Schema
Migrations:
supabase/migrations/20260119000000_create_notifications.sql- Creates notifications table with RLS policies and Realtime supportsupabase/migrations/20260119000001_optimize_notifications_rls.sql- Optimizes RLS policies using(select auth.uid())patternsupabase/migrations/20260119000002_add_notifications_dismissed.sql- Adds dismissed_at column for removing notifications from menusupabase/migrations/20260119100000_add_weekly_digest_email_type.sql- Adds weekly_digest email type for independent preference control
Schema:
notificationstable with user_id, actor_id, type, entity_type, entity_id, data (jsonb), seen_at, dismissed_at, created_at- Optimized RLS policies for performance
- Indexes for unseen notifications and active notifications
- Realtime enabled for live updates
2. Notification Types & Types System
File: src/types/notifications.ts
Defines TypeScript types:
NotificationType- like_photo, like_album, comment_photo, comment_album, comment_event, follow, event_reminder, event_announcement, admin_messageNotificationEntityType- photo, album, event, profile, systemNotificationData- JSON structure for notification metadataNotificationWithActor- Notification with joined actor profile dataNotificationActor- Derived from Profile using Pick utility type
3. Notification Creation & Management
File: src/lib/notifications/create.ts
createNotification()function using admin client to bypass RLS- Handles all notification types with proper data structure
File: src/lib/actions/notifications.ts
Server actions:
markNotificationAsSeen()- Mark single notification as seenmarkAllNotificationsAsSeen()- Mark all notifications as seendismissNotification()- Dismiss notification (removes from menu)createMockNotifications()- Dev utility for testing
File: src/lib/data/notifications.ts
Data fetching functions (using authenticated client for RLS):
getUnseenNotificationsCount()- Get count of unseen notificationsgetRecentNotifications()- Get last N notificationsgetTotalNotificationsCount()- Get total active notifications countgetAllNotifications()- Get all notifications for activity page
4. Notification API Routes
File: src/app/api/notifications/route.ts
- GET endpoint with pagination support (limit, offset)
- Returns notifications with actor data, unseen count, total count, hasMore flag
- Supports pagination for notification menus and activity page
File: src/app/api/cron/weekly-digest/route.ts
Weekly digest cron job:
- Fetches unseen notifications from past 7 days
- Groups by user
- Checks weekly_digest email preferences
- Sends batch emails (max 100 per batch per Resend limit)
- Includes unsubscribe links with weekly_digest type
5. Notification Components
File: src/components/notifications/NotificationButton.tsx
Desktop notification button in header:
- Bell icon with unseen count badge
- Dropdown menu showing last 20 notifications
- Pagination with "Load more" button
- Links to activity page
- Empty state with mock notification creation
File: src/components/notifications/MobileNotificationButton.tsx
Mobile notification button:
- Bottom sheet menu for notifications
- Always positioned left of avatar
- "View all notifications" button at bottom
- Pagination support
File: src/components/notifications/NotificationItem.tsx
Individual notification item:
- Shows thumbnail, actor avatar, or SVG icon based on notification type
- Keyboard accessible (tab, enter/space)
- Visual distinction for seen/unseen (left border, background tint)
- Click to view, dismiss button (only on activity page)
- Uses Heroicons SVG icons instead of emojis
6. Activity Page
File: src/app/account/activity/page.tsx
Server component:
- Authenticates user
- Fetches initial 40 notifications and total count
- Passes to client component
File: src/app/account/activity/ActivityContent.tsx
Client component:
- Groups notifications by date (Today, Yesterday, This week, Earlier)
- Card styling matching other pages
- "Mark all as seen" button
- Pagination with "Load more" (40 per page)
- Dismiss functionality
- Mock notification creation in empty state
7. Notification Hooks
File: src/hooks/useNotifications.ts
React hook for notification state management:
- Fetches notifications from API
- Manages pagination state
- Listens for custom
notifications:refreshevents - Realtime subscription disabled due to SSR hydration issues (uses custom events instead)
- Functions: markAsSeen, markAllAsSeen, dismiss, loadMore, refresh
8. Integration Points
File: src/components/layout/Header.tsx
- Integrated NotificationButton (desktop) and MobileNotificationButton (mobile)
- Notification button positioned left of avatar
File: src/components/layout/MobileMenu.tsx
- Added "Activity" link to mobile menu
File: src/lib/actions/likes.ts
- Triggers notifications for photo and album likes
- Self-notification checks:
photo.user_id !== user.idandalbum.user_id !== user.id
File: src/app/api/comments/route.ts
- Triggers notifications for comments on albums, photos, and events
- Self-notification checks:
ownerId !== user.id - Returns emailTypeKey instead of emailTypeLabel for unsubscribe route
9. Weekly Digest Email
File: src/emails/weekly-digest.tsx
React Email template:
- Lists up to 5 unseen notifications
- Shows total count
- Links to activity page
- Individual notification links to object pages
- Formatted dates in Amsterdam timezone
- Resized thumbnails using Supabase image transformation
- Unsubscribe link
File: vercel.json
- Added weekly digest cron job schedule
10. Email Preferences & Unsubscribe
File: src/utils/emailPreferencesClient.ts
- Added
'weekly_digest'to EmailType union - Functions for fetching and updating email preferences
File: src/app/unsubscribe/[token]/page.tsx
- Added
weekly_digest: 'the weekly digest'to emailTypeLabels - Improved wording for different email types
File: src/app/api/unsubscribe/route.ts
- Returns emailTypeKey for proper unsubscribe page display
11. UI Components & Styling
File: src/components/shared/BottomSheet.tsx
- Fixed backdrop filter animation by removing transition-opacity from parent container
- Allows backdrop's own opacity transition to animate smoothly
File: src/components/shared/Button.tsx
- Used for "View all notifications" link in mobile bottom sheet
File: src/components/shared/Comments.tsx
- Integrated notification creation for comments
12. Fixes & Improvements
Activity Page Empty State:
- Fixed by changing
createPublicClient()tocreateClient()in notification data functions - Ensures RLS policies work correctly with authenticated session
Realtime Subscription:
- Disabled due to SSR hydration issues in Next.js 16
- Uses custom event system (
notifications:refresh) instead - Notifications update via API polling and custom events
Activity Page Styling:
- Added card containers matching other pages
- Left border indicator for unseen notifications
- Proper empty state design
Self-Notification Prevention:
- Restored checks to prevent notifications for own actions
- Photo/album likes:
user_id !== user.id - Comments:
ownerId !== user.id
All Modified Files (36 total)
New Files (18)
supabase/migrations/20260119000000_create_notifications.sqlsupabase/migrations/20260119000001_optimize_notifications_rls.sqlsupabase/migrations/20260119000002_add_notifications_dismissed.sqlsupabase/migrations/20260119100000_add_weekly_digest_email_type.sqlsrc/app/account/activity/ActivityContent.tsxsrc/app/account/activity/page.tsxsrc/app/api/cron/weekly-digest/route.tssrc/app/api/notifications/route.tssrc/components/notifications/MobileNotificationButton.tsxsrc/components/notifications/NotificationButton.tsxsrc/components/notifications/NotificationItem.tsxsrc/emails/weekly-digest.tsxsrc/hooks/useNotifications.tssrc/lib/actions/notifications.tssrc/lib/data/notifications.tssrc/lib/notifications/create.tssrc/types/notifications.tschangelog/2026-01-19-2/commit-message.txtchangelog/2026-01-19-2/files-changed.md
Modified Files (18)
.cursorrulesREADME.mdsrc/app/api/comments/route.ts- Added notification creation, self-notification checks, emailTypeKey returnsrc/app/api/unsubscribe/route.ts- Returns emailTypeKeysrc/app/email/[template]/page.tsx- Email preview supportsrc/app/events/[eventSlug]/page.tsx- Notification integrationsrc/app/unsubscribe/[token]/page.tsx- Added weekly_digest label, improved wordingsrc/components/album/AlbumGrid.tsx- Notification integrationsrc/components/layout/Header.tsx- Added NotificationButton and MobileNotificationButtonsrc/components/layout/MobileMenu.tsx- Added Activity linksrc/components/shared/BottomSheet.tsx- Fixed backdrop animationsrc/components/shared/Button.tsx- Used in mobile notificationssrc/components/shared/Comments.tsx- Notification integrationsrc/database.types.ts- Updated with notifications table typessrc/lib/actions/likes.ts- Added notification creation, self-notification checkssrc/utils/emailPreferencesClient.ts- Added weekly_digest to EmailTypevercel.json- Added weekly digest cron schedule
Impact
- Complete activity feed and notification system implemented
- Real-time updates via custom events (Realtime disabled due to SSR issues)
- Users can view, mark as seen, and dismiss notifications
- Weekly digest emails with independent preference control
- Self-notification prevention for likes and comments
- Proper styling matching existing app design
- Keyboard accessible notification items
- Pagination support for large notification lists
- Mobile-friendly bottom sheet for notifications