Skip to Content

Daily Claim Limit (Unique Constraint)

Demo Project

https://editor.momen.app/tool/z7Bx4APAJrO/WEB?code=LafkRsCNdfdhq&ref=0562398

Introduction

  • Goal: Create a daily reward system where users can claim a reward up to 3 times per day, with database-level protection against concurrent over-claiming.
  • Use Cases: Daily check-ins, limited coupon distributions, or daily point systems.
  • Core Logic: Use a Composite Unique Constraint in the database (Account + Date + Sequence) combined with an Actionflow that calculates the next sequence number and handles insertion conflicts.

Steps

This tutorial uses pre-styled layout blocks from the “Common UI Presets” template page. These presets include basic styling and typography only; they contain no conditional logic, database bindings, or Actionflows. You can copy them into your own app to skip manual styling and focus on the core logic.

Data Storage

To implement a daily claim limit system, we need to establish a dedicated table in the database to store claim records.

Data Model

Table: claim_record

Logs every successful reward claim.

Field NameTypeNote
idBigintPrimary Key
claim_dateDateThe date the reward was claimed
claim_sequenceBigintThe index of the claim for that day (1, 2, or 3)
account_idBigintForeign Key linked to the account table

Database Constraints

To ensure data integrity at the hardware level, we must prevent any duplicate entries for the same user on the same day with the same sequence number.

  1. Select Table: Select the claim_record table.
  2. New constraint: Click on the table settings and select Edit constraint.
  3. Composite unique columns: Add a new unique constraint named unique_claim_record_account_date_sequence.
  4. Fields: Select claim_date, claim_sequence, and account_id. This ensures that the combination of these three fields must be unique across the entire database.

Logic & State Configuration

Actionflow: Claim Reward

This Actionflow validates and executes the reward claim.

  1. Actionflow variable: Create a variable named status with the type Boolean to return the result to the frontend.
  2. Get ID: Add a Get ID node. Its output field is current_account_id.
  3. Query data: Add a Query data node to fetch the user’s claims for the current day.
    • Table: claim_record.
    • Filter:
      • claim_date Equal to Current date.
      • account_id Equal to current_account_id (from the Get ID node).
    • Limit: Set to 3.

  1. Condition: Add a Condition node to check the current claim count.
    • Case 1 (Less than 3 times): Set the condition to Actionflow data/Fetch today's claim records/Count Less than 3.

  1. Insert data: In the “Less than 3 times” branch, add an Insert data node.
    • Table: claim_record.
    • Parameters:
      • claim_date: Set to Current date.
      • account_id: Set to current_account_id.
      • claim_sequence: Use a formula to calculate the next index: Actionflow data/Fetch today's claim records/Count + 1.
    • Conflict resolution: Select the unique_claim_record_account_date_sequence constraint and set the resolution to Do nothing. This silently ignores the request if a race condition occurs.

  1. Set variable (Less than 3 times): In the “Less than 3 times” branch, add a Set variable node after the insertion.
    • Condition: Set the condition to Actionflow data/Insert data/id Is not null.
      • Value: Set status to True.
  2. Set variable (Reached 3 times): In the “3 times reached” branch, add a Set variable node.
    • Value: Set status to False.

  1. Actionflow output: Configure the output to return the status variable.

By setting the Conflict resolution to “Do nothing,” the Actionflow will not crash if a user clicks the button multiple times simultaneously. The database will simply reject the second request, and the status will return False.

UI Construction & Interaction

The frontend uses a Conditional View to dynamically switch between login prompts, active claim buttons, and disabled states based on the user’s real-time data.

1. Page Setup

  1. Create Page: In the Pages tab, click + and add a new page named Page Daily Reward Claim.
  2. Add Conditional View: Drag a Conditional View component onto the canvas. This will act as the container for the different reward states.
  3. Configure Cases: Rename the default cases in the Component Tree:
    • Case 1: Case Less than 3 times
    • Case 2: Case Reached 3 times
    • Case 3: Initializing

2. Active Claim State (Less than 3 times)

  1. Add Button: Inside the Case Less than 3 times case, add a Button component.
  2. Data Binding (Button Text): Click the Databinding icon next to the Button text field.
    • Combine static text with dynamic data.
    • Expression: Claim daily reward ( + Logged in user/claim_record/Count + /3)
    • Filter: In the databinding panel, add a filter to the claim_record relation with claim_date equals Current date, so the count only includes today’s records.

  1. Interaction (OnClick): Go to the Action tab of the button.
    • Trigger: OnClick -> Actionflow.
    • Select Actionflow: Choose Claim Reward.

  1. Feedback Logic (On Success): Click + under On success and select Condition.
    • Case Claim Success: Set the condition to Action result/Actionflow/status Is true.
      • Action: Show toast with the message “Claimed successfully”.
    • Case Claim Failed: Set the condition to Action result/Actionflow/status Is false.
      • Action: Show toast with the message “Claim failed”.
  2. Data Refresh: Add a Refresh logged-in user data action at the end of the On success sequence. This ensures the UI counter and conditional view update immediately after a successful claim.

3. Limit Reached & Initializing States

  1. Disabled Button: In the Case Reached 3 times case, add a Button component.
    • Button text: Set to Claim daily reward (3/3).
    • Interaction: Remove all actions to ensure it is non-interactive.
  2. Login Prompt: In the Initializing case, add a Text component.
    • Content: Set to “Please log in first”.

4. Visibility Logic Configuration

Select the Conditional View and click Config in the right panel to define when each case should be displayed.

  1. Case Less than 3 times:
    • Condition: And
      • Global/is logged in Is true
      • Logged in user/claim_record/Count (filtered by today’s date – apply the same filter as in the button binding) Less than 3.

  1. Case Reached 3 times:
    • Condition: Global/is logged in Is true. (Since this is the second branch, it will only execute if the “Less than 3” condition fails.)
  2. Initializing:
    • Displays when the user is not authenticated.

Verification

Step 1: Authentication Test

  1. Click Preview and use the Login simulation at the bottom of the screen.
  2. Select Restore user to logged out state.
  3. Expected Result: The page displays “Please log in first”.

Step 2: Claiming Rewards

  1. Use Login simulation -> Create new to log in as a test user.
  2. Click the “Claim daily reward (0/3)” button.
  3. Expected Result: A “Claimed successfully” toast appears, and the button text updates to “(1/3)”.

Step 3: Reaching the Daily Limit

  1. Click the button two more times.
  2. Expected Result: After the third claim, the button style changes to the Disabled state and displays “(3/3)”.

Step 4: Database Integrity Check

  1. Go to the Data Source tab and open the claim_record table.
  2. Expected Result: You should see exactly 3 records for the test user with sequence numbers 1, 2, and 3 under today’s date.
⚠️

If you test this in a high-concurrency environment, you might see the Actionflow return “Claim failed.” This is precisely the unique constraint in action, preventing duplicate over-claiming records from being created.

Last updated on