# Cr Field

> Use when adding a new field to an existing Custom Resource. Guides the full workflow: API types, code generation, CRD examples, client investigation, handler mapping, and tests.

- Skill: `epam/cr-field` (Agent Skill)
- Install (CLI): `npx skillmds@latest add epam/cr-field`
- Raw SKILL.md: https://api.skillmd.com/api/skills/epam/cr-field/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: epam (https://skillmd.com/u/epam)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/epam/cr-field

---


## Your task

Add a new field to an existing Custom Resource following the project's established conventions.
Complete every step. The order matters: Step 2 generates code from the types added in Step 1, and Step 5 maps onto the representation type found in Step 4.

---

## Step 1 — Add field to API types

File: `api/v1/{kind}_types.go` (or `api/v1alpha1/` for alpha resources).

Add the struct field with a godoc comment and kubebuilder markers. Choose markers that match the field's semantics:

- `// +required` / `// +optional`
- `// +nullable` — for pointer slices or maps that can be explicitly null
- `// +kubebuilder:validation:Enum=val1;val2` — restrict to allowed values
- `// +kubebuilder:default=value` — set a default when field is omitted
- `// +kubebuilder:example=value` — example shown in generated docs
- `// +kubebuilder:validation:XValidation:rule=...,message=...` — CEL validation (e.g. immutability)

JSON tag: `json:"fieldName,omitempty"` for optional fields, `json:"fieldName"` for required.

See `api/v1/keycloakclient_types.go` for the full variety of marker patterns in use.

---

## Step 2 — Run code generation

```
make generate && make manifests
```

This regenerates DeepCopy methods and CRD YAMLs in `config/crd/bases/` and `deploy-templates/crds/`.

---

## Step 3 — Update CRD examples

Add the new field with a meaningful example value to:
- `config/samples/v1_v1_{kind}.yaml` (`v1_v1alpha1_{kind}.yaml` for alpha kinds)
- `deploy-templates/_crd_examples/{kind}.yaml`

---

## Step 4 — Identify the client and find the Keycloak representation type

Do this before touching handler code: the generated client may not expose the field, and Step 5 maps onto the representation type found here.

### 4a. Confirm the controller uses keycloakapi

All controllers use `pkg/client/keycloakapi/`. Confirm the handler imports this package.

### 4b. Find the Keycloak representation struct

Check `pkg/client/keycloakapi/contracts.go` for the relevant client interface
(`GroupsClient`, `ClientsClient`, `RolesClient`, etc.).
Representation types are type aliases — grep `pkg/client/keycloakapi/generated/client_generated.go`
for the struct name (e.g. `GroupRepresentation`, `ClientRepresentation`, `RoleRepresentation`)
to see which fields are available.

### 4c. Confirm the field exists — then follow this decision tree

- **Field exists in keycloakapi representation** → proceed to Step 5.
- **Field missing from keycloakapi representation** → stop and report it. The spec `pkg/client/keycloakapi/openapi/openapi.yaml` is downloaded from the Keycloak release pinned by `KEYCLOAK_VERSION` in the Makefile, so the field needs a newer release: bump the version and run `make generate-keycloak-go-client`. That is a separate change; ask the user before going further.

---

## Step 5 — Map the field in the chain handler

In `internal/controller/{resource}/chain/` find the handler that creates/updates the resource
(usually `create_or_update_{resource}.go` or `put_{resource}.go`).

Map the field in **both** paths:
- **Create path**: include the field when building the representation struct before the Create call.
- **Update path**: assign the field on the fetched existing representation before the Update call.

Reference: `internal/controller/keycloakrealmgroup/chain/create_or_update_group.go`

**Destination guard.** If the field holds a remote address (host or URL), call
`guard.RequireHost` on it before any Secret tied to it is resolved — inject the guard and
copy the pattern from `internal/controller/keycloakrealm/chain/configure_email.go`.

---

## Step 6 — Update unit tests

File: `internal/controller/{resource}/chain/*_test.go`

Add the field to the spec setup and to the mock expectations for all test cases:
create path, update path, and error paths.

Reference: `internal/controller/keycloakrealmgroup/chain/create_or_update_group_test.go`

---

## Step 7 — Update integration tests

File: `internal/controller/{resource}/*_controller_integration_test.go`

Add the field to the CR creation spec. Assert the correct value is persisted in Keycloak
using `Eventually()` + `g.Expect()`.

Reference: `internal/controller/keycloakrealmgroup/keycloakrealmgroup_controller_integration_test.go`

---

## Step 8 — Validate

Invoke the `run-golangci-lint` skill, then the `run-tests` skill.

