A real-time Bitcoin price guessing game built with SvelteKit and AWS serverless architecture.
Live Demo: https://guessgame.sdrdhlab.xyz
- CLAUDE.md - Quick reference for Claude Code (architecture overview, key patterns, workflows)
- ALTERNATIVES_AND_IMPROVEMENTS.md - Architecture alternatives considered and future improvements
- backend/DEVELOPMENT.md - Complete backend development guide (CDK, Lambda, DynamoDB, GraphQL)
- frontend/DEVELOPMENT.md - Complete frontend development guide (Svelte 5, state management, GraphQL)
Players guess whether the Bitcoin price will go UP or DOWN. After 60 seconds, the guess is resolved and players earn points for correct predictions.
- Real-time Bitcoin price updates via WebSocket subscriptions
- Countdown timer showing time until guess resolution
- Live price update timestamps
- AWS Cognito authentication with email verification
- Serverless backend with AWS Lambda, DynamoDB, SQS, and AppSync
- Live guess resolution with automatic scoring
- Guess history tracking
- Mobile-responsive UI with shadcn-svelte components
- S3 + CloudFlare deployment for production hosting (no CloudFront needed!)
- Framework: SvelteKit with Svelte 5
- Styling: Tailwind CSS v4 + shadcn-svelte
- Auth: AWS Amplify
- API: GraphQL via AWS AppSync
- Hosting: S3 Static Website + CloudFlare CDN
- API: AWS AppSync (GraphQL)
- Auth: AWS Cognito
- Database: DynamoDB
- Queue: SQS for delayed guess resolution
- Functions: 6 Lambda functions
createGuess- Validates and creates new guessesresolveGuess- Resolves guesses after 60s with retry logicgetUser- Fetches user profile and scoregetGuessHistory- Fetches user's guess historypostConfirmation- Cognito trigger that creates user profile after signupstreamProcessor- Pushes real-time updates via AppSync
- Node.js 18+ and npm
- AWS Account with credentials configured
- AWS CLI installed
Deploy everything (backend + frontend) in one command:
# Navigate to backend directory
cd backend
# Install dependencies
npm install
# Bootstrap CDK (first time only)
npx cdk bootstrap
# Deploy all stacks including frontend
npm run deployThe frontend stack will automatically:
- Build the SvelteKit app locally
- Upload to S3
- Enable S3 static website hosting
After deployment, you'll see outputs including:
- WebsiteEndpoint: S3 website endpoint (for CloudFlare CNAME)
- Cognito User Pool ID
- AppSync API Endpoint
- And more...
After deploying, set up your custom domain with CloudFlare DNS:
-
Add CNAME Record: CloudFlare Dashboard → DNS → Records
- Type: CNAME
- Name:
guessgame(or your subdomain) - Target: Your S3 website endpoint (from CDK output)
- Proxy Status: Proxied (orange cloud) ✅
-
SSL/TLS Settings: CloudFlare Dashboard → SSL/TLS
- Set to Full (not Flexible or Full Strict)
-
Test: Visit
https://yourdomain.com- should load with HTTPS
Why CloudFlare? The sdrdhlab.xyz domain is already managed in CloudFlare DNS. Using CloudFlare for both DNS and CDN is simpler than introducing CloudFront (would require managing SSL certificates between CloudFront and CloudFlare, and adds another layer of complexity). S3 Static Website + CloudFlare provides a streamlined deployment with fewer moving parts.
For local development:
cd frontend
# Install dependencies
npm install
# Configure AWS settings (auto-populated from CDK outputs)
# Edit src/lib/aws-config.ts if needed
# Run development server
npm run dev
# Build for production (optional - CDK does this automatically)
npm run buildTo update just the frontend:
cd backend
npx cdk deploy GuessGameFrontendStackThis will rebuild and redeploy the frontend automatically.
- Register: Create a new account with email and password (minimum 8 characters, must include number and special character)
- Verify Email: Enter the 6-digit code sent to your email
- Login: Sign in with your credentials
- Watch Live Price: See real-time Bitcoin price updates with timestamps
- Make a Guess: Click UP or DOWN based on your prediction
- Track Countdown: Watch the timer count down from 60 seconds
- See Resolution: Your guess automatically resolves and score updates
- View History: Check your recent guesses and win rate
cd backend
npm run build # Compile TypeScript
npm test # Run tests (52 tests)
npm run deploy # Deploy all stacks
npx cdk synth # Synthesize CloudFormation
npx cdk diff # Show changes
npx cdk destroy # Tear down all stackscd frontend
npm run dev # Development server (port 5173)
npm run build # Production build
npm run preview # Preview production build
npm run check # Type checkingThe backend includes comprehensive tests for all Lambda functions:
cd backend
npm testTest Coverage: 52 tests covering:
- User creation and validation (postConfirmation)
- Guess creation and validation (createGuess)
- User profile retrieval (getUser)
- Guess history retrieval (getGuessHistory)
- Price fetching and caching (shared utilities)
- Guess resolution with retry logic (resolveGuess)
- Real-time stream processing (streamProcessor)
- Register a new user
- Login to the application
- Make an UP or DOWN guess
- Observe real-time price updates
- Wait 60 seconds for guess resolution
- Verify score update
- Check guess history
Note: These are rough estimates (guesstimates) based on AWS pricing as of the documentation date. Actual costs may vary based on usage patterns, data transfer, AWS region, and pricing changes. Monitor your AWS billing dashboard for accurate cost tracking.
- ~$1.30/month
- Lambda: $8.40
- DynamoDB: $1.25
- AppSync: $1.00
- SQS: $0.52
- Cognito: $0.40
- Data Transfer: $0.01
- Total: ~$11.58/month
guessgame/
├── frontend/ # SvelteKit frontend
│ ├── src/
│ │ ├── lib/
│ │ │ ├── components/ui/ # shadcn-svelte components
│ │ │ ├── aws-config.ts # Amplify configuration
│ │ │ ├── graphql-client.ts # GraphQL queries/mutations
│ │ │ └── stores/
│ │ │ ├── auth.svelte.ts # Authentication store
│ │ │ └── game.svelte.ts # Game state store
│ │ └── routes/
│ │ ├── +layout.svelte # Root layout with auth
│ │ ├── +page.svelte # Home/game page
│ │ ├── login/+page.svelte # Login/register page
│ │ └── verify/+page.svelte # Email verification page
│ └── app.css # Global styles (Tailwind v4)
│
└── backend/ # AWS CDK infrastructure
├── lib/stacks/
│ ├── auth-stack.ts # Cognito User Pool
│ ├── database-stack.ts # DynamoDB Tables
│ ├── queue-stack.ts # SQS Queue
│ ├── compute-stack.ts # Lambda Functions
│ ├── api-stack.ts # AppSync API
│ ├── integration-stack.ts # Stream Processor
│ └── frontend-stack.ts # S3 Static Website (+ CloudFlare)
├── lambdas/
│ ├── createGuess/ # Create guess Lambda
│ ├── resolveGuess/ # Resolve guess Lambda
│ ├── getUser/ # Get user Lambda
│ ├── getGuessHistory/ # Get guess history Lambda
│ ├── postConfirmation/ # Cognito post-signup Lambda
│ ├── streamProcessor/ # Real-time updates Lambda
│ └── shared/ # Shared utilities
└── schema/
└── schema.graphql # GraphQL schema
- SQS Requeuing Pattern: Uses message requeuing for retries instead of internal loops
- Price Caching: Caches fetched prices in DynamoDB for concurrent guess resolution
- Historical Lookup: Checks cached prices first using filter expressions
- Real-time Updates: Dual-purpose streamProcessor for both guess and price updates
- Svelte 5 Runes: Uses modern Svelte 5 reactivity with
$stateand$derived
Problem: CDK deploy fails with "Unable to resolve AWS account"
- Solution: Run
aws configureand set up credentials
Problem: Tests fail with SQS mocking errors
- Solution: These are non-critical mocking issues. The 50 core tests pass.
Problem: "Amplify is not configured"
- Solution: Ensure
.envfile has correct AWS values
Problem: GraphQL errors in console
- Solution: Check AppSync endpoint and authentication in
.env
Problem: Subscriptions not working
- Solution 1: Verify AppSync has real-time subscriptions enabled
- Solution 2: Check for mutation/schema mismatches - subscription filters must match mutation response fields
- Solution 3: Ensure filtered attributes (e.g.,
userIdinonGuessUpdated(userId: $userId)) are included in the GraphQL schema's subscription definition and mutation response type
MIT
Built with:
