Skip to content

Add optional persistence layer for mobile deployments #9

@melvincarvalho

Description

@melvincarvalho

Problem

The relay currently stores all events in memory only. On mobile devices (especially in Termux), this means:

  • Data loss on restart: Phone reboots, app kills, or crashes lose all stored events
  • No durability: Events published to the relay are not persisted
  • Poor user experience: Mobile users expect data to survive restarts

Mobile Use Case

For phone-based relays, persistence is particularly important because:

  • Android may kill background processes for battery optimization
  • Users may restart Termux sessions frequently
  • Device reboots are common
  • Personal relay data should persist across sessions

Proposed Solutions

Option 1: Simple JSON file persistence

// Load events on startup
const loadEvents = () => {
  try {
    if (fs.existsSync('events.json')) {
      return JSON.parse(fs.readFileSync('events.json', 'utf8'))
    }
  } catch (e) {
    console.error('Failed to load events:', e)
  }
  return []
}

// Save events periodically and on shutdown
const saveEvents = (events) => {
  try {
    fs.writeFileSync('events.json', JSON.stringify(events, null, 2))
  } catch (e) {
    console.error('Failed to save events:', e)
  }
}

Option 2: SQLite database (lightweight)

import Database from 'better-sqlite3'

const db = new Database('fonstr.db')
db.exec(`
  CREATE TABLE IF NOT EXISTS events (
    id TEXT PRIMARY KEY,
    pubkey TEXT NOT NULL,
    created_at INTEGER NOT NULL,
    kind INTEGER NOT NULL,
    tags TEXT,
    content TEXT,
    sig TEXT
  )
`)

Option 3: Environment-controlled persistence

const PERSISTENCE = process.env.PERSISTENCE || 'none' // 'none', 'json', 'sqlite'

Implementation Considerations

Performance for mobile:

  • JSON: Simple, fast startup, but slower for large datasets
  • SQLite: Better for searches, more overhead
  • Hybrid: JSON for recent events, SQLite for archive

Storage limits:

  • Should respect MAX_EVENTS cap even with persistence
  • Consider compression for JSON storage
  • Periodic cleanup of old events

Backwards compatibility:

  • Make persistence optional (default: off)
  • Existing in-memory behavior unchanged
  • Environment variable controlled

Benefits

  • Data durability: Events survive restarts
  • Better mobile UX: Relay maintains state across sessions
  • Personal relay viability: Makes phone relays practical for daily use
  • Backup capability: Events can be backed up/restored

Implementation Priority

HIGH for mobile use cases - Essential for production mobile deployment

Testing Requirements

  1. Verify events persist across restarts
  2. Test with various MAX_EVENTS limits
  3. Validate performance impact on mobile devices
  4. Ensure graceful fallback if persistence fails
  5. Test storage cleanup mechanisms

Configuration Examples

# In-memory only (current behavior)
fonstr --port 4444

# JSON persistence
PERSISTENCE=json fonstr --port 4444

# SQLite persistence  
PERSISTENCE=sqlite fonstr --port 4444

This would significantly improve the mobile deployment story and make fonstr suitable for personal relay use.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions