---
# System prepended metadata

title: SNACK 3.0 CHALLENGES

---

# SNACK 3.0 CHALLENGES

In the admin panel:

Challenges (v2.0):
- SNACKUP Challenges
- Completed Challenges
- Completed Gift Challenges
- Challenges Promo Codes

New [v3.0]

```
GET ?version=1
POST { version:1 }

ex: 
v2.0 GET /snack/admin/challenge/getList?pagenumber=1&pagesize=20&order=asc

v3.0 GET /snack/admin/challenge/getList?pagenumber=1&pagesize=20&order=asc&version=1
```

Challenges (v3.0):
- Challenges (v3.0) [6 challenge types]
- Groups (v3.0)
- Completed Challenges (v3.0)
- Leader Board (Dashboard)


## Type of challenges:


| Challenge Type | Value (Int) |
| -------- | -------- | 
| XXX Paid Premium Amount     | 0     |
| Hit XXX steps     | 1     |
| X no of days lower Bio Age than the actual age     | 2     |
| Spend X no of Unique partners     | 3     |
| X no of refer friends     | 4     |
| Group Challenges     | 5     |
| X no of transactions by partner     | 6    |
| X no of transactions with any partners    | 7    |
| Community challenge    | 8    |


**NOTE:
SIT & UAT need to confirm: Admin panel + BE + DB**


Note: only for below challenge type:
start Date & endDate, no of days max of 30 Days

Hit XXX steps  
X no of days lower Bio Age than the actual age

---

challenges [current v2.0]:
```json=
{
    id, // auto generated one
    uid, // we are generating it our end.
    brandPremiumAppId,
    brandName,
    description,
    title,
    subtitle,
    icon,
    imageBackground,
    startDate,
    endDate,
    content,
    terms,
    status, // 0 -> inactive, 1 -> active
    type, // 0 -> normal, 1 -> gift
    createdAt,
    updatedAt,
}
```

challenges_v3.0 [New v3.0]:
```json=
{
    id, // auto generated one
    uid, // we are generating it our end.
    brandPremiumAppId, // optional Default -> NULL
    brandName, // optional Default -> NULL
    title,
    subtitle,
    description,
    icon,
    imageBackground, // optional in create challenge, If it empty from Admin -> default Image.
    listingActiveIcon, // New
    listingInactiveIcon, // New
    startDate,
    endDate,
    content,
    terms,
    status, // 0 -> inactive, 1 -> active
    type, // 0 - 5
    isDashboard,
    sortNum,
    createdAt,
    updatedAt,
    completionValue, // New Type. VARCHAR(255), we cast the type based on the challenge type.,
    dashboardSortNum // Default -> 0
}
```
challenge_groups
```json=
{
    id, // Auto Generated one.
    displayName, // ex: NUS
    title, // National University of Singapore
    logo, // Upload Image
    createdAt,
    updatedAt,
    status, // 0 -> inactive, 1 -> active
}
```

group_challenges
```json=
{
    id,
    challengeUid,
    groupId,
    status, // 0 -> inactive, 1 -> active,
    createdAt,
    updatedAt,
}
```


### Completed Challenges

```json=
user_challenges_v3
{
    id,
    challengeUid,
    groupdId,
    channelUserId,
    email,
    status, // 0 -> Joined but not completed, 1 -> completed, 2 -> completed and redeemed
    progressValue,
    createdAt,
    updatedAt,
    completedAt,
    redeemedAt,
    rewardedAt, // isRewarded, // flag to update the procurement of the Rewards sent to user by email.

}
```

### Leader Board


1. Scheudle the job to update the completed challengs everyday at 12AM
2. Update the completed challenges based on the user action.
- An API call in the background to update the completed challenges in the DB
- Challenge List -> 


- ZA -> Data required for ML;
- Query -> pass the data to ML:
- every end of the Month we can do a data patch to completed challenges:


startDate: 17:05:2022 - 00:00:00
endDate: 18:05:2022 - 23:59:59




## XXX Paid Premium Amount

Within the challenge duration, ZA paid the premium value:
user's progress (paid premium) Value: $20
Admin user configured as: $45

```
ZA: ${snackUrl}/snack/query/statisticsByUser
statisticsType: TOTAL_PAID_PREMIUM

Response:
{
    ...
    "totalPaidPremium":"21.00",
}

```

## Hit XXX steps

Within the challenge duration, get the total number of steps:
user's progress Value: 12,000
Admin user configured as: 20000

```
ZA: ${snackUrl}/snack/query/snackFitActivity

Response:
"historyActivityList": [
            {
                "activityDate": "2021‐08‐24",
                "height": 180,
                "weight": "60",
                "steps": 8100,
                "kcal": 750,
                "sleep": "8.5",
                "rhr": "50.5",
                "bioAge": "26",
                "ageBalance": "1",
                "calcuationTime": "2021‐08‐25 09:39:31"
},

"steps": 8100 Get the accumated value.

```

## X no of days lower Bio Age than the actual age

Within the challenge duration, get the bioAge:
user's progress Value: 6 (Get the no of days use's bio age is greater than zero)
Admin user configured as: 20

```
ZA: ${snackUrl}/snack/query/snackFitActivity

Response:
"historyActivityList": [
            {
                "activityDate": "2021‐08‐24",
                "height": 180,
                "weight": "60",
                "steps": 8100,
                "kcal": 750,
                "sleep": "8.5",
                "rhr": "50.5",
                "bioAge": "26",
                "ageBalance": "1",
                "calcuationTime": "2021‐08‐25 09:39:31"
},

"ageBalance": "1",

23.02.2022 - 2
24.02.2022 - 0
25.02.2022 - 1
26.02.2022 - 0
...

total: 2

2 / 20 = 

```

## Spend X no of Unique partners

Within the challenge duration, check how many SNACKUP partners user is spending.
user's progress Value: 2
Admin user configured as: 5


```
ZA: ${snackUrl}/snack/query/statisticsByUser

statisticsType: TOTAL_FREE_COVERAGE

{
"value": {
        "totalFreeCoverage": "20000",
        "partnerCount": 4,
        "partnerList": [
            "FOODPANDA",
            "UOB",
            "REVOLUT",
            "KIPOS"
        ],
    

partnerCount: 4 (progress Value)

```

## X no of refer friends

Within the challenge duration, check how many referrals user has.
user's progress Value: 2
Admin user configured as: 5

GET no of referral count from user.referrals where channelUserId='' AND (uppadtedAt >= challenge.startDate && updaatedAt <= challenge.endDate)

```
ML DB

```


## Group challenge points calculation

group_user_challenge_points
```json=
{
    id,
    channelUserId,
    challengeUid,
    groupId,
    referralCount,
    points // 0 -> Bonus points completed referrals and No of completed challenges.
    createdAt,
    updatedAt
}
```

1. on the fly get the individual referral count by a channelUserId
2. on the fly get the grp referral count by a group

channelUserID: 134454
No of completed challenges: 3
challengeUid: (ABC), completionValue: 20 pts


User(134454)'s total points for the challenge ABC is 60 pts (3 * 20)

### A schedular will be run every day, time will be provided by MG.


## Leader Board (Dashboard)

@subhaish, @joy, @yahui

```json=
challenge_leaderboard
{
    id,
    challengeUid,
    status, // 0 -> inactive, 1 -> active,
    title, // 
    description,
    imageUrl,
    createdAt,
    updatedAt
}

challenge_leaderboard_points
{
    id,
    leaderboardId,
    points,
    groupId, // logo and the display name or | and title from there.
    createdAt,
    updatedAt
}
```


challenge Use cases.

1. When the challenge is active / completed, admin can edit except [statDate, endDate, completionValue, type of the challenge, title, subtitle]

2. For future grp challenge admin user can able to remove / add a new grp, and able to edit the fields.


For the PROGRESS UPDATE API:

1. Get all the challenges that user joined.
2. Based on each challenge type update the progress Value.


**@Joy, - Feedback from client by 14 Jun 2022
For query the data to update the progress of the challenge, start date will be the joined date of the challenge by the user.**

type == 4
user.referrals & filter user.referrals.updatedAt

## Completed challenges CSV



## Challenge Query

```javascript=
List:
QUERY:
(startDate <= currentDate && currentDate <= endDate) && staus == 1

SORT:
sortNum

Dashboard QUERY:
(startDate <= currentDate && currentDate <= endDate) && staus == 1 && isDashboard == 1

SORT:
dashboardSortNum


History (User):
challenges: noOfDays(currentDate - challenge.startDate) <= 90 && staus == 1

user_challenges:
status = 0 [Joined not completed] && challenge.endDate < currentDate
status = 1 [Completed] && challenge.endDate < currentDate
status = 2 [Completed and Redeemed]
```

Update from clinet: 15 June 2022:

`These 2 parts I am wondering if it is possible. Replace the top 3 leaderboard to school leaderboard, and display the student's rank in their school`

