PRDHunt

Reward - Kids Reward System

A gamified reward and motivation system designed for young children (ages 4-6).

by Spider · yesterday · 0 · EN

Reward - Kids Reward System: Product Requirements Document

Version: 1.0 Date: 2026-04-14 Original Stack: Python/Flask + SQLAlchemy + SQLite + Jinja2 + Bootstrap 5


Table of Contents

  1. Product Overview
  2. User Roles & Authentication
  3. Data Models & Schema
  4. Core Features
  5. Gamification System
  6. Approval Workflows
  7. Airdrops (Bonus Missions)
  8. Shareable Rewards
  9. Image Upload & Custom Rewards
  10. Internationalization (i18n)
  11. Progressive Web App (PWA)
  12. API Endpoints Reference
  13. UI/UX Specifications
  14. Business Rules Summary
  15. Planned / Non-Implemented Features
  16. Security Considerations
  17. Deployment & Infrastructure

1. Product Overview

Reward is a gamified reward and motivation system designed for young children (ages 4-6). It enables parents to define positive behaviors and rewards, while children interact with a playful, hero-themed interface to earn “stars” (coins) and redeem them for treasures (rewards).

Key Concepts

Term in App Internal Name Description
Stars coins Virtual currency earned by kids for good behaviors
Treasures / Gifts rewards Items kids can redeem using their stars
Hero Medals badges Achievement medals earned at coin milestones
Super Days streak Consecutive days with at least one confirmed claim
Special Tasks goals Behavior targets (e.g., “brush teeth 5 times”)
Airdrops airdrops Limited-slot bonus missions created by parents
Hero Dashboard Kid Dashboard The kid’s personal progress page
Treasure Shop Rewards Page Where kids browse and redeem rewards
Parents Panel Settings Page Admin panel for parents (PIN-protected)

Design Philosophy

  • Kid-friendly: Large buttons, emojis, bright colors, animations, sound effects, voice feedback
  • Parent-controlled: All coin awards and deductions require parent approval
  • Bilingual: Full English and Arabic (RTL) support
  • Offline-capable: PWA with service worker caching
  • Claymorphism design: Soft 3D shadows, rounded corners, pastel gradients

2. User Roles & Authentication

2.1 Roles

Role Description Access
Kid Child user who claims behaviors and redeems rewards Kid dashboard, treasure shop, home page
Parent Admin who manages the system and approves actions Settings panel (PIN-protected)
Anonymous Unauthenticated visitor PIN login screen only (if site locked)

2.2 Authentication System

Site Access (Cookie-Based)

  • A cookie named reward_access with value granted is required to access the site
  • Cookie has a 30-day expiration (max_age=2592000)
  • Set after successful PIN entry on the unlock page
  • Without this cookie, all routes redirect to the login screen (except /unlock and static files)

Parent Authentication (Session-Based)

  • Parents authenticate via a numeric PIN stored in the Setting table (key='parent_pin')
  • On successful PIN entry, session['parent_authenticated'] = True is set
  • Required for: confirming claims, confirming redemptions, confirming airdrops, all delete operations, managing kids/behaviors/rewards
  • Logout clears the session key

PIN Setup

  • If no PIN exists in the database, the settings page is accessible without authentication
  • The parent sets their PIN on first access
  • PIN is stored as plaintext in the Setting table (not hashed)

2.3 Site Lock

  • A setting (key='site_lock') toggles site-wide access
  • When locked (value='true'): all visitors must enter PIN to access any page
  • When unlocked (value='false'): the site is open to anyone with the reward_access cookie
  • Toggle is available in the parent settings panel

3. Data Models & Schema

3.1 Kid

Field Type Constraints Default Description
id Integer PK, Auto-increment - Unique identifier
name String(50) NOT NULL - Child’s display name
emoji String(10) - '👶' Avatar emoji
gender String(10) - 'male' 'male' or 'female' - used for reward filtering
coins Integer - 0 Current star balance
target_reward_id Integer FK → Reward.id, Nullable NULL The reward the kid is currently working toward

Relationships: Has many Claims, Goals, RewardImages, RewardRedemptions, KidBadges, AirdropClaims

3.2 Behavior

Field Type Constraints Default Description
id Integer PK - Unique identifier
description String(200) NOT NULL - What the behavior is (e.g., “Brush teeth”)
emoji String(10) - '⭐' Visual icon for the behavior
coin_value Integer - 1 Stars earned when this behavior is confirmed

