298 lines
12 KiB
Markdown
298 lines
12 KiB
Markdown
|
|
# 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`](src/default_config_event.h) template
|
|
2. Add parsing logic in [`config.c`](src/config.c) `load_config_from_database()`
|
|
3. Add global config struct field in [`config.h`](src/config.h)
|
|
4. Update documentation in [`docs/configuration_guide.md`](docs/configuration_guide.md)
|
|
|
|
### Adding New NIP Support
|
|
**Integration Pattern:**
|
|
1. Event validation in [`request_validator.c`](src/request_validator.c)
|
|
2. Protocol handling in [`main.c`](src/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.] |