diff --git a/.cursor/rules/helm.mdc b/.cursor/rules/helm.mdc
new file mode 100644
index 0000000..6afce27
--- /dev/null
+++ b/.cursor/rules/helm.mdc
@@ -0,0 +1,95 @@
+---
+description: 
+globs: 
+alwaysApply: false
+---
+In this project, Helm charts will typically be found in a `/charts/$chart-name` subdirectory.
+
+# Helm Chart Best Practices
+
+This document contains best practices for creating Helm charts, based on the official Helm documentation at https://helm.sh/docs/chart_best_practices/.
+
+## General Conventions
+
+- Chart names should use lowercase letters, numbers, and dashes (no uppercase or underscores)
+- Chart names should be descriptive without being too long
+- Version numbers should follow SemVer 2 standard
+- Reuse official base images for your charts where possible
+- Document all chart dependencies
+- Keep chart simple and focused on one application per chart
+- Ensure your chart properly handles upgrades and rollbacks
+
+## Values
+
+- Use camelCase for key names in values.yaml
+- Document all values using comments in values.yaml
+- Define sensible defaults that work out-of-the-box
+- Use appropriate data types (string, int, boolean, etc.)
+- Structure values hierarchically when appropriate
+- Mark sensitive values with comments
+- Use a flat structure for values that represent environment variables
+
+## Templates
+
+- Clearly structure template files in the templates/ directory
+- Use the include function instead of template for reusable template blocks
+- Add helpful NOTES.txt for users after installation
+- Template functions should use lowercase (e.g., quote not Quote)
+- Whitespace formatting: use YAML's indent feature (|-) for readability
+- Use standard Kubernetes naming conventions in templates
+- Templates should emit valid YAML
+- Validate templates with `helm lint` and `helm template`
+
+## Dependencies
+
+- Use the requirements.yaml file to manage dependencies
+- Pin versions of dependencies to specific ranges
+- Document what your dependencies provide and how they're used
+- Set appropriate global values that dependencies can access
+- Minimize external dependencies when possible
+- Use conditions to enable/disable dependencies where appropriate
+
+## Labels and Annotations
+
+- Include Helm-recommended labels:
+  - app.kubernetes.io/name
+  - app.kubernetes.io/instance
+  - app.kubernetes.io/version
+  - app.kubernetes.io/managed-by
+  - helm.sh/chart
+- Use namespaces with your custom labels to avoid collisions
+- Keep annotations focused on tools that will use them
+- Don't use annotations when labels are more appropriate
+- Follow Kubernetes label syntax constraints
+
+## Pods and PodTemplates
+
+- Set appropriate container resources (requests and limits)
+- Create useful liveness and readiness probes
+- Set security context settings appropriately
+- Use init containers correctly if needed
+- Define suitable update strategies
+- Set appropriate termination periods
+- Handle persistent volumes properly
+
+## Custom Resource Definitions (CRDs)
+
+- Place CRDs in the crds/ directory (not templates/)
+- Document clearly which CRDs your chart requires
+- Label your CRDs appropriately
+- Consider separation of CRD installation and application installation
+- Handle CRD updates carefully (they aren't automatically updated)
+
+## Role-Based Access Control (RBAC)
+
+- Follow principle of least privilege
+- Create dedicated ServiceAccounts for your applications
+- Create specific Roles rather than using ClusterRoles when possible
+- Document all permissions required
+- Use templating to allow users to add custom rules
+- Set clear namespace restrictions where possible
+
+## References
+
+- [Helm Chart Best Practices](mdc:https:/helm.sh/docs/chart_best_practices)
+- [Helm Documentation](mdc:https:/helm.sh/docs)
\ No newline at end of file
diff --git a/.cursor/rules/kots.mdc b/.cursor/rules/kots.mdc
new file mode 100644
index 0000000..fbc2914
--- /dev/null
+++ b/.cursor/rules/kots.mdc
@@ -0,0 +1,568 @@
+---
+description: 
+globs: 
+alwaysApply: false
+---
+# KOTS Development Guide
+
+This document contains information about KOTS template functions and custom resources for developing applications that integrate with the Replicated Platform.
+
+## KOTS Custom Resources
+
+KOTS uses custom resources to extend the Kubernetes API and provide additional functionality specific to application deployment, configuration, and lifecycle management within the Replicated Platform.
+
+### Application Custom Resource
+
+The Application custom resource (`application.yaml`) provides metadata about the application and is used to inform the Admin Console about your application and the relationship between your application and Admin Console.
+
+```yaml
+apiVersion: kots.io/v1beta1
+kind: Application
+metadata:
+  name: my-application
+spec:
+  title: My Application
+  icon: https://my-application.com/icon.png
+  releaseNotes: |
+    New features in this release
+  targetKotsVersion: "1.60.0"
+  minKotsVersion: "1.40.0"
+  requireMinimalRBACPrivileges: true
+  ports:
+    - serviceName: web
+      servicePort: 8000
+      localPort: 8888
+      applicationUrl: "http://web.example.com"
+  statusInformers:
+    - deployment/my-application
+    - deployment/my-database
+  graphs:
+    - title: "CPU Usage"
+      query: 'sum(rate(container_cpu_usage_seconds_total{namespace="{{repl Namespace}}", container="my-app"}[5m]))'
+```
+
+Key fields:
+- `title`: The application name displayed in the Admin Console
+- `icon`: A URI to the application icon
+- `releaseNotes`: Release notes for this version
+- `targetKotsVersion`/`minKotsVersion`: KOTS version compatibility
+- `statusInformers`: List of resources to monitor for application status
+- `ports`: Port forwarding configuration
+- `graphs`: Prometheus queries for displaying metrics
+- `allowRollback`: Enable/disable rollback feature
+- `requireMinimalRBACPrivileges`: Use minimal RBAC privileges
+
+### Config Custom Resource
+
+The Config custom resource (`config.yaml`) defines the configuration options displayed in the Admin Console, allowing you to collect information needed to deploy your application.
+
+```yaml
+apiVersion: kots.io/v1beta1
+kind: Config
+metadata:
+  name: my-application-config
+spec:
+  groups:
+    - name: database
+      title: Database Configuration
+      description: Configuration for the application database
+      items:
+        - name: db_type
+          title: Database Type
+          type: select_one
+          default: embedded
+          items:
+            - name: embedded
+              title: Embedded Database
+            - name: external
+              title: External Database
+        - name: db_host
+          title: Database Host
+          type: text
+          when: repl{{ ConfigOptionEquals "db_type" "external" }}
+        - name: db_password
+          title: Database Password
+          type: password
+          when: repl{{ ConfigOptionEquals "db_type" "external" }}
+```
+
+Key fields:
+- `groups`: List of configuration groups
+  - `name`: Internal name of the group
+  - `title`: Display name of the group
+  - `description`: Explanation of the group's purpose
+  - `items`: Configuration items within the group
+    - `name`: Internal name of the configuration item
+    - `title`: Display name of the item
+    - `type`: Type of UI element (text, password, bool, select_one, etc.)
+    - `default`: Default value
+    - `when`: Conditional visibility based on other configuration values
+    - `required`: Whether the field is required
+    - `items`: Options for select_one/select_many fields
+
+### HelmChart Custom Resource (v2)
+
+The HelmChart v2 custom resource provides a way to include Helm charts in your application. It is a more flexible and powerful version of the original HelmChart resource.
+
+```yaml
+apiVersion: kots.io/v1beta2
+kind: HelmChart
+metadata:
+  name: my-helm-chart
+spec:
+  chart:
+    name: nginx
+    chartVersion: 9.5.1
+    releaseName: my-release
+    helmVersion: v3
+    values:
+      image:
+        registry: repl{{ HasLocalRegistry | ternary LocalRegistryHost "docker.io" }}
+        repository: repl{{ HasLocalRegistry | ternary (printf "%s/nginx" LocalRegistryNamespace) "nginx" }}
+        tag: 1.19.3
+      service:
+        type: repl{{ ConfigOption "service_type" }}
+      resources:
+        limits:
+          memory: repl{{ ConfigOption "memory_limit" }}
+  optionalValues:
+    - when: 'repl{{ ConfigOptionEquals "use_ingress" "1" }}'
+      values:
+        ingress:
+          enabled: true
+          hosts:
+            - host: repl{{ ConfigOption "hostname" }}
+```
+
+Key fields:
+- `chart`: Chart specification
+  - `name`: Name of the chart
+  - `chartVersion`: Version of the chart to use
+  - `releaseName`: Name of the Helm release
+  - `helmVersion`: Version of Helm to use (v2 or v3)
+- `values`: Values to pass to the Helm chart
+- `optionalValues`: Conditional values based on configuration
+  - `when`: Condition for applying the values
+  - `values`: Values to apply when the condition is true
+  - `recursiveMerge`: Whether to recursively merge with base values
+
+### HelmChart Custom Resource (v1)
+
+The original HelmChart custom resource that is now deprecated in favor of v2. It has a simpler structure but less flexibility.
+
+```yaml
+apiVersion: kots.io/v1beta1
+kind: HelmChart
+metadata:
+  name: my-helm-chart
+spec:
+  name: nginx
+  chartVersion: 9.5.1
+  releaseName: my-release
+  helmVersion: v3
+  weight: 2
+  values:
+    service:
+      type: repl{{ ConfigOption "service_type" }}
+```
+
+Key fields:
+- `name`: Name of the chart
+- `chartVersion`: Version of the chart to use
+- `releaseName`: Name of the Helm release
+- `helmVersion`: Version of Helm to use (v2 or v3)
+- `weight`: Order in which charts are processed
+- `values`: Values to pass to the Helm chart
+- `exclude`: Optional field to exclude the chart under certain conditions
+
+### LintConfig Custom Resource
+
+The LintConfig custom resource defines linting rules that can be used to validate an application installation or identify potential issues.
+
+```yaml
+apiVersion: troubleshoot.sh/v1beta2
+kind: LintConfig
+metadata:
+  name: my-app-lintconfig
+spec:
+  lintRules:
+    - podCrashLoopBackOff:
+        checkName: pod-crash-loop-back-off
+        exclude: 
+          - repl{{ ConfigOption "excluded_pod" }}
+        namespace:
+          - repl{{ Namespace }}
+        outcomes:
+          - pass:
+              message: No pods are crash looping
+          - fail:
+              message: One or more pods are crash looping
+    - deploymentStatus:
+        checkName: deployment-status
+        namespace:
+          - repl{{ Namespace }}
+        outcomes:
+          - pass:
+              message: All deployments are ready
+          - fail:
+              message: Some deployments are not ready
+```
+
+Key fields:
+- `lintRules`: List of linting rules to apply
+  - Each rule has a type (e.g., `podCrashLoopBackOff`, `deploymentStatus`)
+  - `checkName`: Name of the check
+  - `exclude`: Resources to exclude from checking
+  - `namespace`: Namespaces to check
+  - `outcomes`: Possible outcomes of the check
+    - `pass`: Conditions and message for a passing check
+    - `fail`: Conditions and message for a failing check
+    - `warn`: Conditions and message for a warning
+
+### Installer Custom Resource
+
+The Installer custom resource defines requirements and instructions for installing an application in a cluster.
+
+```yaml
+apiVersion: kots.io/v1beta1
+kind: Installer
+metadata:
+  name: my-application-installer
+spec:
+  kubernetes:
+    version: "1.23.0"
+  requireMinimalRBACPrivileges: true
+  serviceAccount:
+    create: true
+    name: ""
+```
+
+Key fields:
+- `kubernetes`: Kubernetes compatibility requirements
+  - `version`: Minimum Kubernetes version
+- `requireMinimalRBACPrivileges`: Use minimal RBAC privileges
+- `serviceAccount`: Service account configuration
+
+### Preflight Custom Resource
+
+The Preflight custom resource defines checks to run before installing an application to ensure the environment meets requirements.
+
+```yaml
+apiVersion: troubleshoot.sh/v1beta2
+kind: Preflight
+metadata:
+  name: my-application-preflight
+spec:
+  analyzers:
+    - clusterVersion:
+        outcomes:
+          - fail:
+              when: "< 1.19.0"
+              message: Kubernetes version must be at least 1.19.0
+          - pass:
+              message: Kubernetes version is compatible
+    - nodeResources:
+        checkName: Node Resources
+        outcomes:
+          - fail:
+              when: "count() < 3"
+              message: At least 3 nodes are required
+          - warn:
+              when: "count() < 5"
+              message: At least 5 nodes are recommended
+          - pass:
+              message: Node count is sufficient
+```
+
+Key fields:
+- `analyzers`: List of analyzers to run
+  - Each analyzer has a type (e.g., `clusterVersion`, `nodeResources`)
+  - `checkName`: Name of the check
+  - `outcomes`: Possible outcomes of the analyzer
+    - `pass`: Conditions and message for a passing check
+    - `fail`: Conditions and message for a failing check
+    - `warn`: Conditions and message for a warning
+
+
+## KOTS Template Functions
+
+KOTS template functions allow you to render dynamic values in your Kubernetes manifests and Replicated custom resources. They are based on the Go text/template library and support all functionality of the Go templating language, including if statements, loops, and variables.
+
+### Template Function Syntax
+
+KOTS supports two syntax options for template functions:
+
+1. The recommended `repl{{ ... }}` syntax:
+   ```yaml
+   apiVersion: apps/v1
+   kind: Deployment
+   metadata:
+     name: example
+     labels:
+       app: repl{{ ConfigOption "app_name" }}
+   ```
+
+2. The legacy `{{repl ... }}` syntax:
+   ```yaml
+   apiVersion: apps/v1
+   kind: Deployment
+   metadata:
+     name: example
+     labels:
+       app: '{{repl ConfigOption "app_name" }}'
+   ```
+
+### Common Template Contexts
+
+KOTS provides several contexts that expose different sets of template functions:
+
+#### Config Context
+Functions to access user-supplied configuration values:
+- `ConfigOption(optionName)` - Returns the value of the specified configuration option
+- `ConfigOptionExists(optionName)` - Returns true if the option exists
+- `ConfigOptionEquals(optionName, value)` - Returns true if the option equals the specified value
+
+#### License Context
+Functions to access the customer license information:
+- `LicenseFieldValue(fieldName)` - Returns the value of a license field
+- `LicenseFieldExists(fieldName)` - Returns true if the license field exists
+- `LicenseProperty(propertyName)` - Returns the value of a license property
+- `LicenseDocker()` - Returns Docker Hub registry credentials if configured for the customer
+
+#### Static Context
+Functions for generating and manipulating data:
+- `Namespace()` - Returns the current namespace
+- `RandomString(length)` - Generates a random string
+- `LocalRegistryImagePullSecret()` - Returns the image pull secret for the local registry
+- `TLSCert(caData, certData, keyData, commonName)` - Generates a TLS certificate
+- `Now()` - Returns the current timestamp
+
+#### Identity Context
+Functions for identity service integration:
+- `IdentityServiceEnabled()` - Returns true if the identity service is enabled
+- `IdentityServiceClientID()` - Returns the client ID for the identity service
+- `IdentityServiceClientSecret()` - Returns the client secret for the identity service
+
+#### kURL Context
+Functions for kURL cluster information:
+- `IsKurl()` - Returns true if running in a kURL cluster
+- `KurlNodeJoinToken()` - Returns the kURL node join token
+- `KurlControlPlaneAddress()` - Returns the kURL control plane address
+
+### Common Use Cases and Examples
+
+#### Boolean Comparison
+```yaml
+when: repl{{ and (LicenseFieldValue "feature-1" | ParseBool) (ConfigOptionEquals "radio_example" "option_one")}}
+```
+
+#### Integer Comparison
+```yaml
+when: repl{{ gt (atoi (LicenseFieldValue "numSeats")) 1000 }}
+```
+
+#### String Comparison
+```yaml
+when: repl{{ eq (LicenseFieldValue "customerType") "enterprise" }}
+```
+
+#### Conditional Statements (If-Else)
+```yaml
+repl{{ if eq (ConfigOption "database_type") "embedded" }}
+  embedded: true
+repl{{ else }}
+  external: true
+repl{{ end }}
+```
+
+#### Ternary Operators
+```yaml
+registry: repl{{ HasLocalRegistry | ternary LocalRegistryHost "proxy.replicated.com" }}
+```
+
+#### Indentation in YAML
+```yaml
+annotations: repl{{ ConfigOption "additional_annotations" | nindent 4 }}
+```
+
+#### Generating TLS Certificates
+```yaml
+repl{{ $ca := genCA (ConfigOption "hostname") 365 }}
+repl{{ $cert := genSignedCert (ConfigOption "hostname") (list ) (list (ConfigOption "hostname")) 365 $ca }}
+```
+
+## KOTS Custom Resources
+
+KOTS uses custom resources to manage application deployment and configuration. Here's an overview of the key custom resources:
+
+### Application Custom Resource
+The Application custom resource provides metadata about the application.
+
+```yaml
+apiVersion: kots.io/v1beta1
+kind: Application
+metadata:
+  name: my-application
+spec:
+  title: My Application
+  icon: https://my-application.com/icon.png
+  releaseNotes: |
+    New features in this release
+  targetKotsVersion: "1.60.0"
+  minKotsVersion: "1.40.0"
+  requireMinimalRBACPrivileges: true
+  ports:
+    - serviceName: web
+      servicePort: 8000
+      localPort: 8888
+      applicationUrl: "http://web.example.com"
+  statusInformers:
+    - deployment/my-application
+    - deployment/my-database
+  graphs:
+    - title: "CPU Usage"
+      query: 'sum(rate(container_cpu_usage_seconds_total{namespace="{{repl Namespace}}", container="my-app"}[5m]))'
+```
+
+### Config Custom Resource
+The Config custom resource defines the configuration options displayed in the Admin Console.
+
+```yaml
+apiVersion: kots.io/v1beta1
+kind: Config
+metadata:
+  name: my-application-config
+spec:
+  groups:
+    - name: database
+      title: Database Configuration
+      description: Configuration for the application database
+      items:
+        - name: db_type
+          title: Database Type
+          type: select_one
+          default: embedded
+          items:
+            - name: embedded
+              title: Embedded Database
+            - name: external
+              title: External Database
+        - name: db_host
+          title: Database Host
+          type: text
+          when: repl{{ ConfigOptionEquals "db_type" "external" }}
+        - name: db_password
+          title: Database Password
+          type: password
+          when: repl{{ ConfigOptionEquals "db_type" "external" }}
+```
+
+### HelmChart Custom Resource (v2)
+The HelmChart custom resource v2 defines a Helm chart to be included in the application.
+
+```yaml
+apiVersion: kots.io/v1beta2
+kind: HelmChart
+metadata:
+  name: my-helm-chart
+spec:
+  chart:
+    name: nginx
+    chartVersion: 9.5.1
+    releaseName: my-release
+    helmVersion: v3
+    values:
+      image:
+        registry: repl{{ HasLocalRegistry | ternary LocalRegistryHost "docker.io" }}
+        repository: repl{{ HasLocalRegistry | ternary (printf "%s/nginx" LocalRegistryNamespace) "nginx" }}
+        tag: 1.19.3
+      service:
+        type: repl{{ ConfigOption "service_type" }}
+      resources:
+        limits:
+          memory: repl{{ ConfigOption "memory_limit" }}
+```
+
+### HelmChart Custom Resource (v1)
+The older version of the HelmChart custom resource.
+
+```yaml
+apiVersion: kots.io/v1beta1
+kind: HelmChart
+metadata:
+  name: my-helm-chart
+spec:
+  name: nginx
+  chartVersion: 9.5.1
+  releaseName: my-release
+  helmVersion: v3
+  weight: 2
+  values:
+    service:
+      type: repl{{ ConfigOption "service_type" }}
+```
+
+### LintConfig Custom Resource
+The LintConfig custom resource defines linting rules for the application.
+
+```yaml
+apiVersion: troubleshoot.sh/v1beta2
+kind: LintConfig
+metadata:
+  name: my-app-lintconfig
+spec:
+  lintRules:
+    - podCrashLoopBackOff:
+        checkName: pod-crash-loop-back-off
+        exclude: 
+          - repl{{ ConfigOption "excluded_pod" }}
+        namespace:
+          - repl{{ Namespace }}
+        outcomes:
+          - pass:
+              message: No pods are crash looping
+          - fail:
+              message: One or more pods are crash looping
+    - deploymentStatus:
+        checkName: deployment-status
+        namespace:
+          - repl{{ Namespace }}
+        outcomes:
+          - pass:
+              message: All deployments are ready
+          - fail:
+              message: Some deployments are not ready
+```
+
+## Best Practices
+
+1. **Template Function Validation**:
+   - Use the `helm template` and `kubectl kots render` commands to validate your templates
+   - Test with different license and configuration values
+
+2. **Error Handling**:
+   - Provide default values for template functions that might not return a value
+   - Use conditional logic to handle missing values
+
+3. **Performance**:
+   - Avoid complex template logic that could slow down rendering
+   - Use variables to store values that are used multiple times
+
+4. **Security**:
+   - Never expose sensitive license information in logs or to end users
+   - Use appropriate types (password, etc.) for sensitive configuration items
+
+5. **Configuration Options**:
+   - Group related configuration options together
+   - Provide clear titles, help text, and default values
+   - Use conditional visibility (when) to simplify the configuration experience
+
+## References
+
+- [KOTS Template Functions Examples](mdc:https:/docs.replicated.com/reference/template-functions-examples)
+- [Custom Resource - About](mdc:https:/docs.replicated.com/reference/custom-resource-about)
+- [Custom Resource - Application](mdc:https:/docs.replicated.com/reference/custom-resource-application)
+- [Custom Resource - Config](mdc:https:/docs.replicated.com/reference/custom-resource-config)
+- [Custom Resource - HelmChart v2](mdc:https:/docs.replicated.com/reference/custom-resource-helmchart-v2)
+- [Custom Resource - HelmChart](mdc:https:/docs.replicated.com/reference/custom-resource-helmchart)
+- [Custom Resource - LintConfig](mdc:https:/docs.replicated.com/reference/custom-resource-lintconfig)
\ No newline at end of file
diff --git a/.cursor/rules/replicated.mdc b/.cursor/rules/replicated.mdc
new file mode 100644
index 0000000..e69de29
diff --git a/applications/storagebox/charts/storagebox/Chart.lock b/applications/storagebox/charts/storagebox/Chart.lock
index 366a369..b79f669 100644
--- a/applications/storagebox/charts/storagebox/Chart.lock
+++ b/applications/storagebox/charts/storagebox/Chart.lock
@@ -1,7 +1,7 @@
 dependencies:
 - name: replicated
   repository: oci://registry.replicated.com/library
-  version: 1.0.0
+  version: 1.2.0
 - name: cassandra
   repository: https://charts.bitnami.com/bitnami
   version: 11.4.2
@@ -11,5 +11,5 @@ dependencies:
 - name: tenant
   repository: https://operator.min.io
   version: 6.0.4
-digest: sha256:26170aecba211998f2bb167d1f5dd76728dde0e7578e24c0043d09908cde03fb
-generated: "2025-02-03T14:09:16.375235-05:00"
+digest: sha256:511c7cd4de6c5128afb80df73adf753910c49bc1aff8c05dcafe0e31f6cae2ca
+generated: "2025-03-18T11:42:22.774467-04:00"
diff --git a/applications/storagebox/charts/storagebox/Chart.yaml b/applications/storagebox/charts/storagebox/Chart.yaml
index c4fcbd8..023733a 100644
--- a/applications/storagebox/charts/storagebox/Chart.yaml
+++ b/applications/storagebox/charts/storagebox/Chart.yaml
@@ -2,11 +2,11 @@ apiVersion: v2
 name: storagebox
 description: A Helm chart for different storage options
 type: application
-version: 0.16.0
+version: 0.20.0
 appVersion: 1.0.0
 dependencies:
 - name: replicated
-  version: "~1.0.0"
+  version: "~1.2.0"
   repository: "oci://registry.replicated.com/library"
   condition: replicated.enabled
 - name: cassandra
diff --git a/applications/storagebox/charts/storagebox/values.yaml b/applications/storagebox/charts/storagebox/values.yaml
index d484544..4986788 100644
--- a/applications/storagebox/charts/storagebox/values.yaml
+++ b/applications/storagebox/charts/storagebox/values.yaml
@@ -1,6 +1,7 @@
 replicated:
   enabled: true
 nfs-server:
+  # nfs-server helm values are defined in a library chart: https://raw.githubusercontent.com/k8s-at-home/library-charts/refs/heads/main/charts/stable/common/values.yaml
   enabled: true
   securityContext:
     privileged: true
diff --git a/applications/storagebox/kots/backup.yaml b/applications/storagebox/kots/backup.yaml
index bc8c9bc..7637118 100644
--- a/applications/storagebox/kots/backup.yaml
+++ b/applications/storagebox/kots/backup.yaml
@@ -1,24 +1,39 @@
 apiVersion: velero.io/v1
 kind: Backup
 metadata:
-  name: backup
+  name: storagebox-backup
 spec:
   includedNamespaces:
-  - kotsadm
+  - "*"
+  includedResources:
+  - "*"
+  ### snapshotVolumes might not be supported by EC - I think this requires CSI plugin
+  snapshotVolumes: false
+  ttl: 48h0m0s
   includeClusterResources: true
   orLabelSelectors:
   - matchExpressions:
     # Exclude Replicated resources
     - { key: kots.io/kotsadm, operator: NotIn, values:  ["true"] }
-
-
-#
-# apiVersion: velero.io/v1
-# kind: Backup
-# metadata:
-#   name: backup
-# spec:
-#   includedNamespaces:
-#   - chef-360
-#   includeClusterResources: true
-#
+  # hooks:
+  #     resources:
+  #       - name: postgres-backup
+  #         includedNamespaces:
+  #         - '*'
+  #         excludedNamespaces:
+  #         - some-namespace
+  #         includedResources:
+  #         - pods
+  #         excludedResources: []
+  #         labelSelector:
+  #           matchLabels:
+  #             app: velero
+  #             component: server
+  #         pre:
+  #           - exec:
+  #               container: my-container
+  #               command:
+  #                 - /bin/uname
+  #                 - -a
+  #               onError: Fail
+  #               timeout: 10s
diff --git a/applications/storagebox/kots/ec.yaml b/applications/storagebox/kots/ec.yaml
index 436a3a5..c9bf974 100644
--- a/applications/storagebox/kots/ec.yaml
+++ b/applications/storagebox/kots/ec.yaml
@@ -1,7 +1,7 @@
 apiVersion: embeddedcluster.replicated.com/v1beta1
 kind: Config
 spec:
-  version: 2.0.0+k8s-1.30
+  version: 2.2.0+k8s-1.30
   extensions:
     helm:
       repositories:
diff --git a/applications/storagebox/kots/kots-app.yaml b/applications/storagebox/kots/kots-app.yaml
index f406bc2..a657e83 100644
--- a/applications/storagebox/kots/kots-app.yaml
+++ b/applications/storagebox/kots/kots-app.yaml
@@ -5,7 +5,10 @@ metadata:
 spec:
   title: StorageBox
   allowRollback: false
+  additionalNamespaces:
+    - "*"
   statusInformers:
     - deployment/kotsadm
-    - statefulset/kotsadm-rqlite
-    - statefulset/storagebox-cassandra
+    - repl{{ if ConfigOptionEquals "enable_cassandra" "1" }}statefulset/storagebox-cassandra repl{{ else }}repl{{ end }}
+    - repl{{ if ConfigOptionEquals "enable_postgres" "1" }}clusters.postgresql.cnpg.io/postgres repl{{ else }}repl{{ end }}
+    - repl{{ if ConfigOptionEquals "enable_minio" "1" }}deployment/storagebox-minio repl{{ else }}repl{{ end }}
diff --git a/applications/storagebox/kots/kots-config.yaml b/applications/storagebox/kots/kots-config.yaml
index 7ea8dbc..79941ad 100644
--- a/applications/storagebox/kots/kots-config.yaml
+++ b/applications/storagebox/kots/kots-config.yaml
@@ -48,6 +48,8 @@ spec:
     - name: cassandra_tls_type
       title: Cassandra TLS Type
       type: select_one
+      default: "cassandra_no_ssl"
+      required: true
       items:
       - name: cassandra_no_ssl
         title: TLS client encryption disabled
@@ -55,8 +57,6 @@ spec:
         title: Autogenerate self-signed CA and certificates
       - name: "cassandra_external_ca"
         title: Use external CA and certificates
-      default: "cassandra_no_ssl"
-      required: true
     - name: cassandra_ingress_host
       title: Cassandra TLS Hostname
       type: text
diff --git a/applications/storagebox/kots/restore.yaml b/applications/storagebox/kots/restore.yaml
new file mode 100644
index 0000000..0e1cf69
--- /dev/null
+++ b/applications/storagebox/kots/restore.yaml
@@ -0,0 +1,72 @@
+apiVersion: velero.io/v1
+kind: Restore
+metadata:
+  name: storagebox-restore
+  namespace: velero
+spec:
+  backupName: storagebox-backup
+  includedNamespaces:
+    - '*'  # Include all namespaces to restore the complete application
+
+  # Restore all resources except storage classes which may already exist
+  includedResources:
+    - '*'
+  orLabelSelectors:
+  - matchExpressions:
+    # Exclude Replicated resources
+    - { key: kots.io/kotsadm, operator: NotIn, values:  ["true"] }
+  # Restore PVs from snapshots
+  restorePVs: true
+
+  # Preserve the original node ports for services
+  preserveNodePorts: true
+
+  # Handle existing resources
+  existingResourcePolicy: none
+
+  # Include cluster-scoped resources
+  includeClusterResources: true
+
+  # # Configure restore hooks for stateful components
+  # hooks:
+  #   resources:
+  #   # Cassandra restore hook
+  #   - name: cassandra-restore-hook
+  #     includedResources:
+  #       - pods
+  #     labelSelector:
+  #       matchLabels:
+  #         app.kubernetes.io/name: cassandra
+  #     postHooks:
+  #       - exec:
+  #           container: cassandra
+  #           command:
+  #             - /bin/sh
+  #             - -c
+  #             - "nodetool refresh"
+  #           waitTimeout: 5m
+  #           execTimeout: 2m
+  #           onError: Continue
+
+  #   # PostgreSQL restore hook
+  #   - name: postgres-restore-hook
+  #     includedResources:
+  #       - pods
+  #     labelSelector:
+  #       matchLabels:
+  #         app.kubernetes.io/name: postgres
+  #     postHooks:
+  #       - exec:
+  #           container: postgres
+  #           command:
+  #             - /bin/sh
+  #             - -c
+  #             - "pg_isready"
+  #           waitTimeout: 5m
+  #           execTimeout: 1m
+  #           onError: Continue
+
+  # Configure parallel file downloads for faster restore
+  uploaderConfig:
+    parallelFilesDownload: 10
+    writeSparseFiles: true
diff --git a/applications/storagebox/kots/storagebox-chart.yaml b/applications/storagebox/kots/storagebox-chart.yaml
index 3d56c08..9a78e46 100644
--- a/applications/storagebox/kots/storagebox-chart.yaml
+++ b/applications/storagebox/kots/storagebox-chart.yaml
@@ -5,22 +5,45 @@ metadata:
 spec:
   chart:
     name: storagebox
-    chartVersion: 0.16.0
+    chartVersion: 0.20.0
   values:
     replicated:
       enabled: true
     nfs-server:
       enabled: repl{{ ConfigOptionEquals "nfs_enabled" "1" }}
+      imagePullSecrets:
+        - name: repl{{ ImagePullSecretName }}
+      defaultPodOptions:
+        imagePullSecrets:
+          - name: repl{{ ImagePullSecretName }}
+      image:
+        repository: repl{{ HasLocalRegistry | ternary LocalRegistryHost "proxy.xyyzx.net/storagebox/ghcr.io" }}/{{repl HasLocalRegistry | ternary LocalRegistryNamespace "obeone" }}/nfs-server
+        pullPolicy: IfNotPresent
+      global:
+        fullnameOverride: nfs-server
+      controller:
+        annotations:
+          backup.velero.io/backup-volumes: storagebox-nfs-server-shared
       persistence:
         shared:
           enabled: true
-          type: emptyDir
+          type: pvc
+          readOnly: false
+          accessMode: ReadWriteOnce
+          storageClass: ""
+          size: repl{{ ConfigOption "nfs_storage_size" | default "10Gi" }}
+          retain: true
           mountPath: repl{{ ConfigOption "nfs_share" }}
       env:
         NFS_EXPORT_0: repl{{ ConfigOption "nfs_share" }} repl{{ ConfigOption "nfs_share_options" }}
         NFS_LOG_LEVEL: debug
     cassandra:
       enabled: repl{{ ConfigOptionEquals "cassandra_enabled" "1" }}
+      image:
+        registry: repl{{ HasLocalRegistry | ternary LocalRegistryHost "proxy.xyyzx.net/storagebox/docker.io" }}
+        repository: repl{{ HasLocalRegistry | ternary LocalRegistryNamespace "bitnami" }}/cassandra
+        pullSecrets:
+          - name: repl{{ ImagePullSecretName }}
       truststore_password : repl{{ ConfigOption "cassandra_truststore_password" }}
       keystore_password : repl{{ ConfigOption "cassandra_keystore_password" }}
       dbUser:
@@ -53,13 +76,11 @@ spec:
       tenant:
         name: repl{{ ConfigOption "minio_tenant_name" }}
         image:
-          repository: repl{{ HasLocalRegistry | ternary LocalRegistryHost "quay.io" }}/minio/minio
-          tag: RELEASE.2024-08-17T01-24-54Z
+          repository: repl{{ HasLocalRegistry | ternary LocalRegistryHost "proxy.xyyzx.net/storagebox/quay.io" }}/{{repl HasLocalRegistry | ternary LocalRegistryNamespace "minio" }}/minio
           pullPolicy: IfNotPresent
-        imagePullSecret: { }
+        imagePullSecret:
+          - name: repl{{ ImagePullSecretName }}
         scheduler: { }
-        # configuration:
-        #   name: repl{{ ConfigOption "minio_tenant_configuration_name" }}
         certificate:
           requestAutoCert: true
         configSecret:
@@ -97,7 +118,13 @@ spec:
             tolerations: [ ]
             nodeSelector: { }
             affinity: { }
-            resources: { }
+            resources:
+              limits:
+                cpu: "2000m"
+                memory: "4Gi"
+              requests:
+                cpu: "1000m"
+                memory: "2Gi"
             securityContext:
               runAsUser: 1000
               runAsGroup: 1000
@@ -118,28 +145,13 @@ spec:
           enabled: repl{{ ConfigOptionEquals "minio_tenant_metrics_enabled" "1" }}
           port: repl{{ ConfigOption "minio_tenant_metrics_port" }}
           protocol: repl{{ ConfigOption "minio_tenant_metrics_protocol" }}
-        ###
-        # Array of objects describing one or more buckets to create during tenant provisioning.
-        # Example:
-        #
-        # .. code-block:: yaml
-        #
-        #    - name: my-minio-bucket
-        #         objectLock: false        # optional
-        #         region: us-east-1        # optional
         buckets:
           - name: repl{{ ConfigOption "minio_tenant_bucket_name" }}
             objectLock: repl{{ ConfigOptionEquals "minio_tenant_bucket_object_lock" "1" }}
             region: repl{{ ConfigOption "minio_tenant_bucket_region" }}
-        # Array of Kubernetes secrets from which the Operator generates MinIO users during tenant provisioning.
-        #
-        # Each secret should specify the ``CONSOLE_ACCESS_KEY`` and ``CONSOLE_SECRET_KEY`` as the access key and secret key for that user.
-        # users:
-        #   - '{{repl ConfigOption "minio_tenant_user_name"}}'
-        # secrets:
-        #   name: repl{{ ConfigOption "minio_tenant_user_name" }}
-        #   accessKey: repl{{ ConfigOption "minio_tenant_user_access_key" }}
-        #   secretKey: repl{{ ConfigOption "minio_tenant_user_secret_key" }}
+        users:
+          - name: repl{{ ConfigOption "minio_tenant_user_name" | default "minio-user" }}
+            secretName: repl{{ ConfigOption "minio_tenant_user_secret" | default "minio-user-secret" }}
 
   optionalValues:
     - when: 'repl{{ ConfigOptionEquals "cassandra_tls_type" "cassandra_no_ssl" }}'