Web Paskibraka: My First Deployed Project and Five Lessons That Stuck
My first real project had a live domain and real visitors. It broke in a way I did not see coming, for a reason I did not fully understand until well after it happened. This is that story, and the five things I still think about from it.
The Context
A landing page for a school's Paskibraka organization, the student flag-raising corps in Indonesia. The purpose: introduce the organization to prospective new members, explain what the team does, and display a photo gallery of past activities to attract recruits.
I built this with one friend. I handled the backend; he handled the frontend. We worked independently, met at a cafe to merge our work, deployed to cPanel, and got a real domain up and running.
Stack:
- Backend: PHP (pure, no framework)
- Architecture: MVC (Model-View-Controller)
- Frontend: Bootstrap with a UI template
- Database: MySQL, managed via phpMyAdmin
- Hosting: Shared cPanel
The MVC Architecture
We structured the codebase using MVC, separating concerns without any framework assistance.
app/
├── controllers/
│ ├── HomeController.php # handles home page routing
│ ├── GalleryController.php # handles photo gallery logic
│ └── MemberController.php # handles team member pages
├── models/
│ ├── Photo.php # database queries for photos
│ └── Member.php # database queries for members
├── views/
│ ├── home.php
│ ├── gallery.php
│ └── partials/
│ ├── header.php
│ └── footer.php
└── public/
├── index.php # single entry point
└── assets/
├── css/
├── js/
└── images/
Controllers handled request logic and routing. Models queried the database. Views rendered output. Even without a framework enforcing this structure, it kept the codebase navigable as the project grew.
The Monorepo Structure
Despite being built by two people working separately, this was effectively a monorepo: one codebase, one deployment, frontend and backend merged together.
project/
├── backend/ # PHP MVC: controllers, models, config
│ ├── controllers/
│ ├── models/
│ └── config/
│ └── database.php # MySQL connection
├── frontend/ # Bootstrap template and static assets
│ ├── css/
│ ├── js/
│ └── templates/
└── public/
└── index.php # all requests routed through here
We combined our work manually at those cafe sessions. No Git, no branching, no pull requests. Just two laptops and file-by-file comparison. It worked, with significant friction.
How We Deployed: cPanel
We hosted on shared cPanel hosting, which gave us a working environment without any server configuration.
| Feature | cPanel (Shared) | VPS |
|---|---|---|
| Setup | No server configuration needed | Full manual setup required |
| Database | phpMyAdmin included | Install and configure yourself |
| Cost | Low monthly fee | Scales with compute resources |
| Control | Limited to panel options | Full root access |
| Performance | Shared across tenants | Dedicated resources |
| Best for | Simple apps, early projects | Custom stacks, production systems |
For a first project, cPanel was the right choice. It removed the infrastructure layer entirely so we could focus on building.
What Broke It
The site ran well until we started filling the photo gallery.
First approach: upload images directly to the cPanel file manager. Storage limits filled up faster than expected. So we switched to a shortcut we thought was smart: all the raw photos were already stored on Google Drive, so we referenced them directly using Drive share links in the gallery.
The result was immediate and catastrophic.
Every gallery page load now triggered twenty-plus separate HTTP requests to Google Drive, one per image. No compression, no CDN, no lazy loading. Raw phone photos averaging 4 to 8 MB each, fetched sequentially from an external server with its own latency and rate limits.
Page load time stretched beyond a minute. Navigation between pages was worse. The site quietly stopped being used.
Five Key Learnings
Image loading is an engineering problem, not a cosmetic detail. Raw photos from a smartphone are large. Loading twenty of them on a single page without compression or lazy loading will always break the experience. Techniques like lazy loading, WebP compression, scroll-triggered rendering, and CDN delivery all exist because unmanaged images are a genuine performance concern at any scale.
External resource dependencies become latency dependencies. Every image hosted on Google Drive was a request we could not control: subject to Drive's response time, rate limits, and availability. The correct architecture separates compute from storage, but the storage layer needs to be built for serving assets, not file sharing. Services like AWS S3 or the self-hosted MinIO exist for exactly this purpose.
Version control is not optional when two people share code.
We named files home_v1.php, gallery_final.php, gallery_final2.php. Merging required sitting together and comparing files by hand. Git would have eliminated that friction entirely. We didn't know it existed when we built this. Learning it changed how I work permanently. A useful starting point: Git and GitHub Introduction.
Frameworks solve problems that are not worth solving from scratch. Writing routing, session management, form validation, and security headers in raw PHP is educational once. After that, it is time spent rebuilding what Laravel, Django, or Express have already solved and hardened. Understanding the fundamentals is worth doing. Repeating the fundamentals indefinitely is not.
Compute servers and object storage are different concerns. A web server's job is to run application logic. An object store's job is to hold and serve files. Conflating the two on shared cPanel disk works until storage fills up. Moving files to Google Drive solves the storage problem by creating a worse performance problem. The real solution is separation of concerns from the start.
Where I Learned to Code
Before this project, I learned web development through WPU Unpas, a YouTube channel by Sandhika Galih that covers web programming from fundamentals to projects. It is where I first encountered PHP, MVC architecture, and the discipline of structured web development. I still recommend it to anyone starting out.