Skip to content

Feature: Community Discovery — node selector on first launch #563

@mostronatorcoder

Description

@mostronatorcoder

Context

Currently, Mostro Mobile connects to a single hardcoded Mostro node. As the community network grows, users should be able to choose which trusted Mostro community/node they want to connect to on first launch.

The mostro.community website already implements this: it hardcodes trusted node pubkeys and fetches community metadata (name, avatar, description, currencies, fee) from Nostr kind 0 and kind 38385 events. We replicate this pattern in the mobile app.

User Flow

New user

App install → Walkthrough (complete or skip) → Community Selector → Home

Existing user

App launch → Home → (Settings → Community → Change, if they want)

The selector is shown only once to new users. Existing users are not interrupted.

Trusted Node Pubkeys

Mirror the list from mostro.community. These are the initial trusted communities:

Region Pubkey Telegram Website
🇨🇺 Cuba 00000235a3e904cfe1213a8a54d6f1ec1bef7cc6bfaabd6193e82931ccf1366a @Cuba_Bitcoin cubabitcoin.org
🇪🇸 España 0000cc02101ec29eea9ce623258752b9d7da66c27845ed26846dd0b0fc736b40 @NostroMostro
🇨🇴 Colombia 00000978acc594c506976c655b6decbf2d4af25ffdaa6680f2a9568b0a88441b @ColombiaP2P
🇧🇴 Bolivia 00007cb3305fb972f5cc83f83a8fbca1e64e93c9d1369880a9fd62ef95d23f91 @BtcxBolivia

Default node: 82fa8cb978b43c79b2156585bac2c011176a21d2aead6d9f7c575c005be88390 (to be used when user skips or as initial fallback).

Community Selector Screen

┌─────────────────────────────┐
│  ⚡  Choose your community   │
│  [🔍 Search]               │
│                             │
│  ┌───────────────────────┐  │
│  │ 🧌  Mostro Cuba  🇨🇺   │  │
│  │ Cuba Bitcoin           │  │
│  │ USD  📊 100K–1M sats │  │
│  │ 💰 1.0%  [💬] [🌐]   │  │
│  └───────────────────────┘  │
│  [more cards...]            │
│                             │
│  ┌───────────────────────┐  │
│  │  ⚙️  Use a custom node │  │
│  └───────────────────────┘  │
│                             │
│       [ Skip for now ]      │
└─────────────────────────────┘

Card data sources:

  • kind 0 (Nostr profile): name, about, picture
  • kind 38385 (Mostro info): currencies, min/max sats, fee
  • Hardcoded config: pubkey, region, social links

Technical Approach

1. Trusted Pubkeys

lib/core/config/communities.dart — mirror the approach from mostro.community:

class SocialLink {
  final String type; // telegram, x, instagram, etc.
  final String url;
}

class CommunityConfig {
  final String pubkey; // hex format
  final String region; // e.g. 🇨🇺 Cuba
  final List<SocialLink> social;
  final String? website;
}

const COMMUNITIES = [
  CommunityConfig(
    pubkey: 00000235a3e904cfe1213a8a54d6f1ec1bef7cc6bfaabd6193e82931ccf1366a,
    region: 🇨🇺 Cuba,
    social: [SocialLink(type: telegram, url: https://t.me/Cuba_Bitcoin)],
    website: https://cubabitcoin.org/kmbalache/,
  ),
  CommunityConfig(
    pubkey: 82fa8cb978b43c79b2156585bac2c011176a21d2aead6d9f7c575c005be88390,
    region: 🌐 Default,
    social: [],
  ),
  // ... more communities from mostro.community
];

2. Nostr Fetch (WebSocket only)

Use web_socket_channel package. Connect to wss://relay.mostro.network. Request kind 0 and kind 38385 for all pubkeys. Do NOT add nostr-sdk dependency. Simple WebSocket is enough.

REQ <id> {kinds: [0], authors: [pubkey1, pubkey2, ...]}
REQ <id> {kinds: [38385], authors: [pubkey1, ...], #y: [mostro]}

Timeout: 10s. Partial data is fine (kind 0 may succeed, 38385 may fail).

3. Data Model

class Community {
  final String pubkey;
  final String region;
  final String? name;
  final String? about;
  final String? picture;
  final List<String> currencies;
  final String? minAmount;
  final String? maxAmount;
  final String? fee;
  final List<SocialLink> social;
  final String? website;
}

4. State Management

  • communitySelectorProvider: async provider that fetches communities from Nostr
  • Selected community pubkey stored in SharedPreferences (no Rust changes needed)
  • Show selector only if: !hasCompletedOnboarding && selectedCommunity == null

5. Navigation

CommunitySelectorScreen is pushed after Walkthrough, before Home. Existing users see it only if they never selected a community.

hasCompletedOnboarding
  ? (selectedCommunity != null ? HomeScreen : CommunitySelectorScreen)
  : WalkthroughScreen

6. Settings Integration

Settings → Community:

  • Shows current community card
  • "Change community" → opens selector again
  • "Use custom node" → paste pubkey manually

7. Default Node

If user skips, use Negrunchs node pubkey as default. Store in SharedPreferences as fallback.

TODO

  • Create lib/core/config/communities.dart with trusted pubkeys (from mostro.community + default)
  • Implement Nostr WebSocket client (web_socket_channel, no nostr-sdk)
  • Fetch kind 0 + kind 38385 from relay.mostro.network
  • Create CommunityCard widget
  • Create CommunitySelectorScreen with loading skeleton
  • Add search bar and country filter
  • Add "Use custom node" (manual pubkey input)
  • Add "Skip for now" and "Confirm" buttons
  • Wire into navigation flow after Walkthrough
  • Settings → Community section
  • Empty/error state when relay fails

Out of Scope (v1)

  • Decentralized discovery via NIP
  • Real-time updates when community changes their kind 38385
  • User-created communities (curated list only)

Reference

  • mostro.community: https://github.com/MostroP2P/community
  • Communities config: src/config/communities.ts
  • Communities component: src/components/Communities.astro
  • Kind 38385 spec: docs/fees.md in mostro repo

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions