Live interactive presentation platform showcasing real-time features with SST, Next.js, and AWS IoT Core.
Built for the WarsawJS 2025 presentation: "From AWS Overwhelm to SST Confidence"
This is a complete real-time web application that allows:
- ๐ฌ Live Chat - Audience members can chat in real-time during the presentation
- ๐ณ๏ธ Live Polls - Interactive voting with instant results visualization
- ๐๏ธ Admin Dashboard - Control the presentation flow and enable/disable features
- ๐ Live Slides - Slidev presentation with real-time data integration
All of this is powered by SST (Serverless Stack) and deployed to AWS with just one command!
This project demonstrates how SST makes AWS accessible by:
- Type-safe Infrastructure as Code - Define your AWS resources in TypeScript
- Instant Local Development - Work with real AWS services locally with
sst dev - Built-in Real-time - MQTT over WebSocket via AWS IoT Core, zero config
- Monorepo Support - Share code between frontend, backend, and infrastructure
- Production Ready - Deploy to multiple stages with one command
# Complex CloudFormation YAML
Resources:
MyIoTPolicy:
Type: AWS::IoT::Policy
Properties:
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action: iot:Connect
Resource: !Sub arn:aws:iot:${AWS::Region}:${AWS::AccountId}:*// Simple, typed, and powerful
const realtime = new sst.aws.Realtime("Chat", {
handler: "chat.handler"
});โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ AWS CLOUD โ
โ โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โ
โ โ Next.js โโโโโโโบโ AWS IoT โโโโโโโบโ Lambda โ โ
โ โ Web App โ MQTT โ Core โ Auth โ Functions โ โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โ
โ โ Admin โโโโโโโบโ DynamoDB โ โ Amazon SES โ โ
โ โ Dashboard โ โ Tables โ โ Email โ โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโ โ
โ โ Slidev โ โ
โ โ Slides โ (Static Site on S3 + CloudFront) โ
โ โโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
warsawjs/
โโโ packages/
โ โโโ core/ # ๐ฏ Shared business logic
โ โ โโโ realtime/ # MQTT client & types
โ โ โโโ auth/ # Authentication
โ โ โโโ email/ # Email service
โ โ โโโ dynamo/ # Database entities
โ โ
โ โโโ functions/ # โก Lambda functions
โ โ โโโ src/
โ โ โโโ api/ # REST API handlers
โ โ โโโ auth/ # Auth callbacks
โ โ โโโ realtime/ # MQTT authorizer
โ โ
โ โโโ web/ # ๐ Public web app (Next.js)
โ โโโ admin/ # ๐๏ธ Admin dashboard (Next.js)
โ โโโ slides/ # ๐ Presentation slides (Slidev)
โ
โโโ infra/ # โ๏ธ Infrastructure definitions
โ โโโ realtime.ts # AWS IoT Core setup
โ โโโ database.ts # DynamoDB tables
โ โโโ auth.ts # OpenAuth config
โ โโโ ...
โ
โโโ sst.config.ts # ๐ง SST configuration
- Node.js 18+ or Bun (recommended)
- AWS Account with credentials configured (guide)
- SST CLI (installed automatically with npm)
# 1. Clone the repository
git clone https://github.com/keanuharrell/warsawjs.git
cd warsawjs
# 2. Install dependencies (using Bun - fast!)
bun install
# 3. Set required secrets
npx sst secret set RealtimeWriteToken "your-write-token-here"
npx sst secret set RealtimeReadOnlyToken "your-readonly-token-here"
# 4. Start development (this will deploy to AWS!)
npx sst devThat's it! ๐ Your app is now running with:
- โ Real AWS services (DynamoDB, IoT Core, Lambda)
- โ Live reload for instant feedback
- โ Local function invocation
- โ Real-time infrastructure updates
Once sst dev is running:
- ๐ Web App: http://localhost:3000
- ๐๏ธ Admin Dashboard: http://localhost:3001
- ๐ Slides: http://localhost:3030 (run
cd packages/slides && bun dev)
Real-time messaging between all connected participants.
How it works:
- Users type messages in the web app
- Messages are published to MQTT topic
warsawjs/{stage}/chat - All connected clients (including slides) receive updates instantly
- Messages are stored in DynamoDB for persistence
// It's this simple!
const { messages, publish } = useRealtimeTopic<ChatMessage>('chat')
// Publish a message
publish({ id: '1', text: 'Hello!', username: 'John', timestamp: Date.now() })Interactive polls with real-time results.
How it works:
- Users vote by clicking an option (A, B, C, or D)
- Votes are stored in DynamoDB (upsert by userId)
- Real-time updates via MQTT show live percentages
- Slides display results in a beautiful 2x2 grid
Features:
- โ One vote per user (stored in localStorage)
- โ Vote persistence across page refreshes
- โ Winner card highlighted with ๐
- โ Smooth animations and progress bars
Control the entire presentation flow.
Features:
- ๐ก Enable/disable chat and voting
- ๐ Reset all demo data
- ๐ View real-time connection status
- โ๏ธ Send email summaries
Admin Flow:
1. Open admin dashboard
2. Authenticate (OpenAuth)
3. Enable Chat โ Participants can now chat
4. Enable Vote โ Poll appears on all devices
5. Reset โ Clean slate for next demo
Slidev presentation with embedded real-time components.
Cool Features:
- Live chat messages appear during Demo #1
- Live vote results displayed during Demo #2
- QR code for easy audience participation
- Connection status indicator
| Category | Technology | Why? |
|---|---|---|
| Framework | SST | Type-safe IaC, instant local dev |
| Frontend | Next.js 15 | React framework with App Router |
| Slides | Slidev | Markdown-based slides with Vue |
| Real-time | AWS IoT Core | Managed MQTT broker |
| Database | DynamoDB | Serverless NoSQL database |
| Auth | OpenAuth | Modern auth for serverless |
| Amazon SES | Scalable email service | |
| Styling | Tailwind CSS + shadcn/ui | Beautiful, accessible components |
| ORM | ElectroDB | DynamoDB made easy |
This project uses AWS IoT Core for real-time communication via MQTT over WebSocket.
Topics Structure:
{app}/{stage}/{feature}
Examples:
- warsawjs/dev/chat (development chat)
- warsawjs/prod/vote (production voting)
- warsawjs/dev/control (admin control)
Authorization:
- JWT tokens for admin users (full access)
- Static write token for participants (chat + vote)
- Static read-only token for slides (subscribe only)
The realtime/authorizer.ts Lambda function validates tokens and returns fine-grained permissions:
// Admin (JWT) โ Full access
{ publish: ["warsawjs/dev/*"], subscribe: ["warsawjs/dev/*"] }
// Write token โ Can chat and vote
{ publish: ["warsawjs/dev/chat", "warsawjs/dev/vote"], subscribe: ["warsawjs/dev/*"] }
// Read-only token โ Slides can only subscribe
{ publish: ["warsawjs/dev/_readonly_dummy"], subscribe: ["warsawjs/dev/*"] }The core package is the heart of the application:
- Shared types and business logic
- Framework-agnostic MQTT client
- Reusable across web, admin, functions, and slides
This ensures:
- โ Type safety across packages
- โ Single source of truth
- โ Easy refactoring and updates
npx sst deploy --stage stagingnpx sst deploy --stage productionUpdate infra/dns.ts with your domain:
export const domain = "yourdomain.com"SST will automatically:
- Create CloudFront distributions
- Set up SSL certificates
- Configure DNS records (via Cloudflare)
-
Define types in
packages/core/src/realtime/types.ts:export interface MyFeatureMessage { id: string data: string timestamp: number }
-
Add topic to
TopicTypeunion:export type TopicType = 'chat' | 'vote' | 'control' | 'my-feature'
-
Use in React with the hook:
const { messages, publish } = useRealtimeTopic<MyFeatureMessage>('my-feature')
-
Update authorizer permissions if needed in
functions/src/realtime/authorizer.ts
MQTT Connection Issues:
- Check browser console for
[MQTT]logs - Verify tokens are set:
npx sst secret list - Test topic format:
{app}/{stage}/{feature}
Lambda Functions:
- View logs:
npx sst logs - Tail specific function:
npx sst logs --stage dev --function RealtimeAuthorizer
Infrastructure:
- View resources:
npx sst console - Check CloudFormation: AWS Console โ CloudFormation
This project was created for a WarsawJS presentation, but feel free to:
- โญ Star the repo if you found it helpful
- ๐ Report issues or bugs
- ๐ก Suggest improvements
- ๐ Fork and build your own version
MIT License - feel free to use this code for your own projects!
Keanu Harrell
- ๐ Website: keanuharrell.com
- ๐ GitHub: @keanuharrell
- ๐ง Email: [email protected]
- WarsawJS community for the opportunity to present
- SST team for building an amazing framework
- WebDevCody for the YouTube video that introduced me to SST
- Everyone who contributed to the open-source libraries used in this project
๐ฅ Coming soon! Link to the WarsawJS presentation recording
Built with โค๏ธ using SST
Documentation ยท Discord ยท GitHub