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](https://github.com/nostr-protocol/nips/blob/master/11.md) (relay info), [NIP-70](https://github.com/nostr-protocol/nips/blob/master/70.md) (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`: ```bash chmod +x setup.sh ./setup.sh ``` After setup, database credentials are written to `.env`. Source it before running any `mix` commands: ```bash source .env ``` ### Manual setup Start the Apache AGE Docker container: ```bash 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: ```bash 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 ```bash source .env mix phx.server ``` The relay is available at [http://localhost:4000](http://localhost:4000). After edits to `config/config.exs`, `config/dev.exs`, or `config/runtime.exs`, restart the server manually; other code is hot-reloaded. ## 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 ```bash 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): ```bash mix test.unit ``` Integration tests (requires the database to be running): ```bash source .env mix test.integration ``` Run the full integration probe against the relay API (covers all endpoints, CORS, NIP-11, NIP-70): ```bash 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](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, unit tests): ```bash 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: ```bash mix ecto.gen.migration ``` Edit the generated migration file as needed, then apply it: ```bash mix ecto.migrate ``` Refer to the Fly.io guide [Safe Ecto Migrations](https://github.com/fly-apps/safe-ecto-migrations) for additional information. ## Learn more - Phoenix: https://www.phoenixframework.org/ - Nostr protocol: https://github.com/nostr-protocol/nostr - NIP-01 (basic protocol): https://github.com/nostr-protocol/nips/blob/master/01.md