package store import ( "context" "telesrv/internal/domain" ) // AccountRatingStore owns the composite rating read model and its contribution // ledger. // // The read model is derived: SaveAccountRating writes a recomputed projection, // AccountRatingSignals gathers the raw inputs from the contributing tables, and // the ledger keeps manual adjustments that must survive a recompute. type AccountRatingStore interface { // AccountRating returns the stored projection. Missing rows return // domain.ErrAccountRatingNotFound so callers can distinguish "never computed" // from "computed as zero". AccountRating(ctx context.Context, userID int64) (domain.AccountRating, error) // AccountRatingBatch resolves several users in one round trip. Users without // a row are absent from the map. AccountRatingBatch(ctx context.Context, userIDs []int64) (map[int64]domain.AccountRating, error) // SaveAccountRating upserts the projection using optimistic concurrency on // the stored version; a stale version reports changed=false. SaveAccountRating(ctx context.Context, rating domain.AccountRating) (stored domain.AccountRating, changed bool, err error) // AccountRatingSignals gathers the raw contribution snapshot for one user, // including the manual total carried from the ledger. AccountRatingSignals(ctx context.Context, userID int64) (domain.AccountRatingSignals, error) // AdjustAccountRating appends a manual adjustment. Replaying the same // CommandKey returns the recorded event and applied=false. AdjustAccountRating(ctx context.Context, req domain.AdjustAccountRatingRequest) (event domain.AccountRatingEvent, applied bool, err error) // ListAccountRatings is the admin leaderboard query with keyset paging. ListAccountRatings(ctx context.Context, filter domain.AccountRatingFilter) ([]domain.AccountRating, error) // AccountRatingEvents returns the ledger for one user, newest first. AccountRatingEvents(ctx context.Context, userID int64, limit int) ([]domain.AccountRatingEvent, error) // StaleAccountRatings returns user ids whose projection is older than the // given horizon, for the background recompute worker. StaleAccountRatings(ctx context.Context, olderThanUnix int64, limit int) ([]int64, error) // UnratedAccounts returns user ids that have no projection at all, oldest // account first, for the same worker. // // Without this the read model can never populate itself: StaleAccountRatings // walks account_rating, so it can only refresh rows that already exist, and the // very first row for a user would have to come from an operator recomputing // that user by hand. Seeding is what makes the local admin leaderboard useful. // // Deleted accounts and bots are excluded: neither has a rating to show. UnratedAccounts(ctx context.Context, limit int) ([]int64, error) }