commits
Document what's complete and what's pending for phone verification.
Includes merge strategy, cost estimates, and next steps.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add implementation and security documentation:
- DID_SETUP.md: Keypair generation and deployment
- PHONE_VERIFICATION_IMPLEMENTATION.md: Complete implementation guide
- PHONE_VERIFICATION_SUMMARY.md: Quick reference
- VERIFICATION_SECURITY.md: Security model and attack prevention
Documents the hybrid architecture: privacy-first storage with
cryptographically signed, portable verification badges.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add DID document and environment configuration:
- did:web:coves.social for cryptographic signing
- P-256 EC keypair for ECDSA signatures
- Configurable for self-hosted instances
Third-party apps fetch public key from /.well-known/did.json
to verify verification signatures.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Telnyx selected for SMS delivery:
- 50% cheaper than Twilio ($0.004/SMS vs $0.0079)
- Owned infrastructure (better reliability)
- International number support
- Free expert support
Client handles OTP delivery with proper error handling.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement verification service with security-first design:
- Cryptographically secure OTP generation (crypto/rand)
- Rate limiting (3/hour per phone, 5/day per DID)
- Constant-time OTP comparison (bcrypt)
- Signature binding to subject DID (prevents copying attack)
- Comprehensive error types for XRPC handlers
Service interfaces support future verification types (email, domain).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add privacy-first phone verification tables:
- phone_verifications: Stores hashed phones only (HMAC-SHA256)
- phone_verification_requests: Temporary OTP storage (10min TTL)
- phone_verification_rate_limits: SMS abuse prevention
- phone_verification_audit_log: Security monitoring
Includes cleanup function for expired requests.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add support for cryptographically signed verifications (phone, email, domain, etc.)
to actor profiles. This is a backwards-compatible addition.
Changes:
- Replace simple verified boolean with verifications array
- Add verification lexicon definition with signature support
- Add XRPC endpoints: requestPhone, verifyPhone, getStatus
The verification array allows multiple verification types and is
cryptographically signed by trusted services (e.g., did:web:coves.social).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit implements a complete, secure OAuth 2.0 + atProto authentication system
for Coves, including comprehensive security fixes based on code review.
## 📋 Core Features
### OAuth 2.0 + atProto Authentication
- **DPoP Token Binding (RFC 9449)**: Each session has unique cryptographic key
- **PKCE (RFC 7636)**: S256 challenge method prevents code interception
- **PAR (RFC 9126)**: Pre-registration of authorization requests
- **Complete OAuth Flow**: Login → Authorize → Callback → Session Management
### Implementation Architecture
- **Handlers**: [internal/api/handlers/oauth/](internal/api/handlers/oauth/)
- `login.go` - Initiates OAuth flow with handle resolution
- `callback.go` - Processes authorization code and creates session
- `logout.go` - Session termination
- `metadata.go` - RFC 7591 client metadata endpoint
- `jwks.go` - Public key exposure (JWK Set)
- **OAuth Client**: [internal/atproto/oauth/](internal/atproto/oauth/)
- `client.go` - OAuth HTTP client with PAR, token exchange, refresh
- `dpop.go` - DPoP proof generation (ES256 signatures)
- `pkce.go` - PKCE challenge generation
- **Session Management**: [internal/core/oauth/](internal/core/oauth/)
- `session.go` - OAuth data models (OAuthRequest, OAuthSession)
- `repository.go` - PostgreSQL storage with atomic operations
- `auth_service.go` - Authentication business logic
- **Middleware**: [internal/api/middleware/auth.go](internal/api/middleware/auth.go)
- `RequireAuth` - Enforces authentication
- `OptionalAuth` - Loads user context if available
- Automatic token refresh (< 5 min to expiry)
### Database Schema
- **oauth_requests**: Temporary state during authorization flow (10-min TTL)
- **oauth_sessions**: Long-lived authenticated sessions
- **Indexes**: Performance optimizations for session queries
- **Auto-cleanup**: Trigger-based expiration handling
### DPoP Transport
- **HTTP RoundTripper**: [internal/atproto/xrpc/dpop_transport.go](internal/atproto/xrpc/dpop_transport.go)
- Automatic DPoP proof injection on all requests
- Nonce rotation handling (automatic retry on 401)
- PDS and auth server nonce tracking
## 🔐 Security Features (PR Review Hardening)
### Critical Security Fixes
✅ **CSRF/Replay Protection**: Atomic `GetAndDeleteRequest()` prevents state reuse
✅ **Cookie Secret Validation**: Enforced minimum 32 bytes for session security
✅ **Error Sanitization**: No internal error details exposed to users
✅ **HTTPS Enforcement**: Production-only HTTPS cookies with explicit localhost checks
✅ **Clean Architecture**: Business logic extracted to `AuthService` layer
### Additional Security Measures
✅ **No Token Leakage**: Never log response bodies containing credentials
✅ **Race-Free**: Fixed concurrent access to DPoP nonces with proper mutex handling
✅ **Input Validation**: Handle format checking, state parameter verification
✅ **Session Isolation**: One active session per DID (upgradeable to multiple)
✅ **Automatic Cleanup**: Hourly background job removes expired sessions/requests
### Token Binding & Proof-of-Possession
- Each session generates unique ES256 key pair
- Access tokens cryptographically bound to client
- DPoP proofs include:
- JWK header (public key)
- HTTP method and URL (prevents token replay)
- Access token hash (`ath` claim)
- JTI (unique token ID)
- Server nonce (when required)
## 🎯 Configuration & Setup
### Environment Variables
```bash
# OAuth Configuration (.env.dev)
OAUTH_PRIVATE_JWK=base64:... # Client private key (ES256)
OAUTH_COOKIE_SECRET=... # Session cookie secret (min 32 bytes)
APPVIEW_PUBLIC_URL=http://127.0.0.1:8081
```
### Base64 Encoding Support
- Helper: `GetEnvBase64OrPlain()` supports both plain and base64-encoded values
- Prevents shell escaping issues with JSON in environment variables
- Format: `OAUTH_PRIVATE_JWK=base64:eyJhbGci...` or plain JSON
### Cookie Store Singleton
- Global singleton initialized at startup: `oauth.InitCookieStore(secret)`
- Shared across all handlers for consistent session management
- Validates secret length on initialization
### Database Migration
```sql
-- Migration 003: OAuth tables
-- Migration 004: Performance indexes
```
## 📊 Code Quality & Testing
### Test Coverage
- `env_test.go` - Base64 environment variable handling (8 test cases)
- `dpop_test.go` - DPoP proof structure validation
- `oauth_test.go` - Integration tests for OAuth endpoints
### Linter Compliance
- Fixed errcheck violations (defer close, error handling)
- Formatted with gofmt
- Added nolint directives where appropriate
### Constants & Configuration
- [constants.go](internal/api/handlers/oauth/constants.go) - Named configuration values
- `SessionMaxAge = 7 * 24 * 60 * 60`
- `TokenRefreshThreshold = 5 * time.Minute`
- `MinCookieSecretLength = 32`
## 🎓 Implementation Decisions
### Custom OAuth vs Indigo Library
- **Decision**: Implement custom OAuth client
- **Rationale**: Indigo OAuth library explicitly unstable; custom implementation gives full control over edge cases and nonce retry logic
- **Future**: Migrate when indigo reaches stable v1.0
### Session Storage
- **Decision**: PostgreSQL with one session per DID
- **Rationale**: Simple for initial implementation, easy to upgrade to multiple sessions later, transaction support
### DPoP Key Management
- **Decision**: Unique key per session, stored in database
- **Rationale**: RFC 9449 compliance, token binding security, survives server restarts
## 📈 Performance Optimizations
- `idx_oauth_sessions_did_expires` - Fast session expiry queries
- Partial index for active sessions (`WHERE expires_at > NOW()`)
- Hourly cleanup prevents table bloat
- Cookie store singleton reduces memory allocations
## ✅ Production Readiness
### Real-World Validation
✅ Successfully tested with live PDS: `https://pds.bretton.dev`
✅ Handle resolution: `bretton.dev` → DID → PDS discovery
✅ Complete authorization flow with DPoP nonce retry
✅ Session storage and retrieval validated
✅ Token refresh logic confirmed working
### Security Checklist
✅ DPoP token binding prevents theft/replay
✅ PKCE prevents authorization code interception
✅ PAR reduces attack surface
✅ Atomic state operations prevent CSRF
✅ HTTP-only, secure, SameSite cookies
✅ Private keys never exposed in public endpoints
✅ Automatic token expiration (60 min access, ~90 day refresh)
## 📦 Files Changed
- **27 files**: 3,130 additions, 1 deletion
- **New packages**: oauth handlers, OAuth client, auth middleware
- **New migrations**: OAuth tables + indexes
- **Updated**: main.go (OAuth initialization), .env.dev (configuration docs)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
## Core Features
### Identity Resolution System (internal/atproto/identity/)
- Implement DNS/HTTPS handle resolution using Bluesky Indigo library
- Add DID document resolution via PLC directory
- Create PostgreSQL-backed caching layer (24h TTL)
- Support bidirectional caching (handle ↔ DID)
- Add atomic cache purge with single-query CTE optimization
### Database Schema
- Add identity_cache table with timezone-aware timestamps
- Support handle normalization via database trigger
- Enable automatic expiry checking
### Handle Update System
- Add UpdateHandle method to UserService and UserRepository
- Implement handle change detection in Jetstream consumer
- Update database BEFORE purging cache (prevents race condition)
- Purge BOTH old handle and DID entries on handle changes
- Add structured logging for cache operations
### Bug Fixes
- Fix timezone bugs throughout codebase (use UTC consistently)
- Fix rate limiter timestamp handling
- Resolve pre-existing test isolation bug in identity cache tests
- Fix Makefile test command to exclude restricted directories
### Testing
- Add comprehensive identity resolution test suite (450+ lines)
- Add handle change integration test with cache verification
- All 46+ integration test subtests passing
- Test both local and real atProto handle resolution
### Configuration
- Add IDENTITY_PLC_URL and IDENTITY_CACHE_TTL env vars
- Add golangci-lint configuration
- Update Makefile to avoid permission denied errors
## Architecture Decisions
- Use decorator pattern for caching resolver
- Maintain layer separation (no SQL in handlers)
- Reject database triggers for cache invalidation (keeps logic in app layer)
- Follow atProto best practices from QuickDID
## Files Changed
- 7 new files (identity system + migration + tests)
- 12 modified files (integration + bug fixes)
- ~800 lines of production code
- ~450 lines of tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Groups all atProto-related code under internal/atproto/ for better
code organization:
internal/
├── atproto/
│ ├── lexicon/ # Protocol definitions
│ └── jetstream/ # Firehose consumer
├── core/ # Business logic
└── db/ # Persistence
Changes:
- Moved internal/jetstream/ → internal/atproto/jetstream/
- Updated import paths in cmd/server/main.go
- Updated import paths in all test files
All tests passing:
✅ Unit tests
✅ Integration tests
✅ E2E tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
IDE configuration files should not be tracked in git.
These files are already in .gitignore but were committed before
the ignore rule was added.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Addresses PR review feedback with security, validation, and reliability improvements.
## Security & Validation Improvements
- Add lexicon-compliant error types (InvalidHandle, WeakPassword, etc.)
- Implement official atProto handle validation per spec
- Normalizes to lowercase before validation
- Validates TLD restrictions (.local, .onion, etc. disallowed)
- Max 253 char length enforcement
- Reference: https://atproto.com/specs/handle
- Add password validation (min 8 chars)
- Protects PDS from spam by malicious third-party clients
- PDS remains authoritative on final acceptance
- Add HTTP client timeout (10s) to prevent hanging on slow PDS
- Map service errors to proper XRPC error responses with correct status codes
## Test Reliability Improvements
- Replace fixed time.Sleep() with retry-with-timeout pattern
- Inline retry loops with 500ms polling intervals
- Configurable deadlines per test scenario (10-15s)
- 2x faster test execution on fast systems
- More reliable on slow CI environments
- Add E2E test database setup helper
- Fix test expectations to match new error messages
## Architecture Documentation
- Add TODO comments for future improvements:
- Race condition in Jetstream consumer (sync.Once needed)
- DID→PDS URL resolution via PLC directory for federation
- Document that current implementation works for local dev
- Mark federation support as future enhancement
## Files Changed
New files:
- internal/core/users/errors.go - Domain error types
- tests/e2e/user_signup_test.go - Full E2E test coverage
- internal/atproto/lexicon/social/coves/actor/signup.json - Lexicon spec
- docs/E2E_TESTING.md - E2E testing guide
- internal/jetstream/user_consumer.go - Event consumer
- tests/integration/jetstream_consumer_test.go - Consumer tests
- tests/integration/user_test.go - User service tests
Modified:
- internal/core/users/service.go - Enhanced validation + HTTP timeout
- internal/api/routes/user.go - Lexicon error mapping
- tests/integration/user_test.go - Updated test expectations
## Test Results
✅ All unit/integration tests pass
✅ Full E2E test suite passes (10.3s)
✅ Validates complete signup flow: XRPC → PDS → Jetstream → AppView → PostgreSQL
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements a minimal, production-ready user management system for Coves
with atProto DID-based identity and comprehensive security improvements.
## Core Features
- atProto-compliant user model (DID + handle)
- Single clean migration (001_create_users_table.sql)
- XRPC endpoint: social.coves.actor.getProfile
- Handle-based authentication (resolves handle → DID)
- PostgreSQL AppView indexing
## Security & Performance Fixes
- **Rate limiting**: 100 req/min per IP (in-memory middleware)
- **Input validation**: atProto handle regex validation
- Alphanumeric + hyphens + dots only
- No consecutive hyphens, must start/end with alphanumeric
- 1-253 character length limit
- **Database constraints**: Proper unique constraint error handling
- Clear error messages for duplicate DID/handle
- No internal details leaked to API consumers
- **Performance**: Removed duplicate DB checks (3 calls → 1 call)
## Breaking Changes
- Replaced email/username model with DID/handle
- Deleted legacy migrations (001, 005)
- Removed old repository and service test files
## Architecture
- Repository: Parameterized queries, context-aware
- Service: Business logic with proper validation
- Handler: Minimal XRPC implementation
- Middleware: Rate limiting for public endpoints
## Testing
- Full integration test coverage (4 test suites, all passing)
- Duplicate creation validation tests
- Handle format validation (9 edge cases)
- XRPC endpoint tests (success/error scenarios)
## Documentation
- Updated TESTING_SUMMARY.md with .test handle convention
- Added TODO for federated PDS support
- RFC3339 timestamp formatting
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Consolidate all test and development configuration into a single source
of truth (.env.dev) for cleaner, more maintainable setup.
Changes:
- Remove obsolete .env.test and .env.test.example files
- Update Makefile to load .env.dev variables automatically via include
- Simplify test commands (no more bash subshells or complex sourcing)
- Update integration tests to read config from environment variables
- Rewrite TESTING_SUMMARY.md with current unified approach
- Update LOCAL_DEVELOPMENT.md to reference single config file
Benefits:
- Single source of truth for all configuration
- Simpler test execution: just `make test`
- Isolated test DB (port 5434) separate from dev (port 5433)
- Better documentation and developer experience
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Simplified Configuration:**
- Test database credentials now in .env.dev (single source of truth)
- docker-compose.dev.yml uses env vars for test DB (POSTGRES_TEST_*)
- Makefile sources .env.dev for all test commands
- No need for separate .env.test file
**Removed:**
- run-tests.sh - Redundant, use `make test` instead
**Benefits:**
- All local dev config in one place (.env.dev)
- Less mental overhead (dev + test in same file)
- Consistent variable usage throughout stack
- Simpler developer onboarding
Usage:
- `make test` - Run all tests (handles DB automatically)
- All test config in .env.dev under "Test Database Configuration"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major cleanup now that PDS handles all repository operations:
**Removed:**
- internal/core/repository/ - Repository domain logic (PDS handles this)
- internal/db/postgres/repository_repo.go - Repository database operations
- internal/api/handlers/repository_handler.go - Repository API handlers
- internal/api/routes/repository.go - Repository routes
- tests/integration/repository_test.go - Repository integration tests
- Migrations 002, 003, 004 - Repository/CAR storage tables
- internal/db/local_dev_db_compose/ - Separate dev database setup
- internal/db/test_db_compose/ - Separate test database setup
**Unified:**
- docker-compose.dev.yml now includes PostgreSQL + PDS + optional test DB
- All database management moved to Makefile commands
- Consistent use of .env.dev variables throughout
**Updated:**
- cmd/server/main.go - Simplified to only use user service
- Makefile - All-in-one commands (dev-up starts both PostgreSQL + PDS)
- Added db-migrate, db-reset, test commands using Docker profiles
**Architecture:**
- PDS: Self-contained with SQLite + CAR files (port 3001)
- PostgreSQL: Only for Coves AppView indexing (port 5433)
- Test DB: Available via --profile test (port 5434)
- Single source of truth: docker-compose.dev.yml + .env.dev
Commands:
- `make dev-up` - Start PostgreSQL + PDS
- `make test` - Start test DB + run tests
- `make db-migrate` - Run migrations
- `make db-shell` - Open psql shell
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add docker-compose.dev.yml with Bluesky PDS (port 3001)
- Add .env.dev with development configuration
- Add Makefile with convenient dev commands (help, dev-up, dev-down, etc.)
- Add comprehensive docs/LOCAL_DEVELOPMENT.md guide
- Update CLAUDE.md and ATPROTO_GUIDE.md with correct architecture
- Remove custom carstore implementation (PDS handles this)
- Remove internal/atproto/repo wrapper (not needed)
- Add feed lexicon schemas (getAll, getCommunity, getTimeline)
- Update post lexicons to remove getFeed (replaced by feed queries)
- Update PROJECT_STRUCTURE.md to reflect new architecture
Architecture:
- PDS is self-contained with internal SQLite + CAR storage
- PostgreSQL database only used by Coves AppView for indexing
- AppView subscribes directly to PDS firehose (no relay needed for local dev)
- PDS runs on port 3001 to avoid conflicts with production PDS on 3000
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
feat: Implement union types for moderation configuration
- Replace single moderationConfig with union type supporting both moderator and sortition variants
- Add $type discriminator field following atProto patterns
- Separate tribunal-specific fields (tribunalThreshold, jurySize) to sortition variant only
- Update test files to use new union structure with proper $type fields
- Ensure type safety: only sortition communities can configure tribunal settings
This change improves the lexicon design by:
- Following atProto best practices for discriminated unions
- Providing clear separation between moderation types
- Enabling future extensibility for new moderation approaches
- Maintaining backwards compatibility through the union pattern
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
feat: Add comprehensive lexicon test data and validation fixes
- Add 35 test data files covering all lexicon record types
- Actor records: block, membership, preferences, profile, saved, subscription
- Community records: moderator, profile, rules, wiki
- Interaction records: comment, share, tag
- Moderation records: ruleProposal, tribunalVote, vote
- Post records: post validation
- Fix lexicon schema issues:
- Add 'handle' format to actor profile
- Fix typo in community profile moderation type
- Add required $type field to interaction comments
- Add minItems constraint to tag arrays
- Fix enum values in moderation schemas
- Improve validate-lexicon tool:
- Better number handling to prevent float64 conversion issues
- Add json.Number support for accurate integer validation
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
feat: Implement comprehensive lexicon validation system
- Add internal/validation/lexicon.go with ValidateLexiconData function
- Create validate-lexicon CLI tool for testing lexicon schemas
- Add comprehensive test suite with valid and invalid test cases
- Include test data for actors, communities, posts, interactions, and moderation
- Replace shell-based validation script with Go implementation
- Support for complex validation including enums, unions, and references
This provides a robust foundation for validating atProto lexicon data
in the Coves platform, ensuring data integrity and type safety.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
feat: Add domain knowledge documentation and update lexicon schemas
- Add comprehensive DOMAIN_KNOWLEDGE.md documenting Coves platform concepts
- Update CLAUDE.md with improved development guidelines
- Enhance actor preferences and subscription lexicon schemas
- Improve post retrieval and feed functionality with better tag support
- Update create-pr command documentation
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
feat: Unify post lexicon architecture and improve tag handling
Major architectural improvements to the post lexicon system:
- Unified 5 separate post types into single record with postType discriminator
- Moved tags from author-created content to community interactions (following Bluesky pattern)
- Added tagCounts to post stats and viewer tags to viewerState
- Cleaned up legacy fields (removed nsfw boolean, use contentLabels)
- Simplified embedType enum (image-gallery → image)
- Updated federation schema to use specific platform names
- Clarified title field as optional for certain post types
- Support for up to 8 images in image embeds
This change enables:
- Simpler codebase with single post record type
- Filtering by post type(s) at query level
- Community-driven tagging system
- Consistent embed handling across all post types
- Better federation support with originalAuthor field
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This reverts commit 32f6836b6ebb8af1a475b06c4045a545f06cdcff.
Major architectural improvements to the post lexicon system:
- Unified 5 separate post types into single record with postType discriminator
- Moved tags from author-created content to community interactions (following Bluesky pattern)
- Added tagCounts to post stats and viewer tags to viewerState
- Cleaned up legacy fields (removed nsfw boolean, use contentLabels)
- Simplified embedType enum (image-gallery → image)
- Updated federation schema to use specific platform names
- Clarified title field as optional for certain post types
- Support for up to 8 images in image embeds
This change enables:
- Simpler codebase with single post record type
- Filtering by post type(s) at query level
- Community-driven tagging system
- Consistent embed handling across all post types
- Better federation support with originalAuthor field
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
feat: Reimplement richtext using Bluesky-inspired facet system
- Fixed typo "filesred" → "files" in validate-lexicon/main.go
- Added validate-lexicon binary to .gitignore and removed from git
- Updated facet schema to include required $type fields for AT Protocol compatibility
- Removed duplicate mentions field from microblog.json (use facets instead)
- Added comprehensive facet tests covering UTF-8 byte counting and all feature types
- Fixed lexicon validation test to reference correct schema names
- Added detailed facet documentation with UTF-8 byte counting examples
The facet implementation now follows AT Protocol standards with proper $type
fields for each feature (mention, link, bold, italic, strikethrough, spoiler).
All byte indices use UTF-8 encoding for cross-platform consistency.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace separate markup/mention/link lexicons with unified facet approach
- Use byte-indexed positioning (byteStart/byteEnd) for text annotations
- Support overlapping features: bold, italic, strikethrough, spoiler, mention, link
- Add native support for community mentions with \! prefix
- Update all schemas to use *Facets fields instead of *Markup
- Align with AT Protocol standards for better federation compatibility
BREAKING CHANGE: All richtext markup fields renamed to facets
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement query and procedure lexicon definitions
This commit adds a complete set of lexicon definitions required for the
core functionality of the Coves social platform, following AT Protocol
best practices.
Added 29 new lexicon files across 4 namespaces:
Actor namespace (7 files):
- blockUser.json: Block another user
- getProfile.json: Retrieve user profile with stats
- preferences.json: User preferences record type
- saveItem.json: Save posts/comments for later
- unblockUser.json: Unblock a previously blocked user
- unsaveItem.json: Remove saved items
- updateProfile.json: Update user profile information
Community namespace (10 files):
- create.json: Create a new community
- get.json: Retrieve community details
- getMembers.json: List community members
- getSubscribers.json: List community subscribers
- list.json: List communities with filtering
- moderator.json: Moderator assignment record type
- search.json: Search communities by text
- subscribe.json: Subscribe to a community
- unsubscribe.json: Unsubscribe from a community
- update.json: Update community settings
Post namespace (6 files):
- create.json: Create posts (text, image, video, article, microblog)
- delete.json: Delete a post
- get.json: Retrieve a single post
- getFeed.json: Get post feeds with sorting options
- search.json: Search posts by text
- update.json: Update post content
Interaction namespace (4 files):
- createComment.json: Comment on posts/comments
- deleteComment.json: Delete comments
- createVote.json: Vote on posts/comments
- deleteVote.json: Remove votes
Bug fixes:
- Fixed duplicate 'createdAt' in membership.json required array
- Corrected getSaved.json type from 'procedure' to 'query'
All lexicons follow the established patterns:
- Queries for read operations
- Procedures for write operations
- Proper error definitions
- Consistent parameter naming
- Support for pagination where appropriate
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Refactor: ATProto Repository Storage with Indigo Carstore Integration
- Remove blob storage from repository interface and implementation
- Add GORM integration for better database management
- Integrate Indigo's carstore for proper CAR file storage
- Update repository wrapper to use external blockstore
- Add comprehensive test infrastructure with test database setup
- Add test environment configuration example
- Update dependencies to include required Indigo and IPFS packages
- Fix repository record operations to work without inline value storage
- Add proper error handling and migrations for carstore integration
This refactoring aligns the repository storage with ATProto standards by:
1. Using Indigo's carstore for efficient CAR file management
2. Removing custom blob storage in favor of standard IPFS blockstore
3. Improving test infrastructure for better integration testing
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Feature/lexicon implementation
Implements full-stack user functionality following layered architecture:
- User domain models and validation
- RESTful API endpoints (GET /users/{id}, POST /users)
- PostgreSQL database with migrations and indexes
- Repository pattern with interfaces
- Service layer with business logic
- Integration tests and error handling
- Docker Compose for local development
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Document what's complete and what's pending for phone verification.
Includes merge strategy, cost estimates, and next steps.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add implementation and security documentation:
- DID_SETUP.md: Keypair generation and deployment
- PHONE_VERIFICATION_IMPLEMENTATION.md: Complete implementation guide
- PHONE_VERIFICATION_SUMMARY.md: Quick reference
- VERIFICATION_SECURITY.md: Security model and attack prevention
Documents the hybrid architecture: privacy-first storage with
cryptographically signed, portable verification badges.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add DID document and environment configuration:
- did:web:coves.social for cryptographic signing
- P-256 EC keypair for ECDSA signatures
- Configurable for self-hosted instances
Third-party apps fetch public key from /.well-known/did.json
to verify verification signatures.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Telnyx selected for SMS delivery:
- 50% cheaper than Twilio ($0.004/SMS vs $0.0079)
- Owned infrastructure (better reliability)
- International number support
- Free expert support
Client handles OTP delivery with proper error handling.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement verification service with security-first design:
- Cryptographically secure OTP generation (crypto/rand)
- Rate limiting (3/hour per phone, 5/day per DID)
- Constant-time OTP comparison (bcrypt)
- Signature binding to subject DID (prevents copying attack)
- Comprehensive error types for XRPC handlers
Service interfaces support future verification types (email, domain).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add privacy-first phone verification tables:
- phone_verifications: Stores hashed phones only (HMAC-SHA256)
- phone_verification_requests: Temporary OTP storage (10min TTL)
- phone_verification_rate_limits: SMS abuse prevention
- phone_verification_audit_log: Security monitoring
Includes cleanup function for expired requests.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add support for cryptographically signed verifications (phone, email, domain, etc.)
to actor profiles. This is a backwards-compatible addition.
Changes:
- Replace simple verified boolean with verifications array
- Add verification lexicon definition with signature support
- Add XRPC endpoints: requestPhone, verifyPhone, getStatus
The verification array allows multiple verification types and is
cryptographically signed by trusted services (e.g., did:web:coves.social).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit implements a complete, secure OAuth 2.0 + atProto authentication system
for Coves, including comprehensive security fixes based on code review.
## 📋 Core Features
### OAuth 2.0 + atProto Authentication
- **DPoP Token Binding (RFC 9449)**: Each session has unique cryptographic key
- **PKCE (RFC 7636)**: S256 challenge method prevents code interception
- **PAR (RFC 9126)**: Pre-registration of authorization requests
- **Complete OAuth Flow**: Login → Authorize → Callback → Session Management
### Implementation Architecture
- **Handlers**: [internal/api/handlers/oauth/](internal/api/handlers/oauth/)
- `login.go` - Initiates OAuth flow with handle resolution
- `callback.go` - Processes authorization code and creates session
- `logout.go` - Session termination
- `metadata.go` - RFC 7591 client metadata endpoint
- `jwks.go` - Public key exposure (JWK Set)
- **OAuth Client**: [internal/atproto/oauth/](internal/atproto/oauth/)
- `client.go` - OAuth HTTP client with PAR, token exchange, refresh
- `dpop.go` - DPoP proof generation (ES256 signatures)
- `pkce.go` - PKCE challenge generation
- **Session Management**: [internal/core/oauth/](internal/core/oauth/)
- `session.go` - OAuth data models (OAuthRequest, OAuthSession)
- `repository.go` - PostgreSQL storage with atomic operations
- `auth_service.go` - Authentication business logic
- **Middleware**: [internal/api/middleware/auth.go](internal/api/middleware/auth.go)
- `RequireAuth` - Enforces authentication
- `OptionalAuth` - Loads user context if available
- Automatic token refresh (< 5 min to expiry)
### Database Schema
- **oauth_requests**: Temporary state during authorization flow (10-min TTL)
- **oauth_sessions**: Long-lived authenticated sessions
- **Indexes**: Performance optimizations for session queries
- **Auto-cleanup**: Trigger-based expiration handling
### DPoP Transport
- **HTTP RoundTripper**: [internal/atproto/xrpc/dpop_transport.go](internal/atproto/xrpc/dpop_transport.go)
- Automatic DPoP proof injection on all requests
- Nonce rotation handling (automatic retry on 401)
- PDS and auth server nonce tracking
## 🔐 Security Features (PR Review Hardening)
### Critical Security Fixes
✅ **CSRF/Replay Protection**: Atomic `GetAndDeleteRequest()` prevents state reuse
✅ **Cookie Secret Validation**: Enforced minimum 32 bytes for session security
✅ **Error Sanitization**: No internal error details exposed to users
✅ **HTTPS Enforcement**: Production-only HTTPS cookies with explicit localhost checks
✅ **Clean Architecture**: Business logic extracted to `AuthService` layer
### Additional Security Measures
✅ **No Token Leakage**: Never log response bodies containing credentials
✅ **Race-Free**: Fixed concurrent access to DPoP nonces with proper mutex handling
✅ **Input Validation**: Handle format checking, state parameter verification
✅ **Session Isolation**: One active session per DID (upgradeable to multiple)
✅ **Automatic Cleanup**: Hourly background job removes expired sessions/requests
### Token Binding & Proof-of-Possession
- Each session generates unique ES256 key pair
- Access tokens cryptographically bound to client
- DPoP proofs include:
- JWK header (public key)
- HTTP method and URL (prevents token replay)
- Access token hash (`ath` claim)
- JTI (unique token ID)
- Server nonce (when required)
## 🎯 Configuration & Setup
### Environment Variables
```bash
# OAuth Configuration (.env.dev)
OAUTH_PRIVATE_JWK=base64:... # Client private key (ES256)
OAUTH_COOKIE_SECRET=... # Session cookie secret (min 32 bytes)
APPVIEW_PUBLIC_URL=http://127.0.0.1:8081
```
### Base64 Encoding Support
- Helper: `GetEnvBase64OrPlain()` supports both plain and base64-encoded values
- Prevents shell escaping issues with JSON in environment variables
- Format: `OAUTH_PRIVATE_JWK=base64:eyJhbGci...` or plain JSON
### Cookie Store Singleton
- Global singleton initialized at startup: `oauth.InitCookieStore(secret)`
- Shared across all handlers for consistent session management
- Validates secret length on initialization
### Database Migration
```sql
-- Migration 003: OAuth tables
-- Migration 004: Performance indexes
```
## 📊 Code Quality & Testing
### Test Coverage
- `env_test.go` - Base64 environment variable handling (8 test cases)
- `dpop_test.go` - DPoP proof structure validation
- `oauth_test.go` - Integration tests for OAuth endpoints
### Linter Compliance
- Fixed errcheck violations (defer close, error handling)
- Formatted with gofmt
- Added nolint directives where appropriate
### Constants & Configuration
- [constants.go](internal/api/handlers/oauth/constants.go) - Named configuration values
- `SessionMaxAge = 7 * 24 * 60 * 60`
- `TokenRefreshThreshold = 5 * time.Minute`
- `MinCookieSecretLength = 32`
## 🎓 Implementation Decisions
### Custom OAuth vs Indigo Library
- **Decision**: Implement custom OAuth client
- **Rationale**: Indigo OAuth library explicitly unstable; custom implementation gives full control over edge cases and nonce retry logic
- **Future**: Migrate when indigo reaches stable v1.0
### Session Storage
- **Decision**: PostgreSQL with one session per DID
- **Rationale**: Simple for initial implementation, easy to upgrade to multiple sessions later, transaction support
### DPoP Key Management
- **Decision**: Unique key per session, stored in database
- **Rationale**: RFC 9449 compliance, token binding security, survives server restarts
## 📈 Performance Optimizations
- `idx_oauth_sessions_did_expires` - Fast session expiry queries
- Partial index for active sessions (`WHERE expires_at > NOW()`)
- Hourly cleanup prevents table bloat
- Cookie store singleton reduces memory allocations
## ✅ Production Readiness
### Real-World Validation
✅ Successfully tested with live PDS: `https://pds.bretton.dev`
✅ Handle resolution: `bretton.dev` → DID → PDS discovery
✅ Complete authorization flow with DPoP nonce retry
✅ Session storage and retrieval validated
✅ Token refresh logic confirmed working
### Security Checklist
✅ DPoP token binding prevents theft/replay
✅ PKCE prevents authorization code interception
✅ PAR reduces attack surface
✅ Atomic state operations prevent CSRF
✅ HTTP-only, secure, SameSite cookies
✅ Private keys never exposed in public endpoints
✅ Automatic token expiration (60 min access, ~90 day refresh)
## 📦 Files Changed
- **27 files**: 3,130 additions, 1 deletion
- **New packages**: oauth handlers, OAuth client, auth middleware
- **New migrations**: OAuth tables + indexes
- **Updated**: main.go (OAuth initialization), .env.dev (configuration docs)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
## Core Features
### Identity Resolution System (internal/atproto/identity/)
- Implement DNS/HTTPS handle resolution using Bluesky Indigo library
- Add DID document resolution via PLC directory
- Create PostgreSQL-backed caching layer (24h TTL)
- Support bidirectional caching (handle ↔ DID)
- Add atomic cache purge with single-query CTE optimization
### Database Schema
- Add identity_cache table with timezone-aware timestamps
- Support handle normalization via database trigger
- Enable automatic expiry checking
### Handle Update System
- Add UpdateHandle method to UserService and UserRepository
- Implement handle change detection in Jetstream consumer
- Update database BEFORE purging cache (prevents race condition)
- Purge BOTH old handle and DID entries on handle changes
- Add structured logging for cache operations
### Bug Fixes
- Fix timezone bugs throughout codebase (use UTC consistently)
- Fix rate limiter timestamp handling
- Resolve pre-existing test isolation bug in identity cache tests
- Fix Makefile test command to exclude restricted directories
### Testing
- Add comprehensive identity resolution test suite (450+ lines)
- Add handle change integration test with cache verification
- All 46+ integration test subtests passing
- Test both local and real atProto handle resolution
### Configuration
- Add IDENTITY_PLC_URL and IDENTITY_CACHE_TTL env vars
- Add golangci-lint configuration
- Update Makefile to avoid permission denied errors
## Architecture Decisions
- Use decorator pattern for caching resolver
- Maintain layer separation (no SQL in handlers)
- Reject database triggers for cache invalidation (keeps logic in app layer)
- Follow atProto best practices from QuickDID
## Files Changed
- 7 new files (identity system + migration + tests)
- 12 modified files (integration + bug fixes)
- ~800 lines of production code
- ~450 lines of tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Groups all atProto-related code under internal/atproto/ for better
code organization:
internal/
├── atproto/
│ ├── lexicon/ # Protocol definitions
│ └── jetstream/ # Firehose consumer
├── core/ # Business logic
└── db/ # Persistence
Changes:
- Moved internal/jetstream/ → internal/atproto/jetstream/
- Updated import paths in cmd/server/main.go
- Updated import paths in all test files
All tests passing:
✅ Unit tests
✅ Integration tests
✅ E2E tests
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Addresses PR review feedback with security, validation, and reliability improvements.
## Security & Validation Improvements
- Add lexicon-compliant error types (InvalidHandle, WeakPassword, etc.)
- Implement official atProto handle validation per spec
- Normalizes to lowercase before validation
- Validates TLD restrictions (.local, .onion, etc. disallowed)
- Max 253 char length enforcement
- Reference: https://atproto.com/specs/handle
- Add password validation (min 8 chars)
- Protects PDS from spam by malicious third-party clients
- PDS remains authoritative on final acceptance
- Add HTTP client timeout (10s) to prevent hanging on slow PDS
- Map service errors to proper XRPC error responses with correct status codes
## Test Reliability Improvements
- Replace fixed time.Sleep() with retry-with-timeout pattern
- Inline retry loops with 500ms polling intervals
- Configurable deadlines per test scenario (10-15s)
- 2x faster test execution on fast systems
- More reliable on slow CI environments
- Add E2E test database setup helper
- Fix test expectations to match new error messages
## Architecture Documentation
- Add TODO comments for future improvements:
- Race condition in Jetstream consumer (sync.Once needed)
- DID→PDS URL resolution via PLC directory for federation
- Document that current implementation works for local dev
- Mark federation support as future enhancement
## Files Changed
New files:
- internal/core/users/errors.go - Domain error types
- tests/e2e/user_signup_test.go - Full E2E test coverage
- internal/atproto/lexicon/social/coves/actor/signup.json - Lexicon spec
- docs/E2E_TESTING.md - E2E testing guide
- internal/jetstream/user_consumer.go - Event consumer
- tests/integration/jetstream_consumer_test.go - Consumer tests
- tests/integration/user_test.go - User service tests
Modified:
- internal/core/users/service.go - Enhanced validation + HTTP timeout
- internal/api/routes/user.go - Lexicon error mapping
- tests/integration/user_test.go - Updated test expectations
## Test Results
✅ All unit/integration tests pass
✅ Full E2E test suite passes (10.3s)
✅ Validates complete signup flow: XRPC → PDS → Jetstream → AppView → PostgreSQL
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements a minimal, production-ready user management system for Coves
with atProto DID-based identity and comprehensive security improvements.
## Core Features
- atProto-compliant user model (DID + handle)
- Single clean migration (001_create_users_table.sql)
- XRPC endpoint: social.coves.actor.getProfile
- Handle-based authentication (resolves handle → DID)
- PostgreSQL AppView indexing
## Security & Performance Fixes
- **Rate limiting**: 100 req/min per IP (in-memory middleware)
- **Input validation**: atProto handle regex validation
- Alphanumeric + hyphens + dots only
- No consecutive hyphens, must start/end with alphanumeric
- 1-253 character length limit
- **Database constraints**: Proper unique constraint error handling
- Clear error messages for duplicate DID/handle
- No internal details leaked to API consumers
- **Performance**: Removed duplicate DB checks (3 calls → 1 call)
## Breaking Changes
- Replaced email/username model with DID/handle
- Deleted legacy migrations (001, 005)
- Removed old repository and service test files
## Architecture
- Repository: Parameterized queries, context-aware
- Service: Business logic with proper validation
- Handler: Minimal XRPC implementation
- Middleware: Rate limiting for public endpoints
## Testing
- Full integration test coverage (4 test suites, all passing)
- Duplicate creation validation tests
- Handle format validation (9 edge cases)
- XRPC endpoint tests (success/error scenarios)
## Documentation
- Updated TESTING_SUMMARY.md with .test handle convention
- Added TODO for federated PDS support
- RFC3339 timestamp formatting
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Consolidate all test and development configuration into a single source
of truth (.env.dev) for cleaner, more maintainable setup.
Changes:
- Remove obsolete .env.test and .env.test.example files
- Update Makefile to load .env.dev variables automatically via include
- Simplify test commands (no more bash subshells or complex sourcing)
- Update integration tests to read config from environment variables
- Rewrite TESTING_SUMMARY.md with current unified approach
- Update LOCAL_DEVELOPMENT.md to reference single config file
Benefits:
- Single source of truth for all configuration
- Simpler test execution: just `make test`
- Isolated test DB (port 5434) separate from dev (port 5433)
- Better documentation and developer experience
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
**Simplified Configuration:**
- Test database credentials now in .env.dev (single source of truth)
- docker-compose.dev.yml uses env vars for test DB (POSTGRES_TEST_*)
- Makefile sources .env.dev for all test commands
- No need for separate .env.test file
**Removed:**
- run-tests.sh - Redundant, use `make test` instead
**Benefits:**
- All local dev config in one place (.env.dev)
- Less mental overhead (dev + test in same file)
- Consistent variable usage throughout stack
- Simpler developer onboarding
Usage:
- `make test` - Run all tests (handles DB automatically)
- All test config in .env.dev under "Test Database Configuration"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major cleanup now that PDS handles all repository operations:
**Removed:**
- internal/core/repository/ - Repository domain logic (PDS handles this)
- internal/db/postgres/repository_repo.go - Repository database operations
- internal/api/handlers/repository_handler.go - Repository API handlers
- internal/api/routes/repository.go - Repository routes
- tests/integration/repository_test.go - Repository integration tests
- Migrations 002, 003, 004 - Repository/CAR storage tables
- internal/db/local_dev_db_compose/ - Separate dev database setup
- internal/db/test_db_compose/ - Separate test database setup
**Unified:**
- docker-compose.dev.yml now includes PostgreSQL + PDS + optional test DB
- All database management moved to Makefile commands
- Consistent use of .env.dev variables throughout
**Updated:**
- cmd/server/main.go - Simplified to only use user service
- Makefile - All-in-one commands (dev-up starts both PostgreSQL + PDS)
- Added db-migrate, db-reset, test commands using Docker profiles
**Architecture:**
- PDS: Self-contained with SQLite + CAR files (port 3001)
- PostgreSQL: Only for Coves AppView indexing (port 5433)
- Test DB: Available via --profile test (port 5434)
- Single source of truth: docker-compose.dev.yml + .env.dev
Commands:
- `make dev-up` - Start PostgreSQL + PDS
- `make test` - Start test DB + run tests
- `make db-migrate` - Run migrations
- `make db-shell` - Open psql shell
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add docker-compose.dev.yml with Bluesky PDS (port 3001)
- Add .env.dev with development configuration
- Add Makefile with convenient dev commands (help, dev-up, dev-down, etc.)
- Add comprehensive docs/LOCAL_DEVELOPMENT.md guide
- Update CLAUDE.md and ATPROTO_GUIDE.md with correct architecture
- Remove custom carstore implementation (PDS handles this)
- Remove internal/atproto/repo wrapper (not needed)
- Add feed lexicon schemas (getAll, getCommunity, getTimeline)
- Update post lexicons to remove getFeed (replaced by feed queries)
- Update PROJECT_STRUCTURE.md to reflect new architecture
Architecture:
- PDS is self-contained with internal SQLite + CAR storage
- PostgreSQL database only used by Coves AppView for indexing
- AppView subscribes directly to PDS firehose (no relay needed for local dev)
- PDS runs on port 3001 to avoid conflicts with production PDS on 3000
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace single moderationConfig with union type supporting both moderator and sortition variants
- Add $type discriminator field following atProto patterns
- Separate tribunal-specific fields (tribunalThreshold, jurySize) to sortition variant only
- Update test files to use new union structure with proper $type fields
- Ensure type safety: only sortition communities can configure tribunal settings
This change improves the lexicon design by:
- Following atProto best practices for discriminated unions
- Providing clear separation between moderation types
- Enabling future extensibility for new moderation approaches
- Maintaining backwards compatibility through the union pattern
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add 35 test data files covering all lexicon record types
- Actor records: block, membership, preferences, profile, saved, subscription
- Community records: moderator, profile, rules, wiki
- Interaction records: comment, share, tag
- Moderation records: ruleProposal, tribunalVote, vote
- Post records: post validation
- Fix lexicon schema issues:
- Add 'handle' format to actor profile
- Fix typo in community profile moderation type
- Add required $type field to interaction comments
- Add minItems constraint to tag arrays
- Fix enum values in moderation schemas
- Improve validate-lexicon tool:
- Better number handling to prevent float64 conversion issues
- Add json.Number support for accurate integer validation
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add internal/validation/lexicon.go with ValidateLexiconData function
- Create validate-lexicon CLI tool for testing lexicon schemas
- Add comprehensive test suite with valid and invalid test cases
- Include test data for actors, communities, posts, interactions, and moderation
- Replace shell-based validation script with Go implementation
- Support for complex validation including enums, unions, and references
This provides a robust foundation for validating atProto lexicon data
in the Coves platform, ensuring data integrity and type safety.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add comprehensive DOMAIN_KNOWLEDGE.md documenting Coves platform concepts
- Update CLAUDE.md with improved development guidelines
- Enhance actor preferences and subscription lexicon schemas
- Improve post retrieval and feed functionality with better tag support
- Update create-pr command documentation
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major architectural improvements to the post lexicon system:
- Unified 5 separate post types into single record with postType discriminator
- Moved tags from author-created content to community interactions (following Bluesky pattern)
- Added tagCounts to post stats and viewer tags to viewerState
- Cleaned up legacy fields (removed nsfw boolean, use contentLabels)
- Simplified embedType enum (image-gallery → image)
- Updated federation schema to use specific platform names
- Clarified title field as optional for certain post types
- Support for up to 8 images in image embeds
This change enables:
- Simpler codebase with single post record type
- Filtering by post type(s) at query level
- Community-driven tagging system
- Consistent embed handling across all post types
- Better federation support with originalAuthor field
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major architectural improvements to the post lexicon system:
- Unified 5 separate post types into single record with postType discriminator
- Moved tags from author-created content to community interactions (following Bluesky pattern)
- Added tagCounts to post stats and viewer tags to viewerState
- Cleaned up legacy fields (removed nsfw boolean, use contentLabels)
- Simplified embedType enum (image-gallery → image)
- Updated federation schema to use specific platform names
- Clarified title field as optional for certain post types
- Support for up to 8 images in image embeds
This change enables:
- Simpler codebase with single post record type
- Filtering by post type(s) at query level
- Community-driven tagging system
- Consistent embed handling across all post types
- Better federation support with originalAuthor field
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed typo "filesred" → "files" in validate-lexicon/main.go
- Added validate-lexicon binary to .gitignore and removed from git
- Updated facet schema to include required $type fields for AT Protocol compatibility
- Removed duplicate mentions field from microblog.json (use facets instead)
- Added comprehensive facet tests covering UTF-8 byte counting and all feature types
- Fixed lexicon validation test to reference correct schema names
- Added detailed facet documentation with UTF-8 byte counting examples
The facet implementation now follows AT Protocol standards with proper $type
fields for each feature (mention, link, bold, italic, strikethrough, spoiler).
All byte indices use UTF-8 encoding for cross-platform consistency.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace separate markup/mention/link lexicons with unified facet approach
- Use byte-indexed positioning (byteStart/byteEnd) for text annotations
- Support overlapping features: bold, italic, strikethrough, spoiler, mention, link
- Add native support for community mentions with \! prefix
- Update all schemas to use *Facets fields instead of *Markup
- Align with AT Protocol standards for better federation compatibility
BREAKING CHANGE: All richtext markup fields renamed to facets
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit adds a complete set of lexicon definitions required for the
core functionality of the Coves social platform, following AT Protocol
best practices.
Added 29 new lexicon files across 4 namespaces:
Actor namespace (7 files):
- blockUser.json: Block another user
- getProfile.json: Retrieve user profile with stats
- preferences.json: User preferences record type
- saveItem.json: Save posts/comments for later
- unblockUser.json: Unblock a previously blocked user
- unsaveItem.json: Remove saved items
- updateProfile.json: Update user profile information
Community namespace (10 files):
- create.json: Create a new community
- get.json: Retrieve community details
- getMembers.json: List community members
- getSubscribers.json: List community subscribers
- list.json: List communities with filtering
- moderator.json: Moderator assignment record type
- search.json: Search communities by text
- subscribe.json: Subscribe to a community
- unsubscribe.json: Unsubscribe from a community
- update.json: Update community settings
Post namespace (6 files):
- create.json: Create posts (text, image, video, article, microblog)
- delete.json: Delete a post
- get.json: Retrieve a single post
- getFeed.json: Get post feeds with sorting options
- search.json: Search posts by text
- update.json: Update post content
Interaction namespace (4 files):
- createComment.json: Comment on posts/comments
- deleteComment.json: Delete comments
- createVote.json: Vote on posts/comments
- deleteVote.json: Remove votes
Bug fixes:
- Fixed duplicate 'createdAt' in membership.json required array
- Corrected getSaved.json type from 'procedure' to 'query'
All lexicons follow the established patterns:
- Queries for read operations
- Procedures for write operations
- Proper error definitions
- Consistent parameter naming
- Support for pagination where appropriate
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove blob storage from repository interface and implementation
- Add GORM integration for better database management
- Integrate Indigo's carstore for proper CAR file storage
- Update repository wrapper to use external blockstore
- Add comprehensive test infrastructure with test database setup
- Add test environment configuration example
- Update dependencies to include required Indigo and IPFS packages
- Fix repository record operations to work without inline value storage
- Add proper error handling and migrations for carstore integration
This refactoring aligns the repository storage with ATProto standards by:
1. Using Indigo's carstore for efficient CAR file management
2. Removing custom blob storage in favor of standard IPFS blockstore
3. Improving test infrastructure for better integration testing
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implements full-stack user functionality following layered architecture:
- User domain models and validation
- RESTful API endpoints (GET /users/{id}, POST /users)
- PostgreSQL database with migrations and indexes
- Repository pattern with interfaces
- Service layer with business logic
- Integration tests and error handling
- Docker Compose for local development
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>