Files
carry-your-live/TECHNICAL_DOCS.md
2026-08-06 11:16:47 +02:00

13 KiB

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

-- 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
interface DatabaseContextType {
  database: Database;
  collections: {
    categories: Collection<Category>;
    tasks: Collection<Task>;
    subtasks: Collection<Subtask>;
  };
  isReady: boolean;
  initializeDatabase: () => Promise<void>;
}

useTasks Hook (src/hooks/useTasks.tsx)

Reactive task queries with loading states:

function useTasks(categoryId?: string, showCompleted = false): {
  tasks: Task[];
  loading: boolean;
}

WatermelonDB Models

All models use decorators for field mapping:

@field('column_name') propertyName!: Type;
@date('column_name') dateProperty!: Date;
@children('table_name') relationName!: Query<Model>;

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:

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)
const rotateAnim = useSharedValue(0);
rotateAnim.value = (rotateAnim.value + 0.25) % 1;
  1. Category Selection (CategoryFilter.tsx)
const scaleAnim = useSharedValue(1);
scaleAnim.value = withTiming(selected ? 1.05 : 1);
  1. Checkbox Toggle (TaskItem.tsx)
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