# Repo map — Helm

Ground truth for the course. Paths are from the repo root. Line numbers drift — treat them as
"look near here." Pinned versions: **Helm `v3.14.4`** (`deployments/versions/helm`), Skaffold
`v2.10.0` (`deployments/versions/skaffold`), helm-secrets `v4.7.0` + sops `v3.7.3`
(`deployments/tools.bash:207,220`).

---

## 0. The shape of it

`deployments/helm/` holds ~106 charts. Structure that matters:
- **`libs/util/`** — the **library chart** (`type: library`) with all workload templates.
- **`backend/<svc>/`** — one **application chart** per service (bob, spike, tom,
  conversationmgmt, …), each *tiny*: a `Chart.yaml`, a `values.yaml`, `{env}-{org}-values.yaml`
  files, `secrets/`, `configs/`, and a `templates/app.yaml` that calls one `util.*` macro.
- **`backend/values.yaml`** — a shared cross-service `global:` block.
- **`platforms/`, `data-warehouse/`, `appsmith/`, `emulators/`** — infra charts, some using
  *real* upstream subchart dependencies.

---

## 1. Chart.yaml anatomy *(Lesson 2)*
- Service charts: `apiVersion: v2`, **`type: application`**, `version: 0.1.0`, an `appVersion`.
  <span class="filepath">deployments/helm/backend/bob/Chart.yaml:1-6</span>,
  <span class="filepath">backend/spike/Chart.yaml</span>,
  <span class="filepath">backend/conversationmgmt/Chart.yaml</span>. **No `dependencies:` block**
  (util is copied in — topic 6).
- Library chart: `name: util`, **`type: library`**, `version: 0.1.0` —
  <span class="filepath">deployments/helm/libs/util/Chart.yaml:1-6</span>.

## 2. Values layering *(Lesson 4)*
Four layers, combined by Skaffold `valuesFiles` order (last wins):
1. `deployments/helm/platforms/gateway/{env}-{org}-values.yaml`
2. **`deployments/helm/backend/values.yaml`** — shared, entirely a `global:` block
   (<span class="filepath">backend/values.yaml:1-76</span>: `global.image.repository/tag`,
   `global.vpa`, `global.hasura*`, `global.onDemandNodeDeployment`, `global.caching.redis`).
3. `deployments/helm/backend/{env}-{org}-values.yaml`
4. **`deployments/helm/backend/<svc>/{env}-{org}-values.yaml`** — per-service per-cell deltas
   (<span class="filepath">backend/bob/local-manabie-values.yaml:1-46</span> trims cpu/mem, adds a route).

Per-service default values: <span class="filepath">backend/bob/values.yaml:1-263</span>
(`enabled`, `grpcPort: 5050`, `httpPort: 5080`, `hasuraEnabled`, `migrationEnabled`, `jobs`,
Istio routes, `resources`). `.Values.global.environment`/`.vendor` come from the repo-root
<span class="filepath">deployments/helm/local-manabie-values.yaml:1-10</span> and the Skaffold
`setValueTemplates` (topic 7); they're read via `util.environment`
(<span class="filepath">libs/util/templates/_env.tpl:6-16</span>) and `util.vendor` (`_env.tpl:37-47`).

## 3. Helpers / named templates *(Lessons 3, 5)*
**No `_helpers.tpl`** — helpers are split, all namespaced `util.*`:
- `util.name` <span class="filepath">libs/util/templates/_name.tpl:5-7</span> ·
  `util.fullname` `_name.tpl:14-20` · `util.chart` `_name.tpl:25-27`.
- `util.labels` <span class="filepath">libs/util/templates/_label.tpl:5-13</span> ·
  `util.selectorLabels` `_label.tpl:15-18` · `*.v2` component variants `_label.tpl:28-75`.
- `util.environment` / `util.vendor` <span class="filepath">libs/util/templates/_env.tpl:6-16,37-47</span>.
- Validation via `fail` (not `required`) — <span class="filepath">libs/util/templates/_check.tpl:44</span>.
- Entry macro `util.app` <span class="filepath">libs/util/templates/_app.tpl:7-77</span>
  (wrapped by `util.appWithToggle` `_app.tpl:1-5`, gated on `.Values.enabled`).

