Skip to content

A peer-to-peer messaging platform where senders pay recipients to read messages. Spam becomes impossible. Your inbox becomes profitable.

Notifications You must be signed in to change notification settings

omsuneri/SuneriChat

Repository files navigation

SuneriChat

A peer-to-peer messaging platform that monetizes attention by requiring payment for message delivery. Built on Nostr protocol principles with a value-based communication model.

Problem Statement

Modern messaging platforms suffer from spam, unsolicited messages, and attention exploitation. Users receive countless unwanted messages daily, with no mechanism to filter based on sender commitment. Current solutions either require complex filtering rules or rely on centralized moderation systems.

SuneriChat introduces an economic barrier to messaging, ensuring every communication carries inherent value. Senders pay recipients directly to read their messages, creating a natural spam deterrent while allowing recipients to monetize their attention.

Core Concept

The platform operates on a simple principle: your attention has value. When someone sends you a message, they pay a price you set. This creates three fundamental dynamics:

  1. Senders only reach out when the message matters
  2. Recipients get compensated for reading messages
  3. Spam becomes economically unviable

Unlike traditional chat applications where messages are free and abundant, SuneriChat creates scarcity through economics. Each message represents a value transfer, making communication more intentional and meaningful.

Technical Architecture

System Overview

graph TB
    Client[React Frontend] -->|WebSocket| Server[Node.js Server]
    Client -->|HTTP/REST| API[Next.js API Routes]
    Server -->|Read/Write| DB[(JSON Database)]
    API -->|Read/Write| DB
    Server -->|Socket.IO| Client
    
    subgraph Backend
        Server
        API
        DB
    end
    
    subgraph Frontend
        Client
        Storage[LocalStorage]
        Client -->|Store Keys| Storage
    end
Loading

Architecture Components

Frontend Layer

  • React 18 with TypeScript for type safety
  • Vite for fast development and optimized builds
  • Zustand for state management
  • Socket.IO client for real-time communication
  • LocalStorage for keypair persistence

Backend Layer

  • Next.js API routes for RESTful endpoints
  • Node.js HTTP server with Socket.IO integration
  • JSON file-based database for data persistence
  • WebSocket server for real-time message delivery

Data Flow

sequenceDiagram
    participant Sender
    participant SenderWS as Sender WebSocket
    participant Server
    participant DB as Database
    participant RecipientWS as Recipient WebSocket
    participant Recipient
    
    Sender->>SenderWS: Send message + payment
    SenderWS->>Server: Message data
    Server->>DB: Validate balance
    DB-->>Server: Balance confirmed
    Server->>DB: Deduct from sender
    Server->>DB: Add to recipient
    Server->>DB: Store message
    Server->>RecipientWS: New message event
    RecipientWS->>Recipient: Display message
    Server->>SenderWS: Balance update
    SenderWS->>Sender: Update UI
Loading

Database Schema

The application uses a JSON-based database with the following structure:

{
  "users": {
    "npub...": {
      "npub": "string",
      "username": "string",
      "message_price": "number",
      "balance": "number",
      "created_at": "timestamp"
    }
  },
  "messages": [
    {
      "id": "string",
      "sender": "npub",
      "recipient": "npub",
      "content": "string",
      "amount": "number",
      "timestamp": "number",
      "read": "boolean"
    }
  ],
  "transactions": [
    {
      "id": "string",
      "from_npub": "string",
      "to_npub": "string",
      "amount": "number",
      "type": "string",
      "status": "string",
      "created_at": "timestamp"
    }
  ]
}

Identity System

SuneriChat uses the Nostr protocol's key management approach:

  • Users generate secp256k1 keypairs locally
  • Public keys (npub) serve as user identifiers
  • Private keys (nsec) remain client-side for signing
  • No centralized authentication required
graph LR
    A[Generate Keypair] --> B[Store in LocalStorage]
    B --> C[Create Account]
    C --> D[Set Username]
    D --> E[Ready to Message]
    
    F[Returning User] --> G[Load from LocalStorage]
    G --> H[Auto-login]
Loading

Local Setup

Prerequisites

  • Node.js version 18 or higher
  • npm or yarn package manager
  • Git for version control

Installation Steps

Clone the repository:

git clone <repository-url>
cd XYZ

Install backend dependencies:

npm install

Install frontend dependencies:

cd frontend
npm install
cd ..

Environment Configuration

Create a .env file in the root directory:

NODE_ENV=development
PORT=8081

Create a .env file in the frontend directory:

VITE_API_URL=http://localhost:8081/api
VITE_WS_URL=http://localhost:8081

Running the Application

Start the backend server:

node server-combined.js

The server runs on port 8081 and handles both HTTP requests and WebSocket connections.

In a separate terminal, start the frontend development server:

cd frontend
npm run dev

The frontend runs on port 8080 by default.

Access the application at http://localhost:8080

Usage Guide

First-Time Setup

  1. Navigate to the application URL
  2. Click "Generate New Keys" on the welcome screen
  3. Save your private key securely - it cannot be recovered
  4. Set a username for your account
  5. You receive 1000 SUNC as starting balance

Setting Message Price

Your message price determines what others pay to message you:

  1. Open the sidebar menu
  2. Locate the "Message Price" section
  3. Set a value between 10 and 1000 SUNC
  4. Price updates immediately for new conversations

Sending Messages

  1. Navigate to the Discover page
  2. Search for users by username or public key
  3. Click "Message" on any user card
  4. Type your message in the chat interface
  5. Payment is deducted automatically upon sending

