A company profile site, billboard rental catalogue, and CMS for Media Adhi Persada in Sukabumi. Prospective clients can check which billboard sites are still free, then get in touch over WhatsApp.
Media Adhi Persada (MAP) is an advertising, event organiser, and IT solutions company in Sukabumi. Their old site held nothing but a profile and a list of past work. The billboard sites they rent out were written as plain text, their status was changed by hand, and prospective renters had no way of seeing which sites were still free. When someone got in touch over WhatsApp, MAP also had no idea which page that person had come from.
I rebuilt the site with Laravel 13 as a single application serving two domains. The main domain carries the public site, while the cms subdomain carries a Filament admin panel. Public routes are wrapped in Route::domain() and the Filament panel is registered only on the CMS domain, so /admin on the public site genuinely does not exist.
Everything the site shows can be changed from the CMS: billboards, services, past work, gallery, slider, banners, clients, FAQs, right down to the contact numbers and the WhatsApp message templates. Each time content is saved, the cached HTML of the public pages is cleared with it, so changes show up immediately.
/wa route that records where the click came from (a billboard, a service, a piece of past work, or the site in general) and ignores bots.The raw material was 478 photos taken on the field team's phones, many of them still carrying a camera-app overlay with a phone number and coordinates on it. I wrote a Node script with sharp to compress the photos and build contact sheets, then sorted them one by one into past work, the gallery, or the bin. Ninety-three photos made it through, eighteen of which had to be cropped or pixelated first. Photos that admins upload through the CMS later are cleaned too: EXIF and XMP data, GPS location included, is stripped the moment a file arrives, before the WebP conversion is made.
Caching gave me some trouble. Laravel 13 refuses to unserialise objects from the cache by default, and the database cache driver has no tags. In the end I store the rendered HTML as a plain string, under a key that carries a version number. When content changes, the version is bumped and the old keys expire on their own.
The billboard status rules also had to match exactly in two places: the accessor used for display, and the scope used for filter queries. I tested both against the same cases: no rental at all, a rental in the future, a rental already past, and special statuses such as maintenance.
The map picker in the CMS is a custom Filament field built with Alpine and Leaflet. Coordinates can be read out of a full Google Maps link, but not out of a short maps.app.goo.gl link, because that needs a redirect resolved on the server. For those, the admin is asked to paste the full link instead.
Some things are not finished. A few billboards have no size or coordinates recorded yet, so the site shows "-" for them until the client fills those in through the CMS. One billboard photo carries a GPS stamp that turns out to point somewhere else entirely, so I deliberately left its coordinates empty rather than put a wrong pin on the map.
I did this project alone: gathering the requirements and writing the spec, processing the photos, designing the interface, writing the backend and the CMS, writing the tests, and deploying. The application is packaged with a Dockerfile (a serversideup/php image running PHP 8.5) and runs on Coolify on a VPS with a MySQL 8 database.
The site is running on the server with all of its initial content: 14 pieces of past work, 47 gallery photos, 3 services, and 4 active billboard sites. There are 165 Pest tests covering the public pages, the billboard filters, WhatsApp click tracking, the contact form, the CMS, and SEO. There is no usage data such as message or click counts yet, because the site has not been moved to its own domain.
Next I will move the DNS for mediaadhipersada.id to the new server, submit the sitemap to Google Search Console, and help MAP complete their billboard data. Once WhatsApp click data has built up, I want to add a per-billboard click report so MAP can see which sites get asked about most.