Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions charts/plugin-br-pix-switch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

BACEN-compliant PIX instant payment platform for the Lerian ecosystem.

The plugin is a Go monorepo that produces 10 independently-deployable binaries.
The plugin is a Go monorepo that produces 13 independently-deployable binaries.
This chart deploys all of them with one helm release. Each component has its
own Deployment, Service, ConfigMap, Secret, HPA, and PDB; ingress is opt-in
per component.
Expand All @@ -29,21 +29,24 @@ per component.
| `cobHub` | `cob/hub/api` | 4108 | COB hub |
| `cobProxy` | `cob/proxy/api` | 4109 | COB proxy to BCB |
| `cobSystemplane` | `cob/systemplane/api` | 4110 | Runtime config plane for COB |
| `adapterLerian` | `adapter-lerian/api` | 4113 | Lerian provider adapter (API, disabled by default) |
| `adapterLerianConsumer` | `adapter-lerian/consumer` | 4114 | Lerian provider adapter Kafka consumer (disabled by default) |
| `adapterLerianSystemplane` | `adapter-lerian/systemplane/api` | 4115 | Runtime config plane for adapter-lerian (disabled by default) |

## Architecture

The plugin uses a Proxy/Hub deployment model. A "hub" component owns business
logic and local state (its own Postgres database, sometimes Mongo+Valkey),
while a "proxy" component is a stateless pass-through. Both expose identical
APIs. Three Postgres databases are required (`pix-spi`, `pix-dict`, `pix-cob`)
and one Mongo database (`pix-dict`) for `dict-hub` (`pix-cob` is a
APIs. Four Postgres databases are required (`pix-spi`, `pix-dict`, `pix-cob`,
`pix-adapter-lerian`) and one Mongo database (`pix-dict`) for `dict-hub` (`pix-cob` is a
forward-compat slot the Mongo bootstrap provisions but no component reads yet).

## Required infrastructure

For a full deployment:
- **PostgreSQL**: 3 databases (`pix-spi`, `pix-dict`, `pix-cob`) and a role
`pixswitch` with full ownership of each
- **PostgreSQL**: 4 databases (`pix-spi`, `pix-dict`, `pix-cob`,
`pix-adapter-lerian`) and a role `pixswitch` with full ownership of each
- **MongoDB**: 1 database (`pix-dict`) used by `dict-hub`; the bootstrap also
provisions `pix-cob` as a forward-compat slot, but no component reads it yet
- **Valkey** (Redis-compatible): used by `spi`, `dict-hub`, `dict-hub-vsync`
Expand All @@ -64,6 +67,8 @@ Default `enabled` values:
- `spi`, `spiSystemplane`, `dictHub`, `dictHubVsync`, `dictProxy`,
`dictSystemplane`, `cobHub`, `cobProxy`, `cobSystemplane`: `true`
- `adapterBtgMock`: `false` (it's a mock — only enable in dev/staging)
- `adapterLerian`, `adapterLerianConsumer`, `adapterLerianSystemplane`: `false`
(Lerian provider adapter — enable per environment)

## Configuration

Expand All @@ -87,7 +92,9 @@ The app reads:

Each component publishes and pulls its own image
(`ghcr.io/lerianstudio/plugin-br-pix-switch-<component>-api`), set per
component under `<component>.image.repository`. There is no shared
component under `<component>.image.repository`. Worker components omit the
`-api` suffix (e.g. `plugin-br-pix-switch-dict-hub-vsync` and
`plugin-br-pix-switch-adapter-lerian-consumer`). There is no shared
`global.image.repository`. When a component's `image.tag` is unset it falls
back to `.Chart.AppVersion`, which keeps the cohort in lockstep by default;
override `<component>.image.tag` to pin a specific build per component (rare).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{{- if .Values.adapterLerianConsumer.enabled }}
{{- $component := "adapter-lerian-consumer" }}
{{- $values := .Values.adapterLerianConsumer }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "plugin-br-pix-switch.componentFullname" (dict "context" $ "component" $component) }}
namespace: {{ include "global.namespace" . }}
labels:
{{- include "plugin-br-pix-switch.labels" (dict "context" $ "component" $component) | nindent 4 }}
data:
{{- range $key, $value := $values.configmap }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- /*
OTEL_RESOURCE_SERVICE_VERSION: derive from the deployed image tag so it
tracks releases automatically. Resolution order:
component image.tag > Chart.AppVersion.
Operators can override by setting `<component>.configmap.OTEL_RESOURCE_SERVICE_VERSION`
explicitly (the range above wins because data keys are unique per YAML map,
but we only emit this when the key wasn't already provided).
*/}}
{{- if not (hasKey $values.configmap "OTEL_RESOURCE_SERVICE_VERSION") }}
{{- $compTag := default $.Chart.AppVersion $values.image.tag }}
OTEL_RESOURCE_SERVICE_VERSION: {{ $compTag | quote }}
{{- end }}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
{{- if .Values.adapterLerianConsumer.enabled }}
{{- $component := "adapter-lerian-consumer" }}
{{- $values := .Values.adapterLerianConsumer }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "plugin-br-pix-switch.componentFullname" (dict "context" $ "component" $component) }}
namespace: {{ include "global.namespace" . }}
labels:
{{- include "plugin-br-pix-switch.labels" (dict "context" $ "component" $component) | nindent 4 }}
spec:
revisionHistoryLimit: {{ $values.revisionHistoryLimit | default 10 }}
{{- if not $values.autoscaling.enabled }}
replicas: {{ $values.replicaCount }}
{{- end }}
strategy:
{{- toYaml $values.deploymentStrategy | nindent 4 }}
selector:
matchLabels:
{{- include "plugin-br-pix-switch.selectorLabels" (dict "context" $ "component" $component) | nindent 6 }}
template:
metadata:
{{- with $values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "plugin-br-pix-switch.labels" (dict "context" $ "component" $component) | nindent 8 }}
spec:
{{- with (include "plugin-br-pix-switch.componentImagePullSecrets" (dict "context" $ "componentValues" $values)) }}
{{- if . }}
imagePullSecrets:
{{- . | nindent 8 }}
{{- end }}
{{- end }}
serviceAccountName: {{ include "plugin-br-pix-switch.componentServiceAccountName" (dict "context" $ "component" $component "componentValues" $values) }}
securityContext:
{{- toYaml $values.podSecurityContext | nindent 8 }}
initContainers:
{{- include "plugin-br-pix-switch.waitForDependencies" (dict "context" $ "component" $component "componentValues" $values) | nindent 8 }}
containers:
- name: {{ $component }}
securityContext:
{{- toYaml $values.securityContext | nindent 12 }}
image: {{ include "plugin-br-pix-switch.componentImage" (dict "context" $ "componentValues" $values) }}
imagePullPolicy: {{ include "plugin-br-pix-switch.componentPullPolicy" (dict "context" $ "componentValues" $values) }}
{{- with $values.command }}
command:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with $values.args }}
args:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: http
containerPort: {{ $values.service.port }}
protocol: TCP
envFrom:
- configMapRef:
name: {{ include "plugin-br-pix-switch.componentFullname" (dict "context" $ "component" $component) }}
- secretRef:
name: {{ include "plugin-br-pix-switch.componentSecretName" (dict "context" $ "component" $component "componentValues" $values) }}
{{- /*
Build the env: list when EITHER telemetry is enabled (HOST_IP +
OTEL_EXPORTER_OTLP_ENDPOINT injected via downward API so each
pod talks to its node-local OTel collector by default) OR the
operator has set extraEnvVars. The configmap-supplied
OTEL_EXPORTER_OTLP_ENDPOINT can still be overridden by setting
it in the configmap; the K8s rule is "later env entry wins",
so the configmap value (via envFrom) is overridden by the
explicit env entry below.
*/}}
{{- $telemetryOn := eq (toString (default "false" $values.configmap.TELEMETRY_ENABLED)) "true" }}
{{- $hasExtras := gt (len $values.extraEnvVars) 0 }}
{{- if or $telemetryOn $hasExtras }}
env:
{{- if $telemetryOn }}
- name: HOST_IP
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: "$(HOST_IP):4317"
{{- end }}
{{- if $hasExtras }}
{{- range $k, $v := $values.extraEnvVars }}
- name: {{ $k }}
value: {{ $v | quote }}
{{- end }}
{{- end }}
{{- end }}
resources:
{{- toYaml $values.resources | nindent 12 }}
readinessProbe:
httpGet:
path: {{ $values.readinessProbe.path | default "/lerian/readyz" }}
port: http
initialDelaySeconds: {{ $values.readinessProbe.initialDelaySeconds | default 10 }}
periodSeconds: {{ $values.readinessProbe.periodSeconds | default 5 }}
timeoutSeconds: {{ $values.readinessProbe.timeoutSeconds | default 1 }}
successThreshold: {{ $values.readinessProbe.successThreshold | default 1 }}
failureThreshold: {{ $values.readinessProbe.failureThreshold | default 3 }}
livenessProbe:
httpGet:
path: {{ $values.livenessProbe.path | default "/lerian/health" }}
port: http
initialDelaySeconds: {{ $values.livenessProbe.initialDelaySeconds | default 5 }}
periodSeconds: {{ $values.livenessProbe.periodSeconds | default 10 }}
timeoutSeconds: {{ $values.livenessProbe.timeoutSeconds | default 1 }}
successThreshold: {{ $values.livenessProbe.successThreshold | default 1 }}
failureThreshold: {{ $values.livenessProbe.failureThreshold | default 3 }}
{{- with $values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with $values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with $values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{{- if and .Values.adapterLerianConsumer.enabled .Values.adapterLerianConsumer.autoscaling.enabled }}
{{- $component := "adapter-lerian-consumer" }}
{{- $values := .Values.adapterLerianConsumer }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "plugin-br-pix-switch.componentFullname" (dict "context" $ "component" $component) }}
namespace: {{ include "global.namespace" . }}
labels:
{{- include "plugin-br-pix-switch.labels" (dict "context" $ "component" $component) | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "plugin-br-pix-switch.componentFullname" (dict "context" $ "component" $component) }}
minReplicas: {{ $values.autoscaling.minReplicas }}
maxReplicas: {{ $values.autoscaling.maxReplicas }}
metrics:
{{- if $values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ $values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if $values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ $values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{{- if and .Values.adapterLerianConsumer.enabled .Values.adapterLerianConsumer.pdb.enabled }}
{{- $component := "adapter-lerian-consumer" }}
{{- $values := .Values.adapterLerianConsumer }}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ include "plugin-br-pix-switch.componentFullname" (dict "context" $ "component" $component) }}
namespace: {{ include "global.namespace" . }}
labels:
{{- include "plugin-br-pix-switch.labels" (dict "context" $ "component" $component) | nindent 4 }}
{{- with $values.pdb.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if $values.pdb.minAvailable }}
minAvailable: {{ $values.pdb.minAvailable }}
{{- else if $values.pdb.maxUnavailable }}
maxUnavailable: {{ $values.pdb.maxUnavailable }}
{{- end }}
selector:
matchLabels:
{{- include "plugin-br-pix-switch.selectorLabels" (dict "context" $ "component" $component) | nindent 6 }}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{{- if and .Values.adapterLerianConsumer.enabled (not .Values.adapterLerianConsumer.useExistingSecret) }}
{{- $component := "adapter-lerian-consumer" }}
{{- $values := .Values.adapterLerianConsumer }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "plugin-br-pix-switch.componentFullname" (dict "context" $ "component" $component) }}
namespace: {{ include "global.namespace" . }}
labels:
{{- include "plugin-br-pix-switch.labels" (dict "context" $ "component" $component) | nindent 4 }}
type: Opaque
stringData:
{{- range $key, $value := $values.secrets }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{{- if .Values.adapterLerianConsumer.enabled }}
{{- $component := "adapter-lerian-consumer" }}
{{- $values := .Values.adapterLerianConsumer }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "plugin-br-pix-switch.componentFullname" (dict "context" $ "component" $component) }}
namespace: {{ include "global.namespace" . }}
labels:
{{- include "plugin-br-pix-switch.labels" (dict "context" $ "component" $component) | nindent 4 }}
{{- with $values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ $values.service.type }}
ports:
- port: {{ $values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "plugin-br-pix-switch.selectorLabels" (dict "context" $ "component" $component) | nindent 4 }}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{{- if and .Values.adapterLerianConsumer.enabled .Values.adapterLerianConsumer.serviceAccount.create }}
{{- $component := "adapter-lerian-consumer" }}
{{- $values := .Values.adapterLerianConsumer }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "plugin-br-pix-switch.componentServiceAccountName" (dict "context" $ "component" $component "componentValues" $values) }}
namespace: {{ include "global.namespace" . }}
labels:
{{- include "plugin-br-pix-switch.labels" (dict "context" $ "component" $component) | nindent 4 }}
{{- with $values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{{- if .Values.adapterLerianSystemplane.enabled }}
{{- $component := "adapter-lerian-systemplane" }}
{{- $values := .Values.adapterLerianSystemplane }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "plugin-br-pix-switch.componentFullname" (dict "context" $ "component" $component) }}
namespace: {{ include "global.namespace" . }}
labels:
{{- include "plugin-br-pix-switch.labels" (dict "context" $ "component" $component) | nindent 4 }}
data:
{{- range $key, $value := $values.configmap }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- /*
OTEL_RESOURCE_SERVICE_VERSION: derive from the deployed image tag so it
tracks releases automatically. Resolution order:
component image.tag > Chart.AppVersion.
Operators can override by setting `<component>.configmap.OTEL_RESOURCE_SERVICE_VERSION`
explicitly (the range above wins because data keys are unique per YAML map,
but we only emit this when the key wasn't already provided).
*/}}
{{- if not (hasKey $values.configmap "OTEL_RESOURCE_SERVICE_VERSION") }}
{{- $compTag := default $.Chart.AppVersion $values.image.tag }}
OTEL_RESOURCE_SERVICE_VERSION: {{ $compTag | quote }}
{{- end }}
{{- end }}
Loading
Loading