Browse Source

docs: add Capacitor integration guide and usage decision guide

- Add comprehensive guide explaining when to use the plugin with Capacitor
- Clarify that plugin is only needed for Capacitor-based mobile apps
- Provide platform detection and conditional loading examples
- Add decision flowchart and matrix for easy understanding
- Include integration checklist and common mistakes to avoid
- Show how to check if Capacitor is installed and configured

This clarifies that the plugin is only needed when TimeSafari PWA uses Capacitor
for mobile app development, not for web-only PWAs.
master
Matthew Raymer 3 days ago
parent
commit
c8d545acd0
  1. 492
      docs/capacitor-integration-guide.md
  2. 252
      docs/plugin-usage-decision-guide.md

492
docs/capacitor-integration-guide.md

@ -0,0 +1,492 @@
# DailyNotification Plugin - Capacitor Integration Guide
**Author**: Matthew Raymer
**Version**: 1.0.0
**Created**: 2025-10-08 06:24:57 UTC
## Overview
The DailyNotification plugin is **specifically designed for Capacitor-based mobile applications**. It provides native mobile functionality that is not available in web-only PWAs. This guide explains when and how to use the plugin in your TimeSafari PWA.
## When to Use the Plugin
### ✅ Use the Plugin When:
- **Capacitor is installed** in your TimeSafari PWA project
- **Building for mobile platforms** (Android, iOS)
- **Need native mobile features** like:
- Background notifications
- Native notification scheduling
- Background task execution
- Platform-specific notification channels
- Battery optimization handling
- Exact alarm permissions
### ❌ Don't Use the Plugin When:
- **Web-only PWA** (no Capacitor)
- **Desktop-only Electron app** (though Electron support is available)
- **Server-side rendering** (SSR)
- **Static site generation** (SSG)
## Integration Scenarios
### Scenario 1: Web-Only PWA (No Plugin Needed)
```typescript
// In your web-only TimeSafari PWA
// You continue using your existing code as-is
private async loadNewStarredProjectChanges() {
if (this.activeDid && this.starredPlanHandleIds.length > 0) {
try {
const starredProjectChanges = await getStarredProjectsWithChanges(
this.axios,
this.apiServer,
this.activeDid,
this.starredPlanHandleIds,
this.lastAckedStarredPlanChangesJwtId,
);
this.numNewStarredProjectChanges = starredProjectChanges.data.length;
this.newStarredProjectChangesHitLimit = starredProjectChanges.hitLimit;
} catch (error) {
console.warn("[HomeView] Failed to load starred project changes:", error);
this.numNewStarredProjectChanges = 0;
this.newStarredProjectChangesHitLimit = false;
}
}
}
```
**What happens:**
- Your existing code works perfectly in the browser
- No plugin integration needed
- No native mobile features (background notifications, etc.)
- Limited to web browser capabilities
### Scenario 2: Capacitor-Based PWA (Plugin Recommended)
```typescript
// In your Capacitor-based TimeSafari PWA
import { DailyNotification } from '@timesafari/daily-notification-plugin';
import { Capacitor } from '@capacitor/core';
class TimeSafariHomeView {
async initialize() {
// Check if running in Capacitor
if (Capacitor.isNativePlatform()) {
// Initialize plugin for native mobile features
await this.setupDailyNotification();
} else {
// Use existing web-only code
console.log('Running in web browser - using existing code');
}
}
async setupDailyNotification() {
// Only runs on native platforms (Android, iOS)
await DailyNotification.configure({
timesafariConfig: {
activeDid: this.activeDid,
endpoints: {
projectsLastUpdated: `${this.apiServer}/api/v2/report/plansLastUpdatedBetween`
},
starredProjectsConfig: {
enabled: true,
starredPlanHandleIds: this.starredPlanHandleIds,
lastAckedJwtId: this.lastAckedStarredPlanChangesJwtId,
fetchInterval: '0 8 * * *'
}
},
networkConfig: {
httpClient: this.axios,
baseURL: this.apiServer,
timeout: 30000
}
});
}
async loadNewStarredProjectChanges() {
if (Capacitor.isNativePlatform()) {
// Use plugin-enhanced method on native platforms
await this.loadNewStarredProjectChangesNative();
} else {
// Use existing web method in browser
await this.loadNewStarredProjectChangesWeb();
}
}
async loadNewStarredProjectChangesNative() {
// Plugin-enhanced method with native features
const starredProjectChanges = await this.integrationService.getStarredProjectsWithChanges(
this.activeDid,
this.starredPlanHandleIds,
this.lastAckedStarredPlanChangesJwtId
);
this.numNewStarredProjectChanges = starredProjectChanges.data.length;
this.newStarredProjectChangesHitLimit = starredProjectChanges.hitLimit;
}
async loadNewStarredProjectChangesWeb() {
// Existing web-only method
const starredProjectChanges = await getStarredProjectsWithChanges(
this.axios,
this.apiServer,
this.activeDid,
this.starredPlanHandleIds,
this.lastAckedStarredPlanChangesJwtId,
);
this.numNewStarredProjectChanges = starredProjectChanges.data.length;
this.newStarredProjectChangesHitLimit = starredProjectChanges.hitLimit;
}
}
```
## Platform Detection
### Check if Capacitor is Available
```typescript
import { Capacitor } from '@capacitor/core';
// Check if running in Capacitor
if (Capacitor.isNativePlatform()) {
// Use plugin for native mobile features
await this.setupDailyNotification();
} else {
// Use existing web-only code
console.log('Running in web browser');
}
// Check specific platform
if (Capacitor.getPlatform() === 'android') {
// Android-specific configuration
} else if (Capacitor.getPlatform() === 'ios') {
// iOS-specific configuration
} else {
// Web browser
}
```
### Conditional Plugin Loading
```typescript
// Only load plugin when needed
let DailyNotification: any = null;
let TimeSafariIntegrationService: any = null;
if (Capacitor.isNativePlatform()) {
// Dynamically import plugin only on native platforms
const plugin = await import('@timesafari/daily-notification-plugin');
DailyNotification = plugin.DailyNotification;
TimeSafariIntegrationService = plugin.TimeSafariIntegrationService;
}
// Use plugin conditionally
if (DailyNotification) {
await DailyNotification.configure({...});
} else {
// Use existing web-only code
}
```
## Capacitor Configuration
### 1. Install Capacitor (if not already installed)
```bash
# Install Capacitor
npm install @capacitor/core @capacitor/cli
# Initialize Capacitor
npx cap init
# Add platforms
npx cap add android
npx cap add ios
```
### 2. Configure Capacitor for TimeSafari PWA
```typescript
// capacitor.config.ts
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'app.timesafari',
appName: 'TimeSafari',
webDir: 'dist',
plugins: {
DailyNotification: {
// Plugin configuration
storage: 'tiered',
ttlSeconds: 1800,
enableETagSupport: true,
enableErrorHandling: true,
enablePerformanceOptimization: true
}
}
};
export default config;
```
### 3. Build and Sync
```bash
# Build your PWA
npm run build
# Sync with Capacitor
npx cap sync
# Open in IDE
npx cap open android
npx cap open ios
```
## Platform-Specific Features
### Android Features (Only with Plugin)
```typescript
// Android-specific features
if (Capacitor.getPlatform() === 'android') {
// WorkManager for background tasks
// AlarmManager for exact notifications
// Notification channels
// Battery optimization handling
// Exact alarm permissions
}
```
### iOS Features (Only with Plugin)
```typescript
// iOS-specific features
if (Capacitor.getPlatform() === 'ios') {
// BGTaskScheduler for background tasks
// UNUserNotificationCenter for notifications
// Background App Refresh
// Provisional authorization
// Notification categories
}
```
### Web Features (Existing Code)
```typescript
// Web browser features
if (!Capacitor.isNativePlatform()) {
// Service Worker (if implemented)
// Web Notifications API
// Local Storage
// IndexedDB
// Your existing web-only code
}
```
## Integration Strategy
### 1. Progressive Enhancement
```typescript
class TimeSafariHomeView {
async initialize() {
// Always initialize with existing web code
await this.initializeWeb();
// Enhance with plugin if on native platform
if (Capacitor.isNativePlatform()) {
await this.initializeNative();
}
}
async initializeWeb() {
// Your existing web-only initialization
console.log('Initialized web version');
}
async initializeNative() {
// Plugin-enhanced initialization
await this.setupDailyNotification();
console.log('Initialized native version with plugin');
}
}
```
### 2. Feature Detection
```typescript
class TimeSafariHomeView {
private isNative = Capacitor.isNativePlatform();
private hasPlugin = false;
async initialize() {
if (this.isNative) {
try {
await this.setupDailyNotification();
this.hasPlugin = true;
console.log('Plugin initialized successfully');
} catch (error) {
console.warn('Plugin initialization failed, falling back to web mode');
this.hasPlugin = false;
}
}
}
async loadNewStarredProjectChanges() {
if (this.hasPlugin) {
// Use plugin-enhanced method
await this.loadNewStarredProjectChangesNative();
} else {
// Use existing web method
await this.loadNewStarredProjectChangesWeb();
}
}
}
```
### 3. Graceful Degradation
```typescript
class TimeSafariHomeView {
async loadNewStarredProjectChanges() {
try {
if (this.hasPlugin) {
// Try plugin-enhanced method first
await this.loadNewStarredProjectChangesNative();
} else {
// Fall back to web method
await this.loadNewStarredProjectChangesWeb();
}
} catch (error) {
// If plugin fails, fall back to web method
console.warn('Plugin method failed, falling back to web method');
await this.loadNewStarredProjectChangesWeb();
}
}
}
```
## Build Configuration
### 1. Package.json Scripts
```json
{
"scripts": {
"build": "vite build",
"build:web": "vite build",
"build:android": "vite build && npx cap sync android",
"build:ios": "vite build && npx cap sync ios",
"dev:web": "vite",
"dev:android": "vite && npx cap run android",
"dev:ios": "vite && npx cap run ios"
}
}
```
### 2. Environment Variables
```bash
# .env
VITE_CAPACITOR_ENABLED=true
VITE_PLUGIN_ENABLED=true
# .env.web (web-only build)
VITE_CAPACITOR_ENABLED=false
VITE_PLUGIN_ENABLED=false
```
### 3. Conditional Imports
```typescript
// Only import plugin when needed
const loadPlugin = async () => {
if (import.meta.env.VITE_PLUGIN_ENABLED === 'true') {
return await import('@timesafari/daily-notification-plugin');
}
return null;
};
const plugin = await loadPlugin();
if (plugin) {
await plugin.DailyNotification.configure({...});
}
```
## Testing Strategy
### 1. Web Testing
```bash
# Test web-only version
npm run dev:web
# Test in browser - should use existing code
```
### 2. Native Testing
```bash
# Test Android version
npm run dev:android
# Test on Android device/emulator - should use plugin
# Test iOS version
npm run dev:ios
# Test on iOS device/simulator - should use plugin
```
### 3. Cross-Platform Testing
```typescript
// Test both implementations
const testBothImplementations = async () => {
// Test web implementation
const webResult = await this.loadNewStarredProjectChangesWeb();
// Test native implementation (if available)
if (this.hasPlugin) {
const nativeResult = await this.loadNewStarredProjectChangesNative();
// Compare results
console.log('Web result:', webResult);
console.log('Native result:', nativeResult);
}
};
```
## Common Questions
### Q: Do I need to install the plugin for web-only PWAs?
**A:** No, the plugin is only needed for Capacitor-based mobile apps. Web-only PWAs continue using your existing code.
### Q: What happens if I install the plugin but don't use Capacitor?
**A:** The plugin will not work in web browsers. You should use platform detection to only initialize the plugin on native platforms.
### Q: Can I use the plugin in Electron?
**A:** Yes, the plugin supports Electron, but you need to configure it specifically for Electron.
### Q: How do I handle different platforms?
**A:** Use `Capacitor.getPlatform()` to detect the platform and configure the plugin accordingly.
### Q: What if the plugin fails to initialize?
**A:** Implement graceful degradation to fall back to your existing web-only code.
## Conclusion
The DailyNotification plugin is **only needed when using Capacitor** for mobile app development. For web-only PWAs, you continue using your existing TimeSafari code. The plugin provides native mobile features like background notifications, exact alarm scheduling, and platform-specific optimizations that are not available in web browsers.
**Key Points:**
- ✅ **Use plugin with Capacitor** for mobile apps (Android, iOS)
- ❌ **Don't use plugin** for web-only PWAs
- 🔄 **Use platform detection** to conditionally load the plugin
- 🛡️ **Implement graceful degradation** to fall back to web code
- 🧪 **Test both implementations** to ensure compatibility
---
**Next Steps:**
1. Check if your TimeSafari PWA uses Capacitor
2. If yes, integrate the plugin with platform detection
3. If no, continue using your existing web-only code
4. Test both web and native implementations

