Backend Developer — Building with Go and Backend Architecture
R.
Completed

Maliva

Maliva is a tourism guide app for Malang Raya, designed to help tourists and locals alike make the most out of their trip. Through our application, you can explore the best local attractions, learn about the culture, and plan your trip accordingly.

JavaScriptFirebaseGoogle Cloud

Overview

What was built

Cloud backend for Maliva, a mobile tourism guide app for Malang Raya, Indonesia. The cloud track built and deployed the REST API that served both the Android client and a separate ML recommendation service.

Why it was built

Capstone project for Bangkit Academy 2024 (Google, GoTo, Tokopedia, Traveloka). The constraint was real: three tracks (mobile, ML, cloud) working in parallel toward a fixed demo deadline, each team deploying independently.

Tech stack
JavaScriptExpress.jsNode.jsFirebase StorageFirestoreCloud RunDockerGitHub ActionsGCP
Key features
Attraction discovery for Malang Raya local spots
ML-powered personalised recommendations
Custom-built authentication and authorization with JWT
Firestore content store integration
Automated CI/CD via GitHub Actions
Containerised deployment on Cloud Run

Architecture & Design

Microservice-style cloud architecture on GCP. The Android app communicates with a central Express.js API on Cloud Run. The API uses a custom-built authentication and authorization system with JWT for token verification, Firestore for content data, Firebase Storage for file storage, and makes HTTP calls to a separate ML service for personalised recommendations. CI/CD is fully automated via GitHub Actions.

Client
Android App

User-facing mobile client for Malang Raya tourism

Express.js API (REST)
API Layer
Express.js API

Core REST backend: attractions, users, trip data

Custom Auth (token verify)Firestore (read / write)ML Service (HTTP recommendation)
Service Layer
ML Service

Recommendation model wrapped as a Cloud Run endpoint

Custom Auth

Custom-built authentication and authorization with JWT

Data Layer
Firebase Storage

File and media storage

Firestore

NoSQL content store: attractions, user data

Infrastructure
Cloud Run

Serverless container runtime for API and ML service

GitHub Actions

CI/CD pipeline: build Docker image, push to registry, deploy

Cloud Run (Docker deploy)
Client
API Layer
Service Layer
Data Layer
Infrastructure

Challenges & Solutions

Problem

Three teams (Android, ML, Cloud) needed to integrate at a fixed deadline with no full-time coordination. The cloud track had to build a backend that both the mobile app and the ML model could consume, while keeping deployments independent enough that one track's changes couldn't break another's.

Constraints

  • Cross-functional team: mobile, ML, and cloud tracks developed in parallel
  • Non-negotiable Bangkit programme deadline
  • Must deploy on Google Cloud Platform, budget constrained to free/low-cost tiers
  • No dedicated DevOps; each track owned its own deployment pipeline

Approach

Defined an OpenAPI-style contract document at project start and shared it across all tracks. The cloud API was built with Express.js and deployed to Cloud Run via Docker. The ML model was wrapped as an independent Cloud Run endpoint called over HTTP, keeping it loosely coupled by design. GitHub Actions automated the full build-push-deploy pipeline on every push to main, removing manual deployment entirely.

Technical challenges
01
Challenge

Three tracks developing in parallel needed an API contract before any code was written, otherwise each track would build to different assumptions.

Solution

Defined and shared an OpenAPI-style contract document at project kickoff. Each track implemented to the contract; integration sessions caught drift early.

Outcome

Minimal integration blocking. Issues surfaced at weekly syncs rather than the day before the deadline.

02
Challenge

Manual deployments were error-prone and took hours, which was unsustainable with frequent cross-track integration updates.

Solution

Built a GitHub Actions pipeline: push to main → build Docker image → push to Artifact Registry → deploy to Cloud Run. Zero manual steps.

Outcome

Deployment time dropped from hours of manual work to under 15 minutes, fully repeatable.

03
Challenge

Integrating the ML recommendation model built by a separate team without creating a hard dependency between services.

Solution

The ML team deployed their model as an independent Cloud Run endpoint. The API called it via HTTP with a JSON payload, treating the ML service as an external dependency rather than a shared library.

Outcome

Either service could be updated or redeployed independently. Failure in the ML service degraded recommendations gracefully rather than breaking the main API.

Engineering decisions
01

Cloud Run over App Engine or GKE

Rationale

Cloud Run scales to zero (no idle cost), accepts any Docker image, and deploys in seconds. The right balance between simplicity and capability under a student budget.

Tradeoffs

Cold starts on low-traffic endpoints. Mitigated with a minimum instance count, but that re-introduces idle cost.

02

ML model as a separate HTTP service, not embedded in the API

Rationale

Keeping the ML model as an independent service meant the cloud and ML tracks could deploy independently. No shared codebase, no shared deployment, no coordination overhead.

Tradeoffs

Added network latency on each recommendation call. An embedded model would be faster but would couple the two teams' release cycles.

Results & Learnings

Outcomes
01

Full system delivered within the Bangkit Academy programme deadline

02

Deployment time reduced from hours of manual steps to under 15 minutes via automated CI/CD

03

Mobile, ML, and cloud tracks integrated successfully at the final demo

Learnings

Key Lessons

  • An API contract defined at kickoff is the single highest-leverage action in a parallel cross-functional team
  • CI/CD automation pays back its setup cost within the first week by reducing deployment anxiety near deadlines
  • Treating the ML model as an independent HTTP service made integration clean and failure-isolated

Future Improvements

  • Add a CDN caching layer for frequently accessed attraction data
  • Improve ML model accuracy with a larger, more representative local tourism dataset
  • Add offline support to the Android app for areas with poor connectivity

What I'd Do Differently

  • Set up CI/CD on day one, not week three; the time savings compound immediately
  • Add automated integration tests covering the mobile → API → ML service flow end-to-end