Files
c-relay/.roo/architect/AGENTS.md
2025-09-13 08:49:09 -04:00

12 KiB

AGENTS.md - AI Agent Integration Guide for Architect Mode

Project-Specific Information for AI Agents Working with C-Relay in Architect Mode

Critical Architecture Understanding

System Architecture Overview

C-Relay implements a unique event-based configuration architecture that fundamentally differs from traditional Nostr relays:

┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│   WebSocket     │    │  Configuration   │    │    Database     │
│   + HTTP        │◄──►│  Event System    │◄──►│   (SQLite)      │
│   (Port 8888)   │    │  (Kind 33334)    │    │  Schema v4      │
└─────────────────┘    └──────────────────┘    └─────────────────┘
         │                       │                       │
         ▼                       ▼                       ▼
┌─────────────────┐    ┌──────────────────┐    ┌─────────────────┐
│ nostr_core_lib  │    │   Admin Key      │    │ Event Storage   │
│ (Crypto/Sigs)   │    │   Management     │    │ + Subscriptions │
└─────────────────┘    └──────────────────┘    └─────────────────┘

Core Architectural Principles

1. Event-Driven Configuration

Design Philosophy: Configuration as cryptographically signed events rather than files

  • Benefits: Auditability, remote management, tamper-evidence
  • Trade-offs: Complexity in configuration changes, admin key management burden
  • Implementation: Kind 33334 events stored in same database as relay events

2. Identity-Based Database Naming

Design Philosophy: Database file named by relay's generated public key

  • Benefits: Prevents database conflicts, enables multi-relay deployments
  • Trade-offs: Cannot predict database filename, complicates backup strategies
  • Implementation: <relay_pubkey>.db created in build/ directory

3. Single-Binary Deployment

Design Philosophy: All functionality embedded in one executable

  • Benefits: Simple deployment, no external dependencies to manage
  • Trade-offs: Larger binary size, harder to modularize
  • Implementation: SQL schema embedded as header file, nostr_core_lib as submodule

4. Dual-Protocol Support

Design Philosophy: WebSocket (Nostr) and HTTP (NIP-11) on same port

  • Benefits: Simplified port management, reduced infrastructure complexity
  • Trade-offs: Protocol detection overhead, libwebsockets dependency
  • Implementation: Request routing based on HTTP headers and upgrade requests

Architectural Decision Analysis

Configuration System Design

Traditional Approach vs C-Relay:

Traditional:           C-Relay:
config.json     →     kind 33334 events
ENV variables   →     cryptographically signed tags
File watching   →     database polling/restart

Implications for Extensions:

  • Configuration changes require event signing capabilities
  • No hot-reloading without architectural changes
  • Admin key loss = complete database reset required

Database Architecture Decisions

Schema Design Philosophy:

  • Event Tags as JSON: Separate table with JSON column instead of normalized relations
  • Application-Level Filtering: NIP-40 expiration handled in C, not SQL
  • Embedded Schema: Version 4 schema compiled into binary

Scaling Considerations:

  • SQLite suitable for small-to-medium relays (< 10k concurrent connections)
  • Single-writer limitation of SQLite affects write-heavy workloads
  • JSON tag storage optimizes for read performance over write normalization

Memory Management Architecture

Thread Safety Model:

  • Global subscription manager with mutex protection
  • Per-client subscription limits enforced in memory
  • WebSocket connection state managed by libwebsockets

Resource Management:

  • JSON objects use reference counting (jansson library)
  • String duplication pattern for configuration values
  • Automatic cleanup on client disconnect

Architectural Extension Points

Adding New Configuration Options

Required Changes:

  1. Update default_config_event.h template
  2. Add parsing logic in config.c load_config_from_database()
  3. Add global config struct field in config.h
  4. Update documentation in docs/configuration_guide.md

Adding New NIP Support

Integration Pattern:

  1. Event validation in request_validator.c
  2. Protocol handling in main.c WebSocket callback
  3. Database storage considerations in schema
  4. Add test in tests/ directory

Scaling Architecture

Current Limitations:

  • Single process, no horizontal scaling
  • SQLite single-writer bottleneck
  • Memory-based subscription management

Potential Extensions:

  • Redis for subscription state sharing
  • PostgreSQL for better concurrent write performance
  • Load balancer for read scaling with multiple instances

Deployment Architecture Patterns

Development Deployment

Developer Machine:
├── ./make_and_restart_relay.sh
├── build/c_relay_x86
├── build/<relay_pubkey>.db
└── relay.log

Production SystemD Deployment

/opt/c-relay/:
├── c_relay_x86
├── <relay_pubkey>.db
├── systemd service (c-relay.service)
└── c-relay user isolation

Container Deployment Architecture

Container:
├── Multi-stage build (deps + binary)
├── Volume mount for database persistence
├── Health checks via NIP-11 endpoint
└── Signal handling for graceful shutdown

