← The work

Case study · NusaSportJourney · 2026

A sport-tourism calendar the organizer edits without me

NusaSportJourney publishes Indonesian sport-tourism events: dates, routes, categories and media that change every week. I built the design system, the frontend and the CMS behind it, so the team adds an event without opening a ticket.

15frontend route visits
8bundled event fixtures
0CMS records loaded
40swalkthrough, recorded locally
NusaSportJourney frontend paused on the Borobudur Marathon event detail screen
Frontend only, recorded locally; content-gated routes show the waitlist

The problem

A sports-event organizer sells journeys, not products. Every event carries dates, routes, categories, slots and media that move weekly, and the person updating them is not a developer. An agency build freezes at launch. A hand-rolled admin rots. The site has to stay correct while someone else edits it.

What I built

Owned end to end: design, frontend and the content model.

  • The design system and page templates, derived from the event catalogue rather than a moodboard: one event template that survives an event with one photo and an event with forty
  • The public frontend in Next.js App Router: home, events, event detail, destinations, news, organization, contact and a three-step event-submission form
  • A self-hosted Strapi instance in the same repository, with eleven content types: event, destination, news item, partner, homepage, site settings, navigation, SEO defaults, media assets, analytics and public settings
  • Seed-export and asset-sync scripts, so content moves between the local fallback and the CMS in one command
  • Scroll choreography with GSAP ScrollTrigger and Lenis, an audio-on-tap splash, and a monthly planner that filters the calendar by month
  • Forms with server actions and validation: event submission, contact, plus the FAQ that answers before the form does
Borobudur Marathon 2026 detail page: category badge, registration panel, event details card and location
One event template: registration state, category, date, location, share
Event submission form, step 1 of 3, with the event name field
Submission runs in three steps, not one long form
Contact page: email, phone and office cards, a message form and an FAQ accordion
Contact carries the answers, so the inbox gets fewer questions

Three decisions

  1. Content model before screens

    The schema is the architecture; every template is a render of it. Getting the event model wrong is the only mistake here that cannot be fixed cheaply later.

  2. Editable by the organizer, not by me

    If publishing an event needs a developer, the build failed. Field labels, ordering and media rules were written for the person filling them in, not for me.

  3. Local-first asset mode

    The site renders bundled content when the CMS is unreachable, and only moves to CMS-first once production is ready. That is also why this walkthrough exists: the reviewer sees the product, not an error page.

Evidence

Stack read from the repository on 2026-11-03: Next.js 16.0.10, React 19.2.0, Tailwind 4.1.9, GSAP ScrollTrigger with Lenis, Strapi 5.39 self-hosted, Sentry and PostHog wired in, Vitest for unit tests and Playwright for end-to-end QA. Sixteen pages, eleven content types, and the build queried the CMS for its content: two events, two destinations and two articles.

The walkthrough above records the frontend running locally with no CMS data loaded: splash and home, the events list and a bundled event detail, organization, media kit, contact, event submission, and the legal pages. Destinations and news show the designed waitlist state because their local content fixtures are empty. 1280 by 800, 40 seconds, no audio.

What is not proven here: the launch date, traffic and registration numbers, because those belong to the organizer. The CMS editing session is not recorded either, so "the organizer publishes alone" is a design claim on this page. And nusasportjourney.com answers HTTP 502 from Cloudflare today: the origin needs restoring before this project has a clickable link.

What I would do next

Restore the origin and put that link on the card. Then record thirty seconds of the actual CMS edit, publish a draft event and watch it appear, because that is the claim that separates this build from a static site.

← Back to the work · ramasanjaya3302@gmail.com