Thank you for installing **{{ .Chart.Name }}**.

Release: {{ .Release.Name }} / namespace {{ .Release.Namespace }}

Services use ClusterIP; expose via ingress, gateway, or kubectl port-forward. **reverseproxy:** with **`components.reverseproxy.kubernetesUpstreamHosts: true`** (default), YARP destinations are set by env to **`http://<fullname>-server:<serverPort>/`** and **`http://<fullname>-client:<clientPort>/`** (same pattern for single-node and HA replica counts). Docker Compose uses **`docker-compose.override.yml`** env to **`http://server:…`** / **`http://client:…`** instead (no Helm).

------------------------------------------------------------
## Components

- server: {{ include "certs-ui.fullname" . }}-server:{{ .Values.components.server.service.port }}
- client: {{ include "certs-ui.fullname" . }}-client:{{ .Values.components.client.service.port }}
- reverseproxy: {{ include "certs-ui.fullname" . }}-reverseproxy:{{ .Values.components.reverseproxy.service.port }}

Port-forward API example:

  kubectl port-forward svc/{{ include "certs-ui.fullname" . }}-server {{ .Values.components.server.service.port }}:{{ .Values.components.server.service.port }} -n {{ .Release.Namespace }}

------------------------------------------------------------
## Images

Image tag: **`global.image.tag` when set**, else **`components.*.image.tag`**. There is **no** fallback to Chart `appVersion`; set tags explicitly (chart default is `latest` per component when **`global.image.tag`** is omitted). To force one tag for all images, uncomment **`global.image.tag`** in **`values.yaml`** (see commented examples).

**imagePullPolicy**: **`global.image.pullPolicy` when set**, else **`components.*.image.pullPolicy`**, else **`IfNotPresent`** in the template. Chart **`values.yaml`** sets per-component **`pullPolicy: IfNotPresent`** and omits **`global.image.pullPolicy`** so components win by default. Uncomment the example under **`global.image`** to override all. Values may use **`always`** / **`Always`** (normalized for the Pod spec).

With **`Always`**, the chart sets pod annotation **`rollme`**: by default **`r<Release.Revision>-<unixEpoch>`** so each **`helm upgrade`** bumps the revision even when the tag is unchanged. For **`helm template`** output committed to git, revision is usually **1** and epoch is frozen until you re-render — then pass **`global.rolloutNonce`** from CI (unique per deploy, e.g. pipeline id) so the applied manifest changes every image push. Pin **`global.rollme`** to a string you bump when you need a stable, deterministic rollout key.

With **`IfNotPresent`** (default), **`rollme`** is omitted; the node may keep a cached layer for a mutable tag even if you replace the tag in the registry.

Pod annotation **certs-ui.io/image** is the resolved `registry/repository:tag` for debugging.

Optional per workload under **`components.<name>`**: **`replicaCount`** (default **1**; stateless **client** / **reverseproxy** are safe to raise on an HA cluster), **`livenessProbe`**, **`readinessProbe`**, **`resources`** (standard Kubernetes container fields). Omit a key to leave it unset.

When **`replicaCount` > 1**, the chart creates a **PodDisruptionBudget** (`minAvailable: 1`) for that component.

**Primary replica + ACME:** With multiple **server** pods, exactly one holds the Postgres lease `certs-ui-primary` and runs ACME orchestration (`CertsFlowDomainService`, renewal). Others answer **`AcmeChallengeAsync`** from the database for HTTP-01. Interactive UI flows should hit the primary: the chart defaults **`ClientIP`** session affinity on the **server** Service, and clients should retry on **503** (see `Retry-After` / `ProblemDetails`). After unclean failover, the old lease row can linger until its TTL (~90s with defaults); renewals and clean shutdown avoid stuck primaries.

**Server + RWO PVCs:** the default **acme** / **data** volumes use **ReadWriteOnce**. Kubernetes will not schedule a second server pod on the same volume; for multiple server replicas you need **ReadWriteMany** (or equivalent) and an application design that tolerates shared disk (see product HA roadmap).

------------------------------------------------------------
## Config

Root keys `certsServerConfig`, `certsServerSecrets`, `certsClientRuntime` feed templated `configMapFile` / `secretsFile` content when `tpl: true`.

Use `existingConfigMap` / `existingSecret` to mount resources created outside the chart. With `keep: true`, existing objects are not replaced on upgrade if already present.

------------------------------------------------------------
## Uninstall

  helm uninstall {{ .Release.Name }} -n {{ .Release.Namespace }}
