No description
Find a file
2026-01-08 11:16:33 +01:00
src Fix handle of undefined 2026-01-08 11:16:33 +01:00
static add badger icon and favicon 2026-01-06 15:11:20 +01:00
.clinerules some stuff is working 2025-10-31 22:21:53 +01:00
.dockerignore rework front page, add deployment 2026-01-06 15:00:06 +01:00
.env.example rework front page, add deployment 2026-01-06 15:00:06 +01:00
.gitignore some stuff is working 2025-10-31 22:21:53 +01:00
docker-compose.yml rework front page, add deployment 2026-01-06 15:00:06 +01:00
Dockerfile rework front page, add deployment 2026-01-06 15:00:06 +01:00
LICENSE Add license info 2026-01-07 16:15:52 +01:00
package-lock.json rework front page, add deployment 2026-01-06 15:00:06 +01:00
package.json rework front page, add deployment 2026-01-06 15:00:06 +01:00
README.md Add license info 2026-01-07 16:15:52 +01:00
svelte.config.js rework front page, add deployment 2026-01-06 15:00:06 +01:00
vite.config.js some stuff is working 2025-10-31 22:21:53 +01:00

🦡 Badger - Nostr Badge System

A decentralized badge management system built on the Nostr protocol, implementing NIP-58.

Features

  • Create Badges - Design and publish badge definitions (kind 30009)
  • Award Badges - Award badges to Nostr users (kind 8)
  • Accept Badges - Users can accept or reject badge awards (kind 30008)
  • View Gallery - Browse all badges on the network
  • NIP-07 Authentication - Secure login via browser extensions (Alby, nos2x, etc.)

Tech Stack

  • Svelte 5 - Modern reactive framework with runes
  • SvelteKit - Full-stack framework
  • Applesauce - Nostr event management and relay communication
  • Tailwind CSS + daisyUI - Beautiful, responsive UI
  • RxJS - Reactive data streams
  • Nostr Tools - Nostr protocol utilities

Prerequisites

  • Node.js 18+
  • A Nostr browser extension (Alby, nos2x, Nostore, etc.)

Installation

# Install dependencies
npm install

# Start development server
npm run dev

# Build for production
npm run build

# Preview production build
npm run preview

Deployment (Docker + Traefik)

Prerequisites

  • Docker and Docker Compose
  • Traefik reverse proxy with:
    • External network named traefik_web
    • Certificate resolver named myresolver

Setup

  1. Create environment file:
cp .env.example .env
  1. Configure .env:
NODE_ENV=production
PORT=3000
ORIGIN=https://badger.example.com
DOMAIN=badger.example.com
  1. Build and start:
docker compose up -d --build
  1. View logs:
docker compose logs -f badger

Environment Variables

Variable Required Default Description
NODE_ENV No production Node environment
PORT No 3000 Internal port
ORIGIN Yes - Full URL (e.g., https://badger.example.com)
DOMAIN Yes - Domain for Traefik routing

Usage

1. Authentication

Click "Login with Nostr" in the navigation bar. Your browser extension will prompt you to approve the connection.

2. Creating Badges

  1. Click "Create Badge" in the navigation
  2. Fill in the badge details:
    • Identifier: Unique ID (lowercase, no spaces)
    • Name: Display name for the badge
    • Description: What the badge represents
    • Image URL: Optional badge icon (hosted externally)
  3. Click "Create Badge" - your extension will prompt you to sign the event
  4. Badge will be published to relays and appear in the gallery

3. Viewing Badges

The main page displays:

  • All badges created on the network
  • Your awarded badges (if any)
  • Badge details (name, description, creator)

4. Badge Awards

When a badge creator awards you a badge (kind 8 event), you'll see it in your awards section.

5. Accepting Badges

Users can accept badges to display them publicly by publishing a kind 30008 event referencing the badge and award.

Architecture

Three-Layer Pattern (Applesauce)

┌─────────────────────────────────────────┐
│    Presentation (Svelte Components)    │
└─────────────────────────────────────────┘
                   ↓
┌─────────────────────────────────────────┐
│    Models (Data Transformation)        │
└─────────────────────────────────────────┘
                   ↓
┌─────────────────────────────────────────┐
│    Loaders (Relay Communication)       │
└─────────────────────────────────────────┘
                   ↓
┌─────────────────────────────────────────┐
│  Infrastructure (EventStore + Pool)    │
└─────────────────────────────────────────┘

Key Files

  • src/lib/stores/nostr-infrastructure.svelte.js - EventStore, RelayPool, loaders
  • src/lib/stores/auth.svelte.js - Authentication state
  • src/lib/models/ - Badge, Award, and Profile Badge models
  • src/routes/+page.svelte - Badge gallery
  • src/routes/create/+page.svelte - Badge creation form

NIP-58 Implementation

Badge Definition (kind 30009)

{
  kind: 30009,
  tags: [
    ['d', 'unique-identifier'],
    ['name', 'Badge Name'],
    ['description', 'Badge description'],
    ['image', 'https://example.com/badge.png', '1024x1024']
  ]
}

Badge Award (kind 8)

{
  kind: 8,
  tags: [
    ['a', '30009:creator_pubkey:badge_id'],
    ['p', 'recipient_pubkey']
  ]
}

Profile Badges (kind 30008)

{
  kind: 30008,
  tags: [
    ['d', 'profile_badges'],
    ['a', '30009:creator_pubkey:badge_id'],
    ['e', 'award_event_id']
  ]
}

Default Relays

  • wss://relay.damus.io
  • wss://nos.lol
  • wss://relay.snort.social

Development Notes

Critical Patterns

  1. Loader Bootstrap Order - Loaders must be connected to EventStore before using models
  2. Progressive Streaming - Use scan operator to prevent UI blocking
  3. Subscription Cleanup - Always unsubscribe in $effect cleanup functions
  4. Reactive State - Use Svelte 5 runes ($state, $derived, $effect)

Adding Features

To add new badge-related features:

  1. Create a model in src/lib/models/
  2. Use the model in components via eventStore.model()
  3. Subscribe to updates and clean up properly

License

Public Domain https://unlicense.org/