docs: Document current Expo architecture for native migration
- Document technology stack (Expo, TypeScript, Zustand, SQLite) - Map out all data models and types - Document service dependencies and architecture - Create component dependency diagrams - Document data flow for feed sync and search - Provide migration checklist with priorities - Identify pure TypeScript vs native-dependent services This analysis provides the foundation for migrating business logic from Expo/TypeScript to native platforms (iOS, Android, Linux).
This commit is contained in:
@@ -17,6 +17,8 @@
|
|||||||
"@react-navigation/native": "^7.1.33",
|
"@react-navigation/native": "^7.1.33",
|
||||||
"@tanstack/react-query": "^5.95.2",
|
"@tanstack/react-query": "^5.95.2",
|
||||||
"axios": "^1.14.0",
|
"axios": "^1.14.0",
|
||||||
|
"buffer": "^6.0.3",
|
||||||
|
"events": "^3.3.0",
|
||||||
"expo": "55.0.10-canary-20260328-2049187",
|
"expo": "55.0.10-canary-20260328-2049187",
|
||||||
"expo-constants": "55.0.10-canary-20260328-2049187",
|
"expo-constants": "55.0.10-canary-20260328-2049187",
|
||||||
"expo-device": "55.0.11-canary-20260328-2049187",
|
"expo-device": "55.0.11-canary-20260328-2049187",
|
||||||
@@ -34,6 +36,7 @@
|
|||||||
"expo-system-ui": "55.0.12-canary-20260328-2049187",
|
"expo-system-ui": "55.0.12-canary-20260328-2049187",
|
||||||
"expo-task-manager": "55.0.11-canary-20260328-2049187",
|
"expo-task-manager": "55.0.11-canary-20260328-2049187",
|
||||||
"expo-web-browser": "55.0.11-canary-20260328-2049187",
|
"expo-web-browser": "55.0.11-canary-20260328-2049187",
|
||||||
|
"fast-xml-parser": "^5.5.9",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
"react-dom": "19.2.0",
|
"react-dom": "19.2.0",
|
||||||
"react-native": "0.83.4",
|
"react-native": "0.83.4",
|
||||||
@@ -44,7 +47,7 @@
|
|||||||
"react-native-screens": "~4.23.0",
|
"react-native-screens": "~4.23.0",
|
||||||
"react-native-web": "~0.21.0",
|
"react-native-web": "~0.21.0",
|
||||||
"react-native-worklets": "0.7.2",
|
"react-native-worklets": "0.7.2",
|
||||||
"xml2js": "^0.6.2",
|
"stream-browserify": "^3.0.0",
|
||||||
"zustand": "^5.0.12"
|
"zustand": "^5.0.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -0,0 +1,623 @@
|
|||||||
|
# 01. Analyze and document current Expo architecture
|
||||||
|
|
||||||
|
meta:
|
||||||
|
id: native-business-logic-migration-01
|
||||||
|
feature: native-business-logic-migration
|
||||||
|
priority: P0
|
||||||
|
depends_on: []
|
||||||
|
tags: [analysis, documentation]
|
||||||
|
|
||||||
|
objective:
|
||||||
|
- Document the current Expo/TypeScript architecture to understand what needs to be migrated
|
||||||
|
|
||||||
|
deliverables:
|
||||||
|
- Architecture documentation file
|
||||||
|
- Component dependency diagram
|
||||||
|
- Data flow diagrams
|
||||||
|
- List of all services, stores, and utilities to migrate
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- Review all TypeScript source files in src/
|
||||||
|
- Identify all data models and types
|
||||||
|
- Map out service dependencies
|
||||||
|
- Document state management flow (Zustand stores)
|
||||||
|
- Identify database schema and queries
|
||||||
|
- Document API endpoints and network calls
|
||||||
|
- Create migration checklist
|
||||||
|
|
||||||
|
acceptance_criteria:
|
||||||
|
- Architecture document exists with all components listed
|
||||||
|
- Data flow diagrams created for key features
|
||||||
|
- Migration checklist complete with all items identified
|
||||||
|
- All services and their dependencies documented
|
||||||
|
|
||||||
|
notes:
|
||||||
|
- Focus on business logic, not UI components
|
||||||
|
- Pay attention to async operations and error handling
|
||||||
|
- Document any platform-specific code that needs special handling
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Current Architecture Analysis
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
RSSuper is a multi-platform RSS reader built with **Expo (React Native)** using **TypeScript**. The current architecture follows a service-oriented pattern with Zustand for state management and expo-sqlite for local persistence.
|
||||||
|
|
||||||
|
## Technology Stack
|
||||||
|
|
||||||
|
| Layer | Technology |
|
||||||
|
|-------|------------|
|
||||||
|
| Framework | Expo SDK 55 (canary) |
|
||||||
|
| Runtime | React Native 0.83.4 |
|
||||||
|
| Language | TypeScript 5.9 |
|
||||||
|
| State Management | Zustand 5.x |
|
||||||
|
| Data Fetching | TanStack Query 5.x |
|
||||||
|
| HTTP Client | Axios |
|
||||||
|
| Local Database | expo-sqlite |
|
||||||
|
| Navigation | React Navigation 7.x |
|
||||||
|
| XML Parsing | fast-xml-parser |
|
||||||
|
| Audio | expo-av |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Data Models
|
||||||
|
|
||||||
|
### Core Types (`src/types/feed.ts`)
|
||||||
|
|
||||||
|
```
|
||||||
|
FeedItem
|
||||||
|
├── id: string
|
||||||
|
├── title: string
|
||||||
|
├── link?: string
|
||||||
|
├── description?: string
|
||||||
|
├── content?: string
|
||||||
|
├── author?: string
|
||||||
|
├── published?: Date
|
||||||
|
├── updated?: Date
|
||||||
|
├── categories?: string[]
|
||||||
|
├── enclosure?: { url, type, length? }
|
||||||
|
└── guid?: string
|
||||||
|
|
||||||
|
Feed
|
||||||
|
├── id: string
|
||||||
|
├── title: string
|
||||||
|
├── link?: string
|
||||||
|
├── description?: string
|
||||||
|
├── subtitle?: string
|
||||||
|
├── language?: string
|
||||||
|
├── lastBuildDate?: Date
|
||||||
|
├── updated?: Date
|
||||||
|
├── generator?: string
|
||||||
|
├── ttl?: number
|
||||||
|
├── items: FeedItem[]
|
||||||
|
├── rawUrl: string
|
||||||
|
├── lastFetchedAt?: Date
|
||||||
|
└── nextFetchAt?: Date
|
||||||
|
|
||||||
|
FeedSubscription
|
||||||
|
├── id: string
|
||||||
|
├── url: string
|
||||||
|
├── title: string
|
||||||
|
├── category?: string
|
||||||
|
├── enabled: boolean
|
||||||
|
├── fetchInterval: number (minutes)
|
||||||
|
├── createdAt: Date
|
||||||
|
├── updatedAt: Date
|
||||||
|
├── lastFetchedAt?: Date
|
||||||
|
├── nextFetchAt?: Date
|
||||||
|
├── error?: string
|
||||||
|
└── httpAuth?: { username, password }
|
||||||
|
|
||||||
|
SearchQuery / SearchFilters / SearchResult
|
||||||
|
```
|
||||||
|
|
||||||
|
### Global Types (`src/types/global.d.ts`)
|
||||||
|
|
||||||
|
```
|
||||||
|
NotificationType (enum)
|
||||||
|
├── NEW_ARTICLE
|
||||||
|
├── EPISODE_RELEASE
|
||||||
|
├── CUSTOM_ALERT
|
||||||
|
└── UPGRADE_PROMO
|
||||||
|
|
||||||
|
NotificationConfig
|
||||||
|
AccountSettings
|
||||||
|
PushNotificationConfig
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Services Architecture
|
||||||
|
|
||||||
|
### 1. Feed Service (`src/services/feed-service.ts`)
|
||||||
|
|
||||||
|
**Responsibilities**: RSS/Atom feed parsing and fetching
|
||||||
|
|
||||||
|
```
|
||||||
|
Functions:
|
||||||
|
├── parseFeed(url, data) → ParseResult
|
||||||
|
├── fetchFeed(url, auth?) → ParseResult
|
||||||
|
└── fetchFeeds(subscriptions) → Map<string, ParseResult>
|
||||||
|
|
||||||
|
Dependencies:
|
||||||
|
├── axios (HTTP)
|
||||||
|
└── xml2js (XML parsing)
|
||||||
|
|
||||||
|
Platform: Pure TypeScript - NO native dependencies
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Database Service (`src/services/database.ts`)
|
||||||
|
|
||||||
|
**Responsibilities**: SQLite persistence layer
|
||||||
|
|
||||||
|
```
|
||||||
|
Tables:
|
||||||
|
├── subscriptions
|
||||||
|
│ ├── id (PRIMARY KEY)
|
||||||
|
│ ├── url (UNIQUE)
|
||||||
|
│ ├── title, category
|
||||||
|
│ ├── enabled, fetch_interval
|
||||||
|
│ ├── http_auth_username, http_auth_password
|
||||||
|
│ ├── timestamps (created_at, updated_at, last_fetched_at, next_fetch_at)
|
||||||
|
│ └── error
|
||||||
|
│
|
||||||
|
├── feeds
|
||||||
|
│ ├── id (PRIMARY KEY)
|
||||||
|
│ ├── subscription_id (FOREIGN KEY)
|
||||||
|
│ ├── title, link, description, author
|
||||||
|
│ ├── published, updated, content
|
||||||
|
│ ├── guid (UNIQUE)
|
||||||
|
│ └── created_at
|
||||||
|
│
|
||||||
|
├── feeds_fts (FTS5 virtual table)
|
||||||
|
├── subscriptions_fts (FTS5 virtual table)
|
||||||
|
└── search_history
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
├── initDatabase() → void
|
||||||
|
├── saveSubscription(sub) → void
|
||||||
|
├── getSubscription(id) → FeedSubscription
|
||||||
|
├── getAllSubscriptions() → FeedSubscription[]
|
||||||
|
├── deleteSubscription(id) → void
|
||||||
|
├── saveFeedItems(subscriptionId, items) → void
|
||||||
|
├── getFeedItems(subscriptionId?, limit, offset) → FeedItem[]
|
||||||
|
├── getAllFeedItems(limit, offset) → FeedItem[]
|
||||||
|
└── search history functions
|
||||||
|
|
||||||
|
Dependencies: expo-sqlite
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Search Service (`src/services/search-service.ts`)
|
||||||
|
|
||||||
|
**Responsibilities**: Full-text search using SQLite FTS5
|
||||||
|
|
||||||
|
```
|
||||||
|
Functions:
|
||||||
|
├── searchArticles(query, options) → SearchResult[]
|
||||||
|
├── searchFeeds(query, limit) → SearchResult[]
|
||||||
|
└── combinedSearch(query, options) → { articles, feeds }
|
||||||
|
|
||||||
|
Search Features:
|
||||||
|
├── FTS5 full-text search (primary)
|
||||||
|
├── LIKE fallback search
|
||||||
|
├── Date filters
|
||||||
|
├── Feed filters
|
||||||
|
├── Author filters
|
||||||
|
├── Content type filters
|
||||||
|
└── Multiple sort options
|
||||||
|
|
||||||
|
Dependencies: database service
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Sync Service (`src/services/sync-service.ts`)
|
||||||
|
|
||||||
|
**Responsibilities**: Feed synchronization orchestration
|
||||||
|
|
||||||
|
```
|
||||||
|
Functions:
|
||||||
|
├── syncFeed(subscription) → { success, itemsSynced }
|
||||||
|
├── syncAllFeeds() → { success, totalItemsSynced }
|
||||||
|
├── getFeedsDueForSync() → FeedSubscription[]
|
||||||
|
├── getLocalFeedItems(...) → FeedItem[]
|
||||||
|
├── getAllLocalFeedItems(limit) → FeedItem[]
|
||||||
|
├── hasLocalData() → boolean
|
||||||
|
└── resolveConflict(options) → FeedItem
|
||||||
|
|
||||||
|
Conflict Resolution Strategies:
|
||||||
|
├── newer
|
||||||
|
├── older
|
||||||
|
├── local
|
||||||
|
└── remote
|
||||||
|
|
||||||
|
Dependencies: feed-service, database, feed-store
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Background Sync Service (`src/services/background-sync.ts`)
|
||||||
|
|
||||||
|
**Responsibilities**: Background task management
|
||||||
|
|
||||||
|
```
|
||||||
|
Task: BACKGROUND_SYNC_TASK
|
||||||
|
├── Uses expo-task-manager
|
||||||
|
├── Registers background fetch task
|
||||||
|
└── Syncs all enabled feeds
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
├── registerBackgroundSync() → boolean
|
||||||
|
├── unregisterBackgroundSync() → void
|
||||||
|
└── isBackgroundSyncRegistered() → boolean
|
||||||
|
|
||||||
|
Dependencies: expo-task-manager, sync-service, feed-store
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Notification Service (`src/services/notification-service.ts`)
|
||||||
|
|
||||||
|
**Responsibilities**: Push and local notifications
|
||||||
|
|
||||||
|
```
|
||||||
|
Functions:
|
||||||
|
├── registerNotificationChannels() → void (Android)
|
||||||
|
├── requestNotificationPermissions() → boolean
|
||||||
|
├── getPermissionStatus() → status
|
||||||
|
├── scheduleNotification(config) → string | null
|
||||||
|
├── scheduleNotificationAtTime(config, date) → string | null
|
||||||
|
├── cancelNotification(id) → void
|
||||||
|
├── cancelAllNotifications() → void
|
||||||
|
├── getScheduledNotifications() → NotificationRequest[]
|
||||||
|
├── showNotification(config) → void
|
||||||
|
├── setBadgeCount(count) → void
|
||||||
|
├── getBadgeCount() → number
|
||||||
|
├── addNotificationListener(callback) → unsubscribe
|
||||||
|
└── addNotificationResponseListener(callback) → unsubscribe
|
||||||
|
|
||||||
|
Android Channels:
|
||||||
|
├── default
|
||||||
|
├── new-articles
|
||||||
|
├── episode-releases
|
||||||
|
└── custom-alerts
|
||||||
|
|
||||||
|
Dependencies: expo-notifications, settings-store
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Audio Player Service (`src/services/audio-player.ts`)
|
||||||
|
|
||||||
|
**Responsibilities**: Podcast/audio playback
|
||||||
|
|
||||||
|
```
|
||||||
|
Class: AudioPlayerService
|
||||||
|
├── initialize() → void
|
||||||
|
├── subscribe(callback) → unsubscribe
|
||||||
|
├── play(item) → void
|
||||||
|
├── pause() → void
|
||||||
|
├── resume() → void
|
||||||
|
├── stop() → void
|
||||||
|
├── seekTo(positionMs) → void
|
||||||
|
├── setPlaybackSpeed(speed) → void
|
||||||
|
├── skipForward(seconds) → void
|
||||||
|
├── skipBackward(seconds) → void
|
||||||
|
└── getState() → PlayerState
|
||||||
|
|
||||||
|
Playback States: idle | loading | playing | paused | error
|
||||||
|
Playback Speeds: 0.5 | 0.75 | 1 | 1.25 | 1.5 | 1.75 | 2
|
||||||
|
|
||||||
|
Dependencies: expo-av
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8. API Service (`src/services/api.ts`)
|
||||||
|
|
||||||
|
**Responsibilities**: HTTP client setup (currently minimal)
|
||||||
|
|
||||||
|
```
|
||||||
|
Setup:
|
||||||
|
├── Axios instance with baseURL
|
||||||
|
├── Request interceptor (auth token placeholder)
|
||||||
|
└── Response interceptor (error handling)
|
||||||
|
|
||||||
|
Note: Not actively used - TODO for future cloud sync
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## State Management (Zustand Stores)
|
||||||
|
|
||||||
|
### 1. Feed Store (`src/stores/feed-store.ts`)
|
||||||
|
|
||||||
|
```
|
||||||
|
State:
|
||||||
|
├── subscriptions: FeedSubscription[]
|
||||||
|
├── feedItems: FeedItem[]
|
||||||
|
├── loading: boolean
|
||||||
|
└── error: string | null
|
||||||
|
|
||||||
|
Actions:
|
||||||
|
├── addSubscription(subscription) → Promise<void>
|
||||||
|
├── updateSubscription(id, updates) → void
|
||||||
|
├── removeSubscription(id) → Promise<void>
|
||||||
|
├── loadSubscriptions() → Promise<void>
|
||||||
|
├── loadFeedItems(subscriptionId?, limit?, offset?) → Promise<void>
|
||||||
|
├── setLoading(loading) → void
|
||||||
|
├── setError(error) → void
|
||||||
|
└── clearError() → void
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Settings Store (`src/stores/settings-store.ts`)
|
||||||
|
|
||||||
|
```
|
||||||
|
State:
|
||||||
|
├── syncInterval: SyncInterval
|
||||||
|
├── theme: 'system' | 'light' | 'dark'
|
||||||
|
├── notificationPreferences: NotificationPreferences
|
||||||
|
├── readingPreferences: ReadingPreferences
|
||||||
|
└── accountSettings: AccountSettings
|
||||||
|
|
||||||
|
Actions:
|
||||||
|
├── setSyncInterval(interval) → void
|
||||||
|
├── setTheme(theme) → void
|
||||||
|
├── setNotificationPreferences(prefs) → void
|
||||||
|
├── setReadingPreferences(prefs) → void
|
||||||
|
├── setAccountSettings(settings) → void
|
||||||
|
└── resetSettings() → void
|
||||||
|
|
||||||
|
Persistence: AsyncStorage (via zustand persist)
|
||||||
|
Storage Key: rssuper-settings
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Bookmark Store (`src/stores/bookmark-store.ts`)
|
||||||
|
|
||||||
|
```
|
||||||
|
State:
|
||||||
|
└── bookmarkedIds: Set<string>
|
||||||
|
|
||||||
|
Actions:
|
||||||
|
├── addBookmark(articleId) → void
|
||||||
|
├── removeBookmark(articleId) → void
|
||||||
|
├── toggleBookmark(articleId) → void
|
||||||
|
├── isBookmarked(articleId) → boolean
|
||||||
|
└── getBookmarks() → string[]
|
||||||
|
|
||||||
|
Persistence: AsyncStorage (via zustand persist)
|
||||||
|
Storage Key: rssuper-bookmarks
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Search Store (`src/stores/search-store.ts`)
|
||||||
|
|
||||||
|
```
|
||||||
|
State:
|
||||||
|
├── query: string
|
||||||
|
├── filters: SearchFilters
|
||||||
|
├── sort: SearchSortOption
|
||||||
|
├── page: number
|
||||||
|
├── pageSize: number
|
||||||
|
├── loading: boolean
|
||||||
|
├── error: string | null
|
||||||
|
└── searchHistory: SearchHistoryItem[]
|
||||||
|
|
||||||
|
Actions:
|
||||||
|
├── setQuery(query) → void
|
||||||
|
├── setFilters(filters) → void
|
||||||
|
├── setSort(sort) → void
|
||||||
|
├── setPage(page) → void
|
||||||
|
├── setLoading(loading) → void
|
||||||
|
├── setError(error) → void
|
||||||
|
├── clearSearch() → void
|
||||||
|
├── addToHistory(query) → Promise<void>
|
||||||
|
├── loadHistory() → Promise<void>
|
||||||
|
├── clearHistory() → Promise<void>
|
||||||
|
├── removeFromHistory(query) → Promise<void>
|
||||||
|
└── resetSearch() → void
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Component Dependencies
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ UI Components │
|
||||||
|
│ (feed-item-card, article-card, search-filters, etc.) │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ React Hooks │
|
||||||
|
│ use-feed-list, use-theme, use-color-scheme, use-offline │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Zustand Stores │
|
||||||
|
│ feed-store, settings-store, bookmark-store, search-store │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
│ │ │ │
|
||||||
|
▼ ▼ ▼ ▼
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Services Layer │
|
||||||
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌───────────┐ │
|
||||||
|
│ │feed-service │ │search-service│ │ sync-service │ │ api.ts │ │
|
||||||
|
│ └──────────────┘ └──────────────┘ └──────────────┘ └───────────┘ │
|
||||||
|
│ ┌──────────────────────┐ ┌──────────────────────┐ │
|
||||||
|
│ │background-sync.ts │ │notification-service │ │
|
||||||
|
│ └──────────────────────┘ └──────────────────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Data Layer │
|
||||||
|
│ ┌──────────────────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ database.ts (expo-sqlite) │ │
|
||||||
|
│ │ - subscriptions table │ │
|
||||||
|
│ │ - feeds table │ │
|
||||||
|
│ │ - FTS5 virtual tables │ │
|
||||||
|
│ │ - search_history table │ │
|
||||||
|
│ └──────────────────────────────────────────────────────────────────┘ │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Expo Modules (Native) │
|
||||||
|
│ expo-sqlite, expo-task-manager, expo-notifications, expo-av │
|
||||||
|
└─────────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Data Flow Diagrams
|
||||||
|
|
||||||
|
### Feed Sync Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
User adds subscription
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌───────────────────┐
|
||||||
|
│ feed-store │
|
||||||
|
│ addSubscription() │
|
||||||
|
└─────────┬─────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌───────────────────┐ ┌───────────────────┐
|
||||||
|
│ database.ts │ │ settings-store │
|
||||||
|
│ saveSubscription()│ │ (check intervals) │
|
||||||
|
└─────────┬─────────┘ └───────────────────┘
|
||||||
|
│
|
||||||
|
▼ (manual or background)
|
||||||
|
┌───────────────────┐
|
||||||
|
│ sync-service │
|
||||||
|
│ syncFeed() │
|
||||||
|
└─────────┬─────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌───────────────────┐ ┌───────────────────┐
|
||||||
|
│ feed-service │ │ feed-store │
|
||||||
|
│ fetchFeed() │ │ updateSubscription│
|
||||||
|
│ parseFeed() │ └─────────┬─────────┘
|
||||||
|
└─────────┬─────────┘ │
|
||||||
|
│ ▼
|
||||||
|
│ ┌───────────────────┐
|
||||||
|
│ │ database.ts │
|
||||||
|
│ │ saveFeedItems() │
|
||||||
|
│ └─────────┬─────────┘
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
┌───────────────────┐ ┌───────────────────┐
|
||||||
|
│ axios.get() │ │ UI updates │
|
||||||
|
│ (HTTP request) │ │ via Zustand │
|
||||||
|
└───────────────────┘ └───────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Search Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
User enters search query
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌───────────────────┐
|
||||||
|
│ search-store │
|
||||||
|
│ setQuery() │
|
||||||
|
└─────────┬─────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌───────────────────┐
|
||||||
|
│ search-service │
|
||||||
|
│ searchArticles() │
|
||||||
|
└─────────┬─────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌───────────────────┐ ┌───────────────────┐
|
||||||
|
│ database.ts │ │ FTS5 or LIKE │
|
||||||
|
│ getDb() │────▶│ fallback search │
|
||||||
|
└─────────┬─────────┘ └───────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌───────────────────┐
|
||||||
|
│ SearchResult[] │
|
||||||
|
└─────────┬─────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌───────────────────┐
|
||||||
|
│ UI renders │
|
||||||
|
│ search-results │
|
||||||
|
└───────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migration Checklist
|
||||||
|
|
||||||
|
### Services to Migrate (Pure TypeScript)
|
||||||
|
|
||||||
|
| Service | File | Native Deps | Priority |
|
||||||
|
|---------|------|-------------|----------|
|
||||||
|
| Feed Service | `feed-service.ts` | None | P0 |
|
||||||
|
| Search Service | `search-service.ts` | None | P0 |
|
||||||
|
| Sync Service | `sync-service.ts` | None | P0 |
|
||||||
|
| API Service | `api.ts` | None | P1 |
|
||||||
|
|
||||||
|
### Services with Native Dependencies
|
||||||
|
|
||||||
|
| Service | File | Native Deps | Priority |
|
||||||
|
|---------|------|-------------|----------|
|
||||||
|
| Database | `database.ts` | expo-sqlite | P0 |
|
||||||
|
| Background Sync | `background-sync.ts` | expo-task-manager | P0 |
|
||||||
|
| Notifications | `notification-service.ts` | expo-notifications | P0 |
|
||||||
|
| Audio Player | `audio-player.ts` | expo-av | P1 |
|
||||||
|
|
||||||
|
### Stores to Migrate
|
||||||
|
|
||||||
|
| Store | File | Persistence | Priority |
|
||||||
|
|-------|------|-------------|----------|
|
||||||
|
| Feed Store | `feed-store.ts` | None | P0 |
|
||||||
|
| Settings Store | `settings-store.ts` | AsyncStorage | P0 |
|
||||||
|
| Bookmark Store | `bookmark-store.ts` | AsyncStorage | P0 |
|
||||||
|
| Search Store | `search-store.ts` | None | P0 |
|
||||||
|
|
||||||
|
### Types to Migrate
|
||||||
|
|
||||||
|
| Types | File | Priority |
|
||||||
|
|-------|------|----------|
|
||||||
|
| Feed Types | `types/feed.ts` | P0 |
|
||||||
|
| Global Types | `types/global.d.ts` | P0 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Findings
|
||||||
|
|
||||||
|
1. **Pure TypeScript Services** (can be shared across all platforms):
|
||||||
|
- Feed parsing (RSS/Atom)
|
||||||
|
- Search logic
|
||||||
|
- Sync orchestration
|
||||||
|
- Conflict resolution
|
||||||
|
|
||||||
|
2. **Native Module Dependencies**:
|
||||||
|
- `expo-sqlite` → SQLite database
|
||||||
|
- `expo-task-manager` → Background tasks
|
||||||
|
- `expo-notifications` → Push/local notifications
|
||||||
|
- `expo-av` → Audio playback
|
||||||
|
|
||||||
|
3. **State Management**:
|
||||||
|
- All stores use Zustand
|
||||||
|
- Settings and bookmarks persist to AsyncStorage
|
||||||
|
- Database serves as source of truth for feeds/subscriptions
|
||||||
|
|
||||||
|
4. **Error Handling**:
|
||||||
|
- Most services return `{ success: boolean; error?: string }`
|
||||||
|
- Try-catch blocks with meaningful error messages
|
||||||
|
- Fallback strategies (e.g., FTS → LIKE search)
|
||||||
|
|
||||||
|
5. **Platform-Specific Code**:
|
||||||
|
- `hooks/use-color-scheme.web.ts` - Web-specific color scheme
|
||||||
|
- `components/animated-icon.web.tsx` - Web-specific icon animation
|
||||||
|
- `components/app-tabs.web.tsx` - Web-specific tabs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migration Priorities
|
||||||
|
|
||||||
|
1. **Phase 1**: Data models and types (shared)
|
||||||
|
2. **Phase 2**: Pure TypeScript services (feed, search, sync)
|
||||||
|
3. **Phase 3**: Database layer with expo-sqlite
|
||||||
|
4. **Phase 4**: Background sync with expo-task-manager
|
||||||
|
5. **Phase 5**: Notifications with expo-notifications
|
||||||
|
6. **Phase 6**: Audio player with expo-av
|
||||||
|
7. **Phase 7**: State management integration
|
||||||
Reference in New Issue
Block a user