A community based topic aggregation platform built on atproto

refactor(votes): remove Service interface and write operation types

Remove unused Service interface that declared CreateVote/DeleteVote
methods. These write operations are no longer supported by the AppView.

Remove request/response types that were only used by deleted handlers:
- CreateVoteRequest
- CreateVoteResponse
- DeleteVoteRequest

Keep only types needed for Jetstream indexing:
- Vote (AppView database model)
- VoteRecord (atProto record structure)
- StrongRef (AT-URI + CID reference)
- Repository interface (indexing operations)

Add architecture documentation explaining client-direct write pattern.

Before: 154 lines
After: 99 lines (36% reduction)

+15 -54
+5 -23
internal/core/votes/interfaces.go
··· 2 2 3 3 import "context" 4 4 5 - // Service defines the business logic interface for votes 6 - // Coordinates between Repository, user PDS, and vote validation 7 - type Service interface { 8 - // CreateVote creates a new vote or toggles an existing vote 9 - // Flow: Validate -> Check existing vote -> Handle toggle logic -> Write to user's PDS -> Return URI/CID 10 - // AppView indexing happens asynchronously via Jetstream consumer 11 - // Toggle logic: 12 - // - No vote -> Create vote 13 - // - Same direction -> Delete vote (toggle off) 14 - // - Different direction -> Delete old + Create new (toggle direction) 15 - CreateVote(ctx context.Context, voterDID string, userAccessToken string, req CreateVoteRequest) (*CreateVoteResponse, error) 16 - 17 - // DeleteVote removes a vote from a post/comment 18 - // Flow: Find vote -> Verify ownership -> Delete from user's PDS 19 - // AppView decrements vote count asynchronously via Jetstream consumer 20 - DeleteVote(ctx context.Context, voterDID string, userAccessToken string, req DeleteVoteRequest) error 21 - 22 - // GetVote retrieves a user's vote on a specific subject 23 - // Used to check vote state before creating/toggling 24 - GetVote(ctx context.Context, voterDID string, subjectURI string) (*Vote, error) 25 - } 26 - 27 5 // Repository defines the data access interface for votes 28 6 // Used by Jetstream consumer to index votes from firehose 7 + // 8 + // Architecture: Votes are written directly by clients to their PDS using 9 + // com.atproto.repo.createRecord/deleteRecord. This AppView indexes votes 10 + // from Jetstream for aggregation and querying. 29 11 type Repository interface { 30 12 // Create inserts a new vote into the AppView database 31 13 // Called by Jetstream consumer after vote is created on PDS ··· 38 20 39 21 // GetByVoterAndSubject retrieves a user's vote on a specific subject 40 22 // Used to check existing vote state 41 - GetByVoterAndSubject(ctx context.Context, voterDID string, subjectURI string) (*Vote, error) 23 + GetByVoterAndSubject(ctx context.Context, voterDID, subjectURI string) (*Vote, error) 42 24 43 25 // Delete soft-deletes a vote (sets deleted_at) 44 26 // Called by Jetstream consumer after vote is deleted from PDS
+10 -31
internal/core/votes/vote.go
··· 7 7 // Vote represents a vote in the AppView database 8 8 // Votes are indexed from the firehose after being written to user repositories 9 9 type Vote struct { 10 - ID int64 `json:"id" db:"id"` 10 + CreatedAt time.Time `json:"createdAt" db:"created_at"` 11 + IndexedAt time.Time `json:"indexedAt" db:"indexed_at"` 12 + DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"` 11 13 URI string `json:"uri" db:"uri"` 12 14 CID string `json:"cid" db:"cid"` 13 15 RKey string `json:"rkey" db:"rkey"` 14 16 VoterDID string `json:"voterDid" db:"voter_did"` 15 17 SubjectURI string `json:"subjectUri" db:"subject_uri"` 16 18 SubjectCID string `json:"subjectCid" db:"subject_cid"` 17 - Direction string `json:"direction" db:"direction"` // "up" or "down" 18 - CreatedAt time.Time `json:"createdAt" db:"created_at"` 19 - IndexedAt time.Time `json:"indexedAt" db:"indexed_at"` 20 - DeletedAt *time.Time `json:"deletedAt,omitempty" db:"deleted_at"` 19 + Direction string `json:"direction" db:"direction"` 20 + ID int64 `json:"id" db:"id"` 21 21 } 22 22 23 - // CreateVoteRequest represents input for creating a new vote 24 - // Matches social.coves.interaction.createVote lexicon input schema 25 - type CreateVoteRequest struct { 26 - Subject string `json:"subject"` // AT-URI of post/comment 27 - Direction string `json:"direction"` // "up" or "down" 28 - } 29 - 30 - // CreateVoteResponse represents the response from creating a vote 31 - // Matches social.coves.interaction.createVote lexicon output schema 32 - type CreateVoteResponse struct { 33 - URI string `json:"uri"` // AT-URI of created vote record 34 - CID string `json:"cid"` // CID of created vote record 35 - Existing *string `json:"existing,omitempty"` // AT-URI of existing vote if updating 36 - } 37 - 38 - // DeleteVoteRequest represents input for deleting a vote 39 - // Matches social.coves.interaction.deleteVote lexicon input schema 40 - type DeleteVoteRequest struct { 41 - Subject string `json:"subject"` // AT-URI of post/comment 42 - } 43 - 44 - // VoteRecord represents the actual atProto record structure written to PDS 23 + // VoteRecord represents the atProto record structure indexed from Jetstream 45 24 // This is the data structure that gets stored in the user's repository 46 25 type VoteRecord struct { 47 - Type string `json:"$type"` 48 - Subject StrongRef `json:"subject"` 49 - Direction string `json:"direction"` // "up" or "down" 50 - CreatedAt string `json:"createdAt"` 26 + Type string `json:"$type"` 27 + Subject StrongRef `json:"subject"` 28 + Direction string `json:"direction"` // "up" or "down" 29 + CreatedAt string `json:"createdAt"` 51 30 } 52 31 53 32 // StrongRef represents a strong reference to a record (URI + CID)