Skip to main content
Version: 0.4.x

Platform Features

The scaffold wizard creates an XTenantApp and, when enabled, an XTenantDatabase. These two Crossplane XRs are how tenant apps declare what Kubernetes-level features they need without writing raw Deployment or StatefulSet manifests.

This page covers every supported feature, how it maps to the XR spec, and whether it belongs in the scaffold wizard (project-level, environment-agnostic) or the Promotion panel (per-environment, patched by each overlay).

Two Tiers: Base vs Overlay

tenants-apps/{team}/{appName}/
base/
xtenant-app.yaml ← platform feature toggles: ingress, TLS, probes,
rollout strategy, monitoring, secrets
overlays/dev/
patch-xtenant-app.yaml ← env-specific values: replicas, resources,
ingress host, cert issuer, DB name/tier

The scaffold wizard writes only the base. It declares which features are on or off for the project. The Promotion panel later fills in the env-specific values — replicas, resource limits, ingress hostnames — as JSON 6902 patches on top of the base.

Kubernetes Features

Container Config

FieldDescriptionSet at
containerPortHTTP port your app listens onScaffold wizard
image{registry}/{team}/{appName}:latest — ArgoCD Image Updater takes over after first deployScaffold (base)
imagePullSecretsDefaults to ["regcred"] — the cluster's registry pull secretScaffold (base)
envPlain (non-secret) environment variables, key/valueScaffold wizard
podAnnotationsExtra pod annotations; monitoring annotations added here if enabledScaffold wizard

Replicas & Resources

Set per environment via the Promotion panel — they do not belong in the base because dev and production have different sizing requirements.

# overlays/production/patch-xtenant-app.yaml
- op: replace
path: /spec/parameters/replicas
value: 3
- op: replace
path: /spec/parameters/resources
value:
requests: { cpu: "250m", memory: "256Mi" }
limits: { cpu: "1", memory: "512Mi" }

Health Probes

Enable liveness and readiness probes in the scaffold wizard by providing the HTTP paths. The composition injects these as httpGet probes against containerPort.

spec:
parameters:
probes:
liveness:
enabled: true
path: /healthz
readiness:
enabled: true
path: /ready

The startup probe is available for apps with slow cold-starts but is not exposed in the scaffold wizard — add it manually to the base YAML after scaffolding if needed.

FieldTypeDefault
pathstringrequired when enabled
periodSecondsintcomposition default
failureThresholdintcomposition default

Ingress

The ingress feature toggle lives in the base — it declares that the app is HTTP-reachable. The hostname and cert issuer are overlay-specific and are set by the Promotion panel when creating each environment overlay.

Scaffold wizard toggles (go into base):

ToggleEffect
ingressEnabled: trueTurns on the Ingress resource
certManager: trueAdds TLS block; clusterIssuer set per env via Promote
ssoAuth: trueAdds auth annotation; requires an OAuth2 proxy on the cluster

Overlay patch (set by Promotion panel):

- op: add
path: /spec/parameters/ingress/host
value: payment-api.dev.wxops.cloud
- op: add
path: /spec/parameters/ingress/tls/clusterIssuer
value: letsencrypt-staging

Rollout Strategy

Default is RollingUpdate. Set rolloutType in the scaffold wizard to override:

ValueWhen to use
RollingUpdateDefault; zero-downtime rolling replacement
RecreateApps that cannot run two versions concurrently (database schema changes)
CanaryGradual traffic split; requires Darlane traffic weight config
spec:
parameters:
rolloutStrategy:
type: Recreate

Secret Reloader

When enabled, the composition adds a Reloader annotation that tells Stakater Reloader to restart pods whenever the referenced ConfigMap or Secret changes. Enable in the scaffold wizard:

spec:
parameters:
reloader:
enabled: true

This is safe to leave on in all environments — Reloader is a no-op if the secret doesn't change.

Monitoring (Prometheus)

Enable monitoringEnabled in the scaffold wizard. The composition adds pod annotations that Prometheus uses for service discovery:

metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"

metricsPath defaults to /metrics. Set it in the scaffold wizard if your app exposes metrics on a different path.

Darlane (Debug Pods)

Darlane debug pods are not configured at scaffold time. They are injected per-environment as an overlay patch through the Promotion panel UI or wxops debug.

See the Darlane documentation for the full patch format, traffic routing, file sync, and TTL configuration.

Database

