# Repo map — Kubernetes objects

Ground truth for the course. Every K8s object in this repo is generated from **one library
Helm chart**; lessons point at that chart. Paths are from the repo root. Line numbers drift —
treat them as "look near here."

---

## 0. The one fact that explains everything

Almost every Kubernetes object in this repo is produced by a single **library chart**:
<span class="filepath">deployments/helm/libs/util/</span> (`Chart.yaml` → `type: library`).
It is *not* wired as a normal Helm subchart — <span class="filepath">deployments/helm/update_deps.sh:5-19</span>
physically **copies** `libs/util/templates/` into every service chart's `templates/util/`. So
`backend/tom/templates/util/_deployment.tpl` is a byte-identical generated copy.

> **Cite the `libs/util` source, not the per-service copies.**

Each service's own `templates/app.yaml` is tiny — it just calls one library macro:
```yaml
# deployments/helm/backend/spike/templates/app.yaml:1
{{- include "util.appWithToggle" . -}}
```
That macro (`util.app`, <span class="filepath">deployments/helm/libs/util/templates/_app.tpl:7</span>)
emits, in order: **ConfigMap → Secret → PDB → ServiceAccount → Deployment → Service → VPA →
HPA/KEDA**. One include, a whole app's worth of objects.

---

## 1. Deployments *(Lesson 4)*
- Shared template: <span class="filepath">libs/util/templates/_deployment.tpl:30</span>
  (`define "_util.deployment.spot"`; `kind: Deployment` at :31). Wrapper `util.deployment` at :4.
- **22 backend services are Deployments:** auth, bob, calendar, discount, draft, enigma,
  entryexitmgmt, eureka, fatima, grade, invoicemgmt, jerry, lessonmgmt, mastermgmt,
  **notificationmgmt**, payment, **spike**, timesheet, usermgmt, virtualclassroom, yasuo, zeus.
- **Hand-written extra Deployment (notification team — great example):**
  <span class="filepath">backend/notificationmgmt/templates/deployment-consumers.yaml:2</span> —
  a second Deployment `{name}-consumers` running Kafka consumers (`gjob
  notificationmgmt_consumers`), with an HTTP `/healthz` livenessProbe (:118-127) and
  `terminationGracePeriodSeconds: 60`.
- `-on-demand-node` sibling generated via merge at `_deployment.tpl:125`.

## 2. StatefulSets *(Lesson 7)*
- Shared template: <span class="filepath">libs/util/templates/_statefulset.tpl:4</span>
  (`util.statefulSet`; `kind: StatefulSet` at :5; `serviceName` at :13).
