chore: update plan and rulesets

This commit is contained in:
Matthew Raymer
2025-09-05 13:09:30 +00:00
parent cfeb920493
commit 74e4a20ef9
17 changed files with 1364 additions and 540 deletions
+1
View File
@@ -330,6 +330,7 @@ Track the effectiveness of your Build Architecture Guard:
## 📝 **Changelog**
### 2025-08-22 - Shell Compatibility Fix
- **Fixed**: Replaced `mapfile` command with portable alternative for cross-shell compatibility
- **Impact**: Resolves "mapfile: command not found" errors in pre-commit hooks
- **Files**: `scripts/build-arch-guard.sh`
+24
View File
@@ -11,12 +11,14 @@ The Android Asset Validation System automatically detects and fixes missing Andr
## Problem Solved
Previously, Android builds would fail with errors like:
```
error: resource drawable/splash (aka app.timesafari.app:drawable/splash) not found.
error: resource mipmap/ic_launcher (aka app.timesafari.app:mipmap/ic_launcher) not found.
```
This happened when:
- Source assets existed but weren't generated into Android resources
- Android resource directories were missing
- Asset generation tools weren't run before building
@@ -45,16 +47,19 @@ npm run build:android:studio
### What Gets Validated
#### Source Assets (Required)
- `resources/icon.png` - App icon source
- `resources/splash.png` - Splash screen source
- `resources/splash_dark.png` - Dark mode splash source
#### Android Resources (Generated)
- `android/app/src/main/res/drawable/splash.png` - Splash screen drawable
- `android/app/src/main/res/mipmap-*/ic_launcher.png` - App icons for all densities
- `android/app/src/main/res/mipmap-*/ic_launcher_round.png` - Round app icons for all densities
### Density Levels Checked
- `mipmap-mdpi` (1x)
- `mipmap-hdpi` (1.5x)
- `mipmap-xhdpi` (2x)
@@ -64,6 +69,7 @@ npm run build:android:studio
## Usage
### Automatic Validation (Recommended)
The validation runs automatically during all Android builds:
```bash
@@ -78,6 +84,7 @@ npm run build:android:debug
```
### Manual Validation
Run validation only to check/fix assets:
```bash
@@ -89,6 +96,7 @@ npm run assets:validate:android
```
### Validation Only (No Regeneration)
Check configuration without fixing:
```bash
@@ -98,6 +106,7 @@ npm run assets:validate
## Error Handling
### Missing Source Assets
If source assets are missing, the build fails with clear error messages:
```
@@ -108,6 +117,7 @@ If source assets are missing, the build fails with clear error messages:
```
### Missing Generated Resources
If generated resources are missing, they're automatically regenerated:
```
@@ -119,6 +129,7 @@ If generated resources are missing, they're automatically regenerated:
```
### Generation Failure
If regeneration fails, helpful guidance is provided:
```
@@ -131,6 +142,7 @@ If regeneration fails, helpful guidance is provided:
## Integration Points
### Build Script Integration
The validation is integrated into the main build process:
```bash
@@ -143,6 +155,7 @@ validate_android_assets || {
```
### NPM Scripts
New npm scripts for asset management:
```json
@@ -156,17 +169,20 @@ New npm scripts for asset management:
## Benefits
### For Developers
- **No More Build Failures**: Automatic detection and fixing of missing resources
- **Faster Development**: No need to manually run asset generation tools
- **Clear Error Messages**: Helpful guidance when issues occur
- **Consistent Results**: Same validation on all development machines
### For CI/CD
- **Reliable Builds**: Consistent asset validation across environments
- **Early Detection**: Catches issues before they reach production
- **Automated Fixes**: Self-healing builds when possible
### For Project Maintenance
- **Reduced Support**: Fewer "build doesn't work" issues
- **Documentation**: Clear requirements for required assets
- **Standardization**: Consistent asset structure across the project
@@ -176,21 +192,27 @@ New npm scripts for asset management:
### Common Issues
#### "No assets found in the asset path"
This occurs when the `assets/` directory is empty. The validation system automatically copies source assets and regenerates them.
#### "Failed to generate Android assets"
Check that:
- Source assets exist in `resources/`
- `@capacitor/assets` is installed
- You have write permissions to the Android directories
#### "Asset generation completed but some resources are still missing"
This indicates a problem with the asset generation tool. Try:
1. Running `npm install` to ensure dependencies are up to date
2. Manually running `npx @capacitor/assets generate`
3. Checking the asset generation logs for specific errors
### Manual Recovery
If automatic regeneration fails, you can manually create the missing resources:
```bash
@@ -213,12 +235,14 @@ rm assets/icon.png assets/splash.png assets/splash_dark.png
## Future Enhancements
### Planned Improvements
- **iOS Asset Validation**: Extend validation to iOS assets
- **Asset Quality Checks**: Validate image dimensions and formats
- **Performance Optimization**: Cache validation results
- **CI/CD Integration**: Add validation to GitHub Actions
### Configuration Options
- **Custom Asset Paths**: Support for different asset directory structures
- **Validation Rules**: Configurable validation requirements
- **Skip Options**: Ability to skip validation for specific scenarios
+22
View File
@@ -32,6 +32,7 @@ you apply 1-3 meta-rules that automatically include everything you need.
### **Step 1: Always Start with Core Always-On**
**Every single interaction** starts with:
```
meta_core_always_on.mdc
```
@@ -65,12 +66,14 @@ meta_core_always_on + meta_research + meta_bug_diagnosis
**Important**: Meta-rules represent **workflow phases**, not a rigid sequence. You can:
### **Jump Between Phases Freely**
- **Start with diagnosis** if you already know the problem
- **Go back to research** if your fix reveals new issues
- **Switch to planning** mid-implementation if scope changes
- **Document at any phase** - not just at the end
### **Mode Switching by Invoking Meta-Rules**
Each meta-rule invocation **automatically switches your workflow mode**:
```
@@ -80,11 +83,13 @@ Planning Mode → Invoke @meta_feature_implementation → Implementation Mode
```
### **Phase Constraints, Not Sequence Constraints**
- **Within each phase**: Clear constraints on what you can/cannot do
- **Between phases**: Complete freedom to move as needed
- **No forced order**: Choose the phase that matches your current need
### **Example of Flexible Workflow**
```
1. Start with @meta_research (investigation mode)
2. Jump to @meta_bug_diagnosis (diagnosis mode)
@@ -103,16 +108,19 @@ Planning Mode → Invoke @meta_feature_implementation → Implementation Mode
**Scenario**: User reports that the contact list isn't loading properly
**Initial Meta-Rule Selection**:
```
meta_core_always_on + meta_research + meta_bug_diagnosis
```
**What This Gives You**:
- **Core Always-On**: Human competence focus, time standards, context
- **Research**: Systematic investigation methodology, evidence collection
- **Bug Diagnosis**: Defect analysis framework, root cause identification
**Flexible Workflow**:
1. Apply core always-on for foundation
2. Use research meta-rule for systematic investigation
3. Switch to bug diagnosis when you have enough evidence
@@ -125,16 +133,19 @@ meta_core_always_on + meta_research + meta_bug_diagnosis
**Scenario**: Building a new contact search feature
**Meta-Rule Selection**:
```
meta_core_always_on + meta_feature_planning + meta_feature_implementation
```
**What This Gives You**:
- **Core Always-On**: Foundation principles and context
- **Feature Planning**: Requirements analysis, architecture planning
- **Feature Implementation**: Development workflow, testing strategy
**Iterative Workflow**:
1. Start with core always-on
2. Use feature planning for design and requirements
3. Switch to feature implementation for coding and testing
@@ -147,15 +158,18 @@ meta_core_always_on + meta_feature_planning + meta_feature_implementation
**Scenario**: Writing a migration guide for the new database system
**Meta-Rule Selection**:
```
meta_core_always_on + meta_documentation
```
**What This Gives You**:
- **Core Always-On**: Foundation and context
- **Documentation**: Educational focus, templates, quality standards
**Parallel Workflow**:
1. Apply core always-on for foundation
2. Use documentation meta-rule for educational content creation
3. **Can research** while documenting if you need more information
@@ -198,27 +212,35 @@ Each meta-rule includes success criteria. Use these to validate your work:
## Common Meta-Rule Combinations
### **Research + Diagnosis**
```
meta_core_always_on + meta_research + meta_bug_diagnosis
```
**Use for**: Complex bug investigations requiring systematic analysis
### **Planning + Implementation**
```
meta_core_always_on + meta_feature_planning + meta_feature_implementation
```
**Use for**: End-to-end feature development from concept to deployment
### **Research + Planning**
```
meta_core_always_on + meta_research + meta_feature_planning
```
**Use for**: Feasibility research and solution design
### **Documentation + Context**
```
meta_core_always_on + meta_documentation + [context-specific]
```
**Use for**: Creating comprehensive, educational documentation
## Best Practices
@@ -0,0 +1,131 @@
# TimeSafari Notification System — Executive Summary
**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**.
### Business Value
- **User Engagement:** Daily touchpoints to maintain community connections
- **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
---
## Strategic Approach
### Phase 1 (v1): In-App Orchestrator
**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
- **Content Prefetching:** Fresh content fetched when app is active
- **Cross-Platform:** Same user experience across all platforms
### Phase 2 (v2): Native Plugin
**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
- **Performance Optimization:** Native SQLite and HTTP
---
## Platform Strategy
| Platform | v1 Approach | v2 Enhancement |
|----------|-------------|----------------|
| **iOS** | Local notifications + Background Runner (optional) | Native BGTaskScheduler |
| **Android** | Local notifications + Background Runner (optional) | WorkManager + AlarmManager |
| **Web** | Service Worker push notifications | Enhanced push capabilities |
| **Electron** | OS notifications while app running | Native background services |
---
## Technical Architecture
### Core Components
- **Notification Orchestrator:** Central coordination and state management
- **Platform Adapters:** Platform-specific notification delivery
- **Database Integration:** SQLite persistence with TimeSafari's existing infrastructure
- **Content Management:** Template-based notification content with ETag caching
### Integration Points
- **Existing Database:** Extends TimeSafari's SQLite migration system
- **Platform Services:** Uses established PlatformServiceMixin patterns
- **Settings System:** Integrates with existing user preferences
- **Web Push:** Leverages existing Service Worker infrastructure
---
## Implementation Plan
### Phase 1 Deliverables (v1)
1. **Database Schema:** New notification tables integrated with existing migration system
2. **Core Service:** Notification orchestrator with platform adapters
3. **User Interface:** Settings integration for notification preferences
4. **Testing:** Cross-platform test suite with Playwright
5. **Documentation:** Complete implementation guide and API reference
### Success Metrics
- **Reliability:** 95%+ notification delivery rate across platforms
- **Performance:** <2s notification rendering time
- **User Adoption:** 80%+ opt-in rate for daily notifications
- **Platform Coverage:** 100% feature parity across iOS/Android/Web/Electron
---
## Risk Mitigation
### Technical Risks
- **Platform Limitations:** Mitigated by graceful degradation and fallback strategies
- **Permission Denials:** User education and deep-linking to system settings
- **Background Restrictions:** Conservative approach with offline-first design
### Business Risks
- **User Fatigue:** Configurable frequency and user-controlled preferences
- **Privacy Concerns:** Privacy-first architecture with local data storage
- **Platform Changes:** Abstraction layer protects against OS updates
---
## 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
---
*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.*
File diff suppressed because it is too large Load Diff
+372 -291
View File
@@ -1,34 +1,55 @@
# 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.
---
@@ -46,295 +67,405 @@ Adapters
├─ V1: SchedulerCapacitor, DataStoreSqlite, CallbacksHttp
└─ V2: SchedulerNative, DataStoreNativeSqlite, CallbacksNativeHttp
**Scheduler Adapter:** All notification arming must go through the Scheduler adapter to honor platform timing semantics (exact alarms vs. windowed fallback).
Platform
├─ iOS/Android: LocalNotifications (+ native bridges later)
├─ Web: Service Worker + Push (kept)
└─ Electron: OS notifications (thin adapter)
```
**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).
**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).
---
## 4) Public API (Shared by v1 & v2)
```ts
export type NotificationTime = { hour: number; minute: number }; // local wall-clock
export type SlotId = string; // Format: "HHmm" (e.g., "0800", "1200", "1800") - stable across TZ changes
export type FetchSpec = {
method: 'GET'|'POST';
url: string;
headers?: Record<string,string>;
bodyJson?: Record<string,unknown>;
timeoutMs?: number;
};
export type CallbackProfile = {
fetchContent: FetchSpec;
ackDelivery?: Omit<FetchSpec,'bodyJson'|'timeoutMs'>;
reportError?: Omit<FetchSpec,'bodyJson'|'timeoutMs'>;
heartbeat?: Omit<FetchSpec,'bodyJson'> & { intervalMinutes?: number };
};
export type ConfigureOptions = {
times: NotificationTime[]; // 1..M daily
timezone?: string; // Default: system timezone
ttlSeconds?: number; // Default: 86400 (24h)
prefetchLeadMinutes?: number; // Default: 20
storage: 'shared'|'private'; // Required
contentTemplate: { title: string; body: string }; // Required
callbackProfile?: CallbackProfile; // Optional
};
export interface MultiDailyNotification {
requestPermissions(): Promise<void>;
configure(o: ConfigureOptions): Promise<void>;
runFullPipelineNow(): Promise<void>; // API→DB→Schedule (today's remaining)
deliverStoredNow(slotId?: SlotId): Promise<void>; // 60s cooldown guard
reschedule(): Promise<void>;
getState(): Promise<{
nextOccurrences: Array<{ slotId: SlotId; when: string }>; // ISO
lastFetchAt?: string; lastDeliveryAt?: string;
pendingCount: number; exactAlarmCapable?: boolean;
}>;
}
```
> **Storage semantics:** `'shared'` = app DB; `'private'` = plugin-owned/native DB (v2). (No functional difference in v1.)
**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.
> • **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`
**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. v1 will schedule **the next occurrence per slot** by default; a **configurable depth** (0=today, 1=today+tomorrow) may be enabled as long as the iOS pending cap is respected.
- **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.
- **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.
---
## 7) Platform Essentials
## 7) Timing & Network Requirements
**iOS**
- Local notifications **will** fire without background runtime once scheduled. NSE **will not** mutate locals; delivery-time enrichment requires remote push (future).
**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.
**Platform-Specific Network Access:**
- **iOS:** Foreground/recently backgrounded only; no JS wake when app is killed
- **Android:** Exact alarms vs. windowed triggers based on permissions
- **Web:** Service Worker for push notifications only
- **Electron:** App-running only; no background network access
**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.
**Implementation Details:** See Implementation document for complete timing
constants table, network request profiles, and platform-specific enforcement.
---
## 8) Platform Essentials
**iOS**
- 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.
**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.
**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.
- **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.
**Web**
- Requires registered Service Worker + permission; can deliver with browser closed. **Web will not offline-schedule**.
- Service worker click handlers apply to **web push only**; local notifications on mobile do **not** pass through 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.
**Web**
**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).
- 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 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**
**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.
- 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).
**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.
**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):
**UX notes:** On Windows we **will set** `appUserModelId` so toasts are attributed correctly; on macOS we **will request** notification permission on first use.
**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.
**Prerequisites:** We **will require** Node 18+ (global `fetch`) or we **will polyfill** via `undici` for content fetching in the main process.
**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.
**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
**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
**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
- **Capacitor**: Native SQLite via `CapacitorPlatformService`
- **Electron**: Native SQLite via `ElectronPlatformService` (extends CapacitorPlatformService)
- **Capacitor**: Native SQLite via `CapacitorPlatformService`
- **Electron**: Native SQLite via `ElectronPlatformService` (extends CapacitorPlatformService)
---
## 10) 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
- 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
### Error Taxonomy
**Finite error code set:**
- `FETCH_TIMEOUT` - Network request exceeded timeout
- `ETAG_NOT_MODIFIED` - Server returned 304 (expected)
- `SCHEDULE_DENIED` - OS denied notification scheduling
- `EXACT_ALARM_MISSING` - Android exact alarm permission absent
- `STORAGE_BUSY` - Database locked or unavailable
- `TEMPLATE_MISSING_TOKEN` - Required template variable not found
- `PERMISSION_DENIED` - User denied notification permissions
**Error Codes:** `FETCH_TIMEOUT`, `ETAG_NOT_MODIFIED`, `SCHEDULE_DENIED`,
`EXACT_ALARM_MISSING`, `STORAGE_BUSY`, `TEMPLATE_MISSING_TOKEN`, `PERMISSION_DENIED`.
### Event Logging Envelope
```ts
{
code: string, // Error code from taxonomy
slotId: string, // Affected slot
whenMs: number, // Scheduled time
attempt: number, // Retry attempt (1-based)
networkState: string, // 'online' | 'offline'
tzOffset: number, // Current timezone offset
appState: string, // 'foreground' | 'background' | 'killed'
timestamp: number // UTC timestamp
}
```
**Event Envelope:** `code, slotId, whenMs, attempt, networkState, tzOffset,
appState, timestamp`.
### ACK Payload Format
```ts
{
slotId: string,
fireAt: number, // Scheduled time
deliveredAt: number, // Actual delivery time
deviceTz: string, // Device timezone
appVersion: string, // App version
buildId: string // Build identifier
}
```
- **Event queue (v1):** In-memory queue for `delivery`, `error`, `heartbeat` events. Background/native work **will enqueue**; foreground **will drain** and publish to the UI. **v2 will migrate** to SQLite-backed queue for persistence.
- **Callbacks (optional):** `ackDelivery`, `reportError`, `heartbeat` **will post** to server endpoints when configured.
- **Minimal metrics:** pending count, last fetch, last delivery, next occurrences.
**Implementation:** See Implementation document for complete error taxonomy,
event logging envelope, ACK payload format, and telemetry events.
---
## 13) Feature Flags & Config
### Feature Flags Table
| Flag | Default | Description | Location |
|------|---------|-------------|----------|
| `scheduler` | `'capacitor'` | Scheduler implementation | `notif_config` table |
| `mode` | `'auto'` | Online-first inside lead, else offline-first | `notif_config` table |
| `prefetchLeadMinutes` | `20` | Lead time for prefetch attempts | `notif_config` table |
| `ttlSeconds` | `86400` | Content staleness threshold (24h) | `notif_config` table |
| `iosCategoryIdentifier` | `'TS_DAILY'` | iOS notification category | `notif_config` table |
| `androidChannelId` | `'timesafari.daily'` | Android channel ID (never changes) | `notif_config` table |
**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.
---
## 14) 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
- **macOS notification permission** requested on first use
### 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.
- **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.
---
## 15) 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
- 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 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 keep** existing web push flows intact.
- 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).
---
## 17) 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)
- Complex action sets and rich media on locals (kept minimal).
- Delivery‑time mutation of local notifications on iOS (NSE is for remote).
- Complex action sets and rich media on locals (kept minimal).
- Delivery‑time mutation of local notifications on iOS (NSE is for remote).
- Full analytics pipeline (future enhancement).
---
@@ -342,116 +473,66 @@ We **will deliver** desktop notifications while the Electron app is running. Tru
## 19) Cross-Doc Sync Hygiene
### Canonical Ownership
- **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
- **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
- [ ] **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
### Synchronization Points
- **API code blocks**: Must be identical between Plan §4 and Implementation §3 (Public API (Shared))
- **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
---
## 21) Privacy & Security Alignment
### Privacy-First Architecture
- **User-Controlled Visibility:** Notification preferences **will be** user-controlled with explicit opt-in/opt-out
- **Data Sovereignty:** All notification data **will reside** on user's device; no external tracking or analytics
- **Minimal Data Collection:** We **will collect** only essential data for notification delivery (slot times, content templates)
- **DID Integration:** Notifications **will be** associated with user's Decentralized Identifier (DID) for privacy-preserving identity
### Security Considerations
- **Content Encryption:** Sensitive notification content **will be** encrypted at rest using device keystore
- **Secure Transmission:** All API calls **will use** HTTPS with proper certificate validation
- **Input Validation:** All notification content **will be** validated and sanitized before storage
- **Access Control:** Notification settings **will be** protected by user authentication
### Compliance with TimeSafari Principles
- **Privacy-Preserving:** Follows TimeSafari's privacy-preserving claims architecture
- **User Agency:** Users maintain full control over their notification experience
- **Transparency:** Clear communication about what data is collected and how it's used
- **Minimal Footprint:** Notification system **will have** minimal impact on user privacy
---
## 23) Platform-Specific Implementation Details
### Web Platform (`VITE_PLATFORM=web`)
- **Database:** Uses Absurd SQL (SQLite via IndexedDB) via `WebPlatformService` with worker pattern
- **Notifications:** Web push notifications via Service Worker (minimal implementation)
- **Local Scheduling:** **Not supported** - web cannot schedule local notifications offline
- **API Integration:** Direct HTTP calls for content fetching
- **Storage:** Notification preferences stored in Absurd SQL database
- **Testing:** Playwright E2E tests run on web platform
### Capacitor Platform (`VITE_PLATFORM=capacitor`)
- **Database:** Uses native SQLite via `CapacitorPlatformService`
- **Notifications:** Local notifications via `@capacitor/local-notifications`
- **Local Scheduling:** **Fully supported** - OS-level notification scheduling
- **API Integration:** HTTP calls with mobile-optimized timeouts and retry logic
- **Storage:** Notification preferences stored in native SQLite database
- **Testing:** Playwright E2E tests run on mobile devices (Android/iOS)
### Electron Platform (`VITE_PLATFORM=electron`)
- **Database:** Uses native SQLite via `ElectronPlatformService` (extends CapacitorPlatformService)
- **Notifications:** OS-level notifications via Electron's notification API
- **Local Scheduling:** **Supported** - desktop OS notification scheduling
- **API Integration:** Same as Capacitor platform
- **Storage:** Same as Capacitor platform (via inherited service)
- **Testing:** Same as Capacitor platform
### Cross-Platform Considerations
- **Feature Detection:** Use `process.env.VITE_PLATFORM` for platform-specific behavior
- **Database Abstraction:** PlatformServiceMixin handles database differences transparently
- **API Consistency:** Same TypeScript API across all platforms
- **Fallback Behavior:** Web platform gracefully degrades to push-only notifications
---
## 24) TimeSafari Architecture Compliance
### Design Pattern Adherence
- **Factory Pattern:** Notification service follows `PlatformServiceFactory` singleton pattern
- **Mixin Pattern:** Database access uses existing `PlatformServiceMixin` pattern
- **Migration Pattern:** Database changes follow existing `MIGRATIONS` array pattern
- **Error Handling:** Uses existing `handleApiError` from `src/services/api.ts`
- **Logging:** Uses existing logger from `src/utils/logger` with established patterns
- **Platform Detection:** Uses existing `Capacitor.isNativePlatform()` and `VITE_PLATFORM` patterns
### File Organization Compliance
- **Services:** Follows existing `src/services/` organization with factory and adapters
- **Database:** Extends existing `src/db-sql/migration.ts` and `src/db/tables/settings.ts`
- **Utils:** Extends existing `src/utils/PlatformServiceMixin.ts`
- **Main Entry:** Integrates with existing `src/main.capacitor.ts` initialization
- **Service Workers:** Follows existing `sw_scripts/` organization
### Type Safety Compliance
- **Settings Extension:** Follows existing Settings type extension pattern
- **Interface Definitions:** Uses existing TypeScript interface patterns
- **Error Types:** Follows existing error handling type patterns
- **Platform Types:** Uses existing platform detection type patterns
- **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
---
## 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` | ✅ |
| 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 implementation (v1) to the native plugin (v2). For detailed implementation specifics, see `notification-system-implementation.md`.*
## 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`.*
+4 -1
View File
@@ -5,12 +5,15 @@
**Status**: 🎯 **ACTIVE** - Z-index layering standards
## Objective
Establish consistent z-index values across the TimeSafari application to ensure proper layering of UI elements.
## Result
This document defines the z-index hierarchy for all UI components.
## Use/Run
Reference these values when implementing new components or modifying existing ones to maintain consistent layering.
## Z-Index Hierarchy
@@ -51,7 +54,7 @@ Reference these values when implementing new components or modifying existing on
## Collaboration Hooks
- **Reviewers**: Frontend team, UI/UX designers
- **Sign-off checklist**:
- **Sign-off checklist**:
- [ ] All new components follow z-index guidelines
- [ ] Existing components updated to use defined values
- [ ] Cross-browser testing completed