![](https://i.imgur.com/mZ9C8BQ.jpg)

@Joy can we check the rank for the user within a grp challenge?


Note: Query to MG
For leaderboard points: CRON JOB vs MANUAL (override the value or not)

@Karthik 

As checked with MG it will be MANUAL for phase1, in phase2 we can update the logic with CRON JOB.



1. Update Progress: User request 
- ZA: snackFitActivity, statisticsByUser [1:1]

CRON - Job, 15K - 15K per one challenge, 4 = 60K


Graphene 2.0
- Batch update API [100],


## Phase2: Challenges:
API specification:

ZA -> ML:

CRON - grp challenges




/status/update
ZA -> ML -> AML status [ML DB]:



## Challenge Enhancement for update progress

### Real Time
ML provide an API, ZA will call the ML API whenever the values updated.
- Request body for all challenge types:
- date - current Date

## XXX Paid Premium Amount
```json
{
    "channelUserId": 33434,
    "date": "27-08-2022" 
    "statisticsType": "TOTAL_PAID_PREMIUM"
    "statisticsValue":"21.00"
}
```

## Spend X no of Unique partners

```json
{
    "channelUserId": 33434,
    "date": "27-08-2022"
    "statisticsType": "TOTAL_FREE_COVERAGE_NO_OF_PARTNERS"
    "statisticsValue": 4
}
```

## Hit XXX steps
```json
{
    "channelUserId": 33434,
    "date": "27-08-2022"
    "statisticsType": "SNACK_FIT_TOTAL_STEPS"
    "statisticsValue": 2000
}
```

## X no of days lower Bio Age than the actual age

```json
{
    "channelUserId": 33434,
    "date": "27-08-2022"
    "statisticsType": "SNACK_FIT_AGE_BALANCE"
    "statisticsValue": 0
}
```

Note: Export the data from ZA and import in ML DB before rollout this enhancement.


## upcoming challenges.

```json
{
    "channelUserId": 33434,
    "date": "27-08-2022"
    "statisticsType": "TOTAL_FREE_COVERAGE"
    "statisticsValue": "20000"
}
```















statisticsByUser
snackFitActivity



### statisticsTypes

TOTAL_PAID_PREMIUM
TOTAL_FREE_COVERAGE_NO_OF_PARTNERS
SNACK_FIT_AGE_BALANCE
SNACK_FIT_TOTAL_STEPS



CRON JOB, bulk Query:
[
    ".. channelUserIds", 
    "statisticsType": "TOTAL_FREE_COVERAGE",
]

Note: Each challenge for a user has diff startDate (joined date of the challenge), endDate will be challenge end Date.


## 14.12.2022 => Community Challenge

1. Dashboard [New Template]

Type    "EXPLORE_CHALLENGE"
Title
Image
Template => TOP IMAGE 
htmlDescription => html text

contentImage => NEW IMAGE INPUT [optional]
backgroundColor: {
    startColor: "", [text input] [hex value]
    endColor: "" [text input] [hex value]
} [optional],

Active
Order
Content
![](https://i.imgur.com/At8pKjx.png)
![](https://i.imgur.com/HskWc5y.png)



2. Community Challenge:

![](https://i.imgur.com/jYfJhWX.png)
![](https://i.imgur.com/BN8kgne.png)

Challenge Type => Community challenge (8)
Challenge Title [html text]
Challenge Subtitle [html text]
Description [html text]
Scheduled on
Image Background
Icon
Listing Active Icon Url
Listing Inactive Icon Url
Content
Terms and Conditions
Completion Value
Order
Is Dashboard
Active

NEW TABLE:
`community_challenge_additional_info`
id,
title [html text],
description [html text],
image,
backgroundColor: {
    startColor: "", [text input] [hex value]
    endColor: "" [text input] [hex value]
} [JSON],
content: [
{
    label [html text],
    value [html text],
    info [html text],
    subInfo [html text] [optional],
}
] [JSON],
tiers: [
    {
        displayText (required) [html text],
        displayLabel (required) [html text],
        activeImage (optional),
        inactiveImage (optional),
        isActive (required) [bool]
    }
] [JSON],
contentUpdatedAt, [datetime input] // SGT
createdAt,
updatedAt

# 7.12.2022 - X no of transactions by partner, X no of transaction by any partner

include datasouce in the Filter:
![](https://i.imgur.com/bUJHo7k.png)

Dropdown:
```json 
{
    "None": "",
    "Visa": "DS0005",
    "Mastercard": "DS0013"
}
```