-
Notifications
You must be signed in to change notification settings - Fork 583
Description
Problem
Channels are currently stored as Set with just the channel name. This causes namespace collision when users join the same channel on different timelines.
When a user joins #gaming on mesh (Bluetooth) and #gaming on geohash 9q8yy (Nostr), all messages mix together, violating timeline isolation.
Solution
Composite keys with timeline namespacing:
Format: "{timeline}:{identifier}:{channel}"
Examples:
mesh:#gaming
geo:9q8yy:#gaming
geo:dr5ru:#gaming
This scales naturally to:
- ✅ Multiple geohashes (SF vs NYC)
- ✅ Future timeline types (satellite, LoRa, etc.)
- ✅ Backward compatibility (old keys → mesh: prefix)
Implementation
New: ChannelKeys Helper Object
Single source of truth for all composite key operations - create, parse, validate. Prevents string manipulation bugs and provides clean abstractions.
Core Changes
| Component | Change |
|---|---|
| ChannelManager | Accept timeline param, create composite keys |
| Message Handlers | Route to composite keys, support legacy message.channel field |
| UI Sidebar | Group by timeline: "MESH 🔵" / "GEO 9q8yy 🌐" sections |
| DataManager | Lazy migration: old "#gaming" → "mesh:#gaming" |
Key Features
✅ Scalable - Works with N timelines without schema changes
✅ Backward Compatible - Auto-migration, supports legacy clients
✅ Clean Abstractions - ChannelKeys helper prevents duplication
✅ Type-Safe - Uses existing ChannelID sealed class
Why This Scales
- No schema changes - Still Set, just different string format
- Timeline-agnostic - Composite key pattern works for any future timeline type
- Zero migration cost - Normalization happens lazily on load
- Composable - Can extend to additional dimensions if needed