# Notification Plan (Alerts + Inbox)

Last updated: 2026-03-16
Owner: Product + Mobile
Scope: `JamShalat` (Flutter)

## Implementation Status (2026-03-17)
- Phase 1: Implemented.
- Phase 2: Implemented (Notification Center + unread badge + inbox persistence).
- Phase 3: Implemented (daily checklist reminder scheduling, streak-risk messages, weekly summary, quiet-hours and daily cap preferences).
- Phase 4: Partially implemented via remote-content sync and remote-push ingestion bridge.
- External pending for full Phase 4: SDK/provider wiring (FCM/APNs credentials, token registration, backend push dispatch).

## 1. Problem Statement
Current app has mixed meaning for "notification":
- Device push alert (time-sensitive, appears in system drawer)
- In-app message feed (read-later information)

This causes unclear UX around the bell icon and settings.

## 2. Product Model
Split into two clear products:

1. **Alerts** (`Pemberitahuan`)
- Time-sensitive pushes to OS notification drawer.
- Can ring/vibrate.
- Expire quickly.

2. **Inbox** (`Pesan`)
- In-app list of messages user can read later.
- Has read/unread state.
- No mandatory sound.

Default rule:
- **Push only**: urgent + expiring event.
- **Inbox only**: informational/non-urgent event.
- **Push + Inbox**: important event that also needs follow-up context.

## 3. Terminology (User-Facing)
- Bell icon label/context: `Pemberitahuan`
- Notification center tabs:
  - `Alarm` (alert history + system-triggered items)
  - `Pesan` (inbox/read-later)

## 4. Event Policy Matrix
| Event | Push Drawer | Inbox | Sound | Expiry |
|---|---|---|---|---|
| Adzan time entered | Yes | Optional (off by default) | Yes | At end of prayer window |
| Iqamah reminder | Yes | No | Yes | At iqamah time |
| Next prayer in 10 minutes | Optional | No | Soft | At prayer start |
| Daily checklist reminder | Yes (if enabled) | No | Optional | End of day |
| Streak at risk (Tilawah/Dzikir) | Optional | Yes | No | End of day |
| Weekly worship summary | No | Yes | No | 7 days |
| Permission blocked (notif/exact alarm/location) | Yes | Yes | No | When resolved |
| Schedule/location stale | Yes | Yes | No | When resolved |
| New app content (Doa/Hadits) | No | Yes | No | 30 days |

## 5. Architecture
## 5.1 Channels
- **Local scheduled alerts** (already started in app): Adzan + Iqamah.
- **In-app inbox storage** (new): persisted read/unread messages.
- **Remote push** (future): FCM/APNs for server-driven campaigns/events.

## 5.2 Data Sources
- Prayer schedules: `MyQuranSholatService`.
- User prefs: `AppSettings` + new notification preference model.
- Device status: notification permission, exact alarm permission, location service.

## 5.3 Decision Engine
Input:
- event type
- urgency
- TTL
- user preferences
- cooldown/frequency cap

Output:
- deliver to `push`, `inbox`, or both.

Pseudo rule:
```text
if event.isTimeCritical && event.ttlShort:
  push
if event.needsFollowUp || event.referenceContent:
  inbox
if event.push && event.inboxPolicy == mirror:
  push + inbox
```

## 6. Data Model
## 6.1 Inbox Item (Hive)
Suggested new box: `notification_inbox`

```json
{
  "id": "uuid",
  "type": "streak_risk | summary | system | content | prayer",
  "title": "string",
  "body": "string",
  "createdAt": "iso8601",
  "expiresAt": "iso8601|null",
  "readAt": "iso8601|null",
  "isPinned": false,
  "deeplink": "/route/path",
  "meta": {
    "cityId": "string|null",
    "prayerKey": "fajr|dhuhr|asr|maghrib|isha|null",
    "date": "yyyy-MM-dd|null"
  },
  "source": "local|remote",
  "dedupeKey": "string"
}
```

## 6.2 Preferences
Use existing `AppSettings` for:
- `adhanEnabled` (per prayer)
- `iqamahOffset` (per prayer)

