tech08mag 41eaef92b0
Android Build / Build Android (pull_request) Failing after 50m22s
new pipe
2026-09-02 20:28:07 +02:00
2026-08-23 15:26:52 +02:00
2026-09-02 20:28:07 +02:00
2026-08-26 23:48:42 +02:00
2026-08-23 11:36:17 +02:00
2026-09-02 20:28:07 +02:00
2026-08-07 01:06:03 +02:00
2026-08-25 16:26:10 +02:00
2026-08-25 16:26:10 +02:00
2026-08-25 16:26:10 +02:00
2026-08-23 15:26:52 +02:00
2026-08-26 23:48:42 +02:00

Carry Your Live - Mobile To-Do & Calendar App

A minimalist, offline-first task management app built with Expo, React Native, and WatermelonDB. Features multiple screens with bottom navigation, social features, and a full-featured backend API.

📝 Recent Progress (v1.1.0 - Unreleased)

Added

  • Friends feature: Friend requests, accept/decline/remove, user search, full backend routes
  • Assignee field on tasks: Schema v7, model, types, forms, sync, task actions
  • AssigneeSelector component and assignee display in TaskItem
  • QuickAddBar on tasks overview (copied from calendar)
  • Backend: Mounted friends route, added assigneeId to task validation and sync

Changed

  • Due date prefilled from Calendar "+" button
  • 12-hour time formatting across task rows and pickers
  • Calendar strip scrolls to selected day when navigating months
  • Calendar completion toggle now handles repeating tasks and reminders
  • Task color strips now use the task's category color

Fixed

  • WheelTimePicker FlatList scroll clamping - all hours (0-23) and minutes (0-59) reachable
  • WheelTimePicker selection highlight background connecting selected item with colon separator
  • WheelTimePicker number alignment in scroll list
  • Tasks without a due date no longer get overdue styling
  • useOverdueTasks infinite re-subscription loop (Date.now in effect deps)
  • Web/Android crashes from decorator transform ordering (babel config)
  • FormButtons crash outside FormProvider; Cancel navigation fallback
  • Task repeat settings, reminders and series info now sync to backend

Removed

  • Task color picker (task color now comes from its category)
  • Drag lift popup from TaskItem (scale + shadow on drag)
  • Checkbox from task items
  • Selection bar overlapping QuickAddBar on tasks overview

Features

Core Functionality

  • Offline-First Architecture: Full CRUD operations work offline with WatermelonDB + SQLite
  • Auto-Sync: Background synchronization with custom Postgres API when online
  • Cross-Platform: iOS, Android, and Web from single codebase
  • Desktop Support: Electron wrapper for desktop app distribution

Screens

1. Tasks Screen (To-Do List)

  • Header: App logo + "TODO" title with rounded corners
  • Category Filter: Horizontal scrollable chips (Work, Personal, School, Shopping, Health, Finance, All)
    • Single selection with visual feedback (thicker border, shadow, scale animation)
    • Instant task filtering
  • QuickAddBar: Quick task creation from list view
  • Task List: Virtualized FlatList with sections (Pending/Completed)
    • Task title (truncated with ellipsis)
    • Three-dot overflow menu (Edit, Delete, Duplicate, Mark Complete, Change Category, Change Priority)
    • Priority badges with colors
    • Due date/time with overdue/due-today highlighting
    • Category color indicator strip
    • Assignee display
    • Swipe actions (left: delete, right: complete)
    • Drag-to-reorder with visual drop indicators
    • Long press → Selection mode (multi-delete, multi-complete, change category/priority)
  • Floating Action Button: Bottom-right, opens Add Task screen

2. Calendar Screen

  • Date Strip: Horizontal scrollable days of current month
    • Current day highlighted, scrolls to selected day on month change
  • Month Label: Centered (e.g., "JAN 2026")
  • QuickAddBar: Quick task creation for selected date
  • Task List: Tasks for selected day with category color, title, time, completion status
  • Analog Clock Widget: Decorative analog clock display
  • Empty State: "No tasks scheduled."
  • Day View: Detailed view for selected day (pushes to stack)

3. Stats Screen

  • Client-side statistics (useStats hook)
  • Task completion metrics
  • Category and priority breakdowns

