Malaysian youth aren't broke because they don't know how to save. They're broke because knowing isn't enough at 1am when SaverEats is one tap away. SaveLah steps in at exactly that moment — not with another budgeting dashboard, but with a behavioural pause built directly into the payment flow.
Built for the GXBank Youth Resilience Challenge, targeting university students and fresh graduates caught in the BNPL debt trap.
Live demo Pitch deck Pitch video
Consumer debt among Malaysian youth has reached a critical threshold. BNPL usage generated RM 9.3 billion in the first half of 2025 alone, with 40% of transactions originating from users under 30. In 2024, 877 individuals under 25 were declared bankrupt. Financial literacy campaigns have not moved these numbers. The gap isn't knowledge — it's behaviour at the moment of temptation.
Every financial wellness app assumes the problem is information. They track, categorise, visualise, and educate. But users already know they spend too much on food delivery at midnight. What they need isn't a better graph of their bad decisions after the fact — they need friction before the tap goes through.
SaveLah relocates the intervention from the post-mortem to the moment of intent.
When a user initiates a payment that crosses a behavioural threshold — late night, over budget, third purchase in the same category today — SaveLah intercepts it before authorisation. An AI teammate calls it out in plain language, referencing their actual goal and actual numbers. The user can hold the purchase for later reflection, or proceed with full awareness. Either way, the unconscious tap becomes a conscious choice.
Every cash-in automatically routes a configurable slice to a savings goal before the user can spend it. A daily streak creates a loss-aversion anchor that makes breaking the habit feel costly. A monthly Wrapped summary makes the invisible visible.
| Feature | What it does | Why it works |
|---|---|---|
| Quarantine | Intercepts flagged payments before the PIN screen | Creates a mandatory pause between impulse and action — the gap where better decisions live |
| Scold Mode | AI-generated callout referencing the user's real goal and real numbers | Personalised friction is harder to dismiss than a generic warning |
| Compliment Mode | AI celebration when the user resists or hits a milestone | Positive reinforcement closes the behavioural loop |
| Auto-Save | Configurable % of every cash-in routed to savings before it touches the main balance | Automates the hardest part — starting — by making saving the default, not the exception |
| Save Streak | Daily habit counter with loss-aversion mechanics | Prospect theory: losing a 12-day streak hurts more than the pleasure of one skipped saving day |
| SaveLah Wrapped | Monthly story-card summary of savings and blocked impulses | Makes progress tangible and shareable — social proof for the habit |
| Squad Save | Streak-sharing with friends | Accountability compounds when it's visible to people whose opinion matters |
SaveLah uses Google Gemini 2.5 Flash-Lite for two real-time text generation features: Scold Mode and Compliment Mode. Both run through server-side Next.js Route Handlers and stream responses as SSE.
The implementation uses a hybrid scripted-and-live architecture designed so the demo never breaks regardless of network conditions:
- A pre-written message renders instantly the moment quarantine fires — no loading state, no spinner
- The Gemini API call fires in parallel with an 8-second timeout
- When the first token arrives, the UI crossfades from the scripted message to the live one and shows a Live AI badge
- If the call fails or times out, the scripted message stays — no error, no broken experience
The prompts are constrained by safety rules: Scold Mode only references financial data (amounts, budget percentages, goal progress, time of day). It never references body, identity, lifestyle, or mental health. All framing uses "we" — SaveLah is a teammate, not a judge.
The visual language is built on a six-stop forest green palette (#0D1F12 through #DAF1DE) with a three-layer surface system (bg, bg-surface, bg-inset). All colour values are CSS custom properties so light and dark themes share a single component tree.
Typography pairs Lato for UI copy (weights 400/700/900) with DM Mono for all numeric and currency displays, creating a clear visual distinction between information and data.
The app supports both light and dark themes, detected from OS preference on first load and persisted to localStorage.
| Layer | Choice | Rationale |
|---|---|---|
| Framework | Next.js 15, App Router, TypeScript (strict) | Server components for AI route handlers, client components for state-heavy UI |
| Styling | Tailwind CSS v3 + CSS custom properties | Tailwind for layout velocity; CSS vars for theme-responsive colour without duplication |
| State | Zustand v5 + persist middleware | Minimal API, localStorage persistence, zero boilerplate for a prototype |
| Animation | Framer Motion v11 | Spring physics for sheet animations; layout animations for list mutations |
| AI | Gemini 2.5 Flash-Lite via @google/genai | Fast first token, free tier sufficient for demo, server-side only |
| Icons | lucide-react | Consistent stroke weight across the design system |
Live demo available: https://save-lah.vercel.app
Prerequisites: Node.js 18.18 or later and a free Gemini API key from https://aistudio.google.com/apikey
npm install
cp .env.local.example .env.local # paste your GEMINI_API_KEY
npm run dev # http://localhost:3000The app opens in onboarding. After completing setup, the demo persona is pre-loaded: RM 837.50 balance, 12-day streak, food spending primed at 95% of the weekly limit, and a New Laptop savings goal at 7.8% progress.
To reset the demo to its clean initial state at any point: Settings > Reset Demo.
A complete walkthrough takes under 90 seconds:
- Home — balance card, streak at 12 days, food guardrail bar at 95%
- Pay — SaverEats, RM 89, tap Authorize
- Quarantine fires — AI scold references the late-night timing, the food budget, and the laptop goal simultaneously
- Hold it for me — item parked in the Cooling Off list
- Resist — Compliment Mode celebrates the decision
- Wrapped — swipe through the April story cards
save-lah/
├── app/
│ ├── api/
│ │ ├── scold/route.ts # Streaming Gemini scold endpoint
│ │ └── compliment/route.ts # Streaming Gemini compliment endpoint
│ ├── home/ # Dashboard
│ ├── pay/ # Payment flow + quarantine trigger
│ ├── quarantine/ # Cooling Off list
│ ├── savings/ # Goal progress + auto-save config
│ ├── wrapped/ # Monthly story-card summary
│ ├── squad/ # Social streak sharing
│ ├── settings/ # User configuration
│ └── onboarding/ # First-run setup flow
├── components/ # Shared UI components
├── lib/
│ ├── store.ts # Zustand state + actions
│ ├── anomaly.ts # Rules-based transaction flagging
│ ├── ai-client.ts # Client-side SSE streaming wrapper
│ ├── gemini.ts # Server-side Gemini client
│ ├── prompts.ts # Scold and compliment prompt builders
│ └── fallbacks.ts # Scripted message banks
└── types/ # Shared TypeScript types
Built for the GXBank Youth Resilience Challenge, by team Hack 'n Fly.
SaveLah is a hackathon prototype. No real banking integration. All transactions are simulated. Not affiliated with GX Bank Berhad.
All rights reserved by the team.