01
Public application
- Discover businesses
- Browse products and services
- Favorites
- Reviews
- Public business pages
Independent product · Engineering retrospective
Building a local discovery platform from idea to production.
Or-by is a platform designed to help people discover nearby businesses, products, and services. It became my main independent project and the place where I learned that building software involves much more than writing code.

The idea started with a simple observation. Large cities usually have shopping centers that bring stores, products, and services together in one place. Smaller cities often do not have the same experience.
I started wondering whether a digital product could work as a kind of local virtual shopping center, helping people discover what exists around them and giving local businesses a more structured way to present their products and services.
AI accelerated implementation. Product, architecture, review, debugging, infrastructure, and production decisions remained my responsibility.
I started working on Or-by when I was still learning Node.js, before generative AI tools became part of my development workflow.
The project evolved over time. Later, I began using AI coding agents as development assistants. They did not replace architecture, validation, debugging, or technical decisions, but they reduced the time required to explore solutions and build interfaces.
Frontend development used to be one of the slowest parts of my process because I would first design screens in tools such as Figma and then implement them manually. Combining AI-assisted development with a component library significantly accelerated interface iteration and helped me turn the idea into an MVP.
01
02
03
04
The public app, owner hub, and admin are Next.js applications. API requests reach NGINX on EC2, which forwards them to the Node.js and Express service. The API persists data in private RDS PostgreSQL through TypeORM, while media uploads use presigned URLs for direct PUT requests to Cloudflare R2 outside AWS.
The public app, owner hub, and admin are Next.js applications. Their API requests enter an AWS VPC through NGINX on a public EC2 instance and reach a Node.js and Express container. The API accesses PostgreSQL in private RDS subnets through TypeORM. For media, the API issues a presigned URL and the browser uploads directly to Cloudflare R2 outside AWS. ECR stores the API image, and Terraform provisions the AWS resources without participating in request processing.
Product interfaces used by visitors, business owners, and platform administrators.
API request flow
AWS production boundary
A VPC with the EC2 runtime in a public subnet and PostgreSQL in private database subnets.
Receives HTTPS traffic and forwards API requests to the application container.
Approximately 110 endpoints running as the application service.
Persistent data with database access restricted to the EC2 security group.
Direct media flow
Direct PUT upload from the application, outside the AWS boundary.
Provisioning layer · outside the request flow
Terraform · Defines the VPC, subnets, security groups, IAM, EC2, RDS, ECR, and optional alarms.
05.1
Early in the project, image uploads passed through the backend. That approach increased coupling and made the application server process file transfers outside the core business flow.
The current flow uses presigned URLs: the client requests an authorized URL and uploads directly to Cloudflare R2 with PUT. File type, extension and a 5 MB size limit are validated across the client and server boundaries, keeping the file transfer separate from the API.
The next iteration should add retry strategies, clearer upload state tracking, and stronger failure recovery.
05.2
As the backend grew to approximately 110 REST endpoints, consistent patterns and a clear architecture became increasingly important.
Following the same conventions for modules, validation, services, controllers, errors, and persistence made the API easier to understand and maintain, even as its scope increased.
05.3
Or-by gave me practical experience with application security through concrete safeguards: Zod schemas for body and query validation, authentication and authorization rules, Helmet headers, a CORS allowlist, targeted rate limiting, and request payload limits.
These mechanisms reduce common risks without implying absolute security. The important shift was treating security hardening as part of the architecture rather than a task left until after development.
The most challenging part of Or-by was making the application available in a real production environment.
My first AWS deployment took around four hours just to configure and connect the required pieces. I had to understand EC2, a private RDS PostgreSQL instance, VPCs, subnets, networking, ECR, containers, domains, and how the application components would communicate.
NGINX was configured as a reverse proxy, routing incoming requests to the Node.js application and avoiding direct exposure of the application process. TLS is managed through Certbot, and NGINX enforces the configured 5 MB request body limit. Docker Compose runs the application containers, Terraform describes the AWS infrastructure, and Cloudflare R2 stores media outside AWS.
This experience changed how I think about software engineering. Writing features is only one part of the work. A real application also needs to be deployed, observed, maintained, recovered, and kept available.
My biggest lesson from Or-by was not about a framework or language.
The project showed me that real software engineering is not only about making a feature work. It is also about anticipating failure, understanding bottlenecks, reducing coupling, planning recovery, controlling infrastructure costs, and keeping the application available over time.
That is where software stops being only code and becomes a system that someone must operate and take responsibility for.



Private repository