Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions .github/workflows/release-finalize.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,18 +179,25 @@ jobs:

git fetch origin develop main
git checkout -B "$BACK_BRANCH" origin/develop
# Merge main into develop. Prefer develop's package.json if conflicting
# (develop already holds the next minor from release-prepare).
git merge --no-edit origin/main || {
if git diff --name-only --diff-filter=U | grep -q '^package.json$'; then
git checkout --ours package.json
git add package.json
# Merge main into develop, preferring main's content for any
# conflict (-X theirs) — main holds the shipped release. Then
# restore develop's package.json version (develop already carries
# the next minor from release-prepare).
git merge --no-edit -X theirs origin/main || {
UNMERGED=$(git diff --name-only --diff-filter=U)
if [ -z "$UNMERGED" ] || [ "$UNMERGED" = "package.json" ]; then
[ -n "$UNMERGED" ] && git checkout --ours package.json && git add package.json
git commit --no-edit
else
echo "::error::Unresolvable merge conflict on back-merge"
echo "::error::Unresolvable merge conflict on back-merge: $UNMERGED"
exit 1
fi
}
git checkout origin/develop -- package.json 2>/dev/null || true
if ! git diff --quiet package.json; then
git add package.json
git commit -m "chore: keep develop package.json version on back-merge"
fi
git push -u origin "$BACK_BRANCH"

gh pr create \
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "astro-scaffold",
"type": "module",
"version": "1.0.1",
"version": "1.1.0",
"engines": {
"node": ">=22.12.0"
},
Expand Down
1 change: 1 addition & 0 deletions src/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const portfolio = defineCollection({
clientUrl: z.string().url().optional(),
year: z.number().int(),
status: z.enum(['live', 'maintained', 'archived']),
draft: z.boolean().default(false),
cover: image(),
thumbnail: image(),
gallery: z.array(image()).optional(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ bucket: consumer
client: Ulearna Technology LTD
year: 2024
status: maintained
draft: true
cover: ./cover.webp
thumbnail: ./thumbnail.svg
summary: >
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ bucket: consumer
client: Ulearna Technology LTD
year: 2024
status: maintained
draft: true
cover: ./cover.webp
thumbnail: ./thumbnail.svg
summary: >
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ bucket: consumer
client: Ulearna Technology LTD
year: 2024
status: maintained
draft: true
cover: ./cover.svg
thumbnail: ./thumbnail.svg
summary: >
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ bucket: consumer
client: Ulearna Technology LTD
year: 2024
status: maintained
draft: true
cover: ./cover.svg
thumbnail: ./thumbnail.svg
summary: >
Expand Down
4 changes: 2 additions & 2 deletions src/content/pages/home.en.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ trustClaims:
- label: "Founded in 2019"
- label: "15+ shipped case studies"
- label: "Engineering-led delivery"
- label: "Clients: Pemprov Sulteng · Pemkab Gowa · Ulearna (Dubai, UAE)"
- label: "Clients: Pemprov Sulteng · Pemkab Gowa"

about:
eyebrow: "ABOUT US"
Expand Down Expand Up @@ -99,7 +99,7 @@ founder:
marker: "[ 06 ]"
sectionTitle: "Led by engineering experience"
headline: "Led by engineering experience across product, platform, and operational systems"
narrative: "Ryan's experience spans consumer products for the international market (Dubai/UAE via Ulearna Technology LTD), public-sector and regional tax systems, and platform engineering at GoTo Financial, Reku, and Stockbit/Bibit. Banua Coder approaches every project with a combination of product thinking, engineering depth, and cross-context business operational understanding."
narrative: "Ryan's experience spans consumer products for the international market (Dubai/UAE), public-sector and regional tax systems, and platform engineering at GoTo Financial, Reku, and Stockbit/Bibit. Banua Coder approaches every project with a combination of product thinking, engineering depth, and cross-context business operational understanding."
readMoreLabel: "Full founder profile"

idealClients:
Expand Down
4 changes: 2 additions & 2 deletions src/content/pages/home.id.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ trustClaims:
- label: "Berdiri sejak 2019"
- label: "15+ studi kasus dipublikasikan"
- label: "Dibangun dengan disiplin engineering"
- label: "Klien: Pemprov Sulteng · Pemkab Gowa · Ulearna (Dubai)"
- label: "Klien: Pemprov Sulteng · Pemkab Gowa"

about:
eyebrow: "TENTANG KAMI"
Expand Down Expand Up @@ -99,7 +99,7 @@ founder:
marker: "[ 06 ]"
sectionTitle: "Dipimpin oleh tangan engineer"
headline: "Engineer yang pernah mengerjakan produk konsumen, platform skala besar, dan sistem operasional bisnis"
narrative: "Ryan pernah mengerjakan produk konsumen untuk pasar internasional (Dubai/UAE bersama Ulearna Technology LTD), sistem layanan publik dan pajak daerah, hingga produk skala jutaan pengguna di GoTo Financial, Reku, dan Stockbit/Bibit. Pengalaman ini membentuk cara Banua Coder mendekati setiap proyek—menggabungkan cara berpikir produk, kedalaman engineering, dan pemahaman operasional bisnis."
narrative: "Ryan pernah mengerjakan produk konsumen untuk pasar internasional (Dubai/UAE), sistem layanan publik dan pajak daerah, hingga produk skala jutaan pengguna di GoTo Financial, Reku, dan Stockbit/Bibit. Pengalaman ini membentuk cara Banua Coder mendekati setiap proyek—menggabungkan cara berpikir produk, kedalaman engineering, dan pemahaman operasional bisnis."
readMoreLabel: "Profil lengkap founder"

idealClients:
Expand Down
15 changes: 7 additions & 8 deletions src/data/clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export type Client = {
}

// LICENSE NOTES:
// - ulearna.png: source https://ulearna.com (og:image asset). Nominative fair use for client identification.
// - pemprov-sulteng.svg: https://commons.wikimedia.org/wiki/File:Coat_of_arms_of_Central_Sulawesi.svg — Public domain (PD-IDGov, Indonesian state emblem). Covers both PICO Sulteng and Surat BMPR engagements.
// - pemkab-gowa.png: Pemkab Gowa coat of arms — Public domain (PD-IDGov, Indonesian state emblem). Sourced from owner's branding archive (cleaner asset than the Wikimedia commons version).
// - pemkab-donggala.png: https://commons.wikimedia.org/wiki/File:Lambang_Kabupaten_Donggala.png — Public domain (PD-IDGov). Covers Siap Donggala (Mekari Talenta integration).
Expand All @@ -24,13 +23,13 @@ export type Client = {
// case study (src/content/portfolio/surat-bmpr/) where the partnership context matters.

export const clients: Client[] = [
{
name: 'Ulearna Technology LTD',
logo: 'ulearna.png',
url: 'https://ulearna.com',
tier: 'featured',
context: 'Dubai, UAE — international consumer products (Reab, Carwa)',
},
// {
// name: 'Ulearna Technology LTD',
// logo: 'ulearna.png',
// url: 'https://ulearna.com',
// tier: 'featured',
// context: 'Dubai, UAE — international consumer products (Reab, Carwa)',
// },
{
name: 'PT Brantas Inti Utama',
logo: 'brantas-inti-utama.png',
Expand Down
3 changes: 1 addition & 2 deletions src/data/founder-experience.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ export type FounderExperience = { company: string; logo: string; context: string
// - goto-financial.png: https://commons.wikimedia.org/wiki/File:GoTo_Financial.png — Public domain (PD-IDGov / corporate brand mark).
// - reku.png: https://reku.id/next/assets/images/logo/reku.png — nominative fair use for employer identification.
// - stockbit.svg: https://stockbit.com/images/stockbit.svg — nominative fair use for employer identification.
// - ulearna.png: https://ulearna.com (og:image asset) — nominative fair use for employer identification.

export const founderExperience: FounderExperience[] = [
{ company: 'GoTo Financial', logo: 'goto-financial.png', context: 'Mobile platform engineering' },
{ company: 'Reku', logo: 'reku.png', context: 'Mobile engineering' },
{ company: 'Stockbit/Bibit', logo: 'stockbit.svg', context: 'Mobile platform' },
{ company: 'Ulearna', logo: 'ulearna.png', context: 'International product collaboration (Dubai, UAE)' },
// { company: 'Ulearna', logo: 'ulearna.png', context: 'International product collaboration (Dubai, UAE)' },
]
8 changes: 1 addition & 7 deletions src/lib/estimator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ function buildTeam(input: EstimatorInput): string[] {
}

// ─── Portfolio matching ────────────────────────────────────────────────────
const consumerSlugs = ['reab', 'carwa', 'caretaker']
const consumerSlugs = ['caretaker']
const publicSlugs = ['pico-sulteng', 'patonro', 'lontara']

function matchPortfolio(input: EstimatorInput): string[] {
Expand All @@ -124,16 +124,10 @@ function matchPortfolio(input: EstimatorInput): string[] {
}

if (features.includes('payments')) {
scores['carwa'] = (scores['carwa'] ?? 0) + 1
scores['patonro'] = (scores['patonro'] ?? 0) + 1
}

if (features.includes('realtime')) {
scores['carwa'] = (scores['carwa'] ?? 0) + 1
}

if (features.includes('push')) {
scores['reab'] = (scores['reab'] ?? 0) + 1
scores['caretaker'] = (scores['caretaker'] ?? 0) + 1
}

Expand Down
8 changes: 4 additions & 4 deletions src/pages/dev/components.astro
Original file line number Diff line number Diff line change
Expand Up @@ -294,12 +294,12 @@ import DeviceFrame from '../../components/interactive/DeviceFrame.astro'

<div class="grid sm:grid-cols-2 lg:grid-cols-3 gap-6">
<CaseStudyCard
title="Reab — Social Media Platform"
client="Ulearna Technology LTD"
title="Consumer Social App"
client="International Startup"
year={2024}
bucket="consumer"
summary="Consumer social/media platform with 50,000+ downloads on Google Play. Built for international market, mobile-first experience."
impactStat="50K+ downloads on Google Play"
summary="Consumer social/media platform with strong app store adoption. Built for international market, mobile-first experience."
impactStat="Strong Google Play adoption"
href="#"
/>
<CaseStudyCard
Expand Down
2 changes: 1 addition & 1 deletion src/pages/en/estimate.astro
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Card from '../../components/atoms/Card.astro'
import EstimatorWizard from '../../components/sections/EstimatorWizard.astro'

// Load all EN-locale portfolio entries (fallback to ID if EN missing)
const allPortfolio = await getCollection('portfolio')
const allPortfolio = await getCollection('portfolio', ({ data }) => !data.draft)
const enPortfolio = allPortfolio.filter((p) => p.data.locale === 'en')
const idPortfolio = allPortfolio.filter((p) => p.data.locale === 'id')

Expand Down
12 changes: 6 additions & 6 deletions src/pages/en/founder.astro
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import sikerjaShot1 from '../../content/portfolio/sikerja/screenshots/screenshot
import sikerjaShot2 from '../../content/portfolio/sikerja/screenshots/screenshot-3.webp'
import detexiShot1 from '../../content/portfolio/detexi/screenshots/screenshot-2.webp'
import detexiShot2 from '../../content/portfolio/detexi/screenshots/screenshot-4.webp'
import carwaShot1 from '../../content/portfolio/carwa/screenshots/screenshot-2.webp'
import carwaShot2 from '../../content/portfolio/carwa/screenshots/screenshot-3.webp'
// import carwaShot1 from '../../content/portfolio/carwa/screenshots/screenshot-2.webp'
// import carwaShot2 from '../../content/portfolio/carwa/screenshots/screenshot-3.webp'
import picoShot1 from '../../content/portfolio/pico-sulteng/screenshots/screenshot-1.webp'
import picoShot2 from '../../content/portfolio/pico-sulteng/screenshots/screenshot-4.webp'
import ambientImg from '../../assets/stock/clean-workspace-notebook.jpg'
Expand All @@ -35,7 +35,7 @@ const selectedExperience = [
{ company: 'GoTo Financial', context: 'Mobile platform engineering — large-scale fintech ecosystem' },
{ company: 'Reku', context: 'Mobile engineering — crypto and digital investment application' },
{ company: 'Stockbit / Bibit', context: 'Mobile platform — investment community and mutual fund application' },
{ company: 'Ulearna Technology LTD', context: 'International product collaboration — consumer-facing application for global market' },
// { company: 'Ulearna Technology LTD', context: 'International product collaboration — consumer-facing application for global market' },
{ company: 'Public Sector', context: 'Public digital systems — regional service and payment applications' },
]

Expand Down Expand Up @@ -207,7 +207,7 @@ const founderBreadcrumbSchema = {
Ryan grew up in Central Sulawesi and built his career as a software engineer specializing in mobile engineering, platform systems, and digital product development. From early on, he was drawn to how large systems work from the inside — not just building requested features, but understanding architecture, tradeoffs, and the long-term implications of every technical decision.
</p>
<p>
His career took him into product engineering environments rarely reached by engineers from regional Indonesia: GoTo Financial as Southeast Asia's largest fintech ecosystem, Reku and Stockbit/Bibit as consumer investment platforms serving millions of users, and international collaboration with Ulearna Technology LTD on products targeting a global market. He also worked on public-sector digital systems — regional tax and retribution service applications that demand a different kind of rigor around data trust and workflow clarity than typical consumer apps.
His career took him into product engineering environments rarely reached by engineers from regional Indonesia: GoTo Financial as Southeast Asia's largest fintech ecosystem, Reku and Stockbit/Bibit as consumer investment platforms serving millions of users, and international product collaboration targeting a global market. He also worked on public-sector digital systems — regional tax and retribution service applications that demand a different kind of rigor around data trust and workflow clarity than typical consumer apps.
</p>
<p>
Banua Coder was founded in 2019 from a desire to bring those engineering and product-thinking standards to a local context — businesses and organizations in regional Indonesia that need a technology partner they can genuinely rely on, not just a vendor that codes. Ryan founded Banua Coder on one conviction: the quality of digital solutions should not depend on where a business is located.
Expand Down Expand Up @@ -356,8 +356,8 @@ const founderBreadcrumbSchema = {
{ src: detexiShot1, alt: "Detexi Doctor — search doctors by specialization", label: 'Detexi · 2023' },
{ src: detexiShot2, alt: "Detexi Doctor — patient–doctor consultation flow", label: 'Detexi · 2023' },
// Group: Carwa
{ src: carwaShot1, alt: "Carwa — live digital car auction interface", label: 'Carwa · Dubai · 2024' },
{ src: carwaShot2, alt: "Carwa — auction listing with vehicle specifications", label: 'Carwa · Dubai · 2024' },
// { src: carwaShot1, alt: "Carwa — live digital car auction interface", label: 'Carwa · Dubai · 2024' },
// { src: carwaShot2, alt: "Carwa — auction listing with vehicle specifications", label: 'Carwa · Dubai · 2024' },
// Group: PICO Sulteng
{ src: picoShot1, alt: "PICO Sulteng — provincial COVID-19 statistics dashboard", label: 'PICO Sulteng · 2021' },
{ src: picoShot2, alt: "PICO Sulteng — regional case-distribution map", label: 'PICO Sulteng · 2021' },
Expand Down
28 changes: 2 additions & 26 deletions src/pages/en/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ import heroSiapFront from '../../content/portfolio/siap-donggala/screenshots/scr
import heroSiapBack from '../../content/portfolio/siap-donggala/screenshots/screenshot-3.webp'
import heroDetexiFront from '../../content/portfolio/detexi/screenshots/screenshot-4.webp'
import heroDetexiBack from '../../content/portfolio/detexi/screenshots/screenshot-5.webp'
import heroCarwaFront from '../../content/portfolio/carwa/screenshots/screenshot-clean-1.webp'
import heroCarwaBack from '../../content/portfolio/carwa/screenshots/screenshot-clean-2.webp'
import { Coffee, Sparkles, Landmark, TrendingUp, Lightbulb, ArrowRight } from 'lucide-astro'

const idealClientIcons: Record<string, typeof Coffee> = {
Expand All @@ -38,10 +36,9 @@ const idealClientIcons: Record<string, typeof Coffee> = {
'trending-up': TrendingUp,
'lightbulb': Lightbulb,
}
import heroCarwa from '../../content/portfolio/carwa/screenshots/screenshot-1.webp'

// Load featured portfolio entries for EN locale
const allPortfolioEntries = await getCollection('portfolio')
const allPortfolioEntries = await getCollection('portfolio', ({ data }) => !data.draft)
const featuredProjects = allPortfolioEntries
.filter((p) => p.data.locale === 'en' && p.data.featured)
.sort((a, b) => a.data.order - b.data.order)
Expand Down Expand Up @@ -219,24 +216,13 @@ const orgSchema = {
class="hero-shot-img"
data-hero-slide
/>
<Image
src={heroCarwaBack}
alt=""
widths={[200, 400]}
sizes="200px"
aria-hidden="true"
loading="lazy"
decoding="async"
class="hero-shot-img"
data-hero-slide
/>
</div>

<div
class="hero-shot hero-shot-main"
data-hero-cycle-group="hero-products"
data-hero-cycle-interval="4200"
data-hero-cycle-labels="PICO Sulteng,Sikerja,SIAP Donggala,Detexi,Carwa"
data-hero-cycle-labels="PICO Sulteng,Sikerja,SIAP Donggala,Detexi"
>
<Image
src={heroPicoFront}
Expand Down Expand Up @@ -279,16 +265,6 @@ const orgSchema = {
class="hero-shot-img"
data-hero-slide
/>
<Image
src={heroCarwaFront}
alt="Carwa preview — Dubai digital car auction"
widths={[280, 560]}
sizes="280px"
loading="lazy"
decoding="async"
class="hero-shot-img"
data-hero-slide
/>
</div>

<div class="hero-chip" aria-hidden="true" data-hero-chip>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/en/portfolio/[slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Prose from '../../../components/typography/Prose.astro'
import { renderInlineMd } from '../../../lib/inline-md'

export async function getStaticPaths() {
const allPortfolio = await getCollection('portfolio')
const allPortfolio = await getCollection('portfolio', ({ data }) => !data.draft)
const enEntries = allPortfolio.filter((p) => p.data.locale === 'en')
return enEntries.map((entry) => ({
params: { slug: entry.data.slug },
Expand All @@ -27,7 +27,7 @@ const { data } = entry
const { Content } = await render(entry)

// "Next case study" — same bucket, sorted by order, cycling
const allPortfolio = await getCollection('portfolio')
const allPortfolio = await getCollection('portfolio', ({ data }) => !data.draft)
const sameBucket = allPortfolio
.filter((p) => p.data.locale === 'en' && p.data.bucket === data.bucket && p.data.slug !== data.slug)
.sort((a, b) => a.data.order - b.data.order)
Expand Down
2 changes: 1 addition & 1 deletion src/pages/en/portfolio/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import CaseStudyCard from '../../../components/cards/CaseStudyCard.astro'
import BucketFilter from '../../../components/interactive/BucketFilter.astro'

// Load all EN portfolio entries, sorted by order
const allPortfolio = await getCollection('portfolio')
const allPortfolio = await getCollection('portfolio', ({ data }) => !data.draft)
const projects = allPortfolio
.filter((p) => p.data.locale === 'en')
.sort((a, b) => a.data.order - b.data.order)
Expand Down
2 changes: 1 addition & 1 deletion src/pages/estimate.astro
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Card from '../components/atoms/Card.astro'
import EstimatorWizard from '../components/sections/EstimatorWizard.astro'

// Load all ID-locale portfolio entries to pass as build-time JSON to the wizard
const allPortfolio = await getCollection('portfolio')
const allPortfolio = await getCollection('portfolio', ({ data }) => !data.draft)
const idPortfolio = allPortfolio.filter((p) => p.data.locale === 'id')

// Build a slug → summary map for the wizard's portfolio card rendering
Expand Down
Loading