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 full user, community, and record metadata to comment query API responses.
Completes lexicon compliance for rich comment content including facets, embeds, and labels.
Changes to comment service:
1. **Batch User Hydration**
- Integrate GetByDIDs() for efficient author loading
- Collect all unique author DIDs from comment tree
- Single batch query prevents N+1 problem
- Populate AuthorView.Handle from users table
2. **Community Metadata Hydration**
- Fetch community for each post in response
- Populate community name with priority: DisplayName > Name > Handle > DID
- Construct avatar blob URL: {pds}/xrpc/com.atproto.sync.getBlob?did={did}&cid={cid}
- Graceful fallback if community not found
3. **Rich Text Deserialization**
- Deserialize contentFacets from JSONB (mentions, links, formatting)
- Deserialize embed from JSONB (images, quoted posts)
- Deserialize labels from JSONB (NSFW, spoilers, warnings)
- Populate both CommentView fields and complete record
- Graceful error handling (log warnings, don't fail requests)
4. **Complete Record Population**
- buildCommentRecord() now fully populates all fields
- Record includes: facets, embed, labels per lexicon
- Verbatim atProto record for full compatibility
API Response Enhancements:
- CommentView.ContentFacets: Rich text annotations
- CommentView.Embed: Embedded images or quoted posts
- CommentView.Record: Complete atProto record with all nested fields
- CommunityRef.Name: User-friendly community name
- CommunityRef.Avatar: Full blob URL for avatar image
- AuthorView.Handle: Correct handle from users table
Error Handling:
- All JSON parsing errors logged as warnings
- Requests succeed even if rich content parsing fails
- Missing users/communities handled gracefully
- Maintains API reliability with graceful degradation
Performance:
- Batch user loading prevents N+1 queries
- Single community query per response (acceptable for alpha)
- JSON deserialization happens in-memory (fast)
- No additional database queries for rich content
Lexicon Compliance:
- ✅ social.coves.community.comment.defs#commentView
- ✅ social.coves.community.post.get#authorView
- ✅ social.coves.community.post.get#communityRef
- ✅ All required fields populated, optional fields handled correctly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add GetByDIDs repository method to fetch multiple users in a single query,
preventing N+1 performance issues when hydrating comment authors in threads.
Changes:
- Add GetByDIDs() method to UserRepository interface
- Implement batch query using PostgreSQL ANY() with pq.Array type conversion
- Returns map[string]*User for O(1) lookups by DID
- Gracefully handles missing users (no error, just excluded from result map)
Performance impact:
- Before: N separate queries (1 per comment author)
- After: 1 batch query for all authors in thread
- ~10-100x faster for threads with many unique authors
Implementation uses parameterized query with PostgreSQL array support:
```sql
SELECT did, handle, pds_url, created_at, updated_at
FROM users WHERE did = ANY($1)
```
This is a foundational optimization for Phase 2C metadata hydration.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive documentation of all PR review fixes applied to comment voting
system before production deployment.
Documentation added:
- Phase 2B Production Hardening section (165+ lines)
- Critical issues fixed (3): post reconciliation, error wrapping, deferred work
- Important issues fixed (5): nil pointers, unit tests, documentation, race conditions, auth
- Optimizations implemented (2): query optimization, magic number constants
- Production readiness checklist with 8 categories (all ✅)
Test coverage updates:
- Updated integration test count: 35 tests (was 30)
- Added unit test stats: 22 tests with 32 scenarios, 94.3% coverage
- Updated total test count: 57 tests (was 30)
- Added test execution commands for both integration and unit tests
Technical details documented:
- Post comment count reconciliation implementation (~95 lines)
- Transaction-based atomic updates pattern
- Nil pointer safety with explicit copies
- Fixed timestamps for test reliability
- Collection-based routing for multi-table updates
- Batch query optimization details
- Authentication architecture and middleware validation
Phase 2C roadmap:
- Clarified remaining work items (display names, avatars, rich text)
- Explained lexicon compliance vs feature completeness
- Estimated effort (~1-2 hours)
This ensures all Phase 2B hardening work is documented for future reference and
production deployment validation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add 22 test functions with 32 test scenarios achieving 94.3% code coverage of the
comment service layer. Uses manual mocks (no dependencies) following existing patterns.
Test coverage breakdown:
GetComments() validation:
- Valid request with all required parameters
- Missing PostURI validation
- Invalid sort parameter validation
- Negative limit validation
- Negative depth validation
- Limit exceeding maximum validation
GetComments() functionality:
- Empty result set handling
- Viewer authentication state (authenticated vs unauthenticated)
- Nested replies with hasMore flag
- Multiple comments with correct ordering
- Repository error propagation
buildThreadViews():
- Flat structure (all root comments, no nesting)
- Single-level nesting (comments with direct replies)
- Multi-level nesting (recursive reply chains)
- Depth limiting (respects maxDepth parameter)
- Reply limiting (respects maxRepliesPerParent)
- Empty input handling
buildCommentView():
- Complete comment with all fields populated
- Viewer state hydration (vote direction + voteUri)
- Missing author handling (returns nil)
- Nil input handling
Implementation details:
- Manual mock repositories (mockCommentRepo, mockUserRepo, mockPostRepo, mockCommunityRepo)
- No external dependencies (testify/mock, gomock, etc.)
- Fast execution (~10ms, no database required)
- Comprehensive edge case coverage
This addresses PR review feedback requesting unit test coverage for the service layer
to complement existing integration tests.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add end-to-end integration tests validating comment voting functionality including
vote creation, count updates, and viewer state hydration.
Test coverage:
- TestCommentVote_CreateAndUpdate: Vote count increments and viewer state
- Upvote increments upvote_count and score
- Downvote increments downvote_count and decreases score
- Vote changes properly update counts (up→down, removal)
- TestCommentVote_ViewerState: Viewer-specific state in API responses
- Authenticated viewer sees their vote state (direction + voteUri)
- Authenticated viewer without vote sees null viewer state
- Unauthenticated requests have no viewer object
All tests use fixed timestamps (time.Date) instead of time.Now() to prevent race
conditions and flaky tests. This ensures deterministic test behavior across runs.
Test data setup:
- Uses Jetstream event consumers for realistic indexing flow
- Creates test users, communities, posts, comments, and votes
- Validates full round-trip: event → indexing → query API → response
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove unused cid and created_at columns from batch vote query. These fields were
being fetched but never used in the result mapping.
Changes:
- Remove cid and created_at from SELECT clause
- Keep only subject_uri, direction, and uri (all actively used)
- Maintain same query performance characteristics
This reduces memory usage and network overhead for viewer state hydration without
changing behavior. Each comment query fetches vote state for potentially hundreds
of comments, so column reduction has meaningful impact at scale.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>