A decentralized event management and credentialing system built on atproto.
Rust 82.1%
HTML 17.6%
Dockerfile 0.3%
6 1 0

Clone this repository

https://tangled.org/smokesignal.events/acudo
git@tangled.org:smokesignal.events/acudo

For self-hosted knots, clone URLs may differ based on your setup.

README.md

Acudo#

A decentralized event management and credentialing system built on the AT Protocol, combining traditional ticketing infrastructure with cryptographically-verifiable badges and RSVPs. Acudo bridges Web 2.0 ticketing platforms like Tito with the emerging decentralized social web, enabling event organizers to issue portable, verifiable credentials to attendees.

Overview#

Acudo represents a novel approach to event management in the decentralized web era. By leveraging the AT Protocol (the foundation of Bluesky), it transforms traditional event RSVPs and tickets into cryptographically-signed records that attendees own and control. These records live in the attendee's personal data server (PDS), making them portable across applications and verifiable by third parties.

Key Innovations#

  • Decentralized Credentials: Event attendance becomes a verifiable credential that attendees can showcase across AT Protocol-compatible applications
  • Badge Award System: Sophisticated rule engine that automatically awards badges based on ticket purchases, enabling gamification and special recognition
  • Cryptographic Trust: All records are signed by event organizers, providing cryptographic proof of authenticity
  • Identity Resolution: Advanced caching layer for DID document resolution, optimizing performance while maintaining decentralized principles
  • Hybrid Architecture: Seamlessly integrates traditional ticketing (Tito) with decentralized identity and storage

Technical Architecture#

Core Technologies#

  • Rust & Axum: High-performance async web framework providing sub-millisecond response times
  • AT Protocol SDK: Full integration with atproto-* crates for identity, OAuth, and record management
  • PostgreSQL: JSONB-powered storage with GIN indexing for efficient querying of AT Protocol records
  • Minijinja Templates: Server-side rendering with Jinja2-compatible templating
  • Identity Caching: LRU cache with configurable TTL for DID document resolution

AT Protocol Integration#

Acudo deeply integrates with the AT Protocol ecosystem:

  1. OAuth Flows: Supports both PDS OAuth and AT Protocol Improvement Proposal (AIP) OAuth backends
  2. DID Resolution: Resolves decentralized identifiers through PLC and Web DID methods
  3. Record Creation: Creates lexicon-compliant records with proper signatures
  4. Jetstream Consumer: Real-time event processing from the AT Protocol firehose
  5. Cryptographic Verification: All records are verified using atproto_record::signature

Data Flow#

User → OAuth Login → Ticket Purchase (Tito) → Rule Evaluation → 
Record Creation → Signature → AT Protocol PDS → User's Repository

The system maintains local copies for performance while ensuring the user's PDS remains the source of truth.

Badge Award System#

The badge system uses a JSON Logic-based rule engine (powered by datalogic-rs) to evaluate ticket purchases and determine which AT Protocol records (RSVPs and badge awards) should be created:

Rule Structure#

{
  "aturis": [
    "at://did:plc:cbkjy5n7bk3ax2wplmtjofq2/community.lexicon.calendar.event/3luzkrwivzm2a",
    "at://did:web:oauth-masterclass.atproto.camp/community.lexicon.calendar.event/3lwtxdryiw22b"
  ],
  "create": {
    "and": [
      {
        "==": [
          "Oct 4 Individual Seat (Early Bird)",
          {
            "val": "ticket_type"
          }
        ]
      },
      {
        "<": [
          {
            "val": "purchase_at"
          },
          "2025-08-25T00:00:00Z"
        ]
      }
    ]
  },
  "signature_extra": {}
}

Rules can evaluate:

  • Ticket type and pricing tiers
  • Purchase timing (early bird, last minute)
  • Custom metadata from ticketing platforms
  • Complex logical combinations (AND, OR, NOT)

The aturis field specifies which AT Protocol records to create when the rule evaluates to true:

  • Event RSVPs: at://did:plc:*/community.lexicon.calendar.event/*
  • Badge awards: at://did:plc:*/community.lexicon.badge.award/*

Security Model#

All badges and RSVPs are cryptographically signed by the event organizer's private key. The verification process:

  1. Records are generated server-side with issuer signatures
  2. Client receives pre-signed records for review
  3. User selects which records to create
  4. Server verifies signatures before submission
  5. Records are written to user's PDS repository

This ensures that badges cannot be forged and provides cryptographic proof of the issuer's authorization.

Getting Started#

Prerequisites#

  • Rust 1.89+ (2024 edition)
  • PostgreSQL 15+
  • AT Protocol PDS or OAuth server access
  • Environment variables configured (see Configuration section)

Installation#

  1. Clone the repository
  2. Set up PostgreSQL database
  3. Configure environment variables (see Configuration)
  4. Run database migrations: sqlx migrate run
  5. Build and run: cargo run --release

Configuration#

Core Configuration#

# AT Protocol Configuration
EXTERNAL_BASE=your-event.example.com
ISSUER_DID=did:plc:abc123def456
ISSUER_PRIVATE_KEY=did:key:z6Mk...
EVENT_ATURIS=main=at://did:plc:abc/event.calendar/record-key

