QuickDID is a high-performance AT Protocol identity resolution service written in Rust. It provides handle-to-DID resolution with Redis-backed caching and queue processing.
QuickDID - Development Guide for Claude#
Overview#
QuickDID is a high-performance AT Protocol identity resolution service written in Rust. It provides handle-to-DID resolution with Redis-backed caching and queue processing.
Common Commands#
Building and Running#
# Build the project
cargo build
# Run in debug mode
cargo run
# Run tests
cargo test
# Type checking
cargo check
# Run with environment variables
HTTP_EXTERNAL=localhost:3007 SERVICE_KEY=did:key:z42tmZxD2mi1TfMKSFrsRfednwdaaPNZiiWHP4MPgcvXkDWK cargo run
Development with VS Code#
The project includes a .vscode/launch.json configuration for debugging with Redis integration. Use the "Debug executable 'quickdid'" launch configuration.
Architecture#
Core Components#
-
Handle Resolution (
src/handle_resolver.rs)BaseHandleResolver: Core resolution using DNS and HTTPCachingHandleResolver: In-memory caching layerRedisHandleResolver: Redis-backed persistent caching with 90-day TTL- Uses binary serialization via
HandleResolutionResultfor space efficiency
-
Binary Serialization (
src/handle_resolution_result.rs)- Compact storage format using bincode
- Strips DID prefixes for did:web and did:plc methods
- Stores: timestamp (u64), method type (i16), payload (String)
-
Queue System (
src/queue_adapter.rs)- Supports MPSC (in-process) and Redis adapters
HandleResolutionWorkitems processed asynchronously- Redis uses reliable queue pattern (LPUSH/RPOPLPUSH/LREM)
-
HTTP Server (
src/http/)- XRPC endpoints for AT Protocol compatibility
- Health check endpoint
- DID document serving via .well-known
Key Technical Details#
DID Method Types#
did:web: Web-based DIDs, prefix stripped for storagedid:plc: PLC directory DIDs, prefix stripped for storage- Other DID methods stored with full identifier
Redis Integration#
- Caching: Uses MetroHash64 for key generation, stores binary data
- Queuing: Reliable queue with processing/dead letter queues
- Key Prefixes: Configurable via
QUEUE_REDIS_PREFIXenvironment variable
Handle Resolution Flow#
- Check Redis cache (if configured)
- Fall back to in-memory cache
- Perform DNS TXT lookup or HTTP well-known query
- Cache result with appropriate TTL
- Return DID or error
Environment Variables#
Required#
HTTP_EXTERNAL: External hostname for service endpoints (e.g.,localhost:3007)SERVICE_KEY: Private key for service identity (DID format)
Optional#
HTTP_PORT: Server port (default: 8080)PLC_HOSTNAME: PLC directory hostname (default: plc.directory)REDIS_URL: Redis connection URL for cachingQUEUE_ADAPTER: Queue type - 'mpsc' or 'redis' (default: mpsc)QUEUE_REDIS_PREFIX: Redis key prefix for queues (default: queue:handleresolver:)QUEUE_WORKER_ID: Worker ID for Redis queue (auto-generated if not set)RUST_LOG: Logging level (e.g., debug, info)
Error Handling#
All error strings must use this format:
error-quickdid-<domain>-<number> <message>: <details>
Example errors:
- error-quickdid-resolve-1 Multiple DIDs resolved for method
- error-quickdid-plc-1 HTTP request failed: https://google.com/ Not Found
- error-quickdid-key-1 Error decoding key: invalid
Errors should be represented as enums using the thiserror library.
Avoid creating new errors with the anyhow!(...) or bail!(...) macro.
Testing#
Running Tests#
# Run all tests
cargo test
# Run with Redis integration tests
TEST_REDIS_URL=redis://localhost:6379 cargo test
# Run specific test module
cargo test handle_resolver::tests
Test Coverage Areas#
- Handle resolution with various DID methods
- Binary serialization/deserialization
- Redis caching and expiration
- Queue processing logic
- HTTP endpoint responses
Development Patterns#
Error Handling#
- Uses
anyhow::Resultfor error propagation - Graceful fallbacks when Redis is unavailable
- Detailed tracing for debugging
Performance Optimizations#
- Binary serialization reduces storage by ~40%
- MetroHash64 for fast key generation
- Connection pooling for Redis
- Configurable TTLs for cache entries
Code Style#
- Follow existing Rust idioms and patterns
- Use
tracingfor logging, notprintln! - Prefer
Arcfor shared state across async tasks - Handle errors explicitly, avoid
.unwrap()in production code
Common Tasks#
Adding a New DID Method#
- Update
DidMethodTypeenum inhandle_resolution_result.rs - Modify
parse_did()andto_did()methods - Add test cases for the new method type
Modifying Cache TTL#
- For in-memory: Pass TTL to
CachingHandleResolver::new() - For Redis: Modify
RedisHandleResolver::ttl_seconds()
Debugging Resolution Issues#
- Enable debug logging:
RUST_LOG=debug - Check Redis cache:
redis-cli GET "handle:<hash>" - Monitor queue processing in logs
- Verify DNS/HTTP connectivity to AT Protocol infrastructure
Dependencies#
atproto-identity: Core AT Protocol identity resolutionbincode: Binary serializationdeadpool-redis: Redis connection poolingmetrohash: Fast non-cryptographic hashingtokio: Async runtimeaxum: Web framework