4. Settings Screen

  • Account: Login/Register/Sign Out (SyncModal)
  • Server URL Override: Custom API endpoint configuration
  • Appearance: Accent color picker (dark mode toggle planned)
  • Task Defaults: Default category, sort order (Date, Priority, Alphabetically, Creation Date), show completed toggle
  • Calendar: Days ahead to display
  • Reminders: Global reminder preference (stored, wiring in progress)
  • Notifications: Toggle (stored, wiring in progress)
  • Legal: Privacy Policy, Terms of Service
  • About: Version info

5. Add New Task Screen

  • Category Selector: Horizontal row of colored circles (required)
  • Task Name: Single-line input, 100 char max (required)
  • Subtasks: Unlimited, add/remove individually, nested subtask support
  • Date & Time: Date picker, time picker (WheelTimePicker), calendar button
  • Priority: Dropdown (None, Low, Medium, High, Critical) with color indicators
  • Repeat Profile: Recurring task configuration
  • Reminder: Reminder offset selector
  • Assignee: Assign task to friend
  • Description: Multi-line text area, 1000 char max
  • Bottom Actions: Submit (primary) / Cancel (secondary) fixed buttons

6. Task Detail Screen

  • Full task view with all fields
  • Subtask management (add, complete, reorder, convert to task)
  • Edit functionality
  • Repeat profile configuration

7. Subtask Detail Screen

  • Nested subtask management
  • Convert subtask ↔ task
  • Re-parent subtasks

8. Sync Modal

  • Login/Register forms
  • Forgot/Reset password flow
  • Server URL configuration
  • Sync status display

Task Features

  • Nested Subtasks: Unlimited depth, re-parenting, drag reorder
  • Repeating Tasks: Repeat profiles, series IDs, this/future/all delete scopes, undo-complete
  • Categories/Tags: 6 default categories with colors, custom category editor
  • Priorities: None, Low, Medium, High, Critical with color badges
  • Due Dates/Times: With all-day option
  • Reminders: Per-task reminder offsets
  • Assignees: Assign tasks to friends
  • Overdue/Due Today: Visual highlighting

Social Features

  • Friends System: Send/accept/decline/remove friend requests
  • User Search: Find users by username/email
  • Task Assignment: Assign tasks to friends (client-side, backend schema ready)

Tech Stack

Layer Technology
Framework Expo (React Native) / Expo Router v3
Language TypeScript (strict mode)
Navigation Expo Router (file-based)
Database WatermelonDB + SQLite (expo-sqlite)
State WatermelonDB reactive queries (no Redux)
Forms React Hook Form + Zod validation
UI Components React Native Paper + Custom components
Animations React Native Reanimated v3
Date/Time @react-native-community/datetimepicker + date-fns + WheelTimePicker
Build EAS Build / Gradle (local APK) / Electron Builder (desktop)
CI/CD Gitea Actions (.gitea/workflows/build-apk.yml)
Backend Node.js + Express + TypeScript
Backend DB PostgreSQL + Drizzle ORM
Auth JWT (access + refresh tokens)
Validation Zod (shared with frontend)

Project Structure

