wip_new_notifications #196
Open
anomalist
wants to merge 7 commits from wip_new_notifications
into master
33 changed files with 1234 additions and 201 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. |
@ -1,27 +1,56 @@ |
|||
{ |
|||
"MD013": { |
|||
"line_length": 80, |
|||
"code_blocks": false, |
|||
"tables": false, |
|||
"headings": false |
|||
"MD013": false, |
|||
"MD033": false, |
|||
"MD041": false, |
|||
"MD024": { |
|||
"siblings_only": true |
|||
}, |
|||
"MD029": { |
|||
"style": "ordered" |
|||
}, |
|||
"MD007": { |
|||
"indent": 2 |
|||
}, |
|||
"MD012": { |
|||
"maximum": 1 |
|||
}, |
|||
"MD012": true, |
|||
"MD022": true, |
|||
"MD025": true, |
|||
"MD026": { |
|||
"punctuation": ".,;:!" |
|||
}, |
|||
"MD030": { |
|||
"ul_single": 1, |
|||
"ol_single": 1, |
|||
"ul_multi": 1, |
|||
"ol_multi": 1 |
|||
}, |
|||
"MD031": true, |
|||
"MD032": true, |
|||
"MD047": true, |
|||
"MD009": true, |
|||
"MD010": true, |
|||
"MD004": { "style": "dash" }, |
|||
"MD029": { "style": "ordered" }, |
|||
"MD041": false, |
|||
"MD025": false, |
|||
"MD024": false, |
|||
"MD034": true, |
|||
"MD035": { |
|||
"style": "---" |
|||
}, |
|||
"MD036": false, |
|||
"MD003": false, |
|||
"MD040": false, |
|||
"MD055": false, |
|||
"MD056": false, |
|||
"MD034": false, |
|||
"MD023": false |
|||
"MD037": true, |
|||
"MD038": true, |
|||
"MD039": true, |
|||
"MD040": true, |
|||
"MD042": true, |
|||
"MD043": false, |
|||
"MD044": false, |
|||
"MD045": true, |
|||
"MD046": { |
|||
"style": "fenced" |
|||
}, |
|||
"MD047": true, |
|||
"MD048": { |
|||
"style": "backtick" |
|||
}, |
|||
"MD049": { |
|||
"style": "underscore" |
|||
}, |
|||
"MD050": { |
|||
"style": "asterisk" |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
# Glossary |
|||
|
|||
**T (slot time)** — The local wall-clock time a notification should fire (e.g., 08:00). |
|||
|
|||
**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. |
|||
|
|||
**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. |
|||
|
|||
**TTL (time-to-live)** — Maximum allowed payload age **at fire time**. If `T − fetchedAt > ttlSeconds`, we **skip** arming for that T. |
|||
|
|||
**Shared DB (default)** — The app and plugin open the **same SQLite file**; the app owns schema/migrations, the plugin performs short writes with WAL. |
|||
|
|||
**WAL (Write-Ahead Logging)** — SQLite journaling mode that permits concurrent reads during writes; recommended for foreground-read + background-write. |
|||
|
|||
**`PRAGMA user_version`** — An integer the app increments on each migration; the plugin **checks** (does not migrate) to ensure compatibility. |
|||
|
|||
**Exact alarm (Android)** — Minute-precise alarm via `AlarmManager.setExactAndAllowWhileIdle`, subject to policy and permission. |
|||
|
|||
**Windowed alarm (Android)** — Batched/inexact alarm via `setWindow(start,len)`; we target **±10 minutes** when exact alarms are unavailable. |
|||
|
|||
**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. |
@ -1,77 +1,11 @@ |
|||
# TimeSafari Docs |
|||
# TimeSafari — Native-First Notification System (Clean Pack) — 2025-09-07 |
|||
|
|||
## Generating PDF from Markdown on OSx |
|||
This pack contains a single-version **Native-First** documentation set with a clear definition of **T–lead** and aligned terminology. |
|||
|
|||
This uses Pandoc and BasicTex (LaTeX) Installed through Homebrew. |
|||
**Native-First =** OS-scheduled **background prefetch at T–lead** + **pre-armed one-shot local notifications**. Web-push is retired. |
|||
|
|||
### Set Up |
|||
**Included files** |
|||
|
|||
```bash |
|||
brew install pandoc |
|||
|
|||
brew install basictex |
|||
|
|||
# Setting up LaTex packages |
|||
|
|||
# First update tlmgr |
|||
sudo tlmgr update --self |
|||
|
|||
# Then install LaTex packages |
|||
sudo tlmgr install bbding |
|||
sudo tlmgr install enumitem |
|||
sudo tlmgr install environ |
|||
sudo tlmgr install fancyhdr |
|||
sudo tlmgr install framed |
|||
sudo tlmgr install import |
|||
sudo tlmgr install lastpage # Enables Page X of Y |
|||
sudo tlmgr install mdframed |
|||
sudo tlmgr install multirow |
|||
sudo tlmgr install needspace |
|||
sudo tlmgr install ntheorem |
|||
sudo tlmgr install tabu |
|||
sudo tlmgr install tcolorbox |
|||
sudo tlmgr install textpos |
|||
sudo tlmgr install titlesec |
|||
sudo tlmgr install titling # Required for the fancy headers used |
|||
sudo tlmgr install threeparttable |
|||
sudo tlmgr install trimspaces |
|||
sudo tlmgr install tocloft # Required for \tableofcontents generation |
|||
sudo tlmgr install varwidth |
|||
sudo tlmgr install wrapfig |
|||
|
|||
# Install fonts |
|||
sudo tlmgr install cmbright |
|||
sudo tlmgr install collection-fontsrecommended # And set up fonts |
|||
sudo tlmgr install fira |
|||
sudo tlmgr install fontaxes |
|||
sudo tlmgr install libertine # The main font the doc uses |
|||
sudo tlmgr install opensans |
|||
sudo tlmgr install sourceserifpro |
|||
|
|||
``` |
|||
|
|||
#### References |
|||
|
|||
The following guide was adapted to this project except that we install with Brew and have a few more packages. |
|||
|
|||
Guide: <https://daniel.feldroy.com/posts/setting-up-latex-on-mac-os-x> |
|||
|
|||
### Usage |
|||
|
|||
Use the `pandoc` command to generate a PDF. |
|||
|
|||
```bash |
|||
pandoc usage-guide.md -o usage-guide.pdf |
|||
``` |
|||
|
|||
And you can open the PDF with the `open` command. |
|||
|
|||
```bash |
|||
open usage-guide.pdf |
|||
``` |
|||
|
|||
Or use this one-liner |
|||
|
|||
```bash |
|||
pandoc usage-guide.md -o usage-guide.pdf && open usage-guide.pdf |
|||
``` |
|||
- `notification-system.md` (merged comprehensive guide) |
|||
- `web-push-cleanup-guide.md` (cleanup instructions) |
|||
- `GLOSSARY.md` (definitions incl. **T** and **T–lead**) |
|||
|
@ -0,0 +1,231 @@ |
|||
# TimeSafari — Native-First Notification System |
|||
|
|||
**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** and **rolling-window safety** 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**; enforce **TTL-at-fire**; ETag-aware. |
|||
- **Single system:** One TS API; native adapters swap under the hood. |
|||
- **Platform honesty:** Android exactness via permission; iOS best-effort budget. |
|||
|
|||
### 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 (single shared DB):** The app and the native plugin will use **the same SQLite database file**. The app owns schema/migrations; the plugin opens the same file with WAL enabled and performs short, serialized writes. This keeps one source of truth for payloads, delivery logs, and config. |
|||
|
|||
### SQLite Ownership & Concurrency |
|||
|
|||
* **One DB file:** The plugin opens the **same path** the app uses (no second DB). |
|||
* **Migrations owned by app:** The app executes schema migrations and bumps `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 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. |
|||
|
|||
### Scheduling & T–lead |
|||
|
|||
- **Arm** a rolling window (today + tomorrow within iOS cap). |
|||
- **Attempt** a single **online-first** fetch per slot at **T–lead = T − prefetchLeadMinutes**. |
|||
- If prefetch is skipped, the armed local **still fires** using cached content. |
|||
|
|||
### Policies |
|||
|
|||
- **TTL-at-fire:** If (T − fetchedAt) > `ttlSeconds` → **skip** arming. |
|||
- **Android exactness:** Request `SCHEDULE_EXACT_ALARM`; fallback **±10m** window. |
|||
- **Reboot/time change:** Android receivers re-arm next 24h; iOS on next wake/silent push. |
|||
- **No delivery-time mutation:** iOS locals cannot be mutated by NSE; render before scheduling. |
|||
|
|||
--- |
|||
|
|||
## 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 |
|||
|
|||
* **Configure option:** `dbPath: string` (absolute path or platform alias) is 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` |
|||
|
|||
**Type (TS) extension** |
|||
|
|||
```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 |
|||
}; |
|||
``` |
|||
|
|||
**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 |
|||
|
|||
* **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). |
|||
|
|||
--- |
|||
|
|||
## 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._ |
@ -0,0 +1,551 @@ |
|||
# TimeSafari Web-Push Cleanup Guide |
|||
|
|||
**Status:** 🚀 Native-First Implementation |
|||
**Date:** 2025-01-27T14:30Z (UTC) |
|||
**Author:** Matthew Raymer |
|||
**Scope:** Web-push code cleanup and deprecation |
|||
**Goal:** Remove or quarantine all web-push code paths and mark as deprecated. |
|||
|
|||
--- |
|||
|
|||
## Executive Summary |
|||
|
|||
This document provides a comprehensive cleanup guide for removing web-push code |
|||
paths from TimeSafari. Web-push has been retired for unreliability, and the |
|||
system now focuses on native mobile reliability with Electron best-effort support. |
|||
|
|||
--- |
|||
|
|||
## Cleanup Strategy |
|||
|
|||
### Phase 1: Identify Web-Push Code Paths |
|||
|
|||
#### Service Worker Files |
|||
|
|||
- [ ] `sw_scripts/notification-click.js` - Mark as deprecated |
|||
- [ ] `sw_scripts/` directory - Review for web-push dependencies |
|||
- [ ] Service worker registration code - Remove or quarantine |
|||
|
|||
#### Web-Specific Code |
|||
|
|||
- [ ] Web push notification handlers |
|||
- [ ] Service worker event listeners |
|||
- [ ] Web notification API usage |
|||
- [ ] Push subscription management |
|||
|
|||
#### Configuration Files |
|||
|
|||
- [ ] VitePWA plugin configuration |
|||
- [ ] Service worker build configuration |
|||
- [ ] Web push manifest files |
|||
|
|||
### Phase 2: Mark as Deprecated |
|||
|
|||
#### Code Comments |
|||
|
|||
```javascript |
|||
// DEPRECATED: Web-push notification handling |
|||
// This code is kept for reference but not used in production |
|||
// Replaced by Native-First notification system |
|||
``` |
|||
|
|||
#### Documentation Updates |
|||
|
|||
- [ ] Mark web-push sections as deprecated |
|||
- [ ] Add deprecation notices |
|||
- [ ] Update README files |
|||
- [ ] Update API documentation |
|||
|
|||
### Phase 3: Remove or Quarantine |
|||
|
|||
#### Complete Removal |
|||
|
|||
- [ ] Web push subscription code |
|||
- [ ] Service worker notification handlers |
|||
- [ ] Web-specific notification APIs |
|||
- [ ] Push message handling |
|||
|
|||
#### Quarantine (Keep for Reference) |
|||
|
|||
- [ ] Service worker registration code |
|||
- [ ] Web push configuration |
|||
- [ ] Historical web-push tests |
|||
|
|||
--- |
|||
|
|||
## Detailed Cleanup Tasks |
|||
|
|||
### 1. Service Worker Cleanup |
|||
|
|||
#### Files to Deprecate |
|||
|
|||
**`sw_scripts/notification-click.js`** |
|||
|
|||
```javascript |
|||
// DEPRECATED: Service worker notification handling |
|||
// This code is kept for reference but not used in production |
|||
// Replaced by Native-First notification system |
|||
|
|||
// Original web-push notification click handler |
|||
self.addEventListener('notificationclick', (event) => { |
|||
// DEPRECATED: Web-push only |
|||
event.notification.close(); |
|||
|
|||
const slotId = event.notification.data?.slotId; |
|||
const route = slotId ? '/#/daily' : '/#/notifications'; |
|||
|
|||
event.waitUntil( |
|||
clients.openWindow(route).catch(() => { |
|||
return clients.openWindow('/'); |
|||
}) |
|||
); |
|||
}); |
|||
``` |
|||
|
|||
**Service Worker Registration** |
|||
|
|||
```javascript |
|||
// DEPRECATED: Service worker registration |
|||
// This code is kept for reference but not used in production |
|||
// Replaced by Native-First notification system |
|||
|
|||
if ('serviceWorker' in navigator && process.env.VITE_PLATFORM === 'web') { |
|||
// DEPRECATED: Web-push only |
|||
navigator.serviceWorker.register('/sw.js') |
|||
.then(registration => { |
|||
console.log('Service Worker registered:', registration); |
|||
}) |
|||
.catch(error => { |
|||
console.error('Service Worker registration failed:', error); |
|||
}); |
|||
} |
|||
``` |
|||
|
|||
### 2. Web Push API Cleanup |
|||
|
|||
#### Push Subscription Management |
|||
|
|||
```javascript |
|||
// DEPRECATED: Web push subscription management |
|||
// This code is kept for reference but not used in production |
|||
// Replaced by Native-First notification system |
|||
|
|||
class WebPushManager { |
|||
// DEPRECATED: Web-push only |
|||
async subscribeToPush() { |
|||
// Implementation kept for reference |
|||
} |
|||
|
|||
// DEPRECATED: Web-push only |
|||
async unsubscribeFromPush() { |
|||
// Implementation kept for reference |
|||
} |
|||
} |
|||
``` |
|||
|
|||
#### Push Message Handling |
|||
|
|||
```javascript |
|||
// DEPRECATED: Push message handling |
|||
// This code is kept for reference but not used in production |
|||
// Replaced by Native-First notification system |
|||
|
|||
self.addEventListener('push', (event) => { |
|||
// DEPRECATED: Web-push only |
|||
const data = event.data ? event.data.json() : {}; |
|||
|
|||
const options = { |
|||
body: data.body, |
|||
icon: '/icon-192x192.png', |
|||
badge: '/badge-72x72.png', |
|||
data: data |
|||
}; |
|||
|
|||
event.waitUntil( |
|||
self.registration.showNotification(data.title, options) |
|||
); |
|||
}); |
|||
``` |
|||
|
|||
### 3. Configuration Cleanup |
|||
|
|||
#### VitePWA Plugin Configuration |
|||
|
|||
```javascript |
|||
// DEPRECATED: VitePWA plugin configuration |
|||
// This configuration is kept for reference but not used in production |
|||
// Replaced by Native-First notification system |
|||
|
|||
import { VitePWA } from 'vite-plugin-pwa' |
|||
|
|||
export default defineConfig({ |
|||
plugins: [ |
|||
VitePWA({ |
|||
// DEPRECATED: Web-push only |
|||
registerType: 'autoUpdate', |
|||
workbox: { |
|||
globPatterns: ['**/*.{js,css,html,ico,png,svg}'] |
|||
}, |
|||
includeAssets: ['favicon.ico', 'apple-touch-icon.png', 'masked-icon.svg'], |
|||
manifest: { |
|||
name: 'TimeSafari', |
|||
short_name: 'TimeSafari', |
|||
description: 'TimeSafari App', |
|||
theme_color: '#ffffff', |
|||
icons: [ |
|||
{ |
|||
src: 'pwa-192x192.png', |
|||
sizes: '192x192', |
|||
type: 'image/png' |
|||
} |
|||
] |
|||
} |
|||
}) |
|||
] |
|||
}) |
|||
``` |
|||
|
|||
#### Service Worker Build Configuration |
|||
|
|||
```javascript |
|||
// DEPRECATED: Service worker build configuration |
|||
// This configuration is kept for reference but not used in production |
|||
// Replaced by Native-First notification system |
|||
|
|||
export default defineConfig({ |
|||
build: { |
|||
rollupOptions: { |
|||
input: { |
|||
// DEPRECATED: Web-push only |
|||
sw: 'sw_scripts/notification-click.js' |
|||
} |
|||
} |
|||
} |
|||
}) |
|||
``` |
|||
|
|||
### 4. Test Cleanup |
|||
|
|||
#### Web Push Tests |
|||
|
|||
```javascript |
|||
// DEPRECATED: Web push tests |
|||
// These tests are kept for reference but not used in production |
|||
// Replaced by Native-First notification system |
|||
|
|||
describe('Web Push Notifications (DEPRECATED)', () => { |
|||
// DEPRECATED: Web-push only |
|||
it('should handle push notifications', async () => { |
|||
// Test implementation kept for reference |
|||
}); |
|||
|
|||
// DEPRECATED: Web-push only |
|||
it('should handle notification clicks', async () => { |
|||
// Test implementation kept for reference |
|||
}); |
|||
}); |
|||
``` |
|||
|
|||
#### Service Worker Tests |
|||
|
|||
```javascript |
|||
// DEPRECATED: Service worker tests |
|||
// These tests are kept for reference but not used in production |
|||
// Replaced by Native-First notification system |
|||
|
|||
describe('Service Worker (DEPRECATED)', () => { |
|||
// DEPRECATED: Web-push only |
|||
it('should register service worker', async () => { |
|||
// Test implementation kept for reference |
|||
}); |
|||
|
|||
// DEPRECATED: Web-push only |
|||
it('should handle push events', async () => { |
|||
// Test implementation kept for reference |
|||
}); |
|||
}); |
|||
``` |
|||
|
|||
### 5. Documentation Cleanup |
|||
|
|||
#### README Updates |
|||
|
|||
```markdown |
|||
# TimeSafari Native-First Notification System |
|||
|
|||
## Web-Push Status: DEPRECATED |
|||
|
|||
Web-push has been retired for unreliability. The system now focuses on native mobile reliability with Electron best-effort support. |
|||
|
|||
### Deprecated Features |
|||
- ❌ Web push notifications |
|||
- ❌ Service worker notification handling |
|||
- ❌ Web notification API |
|||
|
|||
### Active Features |
|||
- ✅ Native mobile notifications (Android/iOS) |
|||
- ✅ Electron notifications (best-effort) |
|||
- ✅ OS-scheduled background prefetch |
|||
- ✅ Rolling window safety |
|||
``` |
|||
|
|||
#### API Documentation Updates |
|||
|
|||
```markdown |
|||
## Notification API (Native-First) |
|||
|
|||
### Deprecated Methods |
|||
- `subscribeToPush()` - DEPRECATED: Web-push only |
|||
- `unsubscribeFromPush()` - DEPRECATED: Web-push only |
|||
- `handlePushMessage()` - DEPRECATED: Web-push only |
|||
|
|||
### Active Methods |
|||
- `scheduleExact()` - Native exact scheduling |
|||
- `scheduleWindow()` - Native windowed scheduling |
|||
- `schedulePrefetch()` - Native background prefetch |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## File-by-File Cleanup Checklist |
|||
|
|||
### Service Worker Files |
|||
|
|||
- [ ] `sw_scripts/notification-click.js` - Mark as deprecated |
|||
- [ ] `sw_scripts/` directory - Review for web-push dependencies |
|||
- [ ] Service worker build configuration - Remove or quarantine |
|||
|
|||
### Web-Specific Code |
|||
|
|||
- [ ] `src/main.web.ts` - Remove service worker registration |
|||
- [ ] `src/services/webPush.ts` - Mark as deprecated |
|||
- [ ] `src/utils/serviceWorker.ts` - Mark as deprecated |
|||
- [ ] Web notification API usage - Remove or quarantine |
|||
|
|||
### Configuration Files |
|||
|
|||
- [ ] `vite.config.web.mts` - Remove VitePWA plugin |
|||
- [ ] `package.json` - Remove web-push dependencies |
|||
- [ ] `public/manifest.json` - Mark as deprecated |
|||
- [ ] Service worker build scripts - Remove or quarantine |
|||
|
|||
### Test Files |
|||
|
|||
- [ ] `test-playwright/web-push.spec.ts` - Mark as deprecated |
|||
- [ ] `test/services/webPush.test.ts` - Mark as deprecated |
|||
- [ ] Service worker tests - Mark as deprecated |
|||
|
|||
### Documentation Files |
|||
|
|||
- [ ] `README.md` - Update to reflect native-first approach |
|||
- [ ] `doc/web-push.md` - Mark as deprecated |
|||
- [ ] API documentation - Remove web-push references |
|||
|
|||
--- |
|||
|
|||
## Dependencies to Remove |
|||
|
|||
### NPM Packages |
|||
|
|||
```json |
|||
{ |
|||
"dependencies": { |
|||
// DEPRECATED: Web-push only |
|||
"web-push": "^7.4.0", |
|||
"vite-plugin-pwa": "^0.17.0" |
|||
}, |
|||
"devDependencies": { |
|||
// DEPRECATED: Web-push only |
|||
"workbox-webpack-plugin": "^6.5.0" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### Build Scripts |
|||
|
|||
```json |
|||
{ |
|||
"scripts": { |
|||
// DEPRECATED: Web-push only |
|||
"build:sw": "workbox generateSW", |
|||
"test:sw": "jest --testPathPattern=serviceWorker" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## Migration Guide |
|||
|
|||
### From Web-Push to Native-First |
|||
|
|||
#### Step 1: Remove Web-Push Dependencies |
|||
|
|||
```bash |
|||
# Remove web-push packages |
|||
npm uninstall web-push vite-plugin-pwa workbox-webpack-plugin |
|||
|
|||
# Remove service worker files |
|||
rm -rf sw_scripts/ |
|||
rm -f public/sw.js |
|||
rm -f public/workbox-*.js |
|||
``` |
|||
|
|||
#### Step 2: Update Configuration |
|||
|
|||
```javascript |
|||
// Remove VitePWA plugin from vite.config.web.mts |
|||
export default defineConfig({ |
|||
plugins: [ |
|||
// Remove VitePWA plugin |
|||
// VitePWA({ ... }) |
|||
] |
|||
}) |
|||
``` |
|||
|
|||
#### Step 3: Update Service Registration |
|||
|
|||
```javascript |
|||
// Remove service worker registration from main.web.ts |
|||
// if ('serviceWorker' in navigator) { |
|||
// navigator.serviceWorker.register('/sw.js') |
|||
// } |
|||
``` |
|||
|
|||
#### Step 4: Update Tests |
|||
|
|||
```javascript |
|||
// Remove web-push tests |
|||
// describe('Web Push Notifications', () => { ... }) |
|||
``` |
|||
|
|||
--- |
|||
|
|||
## Verification Checklist |
|||
|
|||
### Code Removal Verification |
|||
|
|||
- [ ] No web-push imports remain |
|||
- [ ] No service worker registration code |
|||
- [ ] No push subscription management |
|||
- [ ] No web notification API usage |
|||
- [ ] No VitePWA plugin configuration |
|||
|
|||
### Documentation Verification |
|||
|
|||
- [ ] All web-push references marked as deprecated |
|||
- [ ] README updated to reflect native-first approach |
|||
- [ ] API documentation updated |
|||
- [ ] Test documentation updated |
|||
|
|||
### Build Verification |
|||
|
|||
- [ ] Web build succeeds without service worker |
|||
- [ ] No service worker files generated |
|||
- [ ] No web-push dependencies in bundle |
|||
- [ ] Native builds work correctly |
|||
|
|||
### Test Verification |
|||
|
|||
- [ ] Web-push tests are marked as deprecated |
|||
- [ ] Native notification tests pass |
|||
- [ ] No web-push test failures |
|||
- [ ] Test suite runs successfully |
|||
|
|||
--- |
|||
|
|||
## Rollback Plan |
|||
|
|||
### Emergency Rollback |
|||
|
|||
If native-first implementation fails, web-push code can be restored: |
|||
|
|||
#### 1. **Restore Dependencies** |
|||
|
|||
```bash |
|||
npm install web-push vite-plugin-pwa workbox-webpack-plugin |
|||
``` |
|||
|
|||
#### 2. **Restore Service Worker Files** |
|||
|
|||
```bash |
|||
git checkout HEAD~1 -- sw_scripts/ |
|||
git checkout HEAD~1 -- public/sw.js |
|||
``` |
|||
|
|||
#### 3. **Restore Configuration** |
|||
|
|||
```bash |
|||
git checkout HEAD~1 -- vite.config.web.mts |
|||
git checkout HEAD~1 -- package.json |
|||
``` |
|||
|
|||
#### 4. **Restore Tests** |
|||
|
|||
```bash |
|||
git checkout HEAD~1 -- test-playwright/web-push.spec.ts |
|||
git checkout HEAD~1 -- test/services/webPush.test.ts |
|||
``` |
|||
|
|||
### Rollback Verification |
|||
|
|||
- [ ] Web-push functionality restored |
|||
- [ ] Service worker registration works |
|||
- [ ] Push notifications work |
|||
- [ ] Tests pass |
|||
|
|||
--- |
|||
|
|||
## Post-Cleanup Tasks |
|||
|
|||
### Code Review |
|||
|
|||
- [ ] Review all changes for completeness |
|||
- [ ] Verify no web-push code remains |
|||
- [ ] Check for orphaned references |
|||
- [ ] Validate native-first implementation |
|||
|
|||
### Testing |
|||
|
|||
- [ ] Run full test suite |
|||
- [ ] Verify native notifications work |
|||
- [ ] Check Electron functionality |
|||
- [ ] Validate mobile builds |
|||
|
|||
### Documentation |
|||
|
|||
- [ ] Update all documentation |
|||
- [ ] Remove web-push references |
|||
- [ ] Update API documentation |
|||
- [ ] Update user guides |
|||
|
|||
--- |
|||
|
|||
## Success Criteria |
|||
|
|||
### Complete Web-Push Removal |
|||
|
|||
- [ ] All web-push code marked as deprecated |
|||
- [ ] Service worker files quarantined |
|||
- [ ] Dependencies removed |
|||
- [ ] Configuration updated |
|||
|
|||
### Native-First Implementation |
|||
|
|||
- [ ] Native notifications work on Android |
|||
- [ ] Native notifications work on iOS |
|||
- [ ] Electron notifications work |
|||
- [ ] Background prefetch works |
|||
|
|||
### Documentation Updated |
|||
|
|||
- [ ] All docs reflect native-first approach |
|||
- [ ] Web-push marked as deprecated |
|||
- [ ] Migration guide provided |
|||
- [ ] Rollback plan documented |
|||
|
|||
--- |
|||
|
|||
_This cleanup guide provides comprehensive instructions for removing web-push |
|||
code paths from TimeSafari. Web-push has been retired for unreliability, and the |
|||
system now focuses on native mobile reliability with Electron best-effort support._ |
Loading…
Reference in new issue