Skip to content

feat: ephemeral channels with TTL-based auto-archiving#232

Open
baxen wants to merge 1 commit intomainfrom
feature/channel-updates
Open

feat: ephemeral channels with TTL-based auto-archiving#232
baxen wants to merge 1 commit intomainfrom
feature/channel-updates

Conversation

@baxen
Copy link
Copy Markdown
Collaborator

@baxen baxen commented Apr 4, 2026

Summary

Adds ephemeral channels — channels that auto-archive after a configurable period of inactivity. Full vertical slice from schema through to the desktop UI.

Changes

Schema

  • Add ttl_seconds (INT) and ttl_deadline (TIMESTAMPTZ) columns to channels table
  • Add partial index idx_channels_ttl_expiry for efficient reaper queries

Database (sprout-db)

  • Extend ChannelRecord with ttl_seconds and ttl_deadline fields
  • Add bump_ttl_deadline() — resets the deadline on channel activity
  • Add reap_expired_ephemeral_channels() — archives channels past their deadline
  • Thread ttl_seconds through create_channel() and create_channel_with_id()

Relay (sprout-relay)

  • Parse ttl tag from NIP-29 create-group events via shared resolve_ttl() helper
  • Bump TTL deadline on every channel-scoped event (skip kind:9007 create)
  • Add background reaper task (configurable interval via SPROUT_REAPER_INTERVAL_SECS, default 60s)
  • Support SPROUT_EPHEMERAL_TTL_OVERRIDE env var for testing with short TTLs
  • Emit channel_auto_archived system messages and update NIP-29 discovery events on auto-archive

Desktop

  • Add "Ephemeral" checkbox to channel and forum creation forms (Zap icon, 1-day default)
  • Thread ttl_seconds through Tauri commands and Nostr event builders
  • Expose ttl_seconds and ttl_deadline in TypeScript types and API layer

Code Quality

  • Extract shared resolve_ttl() in handlers/mod.rs (eliminates duplication between ingest.rs and side_effects.rs)
  • Extract EPHEMERAL_TTL_SECONDS constant in AppSidebar.tsx

How It Works

  1. Client creates a channel with a ttl tag (e.g., ["ttl", "86400"])
  2. Relay stores ttl_seconds=86400 and sets ttl_deadline = NOW() + 86400s
  3. Every new message in the channel resets ttl_deadline forward
  4. Background reaper runs every 60s, archiving channels where ttl_deadline < NOW()
  5. Archived channels get a system message and updated discovery events

Testing

  • SPROUT_EPHEMERAL_TTL_OVERRIDE=60 — override all ephemeral TTLs to 60s
  • SPROUT_REAPER_INTERVAL_SECS=5 — run reaper every 5s
  • Both documented in .env.example

Multi-pod Safety

The reaper uses archived_at IS NULL as an idempotent guard — concurrent runs from multiple relay pods are harmless. A future pass will add pg_advisory_lock coordination alongside the workflow engine.

Add ephemeral channels that auto-archive after a configurable period of
inactivity. Full vertical slice: schema → DB → relay → REST API → desktop UI.

Schema:
- Add ttl_seconds (INT) and ttl_deadline (TIMESTAMPTZ) to channels table
- Add partial index for efficient reaper queries

Database (sprout-db):
- Extend ChannelRecord with ttl_seconds and ttl_deadline fields
- Add bump_ttl_deadline() to reset deadline on channel activity
- Add reap_expired_ephemeral_channels() to archive expired channels
- Thread ttl_seconds through create_channel and create_channel_with_id

Relay (sprout-relay):
- Parse 'ttl' tag from NIP-29 create-group events
- Bump TTL deadline on every channel-scoped event (skip kind:9007 create)
- Add background reaper task (configurable interval, default 60s)
- Support SPROUT_EPHEMERAL_TTL_OVERRIDE env var for testing
- Emit system messages and discovery events on auto-archive

Desktop:
- Add ephemeral checkbox to channel/forum creation forms
- Thread ttl_seconds through Tauri commands and event builders
- Expose ttl_seconds and ttl_deadline in TypeScript types and API layer
- Bump check-file-sizes override for types.ts
@baxen baxen requested a review from wesbillman as a code owner April 4, 2026 04:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants