Flick Knowledge Base
Repository docs from .qoder/repowiki
Search, browse, and read the generated project wiki without leaving the repo.
Voting Mechanism
Referenced Files in This Document
vote.schema.tsvote.service.tsvote.controller.tsvote.repo.tsvote.adapter.tsvote.table.tsvote.cache-keys.tspost.schema.tscomment.schema.tsuser.schema.tsuser.repo.tsblock.guard.tsaudit.controller.tsaudit.repo.tsaudit.schema.tsaudit.types.tsaudit-context.tspost.cache-keys.tscomment.cache-keys.tstransactions.tsenv.tsindex.tsapp.ts
Table of Contents
Introduction
This document describes Flick’s voting/upvoting/downvoting system. It covers vote creation, modification, and removal workflows, user permission controls, score calculation, vote weight considerations, reputation impact, schema validation, duplicate vote prevention, rollback mechanisms, real-time updates, leaderboards, trending content calculations, caching strategies, performance optimizations, and conflict resolution. The goal is to provide a comprehensive yet accessible guide for developers and operators integrating or extending the voting system.
Project Structure
The voting subsystem is implemented as a cohesive module under server/src/modules/vote, with supporting infrastructure in the database layer, caching, auditing, and user permission guards. The module integrates with Post and Comment modules to compute scores and maintain caches.
graph TB
subgraph "Server"
VC["VoteController<br/>POST/PATCH/DELETE"]
VS["VoteService<br/>business logic"]
VR["VoteRepo<br/>Read/CachedRead/Write"]
VA["VoteAdapter<br/>DB queries"]
VT["Votes Table<br/>unique(user,target)"]
CK["Vote Cache Keys"]
end
subgraph "Integration"
PR["Post Repo / Schema"]
CR["Comment Repo / Schema"]
UR["User Repo / Schema"]
BG["Block Guard"]
AC["Audit Controller/Repo/Schema/Types"]
end
VC --> VS
VS --> VR
VR --> VA
VA --> VT
VS --> PR
VS --> CR
VS --> UR
VS --> BG
VS --> AC
VR --> CKDiagram sources
vote.controller.tsvote.service.tsvote.repo.tsvote.adapter.tsvote.table.tsvote.cache-keys.tspost.schema.tscomment.schema.tsuser.schema.tsuser.repo.tsblock.guard.tsaudit.controller.tsaudit.repo.tsaudit.schema.tsaudit.types.tsaudit-context.ts
Section sources
vote.controller.tsvote.service.tsvote.repo.tsvote.adapter.tsvote.table.tsvote.cache-keys.tspost.schema.tscomment.schema.tsuser.schema.tsuser.repo.tsblock.guard.tsaudit.controller.tsaudit.repo.tsaudit.schema.tsaudit.types.tsaudit-context.ts
Core Components
- Validation layer: Zod schemas define allowed vote types and target types, ensuring safe parsing of requests.
- Controller: Exposes REST endpoints for creating, updating, and deleting votes after enforcing user context middleware.
- Service: Orchestrates vote lifecycle, permissions, transactional writes, karma updates, audit logging, and cache invalidation.
- Repository: Provides read, cached read, and write operations backed by the adapter.
- Adapter and Table: Drizzle ORM mapping with a unique constraint preventing duplicate votes per user-target pair.
- Caching: Dedicated cache keys and invalidation to keep vote state and related lists fresh.
- Integration: Resolves target author, enforces block relations, updates user karma, and records audit events.
Section sources
vote.schema.tsvote.controller.tsvote.service.tsvote.repo.tsvote.adapter.tsvote.table.tsvote.cache-keys.ts
Architecture Overview
The voting system follows a layered architecture:
- HTTP layer: Express routes guarded by user context middleware.
- Controller: Parses validated input and delegates to service.
- Service: Performs business logic inside a transaction, updates dependent entities, and invalidates caches.
- Persistence: Drizzle ORM with a unique index on (userId, targetType, targetId) to prevent duplicates.
- Caching: Cache keys scoped to user-target combinations and list/version keys for posts/comments.
- Auditing: Centralized audit recording for all vote operations.
sequenceDiagram
participant Client as "Client"
participant Route as "Express Routes"
participant Ctrl as "VoteController"
participant Svc as "VoteService"
participant Tx as "runTransaction"
participant Repo as "VoteRepo"
participant Adp as "VoteAdapter"
participant DB as "DB (unique index)"
participant Cache as "Cache"
participant Audit as "Audit"
Client->>Route : POST/PATCH/DELETE /api/votes
Route->>Ctrl : withRequiredUserContext
Ctrl->>Svc : createVote/patchVote/delete
Svc->>Tx : begin transaction
Tx->>Repo : Write.create/update/delete
Repo->>Adp : insert/update/delete
Adp->>DB : execute SQL
DB-->>Adp : affected row(s)
Adp-->>Repo : result
Repo-->>Svc : result
Svc->>Cache : invalidateWriteCaches(...)
Svc->>Audit : recordAudit(...)
Tx-->>Svc : commit
Svc-->>Ctrl : result
Ctrl-->>Client : HTTP responseDiagram sources
vote.route.tsvote.controller.tsvote.service.tsvote.repo.tsvote.adapter.tstransactions.tsaudit.controller.tsaudit.repo.ts
Detailed Component Analysis
Vote Schema Validation
- Enforces vote type enum (upvote/downvote) and target type enum (post/comment).
- Provides separate schemas for insert and delete operations.
- Used by the controller to parse and validate incoming requests.
Section sources
vote.schema.tsvote.controller.ts
Vote Controller Endpoints
- POST /api/votes: Create a new vote for a post or comment.
- PATCH /api/votes: Change an existing vote from upvote to downvote or vice versa.
- DELETE /api/votes: Remove a vote.
- All endpoints require a valid user context via middleware.
Example endpoint usage:
- Create vote: POST /api/votes with body containing voteType, targetType, targetId.
- Modify vote: PATCH /api/votes with voteType, targetType, targetId.
- Remove vote: DELETE /api/votes with targetType, targetId.
Section sources
vote.route.tsvote.controller.ts
Vote Service Workflows
- Create vote:
- Resolve target author from Post/Comment repositories.
- Enforce block relation between voter and target author.
- Persist vote in a transaction.
- Update target author’s karma (+1 for upvote, -1 for downvote).
- Record audit event.
- Invalidate caches for user-target and related lists.
- Patch vote:
- Fetch existing vote by user-target.
- If same type, short-circuit with message.
- Otherwise, update vote type and adjust karma accordingly.
- Record audit event.
- Invalidate caches.
- Delete vote:
- Remove vote by user-target.
- Adjust karma in opposite direction of original vote.
- Record audit event.
- Invalidate caches.
flowchart TD
Start([Entry]) --> Parse["Parse and validate input"]
Parse --> TxBegin["Begin transaction"]
TxBegin --> FindTarget["Resolve target author via Post/Comment repo"]
FindTarget --> BlockCheck["Assert no block relation"]
BlockCheck --> Op{"Operation"}
Op --> |Create| CreateVote["Insert vote row"]
Op --> |Patch| LoadExisting["Load existing vote"]
LoadExisting --> SameType{"Same vote type?"}
SameType --> |Yes| ShortCircuit["Return existing vote"]
SameType --> |No| UpdateVote["Update vote type"]
Op --> |Delete| DeleteVote["Delete vote by user-target"]
CreateVote --> Karma["Adjust karma (+/- 1)"]
UpdateVote --> Karma
DeleteVote --> Karma
Karma --> Audit["Record audit event"]
Audit --> Invalidate["Invalidate caches"]
Invalidate --> Commit["Commit transaction"]
Commit --> End([Exit])
ShortCircuit --> EndDiagram sources
vote.service.tsvote.adapter.tsuser.repo.tsaudit.controller.ts
Section sources
vote.service.ts
Duplicate Vote Prevention
- Database-level unique index on (userId, targetType, targetId) prevents concurrent duplicate inserts.
- Service also performs a lookup before insert to provide clear errors and avoid unnecessary DB retries.
Section sources
vote.table.tsvote.adapter.tsvote.service.ts
Rollback Mechanisms
- All vote operations run inside a transaction. Any failure during vote persistence, karma update, or audit recording aborts the entire operation.
- Transaction boundaries ensure atomicity across vote state and dependent counters.
Section sources
vote.service.tstransactions.ts
Score Calculation and Reputation Impact
- Karma adjustment:
- Upvote adds 1 to target author’s karma.
- Downvote subtracts 1 from target author’s karma.
- Patch adjusts karma by twice the delta (e.g., switching from downvote to upvote adds 2).
- No explicit score aggregation is implemented in the voting module; downstream consumers (e.g., Post/Comment modules) can compute derived metrics using vote counts or external scoring algorithms.
Section sources
vote.service.tsvote.service.tsvote.service.ts
Real-Time Updates and Leaderboards
- Real-time updates:
- Vote mutations trigger cache invalidation for user-target and related lists.
- Consumers can subscribe to cache changes or poll invalidated keys to refresh UI.
- Leaderboards:
- Not implemented in the voting module; implementers can derive top authors by querying karma and sorting via user repository APIs.
Section sources
vote.service.tspost.cache-keys.tscomment.cache-keys.ts
Trending Content Calculations
- Not implemented in the voting module; implementers can compute trending scores using vote counts, recency decay, and other signals from the Post/Comment modules.
Section sources
post.schema.tscomment.schema.ts
Vote Caching Strategies
- Cache keys:
- vote:user:{userId}:target:{targetId} for per-user-per-target vote lookup.
- Incremental version keys for posts and comments lists to detect changes efficiently.
- Invalidation:
- After mutation, delete per-user-per-target cache and increment list/version keys.
classDiagram
class VoteCacheKeys {
+userIdAndTarget(id, target) string
}
class PostCacheKeys {
+postVersionKey(id) string
+postsListVersionKey() string
}
class CommentCacheKeys {
+postCommentsVersionKey(postId) string
}
VoteCacheKeys <.. PostCacheKeys : "invalidated by"
VoteCacheKeys <.. CommentCacheKeys : "invalidated by"Diagram sources
vote.cache-keys.tspost.cache-keys.tscomment.cache-keys.ts
Section sources
vote.cache-keys.tsvote.service.ts
Permission Controls
- User context enforcement: All vote routes require a logged-in user.
- Block guard: Prevents users from voting on content authored by blocked users.
- Target existence checks: Ensures target exists before creating/modifying/deleting votes.
Section sources
vote.route.tsvote.service.tsblock.guard.ts
Audit Logging
- All vote operations record audit entries with metadata including targetId and targetType.
- Audit controller/repo/schema/types provide centralized audit handling.
Section sources
vote.service.tsvote.service.tsvote.service.tsaudit.controller.tsaudit.repo.tsaudit.schema.tsaudit.types.tsaudit-context.ts
Dependency Analysis
The voting module depends on:
- Post/Comment repositories for resolving target author IDs.
- User repository for karma updates.
- Audit module for logging.
- Cache for fast reads and invalidation.
- Database adapter/table for persistence with unique constraints.
graph LR
VS["VoteService"] --> PR["PostRepo"]
VS --> CR["CommentRepo"]
VS --> UR["UserRepo"]
VS --> BG["BlockGuard"]
VS --> AC["AuditController"]
VR["VoteRepo"] --> VA["VoteAdapter"]
VA --> VT["votes table"]
VR --> CK["VoteCacheKeys"]Diagram sources
vote.service.tsvote.repo.tsvote.adapter.tsvote.table.tsvote.cache-keys.tspost.schema.tscomment.schema.tsuser.schema.tsuser.repo.tsblock.guard.tsaudit.controller.ts
Section sources
vote.service.tsvote.repo.tsvote.adapter.tsvote.table.tsvote.cache-keys.ts
Performance Considerations
- Unique constraint on (userId, targetType, targetId) prevents duplicates and reduces contention.
- Cached reads for user-target votes minimize repeated DB lookups.
- Incremental cache versioning avoids full recomputation of lists.
- Transactions ensure consistency with minimal round trips.
- Recommendations:
- Use cache warming for hot targets.
- Monitor audit and cache hit rates.
- Consider batching vote operations for bulk UI interactions.
[No sources needed since this section provides general guidance]
Troubleshooting Guide
Common issues and resolutions:
- Vote not found for patch/delete: Ensure the user-target combination exists and matches targetType.
- Target not found: Verify targetId and targetType correctness.
- Unauthorized: Confirm user context middleware is applied and user is authenticated.
- Blocked user: Unblock the target author or operate from another account.
- Duplicate vote: Unique index prevents insertion; handle gracefully by informing clients to patch instead of re-insert.
Section sources
vote.service.tsvote.service.tsvote.adapter.tsvote.table.ts
Conclusion
Flick’s voting system is designed around safety, consistency, and scalability. It prevents duplicates, enforces permissions, maintains author reputation, and keeps caches coherent. While the module itself focuses on vote lifecycle and audit, downstream modules can implement score aggregation, leaderboards, and trending calculations tailored to application needs.
[No sources needed since this section summarizes without analyzing specific files]
Appendices
API Endpoints Summary
- POST /api/votes
- Body: voteType, targetType, targetId
- Response: created vote
- PATCH /api/votes
- Body: voteType, targetType, targetId
- Response: success message and updated vote
- DELETE /api/votes
- Body: targetType, targetId
- Response: success message with deleted vote id
Section sources
vote.route.tsvote.controller.ts
Database Schema Snapshot
- Table: votes
- Columns: id, userId, targetType, targetId, voteType
- Constraints: unique index on (userId, targetType, targetId); index on (targetType, targetId)
Section sources
vote.table.ts