Most teams I've worked with waste 2-3 hours every time they spin up a
new microservice. Create the repo, write the Dockerfile, set up CI,
write Kubernetes manifests, configure ingress, same boilerplate, every
single time.
I decided to automate all of it. One API call. Everything done
automatically.
What it does
POST to /api/services with a service name and language, and the
platform automatically:
- Creates a GitHub repository
- Commits a Dockerfile and GitHub Actions CI pipeline
- Creates a Kubernetes Deployment, Service, and Ingress
- Streams real-time status updates to a live dashboard via SignalR
The HTTP response comes back in under 200ms. All the work happens in a
background worker.
The architecture
The system is split into four .NET projects:
-
Idp.Api— ASP.NET Core 9 API, the entry point -
Idp.Core— domain models and interfaces -
Idp.Infrastructure— GitHub and Kubernetes integrations -
Idp.Worker— background provisioning pipeline
When a request comes in, the controller does one thing — saves a record
to PostgreSQL with status queued and returns 202 Accepted. The
background worker polls every 5 seconds, picks up queued jobs, and runs
the full provisioning pipeline.
The GitHub integration
I used Octokit.net to talk to the GitHub REST API. Here is what happens
when you provision a new service:
var repo = await client.Repository.Create(new NewRepository(serviceName)
{
Description = description,
Private = false,
AutoInit = true
});
// Give GitHub a moment to initialise
await Task.Delay(2000, ct);
// Commit Dockerfile
await client.Repository.Content.CreateFile(
organisation, serviceName, "Dockerfile",
new CreateFileRequest("chore: add Dockerfile", GetDockerfile(language)));
// Commit CI workflow
await client.Repository.Content.CreateFile(
organisation, serviceName, ".github/workflows/ci.yml",
new CreateFileRequest("chore: add CI workflow", GetCiWorkflow()));
The AutoInit: true creates an initial commit so we can push files
immediately. The 2 second delay is important — without it, GitHub
sometimes returns a 404 when you try to commit to a freshly created repo.
The Kubernetes integration
I used the official KubernetesClient NuGet package to create K8s
objects from C#:
// Create Deployment
await client.AppsV1.CreateNamespacedDeploymentAsync(deployment, ns);
// Create Service
await client.CoreV1.CreateNamespacedServiceAsync(service, ns);
// Create Ingress
await client.NetworkingV1.CreateNamespacedIngressAsync(ingress, ns);
Each service gets its own namespace, which keeps things clean and makes
it easy to delete a service and all its resources in one command.
Real-time updates with SignalR
The background worker pushes status updates to all connected browsers
as provisioning progresses:
await hubContext.Clients.All.SendAsync("StatusChanged", new
{
ServiceId = serviceId,
ServiceName = serviceName,
Status = status, // queued → creating_repo → deploying_k8s → deployed
RepoUrl = repoUrl,
ServiceUrl = serviceUrl
});
The dashboard listens for these events and updates the UI in real time
— no polling, no page refresh.
What I learned
Always use async provisioning. The first version was synchronous —
the HTTP request sat open for 6 seconds while GitHub did its work.
Moving to a background worker with a queue made the API feel instant.
GitHub needs a moment after repo creation. If you immediately try
to commit files to a freshly created repo, you get a 404. A 2 second
delay after AutoInit fixes it reliably.
Handle conflicts gracefully in Kubernetes. If you try to create a
resource that already exists, K8s returns a 409 Conflict. Catching that
and either replacing or skipping makes the system idempotent.
Secrets in git history are permanent. I accidentally committed my
GitHub token inside the bin/ folder early on. Even after deleting it,
it was in git history. I had to force push a rewritten history and
immediately rotate the token. Always add **/bin/ and **/obj/ to
.gitignore before your first commit.
The stack
| Layer | Technology |
|---|---|
| API | ASP.NET Core 9 |
| Database | PostgreSQL + Entity Framework Core 9 |
| GitHub automation | Octokit.net |
| Kubernetes automation | KubernetesClient |
| Real-time updates | SignalR |
| Logging | Serilog |
| API docs | Scalar |
Try it yourself
The full source code is on GitHub:
https://github.com/aftabkh4n/idp-platform
Clone it, add your GitHub token to appsettings.json, spin up a
PostgreSQL container, and run it. You should have a working IDP in under
5 minutes.
This is one of four portfolio projects I am building to demonstrate
senior backend engineering skills. Next up: a full Data Platform API
with search, analytics, and recommendations.
If you found this useful or have questions, drop a comment below.

Top comments (0)