Message Economics

When you send a message:

  • Your balance decreases by the recipient's message price
  • The recipient's balance increases by the same amount
  • The message is delivered instantly if recipient is online
  • Messages persist and load on recipient's next login

Understanding Balance

Your balance represents SUNC tokens:

  • Starting balance: 1000 SUNC
  • Earned by receiving messages
  • Spent by sending messages
  • Cannot send if balance is insufficient

Technical Implementation Details

WebSocket Protocol

The application uses Socket.IO for bidirectional communication:

Client Events:

  • send-message: Transmit message with payment
  • user-updated: Broadcast profile changes

Server Events:

  • balance-update: Notify balance changes
  • new-message: Deliver incoming messages
  • message-history: Send conversation history
  • user-updated: Propagate user profile updates

State Management

Zustand provides centralized state with minimal boilerplate:

interface AppState {
  currentUser: User | null
  messages: Message[]
  allUsers: User[]
  isConnected: boolean
}

State updates trigger React re-renders automatically. WebSocket events modify state through defined actions, maintaining consistency between server and client.

Security Considerations

Key Storage: Keys are stored in browser LocalStorage. While convenient for development, production systems should consider:

  • Hardware wallet integration
  • Encrypted storage with user-provided passphrase
  • Session-based key management

Message Privacy: Messages are currently stored in plaintext. End-to-end encryption can be implemented using recipient's public key for encryption and sender's private key for signing.

Balance Manipulation: The current implementation trusts server-side balance calculations. Production systems should:

  • Implement cryptographic proofs of payment
  • Use blockchain or distributed ledger for immutability
  • Add transaction verification mechanisms

Project Structure

XYZ/
├── app/
│   └── api/              # Next.js API routes
│       ├── messages/     # Message endpoints
│       ├── nostr/        # Key generation
│       ├── user/         # User management
│       └── users/        # User listing
├── frontend/
│   └── src/
│       ├── components/   # React components
│       │   ├── chat/     # Chat interface
│       │   ├── discover/ # User discovery
│       │   └── onboarding/ # Setup flow
│       ├── hooks/        # Custom React hooks
│       ├── lib/          # Utilities and services
│       └── store/        # State management
├── lib/
│   └── database.js       # Database operations
├── server-combined.js    # WebSocket server
└── sunerichat-db.json    # Database file

Development Notes

Database Operations

The JSON database reloads on each operation to ensure consistency:

const db = initDatabase()  // Reads from disk
updateBalance(db, npub, amount)  // Modifies in memory
saveDatabase(db)  // Writes to disk

This approach prioritizes simplicity over performance. For production, consider:

  • PostgreSQL or MongoDB for scalability
  • Connection pooling for efficiency
  • Transaction support for atomicity

Message Delivery

Messages follow optimistic UI updates:

  1. Client adds message to local state immediately
  2. WebSocket sends message to server
  3. Server validates and stores message
  4. Server emits to recipient only (not back to sender)
  5. Sender sees their message from optimistic update

This prevents duplicate messages while maintaining responsive UI.

Username Uniqueness

Usernames are enforced unique at the database level:

function isUsernameTaken(db, username, excludeNpub) {
  return Object.values(db.users).some(u => 
    u.username.toLowerCase() === username.toLowerCase() && 
    u.npub !== excludeNpub
  )
}

Case-insensitive comparison prevents "Alice" and "alice" from coexisting.

Performance Considerations

WebSocket Connections

Each user maintains one persistent WebSocket connection. The server tracks connections in a Map:

const users = new Map()  // npub -> socketId
users.set(npub, socket.id)

This enables direct message routing without broadcasting to all connections.

Message History

On connection, the server sends full message history. For large histories:

  • Implement pagination
  • Load recent messages first
  • Fetch older messages on scroll
  • Consider message retention policies

Balance Calculations

Balance updates occur synchronously during message send. This ensures:

  • Atomic balance changes
  • No race conditions
  • Immediate feedback to users

For high-frequency messaging, consider:

  • Batch balance updates
  • Delayed consistency models
  • Optimistic balance predictions

Future Enhancements

Protocol Extensions

Lightning Network Integration: Replace internal SUNC tokens with real Bitcoin payments via Lightning Network. This requires:

  • Lightning node connection
  • Invoice generation per message
  • Payment verification before delivery

Nostr Event Publishing: Publish messages as Nostr events to relay servers, enabling:

  • Decentralized message storage
  • Cross-client compatibility
  • Censorship resistance

Feature Additions

Group Messaging: Split payment across group members based on configurable rules:

  • Equal split among all members
  • Weighted by member-set prices
  • Flat fee per group message

Message Reactions: Allow recipients to react to messages with optional tip:

  • Standard reactions (like, dislike)
  • Custom emoji reactions
  • Additional payment with reaction

Reputation System: Track user behavior metrics:

  • Message quality ratings
  • Response time statistics
  • Blocked user lists

Contributing

When contributing code, follow these guidelines:

  • Use TypeScript for type safety
  • Write descriptive commit messages
  • Add comments for complex logic
  • Test WebSocket events thoroughly
  • Validate balance calculations
  • Check username uniqueness

License

This project is provided as-is for educational and development purposes.

About

A peer-to-peer messaging platform where senders pay recipients to read messages. Spam becomes impossible. Your inbox becomes profitable.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published