Skip to content

[codex] Implement local notifications and inbox#107

Merged
Gamius00 merged 23 commits into
mainfrom
notifications
Jun 9, 2026
Merged

[codex] Implement local notifications and inbox#107
Gamius00 merged 23 commits into
mainfrom
notifications

Conversation

@FleetAdmiralJakob

@FleetAdmiralJakob FleetAdmiralJakob commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds on-device local notification preferences, scheduling, and in-app notification history for issue Whole notification system #93.
  • Adds the notification inbox, unread bell indicator, notification settings page, and app-wide notification sync.
  • Removes per-entry reminder controls and adds mark-as-completed flows for entries and learning-plan sessions.

Scope notes

This PR intentionally uses local scheduled notifications only. Server push notifications and per-event notification customization remain future work tracked separately.

The PR diff was checked against main and does not include the separate skill/context documentation changes.

Validation

  • pnpm check
  • pnpm test

Summary by CodeRabbit

  • New Features

    • Added comprehensive notification system with inbox, preferences, and customizable reminders including daily briefings and event notifications
    • Ability to mark individual day entries and learning plan sessions as complete
    • Notification settings screen for scheduling briefing times and configuring reminder offsets
  • UI/UX Improvements

    • Updated switch component implementation for consistent design across Android and iOS platforms
  • Documentation

    • Updated design system guidance for switch component usage

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1850ce60-7cfc-4d0b-94e7-f4bcd838f05f

📥 Commits

Reviewing files that changed from the base of the PR and between 1f4458f and aa97daf.

