BACKSTAGE PLATFORM-ENGINEERING INTERNAL-DEVELOPER-PORTAL PLUGIN-DEVELOPMENT WEB-DEVELOPMENT TYPESCRIPT REACT DEVELOPER-EXPERIENCE CUSTOMIZATION DEVOPS OPEN-SOURCE SOFTWARE-ARCHITECTURE

Membangun Plugin Kustom di Backstage.io: Mengoptimalkan Internal Developer Portal Anda

⏱️ 13 menit baca
👨‍💻

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:

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:

  1. 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.
  2. 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:

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:

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?

🎯 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:

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:

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