Two Stacks, One Notification Layer
A practitioner running Python automation on Kubernetes at work and on Supabase and Vercel for side projects — and why the compute substrate changed while the Slack notification layer never did.
Most of this section examines patterns published by large engineering organizations. This one is smaller and more ordinary, and that is the point: it is one engineer’s answer to the question what are you actually using to automate your work? — asked and answered twice, because the same person runs two very different stacks for two very different contexts.
The two stacks
At work. Three servers running Docker, orchestrated with Kubernetes, with the automation itself written in Python. The jobs are wired into Slack for notification and Jira for work tracking. It is a long-standing combination rather than a recent build, and it is the part of the stack its owner knows best — which matters more than it sounds like, and is picked apart below.
For personal projects. No Kubernetes. Not because it would not work, but because the operational overhead is not worth paying twice — the stated reason is simply that it is a hassle. Side projects run on Supabase for the managed database and backend, and Vercel for deployment and scheduled functions.
In both. Slack. Automation results, errors, and anything that needs a human to look at it are delivered there, and the personal stack drops Kubernetes long before it would drop notifications.
flowchart LR
subgraph W["At work"]
W1["Python automation"] --> W2["Docker images"]
W2 --> W3["Kubernetes<br/>3 servers"]
W3 --> W4["CronJobs / controllers"]
end
subgraph P["Personal projects"]
P1["Python / TypeScript"] --> P2["Supabase<br/>Postgres + auth + storage"]
P1 --> P3["Vercel<br/>deploys + cron functions"]
end
W4 --> S["Slack<br/>results · errors · approvals"]
P2 --> S
P3 --> S
W4 --> J["Jira<br/>tickets · audit trail"]
Why the split is defensible
It is tempting to read “Kubernetes at work, managed platform at home” as an inconsistency to be resolved. It is closer to the opposite: the same person applied the same screening question — is this worth automating, and at what cost? — to two situations with different answers, and got two different stacks.
| At work | Personal projects | |
|---|---|---|
| Workloads | Many, long-lived, shared | Few, intermittent |
| Failure cost | Other people’s work blocks | Mild personal annoyance |
| Who operates it | A team, on a rota | One person, in spare time |
| Compute | Kubernetes on 3 servers | Supabase + Vercel |
| Marginal cost of a new job | Near zero once the platform exists | Near zero because someone else operates the platform |
Three servers running Kubernetes is a real platform with real fixed costs: upgrades, certificate rotation, node pressure, the control plane itself. Those costs are worth paying when they are amortised across a team’s workloads and someone is on call anyway. The same fixed costs against a handful of personal cron jobs buy nothing — the platform becomes the project. Choosing a managed substrate for the low-stakes context is not a step down in maturity; it is declining to operate infrastructure that has no reason to exist.
The inverse also holds, and is the reason the work stack is not simply moved to a managed platform. Kubernetes at work is earning its overhead: shared scheduling, restart semantics, resource limits, and a place for the platform work described in Internal Developer Platforms to live.
The part that is easy to miss: fluency is a real selection criterion
The work stack is described not just as powerful but as the thing its owner is most confident in. That is easy to dismiss as sentiment. It is not — it is an operational property.
Automation is judged on what happens when it breaks at an inconvenient hour. A stack you have run for years, whose failure modes you recognise from the shape of the log line, has a materially lower mean time to repair than a technically superior stack you learned last month. Scaling Automation Practice makes the organizational version of this argument — that the constraint on an automation programme is rarely the tooling. The individual version is the same: a tool nobody on the team can debug under pressure is not a faster tool.
The honest caveat is that this cuts both ways. Fluency is a legitimate input to a technology decision and a very common cover story for avoiding one. The test is whether you can name what the alternative would buy you and why it does not clear the switching cost. “Kubernetes is a hassle for three cron jobs” passes that test. “We have always used it” does not.
The notification layer is the part that transfers
The stacks diverge completely. The notification layer does not, and that is the transferable finding.
An automated job that runs correctly and tells nobody is indistinguishable from one that did not run at all — which is the failure mode dissected in The Alert That Never Fired, arrived at there from a production outage and here from the far cheaper direction of a side project that silently stopped syncing. Whatever else changes between contexts, the path from “something happened” to “a human knows” has to survive, because it is the part that makes the rest observable.
Delivering that into Slack rather than email is a deliberate choice with real properties:
- It is where the humans already are, so the latency between a failure and someone seeing it is small. Email is a place notifications go to be archived unread.
- It is threaded, so a job’s failure, the investigation, and the resolution stay attached to each other. That thread is often a better incident record than anything written afterwards.
- It is interactive. A Slack message can carry buttons, which is the cheapest possible front-end for the approval steps in Runbook Automation — approve the retry, acknowledge the alert, trigger the rollback.
- It is trivially wired up. An incoming webhook is a
POST. This matters more than it should, because a notification path that is annoying to add is a notification path that gets skipped on the job you write in a hurry.
The Jira half is the same idea on a slower clock. Slack is for the thing that needs attention now; the ticket is for the thing that needs to still exist next week. Automation that opens and updates tickets keeps the work visible to people who were not in the channel at the time, and leaves the audit trail that Compliance as Code depends on.
Where this pattern goes wrong
Enthusiasm for the notification layer has a predictable failure mode, and the strength of the pattern is exactly what causes it.
- Every job posting to one channel. The channel becomes a log stream, and a log stream nobody reads is not a notification. Split by urgency, not by system: one channel for things that need a human now, one for the record.
- Success notifications by default. If a job posts on every successful run, the failures are camouflaged by the successes. Post failures, state changes, and summaries; keep routine success in a dashboard or a daily digest.
- Slack as the only signal. A notification layer that depends on the job itself being alive cannot report that the job stopped running. This is the silent-alerts failure in miniature, and the fix is the same shape: a dead-man’s-switch that expects a heartbeat and pages when it stops arriving. Supabase’s scheduled functions and Kubernetes CronJobs both fail silently in the same way, on both stacks.
- Alerting on Slack from a system that depends on Slack. Keep at least one path — even an SMS to one phone — that does not route through the tool being reported on. The relevant discipline is in Alert Design and Noise Reduction.
What transfers
Transfers well, at any size:
- Choosing the compute substrate per context rather than standardising on the heaviest one you can operate.
- Treating operational fluency as a real input to technology choice, with the switching-cost test applied honestly.
- Keeping the notification layer constant across stacks, so every automation is reachable through one habit.
- Chat for what needs attention now, tickets for what needs to persist.
Needs adaptation:
- Kubernetes on three servers is an at-work answer with a team behind it. A single operator should reach for managed compute first and justify the cluster, not the other way round.
- Slack specifically is incidental; the property that matters is a low-friction, interactive channel where the humans already are. Teams on Teams, Discord, or Matrix get the same benefit.
- The Jira half assumes an organization that already tracks work there. For a personal project the equivalent is usually an issue tracker in the same repo, or nothing at all.
Adoption checklist
- Each context — production, internal tooling, side projects — has a compute substrate chosen for its actual stakes, not inherited from the heaviest one.
- Any platform you operate yourself is carrying enough workloads to justify its fixed operational cost.
- Every automated job has a notification path, and it is the same path for all of them.
- Notifications go where the people already are, and carry enough context to act on without opening another tool.
- Failures and state changes are notified; routine successes are not.
- Anything that must outlive the notification becomes a ticket automatically.
- A heartbeat or dead-man’s-switch covers the case where a job stops running entirely.
- At least one alerting path does not depend on the chat tool it is reporting on.
- Where a stack was chosen for familiarity, you can state what the alternative would buy and why it does not clear the switching cost.
Last updated 30 Aug 2026, 00:00 UTC.