- **Only two backend business services are StatefulSets** (grep confirmed):
  - **`tom`** — bespoke split: <span class="filepath">backend/tom/templates/statefulset.yaml:2</span>
    (`util.statefulSet`) + `tom/templates/app.yaml:1` (everything *except* the workload).
  - **`conversationmgmt`** (the learner's service) —
    <span class="filepath">backend/conversationmgmt/templates/app.yaml:1</span> →
    `util.appStatefulSetWithToggle` → `util.statefulSet` (`_app_statefulset.tpl:20`).
- Infra StatefulSets (platform, not backend): kafka, NATS-JetStream, elastic, yugabyte
  (`deployments/helm/platforms/*/templates/statefulset.yaml`), local registry.

## 3. Services *(Lesson 5)*
- Shared template: <span class="filepath">libs/util/templates/_service.tpl:4</span>
  (`util.service`); **`type: ClusterIP` hard-coded at :12**; http/grpc ports :14-25.
- **No headless service** for tom/conversationmgmt — they reuse the normal ClusterIP service
  (`_statefulset.tpl:13` `serviceName` points at it). Headless services exist only for infra.
- **Only LoadBalancer in backend:** <span class="filepath">backend/zeus/templates/lb_service.yaml:13</span>
  (static IP for sftpgo). **No NodePort** anywhere in backend.

## 4. ConfigMaps & Secrets *(Lesson 6)*
- ConfigMap: <span class="filepath">libs/util/templates/_configmap.tpl:9</span> — packs
  `{svc}.common.config.yaml` + per-vendor/env `{svc}.config.yaml`.
- Secret: <span class="filepath">libs/util/templates/_secret.tpl:9</span> (`type: Opaque`);
  data from SOPS-encrypted `secrets/{vendor}/{env}/*.encrypted.yaml` (`.AsSecrets`, :31-33).
- **How secrets reach a pod:** mounted as `secrets-volume` (`_workload_volumes.tpl:2-10`),
  read-only into the container (`_workload_containers.tpl:47-50`); the app is passed
  `--secretsPath=…encrypted.yaml` (`_workload_containers.tpl:36`) and **decrypts SOPS
  in-process** — *no decrypt sidecar* for the main app. (Only Hasura has a SOPS init container:
  `_workload_init_container.tpl:53-79`.)
- ServiceAccount + **GKE Workload Identity** annotation `iam.gke.io/gcp-service-account`:
  <span class="filepath">libs/util/templates/_serviceaccount.tpl:61</span> *(Lesson 12 / Course 7)*.
- Config/secret **checksum annotations** on the pod template (`_workload_metadata.tpl:3-8`) —
  changing config rolls the pods.

## 5. Autoscaling — KEDA dominant *(Lesson 9)*
- KEDA `ScaledObject` template: <span class="filepath">libs/util/templates/_keda.tpl</span> —
  request-rate (Prometheus `istio_requests_total`, :147-153), optional **kafka-lag**
  (`kafka_consumergroup_lag`, :167-173), cron/on-demand (`minReplicaCount: 0`, :6).
- Wiring: <span class="filepath">libs/util/templates/_app.tpl:39-57</span> — use KEDA if its CRD
  is present, **else** HPA ("Keda uses HPA under the hood, can't use both").
- **Notification team's KEDA (best example):**
  <span class="filepath">backend/notificationmgmt/templates/scaledobject-consumers.yaml:4</span>
  — scales the `-consumers` Deployment on **kafka-lag** (`sum(kafka_consumergroup_lag{…})`,
  :51-56); values `notificationmgmt/prod-tokyo-values.yaml:31-50`
  (`kafkaLag.lagThreshold: "7500"`). Request-rate for the main svc at :11-26.
- HPA fallback (CPU only): <span class="filepath">libs/util/templates/_hpa.tpl:15</span>.
- VPA (widely applied, mostly `updateMode: Off`): <span class="filepath">libs/util/templates/_vpa.tpl:45</span>.
- KEDA CRDs installed from `deployments/helm/platforms/keda/keda-2.17.2-*.

## 6. PodDisruptionBudget *(Lesson 11)*
- Template: <span class="filepath">libs/util/templates/_pdb.tpl:4</span> (`util.pdb`,
  `apiVersion: policy/v1`); **`maxUnavailable: default 1`** at :10 (no `minAvailable`).
  Rendered for every service. Toggle example: tom disables it (`backend/tom/values.yaml:48-49`).

## 7. Probes & resources *(Lesson 8)*
- All in <span class="filepath">libs/util/templates/_workload_containers.tpl</span>:
  - **readinessProbe** :76-99 — `exec: /bin/grpc_health_probe -addr=localhost:{port}` (:92).
  - **startupProbe** :103-122 (`failureThreshold: 12`).
  - **livenessProbe** :123-142 (same `grpc_health_probe`).
  - **resources** :145-146 (`toYaml .Values.resources`).
- Concrete values: <span class="filepath">backend/tom/values.yaml:53-59</span>
  (`requests.memory: 128Mi`, probes enabled).
- Init containers (`_workload_init_container.tpl`): wait-for-deps + `{svc}-migrate` running
  `gjob sql_migrate` (:21-30) — the forward-only migrations from the Postgres course.

## 8. Namespaces & RBAC *(Lesson 12)*
- **Namespace `{{.ENV}}-{{.ORG}}-backend`** set by Skaffold, not templates:
  <span class="filepath">backend/bob/skaffold.yaml:10</span> (also zeus; lmsdwh uses `-lmsdwh`).
  Most services inherit it from an umbrella skaffold invocation.
- **ServiceAccount** is the main per-service RBAC object (`_serviceaccount.tpl:25`).
- Only backend Role-binding: <span class="filepath">backend/gandalf/templates/clusterrolebinding.yaml:3</span>
  — a `ClusterRoleBinding` to `cluster-admin` (local test tool only). No custom Roles/ClusterRoles.
- Namespace-scoped policy in the `common` chart:
  <span class="filepath">backend/common/templates/networkpolicy.yaml</span> (2 NetworkPolicies) +
  `common/templates/limitrange.yaml` (LimitRange).

## 9. The library chart (the source of it all) *(all lessons)*
- <span class="filepath">deployments/helm/libs/util/</span> — 48 `.tpl` files. Key ones:
  `_app.tpl`, `_app_statefulset.tpl`, `_deployment.tpl`, `_statefulset.tpl`, `_service.tpl`,
  `_configmap.tpl`, `_secret.tpl`, `_serviceaccount.tpl`, `_pdb.tpl`, `_hpa.tpl`, `_keda.tpl`,
  `_vpa.tpl`, `_workload_containers.tpl`, `_workload_init_container.tpl`, `_workload_volumes.tpl`,
  `_affinity.v6.tpl`, `_tolerations.v4.tpl`, `_topology_spread_constraints.tpl`.
- Distributed by `deployments/helm/update_deps.sh` (copy, not dependency). *The templating
  mechanics themselves are **Course 3 (Helm)**.*

## 10. Raw (non-library) manifests
- No `deployments/k8s/` dir. Raw manifests limited to: local registry
  (`deployments/registry/registry.yaml` — Service/ConfigMap/StatefulSet/PDB), the emulators
  (`deployments/helm/emulators/*/templates/deployment.yaml`), and KEDA CRDs (raw YAML).
- Semi-raw (own templates, not the util lib): notification's `deployment-consumers.yaml` +
  `scaledobject-consumers.yaml`, and zeus's `lb_service.yaml`.

---

## Anchors cheat-list

| Object | Library template | Best repo example |
|---|---|---|
| Deployment | `libs/util/…/_deployment.tpl:30` | `backend/spike` (via `_app.tpl`) |
| Extra Deployment (consumers) | — | `backend/notificationmgmt/templates/deployment-consumers.yaml:2` |
| StatefulSet | `libs/util/…/_statefulset.tpl:4` | `backend/tom`, `backend/conversationmgmt` |
| Service (ClusterIP) | `libs/util/…/_service.tpl:4` | all services |
| LoadBalancer | — | `backend/zeus/templates/lb_service.yaml:13` |
| ConfigMap / Secret | `_configmap.tpl:9` / `_secret.tpl:9` | all (SOPS in-process decrypt) |
| KEDA ScaledObject | `libs/util/…/_keda.tpl` | `notificationmgmt/…/scaledobject-consumers.yaml:4` |
| HPA (fallback) | `libs/util/…/_hpa.tpl:15` | — |
| VPA | `libs/util/…/_vpa.tpl:45` | all (updateMode Off) |
| PDB | `libs/util/…/_pdb.tpl:4` | all (maxUnavailable 1) |
| Probes (grpc_health_probe) | `_workload_containers.tpl:76-142` | all |
| ServiceAccount + WI | `_serviceaccount.tpl:25,61` | all |
| Namespace `{ENV}-{ORG}-backend` | `backend/bob/skaffold.yaml:10` | — |
