From d9acbb61ff4dedc7ad050ffad197225ad86dd7a9 Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 11 Nov 2025 20:49:35 +0000 Subject: [PATCH] docs: Phase 2.1 Rich Annotations & Highlighting design specification --- ...5-01-11-phase-2-rich-annotations-design.md | 405 ++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 docs/plans/2025-01-11-phase-2-rich-annotations-design.md diff --git a/docs/plans/2025-01-11-phase-2-rich-annotations-design.md b/docs/plans/2025-01-11-phase-2-rich-annotations-design.md new file mode 100644 index 0000000..c15b22f --- /dev/null +++ b/docs/plans/2025-01-11-phase-2-rich-annotations-design.md @@ -0,0 +1,405 @@ +# Phase 2.1 Design: Rich Annotations & Highlighting + +**Date**: 2025-01-11 +**Status**: Approved Design +**Objective**: Build a complete highlighting and annotation system that works offline-first with seamless sync. Users can color-code verses for study and reference management. + +--- + +## Core Philosophy + +- **Instant feedback**: Highlights appear immediately when user acts +- **Never lose work**: All highlights persist locally, sync when possible +- **Distraction-free**: Visual indicators are subtle; details reveal on demand +- **Cross-device sync**: Annotations follow the user across devices + +--- + +## Feature Specifications + +### 1. Highlighting System + +#### Colors & Interaction +- **4 highlight colors**: Yellow (default), Orange, Pink, Blue +- **Two-gesture interaction**: + 1. Single tap verse β†’ Opens details panel (existing behavior) + 2. Long-press or swipe verse β†’ Highlights with default color (yellow) + - Shows mini toast: "Highlighted" + - Verse background changes color immediately + 3. Tap highlighted verse β†’ Details panel opens with Highlights tab active + - Shows current color + ColorPicker + - User can change color or delete highlight + +#### Visual Representation +- **Colored background** on highlighted verses +- **Opacity**: 0.3 (subtle, maintains text contrast) +- **Colors**: + - Yellow: `rgba(255, 193, 7, 0.3)` - Default, general marking + - Orange: `rgba(255, 152, 0, 0.3)` - Important, needs attention + - Pink: `rgba(233, 30, 99, 0.3)` - Devotional, personal significance + - Blue: `rgba(33, 150, 243, 0.3)` - Reference, study focus + +#### Storage +- **Database**: IndexedDB table `highlights` +- **Schema**: + ``` + { + id: string (UUID), + verseId: string, + userId: string (from localStorage auth), + color: 'yellow' | 'orange' | 'pink' | 'blue', + createdAt: timestamp, + updatedAt: timestamp, + syncStatus: 'pending' | 'syncing' | 'synced' | 'error', + syncErrorMsg?: string + } + ``` + +### 2. Cross-References + +#### Visual Indicator +- **Small link icon** (πŸ”—) or dot next to verse number when cross-references exist +- **Placement**: Subtle, doesn't interrupt reading +- **Behavior**: Clicking verse opens details panel with Cross-References tab + +#### Cross-Reference Display +- **Tab in VersDetailsPanel**: "Cross-References" +- **Format**: Collapsible list showing: + - Book name (e.g., "John") + - Chapter:verse reference (e.g., "3:16") + - 1-line preview of the verse text + - Tap to jump to that verse + +#### Quick Jump Behavior +- **Tap reference** β†’ Navigate to verse +- **Add to history**: User can go back to original verse +- **Smooth transition**: No page reload, updates reading view + +#### Data Source +- **Endpoint**: `GET /api/bible/cross-references?verseId={verseId}` +- **Lazy-loaded**: Only fetch when user opens Cross-References tab +- **Cached**: Store in IndexedDB with 7-day expiration + +### 3. Local-First Sync Strategy + +#### Immediate Local Storage +- All highlights saved to IndexedDB instantly when user acts +- Provides instant feedback, works offline +- No waiting for network round-trip + +#### Automatic Sync Queue +- **Background service** tracks `syncStatus` for each highlight: + - `pending`: Created locally, not yet synced + - `syncing`: Currently pushing to server + - `synced`: Successfully synced, in-sync with server + - `error`: Failed to sync, will retry + +#### Auto-Sync Timing +- **Interval**: Every 30 seconds when online +- **Batch operation**: POST all pending highlights in one request +- **Smart batching**: Only send items with `syncStatus: 'pending'` or `'error'` +- **Exponential backoff**: Failed syncs retry after 30s, 60s, 120s, then give up + +#### Conflict Resolution +- **Strategy**: Last-modified timestamp wins +- **Scenario**: User highlights same verse on two devices + - Device 1: Highlights yellow at 10:00:00 + - Device 2: Highlights pink at 10:00:05 + - Result: Pink wins (newer timestamp), displayed on both devices after sync +- **Safety**: No data lossβ€”version history kept server-side for audit + +#### Offline Fallback +- All operations (highlight, change color, delete) queued locally +- Sync indicator shows "Offline" state +- When connection returns: `syncStatus: 'pending'` items auto-sync + +#### Sync Status Indicator +- **Location**: Footer bar (right side, near existing sync indicator) +- **States**: + - "Syncing..." (briefly while POST in flight) + - "Synced βœ“" (green checkmark, 2 second display) + - "Sync failed" (red icon, expandable for retry) + - "Offline" (gray icon) +- **Manual retry**: User can click "Retry" on failed syncs from settings + +### 4. Component Architecture + +#### Enhanced Components + +**HighlightsTab** (NEW - in VersDetailsPanel) +``` +HighlightsTab +β”œβ”€β”€ HighlightToggle +β”‚ └── "Highlight this verse" button (if not highlighted) +β”‚ └── "Remove highlight" button (if highlighted) +β”œβ”€β”€ ColorPicker (if highlighted) +β”‚ β”œβ”€β”€ 4 color swatches (yellow, orange, pink, blue) +β”‚ β”œβ”€β”€ Selected color indicator +β”‚ └── OnColorChange β†’ Update highlight, queue sync +└── HighlightMetadata + β”œβ”€β”€ Created: [date/time] + └── Last modified: [date/time] +``` + +**VerseRenderer** (enhanced in ReadingView) +``` +VerseRenderer +β”œβ”€β”€ HighlightBackground +β”‚ └── Colored background if verse is highlighted +β”œβ”€β”€ VerseNumber + CrossRefIndicator +β”‚ └── Small icon if cross-references available +└── VerseText + └── Regular text, no inline linking +``` + +**HighlightSyncManager** (NEW - in BibleReaderApp) +``` +HighlightSyncManager +β”œβ”€β”€ IndexedDB operations +β”‚ β”œβ”€β”€ addHighlight(verseId, color) +β”‚ β”œβ”€β”€ updateHighlight(highlightId, color) +β”‚ β”œβ”€β”€ deleteHighlight(highlightId) +β”‚ └── getAllHighlights() +β”œβ”€β”€ Sync queue logic +β”‚ β”œβ”€β”€ getPendingHighlights() +β”‚ β”œβ”€β”€ markSyncing(ids) +β”‚ β”œβ”€β”€ markSynced(ids) +β”‚ └── markError(ids, msg) +└── Auto-sync interval + └── Every 30s: fetch pending β†’ POST batch β†’ update status +``` + +### 5. Data Flow + +#### Highlight Creation +``` +1. User long-presses verse +2. VerseRenderer detects long-press +3. Create highlight entry in IndexedDB + { verseId, color: 'yellow', syncStatus: 'pending' } +4. VerseRenderer background changes color +5. Show toast "Highlighted" +6. SyncManager picks it up in next 30s cycle β†’ POST to backend +``` + +#### Highlight Color Change +``` +1. User tap verse β†’ Details panel opens +2. HighlightsTab shows current color + ColorPicker +3. User taps new color +4. Update highlight in IndexedDB with new color + new timestamp +5. VerseRenderer background updates immediately +6. syncStatus changed to 'pending' +7. SyncManager syncs in next cycle +``` + +#### Offline β†’ Reconnect Flow +``` +1. User highlights while offline + β†’ Stored in IndexedDB with syncStatus: 'pending' +2. Connection returns +3. SyncManager detects online status change +4. Fetches all syncStatus: 'pending' or 'error' items +5. POSTs to /api/highlights/bulk +6. Updates syncStatus to 'synced' +7. Shows sync status indicator +``` + +#### Cross-Device Sync +``` +1. App loads on Device 2 +2. Fetch /api/highlights/all from backend +3. For each highlight from server: + - Check if exists locally (by verseId + userId) + - If not: Add to IndexedDB + - If exists: Compare timestamps, keep newer +4. Show user any conflicts (rare) +5. Render highlights with merged data +``` + +### 6. Backend API Endpoints (NEW) + +#### POST /api/highlights +Create a single highlight for authenticated user. + +``` +Request: +{ + verseId: string, + color: 'yellow' | 'orange' | 'pink' | 'blue', + createdAt: timestamp +} + +Response: +{ + id: string (UUID), + verseId: string, + userId: string, + color: string, + createdAt: timestamp, + updatedAt: timestamp, + syncStatus: 'synced' +} +``` + +#### POST /api/highlights/bulk +Batch sync highlights (create or update). + +``` +Request: +{ + highlights: [ + { + id?: string, + verseId: string, + color: string, + createdAt: timestamp, + updatedAt: timestamp + } + ] +} + +Response: +{ + synced: number, + errors: [{ verseId, error }], + serverTime: timestamp +} +``` + +#### GET /api/highlights/all +Fetch all highlights for authenticated user (for cross-device sync). + +``` +Response: +{ + highlights: [ + { + id: string, + verseId: string, + color: string, + createdAt: timestamp, + updatedAt: timestamp + } + ], + serverTime: timestamp +} +``` + +#### GET /api/bible/cross-references +Get cross-referenced verses for a given verse. + +``` +Request: GET /api/bible/cross-references?verseId={verseId} + +Response: +{ + verseId: string, + references: [ + { + refVerseId: string, + bookName: string, + chapter: number, + verse: number, + preview: string (first 60 chars) + } + ] +} +``` + +### 7. Error Handling & Resilience + +**Sync Failures** +- Network timeout: Auto-retry after 30s with exponential backoff +- 400/401 (invalid request): Remove from queue, log error +- 5xx (server error): Keep in queue, retry next cycle +- Display "Sync failed" in footer with manual retry button + +**Offline Highlighting** +- All operations queue locally, appear immediately +- When online: Auto-sync without user intervention +- If sync fails: User notified, can manually retry from settings + +**IndexedDB Quota Exceeded** +- Highlights table should never exceed reasonable size (< 1MB typical) +- If quota warning: Suggest clearing old highlights from settings +- Oldest highlights (by date) suggested for removal first + +**Cross-Device Conflicts** +- Rare: User highlights same verse on two devices at same second +- Resolution: Newer timestamp wins (automatic) +- User sees no warning (conflict handled transparently) + +### 8. Testing Strategy + +#### Unit Tests +- Highlight color validation (only 4 valid colors) +- Sync queue operations (add, remove, get pending) +- Timestamp-based conflict resolution +- IndexedDB CRUD operations +- Batch sync request formatting + +#### Integration Tests +- Highlight creation β†’ immediate display β†’ queued sync +- Offline highlight β†’ reconnect β†’ verify sync success +- Color change persistence across storage layers +- Cross-device highlight fetch and merge +- Sync conflict resolution (timestamp comparison) + +#### E2E Tests +- User highlights verse β†’ sees background change β†’ goes offline β†’ comes back online β†’ highlight is synced +- User highlights on Device 1 β†’ reads on Device 2 β†’ sees highlight immediately after fetch +- User deletes highlight β†’ sync β†’ verify removal on all devices +- Bulk operations: highlight multiple verses rapidly, verify all sync + +#### Manual Testing +- Desktop browsers: Chrome, Firefox, Safari +- Mobile: iOS Safari, Chrome Mobile, Android browsers +- Network conditions: Fast 3G, slow 3G, offline +- Sync conflict scenarios (use network throttling to trigger) + +--- + +## Success Criteria + +- **Offline**: Can highlight and change colors without internet +- **Sync**: Auto-syncs all highlights within 60 seconds of reconnection +- **Performance**: Highlighting action responds in < 200ms +- **Reliability**: No lost highlights after sync +- **UX**: User never confused about sync state (status indicator clear) +- **Accessibility**: All interactions keyboard-navigable + +--- + +## Implementation Dependencies + +### Already Available +- βœ… IndexedDB infrastructure (cache-manager.ts) +- βœ… Details panel infrastructure (VersDetailsPanel.tsx) +- βœ… Verse rendering with click handlers +- βœ… ReadingView component structure +- βœ… Auth system (user identification) + +### New Dependencies +- API endpoints (backend implementation) +- Highlight sync manager (new service) +- Color picker component (can use Material-UI) + +--- + +## Future Enhancements (Phase 3+) + +- **Highlight statistics**: "You've highlighted 47 verses across 12 books" +- **Highlight search**: Find all yellow highlights, or search within highlights +- **Highlight export**: Export all highlights as PDF or CSV with context +- **Highlight sharing**: Share specific highlighted passages with study groups +- **Highlight collections**: Group highlights into "studies" or "topics" + +--- + +## References + +- Current reader: `/root/biblical-guide/components/bible/bible-reader-app.tsx` +- Verse panel: `/root/biblical-guide/components/bible/verse-details-panel.tsx` +- Cache manager: `/root/biblical-guide/lib/cache-manager.ts` +- API Bible endpoints: `/root/biblical-guide/app/api/bible/`