You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
Silberengel ab64eef9dc small tweaks and bug-fixes 3 weeks ago
config small tweaks and bug-fixes 3 weeks ago
docker Specify database to connect to in PG setup script 2 months ago
lib small tweaks and bug-fixes 3 weeks ago
priv small tweaks and bug-fixes 3 weeks ago
rel/overlays/bin Configure for local dev with Docker Compose 2 months ago
test implement issue #6 3 weeks ago
.dockerignore Organize for release builds and dev deployment 2 months ago
.env.example install script, based upon my successful local attempt 3 weeks ago
.formatter.exs Get Phoenix server up and running with Nostr Ecto context 3 months ago
.gitignore Configure for local dev with Docker Compose 2 months ago
AGENTS.md Add Elixir style rule with code example 2 months ago
CLAUDE.md Symlink CLAUDE.md to AGENTS.md 2 months ago
LICENSE.md Initial commit 3 months ago
README.md implement issue #6 3 weeks ago
compose.yaml small tweaks and bug-fixes 3 weeks ago
dev.sh implement issue #6 3 weeks ago
mix.exs small tweaks and bug-fixes 3 weeks ago
mix.lock Add Credo to deps 2 months ago
prd-1-index-relay.md Produce Swagger schema for REST API 2 months ago
setup.sh implement issue #6 3 weeks ago

README.md

Mercury Index-Relay logo

GitCitadel Mercury Index-Relay

A Nostr index relay built with Phoenix 1.8 / Elixir. Stores and serves Nostr events via a REST API, with filter-based querying per NIP-01.

Supported NIPs: NIP-11 (relay info), NIP-70 (protected events)

Getting Started

Prerequisites

  • Docker (for the database)
  • Elixir ~> 1.15

Automated setup

Run the setup script — it installs Erlang/Elixir via asdf, starts the Apache AGE database container, and runs mix setup:

chmod +x setup.sh
./setup.sh

After setup, database credentials are written to .env. Source it before running any mix commands:

source .env

Manual setup

Start the Apache AGE Docker container:

docker run \
  -d \
  --name gc_age_db \
  -p 5455:5432 \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=postgres \
  -e POSTGRES_DB=gc_index_relay_dev \
  apache/age:release_PG17_1.6.0

Set database environment variables, then install dependencies and run migrations:

export POSTGRES_HOST=localhost
export POSTGRES_PORT=5455
export POSTGRES_USER=postgres
export POSTGRES_PASSWORD=postgres
export POSTGRES_DB=gc_index_relay_dev

mix setup

Starting the server

source .env
mix phx.server

The relay is available at http://localhost:4000.

During development, use dev.sh instead to get automatic server restarts when config files change:

source .env && ./dev.sh

API

Method Path Description
GET /api List available endpoints
GET /api/events Query events via URL params (since, until, limit required)
POST /api/events/filter Query events with a NIP-01 filter body (limit required)
GET /api/events/:id Fetch a single event by ID
POST /api/events Publish a new event
DELETE /api/events/:id Delete an event by ID
GET /api/swagger Swagger UI
GET /health Health check

NIP-11 relay info

curl -s -H "Accept: application/nostr+json" http://localhost:4000 | jq

Edit the relay metadata in config/config.exs under the :relay_info key.

Testing

Unit tests (no database required):

mix test.unit

Integration tests (requires the database to be running):

source .env
mix test.integration

Run the full integration probe against the relay API (covers all endpoints, CORS, NIP-11, NIP-70):

source .env
mix test.integration test/gc_index_relay_web/relay_integration_test.exs

The test scenarios are documented in test/features/relay_api.feature and cover:

  • Discovery (GET /api)
  • Publishing and rejecting events (POST /api/events)
  • Deleting events (DELETE /api/events/:id)
  • Cacheable queries (GET /api/events?since=&until=&limit=)
  • Filter-based queries (POST /api/events/filter)
  • Single-event lookup (GET /api/events/:id)
  • CORS preflight and headers
  • NIP-11 relay info document including the icon field

Pre-commit check (compile with warnings-as-errors, format, credo, integration tests):

source .env
mix precommit

Project Overview

Database

  • The database stores Nostr events.
  • Nostr events, once signed, are considered immutable.
  • Uses Apache AGE (PostgreSQL with graph extensions).

Migrations

After modifying an Ecto schema, generate a migration with:

mix ecto.gen.migration <migration-name>

Edit the generated migration file as needed, then apply it:

mix ecto.migrate

Refer to the Fly.io guide Safe Ecto Migrations for additional information.

Learn more