FEATURES_CALENDAR.md raw

Musiquay — Feature: Location-Based Event Calendar

Find cool shows and cultural events nearby, effortlessly. All highly social.

Overview

The event calendar is one of Musiquay's core platform pillars — alongside the scene graph and the services marketplace. It transforms Musiquay from a place where music lives into a place where the scene happens.

Every city has a music scene. Every scene has shows, gigs, festivals, listening parties, workshops, art openings, film screenings. Right now, finding out what's happening requires following a dozen Instagram accounts, checking five different ticketing platforms, and hoping someone in your group chat saw the poster. It's fragmented, platform-locked, and hostile to discovery.

Musiquay's calendar fixes this. Location-based. Social-first. Protocol-native. One place to find everything the scene is doing near you.

Core Concepts

Everything is a Nostr Event

The calendar is not a separate system bolted onto the side. It is Nostr events on the same relay, using the same identities, the same social graph, the same protocol primitives as everything else in Musiquay.

This means:

NIP-52: Calendar Events

Nostr already has a specification for calendar events — NIP-52 — and it maps remarkably well to what Musiquay needs. Reuse first.

NIP-52 provides:

Event KindPurposeMusiquay Usage
Kind 31922Date-based calendar events (all-day/multi-day)Festivals, multi-day events, release dates
Kind 31923Time-based calendar events (specific start/end)Shows, gigs, listening parties, workshops
Kind 31924Calendars (collections of events)Venue calendars, promoter seasons, tour schedules
Kind 31925RSVPs"I'm going", "Maybe", "Can't make it"

Key NIP-52 features already built in:

The protocol already handles the hard parts. Musiquay's job is to build a great UI on top of it and extend where needed.

Features

Location-Based Discovery

The primary interface: what's happening near me?

Social Calendar

This isn't a cold listings page. It's social by design.

Waitlists

When a show sells out, it's not over.

Protocol gaps to settle. NIP-52 has no capacity field, so capacity is a Musiquay convention (["capacity", "<n>"] on the event), and there is no authoritative queue head: promotion is a creator action (a DM to the attendee at the head of the recomputed queue), not a protocol transition. Queue order is derived from joined_at ascending, tie-broken by d ascending; the position tag is informational. The exact flow is specified in PROTOCOL_FLOWS.md.

Ticket Pre-Sales

Early access for the community.

Access windows are access filters. A pre-sale tier is a kind 32217 membership set — d = presale:<event-address>:<tier> — and the checkout checks the buyer against the current window's filter. Because relays serve all signed events to anyone, the window is enforced at purchase time, not by concealing the listing.

Ticket representation is an open decision. Three options are laid out in PROTOCOL_FLOWS.md: a Cashu P2PK ticket (identity-bound, check-in burns the token at the mint, no double entry), a BDHKE blind-signed ticket (unlinkable but transferable and not identity-bound), or a NIP-59 wrapped venue-signed deed. It must be settled before the calendar pillar ships, because it is the only commerce flow with a fraud surface.

Release Countdowns

Building anticipation as a social experience.

Beyond Music

The calendar isn't limited to gigs. The scene is broader than concerts.

If the scene cares about it, it belongs on the calendar. The t (hashtag) tags handle categorization without requiring a rigid taxonomy.

Data Model

Calendar Events (NIP-52 Reuse)

The core data model is NIP-52 with Musiquay-specific conventions for tag usage.

Time-based event (kind 31923) — typical show listing:

{
  "kind": 31923,
  "pubkey": "<venue or promoter pubkey>",
  "content": "Description of the event, lineup details, etc.",
  "tags": [
    ["d", "<unique-identifier>"],
    ["title", "Friday Night at Lux Frágil"],
    ["summary", "DJ sets from local selectors"],
    ["image", "https://blossom.musiquay.com/<hash>"],
    ["start", "1735851600"],
    ["end", "1735876800"],
    ["D", "20090"],
    ["start_tzid", "Europe/Lisbon"],
    ["location", "Lux Frágil, Av. Infante Dom Henrique, Lisboa"],
    ["g", "eyckch"],
    ["p", "<artist-1-pubkey>", "wss://relay.musiquay.com", "performer"],
    ["p", "<artist-2-pubkey>", "wss://relay.musiquay.com", "performer"],
    ["p", "<sound-engineer-pubkey>", "wss://relay.musiquay.com", "sound"],
    ["p", "<photographer-pubkey>", "wss://relay.musiquay.com", "photographer"],
    ["t", "electronic"],
    ["t", "dj"],
    ["price", "10", "EUR"],
    ["r", "https://tickets.example.com/event/123"]
  ]
}

D is required by NIP-52 on time-based events: floor(unix_seconds / 86400), repeated once per day the event covers. It is what makes date-window queries cheap without scanning start/end.

RSVP (kind 31925):

{
  "kind": 31925,
  "pubkey": "<attendee-pubkey>",
  "content": "",
  "tags": [
    ["a", "31923:<venue-pubkey>:<event-d-tag>", "wss://relay.musiquay.com"],
    ["d", "<unique-identifier>"],
    ["status", "accepted"],
    ["fb", "busy"]
  ]
}

Waitlist entry (kind 31925, tag convention):

{
  "kind": 31925,
  "pubkey": "<attendee-pubkey>",
  "content": "",
  "tags": [
    ["a", "31923:<venue-pubkey>:<event-d-tag>", "wss://relay.musiquay.com"],
    ["d", "<unique-identifier>"],
    ["status", "waitlist"],
    ["position", "14"],
    ["joined_at", "1735851600"]
  ]
}

Queue order is derived from joined_at (tie-broken by d tag); position is informational — clients recompute it from the full set of waitlist RSVPs.

Extended Events (Musiquay-Specific)

Where NIP-52 doesn't cover Musiquay's needs, custom event kinds or tag conventions extend it. Following the reuse-first NIP strategy:

ConceptApproach
Waitlist positionTag convention on NIP-52 RSVP (kind 31925) — status set to waitlist, plus position and joined_at tags. The RSVP's unique d tag and timestamp provide queue ordering.
Ticket purchaseCashu P2PK ticket or blind-signed ticket (open decision — see PROTOCOL_FLOWS.md); settled by Lightning or Cashu with the payment linked to the calendar event via a tag
Release countdownDate-based calendar event (kind 31922) with a custom tag indicating it's a release drop
Pre-sale accessTag convention on ticket events — filtered by follow lists or supporter status
Post-event contentStandard Nostr notes/media events that reference the calendar event via a or e tags
Event rosterFull participant record with scene police validation — see FEATURES_ROSTER.md
SetlistsPer-artist song lists linked to tracks, with featured artist tagging — see FEATURES_ROSTER.md

Integration with the Scene Graph

The calendar doesn't exist in isolation. It is deeply woven into the scene graph documented in ARCHITECTURE.md.

A show is not just a listing. It's a node in the scene graph connecting venues, artists, crew, fans, service companies, and the content they create together. Before the show, it's a calendar event. After the show, it's a piece of the scene's permanent history.

Discovery and Recommendations

The social calendar enables organic discovery that cold listings cannot:

No algorithm. No promoted listings. Just the social graph doing what social graphs do — connecting people to what their community cares about.

Payments

All financial transactions use the existing Lightning payment infrastructure:

Musiquay takes zero cut on ticket sales. The payment infrastructure is there to serve the scene, not to extract from it.