Reverse Proxy Architecture

Internet → Nginx/HAProxy → C-Relay
                       ├── WebSocket upgrade handling
                       ├── SSL termination
                       └── Rate limiting

Security Architecture Considerations

Key Management Design

Admin Key Security Model:

  • Generated once, displayed once, never stored
  • Required for all configuration changes
  • Loss requires complete database reset

Relay Identity Model:

  • Separate keypair for relay identity
  • Public key used for database naming
  • Private key never exposed to clients

Event Validation Pipeline

WebSocket Input → JSON Parse → Schema Validate → Signature Verify → Store
                             ↓                 ↓                  ↓
                    reject    reject          reject           success

Attack Surface Analysis

Network Attack Vectors:

  • WebSocket connection flooding (mitigated by libwebsockets limits)
  • JSON parsing attacks (handled by jansson library bounds checking)
  • SQLite injection (prevented by prepared statements)

Configuration Attack Vectors:

  • Admin key compromise (complete relay control)
  • Event signature forgery (prevented by nostr_core_lib validation)
  • Replay attacks (event timestamp validation required)

Non-Obvious Architectural Considerations

Database Evolution Strategy

Current Limitations:

  • Schema changes require database recreation
  • No migration system for configuration events
  • Version 4 schema embedded in binary

Future Architecture Needs:

  • Schema versioning and migration system
  • Backward compatibility for configuration events
  • Database backup/restore procedures

Configuration Event Lifecycle

Event Flow:

Admin Signs Event → WebSocket Submit → Validate → Store → Restart Required
                                    ↓            ↓         ↓
                              Signature Check   Database  Config Reload

Architectural Implications:

  • No hot configuration reloading
  • Configuration changes require planned downtime
  • Event ordering matters for multiple simultaneous changes

Cross-Architecture Deployment

Build System Architecture:

  • Auto-detection of host architecture
  • Cross-compilation support for ARM64
  • Architecture-specific binary outputs

Deployment Implications:

  • Binary must match target architecture
  • Dependencies must be available for target architecture
  • Debug tooling architecture-specific

Performance Architecture Characteristics

Bottlenecks:

  1. SQLite Write Performance: Single writer limitation
  2. JSON Parsing: Per-event parsing overhead
  3. Signature Validation: Cryptographic operations per event
  4. Memory Management: JSON object lifecycle management

Optimization Points:

  • Prepared statement reuse
  • Connection pooling for concurrent reads
  • Event batching for bulk operations
  • Subscription indexing strategies

Integration Architecture Patterns

Monitoring Integration:

  • NIP-11 endpoint for health checks
  • Log file monitoring for operational metrics
  • Database query monitoring for performance
  • Process monitoring for resource usage

Backup Architecture:

  • Database file backup (SQLite file copy)
  • Configuration event export/import
  • Admin key secure storage (external to relay)

Future Extension Architectures

Multi-Relay Coordination:

  • Database sharding by event kind
  • Cross-relay event synchronization
  • Distributed configuration management

Plugin Architecture Possibilities:

  • Event processing pipeline hooks
  • Custom validation plugins
  • External authentication providers

Scaling Architecture Options:

  • Read replicas with PostgreSQL migration
  • Event stream processing with message queues
  • Microservice decomposition (auth, storage, validation)

Architectural Anti-Patterns to Avoid

  1. Configuration File Addition: Breaks event-based config paradigm
  2. Direct Database Modification: Bypasses signature validation
  3. Hard-Coded Ports: Conflicts with auto-fallback system
  4. Schema Modifications: Requires database recreation
  5. Admin Key Storage: Violates security model
  6. Blocking Operations: Interferes with WebSocket event loop
  7. Memory Leaks: JSON objects must be properly reference counted
  8. Thread Unsafe Operations: Global state requires proper synchronization

Architecture Decision Records (Implicit)

Decision: Event-Based Configuration

Context: Traditional config files vs. cryptographic auditability Decision: Store configuration as signed Nostr events Consequences: Complex configuration changes, enhanced security, remote management capability

Decision: SQLite Database

Context: Database choice for relay storage Decision: Embedded SQLite with JSON tag storage Consequences: Simple deployment, single-writer limitation, application-level filtering

Decision: Single Binary Deployment

Context: Dependency management vs. deployment simplicity Decision: Embed all dependencies and schema in binary Consequences: Larger binary, simple deployment, version coupling

Decision: Dual Protocol Support

Context: WebSocket for Nostr, HTTP for NIP-11 Decision: Same port serves both protocols Consequences: Simplified deployment, protocol detection overhead, libwebsockets dependency

These architectural decisions form the foundation of C-Relay's unique approach to Nostr relay implementation and should be carefully considered when planning extensions or modifications. **

[Response interrupted by a tool use result. Only one tool may be used at a time and should be placed at the end of the message.]