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.
Use ON CONFLICT DO NOTHING for comment indexing to handle race
conditions from duplicate Jetstream events (at-least-once delivery).
This eliminates duplicate key constraint errors when the same event
is delivered multiple times.
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add optional authentication support to the Discover feed endpoint so
authenticated users can see their existing likes/votes on posts.
Changes:
- Add voteService and OptionalAuth middleware to Discover handler
- Extract shared PopulateViewerVoteState helper to reduce duplication
- Add FeedPostProvider interface with GetPost() method to all feed types
- Add comprehensive integration tests for viewer vote state
The Discover feed remains public (unauthenticated users can still view it),
but authenticated users now receive their vote state (vote direction and URI)
on each post, matching the behavior of Timeline and Community Feed handlers.
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement PutRecord in PDS client with swapRecord CID validation:
- Add ErrConflict error type for HTTP 409 responses
- Add PutRecord method to Client interface with optimistic locking
- Map 409 status to ErrConflict in wrapAPIError
Migrate UpdateComment to use PutRecord:
- Use existingRecord.CID as swapRecord for concurrent modification detection
- Add ErrConcurrentModification error type in comments package
- Return proper error when PDS detects CID mismatch
Testing:
- Add PutRecord unit tests (success, conflict, typed errors)
- Add PutRecord to mockPDSClient for unit test compatibility
- Add integration test for concurrent modification detection
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement comment deletion that preserves thread structure by keeping
tombstone records with blanked content instead of hiding comments entirely.
Features:
- Add deletion_reason enum (author, moderator) and deleted_by column
- Blank content on delete but preserve threading references
- Include deleted comments in thread queries as "[deleted]" placeholders
- Add RepositoryTx interface for atomic delete + count updates
- Add validation for deletion reason constants
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add SoftDeleteWithReasonTx to mockCommentRepo implementing RepositoryTx.
Update SoftDeleteWithReason to validate deletion reason and delegate
to the Tx method.
Update test for deleted comments to verify they appear as placeholders
with IsDeleted=true instead of being filtered out.
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace inline SQL in deleteCommentAndUpdateCounts with call to
SoftDeleteWithReasonTx via type assertion to RepositoryTx interface.
This eliminates duplicate deletion logic between consumer and repo
while maintaining atomic transaction for delete + count updates.
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add buildDeletedCommentView method that creates placeholder views
for deleted comments with blanked content but preserved threading.
Update buildThreadViews to include deleted comments instead of
skipping them, enabling child comments to remain visible with
their parent showing "[deleted]".
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add SoftDeleteWithReason and SoftDeleteWithReasonTx methods that:
- Blank content, facets, embed, and labels on deletion
- Set deletion_reason and deleted_by metadata
- Validate deletion reason is author or moderator
- Support optional transaction for atomic operations
- Return rows affected for idempotency checks
Update all thread queries to include deleted comments by removing
deleted_at IS NULL filter, preserving thread structure.
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add SoftDeleteWithReason to Repository interface for content-blanking
soft deletes that preserve thread structure.
Add RepositoryTx interface with SoftDeleteWithReasonTx method for
transactional operations, enabling atomic delete + count updates
in the Jetstream consumer.
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add IsDeleted, DeletionReason, and DeletedAt fields to CommentView
for rendering deleted comment placeholders in thread views.
Frontend can display "[deleted]" or "[removed by moderator]" based
on the deletion_reason field.
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add DeletionReasonAuthor and DeletionReasonModerator constants.
Add DeletionReason and DeletedBy fields to Comment struct for
tracking who deleted a comment and why.
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add migration 021 that:
- Creates deletion_reason enum type (author, moderator)
- Adds deletion_reason and deleted_by columns to comments table
- Backfills existing deleted comments as author-deleted
- Removes deleted_at IS NULL filter from thread indexes to preserve structure
- Adds indexes for deletion_reason and deleted_by for moderation queries
馃 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>