code
Clone this repository
https://tangled.org/bretton.dev/coves
git@knot.bretton.dev:bretton.dev/coves
For self-hosted knots, clone URLs may differ based on your setup.
Add 4 test files covering full post creation flow:
1. post_creation_test.go - Service layer tests (11 subtests)
- Happy path with DID and handle resolution
- Validation: missing fields, invalid formats, length limits
- Content label validation (nsfw, spoiler, violence)
- Repository tests: create, duplicate URI handling
2. post_e2e_test.go - TRUE end-to-end test
- Part 1: Write-forward to live PDS
- Part 2: Real Jetstream WebSocket consumption
- Verifies complete cycle: HTTP → PDS → Jetstream → AppView DB
- Tests ~1 second indexing latency
- Requires live PDS and Jetstream services
3. post_handler_test.go - Handler security tests (10+ subtests)
- Reject client-provided authorDid (impersonation prevention)
- Require authentication (401 on missing token)
- Request body size limit (1MB DoS prevention)
- Malformed JSON handling
- All 4 at-identifier formats (DIDs, canonical, @-prefixed, scoped)
- Unicode/emoji support
- SQL injection prevention
4. helpers.go - Test utilities
- JWT token generation for test users
All tests passing. Coverage includes security, validation,
business logic, and real-time indexing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Wire up post creation feature in main server:
1. Initialize post service
- Create post repository (PostgreSQL)
- Create post service with community service integration
- Configure with default PDS URL
2. Register XRPC routes
- POST /xrpc/social.coves.post.create
- Requires OAuth authentication via middleware
3. Start Jetstream consumer for posts
- WebSocket URL: ws://localhost:6008/subscribe
- Collection filter: social.coves.post.record
- Runs in background goroutine
- Indexes CREATE operations (UPDATE/DELETE deferred)
Environment variables:
- POST_JETSTREAM_URL: Override default Jetstream endpoint
Initialization order ensures postRepo created before consumer.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Export community service methods for post creation:
- EnsureFreshToken() - Auto-refresh PDS tokens before write operations
- GetByDID() - Direct repository access for post service
These methods enable posts service to:
1. Fetch community from AppView by DID
2. Ensure fresh PDS credentials before writing to community repo
3. Use community's access token for PDS write-forward
Changes:
- Made ensureFreshToken() public as EnsureFreshToken()
- Added GetByDID() wrapper for repository access
- No functional changes, just visibility
Supports write-forward architecture where posts are written to
community's PDS repository using community's credentials.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add PostEventConsumer for AppView indexing:
- Listen for social.coves.post.record CREATE events via WebSocket
- Parse post records from Jetstream firehose
- Index posts into AppView database
- Handle UPDATE/DELETE deferred until those features exist
Security validation:
- Verify repository DID matches community DID (prevents fake posts)
- Verify community exists in AppView (foreign key integrity)
- Verify author exists in AppView (foreign key integrity)
- Idempotent indexing (safe for Jetstream replays)
Add PostJetstreamConnector:
- Dedicated WebSocket connector for post events
- Collection filter: social.coves.post.record
- Separate from CommunityJetstreamConnector (different event types)
Posts are indexed with ~1 second latency from PDS write.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add POST /xrpc/social.coves.post.create endpoint:
- Authentication required via OAuth middleware
- Validate request body size (1MB limit for DoS prevention)
- Validate at-identifier format for community field
- Reject client-provided authorDid (security)
- Set authorDid from authenticated JWT
- Error mapping for lexicon-compliant responses
Handler security features:
- Body size limit prevents DoS
- Author impersonation prevented
- All 4 at-identifier formats supported
- Proper error codes (400, 401, 403, 404, 500)
Route registration integrates with auth middleware.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add migration 011: posts table with indexes
- Add foreign keys to users and communities
- Add indexes for common query patterns (community feed, author, score)
- Add PostgreSQL repository implementation
- Add Create() and GetByURI() methods
- Add JSON serialization for facets, embeds, labels
Posts table supports:
- AT-URI, CID, rkey for atProto compliance
- Title, content, facets, embed, labels
- Vote counts and score (denormalized for performance)
- Soft delete with deleted_at timestamp
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>