Scrabble Backend API (SnappyIdioms.com)
Server-side implementation for idiom syncing, pearl economy, and game session management
📍 Function Location:
functions/gameAPISupabase🔗 Integration Flow:
- 1. Famous.ai game → Platform API Proxy (Famous.ai server)
- 2. Platform Proxy → verifyGameToken (token validation)
- 3. Platform Proxy → gameAPISupabase (this function)
- 4. gameAPISupabase → Supabase (pearl balances, idioms, sessions)
⚠️ Security Notes:
- • Uses Supabase Service Role Key (server-side only)
- • Validates tokens via verifyGameToken endpoint
- • Implements CORS for cross-origin requests
- • Direct REST API fallback if supabase-js fails
💎 Pearl Caps:
- • Free Users: 50 pearls per week
- • Premium Users: 200 pearls per week
- • Week Reset: Every Monday at 00:00 UTC
🧮 Pearl Calculation Formula:
pearls = 1 + Math.floor(score / 100) + (isPerfect ? 5 : 0)
Base 1 pearl + 1 per 100 points + 5 bonus for perfect round
✅ Pearl Award Flow:
- 1. Game completes → Famous.ai calls
action: 'report-completion' - 2. Backend calculates pearls earned
- 3. Checks weekly cap (free vs premium)
- 4. Awards capped amount
- 5. Updates pearl_balances table
- 6. Logs transaction in pearl_rewards
- 7. Returns total + weekly remaining
📊 Tables:
synced_idioms
{
id: serial primary key,
phrase: text unique not null,
words: text[],
definition: text,
example: text,
difficulty: text,
category: text,
points: integer,
source: text,
mothership_id: text,
updated_at: timestamp
}pearl_balances
{
username: text primary key,
total_pearls: integer default 0,
weekly_pearls: integer default 0,
week_start: date,
is_premium: boolean default false,
updated_at: timestamp
}pearl_rewards
{
id: serial primary key,
username: text not null,
pearls_awarded: integer,
score: integer,
level: integer,
is_perfect: boolean,
idioms_completed: text[],
week_start: date,
created_at: timestamp
}mothership_config
{
id: serial primary key,
app_id: text,
auth_token: text,
entity_name: text default 'Idiom',
is_connected: boolean default false,
sync_status: text,
last_sync_at: timestamp,
last_sync_count: integer,
updated_at: timestamp
}game_sessions
{
id: serial primary key,
username: text,
source: text,
referrer: text,
character: text,
difficulty: text,
embed_mode: boolean,
mothership_user_id: text,
score: integer,
level: integer,
idioms_completed: integer,
session_start: timestamp default now(),
session_end: timestamp
}GET ?action=idioms
Fetch all synced idioms from database
Response: {
success: true,
idioms: [...],
count: 1234
}GET ?action=pearl-balance&username=X
Get pearl balance for specific user
Response: {
total_pearls: 150,
weekly_pearls: 25,
weekly_cap: 50,
weekly_remaining: 25,
is_premium: false,
cap_reached: false,
week_resets_at: "2026-02-24T00:00:00.000Z"
}POST action: 'report-completion'
Award pearls for completed game round
Request: {
action: 'report-completion',
username: 'player123',
score: 450,
level: 3,
is_perfect: true,
completed_idioms: ['break the ice', 'piece of cake']
}
Response: {
success: true,
pearls_calculated: 10,
pearls_awarded: 10,
total_pearls: 160,
weekly_pearls: 35,
weekly_remaining: 15,
cap_reached: false,
message: 'Earned 10 pearls!'
}POST action: 'sync-stash'
Sync offline pearl rewards when player reconnects
Request: {
action: 'sync-stash',
username: 'player123',
stash: [
{ score: 300, level: 1, is_perfect: false },
{ score: 500, level: 2, is_perfect: true }
]
}
Response: {
success: true,
synced: 2,
pearls_synced: 12,
total_pearls: 172,
weekly_remaining: 3
}POST action: 'connect'
Connect to Base44 mothership for idiom syncing
Request: {
action: 'connect',
app_id: '68eed6a8ca9efc733033fb04',
auth_token: 'optional_bearer_token',
entity_name: 'Idiom'
}
Response: {
success: true,
connected: true,
test_count: 1234,
message: 'Connected to Base44 app. Found 1234 test idioms.'
}POST action: 'fetch-idioms'
Fetch and sync all idioms from Base44
Response: {
success: true,
fetched: 1234,
synced: 1230,
errors: 4,
message: 'Successfully synced 1230 idioms from mothership'
}POST action: 'session'
Create game session for analytics
Request: {
action: 'session',
username: 'player123',
character: 'snappy',
difficulty: 'intermediate'
}
Response: {
success: true,
session_id: 42
}🛡️ Direct REST API Fallback:
If supabase-js client fails, the function automatically falls back to direct Supabase REST API calls:
- •
directSupabaseInsert()- POST to /rest/v1/table - •
directSupabaseSelect()- GET from /rest/v1/table - •
directSupabaseUpdate()- PATCH to /rest/v1/table - •
directSupabaseUpsert()- POST with merge-duplicates
⚙️ Safe Wrapper Functions:
async function safeInsert(supabase, table, data) {
try {
// Try supabase-js first
const { error, data: result } = await supabase
.from(table).insert(data).select().single();
if (error) throw error;
return result;
} catch (e) {
// Fall back to direct REST
console.warn('Trying direct REST...');
return await directSupabaseInsert(table, data);
}
}⚠️ Common Issues:
- • Invalid Supabase URL: Validates and cleans URL before use
- • Missing credentials: Clear error messages for missing env vars
- • Guest mode: Returns error when username is 'guest'
- • Weekly cap reached: Returns cap_reached: true
Required Secrets:
SUPABASE_URL=https://YOUR_PROJECT.supabase.co SUPABASE_SERVICE_ROLE_KEY=eyJhbGc...your_key_here
Set these in Base44 Dashboard → Settings → Environment Variables
This backend function implements the complete idiom sync and pearl economy system. Key features:
- ✅ Idiom syncing from Base44 → Supabase
- ✅ Pearl earning with weekly caps (free vs premium)
- ✅ Offline pearl stash syncing
- ✅ Game session tracking
- ✅ Direct REST API fallbacks for reliability
- ✅ CORS support for cross-origin requests
📄 Full Source Code:
View the complete implementation in functions/gameAPISupabase