When the scaffold wizard's database option is enabled, the backend generates an XTenantDatabase CR alongside the XTenantApp.

Project-Level Config (Base)

Only settings that don't change between environments belong in the base:

FieldDescription
spec.parameters.ownerPostgres role owner — set to the team name
spec.parameters.extensionsPostgres extensions to install; defaults to ["uuid-ossp", "pgcrypto"]
spec.parameters.vaultSecretStoreNameAlways vault-tenant — the ClusterSecretStore on spoke clusters
apiVersion: platform.wxops.cloud/v1alpha1
kind: XTenantDatabase
metadata:
name: rocket-team-payment-api-db
spec:
parameters:
owner: rocket-team
extensions: [uuid-ossp, pgcrypto, pg_trgm]
vaultSecretStoreName: vault-tenant

Per-Environment Config (Overlay via Promote)

The Promotion panel adds these fields as JSON 6902 patches to each environment's kustomization.yaml. None of them belong in the base.

FieldDescriptionExample (dev)
dbNameDatabase name inside the clusterpayment-api-dev
tierCluster size preset: micro, small, medium, largemicro
environmentUsed by the composition to select the right CNPG configdev
clusterRefName of the shared CNPG cluster to attach toshared-pg-dev

For production workloads that cannot share a CNPG cluster, use dedicatedCluster:

- op: add
path: /spec/parameters/dedicatedCluster
value:
instances: 2
storageSize: 50Gi
postgresVersion: 16
enablePooler: true

Database Reclaim Policy

databaseReclaimPolicy controls what happens to the Postgres database object when the XTenantDatabase XR is deleted. Default is Retain — the composition keeps the database alive even after the XR is gone. This prevents accidental data loss. Set to Delete only for ephemeral test environments.

Never set databaseReclaimPolicy: Delete in staging or production

The portal does not expose this field in the UI. Edit the base YAML directly only if you need it for a short-lived environment.

Vault Secrets

Vault integration works through External Secrets Operator rather than direct Vault API calls. The scaffold generates ExternalSecret CRs that pull secrets from Vault and materialise them as K8s Secrets on the spoke cluster. The portal writes to Vault but never reads or deletes secrets.

App Secrets

Enable vaultSecrets in the scaffold wizard. The ExternalSecret targets:

Vault path: {team}/{appName}/env
K8s Secret: {appName}-env

The XTenantApp mounts this secret when secretsFrom.app.enabled: true:

spec:
parameters:
secretsFrom:
app:
enabled: true

Populate {team}/{appName}/env in Vault with any key/value pairs your app reads as environment variables. The ExternalSecret syncs on a 1-minute interval.

Database Credentials

Enable databaseSecrets in the scaffold wizard. The ExternalSecret targets:

Vault path: {team}/databases/{appName}-db/connection-creds
K8s Secret: {appName}-db-creds

The XTenantApp mounts this secret when secretsFrom.database.enabled: true:

spec:
parameters:
secretsFrom:
database:
enabled: true
# secretName defaults to {appName}-db-creds; set explicitly if different

The XTenantDatabase composition writes the connection string into this Vault path after provisioning the database. No manual Vault writes needed.

Vault Path Conventions

Secret typeVault pathK8s Secret name
App env vars{team}/{appName}/env{appName}-env
DB credentials{team}/databases/{appName}-db/connection-creds{appName}-db-creds
Custom DB name{team}/databases/{dbName}/connection-creds{dbName}-creds
Write-only model

The portal can write secrets to Vault (during scaffold and config updates) but never reads them back and never deletes them. This is a security constraint — secrets flow into the cluster via ExternalSecret, not through the portal UI.

Feature Reference

Quick reference for what belongs where:

FeatureScaffold wizardPromotion panel
Container port✓ base
Env vars (plain)✓ base
Pod annotations✓ base
Liveness / readiness probe✓ base
Ingress enabled✓ base
TLS / cert-manager✓ base
SSO auth✓ base
Rollout strategy✓ base
Secret reloader✓ base
Prometheus monitoring✓ base
VaultSecrets / DatabaseSecrets✓ base
DB extensions✓ base
Replicas✓ overlay patch
CPU / memory resources✓ overlay patch
Ingress hostname✓ overlay patch
TLS ClusterIssuer✓ overlay patch
DB name, tier, environment✓ overlay patch
DB clusterRef✓ overlay patch
Darlane debug pod✓ overlay patch