## 4. Template functions & built-in objects *(Lesson 3)*
Representative, quotable:
- `.Capabilities.APIVersions.Has "keda.sh/v1alpha1"` — <span class="filepath">_app.tpl:39</span> (KEDA-vs-HPA switch).
- `.Release.Namespace` in a KEDA Prometheus query — <span class="filepath">_keda.tpl:152</span>.
- `tpl (printf "configs/%s.common.config.yaml" .Chart.Name | .Files.Get) . | nindent 4` —
  <span class="filepath">_configmap.tpl:22</span> (render a config file as a template).
- `fromYaml (include …)` + `mustMergeOverwrite` + `toYaml` —
  <span class="filepath">_deployment.tpl:23-25</span> (spot + on-demand merge).
- `default .Values.global.X .Values.X` — <span class="filepath">_statefulset.tpl:12</span>
  (`replicas: {{ default .Values.global.replicaCount .Values.replicaCount }}`).
- `toYaml . | nindent 8` idiom — `_statefulset.tpl:27`, `_deployment.tpl:62`.

## 5. Library chart & the copy mechanism *(Lesson 6)*
- **`update_deps.sh` copies, it doesn't depend.** <span class="filepath">deployments/helm/update_deps.sh:5-6</span>
  (`sourceDir=libs/util/templates/.`), `:14-19` (`rm -rf templates/util; cp -a`), looping over
  `backend/*` and other groups (`:22-58`). That's why every chart has a generated
  `templates/util/` dir.
- **Real dependencies are the exception:**
  - `backend/zeus` — genuine upstream dep on `sftpgo 0.19.0`
    (<span class="filepath">backend/zeus/Chart.yaml:26-30</span>, vendored `charts/sftpgo-0.19.0.tgz`
    + `Chart.lock`).
  - `backend/shamir`, `backend/invoicemgmt` — carry a legacy packaged `util-0.1.0.tgz` under
    `charts/` (old path).
  - Platform/infra charts use normal subchart deps + `.tgz`/`Chart.lock`: keda
    (`platforms/keda/keda-2.17.2.tgz`), spark, camel-k, thanos, airflow
    (`data-warehouse/custom-airflow`), appsmith, istio.

## 6. Hooks & lifecycle *(Lesson 7)*
The DB-migration Job is the primary hook, and it's **gated to local**:
- Gate: <span class="filepath">libs/util/templates/_hook_migration.tpl:1-3</span> —
  `util.hook.migrate.enabled` = `migrationEnabled` AND vendor ≠ synersia AND env matches
  `^local$`. (So this Helm hook runs migrations only in local; prod migrations go through a
  different path — `deployments/job.bash`.)
- The Job: `util.hook.migrate` <span class="filepath">_hook_migration.tpl:5-127</span> — a
  `batch/v1` Job `<fullname>-migrate` with `helm.sh/hook: pre-install,pre-upgrade`,
  `hook-weight: "-47"`, `hook-delete-policy: before-hook-creation` (:11-14); initContainer
  `migrate-sql` runs `gjob sql_migrate` (:40-56).
- **Hook ordering (by weight, lowest first):** ServiceAccount `-50`
  (<span class="filepath">_serviceaccount.tpl:58-59</span>) → Secret `-49` (`_secret.tpl:14-18`)
  → ConfigMap `-48` (`_configmap.tpl:14-18`) → migrate Job `-47`. Promoted to hooks by
  `preHookUpsertStream` / `preHookUpsertKafkaTopic` (Kafka/NATS provisioning) or migration.

## 7. Releases & how Skaffold drives Helm *(Lesson 8)*
- `deploy.helm.releases` in <span class="filepath">skaffold.backend.yaml:5-76</span>
  (`apiVersion: skaffold/v4beta9`).
- First release `common` (`chartPath: deployments/helm/backend/common`, **`createNamespace: true`**
  `:14`, `wait: false`).
