Design a variable daily-login reward system with anti-gaming controls

Tests server-side reward probabilities and idempotency in distributed systems. Strong answers cover: configurable weights, idempotent tokens with DB unique constraints, rolling windows, and server-side grants.
WHAT THIS TESTS: Your ability to design a server-authoritative, auditable rewards pipeline that couples probabilistic business logic with strong consistency and anti-fraud primitives. Interviewers want to see that you understand the difference between an action (a raw event like a login) and a behavior (a stateful pattern that qualifies for a reward), and that you can prevent double-granting and gaming without sacrificing configurability for growth teams.
A GOOD ANSWER COVERS: First, separate accrual from redemption. Accrual processes actions, matches them to campaigns, and issues points; redemption lets users spend those points on offers. Second, make probability distributions fully server-side and configurable. Store reward tiers and weights in a campaign config table so growth teams can tune a 70/25/5 split without deploying code. Third, ingest events through an idempotent conversion layer. Compute a unique token for each action based on the source event, and enforce a unique constraint on the combination of action type and token in an ActionInstance table so retries never double-grant. Fourth, implement anti-gaming controls: use rolling 24-hour windows rather than calendar days to block timezone manipulation, enforce per-user rate limiting, tie grants to verified account state rather than device ID alone, and add anomaly detection for bots farming bonuses. Fifth, keep an immutable ledger of granted rewards for auditability.
COMMON WRONG ANSWERS: Generating the random reward on the client is the biggest red flag because it is trivial to exploit. Using simple calendar-day checks is another weak pattern since users can change timezones or system clocks to collect multiple bonuses. Storing eligibility state only in Redis without a persistent unique constraint invites race conditions and duplicate grants. A vague mention of blockchain or signed tokens without explaining the actual idempotency mechanism is also a warning sign.
LIKELY FOLLOW-UPS: How would you support dynamic A/B tests that change probabilities per user cohort without downtime? How would you scale the action ingestion layer to millions of daily logins while preserving exactly-once semantics? What would you do if a bug caused incorrect probabilities for 24 hours? How do you balance fraud detection with false positives that hurt legitimate user engagement?
ONE CONCRETE EXAMPLE: Imagine a daily login bonus with three tiers: small (10 coins, 70 percent), medium (50 coins, 25 percent), and large (200 coins, 5 percent). When a user opens the app, the client pings the server; the server emits a user_login event. A conversion layer transforms this into an Action with a token computed as hash(user_id plus floor(last_grant_timestamp divided by 86400)). The accrual service checks the ActionInstance table for this unique token; if absent, it rolls against the campaign weight table, issues points into the user's balance, and commits the ActionInstance in the same transaction. The redemption service handles spending those points later. If the user tries to replay the login event, the unique constraint rejects the duplicate ActionInstance, preventing a double grant.
Source: Software Engineering Daily, Building a rewards platform from scratch by Pedro Franceschi
Read the original → softwareengineeringdaily.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.