Note: A category column (VARCHAR, default 'general') is added via schema sync but not actively used in the model definition.

3.3 Reward

Field Type Constraints Default Description
id Integer PK - Unique identifier
name String(100) NOT NULL - Reward display name
details Text Nullable - Optional description
coin_cost Integer NOT NULL - Stars required to redeem
image_path String(255) Nullable - Relative path to reward image
suitable_male Boolean - True Show this reward to boys
suitable_female Boolean - True Show this reward to girls
target_count Integer - 1 Number of completions for milestone tracking
category String(50) - 'general' 'toy', 'activity', 'snack', 'other', 'general', 'custom'
is_milestone Boolean - False Priority reward for goal auto-selection
is_custom Boolean - False Created by kid via image upload
is_shareable Boolean - False Can be redeemed by multiple kids together
min_participants Integer - 2 Minimum kids needed for shareable rewards

3.4 Claim

Field Type Constraints Default Description
id Integer PK - Unique identifier
kid_id Integer FK → Kid.id, NOT NULL - The claiming kid
behavior_id Integer FK → Behavior.id, NOT NULL - The behavior claimed
status String(20) - 'pending' 'pending' or 'confirmed'
created_at DateTime - UTC now When the claim was made

3.5 Goal

Field Type Constraints Default Description
id Integer PK - Unique identifier
kid_id Integer FK → Kid.id, NOT NULL - The kid this goal belongs to
behavior_id Integer FK → Behavior.id, NOT NULL - The behavior to track
target_count Integer - 5 How many times the behavior must be confirmed
current_count Integer - 0 Progress toward the target
created_at DateTime - UTC now When the goal was created

Business Rule: When a claim is confirmed for a behavior that has an active goal for that kid, current_count is incremented by 1.

3.6 RewardImage

Field Type Constraints Default Description
id Integer PK - Unique identifier
kid_id Integer FK → Kid.id, NOT NULL - The kid who uploaded
image_path String(255) NOT NULL - Relative path to image file
reward_id Integer FK → Reward.id, Nullable - Associated custom reward (if created)
created_at DateTime - UTC now Upload timestamp

3.7 RewardRedemption

Field Type Constraints Default Description
id Integer PK - Unique identifier
kid_id Integer FK → Kid.id, NOT NULL - The initiating kid
reward_id Integer FK → Reward.id, NOT NULL - The reward being redeemed
status String(20) - 'pending' 'pending' or 'confirmed'
is_shared Boolean - False Whether this is a shared redemption
participant_ids Text Nullable - JSON array of kid IDs (for shared rewards)
cost_per_kid Integer Nullable - Split cost for shared rewards
created_at DateTime - UTC now When redemption was initiated

3.8 Badge

Field Type Constraints Default Description
id Integer PK - Unique identifier
name String(50) NOT NULL - Badge display name
emoji String(10) Nullable - Badge emoji
image_path String(255) Nullable - Optional badge image
required_coins Integer - 0 Total coins required to earn
description String(200) Nullable - Achievement description

Default Badges (auto-created if none exist):

Name Emoji Required Coins Description
Novice Hero 🌟 10 “Earned your first 10 stars!”
Super Star 50 “Earned 50 stars!”
Golden Hero 🏆 100 “Earned 100 stars!”
Legendary 👑 500 “Earned 500 stars!”

3.9 KidBadge

Field Type Constraints Default Description
id Integer PK - Unique identifier
kid_id Integer FK → Kid.id, NOT NULL - The kid who earned it
badge_id Integer FK → Badge.id, NOT NULL - The badge earned
earned_at DateTime - UTC now When the badge was earned

3.10 Setting

Field Type Constraints Default Description
id Integer PK - Unique identifier
key String(50) UNIQUE, NOT NULL - Setting identifier
value String(255) - - Setting value

Known Keys:

Key Values Description
parent_pin Numeric string Parent authentication PIN
language 'en', 'ar' UI language preference
site_lock 'true', 'false' Whether site requires PIN to access

3.11 Airdrop

Field Type Constraints Default Description
id Integer PK - Unique identifier
title String(200) NOT NULL - Mission title
description Text Nullable - Mission details
coins Integer NOT NULL 10 Star reward for completion
slots Integer - 1 Max number of kids who can claim
is_active Boolean - True Whether the airdrop is available
emoji String(10) - '🔥' Display emoji
created_at DateTime - UTC now Creation timestamp

3.12 AirdropClaim