⛔ Files ignored due to path filters (2)
  • assets/dayova-notification-icon.png is excluded by !**/*.png
  • convex/_generated/api.d.ts is excluded by !**/_generated/**
📒 Files selected for processing (32)
  • app.config.ts
  • convex/dayEntries.test.ts
  • convex/dayEntries.ts
  • convex/notifications.test.ts
  • convex/notifications.ts
  • convex/schema.ts
  • docs/contexts/design-system/CONTEXT.md
  • src/app/(app)/home.tsx
  • src/app/(app)/settings.tsx
  • src/app/_layout.tsx
  • src/app/entry/[id].tsx
  • src/app/entry/new.tsx
  • src/app/learning-plans/[planId]/index.tsx
  • src/app/notification-settings.tsx
  • src/app/notifications.tsx
  • src/components/notification-button.tsx
  • src/components/notification-sync.tsx
  • src/components/ui/select-sheet.tsx
  • src/components/ui/switch.android.tsx
  • src/components/ui/switch.ios.tsx
  • src/components/ui/switch.tsx
  • src/components/ui/switch.types.ts
  • src/features/learning-plans/types.ts
  • src/lib/delivered-notification.test.ts
  • src/lib/delivered-notification.ts
  • src/lib/design-system.ts
  • src/lib/local-notification-scheduler.test.ts
  • src/lib/local-notification-scheduler.ts
  • src/lib/notification-planner.test.ts
  • src/lib/notification-planner.ts
  • src/lib/notification-preferences.test.ts
  • src/lib/notification-preferences.ts

📝 Walkthrough

Walkthrough

This PR implements a complete notification system for Dayova, spanning backend APIs, database schema, frontend screens, and background synchronization. It adds notification preferences, scheduling, delivery tracking, and user-facing inbox/settings UIs. It also refactors the switch component and adds completion toggles across the app.

Changes

Notification System Implementation

Layer / File(s) Summary
Notification schema and preference APIs
convex/schema.ts, convex/notifications.ts
Three new tables (notificationPreferences, localNotificationSchedules, notificationHistory) with queries for preferences, inbox listing, and unread counts; mutations to update preferences with time and offset validation.
Notification planning, scheduling, and delivery
src/lib/notification-planner.ts, src/lib/local-notification-scheduler.ts, src/lib/delivered-notification.ts, tests
Local notification plans generated from preferences and day entries; synchronization to device scheduler; delivered notification extraction and validation with ownership checks.
Local schedule registration and recording
convex/notifications.ts
Backend registration of client notification plans with SHA-256 fingerprinting, deduplication, collision detection, and entry ownership validation; idempotent delivery recording with time-window checks.
Due notification synchronization
convex/notifications.ts
Server-side sync creating daily briefing, before-event, and forgotten-event notifications based on preferences and time; idempotent notification history insertion.
Notification backend tests
convex/notifications.test.ts
Comprehensive coverage of preference defaults/updates, reminder offset deduplication, forgotten-event gating, inbox state transitions, cross-user access control, and daily briefing wording.
Notification settings screen
src/app/notification-settings.tsx
Settings UI with system notification toggle, permission/channel handling, optimistic preference updates, briefing time picker, and reminder offset selection.
Notifications inbox screen
src/app/notifications.tsx
Main notifications screen with category tabs, swipe-to-delete using reanimated worklets, warning banner for disabled system notifications, and inbox list rendering.
Background synchronization component
src/components/notification-sync.tsx, src/app/_layout.tsx
Top-level component coordinating local planning, backend sync, schedule registration, and reconciliation; handles permissions, Android channels, and app state listeners.
Notification button badge
src/components/notification-button.tsx
Displays unread count badge using Convex query with conditional skipping until authentication ready.
Entry and session completion toggles
convex/dayEntries.ts, src/app/(app)/home.tsx, src/app/entry/[id].tsx, src/app/learning-plans/[planId]/index.tsx, src/app/(app)/settings.tsx, src/app/entry/new.tsx
Adds completion mutation to dayEntries; updates home, entry detail, and learning plan screens with completion UI; removes inline notification toggle from settings.
Switch component and SelectSheet enhancements
src/components/ui/switch.tsx, src/components/ui/switch.android.tsx, src/components/ui/switch.ios.tsx, src/components/ui/switch.types.ts, src/components/ui/select-sheet.tsx, src/lib/design-system.ts, docs/contexts/design-system/CONTEXT.md
New switch abstraction with platform-specific implementations (Android Jetpack Compose with Dayova-blue, iOS SwiftUI tint); SelectSheet generalized to numeric types with custom label formatting; design system updated.
Notification plugin configuration
app.config.ts
Expo notifications plugin configured with custom icon and Dayova-blue color.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

ready-for-agent

Poem

🐇 Notifications hop in with careful grace,
Local plans and schedules keep their pace,
Switches flip to blue in Android's glow,
Settings shine as preferences flow,
The inbox dances, badges bright—
A complete system, tested right! ✨

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch notifications

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@FleetAdmiralJakob

Copy link
Copy Markdown
Collaborator Author

@codex Tell me if there will be a system push notification for example if there is an upcoming task in 15 mins and I have the app open?

@chatgpt-codex-connector

Copy link
Copy Markdown

Short answer

Yes — if notification permission is granted and system notifications are enabled, this PR should schedule a local system notification for an upcoming task at the configured reminder offset, which defaults to 15 minutes. The app installs NotificationSync globally in the root layout, so the scheduling/foreground handler is active while the app is open.

What happens when the app is open?

The implementation calls Notifications.setNotificationHandler(...) and explicitly requests foreground display with:

  • shouldShowBanner: true
  • shouldShowList: true
  • shouldPlaySound: false
  • shouldSetBadge: false

So while the app is foregrounded, it is configured to show the notification visually, but without sound or badge updates.

This matches Expo’s foreground notification model: Expo says foreground behavior is controlled with setNotificationHandler, including shouldShowBanner and shouldShowList. Source: Expo “Handle incoming notifications” docs.

One platform caveat: Expo’s Notifications SDK docs note that on Android, shouldPlaySound: false can prevent the drop-down heads-up alert from showing, even if priority/channel settings are present. So on Android, I would expect delivery into the system notification UI/list, but I would not rely on a heads-up banner unless we change the handler to play sound or adjust behavior. Source: Expo Notifications SDK docs.

Is it server push or local notification?

This PR is local scheduled notifications only, not server push. The PR body says server push remains future work, and the code schedules notifications on-device with scheduleNotificationAsync(...) using a date trigger.

So if by “system push notification” you mean “remote push from a server,” then no. If you mean “an OS/system notification shown by the phone,” then yes, this is implemented as a local scheduled system notification.

For “upcoming task in 15 mins” specifically

The planner creates a beforeEvent notification at:

startMinutes - preferences.reminderOffsetMinutes

and the default reminderOffsetMinutes is 15.

That means:

  • A task at 10:00 gets a before-event notification scheduled for 09:45.
  • The notification body will say the task starts in the configured number of minutes.
  • The notification is only scheduled if that trigger time is still in the future.

Preconditions

It will only happen if all of these are true:

  1. The user is signed in / Convex-authenticated, because preferences and day entries are skipped otherwise.
  2. System notifications are enabled in preferences.
  3. OS notification permission is granted, or iOS provisional authorization is present.
  4. The entry is incomplete, has a valid time, and the relevant preference for that entry type is enabled.
  5. The scheduled reminder time is still in the future.

Commands used

  • pwd && rg --files -g 'AGENTS.md' -g 'package.json' -g '*notification*' -g '*Notification*' -g 'app.json' -g 'app.config.*' -g 'expo-env.d.ts' | sed -n '1,120p'
  • sed -n '1,260p' src/components/notification-sync.tsx
  • sed -n '1,260p' src/lib/notification-planner.ts
  • nl -ba src/components/notification-sync.tsx | sed -n '1,180p'
  • nl -ba src/lib/notification-planner.ts | sed -n '123,185p'
  • nl -ba src/lib/local-notification-scheduler.ts | sed -n '44,84p'
  • nl -ba convex/notifications.ts | sed -n '1,120p'
  • rg -n "<NotificationSync|NotificationSync" src/app src/components -g '*.tsx'
  • git status --short

No code changes were made, so I did not commit or create a follow-up PR.

View task →

@FleetAdmiralJakob

Copy link
Copy Markdown
Collaborator Author

@codex What if the reminder offset is being changed but the event is already created?

@chatgpt-codex-connector

Copy link
Copy Markdown

Summary

  • Changed before-event inbox de-dupe to use a stable per-entry event key (before:${entry._id}), so if the reminder offset changes after a before-event notification was already created, Convex won’t create a duplicate notification for the same event.
  • Aligned local scheduled notification planning with the same stable per-entry key while preserving the recalculated trigger time/body from the current reminder offset.
  • Updated local scheduler/planner expectations to use the stable key in notification metadata.
  • Added a regression test proving a reminder offset change from 15 to 30 minutes does not create a second already-due before-event inbox notification.

Committed changes with:

  • 39b7714 Stabilize before-event notification keys

Created follow-up PR:

  • Avoid duplicate before-event reminders after offset changes

Testing

  • pnpm test src/lib/notification-planner.test.ts src/lib/local-notification-scheduler.test.ts convex/notifications.test.ts
  • pnpm check

View task →

@Gamius00
Gamius00 marked this pull request as ready for review June 9, 2026 20:53
@Gamius00
Gamius00 merged commit bb96965 into main Jun 9, 2026
3 of 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.

2 participants