Skip to content

PexMor/myjs

Repository files navigation

Collaborative PIM - Notes, Events & Contacts

A lightweight, real-time collaborative web application for managing personal information (notes, calendar events, contacts) using Y.js CRDTs synchronized over MQTT.

Features

  • Real-time Collaboration: Multiple clients can edit simultaneously with conflict-free merging
  • End-to-End Encryption: AES-GCM 256-bit encryption with HKDF key derivation
  • Reliable Delivery: IndexedDB-backed message queue with ACK tracking
  • MQTT Constraints: Handles message size limits and rate limiting
  • Three Collections:
    • Notes: Markdown editor with live preview
    • Events: iCal-compliant calendar events
    • Contacts: vCard-compliant contact management
  • QR Code Sharing: Instant room sharing via QR code or URL
  • Import/Export: JSON-based data portability
  • Responsive UI: Bootstrap 5 design for desktop and mobile

Quick Start

Development

# Install dependencies
yarn install

# Start dev server
yarn dev

# Build for production
yarn build

Usage

  1. Open the app in your browser
  2. Configure connection (or use defaults):
    • Broker: wss://test.mosquitto.org:8081/mqtt (default)
    • Room: default-room (default)
    • Secret: Custom or use default (shows security warning)
  3. Create notes, events, or contacts
  4. Share room via QR code to collaborate

Configuration

Click the gear icon (⚙️) in the top-right to configure:

  • MQTT broker URL
  • Room name
  • Encryption key (generate random or use custom)
  • Collection visibility (show/hide Notes, Events, Contacts)

Sharing a Room

  1. Click gear icon → "Share Room"
  2. Scan QR code or copy URL
  3. Other users open the URL to join instantly

Architecture

Tech Stack

  • Frontend: Preact + TypeScript + Vite
  • State: Zustand + Y.js CRDTs
  • Sync: Custom MQTT provider with encryption
  • UI: Bootstrap 5 + Bootstrap Icons
  • Markdown: marked
  • QR: qrcode

Data Flow

UI Components
    ↓
Zustand Store (wraps Y.js with deepObserve)
    ↓
Y.js Document (CRDTs)
    ↓
MQTT Provider (encryption, fragmentation, ACKs)
    ↓
MQTT Broker (message relay)

MQTT Provider Features

  • Binary frames: 47-byte header + encrypted payload
  • Fragmentation: Chunks large updates (default: 64 KiB max)
  • Rate limiting: Token bucket algorithm (default: 200 KiB/s)
  • Encryption: AES-GCM 256-bit with HKDF key derivation
  • Reliable delivery: IndexedDB queue with ACK tracking and exponential backoff retry
  • Presence tracking: Periodic beacons to detect active peers
  • Echo prevention: Ignores own messages via client ID matching

Security

Default Encryption Key

The app ships with a default encryption key (MZXW6YTBOI======) for easy deployment. This is insecure for production use!

A dismissible warning banner appears when using the default key. Always generate a custom key for private data.

Key Derivation

Keys are derived using HKDF-SHA256:

  • Input: Shared secret (base32 or base58)
  • Salt: Room name (docId)
  • Info: "mqtt-yjs-v1"
  • Output: AES-GCM 256-bit key

No Authentication

Access control is implicit via shared encryption key knowledge. Anyone with the broker URL + room name + secret can join. This is by design for maximum simplicity.

Data Schema

Notes

{
  id: string; // UUID
  title: string;
  content: string; // Markdown
  created: string; // ISO 8601
  modified: string; // ISO 8601
}

Events (iCal)

{
  id: string; // UUID
  uid: string; // iCal UID
  summary: string;
  dtstart: string; // ISO 8601
  dtend: string; // ISO 8601
  location: string;
  description: string;
  created: string;
  lastmod: string;
}

Contacts (vCard)

{
  id: string           // UUID
  uid: string          // vCard UID (urn:uuid:...)
  fn: string           // Formatted name
  n: {                 // Name components
    family, given, middle, prefix, suffix
  }
  email: string[]      // Multi-value
  tel: string[]        // Multi-value
  adr: Address[]       // Multi-value
  org: string
  title: string
  photo: string
  created: string
  rev: string
}

Import/Export

Export

  1. Click gear icon → "Export Data"
  2. Downloads myjs-export-YYYY-MM-DD.json
  3. Contains all collections

Import

  1. Click gear icon → "Import Data"
  2. Select JSON file
  3. Choose mode:
    • Overwrite: Clears all data, replaces with import
    • Append: Merges with existing (ID-based conflict resolution)

Configuration Persistence

Settings are saved to localStorage:

  • roomConfig: broker, room name, secret
  • collectionVisibility: which collections are visible
  • security-ack-{room}: security warning acknowledgment

Browser Requirements

  • Modern evergreen browser (Chrome, Firefox, Safari, Edge)
  • IndexedDB support
  • Web Crypto API
  • WebSocket support

MQTT Broker Setup

Using Public Test Broker (Default)

URL: wss://test.mosquitto.org:8081/mqtt
Auth: None
Note: Public broker, not for sensitive data

Using Custom Broker

Any MQTT broker with WebSocket support works:

  • Mosquitto with websockets
  • HiveMQ
  • EMQX
  • AWS IoT Core

Development

Project Structure

src/
├── components/       # Preact components
│   └── layout/       # Header, modals
├── providers/        # MQTT Y.js provider
├── stores/           # Zustand stores
├── types/            # TypeScript types
├── utils/            # Crypto, IDB, QR, binary helpers
├── styles/           # CSS
├── app.tsx           # Main app
└── main.tsx          # Entry point

Adding Features

  1. Update data types in src/types/collections.ts
  2. Add CRUD methods to src/stores/use-doc-store.ts
  3. Create UI components in src/components/
  4. Wire into src/app.tsx

Troubleshooting

Connection Issues

  • Check broker URL is correct (wss:// for secure WebSockets)
  • Verify broker is accessible (not behind firewall)
  • Check browser console for MQTT errors

Data Not Syncing

  • Verify all clients use same room name and secret
  • Check encryption key matches across clients
  • Look for decryption errors in console

Performance

  • Default rate limiting: 200 KiB/s
  • Large documents (>1000 items) may slow deepObserve
  • Consider splitting into multiple rooms for very large datasets

License

[Add your license here]

Contributing

[Add contribution guidelines]

Acknowledgments

  • Y.js for CRDTs
  • MQTT.js for browser MQTT client
  • Preact for lightweight React alternative
  • Bootstrap for UI framework