carry-your-live/
├── app/
│   ├── _layout.tsx              # Root layout + DatabaseProvider + AuthProvider
│   ├── (tabs)/
│   │   ├── _layout.tsx          # Bottom tab navigator
│   │   ├── index.tsx            # Tasks screen
│   │   ├── calendar.tsx         # Calendar screen
│   │   ├── stats.tsx            # Stats screen
│   │   └── settings.tsx         # Settings screen
│   ├── add-task.tsx             # Add Task screen
│   ├── day-view.tsx             # Calendar day detail
│   ├── task-detail.tsx          # Task view/edit
│   └── subtask-detail.tsx       # Subtask view/edit
├── src/
│   ├── components/              # Reusable UI components (30+)
│   │   ├── Header.tsx
│   │   ├── CategoryFilter.tsx
│   │   ├── TaskList.tsx
│   │   ├── TaskItem.tsx
│   │   ├── FloatingActionButton.tsx
│   │   ├── CategorySelector.tsx
│   │   ├── TaskNameInput.tsx
│   │   ├── SubtasksSection.tsx
│   │   ├── DateTimePicker.tsx
│   │   ├── PrioritySelector.tsx
│   │   ├── DescriptionInput.tsx
│   │   ├── FormButtons.tsx
│   │   ├── ListItem.tsx
│   │   ├── AnalogClock.tsx
│   │   ├── AssigneeSelector.tsx
│   │   ├── CategoryEditorModal.tsx
│   │   ├── ColorPickerInput.tsx
│   │   ├── ColorWheel.tsx
│   │   ├── DateTimeInput.tsx
│   │   ├── ForgotPasswordModal.tsx
│   │   ├── FriendsModal.tsx
│   │   ├── LegalModal.tsx
│   │   ├── OptionPickerModal.tsx
│   │   ├── QuickAddBar.tsx
│   │   ├── ReminderSelector.tsx
│   │   ├── RepeatSelector.tsx
│   │   ├── ServerUrlModal.tsx
│   │   ├── SubtaskItem.tsx
│   │   ├── SyncModal.tsx
│   │   ├── SyncStatus.tsx
│   │   ├── TabBarIcon.tsx
│   │   ├── TaskDeleteModal.tsx
│   │   ├── TaskOverflowMenu.tsx
│   │   ├── UpdateNotifier.tsx
│   │   └── WheelTimePicker.tsx
│   ├── constants/
│   │   └── index.ts             # Categories, priorities, colors, reminder options
│   ├── database/
│   │   ├── schema.ts            # WatermelonDB schema (v21)
│   │   ├── index.ts             # Database instance + collections
│   │   ├── sync.ts              # Custom API sync adapter (25KB)
│   │   ├── migrations.ts        # Schema migrations
│   │   ├── adapter.ts           # Platform-specific adapters
│   │   └── tombstones.ts        # Deleted record tracking
│   ├── hooks/
│   │   ├── useDatabase.tsx      # Database context & providers
│   │   ├── useTasks.tsx         # Task queries with reactive state
│   │   ├── useCategories.tsx    # Category queries
│   │   ├── useTasksByDate.tsx   # Calendar date queries
│   │   ├── useFriends.tsx       # Friends state & actions
│   │   ├── useAuth.tsx          # Authentication state
│   │   └── useStats.tsx         # Statistics computation
│   ├── models/
│   │   ├── Task.ts              # Task model (assigneeId, repeat, reminders)
│   │   ├── Category.ts
│   │   ├── Subtask.ts
│   │   ├── RepeatProfile.ts
│   │   ├── Friendship.ts
│   │   └── Tombstone.ts
│   ├── services/
│   │   ├── api.ts               # API client with auth
│   │   ├── auth.ts              # Auth token management
│   │   ├── friends.ts           # Friends API calls
│   │   ├── notifications.ts     # Reminder scheduling (expo-notifications)
│   │   ├── repeat.ts            # Repeat task generation
│   │   └── taskActions.ts       # Task CRUD + sync operations
│   ├── theme/
│   │   ├── index.ts             # Theme context, colors, spacing
│   │   └── theme.tsx            # Accent color picker, settings sync
│   ├── types/
│   │   └── index.ts             # TypeScript interfaces
│   └── utils/
│       ├── date.ts              # Date formatting utilities
│       ├── format.ts            # General formatting
│       └── validation.ts        # Zod schemas
├── backend/                     # Backend API (separate package)
│   ├── src/
│   │   ├── index.ts             # Express app entry
│   │   ├── db/
│   │   │   ├── schema.ts        # Drizzle schema (Postgres)
│   │   │   └── index.ts         # DB connection
│   │   ├── routes/
│   │   │   ├── auth.ts          # Register, login, me, forgot/reset password
│   │   │   ├── categories.ts    # Category CRUD
│   │   │   ├── tasks.ts         # Task CRUD + batch
│   │   │   ├── subtasks.ts      # Subtask CRUD
│   │   │   ├── sync.ts          # Pull/push sync endpoints
│   │   │   ├── users.ts         # User profile & settings
│   │   │   ├── friends.ts       # Friend requests, search, management
│   │   │   ├── repeatProfiles.ts# Repeat profile CRUD
│   │   │   └── pushNotifications.ts
│   │   ├── middleware/
│   │   │   ├── auth.ts          # JWT verification
│   │   │   ├── errorHandler.ts
│   │   │   └── validation.ts    # Zod validation middleware
│   │   ├── services/
│   │   └── utils/
│   ├── drizzle.config.ts
│   └── Dockerfile
├── electron/                    # Desktop app entry
├── android/                     # Native Android project
├── assets/                      # Images, fonts
├── patches/                     # patch-package fixes
└── plugins/                     # Expo config plugins