Field Type Constraints Default Description
id Integer PK - Unique identifier
airdrop_id Integer FK → Airdrop.id, NOT NULL - The airdrop being claimed
kid_id Integer FK → Kid.id, NOT NULL - The claiming kid
status String(20) - 'claimed' 'claimed''completed''confirmed'
claimed_at DateTime - UTC now When the kid claimed the airdrop
completed_at DateTime Nullable - When the kid marked it as done
confirmed_at DateTime Nullable - When the parent confirmed completion

4. Core Features

4.1 Kid Management (Parent)

  • Add Kid: Name, emoji avatar, gender (boy/girl)
  • Edit Kid: Update name, emoji, gender
  • Delete Kid: Cascading delete of all associated records (claims, redemptions, goals, reward images)
  • Kids appear as cards on the home page with their emoji and current coin balance

4.2 Behavior Management (Parent)

  • Add Behavior: Description, emoji, coin value (minimum 1)
  • Edit Behavior: Update description, emoji, coin value
  • Delete Behavior: Cascading delete of all associated goals and claims
  • Behaviors appear as quick-action buttons on the kid dashboard

4.3 Reward Management (Parent)

  • Add Reward: Name, coin cost, optional image upload, gender suitability flags, milestone flag, shareable flag
  • Edit Reward: Update all fields including image replacement
  • Delete Reward: Cascading delete of all associated redemptions
  • Rewards are filtered by kid’s gender when displayed in the treasure shop

4.4 Behavior Claiming (Kid)

  1. Kid taps a behavior button on their dashboard
  2. System creates a Claim record with status='pending'
  3. Sound effect plays, speech synthesis announces the behavior
  4. Celebration animation (confetti + star animation) displays
  5. Claim appears in “Waiting for Approval” section on kid dashboard
  6. Claim appears in parent’s “Stars to Approve” queue

Constraints:

  • Maximum 10 pending claims per kid at any time
  • Kid can cancel their own pending claims

4.5 Reward Redemption (Kid)

  1. Kid browses the treasure shop (filtered by gender)
  2. Affordable rewards have green border; unaffordable are grayscaled
  3. Kid taps a reward → confirmation modal appears
  4. If kid has enough coins → RewardRedemption created with status='pending'
  5. If not enough coins → option to “Set as My Goal” (sets target_reward_id)
  6. Parent sees pending redemption in “Rewards to Hand Out” queue

Coin Check: kid.coins >= reward.coin_cost

4.6 Goal Tracking

  • Parent or kid can create goals linking a behavior to a target count
  • When a claim is confirmed for a behavior with an active goal, goal.current_count increments
  • Progress displayed as percentage bar on kid dashboard
  • Trophy emoji shown when current_count >= target_count
  • Goals can be deleted by parents

4.7 Weekly Statistics

  • Bar chart showing last 7 days of confirmed claim counts
  • Each day shows the count of confirmed claims for that kid
  • Days labeled with abbreviated names (SUN-SAT)
  • Displayed on kid dashboard

4.8 Today/Weekly Coin Tracking

  • today_coins: Sum of all behavior coin values from confirmed claims today
  • weekly_coins: Sum of all behavior coin values from confirmed claims in the last 7 days
  • total_earned: Lifetime sum of all confirmed claim coin values
  • total_redeemed: Count of confirmed redemptions

5. Gamification System

5.1 Rank System

Based on total accumulated coins (lifetime, not current balance):

Rank Translation Key Coin Threshold
Small Hero RANK_NOVICE 0+
Super Hero RANK_APPRENTICE 50+
Super Star RANK_HERO 100+
Golden Hero RANK_CHAMPION 250+
Mega Legend RANK_LEGEND 500+

5.2 Level System

