This is a submission for the GitHub Finish-Up-A-Thon Challenge
What I Built
Chatlings is a serverless, real-time chat platform built specifically for children aged 8–14. Every message is screened by AI before anyone else sees it. Every image upload is scanned for inappropriate content. The whole thing runs on AWS and deploys with a single command.
Demo
🔗 Live app: https://d19ptumhqepwqw.cloudfront.net
📂 GitHub: https://github.com/TrickSumo/Chatlings
Where It Was Before This Hackathon
I had built the core of Chatlings using React frontend, WebSocket API, DynamoDB, Lambda functions, and Cognito auth. The features were there. What was missing was the infrastructure layer actually to ship it properly and make it production-ready.
Here's what was unfinished:
-
No IaC. There was no CDK stack. Deployment meant clicking through the AWS console, copying outputs by hand, writing
.envmanually, building, syncing to S3, and invalidating CloudFront. Overall, a 12-step, 1-2 hour process every single time. -
Several DynamoDB bugs: chat history returning max 60 messages, broadcast making N individual reads per member instead of a
BatchGetCommand,UnprocessedKeyssilently dropped in group listing, and stale connection IDs never cleaned up on 410 Gone. - No test coverage. Lambda functions had zero tests.
The core app was there, including real-time chat, AI moderation, image sharing, and Cognito auth. This hackathon was about making it IaC-ready, one-command deployable, tested, and actually shippable.
The Comeback Story
1. One-Command Deployment
The main goal. I wrote a full AWS CDK stack covering every piece of infrastructure, including DynamoDB, S3, 14 Lambda functions, HTTP API Gateway, WebSocket API Gateway, CloudFront, Cognito and wrapped it in a deploy.sh script wired to npm run deploy.
npm run deploy
That one command now:
- Runs
cdk deployand provisions the entire stack - Parses CDK outputs to get CloudFront domain, Cognito config, and S3 bucket
- Writes
Frontend/.envwith the resolved values - Builds the React app and syncs it to S3
- Invalidates the CloudFront cache
Before this, every deploy was manual. Copy outputs, write env vars, build, sync, invalidate. Now it's one command.
2. DynamoDB Fixes
Four bugs that had been quietly sitting in the Lambda code:
Newest messages first: ScanIndexForward defaults to ascending, so chat history was loading from the very beginning. Added ScanIndexForward: false + Limit: 60 + LastEvaluatedKey pagination.
BatchGetCommand instead of N reads: MessageAnalyzer was making one DynamoDB read per group member to fetch connection IDs. Replaced with a single BatchGetCommand + UnprocessedKeys retry loop:
UnprocessedKeys dropped: Same fix pattern applied to ListGroupsForUser. It was silently discarding groups when DynamoDB couldn't process the full batch in one shot.
Stale connection cleanup: When API Gateway returns 410 Gone (connection no longer exists), the handler now removes the stale connectionId from DynamoDB instead of letting them accumulate.
4. Test Coverage
Zero tests existed before this hackathon. I added 25 unit tests across 6 Lambda functions using Jest and aws-sdk-client-mock.
npm test
My Experience with GitHub Copilot
GitHub Copilot was most useful during the CDK and Lambda work. When I was setting up the CloudFront behaviors in cdk/lib/cloudfront.ts, Copilot autocompleted the OriginRequestPolicy import and the property name.
Used GitHub Copilot agent mode to generate mock and test cases for all lambda functions single-handedly. It worked just in a single attempt! 5mins!
The BatchGetCommand + UnprocessedKeys retry loop was a pattern I knew existed, but couldn't remember the exact shape of. Copilot's suggestion was nearly correct on the first try. I adjusted the retry condition, and it worked.
Where Copilot was less helpful: the signed-cookie CloudFront bug. That was a pure config-layer problem, and no amount of code generation helps when you need to understand why CloudFront strips headers by default. I had to read the AWS docs and reason through them myself.
Wrapping Up
Honestly, this hackathon was more fun than I expected. Chatlings had been sitting in my GitHub for a year, but having a deadline changed that completely.
Working with GitHub Copilot throughout made the process faster. When I was deep in CDK configuration or writing repetitive Lambda boilerplate, Copilot filled in the gaps so I could keep thinking about the problem instead of syntax.

Top comments (0)