Replaced inline interface literals with dedicated, documented interface definitions in `pkg/interfaces/`. Introduced `TimeoutError`, `PolicyChecker`, and `Neo4jResultIterator` interfaces to clarify design, improve maintainability, and resolve potential circular dependencies. Updated config and constant usage rules for consistency. Incremented version to v0.31.11.
28 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
ORLY is a high-performance Nostr relay written in Go, designed for personal relays, small communities, and business deployments. It emphasizes low latency, custom cryptography optimizations, and embedded database performance.
Key Technologies:
- Language: Go 1.25.3+
- Database: Badger v4 (embedded), DGraph (distributed graph), or Neo4j (social graph)
- Cryptography: Custom p8k library using purego for secp256k1 operations (no CGO)
- Web UI: Svelte frontend embedded in the binary
- WebSocket: gorilla/websocket for Nostr protocol
- Performance: SIMD-accelerated SHA256 and hex encoding, query result caching with zstd compression
- Social Graph: Neo4j backend with Web of Trust (WoT) extensions for trust metrics
Build Commands
Basic Build
# Build relay binary only
go build -o orly
# Pure Go build (no CGO) - this is the standard approach
CGO_ENABLED=0 go build -o orly
Build with Web UI
# Recommended: Use the provided script
./scripts/update-embedded-web.sh
# Manual build
cd app/web
bun install
bun run build
cd ../../
go build -o orly
Development Mode (Web UI Hot Reload)
# Terminal 1: Start relay with dev proxy
export ORLY_WEB_DISABLE=true
export ORLY_WEB_DEV_PROXY_URL=http://localhost:5173
./orly &
# Terminal 2: Start dev server
cd app/web && bun run dev
Testing
Run All Tests
# Standard test run
./scripts/test.sh
# Or manually with purego setup
CGO_ENABLED=0 go test ./...
# Note: libsecp256k1.so is included in the repository root
# Set LD_LIBRARY_PATH to use it: export LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$(pwd)"
Run Specific Package Tests
# Test database package
cd pkg/database && go test -v ./...
# Test protocol package
cd pkg/protocol && go test -v ./...
# Test with specific test function
go test -v -run TestSaveEvent ./pkg/database
Relay Protocol Testing
# Test relay protocol compliance
go run cmd/relay-tester/main.go -url ws://localhost:3334
# List available tests
go run cmd/relay-tester/main.go -list
# Run specific test
go run cmd/relay-tester/main.go -url ws://localhost:3334 -test "Basic Event"
Benchmarking
# Run Go benchmarks in specific package
go test -bench=. -benchmem ./pkg/database
# Note: Crypto benchmarks are now in the external nostr library at:
# https://git.mleku.dev/mleku/nostr
# Run full relay benchmark suite
cd cmd/benchmark
go run main.go -data-dir /tmp/bench-db -events 10000 -workers 4
# Benchmark reports are saved to cmd/benchmark/reports/
# The benchmark tool tests event storage, queries, and subscription performance
Running the Relay
Basic Run
# Build and run
go build -o orly && ./orly
# With environment variables
export ORLY_LOG_LEVEL=debug
export ORLY_PORT=3334
./orly
Get Relay Identity
# Print relay identity secret and pubkey
./orly identity
Common Configuration
# TLS with Let's Encrypt
export ORLY_TLS_DOMAINS=relay.example.com
# Admin configuration
export ORLY_ADMINS=npub1...
# Follows ACL mode
export ORLY_ACL_MODE=follows
# Enable sprocket event processing
export ORLY_SPROCKET_ENABLED=true
# Enable policy system
export ORLY_POLICY_ENABLED=true
# Database backend selection (badger, dgraph, or neo4j)
export ORLY_DB_TYPE=badger
# DGraph configuration (only when ORLY_DB_TYPE=dgraph)
export ORLY_DGRAPH_URL=localhost:9080
# Neo4j configuration (only when ORLY_DB_TYPE=neo4j)
export ORLY_NEO4J_URI=bolt://localhost:7687
export ORLY_NEO4J_USER=neo4j
export ORLY_NEO4J_PASSWORD=password
# Query cache configuration (improves REQ response times)
export ORLY_QUERY_CACHE_SIZE_MB=512 # Default: 512MB
export ORLY_QUERY_CACHE_MAX_AGE=5m # Cache expiry time
# Database cache tuning (for Badger backend)
export ORLY_DB_BLOCK_CACHE_MB=512 # Block cache size
export ORLY_DB_INDEX_CACHE_MB=256 # Index cache size
export ORLY_INLINE_EVENT_THRESHOLD=1024 # Inline storage threshold (bytes)
# Directory Spider (metadata sync from other relays)
export ORLY_DIRECTORY_SPIDER=true # Enable directory spider
export ORLY_DIRECTORY_SPIDER_INTERVAL=24h # How often to run
export ORLY_DIRECTORY_SPIDER_HOPS=3 # Max hops for relay discovery
# NIP-43 Relay Access Metadata
export ORLY_NIP43_ENABLED=true # Enable invite system
export ORLY_NIP43_INVITE_EXPIRY=24h # Invite code validity
# Authentication modes
export ORLY_AUTH_REQUIRED=false # Require auth for all requests
export ORLY_AUTH_TO_WRITE=false # Require auth only for writes
Code Architecture
Repository Structure
Root Entry Point:
main.go- Application entry point with signal handling, profiling setup, and database initializationapp/main.go- Core relay server initialization and lifecycle management
Core Packages:
app/ - HTTP/WebSocket server and handlers
server.go- Main Server struct and HTTP request routinghandle-*.go- Nostr protocol message handlers (EVENT, REQ, COUNT, CLOSE, AUTH, DELETE)handle-policy-config.go- Kind 12345 policy updates and kind 3 admin follow list handlinghandle-websocket.go- WebSocket connection lifecycle and frame handlinglistener.go- Network listener setupsprocket.go- External event processing script managerpublisher.go- Event broadcast to active subscriptionspayment_processor.go- NWC integration for subscription paymentsblossom.go- Blob storage service initializationweb.go- Embedded web UI serving and dev proxyconfig/- Environment variable configuration using go-simpler.org/env
pkg/database/ - Database abstraction layer with multiple backend support
interface.go- Database interface definition for pluggable backendsfactory.go- Database backend selection (Badger, DGraph, or Neo4j)database.go- Badger implementation with cache tuning and query cachesave-event.go- Event storage with index updatesquery-events.go- Main query execution engine with filter normalizationquery-for-*.go- Specialized query builders for different filter patternsindexes/- Index key construction for efficient lookupsexport.go/import.go- Event export/import in JSONL formatsubscriptions.go- Active subscription trackingidentity.go- Relay identity key managementmigrations.go- Database schema migration runner
pkg/neo4j/ - Neo4j graph database backend with social graph support
neo4j.go- Main database implementationschema.go- Graph schema and index definitions (includes WoT extensions)query-events.go- REQ filter to Cypher translationsave-event.go- Event storage with relationship creationsocial-event-processor.go- Processes kinds 0, 3, 1984, 10000 for social graphWOT_SPEC.md- Web of Trust data model specification (NostrUser nodes, trust metrics)MODIFYING_SCHEMA.md- Guide for schema modifications
pkg/protocol/ - Nostr protocol implementation
ws/- WebSocket message framing and parsingauth/- NIP-42 authentication challenge/responsepublish/- Event publisher for broadcasting to subscriptionsrelayinfo/- NIP-11 relay information documentdirectory/- Distributed directory service (NIP-XX)nwc/- Nostr Wallet Connect clientblossom/- Blob storage protocol
pkg/encoders/ - Optimized Nostr data encoding/decoding
event/- Event JSON marshaling/unmarshaling with buffer poolingfilter/- Filter parsing and validationbech32encoding/- npub/nsec/note encodinghex/- SIMD-accelerated hex encoding using templexxx/xhextimestamp/,kind/,tag/- Specialized field encoders
Cryptographic operations (from git.mleku.dev/mleku/nostr library)
- Pure Go secp256k1 using purego (no CGO) to dynamically load libsecp256k1.so
- Schnorr signature operations (NIP-01)
- ECDH for encrypted DMs (NIP-04, NIP-44)
- Public key recovery from signatures
libsecp256k1.so- Included in repository root for runtime loading
- Key derivation and conversion utilities
- SIMD-accelerated SHA256 using minio/sha256-simd
- SIMD-accelerated hex encoding using templexxx/xhex
pkg/acl/ - Access control systems
acl.go- ACL registry and interfacefollows.go- Follows-based whitelist (admins + their follows can write)managed.go- NIP-86 managed relay with role-based permissionsnone.go- Open relay (no restrictions)
pkg/policy/ - Event filtering and validation policies
- Policy configuration loaded from
~/.config/ORLY/policy.json - Per-kind size limits, age restrictions, custom scripts
- Write-Only Validation: Size, age, tag, and expiry validations apply ONLY to write operations
- Read-Only Filtering:
read_allow,read_deny,privilegedapply ONLY to read operations - See
docs/POLICY_CONFIGURATION_REFERENCE.mdfor authoritative read vs write applicability - Dynamic Policy Hot Reload via Kind 12345 Events:
- Policy admins can update policy configuration without relay restart
- Kind 12345 events contain JSON policy in content field
- Validation-first approach: JSON validated before pausing message processing
- Message processing uses RWMutex: RLock for normal ops, Lock for policy updates
- Policy admin follow lists (kind 3) trigger immediate cache refresh
WriteAllowFollowsrule grants both read+write access to admin follows- Tag validation supports regex patterns per tag type
- Policy Rule Fields:
max_expiry_duration: ISO-8601 duration format (e.g., "P7D", "PT1H30M") for event expiry limitsprotected_required: Requires NIP-70 protected events (must have "-" tag)identifier_regex: Regex pattern for validating "d" tag identifiersfollows_whitelist_admins: Per-rule admin pubkeys whose follows are whitelistedwrite_allow/write_deny: Pubkey whitelist/blacklist for writing (write-only)read_allow/read_deny: Pubkey whitelist/blacklist for reading (read-only)privileged: Party-involved access control (read-only)
- See
docs/POLICY_USAGE_GUIDE.mdfor configuration examples - See
pkg/policy/README.mdfor quick reference
pkg/sync/ - Distributed synchronization
cluster_manager.go- Active replication between relay peersrelay_group_manager.go- Relay group configuration (NIP-XX)manager.go- Distributed directory consensus
pkg/spider/ - Event syncing from other relays
spider.go- Spider manager for "follows" mode- Fetches events from admin relays for followed pubkeys
- Directory Spider (
directory.go):- Discovers relays by crawling kind 10002 (relay list) events
- Expands outward from seed pubkeys (whitelisted users) via hop distance
- Fetches metadata events (kinds 0, 3, 10000, 10002) from discovered relays
- Self-detection prevents querying own relay
- Configurable interval and max hops via
ORLY_DIRECTORY_SPIDER_*env vars
pkg/utils/ - Shared utilities
atomic/- Extended atomic operationsinterrupt/- Signal handling and graceful shutdownapputil/- Application-level utilities
Web UI (app/web/):
- Svelte-based admin interface
- Embedded in binary via
go:embed - Features: event browser, sprocket management, policy management, user admin, settings
- Policy Management Tab: JSON editor with validation, save publishes kind 12345 event
Command-line Tools (cmd/):
relay-tester/- Nostr protocol compliance testingbenchmark/- Multi-relay performance comparisonstresstest/- Load testing toolaggregator/- Event aggregation utilityconvert/- Data format conversionpolicytest/- Policy validation testing
Important Patterns
Pure Go with Purego:
- All builds use
CGO_ENABLED=0 - The p8k crypto library (from
git.mleku.dev/mleku/nostr) usesgithub.com/ebitengine/puregoto dynamically loadlibsecp256k1.soat runtime - This avoids CGO complexity while maintaining C library performance
libsecp256k1.sois included in the repository root- Library must be in
LD_LIBRARY_PATHor same directory as binary for runtime loading
Database Backend Selection:
- Supports multiple backends via
ORLY_DB_TYPEenvironment variable - Badger (default): Embedded key-value store with custom indexing, ideal for single-instance deployments
- DGraph: Distributed graph database for larger, multi-node deployments
- Neo4j: Graph database with social graph and Web of Trust (WoT) extensions
- Processes kinds 0 (profile), 3 (contacts), 1984 (reports), 10000 (mute list) for social graph
- NostrUser nodes with trust metrics (influence, PageRank)
- FOLLOWS, MUTES, REPORTS relationships for WoT analysis
- See
pkg/neo4j/WOT_SPEC.mdfor full schema specification
- Backend selected via factory pattern in
pkg/database/factory.go - All backends implement the same
Databaseinterface defined inpkg/database/interface.go
Database Query Pattern:
- Filters are analyzed in
get-indexes-from-filter.goto determine optimal query strategy - Filters are normalized before cache lookup, ensuring identical queries with different field ordering hit the cache
- Different query builders (
query-for-kinds.go,query-for-authors.go, etc.) handle specific filter patterns - All queries return event serials (uint64) for efficient joining
- Query results cached with zstd level 9 compression (configurable size and TTL)
- Final events fetched via
fetch-events-by-serials.go
WebSocket Message Flow:
handle-websocket.goaccepts connection and spawns goroutine- Incoming frames parsed by
pkg/protocol/ws/ - Routed to handlers:
handle-event.go,handle-req.go,handle-count.go, etc. - Events stored via
database.SaveEvent() - Active subscriptions notified via
publishers.Publish()
Configuration System - CRITICAL RULES:
- Uses
go-simpler.org/envfor struct tags - ALL environment variables MUST be defined in
app/config/config.go- NEVER use
os.Getenv()directly in packages - always pass config via structs - NEVER parse environment variables outside of
app/config/ - This ensures all config options appear in
./orly helpoutput - Database backends receive config via
database.DatabaseConfigstruct - Use
GetDatabaseConfigValues()helper to extract DB config from app config
- NEVER use
- All config fields use
ORLY_prefix with struct tags defining defaults and usage - Supports XDG directories via
github.com/adrg/xdg - Default data directory:
~/.local/share/ORLY - Database-specific config (Neo4j, DGraph, Badger) is passed via
DatabaseConfigstruct inpkg/database/factory.go
Constants - CRITICAL RULES:
- ALWAYS define named constants for values used more than a few times
- ALWAYS define named constants if multiple packages depend on the same value
- Constants shared across packages should be in a dedicated package (e.g.,
pkg/constants/) - Magic numbers and strings are forbidden - use named constants with clear documentation
- Example:
// BAD - magic number if timeout > 30 { // GOOD - named constant const DefaultTimeoutSeconds = 30 if timeout > DefaultTimeoutSeconds {
Event Publishing:
pkg/protocol/publish/manages publisher registry- Each WebSocket connection registers its subscriptions
publishers.Publish(event)broadcasts to matching subscribers- Efficient filter matching without re-querying database
Embedded Assets:
- Web UI built to
app/web/dist/ - Embedded via
//go:embeddirective inapp/web.go - Served at root path
/with API at/api/*
Domain Boundaries & Encapsulation:
- Library packages (e.g.,
pkg/policy) should NOT export internal state variables - Use unexported fields (lowercase) for internal state to enforce encapsulation at compile time
- Provide public API methods (e.g.,
IsEnabled(),CheckPolicy()) instead of exposing internals - When JSON unmarshalling is needed for unexported fields, use a shadow struct with custom
UnmarshalJSON - External packages (e.g.,
app/) should ONLY use public API methods, never access internal fields - DO NOT change unexported fields to exported when fixing bugs - this breaks the domain boundary
Binary-Optimized Tag Storage (IMPORTANT):
- The nostr library (
git.mleku.dev/mleku/nostr/encoders/tag) uses binary optimization foreandptags - When events are unmarshaled from JSON, 64-character hex values in e/p tags are converted to 33-byte binary format (32 bytes hash + null terminator)
- DO NOT use
tag.Value()directly for e/p tags - it returns raw bytes which may be binary, not hex - ALWAYS use these methods instead:
tag.ValueHex()- Returns hex string regardless of storage format (handles both binary and hex)tag.ValueBinary()- Returns 32-byte binary if stored in binary format, nil otherwise
- Example pattern for comparing pubkeys:
// CORRECT: Use ValueHex() for hex decoding pt, err := hex.Dec(string(pTag.ValueHex())) // WRONG: Value() may return binary bytes, not hex pt, err := hex.Dec(string(pTag.Value())) // Will fail for binary-encoded tags! - This optimization saves memory and enables faster comparisons in the database layer
Interface Design - CRITICAL RULES:
Rule 1: ALL interfaces MUST be defined in pkg/interfaces/<name>/
- Interfaces provide isolation between packages and enable dependency inversion
- Keeping interfaces in a dedicated package prevents circular dependencies
- Each interface package should be minimal (just the interface, no implementations)
Rule 2: NEVER use type assertions with interface literals
- NEVER write
.(interface{ Method() Type })- this is non-idiomatic and unmaintainable - Interface literals cannot be documented, tested for satisfaction, or reused
- Example of WRONG approach:
// BAD - interface literal in type assertion if checker, ok := obj.(interface{ Check() bool }); ok { checker.Check() } - Example of CORRECT approach:
// GOOD - use defined interface from pkg/interfaces/ import "next.orly.dev/pkg/interfaces/checker" if c, ok := obj.(checker.Checker); ok { c.Check() }
Rule 3: Resolving Circular Dependencies
- If a circular dependency occurs when adding an interface, move the interface to
pkg/interfaces/ - The implementing type stays in its original package
- The consuming code imports only the interface package
- This pattern:
pkg/interfaces/foo/ <- interface definition (no dependencies) ↑ ↑ pkg/bar/ pkg/baz/ (implements) (consumes via interface)
Existing interfaces in pkg/interfaces/:
acl/- ACL and PolicyChecker interfacesneterr/- TimeoutError interface for network errorsresultiter/- Neo4jResultIterator for database resultsstore/- Storage-related interfacespublisher/- Event publishing interfacestyper/- Type identification interface
Development Workflow
Making Changes to Web UI
- Edit files in
app/web/src/ - For hot reload:
cd app/web && bun run dev(withORLY_WEB_DISABLE=trueandORLY_WEB_DEV_PROXY_URL=http://localhost:5173) - For production build:
./scripts/update-embedded-web.sh
Adding New Nostr Protocol Handlers
- Create
app/handle-<message-type>.go - Add case in
app/handle-message.gomessage router - Implement handler following existing patterns
- Add tests in
app/<handler>_test.go
Adding Database Indexes
- Define index in
pkg/database/indexes/ - Add migration in
pkg/database/migrations.go - Update
save-event.goto populate index - Add query builder in
pkg/database/query-for-<index>.go - Update
get-indexes-from-filter.goto use new index
Environment Variables for Development
# Verbose logging
export ORLY_LOG_LEVEL=trace
export ORLY_DB_LOG_LEVEL=debug
# Enable profiling
export ORLY_PPROF=cpu
export ORLY_PPROF_HTTP=true # Serves on :6060
# Health check endpoint
export ORLY_HEALTH_PORT=8080
Profiling
# CPU profiling
export ORLY_PPROF=cpu
./orly
# Profile written on shutdown
# HTTP pprof server
export ORLY_PPROF_HTTP=true
./orly
# Visit http://localhost:6060/debug/pprof/
# Memory profiling
export ORLY_PPROF=memory
export ORLY_PPROF_PATH=/tmp/profiles
Deployment
Automated Deployment
# Deploy with systemd service
./scripts/deploy.sh
This script:
- Installs Go 1.25.3 if needed
- Builds relay with embedded web UI
- Installs to
~/.local/bin/orly - Creates systemd service
- Sets capabilities for port 443 binding
systemd Service Management
# Start/stop/restart
sudo systemctl start orly
sudo systemctl stop orly
sudo systemctl restart orly
# Enable on boot
sudo systemctl enable orly
# View logs
sudo journalctl -u orly -f
Manual Deployment
# Build for production
./scripts/update-embedded-web.sh
# Or build all platforms
./scripts/build-all-platforms.sh
Key Dependencies
github.com/dgraph-io/badger/v4- Embedded databasegithub.com/gorilla/websocket- WebSocket servergithub.com/minio/sha256-simd- SIMD SHA256github.com/templexxx/xhex- SIMD hex encodinggithub.com/ebitengine/purego- CGO-free C library loadinggo-simpler.org/env- Environment variable configurationlol.mleku.dev- Custom logging library
Testing Guidelines
- Test files use
_test.gosuffix - Use
github.com/stretchr/testifyfor assertions - Database tests require temporary database setup (see
pkg/database/testmain_test.go) - WebSocket tests should use
relay-testerpackage - Always clean up resources in tests (database, connections, goroutines)
Performance Considerations
- Query Cache: 512MB query result cache (configurable via
ORLY_QUERY_CACHE_SIZE_MB) with zstd level 9 compression reduces database load for repeated queries - Filter Normalization: Filters are normalized before cache lookup, so identical queries with different field ordering produce cache hits
- Database Caching: Tune
ORLY_DB_BLOCK_CACHE_MBandORLY_DB_INDEX_CACHE_MBfor workload (Badger backend only) - Query Optimization: Add indexes for common filter patterns; multiple specialized query builders optimize different filter combinations
- Batch Operations: ID lookups and event fetching use batch operations via
GetSerialsByIdsandFetchEventsBySerials - Memory Pooling: Use buffer pools in encoders (see
pkg/encoders/event/) - SIMD Operations: Leverage minio/sha256-simd and templexxx/xhex for cryptographic operations
- Goroutine Management: Each WebSocket connection runs in its own goroutine
Recent Optimizations
ORLY has received several significant performance improvements in recent updates:
Query Cache System (Latest)
- 512MB query result cache with zstd level 9 compression
- Filter normalization ensures cache hits regardless of filter field ordering
- Configurable size (
ORLY_QUERY_CACHE_SIZE_MB) and TTL (ORLY_QUERY_CACHE_MAX_AGE) - Dramatically reduces database load for repeated queries (common in Nostr clients)
- Cache key includes normalized filter representation for optimal hit rate
Badger Cache Tuning
- Optimized block cache (default 512MB, tune via
ORLY_DB_BLOCK_CACHE_MB) - Optimized index cache (default 256MB, tune via
ORLY_DB_INDEX_CACHE_MB) - Resulted in 10-15% improvement in most benchmark scenarios
- See git history for cache tuning evolution
Query Execution Improvements
- Multiple specialized query builders for different filter patterns:
query-for-kinds.go- Kind-based queriesquery-for-authors.go- Author-based queriesquery-for-tags.go- Tag-based queries- Combination builders for
kinds+authors,kinds+tags,kinds+authors+tags
- Batch operations for ID lookups via
GetSerialsByIds - Serial-based event fetching for efficiency
- Filter analysis in
get-indexes-from-filter.goselects optimal strategy
Git Commit Message Format
When asked to "make a commit comment", generate a commit message following this standard format:
Structure:
- First line: 72 characters maximum, imperative mood summary
- Second line: Empty line
- Body: Bullet points describing each change in detail
- Optional: "Files modified:" section listing affected files
Example:
Fix directory spider tag loss: size limits and validation
- Increase WebSocket message size limit from 500KB to 10MB to prevent
truncation of large kind 3 follow list events (8000+ follows)
- Add validation in SaveEvent to reject kind 3 events without p tags
before storage, preventing malformed events from buggy relays
- Implement CleanupKind3WithoutPTags() to remove existing malformed
kind 3 events at startup
- Add enhanced logging showing tag count and event ID when rejecting
invalid kind 3 events for better observability
Files modified:
- app/handle-websocket.go: Increase DefaultMaxMessageSize to 10MB
- pkg/database/save-event.go: Add kind 3 validation with logging
- pkg/database/cleanup-kind3.go: New cleanup function
- app/main.go: Invoke cleanup at startup
Release Process
- Update version in
pkg/version/versionfile (e.g., v1.2.3) - Create and push tag:
git tag v1.2.3 git push origin v1.2.3 - GitHub Actions workflow builds binaries for multiple platforms
- Release created automatically with binaries and checksums
Recent Features (v0.31.x)
Directory Spider
The directory spider (pkg/spider/directory.go) automatically discovers and syncs metadata from other relays:
- Crawls kind 10002 (relay list) events to discover relays
- Expands outward from seed pubkeys (whitelisted users) via configurable hop distance
- Fetches essential metadata events (kinds 0, 3, 10000, 10002)
- Self-detection prevents querying own relay
- Enable with
ORLY_DIRECTORY_SPIDER=true
Neo4j Social Graph Backend
The Neo4j backend (pkg/neo4j/) includes Web of Trust (WoT) extensions:
- Social Event Processor: Handles kinds 0, 3, 1984, 10000 for social graph management
- NostrUser nodes: Store profile data and trust metrics (influence, PageRank)
- Relationships: FOLLOWS, MUTES, REPORTS for social graph analysis
- WoT Schema: See
pkg/neo4j/WOT_SPEC.mdfor full specification - Schema Modifications: See
pkg/neo4j/MODIFYING_SCHEMA.mdfor how to update
Policy System Enhancements
- Write-Only Validation: Size, age, tag validations apply ONLY to writes
- Read-Only Filtering:
read_allow,read_deny,privilegedapply ONLY to reads - Scripts: Policy scripts execute ONLY for write operations
- Reference Documentation:
docs/POLICY_CONFIGURATION_REFERENCE.mdprovides authoritative read vs write applicability - See also:
pkg/policy/README.mdfor quick reference
Authentication Modes
ORLY_AUTH_REQUIRED=true: Require authentication for ALL requestsORLY_AUTH_TO_WRITE=true: Require authentication only for writes (allow anonymous reads)
NIP-43 Relay Access Metadata
Invite-based access control system:
ORLY_NIP43_ENABLED=true: Enable invite system- Publishes kind 8000/8001 events for member changes
- Publishes kind 13534 membership list events
- Configurable invite expiry via
ORLY_NIP43_INVITE_EXPIRY
Documentation Index
| Document | Purpose |
|---|---|
docs/POLICY_CONFIGURATION_REFERENCE.md |
Authoritative policy config reference with read/write applicability |
docs/POLICY_USAGE_GUIDE.md |
Comprehensive policy system user guide |
pkg/policy/README.md |
Policy system quick reference |
pkg/neo4j/README.md |
Neo4j backend overview |
pkg/neo4j/WOT_SPEC.md |
Web of Trust schema specification |
pkg/neo4j/MODIFYING_SCHEMA.md |
How to modify Neo4j schema |
pkg/neo4j/TESTING.md |
Neo4j testing guide |
readme.adoc |
Project README with feature overview |