docs: apply documentation references model agents directive to notification system docs
- Remove duplicate sync checklists from notification-system-plan.md - Fix markdown table formatting (remove double pipes) in executive summary - Streamline cross-document references and eliminate redundant content - Consolidate canonical ownership statements across all three docs - Improve document structure and readability per directive guidelines Files modified: - doc/notification-system-executive-summary.md - doc/notification-system-implementation.md - doc/notification-system-plan.md Compliance: Follows @docs/documentation_references_model_agents.mdc directive for eliminating redundancy, centralizing context, and optimizing reference placement.
This commit is contained in:
@@ -1,24 +1,20 @@
|
||||
# TimeSafari Notification System — Executive Summary
|
||||
|
||||
**Status:** 🚀 Ready for Implementation
|
||||
**Date:** 2025-01-27T14:30Z (UTC)
|
||||
**Author:** Matthew Raymer
|
||||
**Status:** 🚀 Ready for Implementation
|
||||
**Date:** 2025-01-27T14:30Z (UTC)
|
||||
**Author:** Matthew Raymer
|
||||
**Audience:** Executive Leadership, Product Management, Engineering Leadership
|
||||
|
||||
---
|
||||
|
||||
## Executive Overview
|
||||
|
||||
TimeSafari will implement a **multi-platform notification system** that
|
||||
delivers **1-3 daily notifications** to keep users connected to gratitude, gifts,
|
||||
and collaborative projects. The system will work across **iOS, Android, Web,
|
||||
and Electron** platforms with **offline-first reliability** and
|
||||
**privacy-preserving architecture**.
|
||||
TimeSafari will implement a **multi-platform notification system** that delivers **1-3 daily notifications** to keep users connected to gratitude, gifts, and collaborative projects. The system will work across **iOS, Android, Web, and Electron** platforms with **offline-first reliability** and **privacy-preserving architecture**.
|
||||
|
||||
### Business Value
|
||||
|
||||
- **User Engagement:** Daily touchpoints to maintain community connections
|
||||
- **Platform Coverage:** Unified experience across all TimeSafari platforms
|
||||
- **Platform Coverage:** Unified experience across all TimeSafari platforms
|
||||
- **Privacy-First:** User-controlled data with no external tracking
|
||||
- **Reliability:** Offline notifications that work even when app is closed
|
||||
|
||||
@@ -31,7 +27,6 @@ delivers **1-3 daily notifications** to keep users connected to gratitude, gifts
|
||||
**Scope:** Multi-daily local notifications with online/offline flows
|
||||
|
||||
**Key Capabilities:**
|
||||
|
||||
- **Local Notifications:** OS-level delivery on mobile/desktop
|
||||
- **Web Push:** Service Worker-based notifications for web
|
||||
- **Offline Reliability:** Notifications fire even when app is closed
|
||||
@@ -40,11 +35,10 @@ delivers **1-3 daily notifications** to keep users connected to gratitude, gifts
|
||||
|
||||
### Phase 2 (v2): Native Plugin
|
||||
|
||||
**Timeline:** Future enhancement
|
||||
**Timeline:** Future enhancement
|
||||
**Scope:** Native background scheduling and enhanced capabilities
|
||||
|
||||
**Key Capabilities:**
|
||||
|
||||
- **Native Background Work:** OS-level background tasks
|
||||
- **Enhanced Scheduling:** More precise timing and reliability
|
||||
- **Advanced Features:** Rich media and complex actions
|
||||
@@ -118,14 +112,9 @@ delivers **1-3 daily notifications** to keep users connected to gratitude, gifts
|
||||
|
||||
## Document References
|
||||
|
||||
- **Strategic Plan:** `notification-system-plan.md` - Goals, tenets, platform
|
||||
behaviors, acceptance criteria
|
||||
- **Implementation Guide:** `notification-system-implementation.md` - Complete
|
||||
code, database schemas, integration specifics
|
||||
- **This Summary:** High-level overview for executive decision-making
|
||||
- **Strategic Plan:** `notification-system-plan.md` - Goals, tenets, platform behaviors, acceptance criteria
|
||||
- **Implementation Guide:** `notification-system-implementation.md` - Complete code, database schemas, integration specifics
|
||||
|
||||
---
|
||||
|
||||
*This executive summary provides the essential business context and strategic
|
||||
direction for TimeSafari's notification system. For detailed technical
|
||||
specifications and implementation guidance, refer to the referenced documents.*
|
||||
*This executive summary provides the essential business context and strategic direction for TimeSafari's notification system. For detailed technical specifications and implementation guidance, refer to the referenced documents.*
|
||||
@@ -1,16 +1,13 @@
|
||||
# TimeSafari Notification System — Implementation Guide
|
||||
|
||||
**Status:** 🚀 Active implementation
|
||||
**Date:** 2025-09-05T05:09Z (UTC)
|
||||
**Author:** Matthew Raymer
|
||||
**Scope:** Detailed implementation for v1 (in‑app orchestrator)
|
||||
**Goal:** Complete implementation guide with code, database schemas, and
|
||||
integration specifics.
|
||||
**Status:** 🚀 Active implementation
|
||||
**Date:** 2025-09-05T05:09Z (UTC)
|
||||
**Author:** Matthew Raymer
|
||||
**Scope:** Detailed implementation for v1 (in‑app orchestrator)
|
||||
**Goal:** Complete implementation guide with code, database schemas, and integration specifics.
|
||||
|
||||
> **Strategic Overview:** See `notification-system-plan.md` for high-level
|
||||
> strategy, architecture, and planning details.
|
||||
> **Canonical Ownership:** This document owns API definitions, Database
|
||||
> schemas, Adapter implementations, and Code examples.
|
||||
> **Strategic Overview:** See `notification-system-plan.md` for high-level strategy, architecture, and planning details.
|
||||
> **Canonical Ownership:** This document owns API definitions, Database schemas, Adapter implementations, and Code examples.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,55 +1,34 @@
|
||||
# TimeSafari Notification System — Strategic Plan
|
||||
|
||||
**Status:** 🚀 Active plan
|
||||
**Date:** 2025-09-05T05:09Z (UTC)
|
||||
**Author:** Matthew Raymer
|
||||
**Scope:** v1 (in‑app orchestrator) now; path to v2 (native plugin) next
|
||||
**Goal:** We **will deliver** 1..M local notifications/day with content
|
||||
**prefetched** so messages **will display offline**. We **will support**
|
||||
online‑first (API→DB→Schedule) with offline‑first fallback. The system
|
||||
**will enhance** TimeSafari's community-building mission by keeping users
|
||||
connected to gratitude, gifts, and collaborative projects through timely,
|
||||
relevant notifications.
|
||||
**Status:** 🚀 Active plan
|
||||
**Date:** 2025-09-05T05:09Z (UTC)
|
||||
**Author:** Matthew Raymer
|
||||
**Scope:** v1 (in‑app orchestrator) now; path to v2 (native plugin) next
|
||||
**Goal:** We **will deliver** 1..M local notifications/day with content **prefetched** so messages **will display offline**. We **will support** online‑first (API→DB→Schedule) with offline‑first fallback. The system **will enhance** TimeSafari's community-building mission by keeping users connected to gratitude, gifts, and collaborative projects through timely, relevant notifications.
|
||||
|
||||
> **Implementation Details:** See `notification-system-implementation.md` for
|
||||
detailed code, database schemas, and integration specifics.
|
||||
> **Canonical Ownership:** This document owns Goals, Tenets, Platform
|
||||
> behaviors, Acceptance criteria, and Test cases.
|
||||
> **Implementation Details:** See `notification-system-implementation.md` for detailed code, database schemas, and integration specifics.
|
||||
> **Canonical Ownership:** This document owns Goals, Tenets, Platform behaviors, Acceptance criteria, and Test cases.
|
||||
|
||||
---
|
||||
|
||||
## 1) Versioning & Intent
|
||||
|
||||
- **v1 (In‑App Orchestrator):** We **will implement** multi‑daily local
|
||||
notifications, online/offline flows, templating, SQLite persistence, and
|
||||
eventing **inside the app** using Capacitor Local Notifications.
|
||||
- **v2 (Plugin):** We **will extract** adapters to a Capacitor/Native plugin
|
||||
to gain native schedulers (WorkManager/AlarmManager;
|
||||
BGTask+UNUserNotificationCenter), native HTTP, and native SQLite **with the
|
||||
same TypeScript API**.
|
||||
- **v1 (In‑App Orchestrator):** We **will implement** multi‑daily local notifications, online/offline flows, templating, SQLite persistence, and eventing **inside the app** using Capacitor Local Notifications.
|
||||
- **v2 (Plugin):** We **will extract** adapters to a Capacitor/Native plugin to gain native schedulers (WorkManager/AlarmManager; BGTask+UNUserNotificationCenter), native HTTP, and native SQLite **with the same TypeScript API**.
|
||||
|
||||
> We **will retain** the existing web push + Service Worker foundation; the
|
||||
> system **will add** reliable local scheduling on mobile and a unified API
|
||||
> across platforms.
|
||||
> We **will retain** the existing web push + Service Worker foundation; the system **will add** reliable local scheduling on mobile and a unified API across platforms.
|
||||
|
||||
---
|
||||
|
||||
## 2) Design Tenets
|
||||
|
||||
- **Reliability:** OS‑level delivery once scheduled; no reliance on JS being alive
|
||||
at fire time.
|
||||
- **Freshness:** Prefer online‑first within a short prefetch window; degrade
|
||||
gracefully to cached content with TTL.
|
||||
- **Extractable:** Clean interfaces (Scheduler, DataStore, Callbacks) so v2
|
||||
**will swap** adapters without API changes.
|
||||
- **Simplicity:** One‑shot notifications per slot; rolling window scheduling to
|
||||
respect platform caps.
|
||||
- **Observability:** Persist deliveries and errors; surface minimal metrics;
|
||||
enable ACKs.
|
||||
- **Privacy-First:** Follow TimeSafari's privacy-preserving architecture;
|
||||
user-controlled visibility and data sovereignty.
|
||||
- **Community-Focused:** Enhance TimeSafari's mission of connecting people through
|
||||
gratitude, gifts, and collaborative projects.
|
||||
- **Reliability:** OS‑level delivery once scheduled; no reliance on JS being alive at fire time.
|
||||
- **Freshness:** Prefer online‑first within a short prefetch window; degrade gracefully to cached content with TTL.
|
||||
- **Extractable:** Clean interfaces (Scheduler, DataStore, Callbacks) so v2 **will swap** adapters without API changes.
|
||||
- **Simplicity:** One‑shot notifications per slot; rolling window scheduling to respect platform caps.
|
||||
- **Observability:** Persist deliveries and errors; surface minimal metrics; enable ACKs.
|
||||
- **Privacy-First:** Follow TimeSafari's privacy-preserving architecture; user-controlled visibility and data sovereignty.
|
||||
- **Community-Focused:** Enhance TimeSafari's mission of connecting people through gratitude, gifts, and collaborative projects.
|
||||
|
||||
---
|
||||
|
||||
@@ -77,90 +56,58 @@ Platform
|
||||
|
||||
**Execution modes (concise):**
|
||||
|
||||
- **Online‑First:** wake near slot → fetch (ETag, timeout) → persist → schedule;
|
||||
on failure → Offline‑First.
|
||||
- **Offline‑First:** read last good payload from SQLite; if beyond TTL → skip
|
||||
notification (no retry).
|
||||
- **Online‑First:** wake near slot → fetch (ETag, timeout) → persist → schedule; on failure → Offline‑First.
|
||||
- **Offline‑First:** read last good payload from SQLite; if beyond TTL → skip notification (no retry).
|
||||
|
||||
---
|
||||
|
||||
## 4) Public API (Shared by v1 & v2)
|
||||
|
||||
**Core Types & Interface:** See Implementation document for complete API
|
||||
definitions, type interfaces, and design decisions.
|
||||
**Core Types & Interface:** See Implementation document for complete API definitions, type interfaces, and design decisions.
|
||||
|
||||
> **Storage semantics:** `'shared'` = app DB; `'private'` = plugin-owned/native
|
||||
> DB (v2). (No functional difference in v1.)
|
||||
> **Slot Identity & Scheduling Policy**
|
||||
> • **SlotId** uses canonical `HHmm` and remains stable across timezone
|
||||
> changes.
|
||||
> • **Lead window:** default `prefetchLeadMinutes = 20`; no retries once inside
|
||||
the lead.
|
||||
> • **TTL policy:** When offline and content is beyond TTL, **we will skip** the
|
||||
notification (no "(cached)" suffix).
|
||||
> • **Idempotency:** Duplicate "scheduled" deliveries are prevented by a unique
|
||||
index on `(slot_id, fire_at, status='scheduled')`.
|
||||
> • **Time handling:** Slots will follow **local wall-clock** time across TZ/DST;
|
||||
`slotId=HHmm` stays constant and we will **recompute fire times** on offset change.
|
||||
> **Storage semantics:** `'shared'` = app DB; `'private'` = plugin-owned/native DB (v2). (No functional difference in v1.)
|
||||
> **Slot Identity & Scheduling Policy**
|
||||
> • **SlotId** uses canonical `HHmm` and remains stable across timezone changes.
|
||||
> • **Lead window:** default `prefetchLeadMinutes = 20`; no retries once inside the lead.
|
||||
> • **TTL policy:** When offline and content is beyond TTL, **we will skip** the notification (no "(cached)" suffix).
|
||||
> • **Idempotency:** Duplicate "scheduled" deliveries are prevented by a unique index on `(slot_id, fire_at, status='scheduled')`.
|
||||
> • **Time handling:** Slots will follow **local wall-clock** time across TZ/DST; `slotId=HHmm` stays constant and we will **recompute fire times** on offset change.
|
||||
|
||||
---
|
||||
|
||||
## 5) Data Model & Retention (SQLite)
|
||||
|
||||
**Tables:** `notif_contents`, `notif_deliveries`, `notif_config` (see
|
||||
Implementation document for complete schema)
|
||||
**Tables:** `notif_contents`, `notif_deliveries`, `notif_config` (see Implementation document for complete schema)
|
||||
|
||||
**Retention:** We **will keep** ~14 days of contents/deliveries (configurable)
|
||||
and **will prune** via a simple daily job that runs on app start/resume. We
|
||||
**will prune** daily but **will not** VACUUM by default on mobile; disk
|
||||
compaction is deferred.
|
||||
**Retention:** We **will keep** ~14 days of contents/deliveries (configurable) and **will prune** via a simple daily job that runs on app start/resume. We **will prune** daily but **will not** VACUUM by default on mobile; disk compaction is deferred.
|
||||
|
||||
**Payload handling:** We **will template** `{title, body}` **before** scheduling;
|
||||
we **will not** mutate at delivery time.
|
||||
**Payload handling:** We **will template** `{title, body}` **before** scheduling; we **will not** mutate at delivery time.
|
||||
|
||||
---
|
||||
|
||||
## 6) Scheduling Policy & Slot Math
|
||||
|
||||
- **One‑shot per slot** per day (non‑repeating).
|
||||
- **Rolling window:** today's remaining slots; seed tomorrow where platform
|
||||
limits allow.
|
||||
- **TZ/DST safe:** We **will recompute** local wall‑times on app resume and
|
||||
whenever timezone/offset changes; then **reschedule**.
|
||||
- **Android exactness:** If exact alarms are unavailable or denied, we
|
||||
**will use** `setWindow` semantics via the scheduler adapter.
|
||||
- **iOS pending cap:** We **will keep** pending locals within typical caps (~64)
|
||||
by limiting the window and canceling/re‑arming as needed.
|
||||
- **Electron rolling window:** On Electron we **will schedule** the **next
|
||||
occurrence per slot** by default; depth (today+tomorrow) **will be** enabled only
|
||||
when auto-launch is on, to avoid drift while the app is closed.
|
||||
- **Rolling window:** today's remaining slots; seed tomorrow where platform limits allow.
|
||||
- **TZ/DST safe:** We **will recompute** local wall‑times on app resume and whenever timezone/offset changes; then **reschedule**.
|
||||
- **Android exactness:** If exact alarms are unavailable or denied, we **will use** `setWindow` semantics via the scheduler adapter.
|
||||
- **iOS pending cap:** We **will keep** pending locals within typical caps (~64) by limiting the window and canceling/re‑arming as needed.
|
||||
- **Electron rolling window:** On Electron we **will schedule** the **next occurrence per slot** by default; depth (today+tomorrow) **will be** enabled only when auto-launch is on, to avoid drift while the app is closed.
|
||||
|
||||
---
|
||||
|
||||
## 7) Timing & Network Requirements
|
||||
|
||||
**Summary:** The notification system uses lightweight, ETag-aware content
|
||||
fetching with single attempts inside lead windows. All timing constants and
|
||||
detailed network policies are defined in the Implementation document.
|
||||
**Summary:** The notification system uses lightweight, ETag-aware content fetching with single attempts inside lead windows. All timing constants and detailed network policies are defined in the Implementation document.
|
||||
|
||||
**Key Policies:**
|
||||
|
||||
- **Lead policy:** The lead window governs **online-first fetch attempts**, not
|
||||
arming. We **will arm** locals **whenever the app runs**, using the freshest
|
||||
available payload.
|
||||
- **TTL policy:** If offline and content is beyond TTL, we will **skip** the
|
||||
notification (no "cached" suffix).
|
||||
- **Idempotency:** Duplicate "scheduled" rows are prevented by a unique index on
|
||||
`(slot_id, fire_at, status='scheduled')`.
|
||||
- **Wall-clock rule:** Slots will follow **local wall-clock** across TZ/DST;
|
||||
`slotId=HHmm` stays constant and we will **recompute fire times** on offset change.
|
||||
- **Resume debounce:** On app resume/open we will **debounce** pipeline
|
||||
entry points by **30s** per app session to avoid burst fetches.
|
||||
- **No scheduled background network in v1 (mobile):** Local notifications
|
||||
**will deliver offline once armed**, but **we will not** run timed network jobs
|
||||
when the app is terminated. **Network prefetch will occur only while the app is
|
||||
running** (launch/resume/inside lead). Server-driven push (Web SW) and OS
|
||||
background schedulers are a **v2** capability.
|
||||
- **Lead policy:** The lead window governs **online-first fetch attempts**, not arming. We **will arm** locals **whenever the app runs**, using the freshest available payload.
|
||||
- **TTL policy:** If offline and content is beyond TTL, we will **skip** the notification (no "cached" suffix).
|
||||
- **Idempotency:** Duplicate "scheduled" rows are prevented by a unique index on `(slot_id, fire_at, status='scheduled')`.
|
||||
- **Wall-clock rule:** Slots will follow **local wall-clock** across TZ/DST; `slotId=HHmm` stays constant and we will **recompute fire times** on offset change.
|
||||
- **Resume debounce:** On app resume/open we will **debounce** pipeline entry points by **30s** per app session to avoid burst fetches.
|
||||
- **No scheduled background network in v1 (mobile):** Local notifications **will deliver offline once armed**, but **we will not** run timed network jobs when the app is terminated. **Network prefetch will occur only while the app is running** (launch/resume/inside lead). Server-driven push (Web SW) and OS background schedulers are a **v2** capability.
|
||||
|
||||
**Platform-Specific Network Access:**
|
||||
|
||||
@@ -171,18 +118,9 @@ background schedulers are a **v2** capability.
|
||||
|
||||
**Optional Background Prefetch (v1):**
|
||||
|
||||
- **Background Runner (optional, v1):** We **will integrate** Capacitor's
|
||||
Background Runner to **opportunistically prefetch** content on iOS/Android when
|
||||
the OS grants background time. This **will not** provide clock-precise execution
|
||||
and **will not** run after user-terminate on iOS. It **will not** be treated as
|
||||
a scheduler. We **will continue** to *arm* local notifications via our rolling
|
||||
window regardless of Runner availability. When Runner fires near a slot (inside
|
||||
`prefetchLeadMinutes`), it **will** refresh content (ETag, 12s timeout) and,
|
||||
behind a flag, **may** cancel & re-arm that slot with the fresh template if within
|
||||
TTL. If no budget or failure, the previously armed local **will** still deliver.
|
||||
- **Background Runner (optional, v1):** We **will integrate** Capacitor's Background Runner to **opportunistically prefetch** content on iOS/Android when the OS grants background time. This **will not** provide clock-precise execution and **will not** run after user-terminate on iOS. It **will not** be treated as a scheduler. We **will continue** to *arm* local notifications via our rolling window regardless of Runner availability. When Runner fires near a slot (inside `prefetchLeadMinutes`), it **will** refresh content (ETag, 12s timeout) and, behind a flag, **may** cancel & re-arm that slot with the fresh template if within TTL. If no budget or failure, the previously armed local **will** still deliver.
|
||||
|
||||
**Implementation Details:** See Implementation document for complete timing
|
||||
constants table, network request profiles, and platform-specific enforcement.
|
||||
**Implementation Details:** See Implementation document for complete timing constants table, network request profiles, and platform-specific enforcement.
|
||||
|
||||
---
|
||||
|
||||
@@ -190,113 +128,70 @@ constants table, network request profiles, and platform-specific enforcement.
|
||||
|
||||
**iOS**
|
||||
|
||||
- Local notifications **will** fire without background runtime once scheduled.
|
||||
NSE **will not** mutate locals; delivery-time enrichment requires remote push (future).
|
||||
- Local notifications **will** fire without background runtime once scheduled. NSE **will not** mutate locals; delivery-time enrichment requires remote push (future).
|
||||
- **Category ID**: `TS_DAILY` with default `OPEN` action
|
||||
- **Background budget** is short and OS‑managed; any prefetch work
|
||||
**will complete** promptly.
|
||||
- **Background budget** is short and OS‑managed; any prefetch work **will complete** promptly.
|
||||
- **Mobile local notifications will route via action listeners (not the service worker)**.
|
||||
- Background Runner **will** offer **opportunistic** network wake (no guarantees;
|
||||
short runtime; iOS will not run after force-quit). Locals **will** still deliver
|
||||
offline once armed.
|
||||
- Background Runner **will** offer **opportunistic** network wake (no guarantees; short runtime; iOS will not run after force-quit). Locals **will** still deliver offline once armed.
|
||||
|
||||
**Android**
|
||||
|
||||
- Exact alarms on **API 31+** may require `SCHEDULE_EXACT_ALARM`. If exact access
|
||||
is missing on API 31+, we will use a **windowed trigger (default ±10m)** and
|
||||
surface a settings deep-link.
|
||||
- Exact alarms on **API 31+** may require `SCHEDULE_EXACT_ALARM`. If exact access is missing on API 31+, we will use a **windowed trigger (default ±10m)** and surface a settings deep-link.
|
||||
- **We will deep-link users to the exact-alarm settings when we detect denials.**
|
||||
- **Channel defaults**: ID `timesafari.daily`, name "TimeSafari Daily",
|
||||
importance=high (IDs never change)
|
||||
- Receivers for reboot/time change **will be handled** by v2 (plugin); in v1,
|
||||
re‑arming **will occur** on app start/resume.
|
||||
- **Channel defaults**: ID `timesafari.daily`, name "TimeSafari Daily", importance=high (IDs never change)
|
||||
- Receivers for reboot/time change **will be handled** by v2 (plugin); in v1, re‑arming **will occur** on app start/resume.
|
||||
- **Mobile local notifications will route via action listeners (not the service worker)**.
|
||||
- Background Runner **will** offer **opportunistic** network wake (no guarantees;
|
||||
short runtime; iOS will not run after force-quit). Locals **will** still deliver
|
||||
offline once armed.
|
||||
- Background Runner **will** offer **opportunistic** network wake (no guarantees; short runtime; iOS will not run after force-quit). Locals **will** still deliver offline once armed.
|
||||
|
||||
**Web**
|
||||
|
||||
- Requires registered Service Worker + permission; can deliver with browser closed.
|
||||
**Web will not offline-schedule**.
|
||||
- Service Worker click handlers are for **web push only**;
|
||||
**mobile locals bypass the SW**.
|
||||
- SW examples use `/sw.js` as a placeholder; **wire this to your actual build
|
||||
output path** (e.g., `sw_scripts/notification-click.js` or your combined bundle).
|
||||
- **Note**: Service workers are **intentionally disabled** in Electron
|
||||
(`src/main.electron.ts`) and web uses VitePWA plugin for minimal implementation.
|
||||
- Requires registered Service Worker + permission; can deliver with browser closed. **Web will not offline-schedule**.
|
||||
- Service Worker click handlers are for **web push only**; **mobile locals bypass the SW**.
|
||||
- SW examples use `/sw.js` as a placeholder; **wire this to your actual build output path** (e.g., `sw_scripts/notification-click.js` or your combined bundle).
|
||||
- **Note**: Service workers are **intentionally disabled** in Electron (`src/main.electron.ts`) and web uses VitePWA plugin for minimal implementation.
|
||||
|
||||
**Electron**
|
||||
|
||||
- We **will use** native OS notifications with **best-effort scheduling while the
|
||||
app is running**; true background scheduling will be addressed in v2 (native bridges).
|
||||
- We **will use** native OS notifications with **best-effort scheduling while the app is running**; true background scheduling will be addressed in v2 (native bridges).
|
||||
|
||||
**Electron delivery strategy (v1 reality + v2 path)**
|
||||
We **will deliver** desktop notifications while the Electron app is running. True
|
||||
**background scheduling when the app is closed** is **out of scope for v1** and
|
||||
**will be addressed** in v2 via native bridges. We **will adopt** one of the
|
||||
following options (in order of fit to our codebase):
|
||||
**Electron delivery strategy (v1 reality + v2 path)**
|
||||
We **will deliver** desktop notifications while the Electron app is running. True **background scheduling when the app is closed** is **out of scope for v1** and **will be addressed** in v2 via native bridges. We **will adopt** one of the following options (in order of fit to our codebase):
|
||||
|
||||
**In-app scheduler + auto-launch (recommended now):** Keep the orchestrator in
|
||||
the main process, **start on login** (tray app, hidden window), and use the
|
||||
**Electron `Notification` API** for delivery. This requires no new OS services
|
||||
and aligns with our PlatformServiceFactory/mixin patterns.
|
||||
**In-app scheduler + auto-launch (recommended now):** Keep the orchestrator in the main process, **start on login** (tray app, hidden window), and use the **Electron `Notification` API** for delivery. This requires no new OS services and aligns with our PlatformServiceFactory/mixin patterns.
|
||||
|
||||
**Policy (v1):** If the app is **not running**, Electron will **not** deliver
|
||||
scheduled locals. With **auto-launch enabled**, we **will achieve** near-mobile
|
||||
parity while respecting OS sleep/idle behavior.
|
||||
**Policy (v1):** If the app is **not running**, Electron will **not** deliver scheduled locals. With **auto-launch enabled**, we **will achieve** near-mobile parity while respecting OS sleep/idle behavior.
|
||||
|
||||
**UX notes:** On Windows we **will set** `appUserModelId` so toasts are
|
||||
attributed correctly; on macOS we **will request** notification permission on
|
||||
first use.
|
||||
**UX notes:** On Windows we **will set** `appUserModelId` so toasts are attributed correctly; on macOS we **will request** notification permission on first use.
|
||||
|
||||
**Prerequisites:** We **will require** Node 18+ (global `fetch`) or we
|
||||
**will polyfill** via `undici` for content fetching in the main process.
|
||||
**Prerequisites:** We **will require** Node 18+ (global `fetch`) or we **will polyfill** via `undici` for content fetching in the main process.
|
||||
|
||||
---
|
||||
|
||||
## 8) Template Engine Contract
|
||||
## 9) Template Engine Contract
|
||||
|
||||
**Supported tokens:** `{{headline}}`, `{{summary}}`, `{{date}}` (YYYY-MM-DD),
|
||||
`{{time}}` (HH:MM).
|
||||
**Escaping:** HTML-escape all injected values.
|
||||
**Limits:** Title ≤ 50 chars; Body ≤ 200 chars; truncate with ellipsis.
|
||||
**Fallback:** Missing token → `"[Content]"`.
|
||||
**Mutation:** We **will** render templates **before** scheduling; no mutation at
|
||||
delivery time on iOS locals.
|
||||
**Supported tokens:** `{{headline}}`, `{{summary}}`, `{{date}}` (YYYY-MM-DD), `{{time}}` (HH:MM).
|
||||
**Escaping:** HTML-escape all injected values.
|
||||
**Limits:** Title ≤ 50 chars; Body ≤ 200 chars; truncate with ellipsis.
|
||||
**Fallback:** Missing token → `"[Content]"`.
|
||||
**Mutation:** We **will** render templates **before** scheduling; no mutation at delivery time on iOS locals.
|
||||
|
||||
## 9) Integration with Existing TimeSafari Infrastructure
|
||||
---
|
||||
|
||||
**Database:** We **will integrate** with existing migration system in
|
||||
`src/db-sql/migration.ts` following the established `MIGRATIONS` array pattern
|
||||
**Settings:** We **will extend** existing Settings type in
|
||||
`src/db/tables/settings.ts` following the established type extension pattern
|
||||
**Platform Service:** We **will leverage** existing PlatformServiceMixin database
|
||||
utilities following the established mixin pattern
|
||||
**Service Factory:** We **will follow** the existing `PlatformServiceFactory`
|
||||
singleton pattern for notification service creation
|
||||
**Capacitor:** We **will integrate** with existing deep link system in
|
||||
`src/main.capacitor.ts` following the established initialization pattern
|
||||
**Service Worker:** We **will extend** existing service worker infrastructure
|
||||
following the established `sw_scripts/` pattern (Note: Service workers are
|
||||
intentionally disabled in Electron and have minimal web implementation via
|
||||
VitePWA plugin)
|
||||
**API:** We **will use** existing error handling from `src/services/api.ts`
|
||||
following the established `handleApiError` pattern
|
||||
**Logging:** We **will use** existing logger from `src/utils/logger` following
|
||||
the established logging patterns
|
||||
**Platform Detection:** We **will use** existing `process.env.VITE_PLATFORM`
|
||||
patterns (`web`, `capacitor`, `electron`)
|
||||
**Vue Architecture:** We **will follow** Vue 3 + vue-facing-decorator patterns
|
||||
for component integration (Note: The existing `useNotifications` composable in
|
||||
`src/composables/useNotifications.ts` is currently stub functions with
|
||||
eslint-disable comments and needs implementation)
|
||||
**State Management:** We **will integrate** with existing settings system via
|
||||
`PlatformServiceMixin.$saveSettings()` for notification preferences (Note:
|
||||
TimeSafari uses PlatformServiceMixin for all state management, not Pinia stores)
|
||||
**Identity System:** We **will integrate** with existing `did:ethr:`
|
||||
(Ethereum-based DID) system for user context
|
||||
**Testing:** We **will follow** Playwright E2E testing patterns established in TimeSafari
|
||||
## 10) Integration with Existing TimeSafari Infrastructure
|
||||
|
||||
**Database:** We **will integrate** with existing migration system in `src/db-sql/migration.ts` following the established `MIGRATIONS` array pattern
|
||||
**Settings:** We **will extend** existing Settings type in `src/db/tables/settings.ts` following the established type extension pattern
|
||||
**Platform Service:** We **will leverage** existing PlatformServiceMixin database utilities following the established mixin pattern
|
||||
**Service Factory:** We **will follow** the existing `PlatformServiceFactory` singleton pattern for notification service creation
|
||||
**Capacitor:** We **will integrate** with existing deep link system in `src/main.capacitor.ts` following the established initialization pattern
|
||||
**Service Worker:** We **will extend** existing service worker infrastructure following the established `sw_scripts/` pattern (Note: Service workers are intentionally disabled in Electron and have minimal web implementation via VitePWA plugin)
|
||||
**API:** We **will use** existing error handling from `src/services/api.ts` following the established `handleApiError` pattern
|
||||
**Logging:** We **will use** existing logger from `src/utils/logger` following the established logging patterns
|
||||
**Platform Detection:** We **will use** existing `process.env.VITE_PLATFORM` patterns (`web`, `capacitor`, `electron`)
|
||||
**Vue Architecture:** We **will follow** Vue 3 + vue-facing-decorator patterns for component integration (Note: The existing `useNotifications` composable in `src/composables/useNotifications.ts` is currently stub functions with eslint-disable comments and needs implementation)
|
||||
**State Management:** We **will integrate** with existing settings system via `PlatformServiceMixin.$saveSettings()` for notification preferences (Note: TimeSafari uses PlatformServiceMixin for all state management, not Pinia stores)
|
||||
**Identity System:** We **will integrate** with existing `did:ethr:` (Ethereum-based DID) system for user context
|
||||
**Testing:** We **will follow** Playwright E2E testing patterns established in TimeSafari
|
||||
**Database Architecture:** We **will support** platform-specific database backends:
|
||||
|
||||
- **Web**: Absurd SQL (SQLite via IndexedDB) via `WebPlatformService` with worker pattern
|
||||
@@ -305,87 +200,64 @@ TimeSafari uses PlatformServiceMixin for all state management, not Pinia stores)
|
||||
|
||||
---
|
||||
|
||||
## 10) Error Taxonomy & Telemetry
|
||||
## 11) Error Taxonomy & Telemetry
|
||||
|
||||
**Error Codes:** `FETCH_TIMEOUT`, `ETAG_NOT_MODIFIED`, `SCHEDULE_DENIED`,
|
||||
`EXACT_ALARM_MISSING`, `STORAGE_BUSY`, `TEMPLATE_MISSING_TOKEN`, `PERMISSION_DENIED`.
|
||||
**Error Codes:** `FETCH_TIMEOUT`, `ETAG_NOT_MODIFIED`, `SCHEDULE_DENIED`, `EXACT_ALARM_MISSING`, `STORAGE_BUSY`, `TEMPLATE_MISSING_TOKEN`, `PERMISSION_DENIED`.
|
||||
|
||||
**Event Envelope:** `code, slotId, whenMs, attempt, networkState, tzOffset,
|
||||
appState, timestamp`.
|
||||
**Event Envelope:** `code, slotId, whenMs, attempt, networkState, tzOffset, appState, timestamp`.
|
||||
|
||||
---
|
||||
|
||||
## 11) Permission UX & Channels/Categories
|
||||
## 12) Permission UX & Channels/Categories
|
||||
|
||||
- We **will request** notification permission **after** user intent (e.g.,
|
||||
settings screen), not on first render.
|
||||
- **Android:** We **will create** a stable channel ID (e.g., `timesafari.daily`)
|
||||
and **will set** importance appropriately.
|
||||
- **iOS:** We **will register** categories for optional actions; grouping may
|
||||
use `threadIdentifier` per slot/day.
|
||||
- We **will request** notification permission **after** user intent (e.g., settings screen), not on first render.
|
||||
- **Android:** We **will create** a stable channel ID (e.g., `timesafari.daily`) and **will set** importance appropriately.
|
||||
- **iOS:** We **will register** categories for optional actions; grouping may use `threadIdentifier` per slot/day.
|
||||
|
||||
---
|
||||
|
||||
## 12) Eventing & Telemetry
|
||||
## 13) Eventing & Telemetry
|
||||
|
||||
**Error Codes:** `FETCH_TIMEOUT`, `ETAG_NOT_MODIFIED`, `SCHEDULE_DENIED`,
|
||||
`EXACT_ALARM_MISSING`, `STORAGE_BUSY`, `TEMPLATE_MISSING_TOKEN`, `PERMISSION_DENIED`.
|
||||
**Error Codes:** `FETCH_TIMEOUT`, `ETAG_NOT_MODIFIED`, `SCHEDULE_DENIED`, `EXACT_ALARM_MISSING`, `STORAGE_BUSY`, `TEMPLATE_MISSING_TOKEN`, `PERMISSION_DENIED`.
|
||||
|
||||
**Event Envelope:** `code, slotId, whenMs, attempt, networkState, tzOffset,
|
||||
appState, timestamp`.
|
||||
**Event Envelope:** `code, slotId, whenMs, attempt, networkState, tzOffset, appState, timestamp`.
|
||||
|
||||
**Implementation:** See Implementation document for complete error taxonomy,
|
||||
event logging envelope, ACK payload format, and telemetry events.
|
||||
**Implementation:** See Implementation document for complete error taxonomy, event logging envelope, ACK payload format, and telemetry events.
|
||||
|
||||
---
|
||||
|
||||
## 13) Feature Flags & Config
|
||||
## 14) Feature Flags & Config
|
||||
|
||||
**Key Flags:** `scheduler`, `mode`, `prefetchLeadMinutes`, `ttlSeconds`,
|
||||
`iosCategoryIdentifier`, `androidChannelId`, `prefetchRunner`, `runnerRearm`.
|
||||
**Key Flags:** `scheduler`, `mode`, `prefetchLeadMinutes`, `ttlSeconds`, `iosCategoryIdentifier`, `androidChannelId`, `prefetchRunner`, `runnerRearm`.
|
||||
|
||||
**Storage:** Feature flags **will reside** in `notif_config` table as key-value
|
||||
pairs, separate from user settings.
|
||||
**Storage:** Feature flags **will reside** in `notif_config` table as key-value pairs, separate from user settings.
|
||||
|
||||
**Implementation:** See Implementation document for complete feature flags table
|
||||
with defaults and descriptions.
|
||||
**Implementation:** See Implementation document for complete feature flags table with defaults and descriptions.
|
||||
|
||||
---
|
||||
|
||||
## 14) Acceptance (Definition of Done) → Test Cases
|
||||
## 15) Acceptance (Definition of Done) → Test Cases
|
||||
|
||||
### Explicit Test Checks
|
||||
|
||||
- **App killed → locals fire**: Configure slots at 8:00, 12:00, 18:00; kill
|
||||
app; verify notifications fire at each slot on iOS/Android
|
||||
- **ETag 304 path**: Server returns 304 → keep previous content; locals fire
|
||||
with cached payload
|
||||
- **ETag 200 path**: Server returns 200 → update content and re-arm locals with
|
||||
fresh payload
|
||||
- **Offline + beyond TTL**: When offline and content > 24h old → skip notification
|
||||
(no "(cached)" suffix)
|
||||
- **iOS pending cap**: Respect ~64 pending limit; cancel/re-arm as needed within
|
||||
rolling window
|
||||
- **Exact-alarm denied**: Android permission absent → windowed schedule (±10m)
|
||||
activates; UI shows fallback hint
|
||||
- **Permissions disabled** → we will record `SCHEDULE_DENIED` and refrain from
|
||||
queuing locals.
|
||||
- **Window fallback** → when exact alarm is absent on Android, verify target
|
||||
fires within **±10m** of slot time (document as an E2E expectation).
|
||||
- **Timezone change**: On TZ/DST change → recompute wall-clock times; cancel &
|
||||
re-arm all slots
|
||||
- **App killed → locals fire**: Configure slots at 8:00, 12:00, 18:00; kill app; verify notifications fire at each slot on iOS/Android
|
||||
- **ETag 304 path**: Server returns 304 → keep previous content; locals fire with cached payload
|
||||
- **ETag 200 path**: Server returns 200 → update content and re-arm locals with fresh payload
|
||||
- **Offline + beyond TTL**: When offline and content > 24h old → skip notification (no "(cached)" suffix)
|
||||
- **iOS pending cap**: Respect ~64 pending limit; cancel/re-arm as needed within rolling window
|
||||
- **Exact-alarm denied**: Android permission absent → windowed schedule (±10m) activates; UI shows fallback hint
|
||||
- **Permissions disabled** → we will record `SCHEDULE_DENIED` and refrain from queuing locals.
|
||||
- **Window fallback** → when exact alarm is absent on Android, verify target fires within **±10m** of slot time (document as an E2E expectation).
|
||||
- **Timezone change**: On TZ/DST change → recompute wall-clock times; cancel & re-arm all slots
|
||||
- **Lead window respect**: No retries attempted once inside 20min lead window
|
||||
- **Idempotency**: Multiple `runFullPipelineNow()` calls don't create duplicate
|
||||
scheduled deliveries
|
||||
- **Idempotency**: Multiple `runFullPipelineNow()` calls don't create duplicate scheduled deliveries
|
||||
- **Cooldown guard**: `deliverStoredNow()` has 60s cooldown to prevent double-firing
|
||||
|
||||
### Electron-Specific Test Checks
|
||||
|
||||
- **Electron running (tray or window) → notifications fire** at configured slots
|
||||
using Electron `Notification`
|
||||
- **Electron running (tray or window) → notifications fire** at configured slots using Electron `Notification`
|
||||
- **Electron not running →** no delivery (documented limitation for v1)
|
||||
- **Start on Login enabled →** after reboot + login, orchestrator **will re-arm**
|
||||
slots and deliver
|
||||
- **Start on Login enabled →** after reboot + login, orchestrator **will re-arm** slots and deliver
|
||||
- **Template limits honored** (Title ≤ 50, Body ≤ 200) on Electron notifications
|
||||
- **SW scope** not used for Electron (click handlers are **web only**)
|
||||
- **Windows appUserModelId** set correctly for toast attribution
|
||||
@@ -393,76 +265,51 @@ slots and deliver
|
||||
|
||||
### Timing-Verifiable Test Checks
|
||||
|
||||
- **iOS/Android (app killed):** locals will fire at their slots; no network
|
||||
activity at delivery time.
|
||||
- **iOS/Android (resume inside lead):** exactly **one** online-first attempt
|
||||
occurs; if fetch completes within **12s** → content updated; otherwise offline
|
||||
policy applies.
|
||||
- **Android (no exact access):** observed delivery is within **±10 min** of slot
|
||||
time.
|
||||
- **Web push:** SW push event fetch runs once with **12s** timeout; if it times
|
||||
out, the push still displays (from payload).
|
||||
- **Electron (app running):** timer-based locals fire on time; on reboot with
|
||||
**Start on Login**, orchestrator re-arms on first run.
|
||||
- **iOS/Android (app killed):** locals will fire at their slots; no network activity at delivery time.
|
||||
- **iOS/Android (resume inside lead):** exactly **one** online-first attempt occurs; if fetch completes within **12s** → content updated; otherwise offline policy applies.
|
||||
- **Android (no exact access):** observed delivery is within **±10 min** of slot time.
|
||||
- **Web push:** SW push event fetch runs once with **12s** timeout; if it times out, the push still displays (from payload).
|
||||
- **Electron (app running):** timer-based locals fire on time; on reboot with **Start on Login**, orchestrator re-arms on first run.
|
||||
- **TTL behavior:** offline & stale → **skip** (no notification posted).
|
||||
- **ETag path:** with `304`, last payload remains; no duplicate scheduling rows
|
||||
(unique index enforced).
|
||||
- **Cooldown:** calling `deliverStoredNow` twice within **60s** for same slot
|
||||
doesn't produce two notifications.
|
||||
- **Closed app, armed earlier** → locals fire at slot; title/body match last
|
||||
rendered content (proves "render at schedule time" + adapter API).
|
||||
- **Closed app, timezone change before slot** → on next resume, app recomputes
|
||||
and re-arms; already armed notifications will still fire on original wall-time
|
||||
- **Mobile closed-app, no background network:** Arm at T–hours; kill app; verify
|
||||
locals fire with last rendered text; confirm **no** network egress at delivery.
|
||||
- **Web push as network scheduler:** Send push with empty payload → SW fetches
|
||||
within 12s timeout → shows correct text; confirm behavior with browser closed.
|
||||
- **Electron app not running:** No delivery; with **Start on Login**, after
|
||||
reboot first run fetches and re-arms; subsequent slots fire.
|
||||
- **Runner fires in background (Android/iOS):** With Runner enabled and app
|
||||
backgrounded for ≥30 min, at least one prefetch **will** occur; content cache
|
||||
**will** update; already-armed locals **will** still fire on time.
|
||||
- **Runner re-arm (flagged):** If `runnerRearm=true` and Runner fires inside lead
|
||||
with fresh content + within TTL, the system **will** cancel & re-arm the next
|
||||
slot; delivered text **will** match fresh template.
|
||||
- **ETag path:** with `304`, last payload remains; no duplicate scheduling rows (unique index enforced).
|
||||
- **Cooldown:** calling `deliverStoredNow` twice within **60s** for same slot doesn't produce two notifications.
|
||||
- **Closed app, armed earlier** → locals fire at slot; title/body match last rendered content (proves "render at schedule time" + adapter API).
|
||||
- **Closed app, timezone change before slot** → on next resume, app recomputes and re-arms; already armed notifications will still fire on original wall-time
|
||||
- **Mobile closed-app, no background network:** Arm at T–hours; kill app; verify locals fire with last rendered text; confirm **no** network egress at delivery.
|
||||
- **Web push as network scheduler:** Send push with empty payload → SW fetches within 12s timeout → shows correct text; confirm behavior with browser closed.
|
||||
- **Electron app not running:** No delivery; with **Start on Login**, after reboot first run fetches and re-arms; subsequent slots fire.
|
||||
- **Runner fires in background (Android/iOS):** With Runner enabled and app backgrounded for ≥30 min, at least one prefetch **will** occur; content cache **will** update; already-armed locals **will** still fire on time.
|
||||
- **Runner re-arm (flagged):** If `runnerRearm=true` and Runner fires inside lead with fresh content + within TTL, the system **will** cancel & re-arm the next slot; delivered text **will** match fresh template.
|
||||
|
||||
---
|
||||
|
||||
## 15) Test Matrix (Essentials)
|
||||
## 16) Test Matrix (Essentials)
|
||||
|
||||
- **Android:** exact vs inexact branch, Doze/App Standby behavior, reboot/time
|
||||
change, permission denial path, deep‑link to exact‑alarm settings.
|
||||
- **iOS:** BG fetch budget limits, pending cap windowing, local notification
|
||||
delivery with app terminated, category actions.
|
||||
- **Web:** SW lifecycle, push delivery with app closed, click handling, no
|
||||
offline scheduling.
|
||||
- **Cross‑cutting:** ETag/304 behavior, TTL policy, templating correctness, event
|
||||
queue drain, SQLite retention job.
|
||||
- **Android:** exact vs inexact branch, Doze/App Standby behavior, reboot/time change, permission denial path, deep‑link to exact‑alarm settings.
|
||||
- **iOS:** BG fetch budget limits, pending cap windowing, local notification delivery with app terminated, category actions.
|
||||
- **Web:** SW lifecycle, push delivery with app closed, click handling, no offline scheduling.
|
||||
- **Cross‑cutting:** ETag/304 behavior, TTL policy, templating correctness, event queue drain, SQLite retention job.
|
||||
|
||||
---
|
||||
|
||||
## 16) Migration & Rollout Notes
|
||||
## 17) Migration & Rollout Notes
|
||||
|
||||
- We **will keep** existing web push flows intact.
|
||||
- We **will introduce** the orchestrator behind a feature flag, initially with
|
||||
a small number of slots.
|
||||
- We **will introduce** the orchestrator behind a feature flag, initially with a small number of slots.
|
||||
- We **will migrate** settings to accept multiple times per day.
|
||||
- We **will document** platform caveats inside user‑visible settings (e.g.,
|
||||
Android exact alarms, iOS cap).
|
||||
- We **will document** platform caveats inside user‑visible settings (e.g., Android exact alarms, iOS cap).
|
||||
|
||||
---
|
||||
|
||||
## 17) Security & Privacy
|
||||
## 18) Security & Privacy
|
||||
|
||||
- Tokens **will reside** in Keystore/Keychain (mobile) and **will be injected**
|
||||
at request time; they **will not** be stored in SQLite.
|
||||
- Optionally, SQLCipher at rest for mobile; redaction of PII in logs; payload
|
||||
size caps.
|
||||
- Tokens **will reside** in Keystore/Keychain (mobile) and **will be injected** at request time; they **will not** be stored in SQLite.
|
||||
- Optionally, SQLCipher at rest for mobile; redaction of PII in logs; payload size caps.
|
||||
- Content **will be** minimal (title/body); sensitive data **will not be** embedded.
|
||||
|
||||
---
|
||||
|
||||
## 18) Non‑Goals (Now)
|
||||
## 19) Non‑Goals (Now)
|
||||
|
||||
- Complex action sets and rich media on locals (kept minimal).
|
||||
- Delivery‑time mutation of local notifications on iOS (NSE is for remote).
|
||||
@@ -470,69 +317,19 @@ size caps.
|
||||
|
||||
---
|
||||
|
||||
## 19) Cross-Doc Sync Hygiene
|
||||
## 20) Cross-Document Synchronization
|
||||
|
||||
### Canonical Ownership
|
||||
**Canonical Ownership:**
|
||||
- **This document (Plan):** Goals, Tenets, Platform behaviors, Acceptance criteria, Test cases
|
||||
- **Implementation document:** API definitions, Database schemas, Adapter implementations, Code examples
|
||||
|
||||
- **This document (Plan)**: Canonical for Goals, Tenets, Platform behaviors,
|
||||
Acceptance criteria, Test cases
|
||||
- **Implementation document**: Canonical for API definitions, Database schemas,
|
||||
Adapter implementations, Code examples
|
||||
|
||||
### PR Checklist
|
||||
|
||||
When changing notification system behavior, update both documents:
|
||||
|
||||
- [ ] **API changes**: Update types/interfaces in both Plan §4 and Implementation §3
|
||||
- [ ] **Schema changes**: Update Plan §5 and Implementation §2
|
||||
- [ ] **Slot/TTL changes**: Update Plan §4 semantics and Implementation §6 logic
|
||||
- [ ] **Template changes**: Update Plan §9 contract and Implementation examples
|
||||
- [ ] **Error codes**: Update Plan §11 taxonomy and Implementation error handling
|
||||
|
||||
- **API code blocks**: Must be identical between Plan §4 and Implementation §3
|
||||
(Public API (Shared))
|
||||
- **Feature flags**: Must match between Plan §12 table and Implementation defaults
|
||||
- **Test cases**: Plan §13 acceptance criteria must align with Implementation
|
||||
test examples
|
||||
- **Slot/TTL/Lead policies**: Must be identical between Plan §4 policy and
|
||||
Implementation §3 policy
|
||||
**Synchronization Requirements:**
|
||||
- API code blocks must be identical between Plan §4 and Implementation §3
|
||||
- Feature flags must match between Plan §13 and Implementation §15 defaults
|
||||
- Test cases must align between Plan §14 acceptance criteria and Implementation examples
|
||||
- Error codes must match between Plan §11 taxonomy and Implementation error handling
|
||||
- Slot/TTL/Lead policies must be identical between Plan §4 semantics and Implementation §9 logic
|
||||
|
||||
---
|
||||
|
||||
## Sync Checklist
|
||||
|
||||
| Sync item | Plan | Impl | Status |
|
||||
| ------------------------------ | --------------------- | --------------------- | ------ |
|
||||
| Public API block identical | §4 | §3 | ✅ |
|
||||
| `getState()` fields present | §4 | §8 Orchestrator | ✅ |
|
||||
| Capacitor action handlers | §7 (iOS/Android note) | §9 Bootstrap | ✅ |
|
||||
| Electron fetch prereq/polyfill | §7 | §9 Electron | ✅ |
|
||||
| Android ±10m fallback | §7 | §7 SchedulerCapacitor | ✅ |
|
||||
| Retention (no VACUUM v1) | §5 | `$pruneNotifData` | ✅ |
|
||||
| Runner described as **opportunistic prefetch**, not scheduler | §7 | §9 | ✅ |
|
||||
| Feature flag `prefetchRunner` (default `'none'`) | §13 | §15 | ✅ |
|
||||
| Capabilities `networkWake: 'opportunistic' | 'none'` | §7 | Scheduler.capabilities | ✅ |
|
||||
| Runner tick handler bounded to ≤12s | §7 | BackgroundRunnerPrefetch | ✅ |
|
||||
| Optional `runnerRearm` flag & behavior | §7 | Orchestrator + Runner | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## Sync Checklist
|
||||
|
||||
| Sync item | Plan | Impl | Status |
|
||||
| ------------------------------ | --------------------- | --------------------- | ------ |
|
||||
| Public API block identical | §4 | §3 | ✅ |
|
||||
| `getState()` fields present | §4 | §8 Orchestrator | ✅ |
|
||||
| Capacitor action handlers | §7 (iOS/Android note) | §9 Bootstrap | ✅ |
|
||||
| Electron fetch prereq/polyfill | §7 | §9 Electron | ✅ |
|
||||
| Android ±10m fallback | §7 | §7 SchedulerCapacitor | ✅ |
|
||||
| Retention (no VACUUM v1) | §5 | `$pruneNotifData` | ✅ |
|
||||
| Runner described as **opportunistic prefetch**, not scheduler | §7 | §9 | ✅ |
|
||||
| Feature flag `prefetchRunner` (default `'none'`) | §13 | §15 | ✅ |
|
||||
| Capabilities `networkWake: 'opportunistic' | 'none'` | §7 | Scheduler.capabilities | ✅ |
|
||||
| Runner tick handler bounded to ≤12s | §7 | BackgroundRunnerPrefetch | ✅ |
|
||||
| Optional `runnerRearm` flag & behavior | §7 | Orchestrator + Runner | ✅ |
|
||||
|
||||
---
|
||||
|
||||
*This strategic plan focuses on features and future‑tense deliverables, avoids implementation details, and preserves a clear path from the in‑app orchestrator (v1) to native plugin (v2). For executive overview, see `notification-system-executive-summary.md`. For complete implementation details, see `notification-system-implementation.md`.*
|
||||
*This strategic plan focuses on features and future‑tense deliverables, avoids implementation details, and preserves a clear path from the in‑app orchestrator (v1) to native plugin (v2).*
|
||||
Reference in New Issue
Block a user