- Anchor `&ReleaseObject` (`:18-34`) — `valuesFiles` in precedence order (last wins): gateway
  `{env}-{org}` → `backend/values.yaml` (global) → `backend/{env}-{org}` → `backend/<svc>/{env}-{org}`.
- `setValueTemplates` `&DefaultValues` (`:27-31`): `global.environment: "{{.ENV}}"`,
  `global.vendor: "{{.ORG}}"`, `global.image.tag`, `global.caching.enabled`.
- Per-service <span class="filepath">backend/bob/skaffold.yaml:8-38</span>: `name: bob`,
  `chartPath: .`, `namespace: '{{.ENV}}-{{.ORG}}-backend'` (:10), 4 `valuesFiles` (:11-15),
  **`wait: true`**, `statusCheck: true` (:24), `profiles: local` → `kubeContext: kind-kind`.
- ENV/ORG exported by <span class="filepath">deployments/env.bash:38-42</span> feed the
  templated paths + namespace. `skaffold render` = `helm template`; `skaffold run` =
  `helm upgrade --install` (Course 1 L7).

## 8. SOPS ↔ Helm — the non-standard bit *(Lesson 9)*
**SOPS decryption is NOT done at deploy time by Helm or Skaffold.** The encrypted files are
embedded verbatim into a K8s Secret and decrypted **by the Go app at runtime**.
- `.AsSecrets` is a **Helm built-in** on `.Files.Glob`, not custom:
  <span class="filepath">libs/util/templates/_secret.tpl:33</span>
  (`{{ ($.Files.Glob $glob).AsSecrets }}`), glob `secrets/<vendor>/<env>/*.encrypted.yaml`
  (`:31`). dorp/trial merge prod secrets as a fallback (`:35-38`).
- The Secret is mounted; the app is passed `--secretsPath=…encrypted.yaml` and decrypts SOPS
  in-process (K8s course L6; migrate hook `_hook_migration.tpl:49`).
- Secret files: <span class="filepath">backend/bob/secrets/manabie/local/</span>
  (`bob.secrets.encrypted.yaml`, `bob_migrate.secrets.encrypted.yaml`, `hasura*.encrypted.yaml`).
- The `helm-secrets` plugin **is installed** (`deployments/tools.bash:205-224`) but is **not
  wired into the Skaffold deploy path** (grep of skaffold files for sops/helm-secrets = nothing).
  `sops -d` is only shelled out in `deployments/nats_password.bash:22`.

## 9. Chart quality gates *(Lesson 12)*
- `.helmignore` in every chart (e.g. `backend/bob/.helmignore`).
- `NOTES.txt` only in platform charts (redash, import-map-deployer, appsmith, ksql-server).
- Only one `values.schema.json` in the whole repo (`appsmith/mongodb`). No backend schema.
- No `helm lint` in scripts; closest is `helm template` for job rendering
  (<span class="filepath">deployments/job.bash:183</span>). Lockfiles only where real deps exist.

---

## Anchors cheat-list

| Topic | Where |
|---|---|
| Library chart | `deployments/helm/libs/util/Chart.yaml` (`type: library`) |
| Service chart | `backend/bob/Chart.yaml` (`type: application`, no deps) |
| Entry macro | `libs/util/templates/_app.tpl:7` (`util.app`) |
| fullname / labels | `_name.tpl:14-20` / `_label.tpl:5-13` |
| Global values | `backend/values.yaml` (`global:` block) + `_env.tpl:6-16,37-47` |
| Per-cell values | `backend/<svc>/{env}-{org}-values.yaml` |
| Copy mechanism | `deployments/helm/update_deps.sh:5-19` |
| Real dependency (exception) | `backend/zeus/Chart.yaml:26-30` (sftpgo) |
| Migration hook (local-only) | `_hook_migration.tpl:1-3,11-14` |
| Skaffold releases | `skaffold.backend.yaml:5-76`, `backend/bob/skaffold.yaml:8-38` |
| SOPS → Secret (`.AsSecrets`) | `_secret.tpl:31-38` |
| Helm version | `deployments/versions/helm` (`v3.14.4`) |
