Building an application that works on localhost is one thing. Making it work in a production environment is an entirely different challenge.
Recently, I built FlashSeat, a full-stack event reservation application, to gain practical experience with backend development, cloud infrastructure, databases, and software deployment.
The goal was not simply to create another CRUD application. I wanted to understand how different components of a real-world web application communicate and how to deploy them reliably.
Building the Application
FlashSeat allows users to browse events, authenticate with Google, and reserve tickets. It also includes administrative functionality for creating events and uploading images.
I used the following technologies:
- Frontend: React, TypeScript, and Vite
- Backend: Node.js, Express, and TypeScript
- Database: PostgreSQL
- Authentication: Firebase Authentication
- Storage: Amazon S3
- Infrastructure: AWS EC2, RDS, and Amplify
- Deployment: Docker and Caddy
One of my priorities was keeping the architecture understandable while using technologies commonly found in production environments.
The frontend communicates with the backend through REST APIs. The backend handles authentication, validates requests, executes database operations, and communicates with AWS services.
Moving to Production
Initially, the application ran locally using Docker and PostgreSQL.
Deploying it to AWS introduced several challenges that I had not encountered during local development.
I deployed the frontend using AWS Amplify and the backend to an EC2 instance running Docker. PostgreSQL was hosted separately using Amazon RDS, while Caddy handled HTTPS and reverse proxying.
During deployment, I encountered database connectivity issues, missing environment variables, and configuration problems between the frontend and backend.
Debugging these problems required understanding how networking, DNS, security groups, and application configuration interact.
It was an important reminder that deploying software requires skills beyond writing application code.
Improving Reliability
Ticket reservations involve more than inserting records into a database.
If multiple users attempt to reserve the final available ticket simultaneously, the system must maintain consistent inventory.
To address this, I implemented PostgreSQL transactions and row-level locking using SELECT … FOR UPDATE.
I also added automated tests using Vitest and Supertest, along with a GitHub Actions workflow for running checks during development.
What I Learned
FlashSeat helped me connect several areas of software engineering that I had previously studied separately.
I gained practical experience with:
- Designing REST APIs and relational database schemas
- Deploying applications using AWS and Docker
- Debugging production infrastructure
- Managing authentication and cloud storage
- Improving reliability through database transactions and automated testing
Most importantly, I learned that building a feature and operating it reliably are two different responsibilities.
FlashSeat is still a learning project, but it has given me a much clearer understanding of what backend engineering involves beyond writing API endpoints.