Offline-first P2P collaborative workspace. Notion + Miro + Slack without servers.
┌─────────────────────────────────────────────────────────────────┐
│ Flutter (UI) │
│ ├─ Riverpod providers → ViewModels │
│ └─ ComponentBridge → FFI → Rust backend │
└────────────────────────────────────────────────────────────────┬┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Rust Backend (cyan-backend) │
│ ├─ lib.rs — FFI layer (~90 C-compatible functions) │
│ ├─ commands.rs — Command enum (CreateGroup, SendMessage...) │
│ ├─ network_actor — Iroh (QUIC + gossipsub) │
│ ├─ storage/ — SQLite + local files │
│ └─ actors/ — Per-component actors (Chat, FileTree...) │
└─────────────────────────────────────────────────────────────────┘
Group
└─ Workspace
└─ Board
└─ Faces: Notes | Canvas | Chat | Files
Flutter talks to Rust via ComponentBridge:
// Send command to Rust
ComponentBridge.sendCommand('FileTree', '{"type":"LoadTree"}');
// Poll events from Rust
String events = ComponentBridge.pollEvents('FileTree');Key FFI functions exposed from Rust:
| Function | Purpose |
|---|---|
cyan_init() |
Initialize backend |
cyan_send_command(component, json) |
Send command to actor |
cyan_poll_events(component) |
Get events from actor |
cyan_free_string(ptr) |
Free Rust-allocated string |
cyan_create_group/workspace/board |
CRUD operations |
cyan_rename_group/workspace/board |
Rename entities |
cyan_delete_group/workspace/board |
Delete entities |
cyan_seed_demo_if_empty() |
Seed demo data |
lib/
├── main.dart
├── ffi/
│ ├── cyan_bindings.dart # Raw FFI bindings (dart:ffi)
│ └── component_bridge.dart # High-level wrapper
├── providers/
│ ├── navigation_provider.dart
│ ├── file_tree_provider.dart
│ ├── board_grid_provider.dart
│ └── chat_provider.dart
├── models/
│ └── tree_item.dart # Group, Workspace, Board models
├── screens/
│ ├── login_screen.dart
│ └── workspace_screen.dart
└── widgets/
├── icon_rail.dart # Left navigation rail
├── file_tree_widget.dart # Explorer tree view
├── board_grid_widget.dart # Masonry grid of boards
└── chat_panel.dart # Chat with code blocks
- Flutter 3.27+
- Rust toolchain
- For macOS: Xcode
cd cyan-backend
# macOS arm64
cargo build --release --target aarch64-apple-darwin
# Copy to Flutter project
cp target/aarch64-apple-darwin/release/libcyan_backend.a ../cyan_flutter/macos/Libraries/cd cyan_flutter
flutter pub get
flutter run -d macosSync via Iroh (QUIC + gossipsub):
- Discovery:
cyan/discovery/{discovery_key}topic - Group sync:
cyan/group/{group_id}topic - Direct: QUIC connection via Iroh node ID
Sync flow:
- New peer joins discovery topic → announces presence
- Existing peer sends snapshot (full state dump)
- Ongoing changes sync via delta events on group topics
Commands flow: Flutter → FFI → Rust actor Events flow: Rust actor → FFI → Flutter provider
{"type": "LoadTree"}
{"type": "CreateGroup", "name": "...", "icon": "...", "color": "..."}
{"type": "CreateWorkspace", "group_id": "...", "name": "..."}
{"type": "CreateBoard", "workspace_id": "...", "name": "...", "board_type": "..."}{"type": "TreeLoaded", "groups": [...], "workspaces": [...], "boards": [...]}
{"type": "GroupCreated", "id": "...", "name": "..."}
{"type": "Error", "message": "..."}{"type": "LoadChatHistory", "board_id": "..."}
{"type": "SendMessage", "board_id": "...", "text": "..."}{"type": "ChatHistory", "messages": [...]}
{"type": "Message", "id": "...", "text": "...", "sender_id": "...", "timestamp": "..."}SQLite with tables:
| Table | Purpose |
|---|---|
groups |
Group metadata |
workspaces |
Workspace metadata |
objects |
Boards, notes, files |
messages |
Chat messages |
peers |
Known peers |
Content-addressed files via Blake3 hashing.
Monokai-inspired dark theme:
background: 0xFF1E1E1E
surface: 0xFF252525
hover: 0xFF2A2A2A
comment: 0xFF808080
cyan: 0xFF66D9EF
green: 0xFFA6E22E
orange: 0xFFFD971F
pink: 0xFFF92672- Chat context doesn't scope correctly (shows workspace chat when in board)
- Element count badges in BoardGridView showing 0
- Large .dylib/.a files need Git LFS or exclusion from repo
- FAISS integration for search
- Whiteboard canvas polish
- File drag-drop
- iPhone layout (masonry + bottom bar)