A community based topic aggregation platform built on atproto

feat(voting): implement complete voting system with atProto integration master

Implements a production-ready voting system following atProto write-forward architecture with bidirectional voting (upvote/downvote) for forum-style content ranking. ## Key Features - **atProto Write-Forward Architecture**: AppView → PDS → Jetstream → AppView - **User-Owned Votes**: Votes stored in user repositories (at://user_did/...) - **Strong References**: URI + CID for content integrity - **Toggle Logic**: Same direction deletes, opposite direction switches - **Real-time Indexing**: Jetstream consumer with atomic count updates - **PDS-as-Source-of-Truth**: Queries PDS directly to prevent race conditions ## Components Added ### Domain Layer (internal/core/votes/) - Vote model with strong reference support - Service layer with PDS integration and toggle logic - Repository interface for data access - Domain errors (ErrVoteNotFound, ErrSubjectNotFound, etc.) - Comprehensive service unit tests (5 tests, all passing) ### Data Layer (internal/db/postgres/) - Vote repository implementation with idempotency - Comprehensive unit tests (11 tests covering all CRUD + edge cases) - Migration #013: Create votes table with indexes and constraints - Migration #014: Remove FK constraint (critical race condition fix) ### API Layer (internal/api/) - CreateVoteHandler: POST /xrpc/social.coves.interaction.createVote - DeleteVoteHandler: POST /xrpc/social.coves.interaction.deleteVote - Shared error handler (handlers/errors.go) for consistency - OAuth authentication required on all endpoints ### Jetstream Integration (internal/atproto/jetstream/) - VoteEventConsumer: Indexes votes from firehose - Atomic transaction: vote insert + post count update - Security validation: DID format, direction, strong references - Idempotent operations for firehose replays ### Testing (tests/integration/) - E2E test with simulated Jetstream (5 scenarios, <100ms) - TRUE E2E test with live PDS + Jetstream (1.3s, all passing) - Verified complete data flow: API → PDS → Jetstream → AppView ## Critical Fixes ### Fix #1: Toggle Race Condition **Problem**: Querying AppView (eventually consistent) caused duplicate votes **Solution**: Query PDS directly via com.atproto.repo.listRecords **Impact**: Eliminates data corruption, adds ~75ms latency (acceptable) ### Fix #2: Voter Validation Race **Problem**: Vote events arriving before user events caused permanent vote loss **Solution**: Removed FK constraint, allow out-of-order indexing **Migration**: 014_remove_votes_voter_fk.sql **Security**: Maintained via PDS authentication + DID format validation ### Fix #3: PDS Pagination **Problem**: Users with >100 votes couldn't toggle/delete votes **Solution**: Full pagination with reverse=true (newest first) **Capacity**: Supports up to 5000 votes per user (50 pages × 100) ## Technical Implementation **Lexicon**: social.coves.interaction.vote (record type) - subject: StrongRef (URI + CID) - direction: "up" | "down" - createdAt: datetime **Database Schema**: - Unique constraint: one active vote per user per subject - Soft delete support (deleted_at) - DID format constraint (removed FK for race condition fix) - Indexes: subject_uri, voter_did+subject_uri, voter_did **Service Logic**: - Validates subject exists before creating vote - Queries PDS for existing vote (source of truth) - Implements toggle: same → delete, different → switch - Writes to user's PDS with strong reference **Consumer Logic**: - Listens for social.coves.interaction.vote CREATE/DELETE - Validates: DID format, direction, strong reference - Atomically: indexes vote + updates post counts - Idempotent: ON CONFLICT DO NOTHING, safe for replays ## Test Coverage ✅ Repository Tests: 11/11 passing ✅ Service Tests: 5/5 passing (1 skipped by design) ✅ E2E Simulated: 5/5 passing ✅ E2E Live PDS: 1/1 passing (TRUE end-to-end) ✅ Build: Success **Total**: 22 tests, ~3 seconds ## Architecture Compliance ✅ Write-forward pattern (AppView → PDS → Jetstream → AppView) ✅ Layer separation (Handler → Service → Repository → Database) ✅ Strong references for content integrity ✅ Eventual consistency with out-of-order event handling ✅ Idempotent operations for distributed systems ✅ OAuth authentication on all write endpoints ## Performance - Vote creation: <100ms (includes PDS write) - Toggle operation: ~150ms (includes PDS query + write) - Jetstream indexing: <1 second (real-time) - Database indexes: Optimized for common query patterns ## Security ✅ JWT authentication required ✅ Votes validated against user's PDS repository ✅ DID format validation ✅ Strong reference integrity (URI + CID) ✅ Rate limiting (100 req/min per IP) 🚀 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>