# Technical Documentation ## Architecture Overview ``` ┌─────────────────────────────────────────────────────────────────┐ │ Expo App Layer │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Tasks │ │ Calendar │ │ Settings │ │ │ │ Screen │ │ Screen │ │ Screen │ │ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ │ │ │ └────────────────┼────────────────┘ │ │ ▼ │ │ ┌─────────────────────────────────────────────┐ │ │ │ React Hook Form + Zod │ │ │ │ (Form Validation) │ │ │ └─────────────────────────────────────────────┘ │ └────────────────────────────────┬────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Database Layer │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ WatermelonDB Database │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ │ │Categories│ │ Tasks │ │ Subtasks │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ SQLite Adapter (expo-sqlite) │ │ │ └─────────────────────────────────────────────────────────┘ │ └────────────────────────────────┬────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Sync Layer │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Custom Sync Adapter │ │ │ │ • pullChanges() - GET /sync?since={timestamp} │ │ │ │ • pushChanges() - POST /sync/push │ │ │ │ • Conflict resolution (last-write-wins) │ │ │ └─────────────────────────────────────────────────────────┘ │ └────────────────────────────────┬────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Backend API │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Custom Postgres API │ │ │ │ • REST or GraphQL endpoints │ │ │ │ • Authentication (JWT/OAuth) │ │ │ │ • Conflict detection & resolution │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ## Database Schema ### Tables ```sql -- Categories table CREATE TABLE categories ( id TEXT PRIMARY KEY, name TEXT NOT NULL, color TEXT NOT NULL, "order" INTEGER NOT NULL DEFAULT 0, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL ); -- Tasks table CREATE TABLE tasks ( id TEXT PRIMARY KEY, title TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', category_id TEXT NOT NULL, priority TEXT NOT NULL DEFAULT 'none', completed INTEGER NOT NULL DEFAULT 0, due_date INTEGER NOT NULL DEFAULT 0, due_time TEXT NOT NULL DEFAULT '', created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, FOREIGN KEY (category_id) REFERENCES categories(id) ); CREATE INDEX idx_tasks_category ON tasks(category_id); CREATE INDEX idx_tasks_due_date ON tasks(due_date); CREATE INDEX idx_tasks_completed ON tasks(completed); -- Subtasks table CREATE TABLE subtasks ( id TEXT PRIMARY KEY, task_id TEXT NOT NULL, title TEXT NOT NULL, completed INTEGER NOT NULL DEFAULT 0, "order" INTEGER NOT NULL DEFAULT 0, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, FOREIGN KEY (task_id) REFERENCES tasks(id) ); CREATE INDEX idx_subtasks_task ON subtasks(task_id); ``` ## Key Components ### DatabaseProvider (`src/hooks/useDatabase.tsx`) Central context provider managing: - Database initialization - Default category seeding - Collection access - Ready state ```typescript interface DatabaseContextType { database: Database; collections: { categories: Collection; tasks: Collection; subtasks: Collection; }; isReady: boolean; initializeDatabase: () => Promise; } ``` ### useTasks Hook (`src/hooks/useTasks.tsx`) Reactive task queries with loading states: ```typescript function useTasks(categoryId?: string, showCompleted = false): { tasks: Task[]; loading: boolean; } ``` ### WatermelonDB Models All models use decorators for field mapping: ```typescript @field('column_name') propertyName!: Type; @date('column_name') dateProperty!: Date; @children('table_name') relationName!: Query; ``` ## Sync Implementation ### Pull Strategy 1. Client sends `lastPulledAt` timestamp 2. Server returns all changes since timestamp 3. Client applies changes in transaction: - Upsert categories (by id) - Upsert tasks (by id) - Upsert subtasks (by id) ### Push Strategy 1. Client collects local changes (created/updated/deleted) 2. Sends batched changes with `lastPulledAt` 3. Server applies and returns new timestamp ### Conflict Resolution Default: Last-write-wins based on `updatedAt` Customizable in `src/database/sync.ts` ## Navigation Structure ``` app/ ├── _layout.tsx # Stack navigator + DatabaseProvider │ ├── (tabs)/ # Tab group │ │ ├── _layout.tsx # Tabs navigator │ │ ├── index.tsx # / (Tasks) │ │ ├── calendar.tsx # /calendar │ │ └── settings.tsx # /settings │ └── add-task.tsx # /add-task (modal push) ``` ### Navigation Patterns - **Tabs**: Persistent bottom navigation - **Add Task**: Push onto stack (modal on iOS) - **Edit Task**: Push onto stack (future) ## Form Handling ### Add Task Form (`app/add-task.tsx`) Uses `react-hook-form` with `zod` resolver: ```typescript const schema = z.object({ title: z.string().min(1).max(100), description: z.string().max(1000).optional(), categoryId: z.string().min(1), priority: z.enum(['none', 'low', 'medium', 'high', 'critical']), dueDate: z.date().nullable().optional(), dueTime: z.string().optional(), subtasks: z.array(z.object({ title: z.string() })).optional(), }); ``` ### Field Components Each field is a controlled component using `Controller`: - `CategorySelector` - Horizontal chip selection - `TaskNameInput` - Text input with validation - `SubtasksSection` - FieldArray for dynamic subtasks - `DateTimePicker` - Native date/time pickers - `PrioritySelector` - Segmented control - `DescriptionInput` - Multiline text area ## Animations ### Reanimated 3 Patterns 1. **FAB Rotation** (`FloatingActionButton.tsx`) ```typescript const rotateAnim = useSharedValue(0); rotateAnim.value = (rotateAnim.value + 0.25) % 1; ``` 2. **Category Selection** (`CategoryFilter.tsx`) ```typescript const scaleAnim = useSharedValue(1); scaleAnim.value = withTiming(selected ? 1.05 : 1); ``` 3. **Checkbox Toggle** (`TaskItem.tsx`) ```typescript const checkedAnim = useSharedValue(0); checkedAnim.value = withTiming(task.completed ? 1 : 0); ``` ## Platform-Specific Considerations ### iOS - DateTimePicker: `display="spinner"` - Keyboard: `behavior="padding"` - Safe areas: Automatic via `react-native-safe-area-context` ### Android - DateTimePicker: `display="default"` - Keyboard: `behavior="height"` - Elevation shadows for Material Design ### Web - React Native Web for DOM rendering - DateTimePicker falls back to HTML inputs - No native SQLite (uses IndexedDB via expo-sqlite web polyfill) ## Performance Optimizations 1. **Lazy Loading**: Components loaded on demand 2. **Memoization**: `React.memo` for list items 3. **Virtualized Lists**: FlatList with `windowSize` 4. **Query Optimization**: Indexed columns for common queries 5. **Batch Writes**: Database transactions for multiple operations ## Testing Strategy ### Unit Tests - Hooks: `useTasks`, `useCategories` - Validators: Zod schemas - Utilities: Date formatting, priority sorting ### Integration Tests - Database CRUD operations - Sync adapter with mock server - Form submission flow ### E2E Tests - Critical user flows (add task, complete, filter) - Offline/online transitions - Cross-platform consistency ## Deployment Checklist - [ ] Configure `app.json` with production values - [ ] Set `EXPO_PUBLIC_API_URL` environment variable - [ ] Enable EAS Build for iOS/Android - [ ] Configure code signing certificates - [ ] Set up CI/CD pipeline - [ ] Test offline sync scenarios - [ ] Verify push notifications (if enabled) - [ ] Performance profiling on device ## Troubleshooting ### Common Issues **Database not initializing** - Check `expo-sqlite` installation - Verify `DatabaseProvider` wraps app root - Check Metro bundler cache: `npx expo start -c` **Sync failing** - Verify API endpoint accessibility - Check CORS headers on server - Inspect network requests in React Native Debugger **TypeScript errors with WatermelonDB** - Ensure `experimentalDecorators: true` in tsconfig - Check `@nozbe/watermelondb` version compatibility - Run `npx expo-doctor` for dependency issues **Animation not working** - Verify `react-native-reanimated` babel plugin - Check `useNativeDriver: true` for supported properties - Ensure worklet functions are properly extracted