# Database
DATABASE_URL=postgres://user:pass@localhost/acudo

# OAuth Backend Selection
OAUTH_BACKEND=pds  # or "aip" for AT Protocol Improvement Proposal OAuth

Performance Tuning#

# Identity Cache Configuration
IDENTITY_CACHE_SIZE=500           # Max cached DID documents
IDENTITY_CACHE_TTL_MINUTES=10     # Cache TTL

OAuth Backend Configuration#

PDS OAuth#

SIGNING_KEYS=did:key:z6Mk...;did:key:z6Mk...  # Semicolon-separated
PLC_HOSTNAME=plc.directory

AIP OAuth#

AIP_SERVER=https://auth.example.com
AIP_CLIENT_ID=your_client_id
AIP_CLIENT_SECRET=your_client_secret

Admin Configuration#

# Admin Access (semicolon-separated DIDs)
ADMIN_DIDS=did:plc:admin1;did:plc:admin2

# Tito Integration
TITO_WEBHOOK_SECRET=webhook_secret_from_tito

Admin Interface#

Acudo includes a comprehensive admin interface for event organizers:

Features#

  • Badge Rule Management: Create and manage JSON Logic rules for automatic badge awards
  • Event Management: Import and manage events with JSON field search
  • Data Viewing: Browse DID documents, RSVPs, tickets with pagination
  • Real-time Monitoring: View system activity and badge award statistics

Access Control#

Admin access is controlled via DID-based authentication. Only DIDs listed in ADMIN_DIDS environment variable can access admin features. The system returns 404 for unauthorized users to prevent discovery of admin endpoints.

API Endpoints#

Public Endpoints#

  • GET / - Event homepage with activity feed
  • GET /tickets - Ticket management interface (requires auth)
  • POST /records/create - Batch record creation with signature verification
  • GET /auth/login - OAuth login initiation
  • GET /auth/callback - OAuth callback handler
  • POST /api/webhooks/tito - Tito webhook receiver

Well-Known Endpoints#

  • GET /.well-known/did.json - did:web resolution
  • GET /.well-known/atproto-did - AT Protocol DID resolution
  • GET /oauth/client-metadata.json - OAuth client metadata
  • GET /.well-known/jwks.json - JSON Web Key Set

Storage Architecture#

Storage Layers#

  1. Identity Storage: DID documents with pagination support
  2. OAuth Storage: Request tokens with automatic expiration
  3. Event Storage: AT Protocol event records with JSON search
  4. Ticket Storage: Integration with external ticketing systems
  5. Badge Storage: Award records and rule definitions
  6. RSVP Storage: Signed attendance records

Performance Optimizations#

  • Connection Pooling: Configurable pool sizes for database connections
  • Identity Caching: LRU cache reduces DID resolution latency by 90%
  • JSON Indexing: GIN indexes on JSONB columns for sub-millisecond queries
  • Batch Operations: Bulk record creation reduces round trips
  • Async Everything: Tokio-based async runtime for high concurrency

Development#

Testing#

The codebase includes comprehensive test coverage using SQLx's test framework:

# Run all tests
cargo test

# Run specific test suites
cargo test storage::event        # Event storage tests
cargo test identity_cache        # Identity cache tests
cargo test badges                # Badge rule engine tests

# Run with test output
cargo test -- --nocapture

Code Quality#

# Format code
cargo fmt

# Lint with clippy
cargo clippy -- -D warnings

# Check for security vulnerabilities
cargo audit

Error Handling#

Acudo uses a structured error format for debugging:

error-acudo-<domain>-<number> <message>: <details>

Examples:

  • error-acudo-resolve-1: DID resolution failures
  • error-acudo-oauth-1: OAuth flow errors
  • error-acudo-signature-1: Signature verification failures

Future Directions#

Planned Features#

  • Federated Events: Cross-instance event discovery and aggregation
  • Portable Tickets: Transfer tickets between AT Protocol identities
  • Verifiable Attendance: Zero-knowledge proofs for privacy-preserving attendance verification
  • Badge Marketplace: Trade and showcase rare event badges
  • Analytics Dashboard: Event organizer insights with privacy preservation

Protocol Evolution#

Acudo is designed to evolve with the AT Protocol ecosystem:

  1. Lexicon Evolution: New record types for richer event experiences
  2. DID Methods: Support for emerging DID methods beyond PLC and Web
  3. Federation: Multi-instance event networks with shared badge recognition
  4. Interoperability: Bridge to other decentralized identity systems

Contributing#

We welcome contributions from the community! Areas of particular interest:

  1. Badge Rule Templates: Share interesting rule patterns for badge awards
  2. OAuth Providers: Add support for additional OAuth backends
  3. Performance: Optimization of hot paths and database queries
  4. Accessibility: Improve screen reader support and keyboard navigation
  5. Internationalization: Add support for multiple languages

Development Setup#

  1. Fork the repository
  2. Set up local PostgreSQL with the test database
  3. Configure .env file with test credentials
  4. Run cargo test to verify setup
  5. Create feature branch and make changes
  6. Ensure all tests pass and code is formatted
  7. Submit pull request with clear description

For detailed architecture documentation and development guidelines, see CLAUDE.md.

License#

MIT License - see LICENSE file for details.