Data Models

Task

{
  id: string;
  title: string;
  description: string;
  categoryId: string;
  priority: 'none' | 'low' | 'medium' | 'high' | 'critical';
  completed: boolean;
  dueDate: number;        // timestamp (ms)
  dueTime: string;        // "HH:MM" (24h stored, 12h displayed)
  allDay: boolean;
  assigneeId: string | null;
  repeatProfileId: string | null;
  seriesId: string | null;      // For repeating tasks
  isTemplate: boolean;          // Series template
  reminderOffset: string | null; // e.g., "5m", "1h", "1d"
  createdAt: Date;
  updatedAt: Date;
  subtasks: Subtask[];
}

Category

{
  id: string;
  name: string;
  color: '#HEX';
  order: number;
  createdAt: Date;
  updatedAt: Date;
}

Subtask

{
  id: string;
  taskId: string;
  parentSubtaskId: string | null;  // For nesting
  title: string;
  completed: boolean;
  order: number;
  assigneeId: string | null;
  createdAt: Date;
  updatedAt: Date;
}

Repeat Profile

{
  id: string;
  name: string;
  frequency: 'daily' | 'weekly' | 'monthly' | 'yearly' | 'custom';
  interval: number;
  daysOfWeek: number[];      // 0-6 for weekly
  dayOfMonth: number | null; // For monthly
  monthOfYear: number | null; // For yearly
  endDate: number | null;    // Timestamp
  occurrences: number | null;
  createdAt: Date;
  updatedAt: Date;
}

Friendship

{
  id: string;
  userId: string;        // Requester
  friendId: string;      // Recipient
  status: 'pending' | 'accepted' | 'declined' | 'blocked';
  createdAt: Date;
  updatedAt: Date;
}

Default Categories

Name Color Order
Work #E53935 (Red) 0
Personal #43A047 (Green) 1
School #1E88E5 (Blue) 2
Shopping #FB8C00 (Orange) 3
Health #8E24AA (Purple) 4
Finance #FDD835 (Yellow) 5

Priority Colors

Priority Color
None #9E9E9E
Low #43A047
Medium #FB8C00
High #E53935
Critical #B71C1C

Getting Started

Prerequisites

  • Node.js 20+
  • npm or yarn
  • Expo CLI (npm install -g expo-cli)
  • iOS Simulator (Mac) / Android Studio for mobile testing
  • PostgreSQL 16+ (or Docker)

Installation

cd carry-your-live
npm install

cd ../backend
npm install

Development

Frontend

cd carry-your-live

# Start Expo dev server
npx expo start

# Run on specific platform
npx expo start --ios
npx expo start --android
npx expo start --web

Backend

cd backend

# Start PostgreSQL (Docker)
docker-compose up -d postgres

# Configure environment
cp .env.example .env
# Edit .env with your settings

# Run migrations
npm run db:push

# Start dev server
npm run dev

Server runs at http://localhost:3000 (health check: GET /health)

Desktop (Electron)

cd carry-your-live

# Development with live reload
npm run desktop:dev

# Production build
npm run desktop:dist

Building

EAS Build (cloud)

# Install EAS CLI
npm install -g eas-cli

# Configure project
eas build:configure

# Build for platforms
eas build --platform ios
eas build --platform android
eas build --platform web

Profiles defined in eas.json (development, preview, production; production auto-increments version code).

Gradle (local Android APK)

cd carry-your-live/android

# Debug APK (unsigned)
./gradlew assembleDebug

# Release APK (signed with debug keystore)
./gradlew assembleRelease

Output:

android/app/build/outputs/apk/debug/app-debug.apk
android/app/build/outputs/apk/release/app-release.apk

CI/CD Pipeline (Gitea Actions)

.gitea/workflows/build-apk.yml builds a release APK on every push to main (also manually triggerable via workflow_dispatch):

  1. Checkout and setup Node 22, JDK 17 (Temurin)
  2. Android SDK: installs cmdline-tools, licenses, platform-tools, platforms;android-35, build-tools;35.0.0, ndk;27.1.12297006
  3. JS deps: npm ci in carry-your-live/
  4. Debug keystore: generates carry-your-live/android/app/debug.keystore with keytool
  5. Build: ./gradlew assembleRelease in carry-your-live/android/
  6. Upload: APK saved as carry-your-live-release artifact

To run locally exactly as CI does:

keytool -genkeypair -v \
  -keystore carry-your-live/android/app/debug.keystore \
  -alias androiddebugkey -storepass android -keypass android \
  -keyalg RSA -keysize 2048 -validity 10000 \
  -dname "CN=Android Debug,O=Android,C=US"
cd carry-your-live/android && ./gradlew assembleRelease

Backend API Specification

Server runs at http://localhost:3000/api (configurable in src/services/api.ts and src/database/sync.ts):

Authentication

  • POST /api/auth/register - Register new user
  • POST /api/auth/login - Login (returns access + refresh tokens)
  • POST /api/auth/refresh - Refresh access token
  • POST /api/auth/forgot-password - Request password reset
  • POST /api/auth/reset-password - Reset password with token
  • GET /api/auth/me - Get current user

Categories

  • GET /api/categories - List categories
  • POST /api/categories - Create category
  • PATCH /api/categories/:id - Update category
  • DELETE /api/categories/:id - Delete category

Tasks

  • GET /api/tasks - List tasks (with filters: category, completed, due date range, assignee)
  • GET /api/tasks/:id - Get task with subtasks
  • POST /api/tasks - Create task
  • PATCH /api/tasks/:id - Update task
  • DELETE /api/tasks/:id - Delete task (scopes: this/future/all for repeating)
  • POST /api/tasks/batch - Batch operations

Subtasks

  • GET /api/subtasks/task/:taskId - List subtasks for task
  • POST /api/subtasks/task/:taskId - Create subtask
  • PATCH /api/subtasks/:id - Update subtask
  • DELETE /api/subtasks/:id - Delete subtask

Repeat Profiles

  • GET /api/repeat-profiles - List repeat profiles
  • POST /api/repeat-profiles - Create repeat profile
  • PATCH /api/repeat-profiles/:id - Update repeat profile
  • DELETE /api/repeat-profiles/:id - Delete repeat profile

Users

  • GET /api/users/me - Get user with settings
  • PATCH /api/users/me/settings - Update settings (darkMode, defaultCategoryId, sortOrder, etc.)
  • GET /api/users/search - Search users (for friends)

Friends

  • GET /api/friends - List accepted friends
  • GET /api/friends/requests - List pending requests (incoming/outgoing)
  • POST /api/friends/request - Send friend request
  • PATCH /api/friends/request/:id/accept - Accept request
  • PATCH /api/friends/request/:id/decline - Decline request
  • DELETE /api/friends/:id - Remove friend

Sync (Offline-first)

  • GET /api/sync?since=<timestamp> - Pull changes since timestamp
  • POST /api/sync/push - Push local changes

Sync Protocol

The sync endpoint uses a cursor-based approach with tombstones:

  1. Pull: Client sends since timestamp, server returns all changes since then

    {
      "categories": [...],
      "tasks": [...],
      "subtasks": [...],
      "repeatProfiles": [...],
      "friendships": [...],
      "tombstones": [...],
      "timestamp": 1234567890
    }
    
  2. Push: Client sends batched changes with lastPulledAt

    {
      "changes": {
        "categories": [...],
        "tasks": [...],
        "subtasks": [...],
        "repeatProfiles": [...],
        "friendships": [...]
      },
      "tombstones": [...],
      "lastPulledAt": 1234567890
    }
    
  3. Conflict Resolution: Last-write-wins based on updatedAt (customizable in src/database/sync.ts)


Configuration

Frontend Environment Variables

Create .env file in carry-your-live/:

EXPO_PUBLIC_API_URL=http://your-api-url/api

Backend Environment Variables

Create .env file in backend/:

DATABASE_URL=postgresql://user:pass@localhost:5432/carry_your_live
JWT_SECRET=your-32-char-secret
PORT=3000
NODE_ENV=development
FRONTEND_URL=http://localhost:8081

App Config

Modify app.json for:

  • App name, slug, version
  • Icon, splash screen
  • Permissions (notifications, etc.)
  • Orientation, theme

Visual Style Guide

  • Background: White (#FFFFFF) / Dark mode (planned)
  • Primary Accent: #E53935 (Pink/Red) - customizable
  • Typography: Black (#212121) primary, #757575 secondary, #9E9E9E tertiary
  • Borders: Thin (#E0E0E0), selected #E53935
  • Radius: 16-20px for cards/buttons/inputs
  • Spacing: 8px grid system
  • Shadows: Minimal (elevation 1-3)
  • Animations: 150-250ms, cubic easing

Offline-First Architecture

┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│   Expo App  │────▶│ WatermelonDB │────▶│  Backend    │
│ (iOS/Android│     │  (SQLite)    │     │  (Postgres) │
│    Web)     │◀───▶│  + Sync      │◀───▶│             │
└─────────────┘     └──────────────┘     └─────────────┘
  1. All writes go to local SQLite first
  2. Reactive queries update UI instantly
  3. Background sync pushes/pulls changes
  4. Conflict resolution: last-write-wins (customizable)
  5. Tombstones track deletions for sync

Current Implementation Status

Based on code audit (August 2026):

Feature Status Notes
Core CRUD (tasks, subtasks, categories) ✅ Complete
Nested subtasks ✅ Complete Unlimited depth
Repeating tasks ✅ Complete Profiles, series, this/future/all delete
Categories & priorities ✅ Complete
Calendar with date strip ✅ Complete Month nav, day detail
Stats screen ✅ Complete Client-side only
Settings screen ✅ Complete Most settings wired
Friends system ✅ Complete Backend + UI
Task assignees ✅ Complete Schema v7, UI, sync
QuickAddBar ✅ Complete Tasks + Calendar
Offline sync (WatermelonDB) ✅ Complete Schema v21, tombstones
Backend API ✅ Complete Express + Drizzle + Postgres
Auth (JWT) ✅ Complete Register, login, refresh, forgot/reset
Dark mode / theme toggle ❌ Missing Backend column exists, UI not implemented
Notifications toggle 🟡 Partial Stored but not respected
Global reminder preference 🟡 Partial Stored but not applied
Forgot/reset password UI 🟡 Partial Backend done, no client UI
Pull-to-refresh → sync 🟡 Partial Reloads local only
Client settings sync 🟡 Partial AsyncStorage only, not synced to backend
Reminder enum mismatch 🟡 Partial Client uses '5m'/'1h', spec uses minutes

Roadmap Highlights

v1.1.0 — Friends & Assignees (Current Unreleased)

  • Ship existing Unreleased changes
  • Fix notifications toggle, wire up rescheduleAllReminders()
  • Apply global reminder preference
  • Make pull-to-refresh trigger real sync
  • Add forgot/reset password UI
  • Unify reminder offset enums

v1.2.0 — Theming & Findability

  • Light mode + follow-system-theme
  • Sync all settings to PATCH /users/me/settings
  • Task search (filter + global)
  • Friend request badges/indicators

v1.3.0 — Stats & Insights

  • Persisted stats snapshots
  • Productivity trends, streaks
  • Export stats (CSV/image)

v1.4.0 — Quick Capture & Calendar UX

  • Natural language quick-add
  • Drag-and-drop rescheduling in calendar
  • Month grid view
  • "Today at a glance" dashboard

v1.5.0 — Power Tools & Personalization

  • Task templates, soft-archive, attachments
  • Markdown support, deep links
  • Biometric lock, haptics, reduced motion
  • Android home-screen widget

v2.0.0 — Collaboration

  • Real task assignment delivery
  • Shared lists with permissions
  • Server push notifications (FCM/APNs)
  • Comments/activity feed

Contributing

  1. Follow existing code conventions
  2. Use TypeScript strict mode
  3. Write components with React Hook Form + Zod
  4. Use WatermelonDB decorators for models
  5. Test offline scenarios
  6. Run npm run lint and npm run typecheck before committing

License

MIT

S
Description
No description provided
Readme
2 GiB
v1.0.18
Latest
2026-08-27 04:53:36 +00:00
Languages
TypeScript 97.6%
JavaScript 1.7%
Kotlin 0.6%