diff --git a/backend/app/jobs/notifications.py b/backend/app/jobs/notifications.py index 5b7cbf6..cd3099e 100644 --- a/backend/app/jobs/notifications.py +++ b/backend/app/jobs/notifications.py @@ -103,6 +103,12 @@ async def _dispatch_events(db: AsyncSession, settings: Settings, now: datetime) and_( CalendarEvent.start_datetime >= now, CalendarEvent.start_datetime <= window_end, + # Exclude recurring parent templates — they duplicate the child instance rows. + # Parent templates have recurrence_rule set but no parent_event_id. + ~and_( + CalendarEvent.recurrence_rule != None, # noqa: E711 + CalendarEvent.parent_event_id == None, # noqa: E711 + ), ) ).options(selectinload(CalendarEvent.location)) ) diff --git a/frontend/src/components/layout/LockOverlay.tsx b/frontend/src/components/layout/LockOverlay.tsx index cec2cd6..281faf7 100644 --- a/frontend/src/components/layout/LockOverlay.tsx +++ b/frontend/src/components/layout/LockOverlay.tsx @@ -56,7 +56,7 @@ export default function LockOverlay() { }; return ( -