Skip to content
Back to skills

Helm Standards

ASecurity

Standards for Helm charts in SDD projects, including settings-driven patterns.

  • 43 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added February 8, 2026
developmenttypescriptbashnodeexpressapidatabasefullstackci/cd

Works with

  • api

Security analysis

A100/100

Scanned September 8, 2026

npx -y skills add LiorCohen/sdd --skill helm-standards --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Helm Standards?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Helm Standards
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/liorcohen-helm-standards/badge)](https://www.skillsdirectory.com/skills/liorcohen-helm-standards)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: helm-standards
description: Standards for Helm charts in SDD projects, including settings-driven patterns.
---

# Helm Standards Skill

Standards for Helm charts in SDD projects. Charts are generated based on component settings from `sdd/sdd-settings.yaml`.

## Skills

Use the following skills for reference:
- `techpack-settings` — Authoritative source for helm component settings schema, validation rules, and the chart-per-deployment pattern

## Chart-per-Deployment Pattern

Each deployment configuration gets its own helm chart. A single server can have multiple helm charts (e.g., one for API mode with ingress, one for worker mode without). Delegate to the `techpack-settings` skill for the complete helm settings schema — it returns `deploys` (server reference), `deploy_type` (server/webapp), `deploy_modes` (array of mode strings like `[api, worker]`), `ingress` (boolean), and `assets` (static file configuration). These settings determine which templates are included in each chart.

## Directory Structure

Helm charts live at `components/helm_charts/<name>/`:

```text
components/helm_charts/
├── main-server-api/          # API deployment
│   ├── Chart.yaml
│   ├── values.yaml
│   └── templates/
│       ├── _helpers.tpl
│       ├── deployment.yaml
│       ├── service.yaml
│       ├── ingress.yaml
│       ├── configmap.yaml
│       └── servicemonitor.yaml
├── main-server-worker/       # Worker deployment (no ingress)
│   ├── Chart.yaml
│   ├── values.yaml
│   └── templates/
│       ├── _helpers.tpl
│       ├── deployment.yaml
│       ├── configmap.yaml
│       └── servicemonitor.yaml
├── admin-dashboard/          # Webapp deployment
│   ├── Chart.yaml
│   ├── values.yaml
│   └── templates/
│       ├── _helpers.tpl
│       ├── deployment.yaml
│       ├── service.yaml
│       ├── ingress.yaml
│       └── configmap.yaml
└── umbrella/                 # Optional: installs all charts
    ├── Chart.yaml
    └── values.yaml
```

## Values File Conventions

| File | Purpose |
|------|---------|
| `values.yaml` | Default values (development-safe) |
| `values-{env}.yaml` | Environment overrides (local, staging, production) |

## Required Values

Every Helm chart must define these values:

```yaml
# Infrastructure settings (NOT application config)
nodeEnv: development          # NODE_ENV for libraries (Express caching, etc.)

# Application config (from config component)
config: {}                    # Merged config from components/config/envs/{env}/
```

## Server Chart Values

### Single Mode Server

```yaml
replicaCount: 1
nodeEnv: development

image:
  repository: main-server
  tag: latest
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 3000

observability:
  metrics:
    enabled: true
    port: 9090
    serviceMonitor:
      enabled: false
      interval: 30s

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 100m
    memory: 128Mi

config: {}
```

### Hybrid Server (Multiple Modes)

```yaml
nodeEnv: development

image:
  repository: main-server
  tag: latest
  pullPolicy: IfNotPresent

# Each mode gets independent scaling
api:
  enabled: true
  replicaCount: 2
  resources:
    limits:
      cpu: 500m
      memory: 512Mi
    requests:
      cpu: 100m
      memory: 128Mi

worker:
  enabled: true
  replicaCount: 5
  resources:
    limits:
      cpu: 1000m
      memory: 1Gi
    requests:
      cpu: 200m
      memory: 256Mi

service:
  type: ClusterIP
  port: 3000

observability:
  metrics:
    enabled: true
    port: 9090
    serviceMonitor:
      enabled: false
      interval: 30s

config: {}
```

## Webapp Chart Values

```yaml
replicaCount: 1
nodeEnv: development

image:
  repository: nginx
  tag: alpine
  pullPolicy: IfNotPresent

assets:
  type: bundled              # bundled | entrypoint
  path: /usr/share/nginx/html

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: true
  className: nginx
  hosts:
    - host: app.example.com
      paths:
        - path: /
          pathType: Prefix

config: {}                   # Injected into HTML at deploy time
```

## Observability Integration

All server charts include observability by default:

### ServiceMonitor (Prometheus/Victoria Metrics)

```yaml
# templates/servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: {{ include "common.fullname" . }}
spec:
  selector:
    matchLabels:
      {{- include "common.selectorLabels" . | nindent 6 }}
  endpoints:
    - port: metrics
      interval: {{ .Values.observability.metrics.serviceMonitor.interval }}
      path: /metrics
```

### Metrics Endpoint

All servers expose metrics on port 9090:
- `/metrics` - Prometheus format metrics
- `/health/live` - Liveness probe
- `/health/ready` - Readiness probe

### Structured Logging

Applications output JSON logs to stdout. The cluster's log collector (Victoria Logs) picks them up automatically.

**Note:** Cluster-level observability infrastructure is set up separately (see task #47).

## Config Injection Pattern

### Server Config

Config is mounted via ConfigMap at `/app/config/config.yaml`:

```yaml
# templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "common.fullname" . }}-config
data:
  config.yaml: |
    {{- toYaml .Values.config | nindent 4 }}
```

### Webapp Config

Config is injected into HTML at deploy time:

1. Webapp exports: `export const startApp = (config: AppConfig) => { ... }`
2. Helm chart's index.html has: `startApp(__SDD_CONFIG__)`
3. Init container replaces `__SDD_CONFIG__` with JSON from ConfigMap

## Populating Config at Deploy Time

```bash
# Generate config for production environment
<plugin-root>/fullstack-typescript/system/system-run.sh config generate --env production --component main-server \
  --output helm-values-config.yaml

# Deploy with config
helm install my-release ./components/helm_charts/main-server-api \
  -f values-production.yaml \
  --set-file config=helm-values-config.yaml
```

## Environment Variables

| Var | Source | Purpose |
|-----|--------|---------|
| `NODE_ENV` | `.Values.nodeEnv` | Library behavior (Express caching, etc.) |
| `SDD_CONFIG_PATH` | Static `/app/config/config.yaml` | Path to mounted config |
| `SDD_SERVER_MODE` | Set per deployment | For hybrid: which mode (api, worker, cron) |

## Secret References

Config contains secret **names**, not values. Applications use K8s `secretKeyRef` to load the actual values:

```yaml
# values-production.yaml
config:
  database:
    host: db.production.internal
    passwordSecret: "my-db-credentials"  # K8s Secret name
```

```yaml
# templates/deployment.yaml - Using secretKeyRef
env:
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: {{ .Values.config.database.passwordSecret }}
        key: password
```

## Best Practices

1. **Chart-per-deployment** - Separate charts for different deployment configurations
2. **Settings-driven templates** - Use component settings to determine what's included
3. **Never hardcode environment values** - Use values files for all environment differences
4. **Keep secrets external** - Reference K8s Secrets by name only
5. **Config component is source of truth** - Helm just mounts it
6. **Validate config before deploy** - Use `/sdd I want to validate my config` in CI/CD
7. **Independent scaling** - Use separate deployments for hybrid modes

---

## Input / Output

This skill defines no input parameters or structured output.


## Related Skills

- `config-standards` — Delegate to this for config naming and structure conventions. Defines the config schema patterns that Helm `values.yaml` must align with.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.