Browse Source
- Add GLOSSARY.md with core terminology and cross-references - Add implementation-roadmap.md with 3-phase development plan - Add notification-system.md with Native-First architecture spec - Update ios/Plugin/README.md to reflect actual vs planned implementation status This establishes the foundation for implementing shared SQLite storage, TTL-at-fire enforcement, rolling window safety, and platform completion as outlined in the phased roadmap. Files: 4 changed, 807 insertions(+), 13 deletions(-)research/notification-plugin-enhancement
7 changed files with 903 additions and 13 deletions
@ -0,0 +1,96 @@ |
|||||
|
--- |
||||
|
title: Documentation, References, and Model Agent Use |
||||
|
version: 1.1 |
||||
|
alwaysApply: true |
||||
|
scope: code, project-plans |
||||
|
--- |
||||
|
|
||||
|
# Directive on Documentation, References, and Model Agent Use in Code and Project Plans |
||||
|
|
||||
|
To ensure clarity, efficiency, and high-value documentation within code and project plans—and to leverage **model agents** (AI- or automation-based assistants) effectively—contributors must follow these rules: |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## 1. Documentation and References Must Add Clear Value |
||||
|
|
||||
|
- Only include documentation, comments, or reference links when they provide _new, meaningful information_ that assists understanding or decision-making. |
||||
|
- Avoid duplicating content already obvious in the codebase, version history, or linked project documents. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## 2. Eliminate Redundant or Noisy References |
||||
|
|
||||
|
- Remove references that serve no purpose beyond filling space. |
||||
|
- Model agents may automatically flag and suggest removal of trivial references (e.g., links to unchanged boilerplate or self-evident context). |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## 3. Explicit Role of Model Agents |
||||
|
|
||||
|
Model agents are **active participants** in documentation quality control. Their tasks include: |
||||
|
|
||||
|
- **Relevance Evaluation**: Automatically analyze references for their substantive contribution before inclusion. |
||||
|
- **Redundancy Detection**: Flag duplicate or trivial references across commits, files, or tasks. |
||||
|
- **Context Linking**: Suggest appropriate higher-level docs (designs, ADRs, meeting notes) when a code change touches multi-stage or cross-team items. |
||||
|
- **Placement Optimization**: Recommend centralization of references (e.g., in plan overviews, ADRs, or merge commit messages) rather than scattered low-value inline references. |
||||
|
- **Consistency Monitoring**: Ensure references align with team standards (e.g., ADR template, architecture repo, or external policy documents). |
||||
|
|
||||
|
Contributors must treat agent recommendations as **first-pass reviews** but remain accountable for final human judgment. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## 4. Contextual References for Complex Items |
||||
|
|
||||
|
- Use **centralized references** for multi-stage features (e.g., architectural docs, research threads). |
||||
|
- Keep inline code comments light; push broader context into centralized documents. |
||||
|
- Model agents may auto-summarize complex chains of discussion and attach them as a single reference point. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## 5. Centralization of Broader Context |
||||
|
|
||||
|
- Store overarching context (design docs, proposals, workflows) in accessible, well-indexed places. |
||||
|
- Model agents should assist by **generating reference maps** that track where docs are cited across the codebase. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## 6. Focused Documentation |
||||
|
|
||||
|
- Documentation should explain **why** and **how** decisions are made, not just what was changed. |
||||
|
- Model agents can auto-generate first-pass explanations from commit metadata, diffs, and linked issues—but humans must refine them for accuracy and intent. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## 7. Review and Accountability |
||||
|
|
||||
|
- Reviewers and team leads must reject submissions containing unnecessary or low-quality documentation. |
||||
|
- Model agent outputs are aids, not replacements—contributors remain responsible for **final clarity and relevance**. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## 8. Continuous Improvement and Agent Feedback Loops |
||||
|
|
||||
|
- Encourage iterative development of model agents so their evaluations become more precise over time. |
||||
|
- Contributions should include **feedback on agent suggestions** (e.g., accepted, rejected, or corrected) to train better future outputs. |
||||
|
- Agents should log patterns of “rejected” suggestions for refinement. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## 9. Workflow Overview (Mermaid Diagram) |
||||
|
|
||||
|
```mermaid |
||||
|
flowchart TD |
||||
|
A[Contributor] -->|Writes Code & Draft Docs| B[Model Agent] |
||||
|
B -->|Evaluates References| C{Relevant?} |
||||
|
C -->|Yes| D[Suggest Placement & Context Links] |
||||
|
C -->|No| E[Flag Redundancy / Noise] |
||||
|
D --> F[Contributor Refines Docs] |
||||
|
E --> F |
||||
|
F --> G[Reviewer] |
||||
|
G -->|Approves / Requests Revisions| H[Final Documentation] |
||||
|
G -->|Feedback on Agent Suggestions| B |
||||
|
``` |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
✅ **Outcome:** By integrating disciplined contributor standards with **model agent augmentation**, the team achieves documentation that is consistently _relevant, concise, centralized, and decision-focused_. AI ensures coverage and noise reduction, while humans ensure precision and judgment. |
@ -0,0 +1,31 @@ |
|||||
|
# Glossary |
||||
|
|
||||
|
**📝 SANITY CHECK IMPROVEMENTS APPLIED:** This document has been updated to accurately reflect current implementation status vs. planned features. |
||||
|
|
||||
|
**T (slot time)** — The local wall-clock time a notification should fire (e.g., 08:00). *See Notification System → Scheduling & T–lead.* |
||||
|
|
||||
|
**T–lead** — The moment **`prefetchLeadMinutes`** before **T** when the system *attempts* a **single** background prefetch. T–lead **controls prefetch attempts, not arming**; locals are pre-armed earlier to guarantee closed-app delivery. *See Notification System → Scheduling & T–lead and Roadmap Phase 2.1.* |
||||
|
|
||||
|
**Lead window** — The interval from **T–lead** up to **T** during which we **try once** to refresh content. It does **not** control arming; we pre-arm earlier. *See Notification System → Scheduling & T–lead.* |
||||
|
|
||||
|
**Rolling window** — Always keep **today's remaining** (and tomorrow if iOS pending caps allow) locals **armed** so the OS can deliver while the app is closed. *See Notification System → Scheduling & T–lead and Roadmap Phase 1.3.* |
||||
|
|
||||
|
**TTL (time-to-live)** — Maximum allowed payload age **at fire time**. If `T − fetchedAt > ttlSeconds`, we **skip** arming for that T. *See Notification System → Policies and Roadmap Phase 1.2.* |
||||
|
|
||||
|
**Shared DB (planned)** — The app and plugin will open the **same SQLite file**; the app owns schema/migrations, the plugin performs short writes with WAL. *Currently using SharedPreferences/UserDefaults.* *See Notification System → Storage and Roadmap Phase 1.1.* |
||||
|
|
||||
|
**WAL (Write-Ahead Logging)** — SQLite journaling mode that permits concurrent reads during writes; recommended for foreground-read + background-write. *See Notification System → Storage and Roadmap Phase 1.1.* |
||||
|
|
||||
|
**`PRAGMA user_version`** — An integer the app increments on each migration; the plugin **checks** (does not migrate) to ensure compatibility. *See Notification System → Storage and Roadmap Phase 1.1.* |
||||
|
|
||||
|
**Exact alarm (Android)** — Minute-precise alarm via `AlarmManager.setExactAndAllowWhileIdle`, subject to policy and permission. *See Notification System → Policies and Roadmap Phase 2.2.* |
||||
|
|
||||
|
**Windowed alarm (Android)** — Batched/inexact alarm via `setWindow(start,len)`; we target **±10 minutes** when exact alarms are unavailable. *See Notification System → Policies and Roadmap Phase 2.2.* |
||||
|
|
||||
|
**Delivery-time mutation (iOS)** — Not available for **local** notifications. Notification Service Extensions mutate **remote** pushes only; locals must be rendered before scheduling. *See Notification System → Policies.* |
||||
|
|
||||
|
**Start-on-Login** — Electron feature that automatically launches the application when the user logs into their system, enabling background notification scheduling and delivery after system reboot. *See Roadmap Phase 2.3.* |
||||
|
|
||||
|
**Tiered Storage (current)** — Current implementation uses SharedPreferences (Android) / UserDefaults (iOS) for quick access, in-memory cache for structured data, and file system for large assets. *See Notification System → Storage and Roadmap Phase 1.1.* |
||||
|
|
||||
|
**No delivery-time network:** Local notifications display **pre-rendered content only**; never fetch at delivery. *See Notification System → Policies.* |
@ -0,0 +1,486 @@ |
|||||
|
# Daily Notification Plugin - Implementation Roadmap |
||||
|
|
||||
|
**📝 SANITY CHECK IMPROVEMENTS APPLIED:** This document has been updated to clarify current implementation status and distinguish between existing infrastructure and planned T–lead logic. |
||||
|
|
||||
|
**Status:** Ready for implementation |
||||
|
**Date:** 2025-01-27 |
||||
|
**Author:** Matthew Raymer |
||||
|
**Assessment Date:** 2025-01-27 |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Executive Summary |
||||
|
|
||||
|
This document outlines the implementation roadmap to bring the current Daily Notification Plugin (65% complete) to full compliance with the Native-First Notification System specification. The implementation is organized into three phases, with Phase 1 containing critical infrastructure components required for core functionality. |
||||
|
|
||||
|
### Current State Assessment |
||||
|
- **Overall Completion:** 65% of specification requirements |
||||
|
- **Critical Gaps:** SQLite database sharing, TTL-at-fire enforcement, rolling window safety |
||||
|
- **Current Storage:** SharedPreferences (Android) / UserDefaults (iOS) + in-memory cache |
||||
|
- **Background Infrastructure:** Basic WorkManager (Android) exists, but lacks T–lead logic |
||||
|
- **Critical Path:** Data persistence → Freshness enforcement → Platform completion |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Current Implementation Status Clarification |
||||
|
|
||||
|
### Background Fetch Infrastructure |
||||
|
**Current State:** Basic infrastructure exists but lacks T–lead logic |
||||
|
- **Android:** `DailyNotificationFetchWorker.java` (WorkManager) exists |
||||
|
- **Android:** `DailyNotificationFetcher.java` with scheduling logic exists |
||||
|
- **Missing:** T–lead calculation, TTL enforcement, ETag support |
||||
|
- **Status:** Infrastructure ready, T–lead logic needs implementation |
||||
|
|
||||
|
### iOS Implementation Status |
||||
|
**Current State:** Basic plugin structure with power management |
||||
|
- **Implemented:** Plugin skeleton, power management, UserDefaults storage |
||||
|
- **Missing:** BGTaskScheduler, background tasks, T–lead prefetch |
||||
|
- **Status:** Foundation exists, background execution needs implementation |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
**Gate:** No further freshness or scheduling work merges to main until **shared SQLite** (see Glossary → Shared DB) is in place and reading/writing under **WAL** (see Glossary → WAL), with UI hot-read verified. |
||||
|
|
||||
|
**Dependencies:** None |
||||
|
|
||||
|
### 1.1 SQLite Database Sharing Implementation |
||||
|
|
||||
|
**Priority:** CRITICAL |
||||
|
|
||||
|
#### Requirements |
||||
|
- Migrate from SharedPreferences/UserDefaults to shared SQLite database (see Glossary → Shared DB) |
||||
|
- WAL mode configuration for concurrent access (see Glossary → WAL) |
||||
|
- Schema version checking and compatibility validation (see Glossary → PRAGMA user_version) |
||||
|
- Required tables: `notif_contents`, `notif_deliveries`, `notif_config` |
||||
|
- **Migration Strategy:** Gradual migration from current tiered storage (see Glossary → Tiered Storage) |
||||
|
|
||||
|
#### Implementation Tasks |
||||
|
- [ ] **Migration from Current Storage** |
||||
|
- Create migration utilities from SharedPreferences to SQLite |
||||
|
- Implement data migration from UserDefaults to SQLite (iOS) |
||||
|
- Add backward compatibility during transition |
||||
|
- Preserve existing notification data during migration |
||||
|
|
||||
|
- [ ] **SQLite Setup (Android)** |
||||
|
- Create `DailyNotificationDatabase.java` with WAL mode (see Glossary → WAL) |
||||
|
- Implement schema version checking (`PRAGMA user_version`) (see Glossary → PRAGMA user_version) |
||||
|
- Add database connection management with proper error handling |
||||
|
|
||||
|
- [ ] **Database Configuration** |
||||
|
- Add `dbPath: string` to `ConfigureOptions` interface |
||||
|
- Implement database path resolution (absolute vs platform alias) |
||||
|
- Add `storage: 'shared'` configuration option |
||||
|
- Extend existing `NotificationOptions` with database settings |
||||
|
|
||||
|
- [ ] **Database Schema** |
||||
|
```sql |
||||
|
-- notif_contents: keep history, newest-first reads |
||||
|
CREATE TABLE IF NOT EXISTS notif_contents( |
||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT, |
||||
|
slot_id TEXT NOT NULL, |
||||
|
payload_json TEXT NOT NULL, |
||||
|
fetched_at INTEGER NOT NULL, -- epoch ms |
||||
|
etag TEXT, |
||||
|
UNIQUE(slot_id, fetched_at) |
||||
|
); |
||||
|
CREATE INDEX IF NOT EXISTS notif_idx_contents_slot_time |
||||
|
ON notif_contents(slot_id, fetched_at DESC); |
||||
|
|
||||
|
-- notif_deliveries: track many deliveries per slot/time |
||||
|
CREATE TABLE IF NOT EXISTS notif_deliveries( |
||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT, |
||||
|
slot_id TEXT NOT NULL, |
||||
|
fire_at INTEGER NOT NULL, -- intended fire time (epoch ms) |
||||
|
delivered_at INTEGER, -- when actually shown (epoch ms) |
||||
|
status TEXT NOT NULL DEFAULT 'scheduled', -- scheduled|shown|error|canceled |
||||
|
error_code TEXT, error_message TEXT |
||||
|
); |
||||
|
|
||||
|
-- notif_config: generic configuration KV |
||||
|
CREATE TABLE IF NOT EXISTS notif_config( |
||||
|
k TEXT PRIMARY KEY, |
||||
|
v TEXT NOT NULL |
||||
|
); |
||||
|
``` |
||||
|
|
||||
|
#### Acceptance Criteria |
||||
|
- [ ] App and plugin can open the same SQLite file |
||||
|
- [ ] WAL mode enables concurrent reads during writes |
||||
|
- [ ] Schema version checking prevents compatibility issues |
||||
|
- [ ] All required tables exist and are accessible |
||||
|
- [ ] Shared DB visibility: UI reads updated rows immediately |
||||
|
- [ ] WAL overlap shows no UI blocking during background writes |
||||
|
- [ ] UI can read a row written by a background job **within the same second** (WAL hot-read) |
||||
|
- [ ] Plugin refuses to write if `PRAGMA user_version` < expected |
||||
|
|
||||
|
### 1.2 TTL-at-Fire Enforcement |
||||
|
|
||||
|
**Priority:** CRITICAL |
||||
|
|
||||
|
#### Requirements |
||||
|
- Skip arming notifications if `(T - fetchedAt) > ttlSeconds` (see Glossary → TTL) |
||||
|
- Validate freshness before scheduling |
||||
|
- Log TTL violations for debugging |
||||
|
- **Current State:** Not implemented - needs to be added to existing scheduling logic |
||||
|
- **Shared DB (single file):** App owns migrations (`PRAGMA user_version`) (see Glossary → PRAGMA user_version); plugin opens the **same path**; enable `journal_mode=WAL` (see Glossary → WAL), `synchronous=NORMAL`, `busy_timeout=5000`, `foreign_keys=ON`; background writes are **short & serialized**. |
||||
|
|
||||
|
#### Implementation Tasks |
||||
|
- [ ] **TTL Validation Logic** |
||||
|
- Insert TTL check into the scheduler path **before** any arm/re-arm |
||||
|
- Add log code `TTL_VIOLATION` |
||||
|
- Implement freshness validation before arming |
||||
|
- Before arming, if `(T − fetchedAt) > ttlSeconds`, **skip arming** and log `TTL_VIOLATION` |
||||
|
- Add TTL configuration to `NotificationOptions` |
||||
|
|
||||
|
- [ ] **Freshness Checking** |
||||
|
- Create `isContentFresh()` method |
||||
|
- Implement TTL calculation logic |
||||
|
- Add logging for TTL violations |
||||
|
|
||||
|
- [ ] **Configuration Integration** |
||||
|
- Add `ttlSeconds` to `NotificationOptions` interface |
||||
|
- Implement default TTL values (3600 seconds = 1 hour) |
||||
|
- Add TTL validation in option validation |
||||
|
|
||||
|
#### Acceptance Criteria |
||||
|
- [ ] Notifications are skipped if content is stale |
||||
|
- [ ] TTL violations are logged with timestamps |
||||
|
- [ ] Default TTL values are applied when not specified |
||||
|
- [ ] Freshness checking works across all platforms |
||||
|
- [ ] No armed notification violates **TTL-at-fire** |
||||
|
- [ ] No armed row violates TTL at T across platforms |
||||
|
|
||||
|
### 1.3 Rolling Window Safety |
||||
|
|
||||
|
**Priority:** CRITICAL |
||||
|
|
||||
|
#### Requirements |
||||
|
- Keep today's remaining notifications armed |
||||
|
- Keep tomorrow's notifications armed (within iOS caps) (see Glossary → Rolling window) |
||||
|
- Ensure closed-app delivery reliability |
||||
|
- **Current State:** Basic scheduling exists, but no rolling window logic |
||||
|
|
||||
|
#### Implementation Tasks |
||||
|
- [ ] **Rolling Window Logic** (see Glossary → Rolling window) |
||||
|
- Implement `armRollingWindow()` method |
||||
|
- Calculate today's remaining slots |
||||
|
- Calculate tomorrow's slots within iOS limits |
||||
|
- Account for iOS pending-notification limits; arm tomorrow only if within cap |
||||
|
|
||||
|
- [ ] **iOS Capacity Management** |
||||
|
- Implement iOS pending notification limit checking |
||||
|
- Add capacity-aware scheduling logic |
||||
|
- Handle capacity overflow gracefully |
||||
|
|
||||
|
- [ ] **Window Maintenance** |
||||
|
- Create `maintainRollingWindow()` method |
||||
|
- Implement automatic re-arming logic |
||||
|
- Add window state persistence |
||||
|
|
||||
|
#### Acceptance Criteria |
||||
|
- [ ] Today's remaining notifications stay armed |
||||
|
- [ ] Tomorrow's notifications are armed within iOS caps |
||||
|
- [ ] Closed-app delivery works reliably |
||||
|
- [ ] Window maintenance runs automatically |
||||
|
- [ ] Today always armed; tomorrow armed when within iOS cap |
||||
|
|
||||
|
### 1.4 Configuration API Enhancement |
||||
|
|
||||
|
**Priority:** HIGH |
||||
|
|
||||
|
#### Requirements |
||||
|
- Add `dbPath` configuration option |
||||
|
- Implement database path resolution |
||||
|
- Add storage mode configuration |
||||
|
- **Current State:** No database path configuration exists |
||||
|
|
||||
|
#### Implementation Tasks |
||||
|
- [ ] **Interface Updates** |
||||
|
- Extend `ConfigureOptions` with `dbPath: string` |
||||
|
- Add `storage: 'shared'` option |
||||
|
- Update validation logic |
||||
|
|
||||
|
- [ ] **Path Resolution** |
||||
|
- Implement absolute path handling |
||||
|
- Add platform-specific path resolution |
||||
|
- Create path validation logic |
||||
|
|
||||
|
#### Acceptance Criteria |
||||
|
- [ ] `dbPath` can be configured via API |
||||
|
- [ ] Path resolution works on all platforms |
||||
|
- [ ] Configuration validation prevents invalid paths |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Phase 2: Platform Completion (High Priority) |
||||
|
|
||||
|
**Dependencies:** Phase 1 completion - **CRITICAL:** Phase 2 cannot start until SQLite sharing + TTL enforcement are finished |
||||
|
|
||||
|
### 2.1 iOS Background Tasks Implementation |
||||
|
|
||||
|
**Priority:** HIGH |
||||
|
|
||||
|
#### Requirements |
||||
|
- `BGTaskScheduler` for T-lead prefetch (see Glossary → T–lead) |
||||
|
- Silent push nudge support |
||||
|
- Background execution budget management |
||||
|
- Schedule prefetch at **T–lead = T − prefetchLeadMinutes** (see Glossary → T–lead) |
||||
|
- On wake, perform **one** ETag-aware fetch with **12s** timeout; **never** fetch at delivery |
||||
|
- Optionally (re)arm if still within **TTL-at-fire** (see Glossary → TTL) |
||||
|
- Single attempt at **T–lead**; **12s** timeout; no delivery-time fetch; (re)arm only if within **TTL-at-fire**. **(Planned)** |
||||
|
|
||||
|
#### Implementation Tasks |
||||
|
- [ ] **BGTaskScheduler Integration** |
||||
|
- Create `DailyNotificationBackgroundTask.swift` |
||||
|
- Implement background task registration |
||||
|
- Add task expiration handling |
||||
|
|
||||
|
- [ ] **Silent Push Support** |
||||
|
- Add silent push notification handling |
||||
|
- Implement push-to-background task bridge |
||||
|
- Add push token management |
||||
|
|
||||
|
- [ ] **Budget Management** |
||||
|
- Implement execution budget tracking |
||||
|
- Add budget-aware scheduling |
||||
|
- Handle budget exhaustion gracefully |
||||
|
|
||||
|
#### Acceptance Criteria |
||||
|
- [ ] Background tasks run at T-lead (see Glossary → T–lead) |
||||
|
- [ ] Silent push can trigger background execution |
||||
|
- [ ] Budget management prevents system penalties |
||||
|
- [ ] Background execution works when app is closed |
||||
|
- [ ] iOS BGTask best-effort at T–lead; closed-app still delivers via rolling window (see Glossary → Rolling window) |
||||
|
|
||||
|
### 2.2 Android Fallback Completion |
||||
|
|
||||
|
**Priority:** HIGH |
||||
|
|
||||
|
#### Requirements |
||||
|
- Complete ±10 minute windowed alarm implementation (see Glossary → Windowed alarm) |
||||
|
- Finish reboot/time change recovery |
||||
|
- Improve exact alarm fallback handling (see Glossary → Exact alarm) |
||||
|
- Finalize ±10m windowed alarm; reboot/time-change recovery; deep-link to Exact Alarm permission. **(Planned)** |
||||
|
|
||||
|
#### Implementation Tasks |
||||
|
- [ ] **Windowed Alarm Implementation** |
||||
|
- Complete `scheduleInexactAlarm()` method |
||||
|
- Implement ±10 minute window targeting |
||||
|
- Add window size configuration |
||||
|
|
||||
|
- [ ] **Recovery Mechanisms** |
||||
|
- Complete `BOOT_COMPLETED` receiver |
||||
|
- Implement `TIMEZONE_CHANGED` handling |
||||
|
- Add `TIME_SET` recovery logic |
||||
|
|
||||
|
- [ ] **Fallback Logic** |
||||
|
- Improve exact alarm permission checking |
||||
|
- Add graceful degradation to windowed alarms |
||||
|
- Implement fallback logging |
||||
|
|
||||
|
#### Acceptance Criteria |
||||
|
- [ ] Windowed alarms target ±10 minute windows |
||||
|
- [ ] Reboot recovery re-arms next 24h |
||||
|
- [ ] Time change recovery recomputes schedules |
||||
|
- [ ] Fallback works seamlessly |
||||
|
- [ ] Android exact permission path verified with fallback ±10m |
||||
|
|
||||
|
### 2.3 Electron Platform Support |
||||
|
|
||||
|
**Priority:** MEDIUM |
||||
|
|
||||
|
#### Requirements |
||||
|
- Notifications while app is running |
||||
|
- Start-on-Login support |
||||
|
- Best-effort background scheduling |
||||
|
|
||||
|
#### Implementation Tasks |
||||
|
- [ ] **Electron Integration** |
||||
|
- Create `DailyNotificationElectron.ts` |
||||
|
- Implement notification API |
||||
|
- Add Start-on-Login support |
||||
|
|
||||
|
- [ ] **Background Limitations** |
||||
|
- Document Electron limitations |
||||
|
- Implement best-effort scheduling |
||||
|
- Add fallback mechanisms |
||||
|
|
||||
|
#### Acceptance Criteria |
||||
|
- [ ] Notifications work while app is running |
||||
|
- [ ] Start-on-Login enables post-reboot delivery |
||||
|
- [ ] Limitations are clearly documented |
||||
|
- [ ] Best-effort scheduling is implemented |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Phase 3: Network Optimization (Medium Priority) |
||||
|
|
||||
|
**Dependencies:** Phase 1 completion - **CRITICAL:** Phase 3 cannot start until SQLite sharing + TTL enforcement are finished |
||||
|
|
||||
|
### 3.1 ETag Support Implementation |
||||
|
|
||||
|
**Priority:** MEDIUM |
||||
|
|
||||
|
#### Requirements |
||||
|
- ETag headers in fetch requests |
||||
|
- 304 response handling |
||||
|
- Network efficiency optimization |
||||
|
|
||||
|
#### Implementation Tasks |
||||
|
- [ ] **ETag Headers** |
||||
|
- Add ETag to fetch requests |
||||
|
- Implement ETag storage in database |
||||
|
- Add ETag validation logic |
||||
|
|
||||
|
- [ ] **304 Response Handling** |
||||
|
- Implement 304 response processing |
||||
|
- Add conditional request logic |
||||
|
- Handle ETag mismatches |
||||
|
|
||||
|
- [ ] **Network Optimization** |
||||
|
- Add request caching |
||||
|
- Implement conditional fetching |
||||
|
- Add network efficiency metrics |
||||
|
|
||||
|
#### Acceptance Criteria |
||||
|
- [ ] ETag headers are sent with requests |
||||
|
- [ ] 304 responses are handled correctly |
||||
|
- [ ] Network efficiency is improved |
||||
|
- [ ] Conditional requests work reliably |
||||
|
|
||||
|
### 3.2 Advanced Error Handling |
||||
|
|
||||
|
**Priority:** MEDIUM |
||||
|
|
||||
|
#### Requirements |
||||
|
- Comprehensive error categorization |
||||
|
- Retry logic with exponential backoff |
||||
|
- Error reporting and telemetry |
||||
|
|
||||
|
#### Implementation Tasks |
||||
|
- [ ] **Error Categories** |
||||
|
- Define error types and codes |
||||
|
- Implement error classification |
||||
|
- Add error severity levels |
||||
|
|
||||
|
- [ ] **Retry Logic** |
||||
|
- Implement exponential backoff |
||||
|
- Add retry limit configuration |
||||
|
- Create retry state management |
||||
|
|
||||
|
- [ ] **Telemetry** |
||||
|
- Add error reporting |
||||
|
- Implement success/failure metrics |
||||
|
- Create debugging information |
||||
|
|
||||
|
#### Acceptance Criteria |
||||
|
- [ ] Errors are properly categorized |
||||
|
- [ ] Retry logic works with backoff |
||||
|
- [ ] Telemetry provides useful insights |
||||
|
- [ ] Debugging information is comprehensive |
||||
|
|
||||
|
### 3.3 Performance Optimization |
||||
|
|
||||
|
**Priority:** LOW |
||||
|
|
||||
|
#### Requirements |
||||
|
- Database query optimization |
||||
|
- Memory usage optimization |
||||
|
- Battery usage optimization |
||||
|
|
||||
|
#### Implementation Tasks |
||||
|
- [ ] **Database Optimization** |
||||
|
- Add database indexes |
||||
|
- Optimize query performance |
||||
|
- Implement connection pooling |
||||
|
|
||||
|
- [ ] **Memory Optimization** |
||||
|
- Reduce memory footprint |
||||
|
- Implement object pooling |
||||
|
- Add memory usage monitoring |
||||
|
|
||||
|
- [ ] **Battery Optimization** |
||||
|
- Minimize background CPU usage |
||||
|
- Optimize network requests |
||||
|
- Add battery usage tracking |
||||
|
|
||||
|
#### Acceptance Criteria |
||||
|
- [ ] Database queries are optimized |
||||
|
- [ ] Memory usage is minimized |
||||
|
- [ ] Battery usage is optimized |
||||
|
- [ ] Performance metrics are tracked |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Implementation Guidelines |
||||
|
|
||||
|
### Development Standards |
||||
|
- **Code Quality:** Follow existing code style and documentation standards |
||||
|
- **Testing:** Write unit tests for all new functionality |
||||
|
- **Documentation:** Update documentation for all API changes |
||||
|
- **Logging:** Add comprehensive logging with proper tagging |
||||
|
- **Security:** Follow security best practices for database access |
||||
|
|
||||
|
### Testing Requirements |
||||
|
- **Unit Tests:** All new methods must have unit tests |
||||
|
- **Integration Tests:** Test database sharing functionality |
||||
|
- **Platform Tests:** Test on Android, iOS, and Electron |
||||
|
- **Edge Cases:** Test TTL violations, network failures, and recovery scenarios |
||||
|
|
||||
|
### Documentation Updates |
||||
|
- **API Documentation:** Update TypeScript definitions |
||||
|
- **Implementation Guide:** Update implementation documentation |
||||
|
- **Troubleshooting:** Add troubleshooting guides for common issues |
||||
|
- **Examples:** Create usage examples for new features |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Success Metrics |
||||
|
|
||||
|
### Phase 1 Success Criteria |
||||
|
- [ ] SQLite database sharing works reliably |
||||
|
- [ ] TTL-at-fire enforcement prevents stale notifications |
||||
|
- [ ] Rolling window ensures closed-app delivery |
||||
|
- [ ] Configuration API supports all required options |
||||
|
|
||||
|
### Phase 2 Success Criteria |
||||
|
- [ ] iOS background tasks run at T-lead |
||||
|
- [ ] Android fallback works seamlessly |
||||
|
- [ ] Electron notifications work while running |
||||
|
- [ ] All platforms support the unified API |
||||
|
|
||||
|
### Phase 3 Success Criteria |
||||
|
- [ ] ETag support improves network efficiency |
||||
|
- [ ] Error handling is comprehensive and robust |
||||
|
- [ ] Performance is optimized across all platforms |
||||
|
- [ ] System meets all specification requirements |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Risk Mitigation |
||||
|
|
||||
|
### Technical Risks |
||||
|
- **Database Compatibility:** Test schema version checking thoroughly |
||||
|
- **Platform Differences:** Implement platform-specific fallbacks |
||||
|
- **Background Execution:** Handle iOS background execution limitations |
||||
|
- **Permission Changes:** Monitor Android permission policy changes |
||||
|
|
||||
|
### Implementation Risks |
||||
|
- **Scope Creep:** Stick to specification requirements |
||||
|
- **Testing Coverage:** Ensure comprehensive testing |
||||
|
- **Documentation:** Keep documentation up-to-date |
||||
|
- **Performance:** Monitor performance impact |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Conclusion |
||||
|
|
||||
|
This roadmap provides a structured approach to completing the Daily Notification Plugin implementation. Phase 1 addresses the critical infrastructure gaps, Phase 2 completes platform-specific functionality, and Phase 3 optimizes the system for production use. |
||||
|
|
||||
|
The implementation should follow the existing code patterns and maintain the high quality standards established in the current codebase. Regular testing and documentation updates are essential for success. |
||||
|
|
||||
|
**Next Steps:** |
||||
|
1. Review and approve this roadmap |
||||
|
2. Begin Phase 1 implementation |
||||
|
3. Set up testing infrastructure |
||||
|
4. Create implementation tracking system |
@ -0,0 +1,247 @@ |
|||||
|
# TimeSafari — Native-First Notification System |
||||
|
|
||||
|
**📝 SANITY CHECK IMPROVEMENTS APPLIED:** This document has been updated to clarify current background fetch infrastructure status and iOS implementation completeness. |
||||
|
|
||||
|
**Status:** Ready for implementation |
||||
|
**Date:** 2025-09-07 |
||||
|
**Author:** Matthew Raymer |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Executive Summary |
||||
|
|
||||
|
Ship a **single, Native-First** notification system: OS-scheduled **background prefetch at T–lead** + **pre-armed** local notifications. Web-push is retired. |
||||
|
|
||||
|
### What we deliver |
||||
|
|
||||
|
- **Closed-app delivery:** Pre-armed locals fire even if the app is closed. |
||||
|
- **Freshness:** One prefetch attempt per slot at **T–lead**; ETag/TTL controls; skip when stale. |
||||
|
- **Android precision:** Exact alarms with permission; windowed fallback (±10m) otherwise. |
||||
|
- **Resilience:** Re-arm after reboot/time-change (Android receivers; iOS on next wake/silent push). |
||||
|
- **Cross-platform:** Same TS API (iOS/Android/Electron). Electron is best-effort while running. |
||||
|
|
||||
|
### Success signals |
||||
|
|
||||
|
- High delivery reliability, minute-precision on Android with permission. |
||||
|
- Prefetch budget hit rate at **T–lead**; zero stale deliveries beyond TTL. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Strategic Plan |
||||
|
|
||||
|
### Goal |
||||
|
|
||||
|
Deliver 1..M daily notifications with **OS background prefetch at T–lead** *(see Glossary)* and **rolling-window safety** *(see Glossary)* so messages display with fresh content even when the app is closed. |
||||
|
|
||||
|
### Tenets |
||||
|
|
||||
|
- **Reliability first:** OS delivers once scheduled; no JS at delivery time. |
||||
|
- **Freshness with guardrails:** Prefetch at **T–lead** *(see Glossary)*; enforce **TTL-at-fire** *(see Glossary)*; ETag-aware. |
||||
|
- **Single system:** One TS API; native adapters swap under the hood. |
||||
|
- **Platform honesty:** Android exactness via permission; iOS best-effort budget. |
||||
|
- **No delivery-time network:** Local notifications display **pre-rendered content only**; never fetch at delivery. |
||||
|
|
||||
|
### Architecture (high level) |
||||
|
|
||||
|
App (Vue/TS) → Orchestrator (policy) → Native Adapters: |
||||
|
|
||||
|
- **SchedulerNative** — AlarmManager (Android) / UNUserNotificationCenter (iOS) |
||||
|
- **BackgroundPrefetchNative** — WorkManager (Android) / BGTaskScheduler (+ silent push) (iOS) |
||||
|
- **DataStore** — SQLite |
||||
|
|
||||
|
**Storage:** **Current:** SharedPreferences (Android) / UserDefaults (iOS) + in-memory cache (see Glossary → Tiered Storage). **Planned:** one **shared SQLite** file (see Glossary → Shared DB); the app owns schema/migrations; the plugin opens the same path with **WAL** (see Glossary → WAL); background writes are **short & serialized**. *(Keep the "(Planned)" label until Phase 1 ships.)* |
||||
|
|
||||
|
### SQLite Ownership & Concurrency *(Planned)* |
||||
|
|
||||
|
* **One DB file:** The plugin will open the **same path** the app uses (no second DB). |
||||
|
* **Migrations owned by app:** The app executes schema migrations and bumps `PRAGMA user_version` (see Glossary → PRAGMA user_version). The plugin **never** migrates; it **asserts** the expected version. |
||||
|
* **WAL mode:** Open DB with `journal_mode=WAL`, `synchronous=NORMAL`, `busy_timeout=5000`, `foreign_keys=ON`. WAL (see Glossary → WAL) allows foreground reads while a background job commits quickly. |
||||
|
* **Single-writer discipline:** Background jobs write in **short transactions** (UPSERT per slot), then return. |
||||
|
* **Encryption (optional):** If using SQLCipher, the **same key** is used by both app and plugin. Do not mix encrypted and unencrypted openings. |
||||
|
|
||||
|
*Note: Currently using SharedPreferences (Android) / UserDefaults (iOS) with in-memory cache. See Implementation Roadmap → Phase 1.1 for migration steps.* |
||||
|
|
||||
|
### Scheduling & T–lead *(Planned)* |
||||
|
|
||||
|
- Arm **rolling window** (see Glossary → Rolling window). **(Planned)** |
||||
|
- Exactly **one** online-first fetch at **T–lead** (see Glossary → T–lead) with **12s** timeout; **ETag/304** respected. **(Planned)** |
||||
|
- If fresh **and** within **TTL-at-fire** (see Glossary → TTL), (re)arm; otherwise keep prior content. **(Planned)** |
||||
|
- If the OS skips the wake, the pre-armed local still fires from cache. **(Planned)** |
||||
|
|
||||
|
*Note: Current implementation has basic scheduling and WorkManager infrastructure (Android) but lacks T–lead prefetch logic, rolling window logic, and iOS background tasks. See Implementation Roadmap → Phase 1-2.* |
||||
|
|
||||
|
### Policies *(Mixed Implementation)* |
||||
|
|
||||
|
- **TTL-at-fire** (see Glossary → TTL): Before arming for T, if `(T − fetchedAt) > ttlSeconds` → **skip**. **(Planned)** |
||||
|
- **Android exactness** (see Glossary → Exact alarm): **(Partial)** — permission flow exists; finalize ±10m window & deep-link to settings. |
||||
|
- **Reboot/time change:** **(Partial)** — Android receivers partially present; iOS via next wake/silent push. |
||||
|
- **No delivery-time network** (see Glossary → No delivery-time network): Local notifications display **pre-rendered content only**; never fetch at delivery. **(Implemented)** |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Implementation Guide |
||||
|
|
||||
|
### 1) Interfaces (TS stable) |
||||
|
|
||||
|
- **SchedulerNative**: `scheduleExact({slotId, whenMs, title, body, extra})`, `scheduleWindow(..., windowLenMs)`, `cancelBySlot`, `rescheduleAll`, `capabilities()` |
||||
|
- **BackgroundPrefetchNative**: `schedulePrefetch(slotId, atMs)`, `cancelPrefetch(slotId)` |
||||
|
- **DataStore**: SQLite adapters (notif_contents, notif_deliveries, notif_config) |
||||
|
- **Public API**: `configure`, `requestPermissions`, `runFullPipelineNow`, `reschedule`, `getState` |
||||
|
|
||||
|
### DB Path & Adapter Configuration *(Planned)* |
||||
|
|
||||
|
* **Configure option:** `dbPath: string` (absolute path or platform alias) will be passed from JS to the plugin during `configure()`. |
||||
|
* **Shared tables:** |
||||
|
|
||||
|
* `notif_contents(slot_id, payload_json, fetched_at, etag, …)` |
||||
|
* `notif_deliveries(slot_id, fire_at, delivered_at, status, error_code, …)` |
||||
|
* `notif_config(k, v)` |
||||
|
* **Open settings:** |
||||
|
|
||||
|
* `journal_mode=WAL` |
||||
|
* `synchronous=NORMAL` |
||||
|
* `busy_timeout=5000` |
||||
|
* `foreign_keys=ON` |
||||
|
|
||||
|
*Note: Currently using SharedPreferences/UserDefaults (see Glossary → Tiered Storage). Database configuration is planned for Phase 1.* |
||||
|
|
||||
|
See **Implementation Roadmap → Phase 1.1** for migration steps and schema. |
||||
|
|
||||
|
**Type (TS) extension** *(Planned)* |
||||
|
|
||||
|
```ts |
||||
|
export type ConfigureOptions = { |
||||
|
// …existing fields… |
||||
|
dbPath: string; // shared DB file the plugin will open |
||||
|
storage: 'shared'; // canonical value; plugin-owned DB is not used |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
*Note: Current `NotificationOptions` interface exists but lacks `dbPath` configuration. This will be added in Phase 1.* |
||||
|
|
||||
|
**Plugin side (pseudo)** |
||||
|
|
||||
|
```kotlin |
||||
|
// Android open |
||||
|
val db = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE) |
||||
|
db.execSQL("PRAGMA journal_mode=WAL") |
||||
|
db.execSQL("PRAGMA synchronous=NORMAL") |
||||
|
db.execSQL("PRAGMA foreign_keys=ON") |
||||
|
db.execSQL("PRAGMA busy_timeout=5000") |
||||
|
// Verify schema version |
||||
|
val uv = rawQuery("PRAGMA user_version").use { it.moveToFirst(); it.getInt(0) } |
||||
|
require(uv >= MIN_EXPECTED_VERSION) { "Schema version too old" } |
||||
|
``` |
||||
|
|
||||
|
```swift |
||||
|
// iOS open (FMDB / SQLite3) |
||||
|
// Set WAL via PRAGMA after open; check user_version the same way. |
||||
|
``` |
||||
|
|
||||
|
### 2) Templating & Arming |
||||
|
|
||||
|
- Render `title/body` **before** scheduling; pass via **SchedulerNative**. |
||||
|
- Route all arming through **SchedulerNative** to centralize Android exact/window semantics. |
||||
|
|
||||
|
### 3) T–lead (single attempt) |
||||
|
|
||||
|
**T–lead governs prefetch, not arming.** We **arm** one-shot locals as part of the rolling window so closed-app delivery is guaranteed. At **T–lead = T − prefetchLeadMinutes**, the **native background job** attempts **one** 12s ETag-aware fetch. If fresh content arrives and will not violate **TTL-at-fire**, we (re)arm the upcoming slot; if the OS skips the wake, the pre-armed local still fires with cached content. |
||||
|
|
||||
|
- Compute T–lead = `whenMs - prefetchLeadMinutes*60_000`. |
||||
|
- `BackgroundPrefetchNative.schedulePrefetch(slotId, atMs=T–lead)`. |
||||
|
- On wake: **ETag** fetch (timeout **12s**), persist, optionally cancel & re-arm if within TTL. |
||||
|
- Never fetch at delivery time. |
||||
|
|
||||
|
### 4) TTL-at-fire |
||||
|
|
||||
|
**TTL-at-fire:** Before arming for time **T**, compute `T − fetchedAt`. If that exceeds `ttlSeconds`, **do not arm** (skip). This prevents posting stale notifications when the app has been closed for a long time. |
||||
|
|
||||
|
`if (whenMs - fetchedAt) > ttlSeconds*1000 → skip` |
||||
|
|
||||
|
### 5) Android specifics |
||||
|
|
||||
|
- Request `SCHEDULE_EXACT_ALARM`; deep-link if denied; fallback to `setWindow(start,len)` (±10m). |
||||
|
- Receivers: `BOOT_COMPLETED`, `TIMEZONE_CHANGED`, `TIME_SET` → recompute & re-arm for next 24h and schedule T–lead prefetch. |
||||
|
|
||||
|
### 6) iOS specifics |
||||
|
|
||||
|
- `BGTaskScheduler` for T–lead prefetch (best-effort). Optional silent push nudge. |
||||
|
- Locals: `UNCalendarNotificationTrigger` (one-shots); no NSE mutation for locals. |
||||
|
|
||||
|
### 7) Network & Timeouts |
||||
|
|
||||
|
- Content fetch: **12s** timeout; single attempt at T–lead; ETag/304 respected. |
||||
|
- ACK/Error: **8s** timeout, fire-and-forget. |
||||
|
|
||||
|
### 8) Electron |
||||
|
|
||||
|
- Notifications while app is running; recommend **Start-on-Login**. No true background scheduling when fully closed. |
||||
|
|
||||
|
### 9) Telemetry |
||||
|
|
||||
|
- Record `scheduled|shown|error`; ACK deliveries (8s timeout); include slot/times/TZ/app version. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Capability Matrix |
||||
|
|
||||
|
| Capability | Android (Native) | iOS (Native) | Electron | Web | |
||||
|
|---|---|---|---|---| |
||||
|
| Multi-daily locals (closed app) | ✅ | ✅ | ✅ (app running) | — | |
||||
|
| Prefetch at T–lead (app closed) | ✅ WorkManager | ⚠️ BGTask (best-effort) | ✅ (app running) | — | |
||||
|
| Re-arm after reboot/time-change | ✅ Receivers | ⚠️ On next wake/silent push | ✅ Start-on-Login | — | |
||||
|
| Minute-precision alarms | ✅ with exact permission | ❌ not guaranteed | ✅ timer best-effort | — | |
||||
|
| Delivery-time mutation for locals | ❌ | ❌ | — | — | |
||||
|
| ETag/TTL enforcement | ✅ | ✅ | ✅ | — | |
||||
|
| Rolling-window safety | ✅ | ✅ | ✅ | — | |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Acceptance Criteria |
||||
|
|
||||
|
### Core |
||||
|
|
||||
|
- **Closed-app delivery:** Armed locals fire at T with last rendered content. No delivery-time network. |
||||
|
- **T–lead prefetch:** Single background attempt at **T–lead**; if skipped, delivery still occurs from cache. |
||||
|
- **TTL-at-fire:** No armed local violates TTL at T. |
||||
|
|
||||
|
### Android |
||||
|
|
||||
|
- **Exact permission path:** With `SCHEDULE_EXACT_ALARM` → within ±1m; else **±10m** window. |
||||
|
- **Reboot recovery:** After reboot, receivers re-arm next 24h and schedule T–lead prefetch. |
||||
|
- **TZ/DST change:** Recompute & re-arm; future slots align to new wall-clock. |
||||
|
|
||||
|
### iOS |
||||
|
|
||||
|
- **BGTask budget respected:** Prefetch often runs but may be skipped; delivery still occurs via rolling window. |
||||
|
- **Force-quit caveat:** No background execution after user terminate; delivery still occurs if pre-armed. |
||||
|
|
||||
|
### Electron |
||||
|
|
||||
|
- **Running-app rule:** Delivery only while app runs; with Start-on-Login, after reboot the orchestrator re-arms and subsequent slots deliver. |
||||
|
|
||||
|
### Network |
||||
|
|
||||
|
- Content fetch timeout **12s**; ACK/Error **8s**; no retries inside lead; ETag honored. |
||||
|
|
||||
|
### Observability |
||||
|
|
||||
|
- Log/telemetry for `scheduled|shown|error`; ACK payload includes slot, times, device TZ, app version. |
||||
|
|
||||
|
### DB Sharing *(Planned)* |
||||
|
|
||||
|
* **Shared DB visibility:** A background prefetch writes `notif_contents`; the foreground UI **immediately** reads the same row. |
||||
|
* **WAL overlap:** With the app reading while the plugin commits, no user-visible blocking occurs. |
||||
|
* **Version safety:** If `user_version` is behind, the plugin emits an error and does not write (protects against partial installs). |
||||
|
|
||||
|
*Note: Currently using SharedPreferences/UserDefaults with in-memory cache. SQLite sharing is planned for Phase 1.* |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
## Web-Push Cleanup |
||||
|
|
||||
|
Web-push functionality has been retired due to unreliability. All web-push related code paths and documentation sections should be removed or marked as deprecated. See `web-push-cleanup-guide.md` for detailed cleanup steps. |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
_This document consolidates the Native-First notification system strategy, implementation details, capabilities, and acceptance criteria into a single comprehensive reference._ |
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue