A todo and personal organisation app
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Architecture#

Overview#

Toadist uses a client-server architecture with offline-first capabilities.

┌─────────────────┐     ┌─────────────────┐
│  Flutter Client │────▶│   Dart Server   │
│                 │◀────│                 │
│  - Local Storage│     │  - PostgreSQL   │
│  - Noot Pool    │     │  - REST API     │
│  - Views        │     │  - WebSocket    │
└─────────────────┘     └─────────────────┘

Client Architecture#

Layer Structure#

┌────────────────────────────────────┐
│            Views (UI)              │
├────────────────────────────────────┤
│           AppService               │
├────────────────────────────────────┤
│  NootPool │ ApiClient │ Storage    │
├────────────────────────────────────┤
│     Models (Noot, Activity)        │
└────────────────────────────────────┘

Key Components#

Component Responsibility
AppService Central service managing auth, sync, and connectivity
NootPool In-memory store with filtering, sorting, and event streaming
ApiClient HTTP client for server communication
LocalStorage JSON file persistence for offline mode
EncryptionService AES-256-GCM encryption for sensitive data

Server Architecture#

Request Flow#

Request → CORS → Auth → Router → Handler → Response
                   ↓
              Database

Components#

Component Responsibility
AuthMiddleware JWT token validation
DatabaseService PostgreSQL connection pool
StorageService Noot CRUD operations
WebSocketHandler Real-time event broadcasting

Data Model#

Noot Structure#

Noot
├── id: UUID
├── version: int
├── createdAt: DateTime
├── modifiedAt: DateTime
├── deleted: bool
├── activities: List<Activity>
└── checksum: SHA-256

Activity System#

  • Base Activity class with ActivityBaseProperties
  • Each activity type extends Activity
  • Activities serialize to/from JSON
  • ActivityRegistry manages type registration

Sync Protocol#

Checksum-Based Sync#

  1. Client sends local noot checksums
  2. Server compares with stored checksums
  3. Server returns:
    • Changed noots (different checksums)
    • Deleted noot IDs
    • New noots from client to store

Conflict Resolution#

  • Last-write-wins based on version number
  • Higher version takes precedence
  • Local changes queue until sync completes

Security#

Authentication#

  • JWT tokens with 24-hour expiration
  • Refresh tokens for 30-day sessions
  • Secure token storage via SharedPreferences

Encryption#

  • AES-256-GCM for sensitive activities
  • PBKDF2 key derivation from user password
  • Per-activity encryption (opt-in via encrypted flag)