level = (kid.coins // 10) + 1

Level is derived from current coin balance divided by 10, plus 1.

5.3 Streak System

  • A streak counts consecutive days where the kid has at least one confirmed claim
  • Calculated by looping backward from today, up to 100 days
  • Breaks when a day has zero confirmed claims (except day 0)
  • Different narrative messages at streak milestones:
Streak Message Key English Text
1 STREAK_STORY_1 “The journey begins! You’re a hero in training.”
3 STREAK_STORY_3 “The forest is cheering! You’ve found the magic path.”
5 STREAK_STORY_5 “The castle is near! You’re showing great power.”
7 STREAK_STORY_7 “The dragon is a friend! You are a true champion.”
10 STREAK_STORY_10 “You’re flying with the stars! Absolute legend.”
30 STREAK_STORY_30 “You are the king of the hero world! Unstoppable!”

5.4 Badge System

  • Badges are auto-awarded when a kid’s total coins reach a threshold
  • Checked every time a claim is confirmed (check_for_badges())
  • 4 default badges are created automatically if none exist in the database
  • When new badges are earned, a modal notification is displayed on the kid dashboard
  • Badges are displayed in the “My Collection” section

Badge Award Logic:

  1. Query all badges where required_coins <= kid.coins
  2. Exclude badges the kid already has (via KidBadge table)
  3. Create KidBadge entries for newly qualified badges
  4. Return list of newly earned badges for UI notification

5.5 Next Reward / Progress Tracking

Auto-selection logic (if no target reward set):

  1. Filter rewards by kid’s gender
  2. Prefer rewards marked as is_milestone=True
  3. Sort by coin_cost ascending
  4. Find first reward with coin_cost > kid.coins (next achievable)
  5. If all rewards are affordable, use the most expensive one

Progress calculation:

progress = min(100, (kid.coins / next_reward.coin_cost) * 100)

Visual progress tracker: 5 checkpoint nodes at 20% intervals, with star emojis for completed checkpoints and empty circles for remaining.


6. Approval Workflows

All coin-affecting operations require parent confirmation. There are three parallel workflows:

6.1 Behavior Claim Workflow

Kid claims behavior → Claim(status='pending')
                    → Parent views in settings queue
                    → Parent confirms → status='confirmed'
                                      → kid.coins += behavior.coin_value
                                      → goal.current_count += 1 (if goal exists)
                                      → check_for_badges(kid)

6.2 Reward Redemption Workflow

Kid redeems reward → RewardRedemption(status='pending')
                   → Parent views in settings queue
                   → Parent confirms → status='confirmed'
                                     → kid.coins -= reward.coin_cost

6.3 Airdrop Workflow

Kid claims airdrop → AirdropClaim(status='claimed')
Kid marks done     → status='completed'
                   → Parent views in settings queue
                   → Parent confirms → status='confirmed'
                                     → kid.coins += airdrop.coins

6.4 Parent Confirmation UX

  • Double-click safety: First click changes button text to “Are you sure?”, second click confirms
  • All confirmation actions are POST requests returning JSON responses
  • Parent must be authenticated (session['parent_authenticated'])

7. Airdrops (Bonus Missions)

7.1 Concept

Airdrops are special, high-value, limited-slot bonus tasks created by parents. They appear on the home page for all kids to see and claim.

7.2 Parent Management

  • Create: Title, description, coin reward, slot count, emoji
  • Edit: Update all fields
  • Delete: Cascading delete of all associated claims
  • Default values: coins=10, slots=1, emoji=‘🔥’, is_active=True

7.3 Kid Interaction

  1. Airdrops appear on the home page with available slot count
  2. Kid selects “Claim Now” → modal asks which kid is claiming
  3. System validates: no duplicate claims, slots available
  4. Claim created with status='claimed'
  5. Airdrop appears in kid’s “Active Airdrops” section on dashboard
  6. Kid marks as “I Finished It!” → status='completed'
  7. Parent confirms → coins awarded

7.4 Constraints

  • One claim per kid per airdrop (enforced by query)
  • Maximum claims limited by airdrop.slots
  • Available slots displayed as: slots - count(claims)
  • Only active airdrops (is_active=True) shown on home page

8. Shareable Rewards

8.1 Concept

Shareable rewards allow multiple kids to split the cost of a single reward they enjoy together (e.g., a box of donuts).

8.2 Initiation Flow

  1. Kid selects a shareable reward in the treasure shop
  2. Cost is split: cost_per_kid = reward.coin_cost // 2 (hardcoded division by 2)
  3. Kid must have coins >= cost_per_kid to initiate
  4. RewardRedemption created with:
    • is_shared=True
    • participant_ids=JSON([kid_id])
    • cost_per_kid calculated value

8.3 Join Flow

  1. Pending shared rewards appear on the home page for all kids
  2. System polls /get_shared_rewards endpoint to fetch pending shared redemptions
  3. Another kid can “Join” the shared reward
  4. Join validates: kid has coins >= cost_per_kid, kid not already in participants
  5. Kid ID appended to participant_ids JSON array

8.4 Confirmation Flow

  1. Parent sees shared redemption in settings queue
  2. On confirm: cost recalculated as reward.coin_cost // len(participants)
  3. Validation: all participants must have enough coins
  4. If any participant lacks coins → error with that kid’s name
  5. If all valid → deduct cost_per_kid from each participant

8.5 Current Limitation

  • Cost split is hardcoded to divide by 2 on initiation (not dynamic based on actual participant count)
  • On confirmation, cost is recalculated based on actual participant count
  • The min_participants field on Reward exists but is not enforced in the redemption flow

9. Image Upload & Custom Rewards

9.1 Kid Upload Flow

  1. Kid accesses upload form on their dashboard (album section)
  2. Provides: image file, reward name, coin cost, category, milestone flag
  3. System validates file extension: {png, jpg, jpeg, gif}
  4. Filename secured: kid_{kid_id}_{timestamp}_{original_filename}
  5. Image processed with Pillow: thumbnail to 800x800, quality 85, optimized
  6. Saved to: static/images/rewards/
  7. Creates a Reward record with is_custom=True and gender flags based on kid’s gender
  8. Creates a RewardImage record linking to the reward

9.2 Parent Delete

  • Parent can delete reward images
  • If the associated reward is custom (is_custom=True), it cascading deletes:
    • All RewardRedemption records for that reward
    • The Reward record itself
    • The RewardImage record
  • Requires parent authentication

9.3 Album Display

  • Kid dashboard shows uploaded images in a 2-column grid
  • Images use lazy loading (loading="lazy")
  • Ordered by created_at descending

10. Internationalization (i18n)

10.1 Supported Languages

Code Language Direction Translation Keys
en English LTR 92 keys
ar Arabic RTL 207 keys

10.2 Implementation

  • Translations stored as JSON files in app/translations/{lang}.json
  • Language preference stored in Setting table (key='language')
  • Loaded on every request via before_app_request hook
  • Available in templates as {{ t.KEY_NAME }}
  • RTL flag (g.rtl) set to True when language is Arabic
  • Templates use dir="{{ 'rtl' if rtl else 'ltr' }}" on HTML elements
  • Fallback: if a language file is missing, English is loaded

10.3 Language Switching

  • Dropdown in parent settings panel (English/Arabic with flag emojis)
  • POST action set_lang updates or creates the language setting
  • Takes effect immediately on page reload

10.4 Voice/Speech

  • JavaScript speechSynthesis API used for voice feedback
  • Language set to Arabic (ar-SA) when RTL, English otherwise
  • Used for: behavior claim announcements, reward reached notifications, streak celebrations

11. Progressive Web App (PWA)

11.1 Manifest

  • App Name: “Reward System”
  • Display: Standalone (full-screen app behavior)
  • Theme Color: #ff7e5f (coral)
  • Background: #fff5f0 (warm cream)
  • Icons: Referenced from /static/images/logo.png

11.2 Service Worker

  • Cache Name: reward-v1
  • Strategy:
    • Static assets (CSS, JS, images, sounds): Cache-first
    • HTML/navigation: Network-first with cache fallback
  • Registration: On page load in all templates

11.3 Install Prompt

  • Captured via beforeinstallprompt event
  • Shown as a sticky banner on the home page
  • Text: “Install App” / localized equivalent

12. API Endpoints Reference

12.1 Page Routes (GET, return HTML)

Route Auth Description
GET / Cookie Home page: kid cards + active airdrops + shared rewards
GET /kid/<id> Cookie Kid dashboard with all stats and progress
GET /kid/<id>/rewards Cookie Treasure shop (gender-filtered)
GET /settings Session (PIN) Parent admin panel
GET /service-worker.js None Service worker JavaScript file

12.2 Action Routes (POST, return JSON or redirect)

Kid Actions (No parent auth required)

Route Input Returns Description
POST /claim kid_id, behavior_id JSON Create pending behavior claim
POST /cancel_claim claim_id JSON Cancel pending claim
POST /redeem kid_id, reward_id, is_shared JSON Initiate reward redemption
POST /cancel_redemption redemption_id JSON Cancel pending redemption
POST /join_shareable kid_id, redemption_id JSON Join a shared reward
POST /set_target_reward kid_id, reward_id JSON Set kid’s goal reward
POST /airdrop/claim kid_id, airdrop_id JSON Claim an airdrop slot
POST /airdrop/complete claim_id JSON Mark airdrop as done
POST /upload_reward_image kid_id, image, coin_cost, category, reward_name, is_milestone Redirect Upload custom reward
POST /add_goal kid_id, behavior_id, target_count Redirect Create behavior goal

Parent Actions (Require session['parent_authenticated'])

Route Input Returns Description
POST /confirm_claim claim_id JSON Approve claim, award coins
POST /confirm_redemption redemption_id JSON Approve redemption, deduct coins
POST /confirm_airdrop claim_id JSON Confirm airdrop, award coins
POST /delete_airdrop airdrop_id Redirect Delete airdrop + claims
POST /add_airdrop title, description, coins, slots, emoji Redirect Create new airdrop
POST /delete_reward_image/<id> - Redirect Delete image + custom reward

Settings Actions (via POST /settings with action parameter)

Action Input Description
login pin Authenticate parent with PIN
logout - Clear parent session
set_lang lang Change UI language
set_pin pin Set or update parent PIN
toggle_lock - Toggle site lock
add_kid name, emoji, gender Create kid
edit_kid kid_id, name, emoji, gender Update kid
delete_kid kid_id Delete kid + cascade
add_behavior description, emoji, coin_value Create behavior
edit_behavior behavior_id, description, emoji, coin_value Update behavior
delete_behavior behavior_id Delete behavior + cascade
add_reward name, coin_cost, image, suitable_male, suitable_female, is_milestone, is_shareable Create reward
edit_reward reward_id, name, coin_cost, image, suitable_male, suitable_female, is_milestone, is_shareable Update reward
delete_reward reward_id Delete reward + cascade
add_goal kid_id, behavior_id, target_count Create goal
delete_goal goal_id Delete goal

Data Endpoints

Route Method Returns Description
GET /get_shared_rewards GET JSON array List pending shared redemptions with participant names

12.3 Authentication Routes

Route Method Input Description
POST /unlock POST pin Validate PIN, set access cookie

13. UI/UX Specifications

13.1 Design System

  • Style: Claymorphism (soft 3D shadows, rounded corners, raised surfaces)
  • Color Palette:
    • Primary gradient: #ff7e5f#feb47b (coral to peach)
    • Kid-friendly colors: rotating set of 7 (pink, blue, green, orange, purple, yellow, teal)
    • Background: #fff5f0 (warm cream)
    • Success: green tones
    • Warning/milestone: amber/gold
  • Typography: Rubik font (Google Fonts), rounded, friendly
  • Border Radius: Heavy use of 20px-30px border radius
  • Shadows: Multi-layer soft shadows (8px 8px 15px rgba(0,0,0,0.1), -4px -4px 10px rgba(255,255,255,0.5))

13.2 Animations

Animation Used For Description
bounce Headers, titles, emojis Vertical oscillation
wobble Coin balance, badges Horizontal wiggle
pulse Progress bar, badges Scale in/out
shake Kid emoji on click Rotation shake
rainbow-title Dashboard title Color cycle through 5 colors
float Rewards, images Vertical float + slight rotation
float-gentle Clay cards Subtle vertical float
float-horizontal Cloud decorations Horizontal movement
confetti-fall Celebration screen Falling + rotating particles
star-spawn Progress nodes Scale + rotate spawn
bounce-soft Reward reached message Gentle bounce
shine Progress bar Sparkle/shimmer effect

13.3 Sound Effects

Sound File Trigger
Pop pop.mp3 Button clicks, UI interactions
Success success.mp3 Claim confirmation, achievements
Coin coin.mp3 Coin collection (referenced, may not be used)

13.4 Page Layouts

Home Page (index.html)

  • Hero title with animation
  • Kid cards in responsive grid
  • Active airdrops section (if any)
  • Shared rewards section (dynamically loaded)
  • Fixed settings gear button (bottom-right)
  • PWA install banner (conditional)

Kid Dashboard (kid_dashboard.html)

  • Red gradient header with kid info, rank, streak
  • Stats bar (coins, treasures, streak)
  • Progress tracking card with 5-node visual tracker
  • Weekly activity bar chart
  • Pending claims section
  • Active airdrops section
  • My Collection (badges + redeemed rewards)
  • Quick-action behavior buttons (color-coded grid)
  • Goals progress section
  • Photo album section
  • Fixed bottom navigation bar (4 items)

Treasure Shop (rewards.html)

  • Header with coin balance (large, animated)
  • Responsive reward card grid
  • Color-coded affordability (green border vs grayscale)
  • Category badges on cards
  • Shareable indicator (🍩)
  • Redeem/Goal modal
  • Fixed bottom navigation

Parent Settings (settings.html)

  • Top bar with language selector + logout
  • Site lock toggle card
  • 3-column layout:
    • Column 1: Approval queues (claims, airdrops, redemptions)
    • Column 2: Kid management
    • Column 3: Behavior management + Airdrop management
  • Full-width rewards management section
  • Emoji picker modal

PIN Login (settings_login.html)

  • Centered card (400px max-width)
  • Numeric PIN input with wide letter-spacing
  • Error display
  • Back to home link

13.5 Bottom Navigation Bar

Fixed at bottom on all kid-facing pages:

Position Icon Label Route
1 🏠 Home /
2 🌟 My Stars /kid/{id}
3 🎁 Treasure Shop /kid/{id}/rewards
4 ⚙️ Settings /settings

Active item highlighted in primary color.


14. Business Rules Summary

Coin Economy

  1. Coins are earned only through parent-confirmed behavior claims
  2. Coins are spent only through parent-confirmed reward redemptions
  3. Coins can also be earned through parent-confirmed airdrop completions
  4. A kid’s coins field represents their current balance (earned minus spent)
  5. Coin values are always positive integers
  6. No concept of negative balance - redemption requires sufficient coins

Claim Rules

  1. Maximum 10 pending claims per kid at any time
  2. Only pending claims can be cancelled
  3. Confirming a claim: adds coins + increments goal progress + checks badges
  4. Claims are timestamped in UTC

Redemption Rules

  1. Kid must have coins >= coin_cost to initiate redemption
  2. For shared rewards: kid must have coins >= cost_per_kid (cost // 2 on initiation)
  3. On shared confirmation: cost recalculated as coin_cost // actual_participant_count
  4. Only pending redemptions can be cancelled
  5. Cancellation does NOT refund coins (coins are deducted only on confirmation)

Reward Display Rules

  1. Rewards filtered by kid’s gender (suitable_male / suitable_female)
  2. Milestone rewards get priority in auto-selection for next goal
  3. Custom rewards (kid-uploaded) flagged with is_custom=True
  4. Shareable rewards indicated with 🍩 emoji

Airdrop Rules

  1. One claim per kid per airdrop (no duplicate claims)
  2. Total claims cannot exceed airdrop.slots
  3. 3-step status flow: claimedcompletedconfirmed
  4. Coins awarded only on parent confirmation
  5. Deleting an airdrop cascades to all its claims

Goal Rules

  1. Goal progress increments when a related behavior claim is confirmed
  2. Goals are not automatically deleted when completed
  3. Multiple goals for the same behavior/kid combination are possible (no uniqueness constraint)

Badge Rules

  1. Badges auto-created on first check if none exist in database
  2. Awarded based on kid.coins >= badge.required_coins
  3. Once earned, badges are never revoked (even if coins decrease from spending)
  4. Badge check runs on every claim confirmation

Deletion Cascades

  1. Delete Kid: removes all Claims, RewardRedemptions, Goals, RewardImages for that kid
  2. Delete Behavior: removes all Goals and Claims for that behavior
  3. Delete Reward: removes all RewardRedemptions for that reward
  4. Delete Airdrop: removes all AirdropClaims for that airdrop
  5. Delete RewardImage: if linked to custom reward, removes the Reward and its RewardRedemptions

15. Planned / Non-Implemented Features

These features are documented in project files but not yet implemented:

15.1 Airdrop Expiry Timer (from new_concepts.md)

  • “Flash Airdrops” that disappear if not claimed within a time window
  • No timer/expiry fields exist in the current Airdrop model
  • Currently, airdrops persist until manually deleted

15.2 Airdrop Urgency Tags (from new_concepts.md)

  • Visual urgency indicator (🔥) for time-sensitive airdrops
  • The emoji field exists but urgency is not a separate concept from the static emoji

15.3 Shareable Reward Participation Threshold (from new_concepts.md)

  • min_participants field exists on Reward model but is not enforced in the redemption flow
  • Currently any number of participants can join (or just the initiator)
  • No maximum participant limit is enforced

15.4 Contribution Tracking for Shared Rewards (from new_concepts.md)

  • Parent dashboard should show who contributed what amount to shared rewards
  • Currently only shows the initiator and total cost, not per-participant breakdown in the approval queue

15.5 Shared Reward Status Flow (from new_concepts.md)

  • Designed: “Pending Join” state until minimum participation is met, then moves to “Redeemed”
  • Currently: shared rewards go straight to pending and can be confirmed regardless of participant count

15.6 Sound Effect Variety (from UPDATE_LOG.md)

  • “Add sound effect variety for different achievement tiers”
  • Currently uses same sounds for all achievements

15.7 Prominent Progress Tab (from PLAN.md)

  • “Add a ‘Progress’ tab or section specifically for long-term goals”
  • Currently goals are shown within the kid dashboard but not as a standalone section

15.8 Level Names (from en.json)

Translation keys exist but are not used in the current UI:

Key Value
LEVEL_NAME_1 Star Scout
LEVEL_NAME_2 Moon Walker
LEVEL_NAME_3 Galaxy Guard
LEVEL_NAME_4 Planet Protector
LEVEL_NAME_5 Cosmic King
LEVEL_NAME_6 Universe Hero

15.9 Behavior Categories (from schema sync)

  • category column added to Behavior table via schema sync
  • Default 'general'
  • Not exposed in the parent settings form for editing
  • Behaviors are ordered by category in queries but no category management exists

15.10 Reward Details Field

  • details (Text) field exists on Reward model
  • Not shown in any template or editable in the parent settings form

16. Security Considerations

Current Implementation

Aspect Status Notes
PIN Storage Plaintext Not hashed - stored as plain string in Setting table
CSRF Protection None No CSRF tokens on POST forms
File Upload Validation Extension only Validates by extension ({png, jpg, jpeg, gif}), not MIME type
SQL Injection Protected SQLAlchemy ORM used throughout
XSS Partial Jinja2 auto-escaping, but some {{ }} in JS contexts
Session Secret Hardcoded SECRET_KEY = 'dev-key-placeholder'
Authorization Session-based Parent actions check session['parent_authenticated']
Rate Limiting None No rate limiting on any endpoint
Input Validation Minimal Coin values cast to int, no negative value checks

Recommendations for Reimplementation

  1. Hash the parent PIN (bcrypt or similar)
  2. Add CSRF tokens to all forms
  3. Validate file MIME types, not just extensions
  4. Use a proper random secret key
  5. Add rate limiting on PIN attempts
  6. Validate all numeric inputs (no negatives, reasonable ranges)
  7. Sanitize file names more aggressively

17. Deployment & Infrastructure

Docker Setup

# docker-compose.yml
services:
  app:
    build: ./app
    volumes:
      - ./app:/app
      - ./data:/data
    ports:
      - "5821:5000"
    environment:
      - DATABASE_URL=sqlite:////data/reward.db
    restart: always
    command: gunicorn --bind 0.0.0.0:5000 --workers 4 --threads 2 "main:create_app()"

Application Server

  • Server: Gunicorn with gevent worker class
  • Workers: 4
  • Threads: 2 per worker
  • Bind: 0.0.0.0:5000
  • Entry point: main:create_app()

Database

  • Engine: SQLite
  • Location: /data/reward.db (mounted volume for persistence)
  • Migrations: Flask-Migrate (Alembic)
  • Schema Sync: sync_db_schema() function adds missing columns via raw SQL ALTER TABLE

Static Files

  • Served by Flask directly from app/static/
  • Images uploaded to app/static/images/rewards/
  • Image optimization: Pillow thumbnail 800x800, quality 85

Dependencies

Flask==3.0.3
Flask-SQLAlchemy==3.1.1
Flask-Migrate==4.0.7
Pillow==10.3.0
gunicorn==25.1.0
gevent==25.9.1

Appendix A: Translation Key Reference

See app/translations/en.json (92 keys) and app/translations/ar.json (207 keys) for the complete translation dictionaries. Arabic has more keys due to additional contextual translations and voice prompts.

Appendix B: Database Schema Sync Columns

The following columns are added at runtime via sync_db_schema() if they don’t exist:

Table Column Definition
kid target_reward_id INTEGER
behavior category VARCHAR DEFAULT ‘general’
reward category VARCHAR DEFAULT ‘general’
reward is_milestone BOOLEAN DEFAULT 0
reward suitable_male BOOLEAN DEFAULT 1
reward suitable_female BOOLEAN DEFAULT 1
reward is_custom BOOLEAN DEFAULT 0
reward_image reward_id INTEGER (FK)

Appendix C: Entity Relationship Summary

Kid ──┬── has many ── Claim ── belongs to ── Behavior
      ├── has many ── Goal ── belongs to ── Behavior
      ├── has many ── RewardImage ── belongs to ── Reward
      ├── has many ── RewardRedemption ── belongs to ── Reward
      ├── has many ── KidBadge ── belongs to ── Badge
      ├── has many ── AirdropClaim ── belongs to ── Airdrop
      └── belongs to (optional) ── Reward (target_reward_id)

Setting (standalone key-value store)

Comments (0)

Sign in to comment.