Add new fields (either in `AppSettings` or separate box):
- `alertsEnabled` (global)
- `inboxEnabled` (global)
- `streakRiskEnabled`
- `dailyChecklistReminderEnabled`
- `weeklySummaryEnabled`
- `quietHoursStart` / `quietHoursEnd`
- `maxNonPrayerPushPerDay` (default 2)

## 6.3 Badge Source
- Bell badge count = unread inbox count only.
- Do not include "already fired system push" count.

## 7. Local Notification Spec (Current + Next)
## 7.1 Channels
- `adhan_channel`: max importance, sound on.
- `iqamah_channel`: high importance, sound on.
- Later:
  - `habit_channel` (streak/checklist)
  - `system_channel` (permission/location)

## 7.2 Permission Strategy
- Request `POST_NOTIFICATIONS` and exact alarm capability only when needed.
- If denied:
  - create Inbox warning item
  - show non-blocking UI notice

## 7.3 Scheduling Rules
- Keep 2-day rolling window (today + tomorrow).
- Resync on:
  - app start
  - city change
  - prayer settings change
  - adzan toggle change
  - daily boundary change (00:05 local)
- Deduplicate by key: `cityId + date + prayer + kind(adhan/iqamah)`.

## 8. UX Specification
## 8.1 Bell Icon
- Tap action: open Notification Center.
- Badge: unread inbox count.
- Long-press (optional): quick actions
  - toggle `Alarm Sholat`
  - open Iqamah settings
  - sync now

## 8.2 Notification Center Screen
Tabs:
- `Alarm`
  - recent fired alerts (read-only timeline, optional v2)
- `Pesan`
  - unread/read list with filters (`Semua`, `Belum Dibaca`, `Sistem`)

Item actions:
- Tap: open deeplink target.
- Swipe: mark read/unread.
- Optional: pin important item.

## 8.3 Copy Guidelines
- Urgent: concise, action-first.
- Inbox: context-rich but short (max ~120 chars body preview).
- Prayer push examples:
  - `Adzan • Subuh`
  - `Waktu sholat Subuh telah masuk.`

## 9. Deep Link Map
- Permission blocked -> `/settings` (notifications section)
- Location disabled -> `/settings` or location setup section
- Streak risk Tilawah -> `/quran`
- Streak risk Dzikir -> `/tools/dzikir`
- Weekly summary -> `/laporan`
- Prayer event details -> `/` (Beranda)

## 10. Analytics
Track:
- `notif_push_scheduled`
- `notif_push_fired`
- `notif_push_opened`
- `notif_inbox_created`
- `notif_inbox_opened`
- `notif_mark_read`
- `notif_settings_changed`
- `notif_permission_denied`

Dimensions:
- `event_type`
- `channel` (`push|inbox|both`)
- `city_id`
- `simple_mode`

## 11. Rollout Plan
## Phase 1 (Now)
- Stabilize prayer alerts (Adzan + Iqamah) local scheduling.
- Working sound toggle in hero card and settings.
- Permission and exact-alarm checks.

## Phase 2
- Build Notification Center page + unread badge.
- Add inbox persistence and read/unread actions.
- Add system warning messages to inbox.

## Phase 3
- Add non-prayer reminders (checklist, streak risk, weekly summary).
- Add cooldown/frequency cap and quiet hours.

## Phase 4
- Remote push integration (FCM/APNs).
- Server-defined campaigns/content updates.

## 12. Acceptance Criteria
- Toggling adzan off removes all pending adzan/iqamah notifications.
- Toggling adzan on schedules valid upcoming notifications for enabled prayers.
- Changing iqamah minutes updates future scheduled iqamah alerts immediately.
- Bell opens Notification Center (after Phase 2).
- Unread badge count reflects inbox unread only.
- No duplicate notifications for same prayer/time/city.

## 13. QA Checklist
- Android 13/14: permission denied -> graceful fallback.
- Exact alarm disabled -> user warning path works.
- Timezone changes -> schedule recalculates correctly.
- Day rollover -> next-day notifications still present.
- City changes -> old city schedules removed; new city schedules added.
- Device reboot (future): optional reschedule receiver if needed.

## 14. Open Decisions
1. Should adzan events be mirrored into inbox by default?
2. Should quiet hours suppress non-prayer push only, or all push except adzan?
3. Should `Alarm` tab show only fired events or also pending schedule preview?
