A Claude Code skill scaffolds your whole onboarding from a short chat. You just review the PR.
payments-api
> claude "onboard payments-api to the platform" ● readiness check — repo · image · port · branch ✓ ● gathered the essentials — hostname, scaling ● wrote .infrastructure/development.yaml ● wrote .github/workflows/infrastructure.yml(gatecheck) ● ran the gatecheck locally — passed ✓ ✓ opened PR #42 → development— you review & merge
it scaffolds deployment infra only — never your app code
Skills for the whole lifecycle
onboard-service is one of a set — the same chat-driven flow covers a service from first deploy to day-2.
onboarding-readiness-check pre-flight — is the repo ready to deploy?
exposure:
hostname: portal.dev.younium.cc
auth:
mode: signedIn # any logged-in user
instance: frontegg # customers · or entra
gates: # optional — gate a path to a role
- pathPrefix: /admin/
roles: [Admin]
Zero auth code no OIDC in your app, no AAD app to register
instance entra for internal tools · frontegg for customers
gates require a role on a path; everything else stays open to any signed-in user
Automatic login redirect, session cookie & /logout — all handled
the raw IdP access token — forwarded on signedIn routes (not on gated sub-paths)
• Primary key = X-Auth-Request-User (the GUID); Email can be missing on Entra — fall back to Preferred-Username
• Groups is base64 → JSON, not comma-separated — decode then parse (changed from oauth2-proxy)
• Authorization: Bearer is a real IdP access token — you can relay it to another same-instance service (mind the aud/scopes)
• Trust these headers only from the gateway — EG strips client-supplied copies
• Switching instance resets sessions & flips User (oid↔sub); /logout signs out every app under .dev.younium.cc
For each block the platform: creates the resource (where applicable) · gives your service's own Azure identity exactly that access — your container, your topic, that account — · injects coordinates as env vars (BLOB_accountUrl, APPCONFIG_endpoint, …)
One credential. That's the whole pattern.
var credential = new DefaultAzureCredential(); // no options, no client IDs, no secrets
var blob = new BlobContainerClient(new Uri($"{Env("BLOB_accountUrl")}/{Env("BLOB_containerName")}"), credential);
builder.Configuration.AddAzureAppConfiguration(o => o.Connect(new Uri(Env("APPCONFIG_endpoint")), credential));
var sender = new ServiceBusClient(Env("SB_namespaceFqdn"), credential).CreateSender("orders");
• Every pod runs as your service's identity — the SDK finds it automatically
• No passwords or connection-string secrets exist anywhere in this flow
• Isolation is mutual and enforced by Azure: you can't read another service's data, and nothing else can read yours
# MSSQL fresh — empty DB, run your own migrations
mssql:
databases:
- { name: appdb, secretName: appdb-mssql, mode: fresh }
# MSSQL copy — clone the golden reference (default)
mssql:
databases:
- { name: appdb, secretName: appdb-mssql } # mode: copy is implicit — same as omitting mode
# MSSQL copy — stamp from another DB
mssql:
databases:
- { name: appdb, secretName: appdb-mssql,
mode: copy, sourceDatabase: ynm-db-reference-golden }
MSSQL modes
fresh empty database — run your own migrations
copy— default Azure DB copy; stamps from the platform golden DB
sourceDatabase copy from a specific DB instead (advanced)
✓ Fixes migrations in test environments — every environment gets its own copy of the database, so migrations run isolated and clean: no shared-DB drift, no conflicts between branches or PR previews.
Read-only content volumes
volumes:
- catalog: fonts # platform-managed asset
mountPath: /usr/share/fonts/truetype/ms
- container: ai-system-prompts # your blob container
mountPath: /mnt/ai-system-prompts
prefix: prod/ # optional subfolder (must end with /)
static files in your pod — an init container hydrates blob content into a read-only mount at pod start
catalog — platform-managed shared assets (no azureAccess block needed)
catalog
typical mountPath
fonts
/usr/share/fonts/truetype/ms
only fonts on dev/eu01 today — new entries need a cluster overlay PR
container — your own blob container (must match azureAccess.blob) not for read-write state — that's what databases and blob are for
Test environments — a full stack per branch
Label a PR test-env and the platform spins up a complete, isolated copy — your branch's services, their own URLs, their own data. Close the PR and it's gone.
PR · label test-env→namespace env-<name>→your branch, live own URLs · own DB copy
✓Isolated — own namespace + hostnames under the wildcard zone
✓Realistic data — its own database copy; migrations run clean
✓Production-shaped — same platform-service render as dev & prod
✓Ephemeral — created on the label, torn down when the PR closes
defined as a file in ynm-environments · dev cluster today
From merge to production
Merge to development → live on dev · automatic
merge → development→CI builds image tagged 1.4.0 → ACR→Kargo picks it up writes tag → development.yaml→live on dev webhook-driven · no clicks
Sandbox & production · one click each
Kargo UI · Promote→opens a promotion/* PR tag → sandbox.yaml→auto-merges on green check→live · both regions then Promote → prod
Instant rollback
re-promote a previous version in Kargo — one click, no rebuild (the image already exists)
Canary / blue-green
add a rollout block — weighted traffic shift with auto-analysis; rolls back itself if metrics regress · dashboard ↗
One product, many repos
A product is rarely one repo. Give each repo the samepromotion.project key and they share one Kargo pipeline and UI — see and promote the whole product together.
# in every repo of the product
promotion:
kargo: true
project: core # same key everywhere
→
Kargo · kargo-grp-core
monolith-api dev → sandbox → prod
web-angular dev → sandbox → prod
web-admintool dev → sandbox → prod
• each repo keeps its own image & build; the group just collects them in one pane
• promote members together or one at a time — same Promote click, same promotion/* PR flow
• add a service to the product by setting the key — no infra PR (groups are pre-registered per cluster)
shaped by what you ask for — tell us in #cloudops-support
One folder in your repo. The platform does the rest.
slack · #cloudops-support
~0:30. First-ever platform intro for the dev team. Promise up front:
this talk is everything you need to ship and run a service — and it
fits in one YAML file you own.
~1:30. The "why" before the "how". Lead with Container Apps so it reads as
evolution, not a rewrite. Security/SOC 2 = credibility + necessity. Clean
slate = the legacy cluster's mistakes are fixed at the root, not patched.
Reliability + cost are the day-to-day wins devs feel. Land it: same paved
road for everyone, you move at Git speed, the platform handles the rest.
~1:30. Demystify "platform". Two honest pieces. One: it's a real AKS cluster,
run from Git by ArgoCD and partitioned into two ArgoCD projects — `core`
(CloudOps-owned platform addons) and `services` (developer workloads, your
namespaces). Two: you only ever touch one file in your repo; a shared Helm
chart is the translation layer that turns it into Kubernetes. The K8s
complexity is real — it's the platform's problem, not yours.
~2:00. Reframe: the manifest is the one artefact that matters. Walk the chart
left-to-right once, then the four jobs it does — these are the rest of the
deck's section headers, so this slide is the map. Land the contract: if you
ever want to click in Azure or run kubectl, stop — it goes in the file.
~1:00. The hero: you don't even write the YAML. Walk the terminal top to
bottom — each ● is a step the skill performs (readiness check → the two files
→ a local gatecheck → a PR). The payoff line: it never writes app code, so
app-side gaps come back as TODOs. Next slide: the rest of the skill family.
~1:00. The point: onboarding is one skill in a family that spans the whole
lifecycle — readiness → onboard → add-database → modify → verify → inspect.
All in the ynm-platform plugin. None write app code; mutating ones land a PR,
inspecting ones are read-only. Reassures the control-conscious dev.
~2:00. Pay off the four verbs from "The manifest": here they are in one real
file. Walk it top to bottom — each marked block is one job. Top-level
postgres/mssql are repo-scoped (not per-service). Mention the companion
gatecheck workflow that blocks bad manifests pre-merge, and point at
platform.md + platform-demo to copy from. The deep-dive slides follow.
~3:00. Switch to the browser. Walk admin.dev.younium.cc: the service list,
open one service → its rendered manifest, claims, health, and the links out
(dashboards, logs, the live URL). Read-only — fastest answer to "what's
deployed and is it healthy". Tie back: everything shown here came from the
one manifest file.
~2:00. The hero is the baseline: six production features you never asked for —
that's the "without asking" payoff. The hardened pod baseline is overridable
if your image truly needs root/writable FS, but discourage it. The purple
chips are the opt-in menu — gesture at them, don't read them; the main ones
get their own slides later.
~1:30. The hero: one hostname line under *.dev.younium.cc → a real HTTPS URL.
Wildcard cert, DNS, and the Gateway route are all automatic — no ACME wait.
The knobs row: path shares a host (longest prefix wins), stripPrefix only when
the app serves from /, tls: none for internal services, auth → SSO, up next.
~2:00. Dev message: one block, no auth code. The gateway (Envoy-native OIDC)
does the sign-in; your app trusts the X-Auth-Request-* headers (next slide).
instance = entra (employees) / frontegg (customers). gates require a role on a
path; everything else is open to any signed-in user. Login redirect, cookie
and /logout are automatic. (V2 removed mode: role and logout — use signedIn +
gates; a logged-out hit on a gated path is a bare 401, log in at / first.)
~1:30. Deltas from V1 oauth2-proxy: primary identifier is X-Auth-Request-User
(oid/sub GUID); Email may be absent on Entra (use Preferred-Username); Groups
is base64-encoded JSON, not CSV — decode + parse. No Bearer/access-token header
is forwarded. sso-demo-eg echoes the headers for debugging.
~1:30. mode: http is the default and the cost win (zero when idle). replicas
for always-on. metrics for queue/event-driven workers (KEDA triggers). The
cold-start warning prevents the #1 support thread. Health checks next.
~1:30. Rule of thumb: if it's a value, config. If it's sensitive, Key
Vault + secrets block. There is no third place.
~2:30. Emphasize granularity: Service Bus access is per-topic and
per-direction (send vs receive). storage = the pre-existing shared data
accounts, allowlisted by name. Nobody writes Terraform for any of this.
~2:00. If anyone asks "which credential type": always
DefaultAzureCredential, no arguments. It works locally too (az login /
VS credential) — same code path from laptop to cluster.
~2:30. Pick fresh for greenfield schema work; copy (default) when you want
realistic reference data on day one. sourceDatabase is rarely needed — the
golden ynm-db-reference-golden is the usual stamp source. platform-demo has
working Npgsql + SqlClient samples. MSSQL: drop InvariantGlobalization in csproj.
~1:30. assetCatalog is cluster-scoped (clusters/dev/eu01/values.yaml); gatecheck
rejects unknown catalog names. Content updates need a pod restart. container
volumes pair with azureAccess.blob; catalog volumes auto-emit AssetsAccess.
~1:30. Test environments = the environments ApplicationSet (wave 31): a file in
ynm-environments deploys charts/platform-service into env-<name>. A PR labelled
test-env writes that file for your branch → a full, isolated stack with its own
URLs and its own DB copy; closing the PR tears it down. Same render as a real
service — what you test is what ships. Pairs with the per-env DB copy (prev slide).
~2:00. Build once, promote the digest — the exact bits tested on dev ship to
prod. Dev is fully automatic (Kargo direct-pushes the tag). Sandbox/prod is one
Promote click → Kargo opens a kargo/promotion/* PR that auto-merges on the green
check (branch protection stays enforced, no bypass) → ArgoCD deploys both
regions. Rollback = re-promote an older Freight (no rebuild). Canary/blue-green
= the rollout field (Argo Rollouts) with automated analysis + auto-abort.
~1:30. Grouped Projects: promotion.project: <name> lands the repo in the shared
kargo-grp-<name> Project (Warehouse + Stage per member) instead of a per-repo
one. The use case is a product spanning many repos/services (core =
monolith-api + frontend + several services). One UI pane, promote together or
individually. Group names are registered in servicesPromo.projects; the
gatecheck rejects unregistered names. All real services are grouped.
~1:00. The near-term roadmap: (1) Slack integration for build/promotion
notifications, (2) onboard CPQ — the first large service, (3) enable test
environments for the Younium core services, (4) finalize the sandbox → prod
promotion procedures. Demand-driven — invite asks.
~0:30. Close with the action: clone platform-demo, copy the
.infrastructure folder, rename things, open your first PR. Offer to
pair on the first onboarding.