This repository focuses on mastering Platform Engineering concepts and building Internal Development Platforms (IDP) using Backstage.io, service catalogs, and golden paths for developer self-service.
By working through this repository, you will:
- Understand Platform Engineering principles and philosophy
- Master Backstage.io for building developer portals
- Implement service catalogs and software templates
- Design golden paths for common workflows
- Build developer self-service capabilities
- Integrate platform APIs and plugins
- Measure platform adoption and developer experience
- Understanding of cloud infrastructure (Azure)
- Completed learning-idp-infrastructure-as-code
- Completed learning-idp-cicd-pipelines
- Node.js 18+ and Yarn installed
- Docker and Kubernetes knowledge
- Git and GitHub account
learning-idp-platform-engineering/
βββ README.md # This file
βββ REFERENCES.md # Links to resources and related repos
βββ .gitignore # Git ignore patterns
βββ .env.example # Environment variables template
β
βββ docs/
β βββ concepts/
β β βββ 01-platform-engineering-overview.md
β β βββ 02-developer-experience.md
β β βββ 03-golden-paths.md
β β βββ 04-service-catalog.md
β β βββ 05-platform-apis.md
β β βββ 06-platform-metrics.md
β βββ guides/
β β βββ getting-started-backstage.md
β β βββ creating-templates.md
β β βββ plugin-development.md
β β βββ integrations.md
β β βββ platform-adoption.md
β βββ examples/
β βββ simple-service-catalog.md
β βββ software-template.md
β βββ custom-plugin.md
β βββ platform-portal.md
β βββ golden-path-workflow.md
β
βββ backstage/
β βββ app/
β β βββ package.json
β β βββ tsconfig.json
β β βββ src/
β β βββ App.tsx
β β βββ components/
β β βββ theme/
β β
β βββ packages/
β β βββ backend/
β β β βββ package.json
β β β βββ src/
β β β βββ index.ts
β β β βββ plugins/
β β βββ app/
β β βββ package.json
β β βββ src/
β β
β βββ plugins/
β β βββ azure-devops/
β β β βββ package.json
β β β βββ src/
β β βββ cost-insights/
β β β βββ package.json
β β β βββ src/
β β βββ platform-metrics/
β β βββ package.json
β β βββ src/
β β
β βββ catalog/
β β βββ entities/
β β β βββ components/
β β β β βββ api-service.yaml
β β β β βββ web-app.yaml
β β β β βββ microservice.yaml
β β β βββ systems/
β β β β βββ platform.yaml
β β β β βββ product.yaml
β β β βββ apis/
β β β β βββ rest-api.yaml
β β β β βββ graphql-api.yaml
β β β βββ resources/
β β β β βββ database.yaml
β β β β βββ storage.yaml
β β β β βββ kubernetes.yaml
β β β βββ domains/
β β β βββ platform.yaml
β β β βββ product.yaml
β β βββ locations/
β β βββ catalog-info.yaml
β β
β βββ templates/
β β βββ python-service/
β β β βββ template.yaml
β β β βββ skeleton/
β β β βββ catalog-info.yaml
β β β βββ README.md
β β β βββ src/
β β βββ react-app/
β β β βββ template.yaml
β β β βββ skeleton/
β β βββ azure-function/
β β β βββ template.yaml
β β β βββ skeleton/
β β βββ infrastructure/
β β βββ template.yaml
β β βββ skeleton/
β β
β βββ techdocs/
β βββ default/
β β βββ mkdocs.yml
β βββ components/
β
βββ platform-apis/
β βββ service-provisioning/
β β βββ src/
β β β βββ main.py
β β β βββ routers/
β β β βββ services/
β β βββ tests/
β β
β βββ resource-management/
β β βββ src/
β β βββ tests/
β β
β βββ developer-portal/
β βββ src/
β βββ tests/
β
βββ golden-paths/
β βββ web-application/
β β βββ README.md
β β βββ template.yaml
β β βββ workflows/
β β βββ setup.yaml
β β βββ deploy.yaml
β β βββ monitor.yaml
β β
β βββ api-service/
β β βββ README.md
β β βββ template.yaml
β β βββ workflows/
β β
β βββ data-pipeline/
β β βββ README.md
β β βββ template.yaml
β β βββ workflows/
β β
β βββ infrastructure/
β βββ README.md
β βββ template.yaml
β βββ workflows/
β
βββ examples/
β βββ 01_basic_catalog/
β β βββ catalog-info.yaml
β β βββ README.md
β β
β βββ 02_software_templates/
β β βββ python-service-template.yaml
β β βββ react-app-template.yaml
β β βββ README.md
β β
β βββ 03_custom_plugins/
β β βββ cost-plugin/
β β βββ metrics-plugin/
β β βββ README.md
β β
β βββ 04_techdocs/
β β βββ component-docs/
β β βββ README.md
β β
β βββ 05_integrations/
β βββ azure-devops/
β βββ github-actions/
β βββ README.md
β
βββ automation/
β βββ onboarding/
β β βββ create-project.py
β β βββ setup-permissions.py
β β βββ configure-resources.py
β β
β βββ scaffolding/
β β βββ generate-service.py
β β βββ generate-infrastructure.py
β β
β βββ monitoring/
β βββ track-adoption.py
β βββ measure-experience.py
β
βββ metrics/
β βββ dashboards/
β β βββ platform-adoption.json
β β βββ developer-experience.json
β β βββ service-catalog.json
β β
β βββ queries/
β βββ usage-metrics.kql
β βββ experience-metrics.kql
β
βββ infrastructure/
β βββ backstage-deployment/
β β βββ kubernetes/
β β β βββ deployment.yaml
β β β βββ service.yaml
β β β βββ ingress.yaml
β β βββ bicep/
β β βββ backstage.bicep
β β
β βββ platform-services/
β βββ api-gateway/
β βββ service-mesh/
β
βββ tests/
β βββ unit/
β β βββ test_templates.py
β β βββ test_plugins.py
β β
β βββ integration/
β β βββ test_catalog.py
β β βββ test_workflows.py
β β
β βββ e2e/
β βββ test_developer_flow.py
β
βββ .github/
βββ workflows/
βββ backstage-deploy.yml
βββ template-validation.yml
βββ plugin-tests.yml
git clone https://github.com/vanHeemstraSystems/learning-idp-platform-engineering.git
cd learning-idp-platform-engineering# Install Node.js 18+ and Yarn
# On Ubuntu/Debian:
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
npm install -g yarn
# Verify installations
node --version
yarn --version# Create Backstage app
npx @backstage/create-app@latest
# Navigate to app directory
cd my-backstage-app
# Start development server
yarn dev# catalog-info.yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: my-first-service
description: My first service in the platform
annotations:
github.com/project-slug: my-org/my-first-service
spec:
type: service
lifecycle: production
owner: team-platform
system: platformFollow this recommended sequence:
Day 1-2: Platform Engineering Concepts
- Read
docs/concepts/01-platform-engineering-overview.md - Study
docs/concepts/02-developer-experience.md - Understand platform vs product thinking
Day 3-4: Backstage.io Setup
- Follow
docs/guides/getting-started-backstage.md - Set up local Backstage instance
- Explore default plugins
Day 5-7: Service Catalog
- Read
docs/concepts/04-service-catalog.md - Add services to catalog
- Define ownership and relationships
Day 1-3: Software Templates
- Study
docs/guides/creating-templates.md - Work through
examples/02_software_templates/ - Create custom templates
Day 4-7: Golden Paths
- Read
docs/concepts/03-golden-paths.md - Design workflow golden paths
- Implement in
golden-paths/
Day 1-4: Plugin Development
- Study
docs/guides/plugin-development.md - Work through
examples/03_custom_plugins/ - Create custom plugin
Day 5-7: Integrations
- Complete
docs/guides/integrations.md - Integrate Azure DevOps
- Configure GitHub Actions
Day 1-3: Platform APIs
- Read
docs/concepts/05-platform-apis.md - Build self-service APIs
- Implement in
platform-apis/
Day 4-7: Metrics & Adoption
- Study
docs/concepts/06-platform-metrics.md - Implement platform metrics
- Track developer experience
βββββββββββββββββββββββββββββββββββββββββββ
β PLATFORM ENGINEERING GOALS β
βββββββββββββββββββββββββββββββββββββββββββ€
β 1. Reduce cognitive load β
β 2. Enable self-service β
β 3. Standardize workflows β
β 4. Improve developer experience β
β 5. Increase development velocity β
βββββββββββββββββββββββββββββββββββββββββββ
Developer Intent
β
Golden Path
β
Template
β
Automation
β
Resources
β
Monitoring
# catalog-info.yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: payment-service
description: Payment processing microservice
annotations:
github.com/project-slug: my-org/payment-service
azure-devops.com/project-repo: my-org/payment-service
tags:
- python
- fastapi
- payments
links:
- url: https://payment-api.example.com
title: Production API
icon: dashboard
- url: https://docs.example.com/payment-service
title: Documentation
icon: docs
spec:
type: service
lifecycle: production
owner: team-payments
system: payment-platform
dependsOn:
- resource:payment-database
- component:notification-service
providesApis:
- payment-api# templates/python-service/template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: python-fastapi-service
title: Python FastAPI Service
description: Create a new Python FastAPI microservice
tags:
- python
- fastapi
- recommended
spec:
owner: team-platform
type: service
parameters:
- title: Service Information
required:
- name
- description
- owner
properties:
name:
title: Service Name
type: string
description: Unique name for your service
ui:autofocus: true
description:
title: Description
type: string
description: What does this service do?
owner:
title: Owner
type: string
description: Team owning this service
ui:field: OwnerPicker
ui:options:
catalogFilter:
kind: Group
- title: Azure Configuration
required:
- resourceGroup
- location
properties:
resourceGroup:
title: Resource Group
type: string
description: Azure Resource Group name
location:
title: Location
type: string
description: Azure region
enum:
- westeurope
- northeurope
- eastus
default: westeurope
steps:
- id: fetch-base
name: Fetch Base Template
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
description: ${{ parameters.description }}
owner: ${{ parameters.owner }}
- id: publish
name: Publish to GitHub
action: publish:github
input:
allowedHosts: ['github.com']
description: ${{ parameters.description }}
repoUrl: github.com?owner=my-org&repo=${{ parameters.name }}
- id: register
name: Register Component
action: catalog:register
input:
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: '/catalog-info.yaml'
- id: create-azure-resources
name: Create Azure Resources
action: azure:resource-group:create
input:
name: ${{ parameters.resourceGroup }}
location: ${{ parameters.location }}
output:
links:
- title: Repository
url: ${{ steps.publish.output.remoteUrl }}
- title: Open in Backstage
icon: catalog
entityRef: ${{ steps.register.output.entityRef }}// plugins/platform-metrics/src/plugin.ts
import {
createPlugin,
createRoutableExtension,
} from '@backstage/core-plugin-api';
export const platformMetricsPlugin = createPlugin({
id: 'platform-metrics',
routes: {
root: rootRouteRef,
},
});
export const PlatformMetricsPage = platformMetricsPlugin.provide(
createRoutableExtension({
name: 'PlatformMetricsPage',
component: () =>
import('./components/PlatformMetricsPage').then(
m => m.PlatformMetricsPage
),
mountPoint: rootRouteRef,
})
);// plugins/platform-metrics/src/components/PlatformMetricsPage.tsx
import React from 'react';
import { Grid, Card, CardContent, Typography } from '@material-ui/core';
import { InfoCard } from '@backstage/core-components';
export const PlatformMetricsPage = () => {
const metrics = usePlatformMetrics();
return (
<Grid container spacing={3}>
<Grid item xs={12} md={4}>
<InfoCard title="Active Services">
<Typography variant="h3">
{metrics.activeServices}
</Typography>
</InfoCard>
</Grid>
<Grid item xs={12} md={4}>
<InfoCard title="Deployments This Week">
<Typography variant="h3">
{metrics.weeklyDeployments}
</Typography>
</InfoCard>
</Grid>
<Grid item xs={12} md={4}>
<InfoCard title="Developer Satisfaction">
<Typography variant="h3">
{metrics.satisfaction}%
</Typography>
</InfoCard>
</Grid>
</Grid>
);
};# platform-apis/service-provisioning/src/main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
app = FastAPI(
title="Platform Service Provisioning API",
description="Self-service API for provisioning platform services"
)
class ServiceRequest(BaseModel):
name: str
type: str
owner: str
environment: str
config: dict
class ServiceResponse(BaseModel):
id: str
name: str
status: str
endpoints: List[str]
repository_url: str
@app.post("/services", response_model=ServiceResponse)
async def create_service(request: ServiceRequest):
"""
Create a new service using the platform's golden path
"""
# Validate request
if request.type not in ["api", "web", "worker"]:
raise HTTPException(status_code=400, detail="Invalid service type")
# Create from template
service = await create_from_template(
name=request.name,
type=request.type,
owner=request.owner
)
# Provision infrastructure
infrastructure = await provision_infrastructure(
service_id=service.id,
environment=request.environment,
config=request.config
)
# Register in service catalog
await register_in_catalog(service)
return ServiceResponse(
id=service.id,
name=service.name,
status="provisioning",
endpoints=infrastructure.endpoints,
repository_url=service.repository_url
)
@app.get("/services/{service_id}", response_model=ServiceResponse)
async def get_service(service_id: str):
"""
Get service details
"""
service = await fetch_service(service_id)
if not service:
raise HTTPException(status_code=404, detail="Service not found")
return service# Enable developers to provision their own resources
template:
parameters:
- user inputs (minimal)
steps:
- validate
- provision
- configure
- register
- notifyGolden Path = Template + Automation + Best Practices
Components:
- Pre-configured templates
- Automated workflows
- Built-in security
- Observability by default
- Documentation included
# Platform metrics to track
metrics = {
"adoption": {
"active_services": count,
"template_usage": count,
"developer_signups": count
},
"experience": {
"time_to_first_deploy": duration,
"template_completion_rate": percentage,
"support_tickets": count
},
"performance": {
"provisioning_time": duration,
"deployment_frequency": rate,
"success_rate": percentage
}
}Feedback Loop:
1. Gather developer feedback
2. Analyze pain points
3. Improve platform
4. Measure impact
5. Repeat
- learning-internal-development-platform - Main overview
- learning-idp-infrastructure-as-code - IaC for platform
- learning-idp-cicd-pipelines - Platform automation
- learning-idp-api-development - Platform APIs
- learning-idp-observability - Platform monitoring
This is a personal learning repository, but suggestions and improvements are welcome!
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Ensure all tests pass
- Submit a pull request
This project is for educational purposes. See LICENSE file for details.
Willem van Heemstra
- GitHub: @vanHeemstraSystems
- LinkedIn: Willem van Heemstra
Last updated: December 18, 2025 Part of the learning-internal-development-platform series