Repository: kubernetes-sigs/kro

Issue:
Implement SimpleSchema minimum and maximum support
### Feature Description

Add support for `minimum` and `maximum` [schema properties](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.32/#jsonschemaprops-v1-apiextensions-k8s-io) to SimpleSchema.

**Additional Context**: the `minimum` and `maximum` schema properties are useful in limiting ranges for numbers, e.g. non-negative or within a semantically valid range.

Example schema that fails today:
```yaml
replicas: integer | minimum=0
cpuTarget: number | minimum=0 maximum=1
```

* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue
* If you are interested in working on this feature, please leave a comment


Discussion:
@MunishMummadi: Hey @fsommar,

I would like to work on this issue. Can you assign it to me?

Based on my understanding, I will:
- Update `markers.go` with min and max markers + parsing logic.
- Update `field.go` with the struct related to min and max.
- Adding validation to `transform.go` for generating the JSON schema.@a-hilaly: Looks like this was fixed by @HeeManSu in #348, closing@MunishMummadi: Noted!!

Solution patch:
diff --git a/README.md b/README.md
index 952435d..903031d 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,13 @@
 # kro | Kube Resource Orchestrator
 
+
+[![Go Report Card](https://goreportcard.com/badge/github.com/kro-run/kro)](https://goreportcard.com/report/github.com/kro-run/kro)
+[![unit tests](https://github.com/kro-run/kro/actions/workflows/unit-tests.yaml/badge.svg)](https://github.com/kro-run/kro/actions/workflows/unit-tests.yaml)
+![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/kro-run/Kro)
+![GitHub License](https://img.shields.io/github/license/kro-run/kro)
+[![Build and Publish](https://github.com/kro-run/kro/actions/workflows/build-push-image.yaml/badge.svg?branch=main)](https://github.com/kro-run/kro/actions/workflows/build-push-image.yaml)
+![GitHub Repo stars](https://img.shields.io/github/stars/kro-run/kro)
+
 This project aims to simplify the creation and management of complex custom resources for Kubernetes.
 
 Kube Resource Orchestrator (**kro**) helps you to define complex multi-resource constructs as reusable components in your applications and systems. It does this by providing a Kubernetes-native, vendor agnostic way to define groupings of Kubernetes resources. 
diff --git a/examples/apigateway/vpc-lattice/README.md b/examples/apigateway/vpc-lattice/README.md
new file mode 100644
index 0000000..32883e4
--- /dev/null
+++ b/examples/apigateway/vpc-lattice/README.md
@@ -0,0 +1,170 @@
+# KRO VPC Lattice Demo
+
+This example demonstrates how to use KRO (Kubernetes Resource Orchestrator) to deploy and manage Amazon VPC Lattice resources on an Amazon EKS cluster, providing a streamlined approach to service networking in Kubernetes.
+
+## Overview
+
+Amazon VPC Lattice is a fully managed application networking service that enables you to connect, secure, and monitor all your services across multiple accounts and virtual private clouds (VPCs). This demo shows how to:
+
+1. Use KRO to define reusable resource graphs for VPC Lattice integration
+2. Implement Kubernetes Gateway API with the AWS Gateway Controller
+3. Deploy applications with simplified networking configuration
+4. Connect Kubernetes services to the VPC Lattice service network
+
+![Architecture Diagram](images/draw.png)
+
+
+## Prerequisites
+
+- Amazon EKS cluster
+- AWS CLI configured with appropriate permissions
+- kubectl installed and configured
+- Helm v3
+- jq
+
+## Installation
+
+### 1. Install KRO
+
+KRO (Kubernetes Resource Orchestrator) provides a way to define, deploy and manage complex Kubernetes resources as reusable templates.
+
+```bash
+export KRO_VERSION=$(curl -sL \
+    https://api.github.com/repos/kro-run/kro/releases/latest | \
+    jq -r '.tag_name | ltrimstr("v")'
+  )
+helm install kro oci://ghcr.io/kro-run/kro/kro \
+  --namespace kro \
+  --create-namespace \
+  --version=${KRO_VERSION}
+```
+
+### 2. Install Kubernetes Gateway API and AWS Gateway API Controller
+
+This step installs the Kubernetes Gateway API CRDs and the AWS Gateway API Controller for Amazon VPC Lattice integration.
+
+First, configure the necessary security group rules to allow VPC Lattice to communicate with your EKS cluster:
+
+```bash
+# Set environment variables
+export AWS_REGION=<your-aws-region>
+export EKS_CLUSTER_NAME=<your-eks-cluster-name>
+export LATTICE_IAM_ROLE=<your-lattice-iam-role-arn>
+
+# Configure security group rules
+CLUSTER_SG=$(aws eks describe-cluster --name $EKS_CLUSTER_NAME --output json| jq -r '.cluster.resourcesVpcConfig.clusterSecurityGroupId')
+PREFIX_LIST_ID=$(aws ec2 describe-managed-prefix-lists --query "PrefixLists[?PrefixListName=='com.amazonaws.$AWS_REGION.vpc-lattice'].PrefixListId" | jq -r '.[]')
+aws ec2 authorize-security-group-ingress --group-id $CLUSTER_SG --ip-permissions "PrefixListIds=[{PrefixListId=${PREFIX_LIST_ID}}],IpProtocol=-1"
+PREFIX_LIST_ID_IPV6=$(aws ec2 describe-managed-prefix-lists --query "PrefixLists[?PrefixListName=='com.amazonaws.$AWS_REGION.ipv6.vpc-lattice'].PrefixListId" | jq -r '.[]')
+aws ec2 authorize-security-group-ingress --group-id $CLUSTER_SG --ip-permissions "PrefixListIds=[{PrefixListId=${PREFIX_LIST_ID_IPV6}}],IpProtocol=-1"
+```
+
+Next, install the Kubernetes Gateway API and AWS Gateway Controller:
+
+```bash
+# Install Kubernetes Gateway API CRDs
+kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml
+
+# Log in to AWS ECR public registry
+aws ecr-public get-login-password --region us-east-1 \
+  | helm registry login --username AWS --password-stdin public.ecr.aws
+
+# Get latest controller version
+LATTICE_CONTROLLER_VERSION=$(curl -sL \
+    https://api.github.com/repos/aws/aws-application-networking-k8s/releases/latest | \
+    jq -r '.tag_name | ltrimstr("v")'
+  )
+
+# Install AWS Gateway Controller
+helm install gateway-api-controller \
+    oci://public.ecr.aws/aws-application-networking-k8s/aws-gateway-controller-chart \
+    --version=v${LATTICE_CONTROLLER_VERSION} \
+    --create-namespace \
+    --set=aws.region=${AWS_REGION} \
+    --set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"="$LATTICE_IAM_ROLE" \
+    --set=defaultServiceNetwork=kro-vpc-lattice-demo \
+    --namespace gateway-api-controller \
+    --wait
+```
+
+### Deploy gatewayClass and gateway resources 
+```
+kubectl apply -f resources/gatewayclass.yaml
+kubectl apply -f resources/gateway.yaml
+```
+
+
+## Resource Graph Definitions
+
+### 3. Deploy the Lattice Resource Graph Definition
+
+Create a Lattice Resource Graph Definition that maps VPC Lattice components to Kubernetes resources:
+
+```bash
+kubectl apply -f rg-lattice.yaml
+```
+
+The `rg-lattice.yaml` defines how to translate a simple schema into VPC Lattice-related Kubernetes Gateway API resources, including TargetGroupPolicy, and HTTPRoute.
+
+### 4. Deploy the WebApp Resource Graph Definition
+
+Create a WebApp Resource Graph Definition to simplify application deployment:
+
+```bash
+kubectl apply -f rg-webapp.yaml
+```
+
+The `rg-webapp.yaml` defines a template for deploying a web application with a Kubernetes Deployment and Service.
+
+### 5. Deploy the WebService Resource Graph Definition
+
+Create a WebService Resource Graph Definition that combines the WebApp and Lattice resources:
+
+```bash
+kubectl apply -f rg-webservice.yaml
+```
+
+The `rg-webservice.yaml` combines the WebApp and Lattice resource graphs, allowing you to deploy a web service with optional VPC Lattice integration.
+
+## Deploying Your Application
+
+### 6. Deploy Your Application Instance
+
+Create an instance of the WebService with VPC Lattice integration enabled:
+
+```bash
+kubectl apply -f instance.yaml
+```
+
+## Architecture
+
+This project implements a three-layer architecture:
+
+1. **Base Resources Layer**: Core Kubernetes resources (TargetGroupPolicy, HTTPRoute, Deployment, Service)
+2. **Resource Graph Layer**: Reusable templates (Lattice, WebApp, WebService) that abstract the base resources
+3. **Instance Layer**: Application-specific instances created from the resource graphs
+
+## Accessing Your Service
+
+Once deployed, your service will be accessible through the VPC Lattice service network. You can find the VPC Lattice endpoint using the AWS Console or the following AWS CLI command:
+
+```bash
+aws vpc-lattice list-service-networks
+aws vpc-lattice list-services --service-network-identifier kro-vpc-lattice-demo
+```
+
+## Benefits of This Approach
+
+- **Simplified Configuration**: Reduce complexity by abstracting away the detailed configuration of VPC Lattice resources
+- **Reusable Templates**: Create standardized deployment patterns that can be reused across multiple applications
+- **Declarative Approach**: Define the desired state of your infrastructure and application components
+- **Improved Developer Experience**: Allow developers to deploy applications with VPC Lattice integration without deep networking knowledge
+
+## Troubleshooting
+
+- Ensure your EKS cluster has the required IAM permissions for VPC Lattice integration
+- Verify the security group rules are correctly configured to allow VPC Lattice traffic
+- Check the Gateway API Controller logs for any errors:
+  ```bash
+  kubectl logs -n gateway-api-controller -l app.kubernetes.io/name=gateway-api-controller
+  ```
diff --git a/examples/apigateway/vpc-lattice/images/draw.png b/examples/apigateway/vpc-lattice/images/draw.png
new file mode 100644
index 0000000..de908e4
Binary files /dev/null and b/examples/apigateway/vpc-lattice/images/draw.png differ
diff --git a/examples/apigateway/vpc-lattice/instance.yaml b/examples/apigateway/vpc-lattice/instance.yaml
new file mode 100644
index 0000000..e0d3dfe
--- /dev/null
+++ b/examples/apigateway/vpc-lattice/instance.yaml
@@ -0,0 +1,10 @@
+apiVersion: kro.run/v1alpha1
+kind: WebService
+metadata:
+  name: test-app
+spec:
+  name: test-app
+  image: nginx
+  service: {}
+  vpclattice:
+    enabled: true
diff --git a/examples/apigateway/vpc-lattice/resources/gateway.yaml b/examples/apigateway/vpc-lattice/resources/gateway.yaml
new file mode 100644
index 0000000..e8f85b8
--- /dev/null
+++ b/examples/apigateway/vpc-lattice/resources/gateway.yaml
@@ -0,0 +1,14 @@
+apiVersion: gateway.networking.k8s.io/v1
+kind: Gateway
+metadata:
+  name: kro-vpc-lattice-demo
+  namespace: default
+spec:
+  gatewayClassName: amazon-vpc-lattice
+  listeners:
+  - allowedRoutes:
+      namespaces:
+        from: Same
+    name: http
+    port: 80
+    protocol: HTTP
\ No newline at end of file
diff --git a/examples/apigateway/vpc-lattice/resources/gatewayclass.yaml b/examples/apigateway/vpc-lattice/resources/gatewayclass.yaml
new file mode 100644
index 0000000..472474e
--- /dev/null
+++ b/examples/apigateway/vpc-lattice/resources/gatewayclass.yaml
@@ -0,0 +1,6 @@
+apiVersion: gateway.networking.k8s.io/v1
+kind: GatewayClass
+metadata:
+  name: amazon-vpc-lattice
+spec:
+  controllerName: application-networking.k8s.aws/gateway-api-controller
diff --git a/examples/apigateway/vpc-lattice/rg-lattice.yaml b/examples/apigateway/vpc-lattice/rg-lattice.yaml
new file mode 100644
index 0000000..26cb63e
--- /dev/null
+++ b/examples/apigateway/vpc-lattice/rg-lattice.yaml
@@ -0,0 +1,60 @@
+apiVersion: kro.run/v1alpha1
+kind: ResourceGraphDefinition
+metadata:
+  name: lattice.kro.run
+spec:
+  schema:
+    apiVersion: v1alpha1
+    kind: Lattice
+    spec:
+      name: string
+      namespace: string | default=default
+      port: integer | default=80
+      vpcLatticeName: string | default="kro-vpc-lattice-demo"
+      listenerProtocol: string | default="HTTP"
+
+  resources:
+  - id: targetgrouppolicy
+    template:
+      apiVersion: application-networking.k8s.aws/v1alpha1
+      kind: TargetGroupPolicy
+      metadata:
+        name: ${schema.spec.vpcLatticeName}
+        namespace: ${schema.spec.namespace}
+      spec:
+        targetRef:
+          group: ""
+          kind: Service
+          name: ${schema.spec.name}
+        protocol: ${schema.spec.listenerProtocol}
+        protocolVersion: HTTP1
+        healthCheck:
+          enabled: true
+          intervalSeconds: 10
+          timeoutSeconds: 1
+          healthyThresholdCount: 3
+          unhealthyThresholdCount: 2
+          path: "/"
+          port: ${schema.spec.port}
+          protocol: HTTP
+          protocolVersion: HTTP1
+          statusMatch: "200"
+
+  - id: httproute
+    template:
+      apiVersion: gateway.networking.k8s.io/v1beta1
+      kind: HTTPRoute
+      metadata:
+        name: ${schema.spec.name}
+        namespace: ${schema.spec.namespace}
+      spec:
+        parentRefs:
+          - name: ${schema.spec.vpcLatticeName}
+            sectionName: http
+        rules:
+          - backendRefs:
+              - name: ${schema.spec.name}
+                namespace: ${schema.spec.namespace}
+                kind: Service
+                port: ${schema.spec.port}
+                weight: 100
diff --git a/examples/apigateway/vpc-lattice/rg-webapp.yaml b/examples/apigateway/vpc-lattice/rg-webapp.yaml
new file mode 100644
index 0000000..b741f0a
--- /dev/null
+++ b/examples/apigateway/vpc-lattice/rg-webapp.yaml
@@ -0,0 +1,78 @@
+apiVersion: kro.run/v1alpha1
+kind: ResourceGraphDefinition
+metadata:
+  name: webapp.kro.run
+spec:
+  schema:
+    apiVersion: v1alpha1
+    kind: WebApp
+    spec:
+      name: string
+      namespace: string | default=default
+      image: string | default=nginx
+      port: integer | default=80
+      replicas: integer | default=3
+      service:
+        enabled: boolean | default=true
+      serviceAccount: string | default=default
+    status:
+      deploymentConditions: ${deployment.status.conditions}
+      availableReplicas: ${deployment.status.availableReplicas}
+
+  resources:
+  - id: deployment
+    readyWhen:
+      - ${deployment.spec.replicas == deployment.status.availableReplicas}
+    template:
+      apiVersion: apps/v1
+      kind: Deployment
+      metadata:
+        name: ${schema.spec.name}
+        namespace: ${schema.spec.namespace}
+        labels:
+          app.kubernetes.io/name: ${schema.spec.name}
+      spec:
+        replicas: ${schema.spec.replicas}
+        selector:
+          matchLabels:
+            app.kubernetes.io/name: ${schema.spec.name}
+            app: ${schema.spec.name}
+        template:
+          metadata:
+            labels:
+              app.kubernetes.io/name: ${schema.spec.name}
+              app: ${schema.spec.name}
+          spec:
+            serviceAccountName: ${schema.spec.serviceAccount}
+            containers:
+            - name: ${schema.spec.name}
+              image: ${schema.spec.image}
+              imagePullPolicy: Always
+              ports:
+              - containerPort: ${schema.spec.port}
+              resources:
+                requests:
+                  memory: "64Mi"
+                  cpu: "250m"
+                limits:
+                  memory: "1Gi"
+                  cpu: "1"
+            restartPolicy: Always
+
+  - id: service
+    includeWhen:
+    - ${schema.spec.service.enabled}  
+    template:
+      apiVersion: v1
+      kind: Service
+      metadata:
+        name: ${deployment.metadata.name}
+        namespace: ${deployment.metadata.namespace}
+      spec:
+        selector:
+          app: ${schema.spec.name}
+        ports:
+        - name: http
+          protocol: TCP
+          port: ${schema.spec.port}
+          targetPort: ${schema.spec.port}
diff --git a/examples/apigateway/vpc-lattice/rg-webservice.yaml b/examples/apigateway/vpc-lattice/rg-webservice.yaml
new file mode 100644
index 0000000..ccf1355
--- /dev/null
+++ b/examples/apigateway/vpc-lattice/rg-webservice.yaml
@@ -0,0 +1,59 @@
+apiVersion: kro.run/v1alpha1
+kind: ResourceGraphDefinition
+metadata:
+  name: webservice.kro.run
+spec:
+  schema:
+    apiVersion: v1alpha1
+    kind: WebService
+    spec:
+      name: string
+      namespace: string | default=default
+      image: string | default=nginx
+      port: integer | default=80
+      replicas: integer | default=3
+      service:
+        enabled: boolean | default=true
+      serviceAccount: string | default=default
+      vpclattice:
+        enabled: boolean | default=false
+      vpcLatticeName: string | default="kro-vpc-lattice-demo"
+      gatewayClassName: string | default=amazon-vpc-lattice
+      listenerProtocol: string | default="HTTP"
+
+
+  resources:
+  - id: webapp
+    template:
+      apiVersion: kro.run/v1alpha1
+      kind: WebApp
+      metadata:
+        name: ${schema.spec.name}
+        namespace: ${schema.spec.namespace}
+        labels:
+          app.kubernetes.io/name: ${schema.spec.name}
+      spec:
+        name: ${schema.spec.name}
+        namespace: ${schema.spec.namespace}
+        image: ${schema.spec.image}
+        port: ${schema.spec.port}
+        replicas: ${schema.spec.replicas}
+        service:
+          enabled: ${schema.spec.service.enabled}
+        serviceAccount: ${schema.spec.serviceAccount}
+
+  - id: lattice
+    includeWhen:
+    - ${schema.spec.vpclattice.enabled}
+    template:
+      apiVersion: kro.run/v1alpha1
+      kind: Lattice
+      metadata:
+        name: ${schema.spec.name}
+      spec:
+        name: ${schema.spec.name}
+        namespace: ${schema.spec.namespace}
+        port: ${schema.spec.port}
+        vpcLatticeName: ${schema.spec.vpcLatticeName}
+        listenerProtocol: ${schema.spec.listenerProtocol}
+        gatewayClassName: ${schema.spec.gatewayClassName}
diff --git a/examples/aws/llm/llm.yaml b/examples/aws/llm/llm.yaml
index 31eff03..0b5a2d4 100644
--- a/examples/aws/llm/llm.yaml
+++ b/examples/aws/llm/llm.yaml
@@ -45,7 +45,6 @@ spec:
       kind: StorageClass
       metadata:
         name: ${schema.spec.name}-storage-class
-        namespace: ${schema.spec.namespace}
         annotations:
           storageclass.kubernetes.io/is-default-class: "true"
       parameters:
diff --git a/pkg/graph/parser/parser.go b/pkg/graph/parser/parser.go
index 6e4a9ef..6c4f7e4 100644
--- a/pkg/graph/parser/parser.go
+++ b/pkg/graph/parser/parser.go
@@ -68,59 +68,94 @@ func parseResource(resource interface{}, schema *spec.Schema, path string) ([]va
 }
 
 func getExpectedTypes(schema *spec.Schema) ([]string, error) {
-	// Handle "x-kubernetes-preserve-unknown-fields" extension first
-	if hasStructuralSchemaMarkerEnabled(schema, xKubernetesPreserveUnknownFields) {
+	// Handle extensions (like x-kubernetes-int-or-string)
+	if types, found := handleSchemaExtensions(schema); found {
+		return types, nil
+	}
+
+	// Handle composite schemas (like OneOf, AnyOf)
+	if types, found := handleCompositeSchemas(schema); found {
+		return types, nil
+	}
+
+	// Handle direct type definitions
+	if len(schema.Type) > 0 && schema.Type[0] != "" {
+		return schema.Type, nil
+	}
+
+	// Handle additional properties
+	if schema.AdditionalProperties != nil && schema.AdditionalProperties.Allows {
+		// NOTE(a-hilaly): I don't like the type "any", we might want to change this to "object"
+		// in the future; just haven't really thought about it yet.
+		// Basically "any" means that the field can be of any type, and we have to check
+		// the ExpectedSchema field.
 		return []string{schemaTypeAny}, nil
 	}
 
+	return nil, fmt.Errorf("unknown schema type")
+}
+
+// handleSchemaExtensions processes Kubernetes-specific schema extensions
+// and returns appropriate types if extensions are present.
+func handleSchemaExtensions(schema *spec.Schema) ([]string, bool) {
+	// Handle "x-kubernetes-preserve-unknown-fields" extension
+	if hasStructuralSchemaMarkerEnabled(schema, xKubernetesPreserveUnknownFields) {
+		return []string{schemaTypeAny}, true
+	}
+
 	// Handle "x-kubernetes-int-or-string" extension
 	if hasStructuralSchemaMarkerEnabled(schema, xKubernetesIntOrString) {
-		return []string{"string", "integer"}, nil
+		return []string{"string", "integer"}, true
 	}
 
+	return nil, false
+}
+
+// handleCompositeSchemas processes OneOf and AnyOf schemas
+// and returns collected types if present.
+func handleCompositeSchemas(schema *spec.Schema) ([]string, bool) {
 	// Handle OneOf schemas
 	if len(schema.OneOf) > 0 {
-		var types []string
-
-		for _, subSchema := range schema.OneOf {
-			// If there are structural constraints, inject object
-			if len(subSchema.Required) > 0 || subSchema.Not != nil {
-				if !slices.Contains(types, "object") {
-					types = append(types, "object")
-				}
-			}
-			// Collect types if present
-			if len(subSchema.Type) > 0 {
-				types = append(types, subSchema.Type...)
-			}
-		}
-		// If we found any types, return them
+		types := collectTypesFromSubSchemas(schema.OneOf)
 		if len(types) > 0 {
-			return types, nil
+			return types, true
 		}
 	}
 
 	// Handle AnyOf schemas
 	if len(schema.AnyOf) > 0 {
-		var types []string
-		for _, subType := range schema.AnyOf {
-			types = append(types, subType.Type...)
+		types := collectTypesFromSubSchemas(schema.AnyOf)
+		if len(types) > 0 {
+			return types, true
 		}
-		return types, nil
 	}
 
-	if len(schema.Type) > 0 && schema.Type[0] != "" {
-		return schema.Type, nil
-	}
+	return nil, false
+}
 
-	if schema.AdditionalProperties != nil && schema.AdditionalProperties.Allows {
-		// NOTE(a-hilaly): I don't like the type "any", we might want to change this to "object"
-		// in the future; just haven't really thought about it yet.
-		// Basically "any" means that the field can be of any type, and we have to check
-		// the ExpectedSchema field.
-		return []string{schemaTypeAny}, nil
+// collectTypesFromSubSchemas extracts types from a slice of schemas,
+// handling structural constraints like Required and Not.
+func collectTypesFromSubSchemas(subSchemas []spec.Schema) []string {
+	var types []string
+
+	for _, subSchema := range subSchemas {
+		// If there are structural constraints, inject object type
+		if len(subSchema.Required) > 0 || subSchema.Not != nil {
+			if !slices.Contains(types, "object") {
+				types = append(types, "object")
+			}
+		}
+		// Collect types if present
+		if len(subSchema.Type) > 0 {
+			for _, t := range subSchema.Type {
+				if t != "" && !slices.Contains(types, t) {
+					types = append(types, t)
+				}
+			}
+		}
 	}
-	return nil, fmt.Errorf("unknown schema type")
+
+	return types
 }
 
 func validateSchema(schema *spec.Schema, path string) error {
diff --git a/pkg/simpleschema/markers.go b/pkg/simpleschema/markers.go
index 9eaf3dd..d422b48 100644
--- a/pkg/simpleschema/markers.go
+++ b/pkg/simpleschema/markers.go
@@ -46,11 +46,16 @@ const (
 	MarkerTypeDefault MarkerType = "default"
 	// MarkerTypeDescription represents the `description` marker.
 	MarkerTypeDescription MarkerType = "description"
+	// MarkerTypeMinimum represents the `minimum` marker.
+	MarkerTypeMinimum MarkerType = "minimum"
+	// MarkerTypeMaximum represents the `maximum` marker.
+	MarkerTypeMaximum MarkerType = "maximum"
 )
 
 func markerTypeFromString(s string) (MarkerType, error) {
 	switch MarkerType(s) {
-	case MarkerTypeRequired, MarkerTypeDefault, MarkerTypeDescription:
+	case MarkerTypeRequired, MarkerTypeDefault, MarkerTypeDescription,
+		MarkerTypeMinimum, MarkerTypeMaximum:
 		return MarkerType(s), nil
 	default:
 		return "", fmt.Errorf("unknown marker type: %s", s)
diff --git a/pkg/simpleschema/transform.go b/pkg/simpleschema/transform.go
index df12c58..7218e76 100644
--- a/pkg/simpleschema/transform.go
+++ b/pkg/simpleschema/transform.go
@@ -15,6 +15,7 @@ package simpleschema
 
 import (
 	"fmt"
+	"strconv"
 
 	extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 )
@@ -203,6 +204,14 @@ func (tf *transformer) applyMarkers(schema *extv1.JSONSchemaProps, markers []*Ma
 			schema.Default = &extv1.JSON{Raw: defaultValue}
 		case MarkerTypeDescription:
 			schema.Description = marker.Value
+		case MarkerTypeMinimum:
+			if val, err := strconv.ParseFloat(marker.Value, 64); err == nil {
+				schema.Minimum = &val
+			}
+		case MarkerTypeMaximum:
+			if val, err := strconv.ParseFloat(marker.Value, 64); err == nil {
+				schema.Maximum = &val
+			}
 		}
 	}
 }



Test patch:
diff --git a/pkg/graph/parser/parser_test.go b/pkg/graph/parser/parser_test.go
index a02615f..bcceb08 100644
--- a/pkg/graph/parser/parser_test.go
+++ b/pkg/graph/parser/parser_test.go
@@ -1495,3 +1495,83 @@ func TestPreserveUnknownFields(t *testing.T) {
 		})
 	}
 }
+
+func TestCollectTypesFromSubSchemas(t *testing.T) {
+	testCases := []struct {
+		name       string
+		subSchemas []spec.Schema
+		wantTypes  []string
+	}{
+		{
+			name: "simple types without constraints",
+			subSchemas: []spec.Schema{
+				{SchemaProps: spec.SchemaProps{Type: []string{"string"}}},
+				{SchemaProps: spec.SchemaProps{Type: []string{"integer"}}},
+			},
+			wantTypes: []string{"string", "integer"},
+		},
+		{
+			name: "with Required constraint",
+			subSchemas: []spec.Schema{
+				{SchemaProps: spec.SchemaProps{
+					Type:     []string{"string"},
+					Required: []string{"field"},
+				}},
+			},
+			wantTypes: []string{"object", "string"},
+		},
+		{
+			name: "with Not constraint",
+			subSchemas: []spec.Schema{
+				{SchemaProps: spec.SchemaProps{
+					Type: []string{"string"},
+					Not: &spec.Schema{
+						SchemaProps: spec.SchemaProps{Type: []string{"integer"}},
+					},
+				}},
+			},
+			wantTypes: []string{"object", "string"},
+		},
+		{
+			name: "with both Required and Not constraints",
+			subSchemas: []spec.Schema{
+				{SchemaProps: spec.SchemaProps{
+					Type:     []string{"string"},
+					Required: []string{"field"},
+					Not: &spec.Schema{
+						SchemaProps: spec.SchemaProps{Type: []string{"integer"}},
+					},
+				}},
+			},
+			wantTypes: []string{"object", "string"},
+		},
+		{
+			name: "duplicate types",
+			subSchemas: []spec.Schema{
+				{SchemaProps: spec.SchemaProps{Type: []string{"string"}}},
+				{SchemaProps: spec.SchemaProps{Type: []string{"string"}}},
+				{SchemaProps: spec.SchemaProps{
+					Type:     []string{"string"},
+					Required: []string{"field"},
+				}},
+			},
+			wantTypes: []string{"object", "string"},
+		},
+		{
+			name: "empty type",
+			subSchemas: []spec.Schema{
+				{SchemaProps: spec.SchemaProps{Type: []string{""}}},
+			},
+			wantTypes: []string{},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			gotTypes := collectTypesFromSubSchemas(tc.subSchemas)
+			if !areEqualSlices(gotTypes, tc.wantTypes) {
+				t.Errorf("collectTypesFromSubSchemas() = %v, want %v", gotTypes, tc.wantTypes)
+			}
+		})
+	}
+}
diff --git a/pkg/simpleschema/field_test.go b/pkg/simpleschema/field_test.go
index a8f8984..33840a5 100644
--- a/pkg/simpleschema/field_test.go
+++ b/pkg/simpleschema/field_test.go
@@ -51,6 +51,26 @@ func TestParseFieldSchema(t *testing.T) {
 			wantMarkers: nil,
 			wantErr:     true,
 		},
+		{
+			name:        "integer field with min and max",
+			fieldSchema: "integer | minimum=0 maximum=100",
+			wantType:    "integer",
+			wantMarkers: []*Marker{
+				{MarkerType: MarkerTypeMinimum, Key: "minimum", Value: "0"},
+				{MarkerType: MarkerTypeMaximum, Key: "maximum", Value: "100"},
+			},
+			wantErr: false,
+		},
+		{
+			name:        "number field with decimal constraints",
+			fieldSchema: "float | minimum=0.1 maximum=1.0",
+			wantType:    "float",
+			wantMarkers: []*Marker{
+				{MarkerType: MarkerTypeMinimum, Key: "minimum", Value: "0.1"},
+				{MarkerType: MarkerTypeMaximum, Key: "maximum", Value: "1.0"},
+			},
+			wantErr: false,
+		},
 	}
 
 	for _, tt := range tests {
diff --git a/pkg/simpleschema/markers_test.go b/pkg/simpleschema/markers_test.go
index cacf57f..0b63d26 100644
--- a/pkg/simpleschema/markers_test.go
+++ b/pkg/simpleschema/markers_test.go
@@ -86,6 +86,24 @@ func TestParseMarkers(t *testing.T) {
 			},
 			wantErr: false,
 		},
+		{
+			name:  "minimum and maximum markers",
+			input: "minimum=0 maximum=100",
+			want: []*Marker{
+				{MarkerType: MarkerTypeMinimum, Key: "minimum", Value: "0"},
+				{MarkerType: MarkerTypeMaximum, Key: "maximum", Value: "100"},
+			},
+			wantErr: false,
+		},
+		{
+			name:  "decimal minimum and maximum",
+			input: "minimum=0.1 maximum=1.5",
+			want: []*Marker{
+				{MarkerType: MarkerTypeMinimum, Key: "minimum", Value: "0.1"},
+				{MarkerType: MarkerTypeMaximum, Key: "maximum", Value: "1.5"},
+			},
+			wantErr: false,
+		},
 		{
 			name:  "Markers with spaces in values",
 			input: "description=\"This has spaces\" default=5 required=true",