@ -3,7 +3,7 @@
**Author**: Matthew Raymer
**Author**: Matthew Raymer
**Version**: 1.0.0
**Version**: 1.0.0
**Created**: 2025-10-02 07:47:04 UTC
**Created**: 2025-10-02 07:47:04 UTC
**Last Updated**: 2025-10-02 10:1 5:00 UTC
**Last Updated**: 2025-10-02 10:4 5:00 UTC
## Overview
## Overview
@ -70,7 +70,7 @@ class JWTHelper {
// Background HTTP Worker
// Background HTTP Worker
class DataFetchWorker : CoroutineWorker {
class DataFetchWorker : CoroutineWorker {
suspend fun doWork(): Result {
suspend fun doWork(): Result {
val jwt = generateJWT(user Did, 60)
val jwt = generateJWT(active Did, 60)
val headers = mapOf(
val headers = mapOf(
"Authorization" to "Bearer $jwt",
"Authorization" to "Bearer $jwt",
"Content-Type" to "application/json"
"Content-Type" to "application/json"
@ -78,7 +78,7 @@ class DataFetchWorker : CoroutineWorker {
val offersResponse = httpClient.get("$apiServer/api/v2/report/offers") {
val offersResponse = httpClient.get("$apiServer/api/v2/report/offers") {
headers { headers.forEach { append(it.key, it.value) } }
headers { headers.forEach { append(it.key, it.value) } }
parameter("recipientDid", userDid)
parameter("recipientId", activeDid) // Use activeDid for recipient filtering
parameter("afterId", lastKnownOfferId)
parameter("afterId", lastKnownOfferId)
}
}
@ -118,7 +118,7 @@ class JWTHelper {
// Background HTTP Task
// Background HTTP Task
class DataFetchTask {
class DataFetchTask {
func fetchData() async {
func fetchData() async {
let jwt = generateJWT(userDid: user Did, expiresInSeconds: 60)
let jwt = generateJWT(userDid: active Did, expiresInSeconds: 60)
var request = URLRequest(url: apiURL)
var request = URLRequest(url: apiURL)
request.setValue("Bearer \(jwt)", forHTTPHeaderField: "Authorization")
request.setValue("Bearer \(jwt)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
@ -173,7 +173,7 @@ interface PluginConfig {
jwtExpirationSeconds: number;
jwtExpirationSeconds: number;
requestTimeoutMs: number;
requestTimeoutMs: number;
retryAttempts: number;
retryAttempts: number;
userDid: string;
activeDid: string; // Simplified to single active DID
lastKnownOfferId?: string;
lastKnownOfferId?: string;
lastKnownPlanId?: string;
lastKnownPlanId?: string;
}
}
@ -203,11 +203,22 @@ interface PluginConfig {
### Data Persistence
### Data Persistence
- **Android Room database** for caching API responses
#### **Platform-Specific Storage Architecture**
- **iOS Core Data** for persistent storage
- **Web IndexedDB** for web platform caching
**Android/Electron Platforms:**
- **TTL enforcement** for cached data freshness
- ** @capacitor -community/sqlite** plugin integration for native SQLite access
- **SQLite integration** via @capacitor -community/sqlite for unified storage across platforms
- **Shared plugin database** - Plugin manages its own SQLite database instance
- **Direct SQL execution** via plugin's `dbExec()` methods for complex queries
- **Background worker integration** for database operations during content fetch
**Web Platform:**
- **absurd-sql** for SQLite support in browser (managed by host application)
- **Plugin delegation pattern** - Plugin provides SQL queries, host executes them
- **IndexedDB fallback** for basic caching when SQLite unavailable
**iOS Platform:**
- **Core Data integration** via native Swift implementation
- **Background task compatibility** with iOS background refresh constraints
### State Synchronization
### State Synchronization
@ -243,11 +254,78 @@ Based on TimeSafari's optimization patterns:
## Integration Points
## Integration Points
### Existing Plugin APIs
### Enhanced Plugin Interface for Host Application Integration
#### **Database Integration Patterns**
**Android/Electron: Plugin-Managed SQLite**
```typescript
// Plugin handles database operations directly
await plugin.configure({
dbPath: 'daily_notifications.db',
storage: 'shared'
});
// Plugin provides database access methods
const results = await plugin.executeContentFetch(config);
await plugin.cacheContentData(results);
// Host application accesses cached data via plugin
const cachedData = await plugin.getContentCache();
```
**Web: Host-Managed Database**
```typescript
// Host application manages absurd-sql database
import { openDatabase } from 'absurd-sql';
const db = await openDatabase('daily_notifications.db');
// Plugin provides SQL queries, host executes them
const query = await plugin.getContentFetchQuery(apiEndpoint, credentials);
const results = await db.exec(query);
- **Extend** `DailyNotification.configure()` to include API server settings
// Plugin receives results for processing
- **Add** new methods: `setUserCredentials()` , `fetchActivityData()` , `getCachedData()`
await plugin.processContentData(results);
- **Trigger** notifications based on fetched data differences
```
**iOS: Hybrid Approach**
```typescript
// Plugin manages Core Data operations on background thread
await plugin.scheduleContentFetch(config);
// Host application accesses stored data via plugin APIs
const notificationData = await plugin.getLastNotification();
const cachedContent = await plugin.getContentHistory();
```
#### **New Plugin Methods Required**
```typescript
interface EnhancedDailyNotificationPlugin {
// Database configuration
configureDatabase(options: {
storageType: 'plugin-managed' | 'host-managed';
dbPath?: string;
encryption?: boolean;
}): Promise< void > ;
// Content fetch with database integration
fetchAndStoreContent(config: ContentFetchConfig): Promise< ContentFetchResult > ;
// Credential management - simplified to activeDid only
setActiveDid(activeDid: string): Promise< void > ;
// Data access for host application
getStoredContent(query: string, params?: any[]): Promise< any [ ] > ;
clearStoredContent(options?: { olderThan?: number }): Promise< void > ;
// Background task coordination
getBackgroundTaskStatus(): Promise< BackgroundTaskStatus > ;
pauseBackgroundTasks(): Promise< void > ;
resumeBackgroundTasks(): Promise< void > ;
}
```
### Background Scheduling
### Background Scheduling
@ -343,8 +421,9 @@ GET {apiServer}/api/v2/report/offersToPlansOwnedByMe?afterId={jwtId}&beforeId={j
### Token Generation
### Token Generation
- Accept user DID as input
- Accept activeDid as input
- Generate appropriate authentication token based on user's credential type
- Generate JWT authentication token using DID signing
- Include activeDid as both issuer (`iss`) and subject (`sub`)
- Return token for immediate use or caching
- Return token for immediate use or caching
### Request Execution
### Request Execution
@ -374,7 +453,11 @@ GET {apiServer}/api/v2/report/offersToPlansOwnedByMe?afterId={jwtId}&beforeId={j
- Implement DID-based authentication
- Implement DID-based authentication
- Integrate API endpoint calls
- Integrate API endpoint calls
- Add response parsing and validation
- Add response parsing and validation
- Implement basic caching
- Implement platform-specific database integration:
- **Android/Electron** : Direct @capacitor -community/sqlite integration
- **Web** : Plugin delegation pattern with absurd-sql coordination
- **iOS** : Core Data background thread integration
- Implement simplified activeDid-based authentication and API calls
### Phase 3: Background Integration (Weeks 5-6)
### Phase 3: Background Integration (Weeks 5-6)