Membangun Plugin Kustom di Backstage.io: Mengoptimalkan Internal Developer Portal Anda
Internal Developer Portal (IDP) telah menjadi alat esensial bagi tim engineering modern. Bayangkan IDP sebagai “pusat kendali” atau “dashboard utama” bagi developer Anda. Di sana, mereka bisa menemukan dokumentasi, melihat status layanan, membuat proyek baru, atau bahkan meluncurkan deployment, semuanya dari satu tempat. Backstage.io, sebuah proyek open-source dari Spotify, adalah salah satu framework paling populer untuk membangun IDP.
Backstage menawarkan banyak fungsionalitas out-of-the-box yang luar biasa. Namun, setiap organisasi memiliki kebutuhan, tool, dan workflow yang unik. Di sinilah kekuatan sejati Backstage muncul: kemampuan untuk diperluas dengan plugin kustom.
Artikel ini akan membawa Anda menyelami dunia pengembangan plugin kustom di Backstage.io. Kita akan belajar mengapa plugin kustom itu penting, bagaimana arsitekturnya bekerja, dan yang terpenting, bagaimana Anda bisa mulai membangun plugin Anda sendiri untuk membuat IDP yang benar-benar disesuaikan dengan kebutuhan tim Anda.
1. Pendahuluan: Mengapa Plugin Kustom adalah Kunci IDP yang Efektif?
Anda mungkin bertanya, “Mengapa saya harus repot-repot membuat plugin kustom jika Backstage sudah punya banyak fitur?” Pertanyaan bagus! Backstage memang kaya fitur, tapi ada beberapa skenario di mana plugin kustom menjadi sangat vital:
- Integrasi Sistem Internal yang Unik: Tim Anda mungkin menggunakan tool internal yang spesifik (misalnya, sistem manajemen proyek kustom, dashboard metrik internal, atau deployment tool buatan sendiri). Plugin kustom memungkinkan Anda mengintegrasikan tool ini langsung ke Backstage, menciptakan pengalaman yang mulus.
- Workflow Spesifik Organisasi: Setiap tim memiliki cara kerja yang berbeda. Mungkin ada alur persetujuan proyek tertentu, proses onboarding unik, atau cara khusus untuk melihat data performa. Plugin kustom bisa mengotomatisasi dan menyederhanakan workflow ini dalam IDP.
- Peningkatan Developer Experience (DX): Dengan menyatukan semua informasi dan tool yang relevan dalam satu tempat, Anda mengurangi context switching dan frustrasi developer. Plugin kustom adalah cara terbaik untuk menghilangkan gesekan dalam pekerjaan sehari-hari developer.
- Menyediakan Data yang Relevan: Terkadang, Anda perlu menampilkan data yang sangat spesifik atau agregat dari berbagai sumber yang tidak bisa diakses langsung oleh plugin bawaan. Plugin kustom bisa menjadi jembatan untuk data tersebut.
Singkatnya, plugin kustom mengubah Backstage dari sekadar dashboard menjadi platform yang benar-benar berdaya guna, yang tumbuh dan beradaptasi bersama kebutuhan tim Anda.
2. Memahami Arsitektur Plugin Backstage: Fondasi Kustomisasi Anda
Sebelum kita mulai menulis kode, penting untuk memahami bagaimana plugin bekerja di Backstage. Bayangkan Backstage sebagai sebuah kota besar. Setiap plugin adalah bangunan unik di kota itu, dan ada jalan-jalan serta infrastruktur yang menghubungkan mereka.
Backstage memisahkan fungsionalitas menjadi dua jenis utama:
- Frontend Plugins: Ini adalah bagian yang berinteraksi langsung dengan pengguna di browser. Mereka bertanggung jawab untuk UI, menampilkan data, dan menangani interaksi pengguna. Sebagian besar plugin yang Anda lihat di Backstage (seperti daftar layanan, dokumentasi, atau dashboard CI/CD) adalah frontend plugins. Mereka dibangun menggunakan React dan TypeScript.
- Backend Plugins: Ini adalah bagian yang berjalan di sisi server. Mereka bertanggung jawab untuk logika bisnis yang lebih kompleks, berinteraksi dengan database atau API eksternal, dan menangani autentikasi/otorisasi yang sensitif. Anda akan membutuhkan backend plugin jika frontend plugin Anda perlu mengakses sumber daya yang tidak bisa diakses langsung dari browser atau memerlukan komputasi berat. Mereka dibangun menggunakan Node.js dan TypeScript.
📌 Konsep Penting dalam Plugin Backstage:
- Extensions: Ini adalah unit terkecil dari fungsionalitas yang disediakan oleh sebuah plugin. Contohnya, sebuah plugin bisa menyediakan extension berupa halaman baru, tab di halaman detail layanan, atau bahkan sebuah tombol di UI.
- APIs: Backstage menyediakan banyak API bawaan (Utility APIs) yang bisa digunakan oleh plugin Anda untuk berinteraksi dengan fungsionalitas inti Backstage (misalnya, API untuk mengambil data dari catalog, API untuk notifikasi, atau API untuk autentikasi). Anda juga bisa mendefinisikan API kustom Anda sendiri.
Secara umum, sebuah frontend plugin akan menggunakan API yang disediakan oleh backend plugin atau API eksternal untuk mengambil data, lalu menampilkan data tersebut melalui extension di UI.
3. Langkah Awal: Membuat Plugin Frontend Sederhana
Mari kita mulai dengan membuat frontend plugin yang menampilkan daftar link penting untuk tim Anda. Ini adalah contoh sederhana namun praktis untuk memahami dasar-dasar pengembangan plugin.
✅ Prasyarat: Anda sudah memiliki instance Backstage yang berjalan. Jika belum, Anda bisa memulainya dengan:
npx @backstage/create-app
Ikuti petunjuknya, lalu jalankan yarn install dan yarn dev untuk melihat aplikasi Backstage Anda.
🎯 Membuat Plugin Baru:
Dari root direktori proyek Backstage Anda, jalankan perintah berikut:
yarn new --select plugin
Anda akan diminta untuk memberikan ID plugin (misalnya my-team-links) dan nama plugin (misalnya My Team Links). Pilih “Frontend” saat ditanya jenis plugin.
Perintah ini akan membuat direktori baru di packages/plugins/my-team-links dengan struktur dasar plugin.
💡 Struktur Kunci Plugin Frontend:
src/index.ts: Ini adalah entry point plugin Anda. Di sini Anda akan mendefinisikan plugin itu sendiri dan extension yang disediakannya.src/plugin.ts: Mendefinisikan instance plugin Backstage.src/routes.ts: Mendefinisikan rute untuk halaman-halaman dalam plugin Anda.src/components/: Folder untuk komponen React yang membentuk UI plugin Anda.
Mari kita modifikasi packages/plugins/my-team-links/src/components/ExampleComponent/ExampleComponent.tsx (atau buat file baru seperti MyTeamLinksPage.tsx) untuk menampilkan daftar link:
// packages/plugins/my-team-links/src/components/MyTeamLinksPage/MyTeamLinksPage.tsx
import React from 'react';
import {
Typography,
Grid,
Card,
CardContent,
Link as MuiLink,
} from '@material-ui/core';
import {
InfoCard,
Header,
Page,
Content,
ContentHeader,
HeaderLabel,
SupportButton,
} from '@backstage/core-components';
import { Link } from 'react-router-dom';
const teamLinks = [
{ title: 'Dokumentasi Teknis', url: 'https://docs.example.com', description: 'Panduan teknis dan arsitektur.' },
{ title: 'Dashboard Metrik', url: 'https://metrics.example.com', description: 'Pantau performa aplikasi.' },
{ title: 'Jira Board Tim', url: 'https://jira.example.com', description: 'Lacak pekerjaan dan sprint.' },
{ title: 'Slack Channel Tim', url: 'https://slack.example.com/team-channel', description: 'Komunikasi tim inti.' },
];
export const MyTeamLinksPage = () => (
<Page themeId="home">
<Header title="Link Penting Tim Saya" subtitle="Akses cepat ke sumber daya utama.">
<HeaderLabel label="Owner" value="Platform Team" />
<HeaderLabel label="Lifecycle" value="Production" />
</Header>
<Content>
<ContentHeader title="Sumber Daya Cepat">
<SupportButton>Butuh bantuan?</SupportButton>
</ContentHeader>
<Grid container spacing={3} direction="column">
<Grid item>
<InfoCard title="Link Umum">
<Typography variant="body1">
Berikut adalah beberapa link penting yang sering digunakan oleh tim kami.
</Typography>
</InfoCard>
</Grid>
<Grid item>
<Grid container spacing={2}>
{teamLinks.map((link, index) => (
<Grid item xs={12} sm={6} md={4} key={index}>
<Card variant="outlined">
<CardContent>
<Typography variant="h6" component="h2">
<MuiLink href={link.url} target="_blank" rel="noopener noreferrer">
{link.title}
</MuiLink>
</Typography>
<Typography variant="body2" color="textSecondary">
{link.description}
</Typography>
</CardContent>
</Card>
</Grid>
))}
</Grid>
</Grid>
</Grid>
</Content>
</Page>
);
Kemudian, Anda perlu mendaftarkan halaman ini di entry point plugin Anda. Edit packages/plugins/my-team-links/src/routes.ts dan packages/plugins/my-team-links/src/plugin.ts agar mengarah ke komponen MyTeamLinksPage:
// packages/plugins/my-team-links/src/routes.ts
import { createRouteRef } from '@backstage/core-plugin-api';
export const rootRouteRef = createRouteRef({
id: 'my-team-links',
});
// packages/plugins/my-team-links/src/plugin.ts
import { createPlugin, createRoutableExtension } from '@backstage/core-plugin-api';
import { rootRouteRef } from './routes';
export const myTeamLinksPlugin = createPlugin({
id: 'my-team-links',
routes: {
root: rootRouteRef,
},
});
export const MyTeamLinksPage = myTeamLinksPlugin.provide(
createRoutableExtension({
name: 'MyTeamLinksPage',
component: () =>
import('./components/MyTeamLinksPage').then(m => m.MyTeamLinksPage),
mountPoint: rootRouteRef,
}),
);
Terakhir, Anda perlu menambahkan plugin ini ke aplikasi Backstage Anda. Edit packages/app/src/App.tsx dan tambahkan MyTeamLinksPage ke daftar halaman:
// packages/app/src/App.tsx
import React from 'react';
import { Route, Routes } from 'react-router-dom';
import { MyTeamLinksPage } from '@backstage/plugin-my-team-links'; // Import plugin Anda
// ... import lainnya
const App = () => (
<AppProvider>
<AlertDisplay />
<OAuthRequestDialog />
<AppRouter>
<Root>
<Routes>
{/* ... rute lainnya */}
<Route path="/my-team-links" element={<MyTeamLinksPage />} /> {/* Tambahkan rute ini */}
</Routes>
</Root>
</AppRouter>
</AppProvider>
);
Jalankan yarn dev lagi. Anda sekarang akan melihat halaman baru di /my-team-links di IDP Anda! Anda bisa menambahkan link ke navigasi samping dengan mengedit packages/app/src/components/Root/Root.tsx.
4. Menambahkan Backend Plugin (Opsional tapi Kuat)
Katakanlah Anda ingin plugin “My Team Links” Anda tidak hanya menampilkan link statis, tetapi juga mengambil link dari database internal atau API yang membutuhkan autentikasi khusus server. Di sinilah backend plugin berperan.
⚠️ Kapan Anda butuh Backend Plugin?
- Mengakses database atau sistem internal yang tidak boleh terekspos langsung ke frontend.
- Melakukan operasi yang membutuhkan hak akses khusus yang hanya tersedia di server.
- Agregasi data dari berbagai sumber backend sebelum dikirim ke frontend.
- Menyimpan konfigurasi atau state yang persisten di sisi server.
🎯 Membuat Backend Plugin Baru:
Sama seperti frontend plugin, Anda bisa menggunakan perintah yarn new:
yarn new --select plugin
Kali ini, berikan ID plugin (misalnya my-team-links-backend) dan pilih “Backend” saat ditanya jenis plugin.
Ini akan membuat direktori di packages/backend/plugins/my-team-links-backend (atau mirip).
💡 Struktur Kunci Plugin Backend:
src/service/router.ts: Ini adalah tempat Anda mendefinisikan endpoint API REST untuk backend plugin Anda.src/index.ts: Entry point untuk mendaftarkan plugin ke backend Backstage.
Mari kita buat backend plugin sederhana yang mengembalikan daftar link:
// packages/backend/plugins/my-team-links-backend/src/service/router.ts
import { createRouter } from '@backstage/plugin-my-team-links-backend';
import { Router } from 'express';
import { LoggerService } from '@backstage/backend-plugin-api';
interface RouterOptions {
logger: LoggerService;
}
export async function createMyTeamLinksRouter(
options: RouterOptions,
): Promise<Router> {
const { logger } = options;
const router = Router();
router.use(express.json());
router.get('/links', (_, response) => {
logger.info('Fetching team links from backend');
const backendTeamLinks = [
{ id: '1', title: 'Internal Wiki', url: 'https://wiki.internal.com' },
{ id: '2', title: 'Production Status', url: 'https://status.prod.com' },
];
response.json(backendTeamLinks);
});
// Example of a POST endpoint
router.post('/links', (request, response) => {
const newLink = request.body;
logger.info(`Adding new link: ${JSON.stringify(newLink)}`);
// In a real app, you'd save this to a database
response.status(201).json({ message: 'Link added successfully', link: newLink });
});
return router;
}
Kemudian, daftarkan backend plugin ini di packages/backend/src/index.ts atau di file backend utama Anda:
// packages/backend/src/index.ts
// ... imports lainnya
import { createMyTeamLinksRouter } from '@backstage/plugin-my-team-links-backend'; // Import router Anda
async function main() {
const services = await createBackendSystem();
const { logger } = services.root.get// ... dan layanan lainnya
// Tambahkan backend router Anda di sini
services.backend.add(
createMyTeamLinksRouter({
logger,
// ... tambahkan dependensi lain jika ada
}),
);
await services.start();
}
main().catch(error => {
console.error('Backend startup failed:', error);
process.exit(1);
});
Setelah itu, Anda bisa memanggil endpoint /api/my-team-links-backend/links dari frontend plugin Anda menggunakan fetch atau createApiFactory dari Backstage.
5. Tips dan Best Practices dalam Pengembangan Plugin
Mengembangkan plugin kustom bisa menjadi sangat kuat, tetapi ada beberapa hal yang perlu diingat agar prosesnya mulus dan hasilnya berkualitas:
- Ikuti Design System Backstage: Backstage menggunakan Material UI. Manfaatkan komponen-komponen yang sudah ada dari
@backstage/core-componentsdan@material-ui/coreuntuk menjaga konsistensi UI/UX. Ini akan membuat plugin Anda terasa seperti bagian integral dari Backstage, bukan tempelan. - Gunakan Utility APIs Backstage: Hindari reinventing the wheel. Backstage memiliki banyak Utility APIs untuk hal-hal seperti notifikasi, dialog, autentikasi, dan akses ke catalog. Pelajari dan manfaatkan ini.
- Pengujian adalah Kunci: Sama seperti pengembangan aplikasi lainnya, tulis unit test untuk logika plugin Anda dan integration test untuk memastikan plugin berinteraksi dengan Backstage dan API lain seperti yang diharapkan. Backstage menyediakan testing utilities untuk ini.
- Dokumentasikan Plugin Anda: Karena ini adalah solusi kustom, pastikan Anda mendokumentasikan dengan baik bagaimana plugin bekerja, cara mengonfigurasinya, dan prasyarat apa pun. Ini akan sangat membantu developer lain di tim Anda.
- Pertimbangkan Keamanan: Jika backend plugin Anda berinteraksi dengan sistem sensitif, pastikan Anda menerapkan praktik keamanan terbaik: validasi input, autentikasi/otorisasi yang tepat, dan logging aktivitas.
- Manajemen Dependensi: Backstage adalah monorepo. Pastikan Anda menggunakan versi dependensi yang konsisten dengan proyek Backstage inti Anda. Gunakan
yarn workspaceuntuk menambahkan dependensi ke plugin Anda.
Kesimpulan
Plugin kustom adalah fitur super power yang memungkinkan Anda membentuk Backstage menjadi Internal Developer Portal yang benar-benar unik dan kuat, disesuaikan dengan DNA organisasi Anda. Dengan memahami arsitektur dasar dan mengikuti praktik terbaik, Anda dapat menciptakan pengalaman developer yang luar biasa, meningkatkan produktivitas, dan mempercepat inovasi di seluruh tim engineering Anda.
Jangan ragu untuk mulai bereksperimen. Mulailah dengan plugin sederhana, lalu secara bertahap kembangkan fungsionalitasnya seiring dengan kebutuhan tim Anda. Dunia IDP yang berpusat pada developer menanti!
🔗 Baca Juga
- Membangun Internal Developer Portal dengan Backstage.io: Fondasi Produktivitas dan Self-Service untuk Tim Developer Anda
- Membangun Service Scorecard untuk Internal Developer Portal Anda: Mengukur Kesehatan dan Kualitas Layanan
- Platform Engineering: Membangun Fondasi yang Membantu Developer Bergerak Cepat dan Aman
- Pola Developer Self-Service: Memberdayakan Tim dengan Otomatisasi dan Kontrol