252
docs/plugin-usage-decision-guide.md

@ -0,0 +1,252 @@
# DailyNotification Plugin - Usage Decision Guide
**Author**: Matthew Raymer
**Version**: 1.0.0
**Created**: 2025-10-08 06:24:57 UTC
## Quick Decision Flow
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ TimeSafari PWA Project │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ Does your │ │
│ │ TimeSafari │ │
│ │ PWA use │ │
│ │ Capacitor? │ │
│ └─────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ YES │ │ NO │ │
│ │ │ │ │ │
│ │ ┌─────────────┐│ │ ┌─────────────┐│ │
│ │ │ Use ││ │ │ Don't ││ │
│ │ │ Plugin ││ │ │ Use ││ │
│ │ │ ││ │ │ Plugin ││ │
│ │ │ ✅ Native ││ │ │ ││ │
│ │ │ mobile ││ │ │ ❌ Web-only ││ │
│ │ │ features ││ │ │ PWA ││ │
│ │ │ ✅ Background││ │ │ ❌ No native││ │
│ │ │ notifications││ │ │ features ││ │
│ │ │ ✅ Platform ││ │ │ ❌ Use ││ │
│ │ │ specific ││ │ │ existing ││ │
│ │ │ optimizations││ │ │ code ││ │
│ │ └─────────────┘│ │ └─────────────┘│ │
│ └─────────────────┘ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
```
## Detailed Decision Matrix
| Scenario | Use Plugin? | Why? | What to Do |
|----------|-------------|------|------------|
| **Web-only PWA** | ❌ **NO** | Plugin requires Capacitor for native mobile features | Continue using your existing `loadNewStarredProjectChanges()` code |
| **Capacitor + Android** | ✅ **YES** | Plugin provides WorkManager, AlarmManager, notification channels | Integrate plugin with platform detection |
| **Capacitor + iOS** | ✅ **YES** | Plugin provides BGTaskScheduler, UNUserNotificationCenter | Integrate plugin with platform detection |
| **Capacitor + Electron** | ✅ **YES** | Plugin provides desktop notifications and background tasks | Integrate plugin with Electron-specific configuration |
| **Capacitor + Web** | ❌ **NO** | Web browser doesn't support native mobile features | Use existing web code, plugin won't work |
## Code Examples
### Scenario 1: Web-Only PWA (No Plugin)
```typescript
// Your existing TimeSafari PWA code - NO CHANGES NEEDED
class TimeSafariHomeView {
private async loadNewStarredProjectChanges() {
if (this.activeDid && this.starredPlanHandleIds.length > 0) {
try {
const starredProjectChanges = await getStarredProjectsWithChanges(
this.axios,
this.apiServer,
this.activeDid,
this.starredPlanHandleIds,
this.lastAckedStarredPlanChangesJwtId,
);
this.numNewStarredProjectChanges = starredProjectChanges.data.length;
this.newStarredProjectChangesHitLimit = starredProjectChanges.hitLimit;
} catch (error) {
console.warn("[HomeView] Failed to load starred project changes:", error);
this.numNewStarredProjectChanges = 0;
this.newStarredProjectChangesHitLimit = false;
}
}
}
}
```
**What happens:**
- Your existing code works perfectly in web browsers
- No plugin integration needed
- No native mobile features (background notifications, etc.)
- Limited to web browser capabilities
### Scenario 2: Capacitor-Based PWA (Use Plugin)
```typescript
// Your TimeSafari PWA with Capacitor - USE PLUGIN
import { Capacitor } from '@capacitor/core';
import { DailyNotification } from '@timesafari/daily-notification-plugin';
class TimeSafariHomeView {
async initialize() {
// Check if running in Capacitor
if (Capacitor.isNativePlatform()) {
// Initialize plugin for native mobile features
await this.setupDailyNotification();
} else {
// Use existing web-only code
console.log('Running in web browser - using existing code');
}
}
async setupDailyNotification() {
// Only runs on native platforms (Android, iOS)
await DailyNotification.configure({
timesafariConfig: {
activeDid: this.activeDid,
endpoints: {
projectsLastUpdated: `${this.apiServer}/api/v2/report/plansLastUpdatedBetween`
},
starredProjectsConfig: {
enabled: true,
starredPlanHandleIds: this.starredPlanHandleIds,
lastAckedJwtId: this.lastAckedStarredPlanChangesJwtId,
fetchInterval: '0 8 * * *'
}
},
networkConfig: {
httpClient: this.axios,
baseURL: this.apiServer,
timeout: 30000
}
});
}
async loadNewStarredProjectChanges() {
if (Capacitor.isNativePlatform()) {
// Use plugin-enhanced method on native platforms
await this.loadNewStarredProjectChangesNative();
} else {
// Use existing web method in browser
await this.loadNewStarredProjectChangesWeb();
}
}
}
```
**What happens:**
- Plugin provides native mobile features (background notifications, etc.)
- Enhanced error handling and performance optimization
- Platform-specific optimizations (Android WorkManager, iOS BGTaskScheduler)
- Graceful fallback to web code when not on native platform
## How to Check if You Need the Plugin
### 1. Check if Capacitor is Installed
```bash
# Check if Capacitor is in your package.json
npm list @capacitor/core
# Or check your package.json file
cat package.json | grep capacitor
```
### 2. Check if Capacitor is Configured
```bash
# Check if capacitor.config.ts exists
ls capacitor.config.ts
# Or check if capacitor.config.js exists
ls capacitor.config.js
```
### 3. Check if Native Platforms are Added
```bash
# Check if Android platform is added
ls android/
# Check if iOS platform is added
ls ios/
```
### 4. Check in Your Code
```typescript
// Add this to your TimeSafari PWA to check
import { Capacitor } from '@capacitor/core';
console.log('Platform:', Capacitor.getPlatform());
console.log('Is Native:', Capacitor.isNativePlatform());
console.log('Is Web:', Capacitor.getPlatform() === 'web');
```
## Integration Checklist
### ✅ If You Have Capacitor:
- [ ] Install the DailyNotification plugin
- [ ] Add platform detection to your code
- [ ] Configure the plugin for your TimeSafari data
- [ ] Test on Android device/emulator
- [ ] Test on iOS device/simulator
- [ ] Test web fallback in browser
- [ ] Implement graceful degradation
### ❌ If You Don't Have Capacitor:
- [ ] Continue using your existing code
- [ ] No plugin integration needed
- [ ] No changes required
- [ ] Your existing `loadNewStarredProjectChanges()` works perfectly
## Common Mistakes
### ❌ Mistake 1: Installing Plugin Without Capacitor
```typescript
// DON'T DO THIS - Plugin won't work in web browsers
import { DailyNotification } from '@timesafari/daily-notification-plugin';
// This will fail in web browsers
await DailyNotification.configure({...});
```
### ❌ Mistake 2: Not Using Platform Detection
```typescript
// DON'T DO THIS - Always tries to use plugin
await DailyNotification.configure({...}); // Fails in web browsers
```
### ✅ Correct Approach: Platform Detection
```typescript
// DO THIS - Only use plugin on native platforms
import { Capacitor } from '@capacitor/core';
if (Capacitor.isNativePlatform()) {
await DailyNotification.configure({...});
} else {
// Use existing web code
}
```
## Summary
**The DailyNotification plugin is ONLY needed when your TimeSafari PWA uses Capacitor for mobile app development.**
- **Web-only PWA**: Continue using your existing code, no plugin needed
- **Capacitor-based PWA**: Use the plugin with platform detection for native mobile features
- **Always implement graceful degradation** to fall back to web code when needed
---
**Quick Answer**: If your TimeSafari PWA doesn't use Capacitor, you don't need the DailyNotification plugin. Your existing `loadNewStarredProjectChanges()` code works perfectly for web-only PWAs.
Loading…
Cancel
Save