Repository: neuro-inc/app-types
Pull request #83: MLO-212: Change input types and improved schema rendering
Author: login: taddeusb90
Created: 2025-04-25T07:41:23Z | Merged: 2025-04-30T12:37:47Z


## MLFLOW
![Screenshot 2025-04-29 at 12 09 06](https://github.com/user-attachments/assets/3f6fa453-6860-4fe2-8607-39eda1b9a006)
![Screenshot 2025-04-29 at 12 08 20](https://github.com/user-attachments/assets/a445c7a0-3902-4a5e-81bd-2d4dcf7399bf)
![Screenshot 2025-04-29 at 12 07 25](https://github.com/user-attachments/assets/0c55b751-8e48-48ac-905b-3d12bb7e5d01)

## WEAVIATE

![Screenshot 2025-04-29 at 20 05 19](https://github.com/user-attachments/assets/527adc91-b208-4abf-b98c-5f4a965ed43e)
![Screenshot 2025-04-29 at 20 04 26](https://github.com/user-attachments/assets/505e1c28-4514-4f47-afb0-4a17794741c4)
![Screenshot 2025-04-29 at 20 04 15](https://github.com/user-attachments/assets/d0903c95-6e5a-4b51-8429-9852aa300636)



Diff:
diff --git a/src/apolo_app_types/helm/apps/common.py b/src/apolo_app_types/helm/apps/common.py
index 5e18999f..904b50c7 100644
--- a/src/apolo_app_types/helm/apps/common.py
+++ b/src/apolo_app_types/helm/apps/common.py
@@ -10,10 +10,14 @@
 import yaml
 from apolo_sdk import Preset
 
-from apolo_app_types.helm.apps.ingress import get_ingress_values
+from apolo_app_types.helm.apps.ingress import (
+    get_grpc_ingress_values,
+    get_http_ingress_values,
+)
 from apolo_app_types.protocols.common import (
     ApoloFilesMount,
-    Ingress,
+    IngressGrpc,
+    IngressHttp,
     Preset as PresetType,
 )
 from apolo_app_types.protocols.common.k8s import Port
@@ -252,7 +256,8 @@ def append_apolo_storage_integration_annotations(
 async def gen_extra_values(
     apolo_client: apolo_sdk.Client,
     preset_type: PresetType,
-    ingress: Ingress | None = None,
+    ingress_http: IngressHttp | None = None,
+    ingress_grpc: IngressGrpc | None = None,
     namespace: str | None = None,
     port_configurations: list[Port] | None = None,
 ) -> dict[str, t.Any]:
@@ -266,13 +271,35 @@ async def gen_extra_values(
     affinity_vals = preset_to_affinity(preset)
     resources_vals = preset_to_resources(preset)
     ingress_vals: dict[str, t.Any] = {}
-    if ingress:
+    http_ingress_conf: dict[str, t.Any] | None = None
+    grpc_ingress_conf: dict[str, t.Any] | None = None
+
+    if ingress_http or ingress_grpc:
         if not namespace:
             exception_msg = "Namespace is required when ingress is provided."
             raise ValueError(exception_msg)
-        ingress_vals = await get_ingress_values(
-            apolo_client, ingress, namespace, port_configurations
-        )
+        if ingress_http:
+            http_ingress_conf = await get_http_ingress_values(
+                apolo_client, ingress_http, namespace, port_configurations
+            )
+        if ingress_grpc:
+            grpc_ingress_conf = await get_grpc_ingress_values(
+                apolo_client, ingress_grpc, namespace, port_configurations
+            )
+
+    # Construct the final ingress values dictionary
+    if http_ingress_conf or grpc_ingress_conf:
+        ingress_vals["ingress"] = {
+            "enabled": True,  # Enable if either HTTP or gRPC is configured
+            **(http_ingress_conf or {}),  # Spread HTTP config if exists
+            "grpc": (
+                grpc_ingress_conf or {"enabled": False}
+            ),  # Add gRPC config under 'grpc' key
+        }
+        # Ensure annotations dict exists at the top level if http added it,
+        # otherwise initialize if only grpc is present.
+        if "annotations" not in ingress_vals["ingress"] and grpc_ingress_conf:
+            ingress_vals["ingress"]["annotations"] = {}
 
     return {
         "preset_name": preset_name,
diff --git a/src/apolo_app_types/helm/apps/custom_deployment.py b/src/apolo_app_types/helm/apps/custom_deployment.py
index dfb03d00..fdb9c654 100644
--- a/src/apolo_app_types/helm/apps/custom_deployment.py
+++ b/src/apolo_app_types/helm/apps/custom_deployment.py
@@ -62,7 +62,8 @@ async def gen_extra_values(
             apolo_client=self.client,
             preset_type=input_.preset,
             namespace=namespace,
-            ingress=input_.networking.ingress,
+            ingress_http=input_.networking.ingress_http,
+            ingress_grpc=None,
             port_configurations=input_.networking.ports,
         )
         image_docker_url = await get_image_docker_url(
diff --git a/src/apolo_app_types/helm/apps/fooocus.py b/src/apolo_app_types/helm/apps/fooocus.py
index e27462a5..9d424f80 100644
--- a/src/apolo_app_types/helm/apps/fooocus.py
+++ b/src/apolo_app_types/helm/apps/fooocus.py
@@ -95,7 +95,7 @@ async def gen_extra_values(
             container=Container(env=[Env(name=k, value=v) for k, v in env.items()]),
             networking=NetworkingConfig(
                 service_enabled=True,
-                ingress=input_.ingress,
+                ingress_http=input_.ingress_http,
                 ports=[
                     Port(name="http", port=7865),
                 ],
diff --git a/src/apolo_app_types/helm/apps/ingress.py b/src/apolo_app_types/helm/apps/ingress.py
index e8ac4070..31a742a7 100644
--- a/src/apolo_app_types/helm/apps/ingress.py
+++ b/src/apolo_app_types/helm/apps/ingress.py
@@ -4,7 +4,7 @@
 import apolo_sdk
 from yarl import URL
 
-from apolo_app_types.protocols.common import Ingress
+from apolo_app_types.protocols.common import IngressGrpc, IngressHttp
 from apolo_app_types.protocols.common.k8s import Port
 
 
@@ -81,35 +81,22 @@ async def _generate_ingress_config(
     }
 
 
-async def get_ingress_values(
+async def get_http_ingress_values(
     apolo_client: apolo_sdk.Client,
-    ingress: Ingress,
+    ingress_http: IngressHttp,
     namespace: str,
     port_configurations: list[Port] | None = None,
 ) -> dict[str, t.Any]:
+    http_ingress_config = await _generate_ingress_config(
+        apolo_client, namespace, port_configurations
+    )
     ingress_vals: dict[str, t.Any] = {
-        "ingress": {"grpc": {"enabled": False}, "annotations": {}}
+        "enabled": True,
+        **http_ingress_config,  # Merge the generated config directly
     }
-    if not ingress.enabled:
-        ingress_vals["ingress"]["enabled"] = False
-        return ingress_vals
-
-    res = await _generate_ingress_config(apolo_client, namespace, port_configurations)
-    ingress_vals["ingress"].update(res)
-    if ingress.grpc and ingress.grpc.enabled:
-        grpc_ingress_config = await _generate_ingress_config(
-            apolo_client, namespace, port_configurations, namespace_suffix="-grpc"
-        )
-        ingress_vals["ingress"]["grpc"] = {
-            "enabled": True,
-            "className": "traefik",
-            "hosts": grpc_ingress_config["hosts"],
-            "annotations": {
-                "traefik.ingress.kubernetes.io/router.entrypoints": "websecure",
-                "traefik.ingress.kubernetes.io/service.serversscheme": "h2c",
-            },
-        }
-    if ingress.http_auth:
+
+    # Handle auth based on its presence in the input object
+    if ingress_http.auth:
         forward_auth_name = "forwardauth"
         forward_auth_config = {
             "enabled": True,
@@ -117,9 +104,45 @@ async def get_ingress_values(
             "address": str(_get_forward_auth_address(apolo_client)),
             "trustForwardHeader": True,
         }
-        ingress_vals["ingress"]["forwardAuth"] = forward_auth_config
-        ingress_vals["ingress"]["annotations"][
+        ingress_vals["forwardAuth"] = forward_auth_config
+        ingress_vals.setdefault("annotations", {})  # Ensure annotations key exists
+        ingress_vals["annotations"][
             "traefik.ingress.kubernetes.io/router.middlewares"
         ] = f"{namespace}-{forward_auth_name}@kubernetescrd"
 
     return ingress_vals
+
+
+async def get_grpc_ingress_values(
+    apolo_client: apolo_sdk.Client,
+    ingress_grpc: IngressGrpc,
+    namespace: str,
+    port_configurations: list[Port] | None = None,
+) -> dict[str, t.Any]:
+    grpc_ingress_config = await _generate_ingress_config(
+        apolo_client, namespace, port_configurations, namespace_suffix="-grpc"
+    )
+    grpc_vals: dict[str, t.Any] = {
+        "enabled": True,
+        "className": "traefik",
+        "hosts": grpc_ingress_config["hosts"],
+        "annotations": {
+            "traefik.ingress.kubernetes.io/router.entrypoints": "websecure",
+            "traefik.ingress.kubernetes.io/service.serversscheme": "h2c",
+        },
+    }
+
+    if ingress_grpc.auth:
+        forward_auth_name = "forwardauth"
+        grpc_vals["auth"] = {
+            "enabled": True,
+            "name": forward_auth_name,
+            "address": str(_get_forward_auth_address(apolo_client)),
+            "trustForwardHeader": True,
+        }
+        grpc_vals.setdefault("annotations", {})  # Ensure annotations key exists
+        grpc_vals["annotations"]["traefik.ingress.kubernetes.io/router.middlewares"] = (
+            f"{namespace}-{forward_auth_name}@kubernetescrd"
+        )
+
+    return grpc_vals
diff --git a/src/apolo_app_types/helm/apps/jupyter.py b/src/apolo_app_types/helm/apps/jupyter.py
index 4f9a019e..70e5a0f5 100644
--- a/src/apolo_app_types/helm/apps/jupyter.py
+++ b/src/apolo_app_types/helm/apps/jupyter.py
@@ -11,7 +11,7 @@
     CustomDeploymentChartValueProcessor,
 )
 from apolo_app_types.protocols.common import Container, Env, StorageMounts
-from apolo_app_types.protocols.common.ingress import Ingress
+from apolo_app_types.protocols.common.ingress import IngressHttp
 from apolo_app_types.protocols.common.k8s import Port
 from apolo_app_types.protocols.custom_deployment import NetworkingConfig
 from apolo_app_types.protocols.jupyter import JupyterAppInputs, JupyterTypes
@@ -92,7 +92,7 @@ async def gen_extra_values(
             ),
             networking=NetworkingConfig(
                 service_enabled=True,
-                ingress=Ingress(enabled=True, http_auth=input_.networking.http_auth),
+                ingress_http=IngressHttp(auth=input_.networking.http_auth),
                 ports=[
                     Port(name="http", port=self._jupyter_port),
                 ],
diff --git a/src/apolo_app_types/helm/apps/llm.py b/src/apolo_app_types/helm/apps/llm.py
index 5eeb7dd5..8d18cc8a 100644
--- a/src/apolo_app_types/helm/apps/llm.py
+++ b/src/apolo_app_types/helm/apps/llm.py
@@ -142,7 +142,8 @@ async def gen_extra_values(
         values = await gen_extra_values(
             self.client,
             input_.preset,
-            input_.ingress,
+            input_.ingress_http,
+            None,
             namespace,
         )
         values["podAnnotations"] = self._configure_extra_annotations(input_)
diff --git a/src/apolo_app_types/helm/apps/mlflow.py b/src/apolo_app_types/helm/apps/mlflow.py
index 8b7ca744..fb2a5f39 100644
--- a/src/apolo_app_types/helm/apps/mlflow.py
+++ b/src/apolo_app_types/helm/apps/mlflow.py
@@ -60,7 +60,8 @@ async def gen_extra_values(
         base_vals = await gen_extra_values(
             apolo_client=self.client,
             preset_type=input_.preset,
-            ingress=input_.ingress,
+            ingress_http=input_.ingress_http,
+            ingress_grpc=None,
             namespace=namespace,
         )
 
@@ -84,20 +85,19 @@ async def gen_extra_values(
 
         artifact_mounts: StorageMounts | None = None
         artifact_env_val = None
-        if input_.artifact_store and input_.artifact_store.apolo_files:
+        if input_.artifact_store:
             artifact_env_val = "file:///mlflow-artifacts"
             envs.append(Env(name="MLFLOW_ARTIFACT_ROOT", value=artifact_env_val))
 
-            if input_.artifact_store.apolo_files:
-                artifact_mounts = StorageMounts(
-                    mounts=[
-                        ApoloFilesMount(
-                            storage_uri=input_.artifact_store.apolo_files,
-                            mount_path=MountPath(path="/mlflow-artifacts"),
-                            mode=ApoloMountMode(mode="rw"),
-                        )
-                    ]
-                )
+            artifact_mounts = StorageMounts(
+                mounts=[
+                    ApoloFilesMount(
+                        storage_uri=input_.artifact_store,
+                        mount_path=MountPath(path="/mlflow-artifacts"),
+                        mode=ApoloMountMode(mode="rw"),
+                    )
+                ]
+            )
 
         mlflow_cmd = ["mlflow"]
         mlflow_args = [
@@ -116,7 +116,6 @@ async def gen_extra_values(
                 repository="ghcr.io/apolo-actions/mlflow",
                 tag="v2.19.0",
             ),
-            ingress=input_.ingress,
             container=Container(
                 command=mlflow_cmd,
                 args=mlflow_args,
@@ -124,7 +123,7 @@ async def gen_extra_values(
             ),
             networking=NetworkingConfig(
                 service_enabled=True,
-                ingress=input_.ingress,
+                ingress_http=input_.ingress_http,
                 ports=[
                     Port(name="http", port=5000),
                 ],
diff --git a/src/apolo_app_types/helm/apps/privategpt.py b/src/apolo_app_types/helm/apps/privategpt.py
index 12ba6298..35105ab2 100644
--- a/src/apolo_app_types/helm/apps/privategpt.py
+++ b/src/apolo_app_types/helm/apps/privategpt.py
@@ -94,7 +94,7 @@ async def gen_extra_values(
             container=Container(env=[Env(name=k, value=v) for k, v in env.items()]),
             networking=NetworkingConfig(
                 service_enabled=True,
-                ingress=input_.ingress,
+                ingress_http=input_.ingress_http,
                 ports=[
                     Port(name="http", port=8080),
                 ],
diff --git a/src/apolo_app_types/helm/apps/stable_diffusion.py b/src/apolo_app_types/helm/apps/stable_diffusion.py
index be0046e8..952ea653 100644
--- a/src/apolo_app_types/helm/apps/stable_diffusion.py
+++ b/src/apolo_app_types/helm/apps/stable_diffusion.py
@@ -9,9 +9,6 @@
     get_component_values,
     get_preset,
 )
-from apolo_app_types.helm.apps.ingress import (
-    get_ingress_values,
-)
 from apolo_app_types.helm.utils.deep_merging import merge_list_of_dicts
 
 
@@ -49,17 +46,11 @@ async def gen_extra_values(
     ) -> dict[str, t.Any]:
         preset_name = input_.preset.name
         generic_vals = await gen_extra_values(
-            self.client, input_.preset, input_.ingress, namespace
+            self.client, input_.preset, input_.ingress_http, None, namespace
         )
 
         preset = get_preset(self.client, preset_name)
 
-        ingress_api = await get_ingress_values(
-            self.client,
-            input_.ingress,
-            namespace,
-        )
-
         component_vals = get_component_values(preset, preset_name)
         api_vars = self._get_env_vars(preset)
         img_repository = self._get_image_repository(preset)
@@ -75,7 +66,6 @@ async def gen_extra_values(
                 model_vals,
                 {
                     "api": {
-                        **ingress_api,
                         **component_vals,
                         "env": api_vars,
                         "image": {
diff --git a/src/apolo_app_types/helm/apps/text_embeddings.py b/src/apolo_app_types/helm/apps/text_embeddings.py
index f13eab34..c66edf39 100644
--- a/src/apolo_app_types/helm/apps/text_embeddings.py
+++ b/src/apolo_app_types/helm/apps/text_embeddings.py
@@ -39,7 +39,7 @@ async def gen_extra_values(
             image=input_.container_image,
             networking=NetworkingConfig(
                 service_enabled=True,
-                ingress=input_.ingress,
+                ingress_http=input_.ingress_http,
                 ports=[
                     Port(name="http", port=3000),
                 ],
diff --git a/src/apolo_app_types/helm/apps/weaviate.py b/src/apolo_app_types/helm/apps/weaviate.py
index 7f706171..6456d249 100644
--- a/src/apolo_app_types/helm/apps/weaviate.py
+++ b/src/apolo_app_types/helm/apps/weaviate.py
@@ -108,14 +108,20 @@ async def gen_extra_values(
 
         # Get base values
         values = await gen_extra_values(
-            self.client, input_.preset, input_.ingress, namespace
+            apolo_client=self.client,
+            preset_type=input_.preset,
+            ingress_http=input_.ingress_http,
+            ingress_grpc=input_.ingress_grpc,
+            namespace=namespace,
         )
 
-        # Add authentication values
-        if input_.cluster_api:
-            auth_vals = await self._get_auth_values(input_.cluster_api)
-        else:
-            auth_vals = {}
+        # TODO: temporarily removed cluster_api from WeaviateInputs and
+        # relying on ingress_http and ingress_grpc auth level.
+        # Will make it available again later.
+        # if input_.cluster_api:
+        #     auth_vals = await self._get_auth_values(input_.cluster_api)
+        # else:
+        #     auth_vals = {}
 
         # Configure backups if enabled
         if input_.backup_bucket:
@@ -127,7 +133,7 @@ async def gen_extra_values(
         return merge_list_of_dicts(
             [
                 values,
-                auth_vals,
+                # auth_vals,
                 {"storage": {"size": f"{input_.persistence.size}Gi"}},
             ]
         )
diff --git a/src/apolo_app_types/protocols/common/__init__.py b/src/apolo_app_types/protocols/common/__init__.py
index 42fd9387..570af1cd 100644
--- a/src/apolo_app_types/protocols/common/__init__.py
+++ b/src/apolo_app_types/protocols/common/__init__.py
@@ -11,7 +11,7 @@
 from .buckets import Bucket
 from .containers import ContainerImage
 from .hugging_face import HuggingFaceCache, HuggingFaceModel
-from .ingress import Ingress, IngressGrpc
+from .ingress import IngressGrpc, IngressHttp
 from .k8s import Container, DeploymentName, Env
 from .networking import GraphQLAPI, GrpcAPI, RestAPI
 from .openai_compat import OpenAICompatChatAPI, OpenAICompatEmbeddingsAPI
@@ -34,7 +34,7 @@
 __all__ = [
     "AppInputsDeployer",
     "AppOutputs",
-    "Ingress",
+    "IngressHttp",
     "IngressGrpc",
     "Postgres",
     "Redis",
diff --git a/src/apolo_app_types/protocols/common/ingress.py b/src/apolo_app_types/protocols/common/ingress.py
index 761666e1..6095d55a 100644
--- a/src/apolo_app_types/protocols/common/ingress.py
+++ b/src/apolo_app_types/protocols/common/ingress.py
@@ -1,50 +1,51 @@
 from pydantic import ConfigDict, Field
 
 from apolo_app_types.protocols.common.abc_ import AbstractAppFieldType
-from apolo_app_types.protocols.common.schema_extra import (
-    SchemaExtraMetadata,
-)
+from apolo_app_types.protocols.common.schema_extra import SchemaExtraMetadata
 
 
 class IngressGrpc(AbstractAppFieldType):
-    enabled: bool = Field(
-        ...,
+    model_config = ConfigDict(
+        protected_namespaces=(),
         json_schema_extra=SchemaExtraMetadata(
-            title="Enabled",
-            description="If GRPC is enabled.",
+            title="Enable gRPC Ingress",
+            description="Enable access to your service over the internet using gRPC.",
+        ).as_json_schema_extra(),
+    )
+    auth: bool = Field(
+        default=True,
+        description="Require credentials with "
+        "permissions to access this application"
+        " for all incoming gRPC requests.",
+        title="Enable Authentication and Authorization",
+        json_schema_extra=SchemaExtraMetadata(
+            title="Enable Authentication and Authorization",
+            description="Require credentials with "
+            "permissions to access this application"
+            " for all incoming gRPC requests.",
         ).as_json_schema_extra(),
     )
 
 
-class Ingress(AbstractAppFieldType):
+class IngressHttp(AbstractAppFieldType):
     model_config = ConfigDict(
         protected_namespaces=(),
         json_schema_extra=SchemaExtraMetadata(
-            title="Public HTTP Ingress",
+            title="Enable HTTP Ingress",
             description="Enable access to your "
             "application over the internet using HTTPS.",
         ).as_json_schema_extra(),
     )
-    http_auth: bool = Field(
+    auth: bool = Field(
         default=True,
+        description="Require credentials with "
+        "permissions to access this application"
+        " for all incoming HTTPS requests.",
+        title="Enable Authentication and Authorization",
         json_schema_extra=SchemaExtraMetadata(
-            title="Apolo Authorization",
+            title="Enable Authentication and Authorization",
             description="Require credentials with "
             "permissions to access this application"
             " for all incoming HTTPS requests.",
         ).as_json_schema_extra(),
     )
-    enabled: bool = Field(
-        ...,
-        json_schema_extra=SchemaExtraMetadata(
-            description="Enable Ingress.",
-            title="Ingress Enabled",
-        ).as_json_schema_extra(),
-    )
-    grpc: IngressGrpc | None = Field(
-        default=None,
-        json_schema_extra=SchemaExtraMetadata(
-            title="Enable GRPC",
-            description="Enable and configure GRPC support for the ingress.",
-        ).as_json_schema_extra(),
-    )
diff --git a/src/apolo_app_types/protocols/custom_deployment.py b/src/apolo_app_types/protocols/custom_deployment.py
index 4ed9866a..4c700592 100644
--- a/src/apolo_app_types/protocols/custom_deployment.py
+++ b/src/apolo_app_types/protocols/custom_deployment.py
@@ -7,7 +7,7 @@
     Container,
     ContainerImage,
     DeploymentName,
-    Ingress,
+    IngressHttp,
     Preset,
     RestAPI,
     SchemaExtraMetadata,
@@ -31,7 +31,7 @@ class NetworkingConfig(BaseModel):
         description="Whether to enable the service.",
     )
 
-    ingress: Ingress = Field(default_factory=lambda: Ingress(enabled=True))
+    ingress_http: IngressHttp | None = Field(default_factory=lambda: IngressHttp())
 
     ports: list[Port] = Field(
         default_factory=lambda: [Port()],
diff --git a/src/apolo_app_types/protocols/fooocus.py b/src/apolo_app_types/protocols/fooocus.py
index b4e0c933..c9b7ce56 100644
--- a/src/apolo_app_types/protocols/fooocus.py
+++ b/src/apolo_app_types/protocols/fooocus.py
@@ -6,7 +6,7 @@
     AppInputs,
     AppInputsDeployer,
     AppOutputsDeployer,
-    Ingress,
+    IngressHttp,
     Preset,
     RestAPI,
     SchemaExtraMetadata,
@@ -47,7 +47,7 @@ class FooocusSpecificAppInputs(BaseModel):
 class FooocusAppInputs(AppInputs):
     preset: Preset
     fooocus_specific: FooocusSpecificAppInputs
-    ingress: Ingress
+    ingress_http: IngressHttp
 
 
 class FooocusAppOutputs(AppOutputs):
diff --git a/src/apolo_app_types/protocols/llm.py b/src/apolo_app_types/protocols/llm.py
index fb3125a7..f9cf073f 100644
--- a/src/apolo_app_types/protocols/llm.py
+++ b/src/apolo_app_types/protocols/llm.py
@@ -7,7 +7,7 @@
     AppOutputsDeployer,
     HuggingFaceCache,
     HuggingFaceModel,
-    Ingress,
+    IngressHttp,
     Preset,
     SchemaExtraMetadata,
     SchemaMetaType,
@@ -74,7 +74,10 @@ class Web(AbstractAppFieldType):
 
 class LLMInputs(AppInputs):
     preset: Preset
-    ingress: Ingress
+    ingress_http: IngressHttp | None = Field(
+        default=None,
+        title="Enable HTTP Ingress",
+    )
     llm: LLMModel
     cache_config: HuggingFaceCache | None = Field(
         default=None,
diff --git a/src/apolo_app_types/protocols/mlflow.py b/src/apolo_app_types/protocols/mlflow.py
index a24ea661..b81c232f 100644
--- a/src/apolo_app_types/protocols/mlflow.py
+++ b/src/apolo_app_types/protocols/mlflow.py
@@ -1,5 +1,4 @@
 import enum
-from typing import Literal
 
 from pydantic import ConfigDict, Field
 
@@ -8,7 +7,7 @@
     ApoloFilesPath,
     AppInputs,
     AppOutputs,
-    Ingress,
+    IngressHttp,
     Preset,
     RestAPI,
     SchemaExtraMetadata,
@@ -57,44 +56,31 @@ class SQLitePVCConfig(AbstractAppFieldType):
     )
 
 
-class ArtifactStoreConfig(AbstractAppFieldType):
-    """
-    Configuration for MLFlow artifact storage.
-    Use Apolo Files to store your MLFlow artifacts
-    (model binaries, dependency files, etc).
-    """
-
+class MLFlowMetadataPostgres(AbstractAppFieldType):
     model_config = ConfigDict(
         protected_namespaces=(),
         json_schema_extra=SchemaExtraMetadata(
-            title="Artifact Store",
-            description="Configuration for MLFlow artifact storage.",
+            title="Postgres",
+            description="Use PostgreSQL server as metadata storage for MLFlow.",
         ).as_json_schema_extra(),
     )
-    apolo_files: ApoloFilesPath | None = Field(
-        default=None,
-        description=(
-            "Use Apolo Files to store your MLFlow artifacts "
-            "(model binaries, dependency files, etc). "
-            "E.g. 'storage://cluster/myorg/proj/mlflow-artifacts'"
-        ),
-        title="Storage Path",
-    )
-
-
-class MLFlowMetadataPostgres(AbstractAppFieldType):
-    type: Literal["postgres"] = "postgres"
     postgres_uri: PostgresURI
 
 
 class MLFlowMetadataSQLite(AbstractAppFieldType):
-    type: Literal["sqlite"] = "sqlite"
+    model_config = ConfigDict(
+        protected_namespaces=(),
+        json_schema_extra=SchemaExtraMetadata(
+            title="SQLite",
+            description=(
+                "Use SQLite on a dedicated block device as metadata store for MLFlow."
+            ),
+        ).as_json_schema_extra(),
+    )
     pvc_name: str = "mlflow-sqlite-storage"
-    internal_web_app_url: RestAPI | None = None
-    external_web_app_url: RestAPI | None = None
 
 
-MLFlowMetaStorage = MLFlowMetadataPostgres | MLFlowMetadataSQLite
+MLFlowMetaStorage = MLFlowMetadataSQLite | MLFlowMetadataPostgres
 
 
 class MLFlowAppInputs(AppInputs):
@@ -106,9 +92,16 @@ class MLFlowAppInputs(AppInputs):
     """
 
     preset: Preset
-    ingress: Ingress
-    metadata_storage: MLFlowMetaStorage | None = None
-    artifact_store: ArtifactStoreConfig | None = None
+    ingress_http: IngressHttp
+    metadata_storage: MLFlowMetaStorage
+    artifact_store: ApoloFilesPath = Field(
+        description=(
+            "Use Apolo Files to store your MLFlow artifacts "
+            "(model binaries, dependency files, etc). "
+            "E.g. 'storage://cluster/myorg/proj/mlflow-artifacts'"
+        ),
+        title="Artifact Store",
+    )
 
 
 class MLFlowAppOutputs(AppOutputs):
diff --git a/src/apolo_app_types/protocols/private_gpt.py b/src/apolo_app_types/protocols/private_gpt.py
index 8c54d909..582c399e 100644
--- a/src/apolo_app_types/protocols/private_gpt.py
+++ b/src/apolo_app_types/protocols/private_gpt.py
@@ -9,7 +9,7 @@
 from apolo_app_types.protocols.common import (
     AppInputsDeployer,
     AppOutputsDeployer,
-    Ingress,
+    IngressHttp,
     Preset,
     SchemaExtraMetadata,
 )
@@ -57,7 +57,7 @@ class PrivateGptSpecific(BaseModel):
 
 class PrivateGPTAppInputs(AppInputs):
     preset: Preset
-    ingress: Ingress
+    ingress_http: IngressHttp
     pgvector_user: CrunchyPostgresUserCredentials
     embeddings_api: OpenAICompatEmbeddingsAPI
     llm_chat_api: OpenAICompatChatAPI
diff --git a/src/apolo_app_types/protocols/stable_diffusion.py b/src/apolo_app_types/protocols/stable_diffusion.py
index ab97acaf..8a055b14 100644
--- a/src/apolo_app_types/protocols/stable_diffusion.py
+++ b/src/apolo_app_types/protocols/stable_diffusion.py
@@ -7,7 +7,7 @@
     AppOutputs,
     AppOutputsDeployer,
     HuggingFaceModel,
-    Ingress,
+    IngressHttp,
     Preset,
     RestAPI,
     SchemaExtraMetadata,
@@ -41,7 +41,7 @@ class StableDiffusionParams(AbstractAppFieldType):
 
 
 class StableDiffusionInputs(AppInputs):
-    ingress: Ingress
+    ingress_http: IngressHttp
     preset: Preset
     stable_diffusion: StableDiffusionParams
 
diff --git a/src/apolo_app_types/protocols/text_embeddings.py b/src/apolo_app_types/protocols/text_embeddings.py
index b4c40307..fd52ce87 100644
--- a/src/apolo_app_types/protocols/text_embeddings.py
+++ b/src/apolo_app_types/protocols/text_embeddings.py
@@ -6,7 +6,7 @@
     AppInputsDeployer,
     AppOutputsDeployer,
     HuggingFaceModel,
-    Ingress,
+    IngressHttp,
     Preset,
 )
 from apolo_app_types.protocols.common.openai_compat import OpenAICompatEmbeddingsAPI
@@ -19,7 +19,10 @@ class Image(AbstractAppFieldType):
 
 class TextEmbeddingsInferenceAppInputs(AppInputs):
     preset: Preset
-    ingress: Ingress
+    ingress_http: IngressHttp | None = Field(
+        default=None,
+        title="Enable HTTP Ingress",
+    )
     model: HuggingFaceModel
     container_image: ContainerImage = Field(
         default=ContainerImage(
@@ -33,7 +36,10 @@ class TextEmbeddingsInferenceAppInputs(AppInputs):
 
 class TextEmbeddingsInferenceInputs(AppInputsDeployer):
     preset_name: str
-    ingress: Ingress
+    ingress_http: IngressHttp | None = Field(
+        default=None,
+        title="Enable HTTP Ingress",
+    )
     model: HuggingFaceModel
     image: Image
 
diff --git a/src/apolo_app_types/protocols/weaviate.py b/src/apolo_app_types/protocols/weaviate.py
index 0945faf1..09b66e25 100644
--- a/src/apolo_app_types/protocols/weaviate.py
+++ b/src/apolo_app_types/protocols/weaviate.py
@@ -7,7 +7,8 @@
     Bucket,
     GraphQLAPI,
     GrpcAPI,
-    Ingress,
+    IngressGrpc,
+    IngressHttp,
     Preset,
     RestAPI,
     StorageGB,
@@ -23,8 +24,15 @@ class WeaviateInputs(AppInputs):
         default_factory=lambda: StorageGB(size=WEAVIATE_MIN_GB_STORAGE)
     )
     backup_bucket: Bucket | None = None
-    ingress: Ingress
-    cluster_api: BasicAuth | None = None  # noqa: N815
+    ingress_http: IngressHttp | None = Field(
+        default=None,
+        title="Enable HTTP Ingress",
+    )
+    ingress_grpc: IngressGrpc | None = Field(
+        default=None,
+        title="Enable gRPC Ingress",
+    )
+    # cluster_api: BasicAuth | None = None
 
     @field_validator("persistence")
     def validate_storage_size(cls, value: StorageGB) -> StorageGB:  # noqa: N805
diff --git a/tests/unit/test_custom_deployment_input_generation.py b/tests/unit/test_custom_deployment_input_generation.py
index e13c7f66..651037e0 100644
--- a/tests/unit/test_custom_deployment_input_generation.py
+++ b/tests/unit/test_custom_deployment_input_generation.py
@@ -9,7 +9,7 @@
 )
 from apolo_app_types.app_types import AppType
 from apolo_app_types.inputs.args import app_type_to_vals
-from apolo_app_types.protocols.common import Ingress, Preset
+from apolo_app_types.protocols.common import IngressHttp, Preset
 from apolo_app_types.protocols.common.k8s import Port
 from apolo_app_types.protocols.common.storage import (
     ApoloFilesMount,
@@ -44,10 +44,7 @@ async def test_custom_deployment_values_generation(setup_clients):
                 ports=[
                     Port(name="http", port=8080),
                 ],
-                ingress=Ingress(
-                    enabled=True,
-                    clusterName="default",
-                ),
+                ingress_http=IngressHttp(),
             ),
         ),
         apolo_client=setup_clients,
@@ -98,10 +95,7 @@ async def test_custom_deployment_values_generation_with_storage_mounts(setup_cli
                 ports=[
                     Port(name="http", port=8080),
                 ],
-                ingress=Ingress(
-                    enabled=True,
-                    clusterName="default",
-                ),
+                ingress_http=IngressHttp(),
             ),
             storage_mounts=StorageMounts(
                 mounts=[
@@ -189,10 +183,7 @@ async def test_custom_deployment_values_generation_with_multiport_exposure(
                 Port(name="http1", port=8000, path="/path_prefix1"),
                 Port(name="http2", port=9000, path="/path_prefix2"),
             ],
-            ingress=Ingress(
-                enabled=True,
-                clusterName="default",
-            ),
+            ingress_http=IngressHttp(),
         ),
     )
     helm_args, helm_params = await app_type_to_vals(
@@ -251,9 +242,7 @@ async def test_custom_deployment_values_generation_path_port_not_supplied(
             ports=[
                 Port(name="http", port=8080),
             ],
-            ingress=Ingress(
-                enabled=True,
-            ),
+            ingress_http=IngressHttp(),
         ),
     )
     helm_args, helm_params = await app_type_to_vals(
diff --git a/tests/unit/test_fooocus_input_generation.py b/tests/unit/test_fooocus_input_generation.py
index 9d6078de..7c132024 100644
--- a/tests/unit/test_fooocus_input_generation.py
+++ b/tests/unit/test_fooocus_input_generation.py
@@ -4,7 +4,7 @@
 
 from apolo_app_types.app_types import AppType
 from apolo_app_types.inputs.args import app_type_to_vals
-from apolo_app_types.protocols.common import Ingress, Preset
+from apolo_app_types.protocols.common import IngressHttp, Preset
 from apolo_app_types.protocols.fooocus import (
     FooocusAppInputs,
     FooocusSpecificAppInputs,
@@ -23,8 +23,7 @@ async def test_fooocus_values_generation(setup_clients):
     helm_args, helm_params = await app_type_to_vals(
         input_=FooocusAppInputs(
             preset=Preset(name="cpu-small"),
-            ingress=Ingress(
-                enabled=True,
+            ingress_http=IngressHttp(
                 clusterName="default",
             ),
             fooocus_specific=FooocusSpecificAppInputs(
diff --git a/tests/unit/test_llm_input_generation.py b/tests/unit/test_llm_input_generation.py
index a32d9090..bfbc1bf3 100644
--- a/tests/unit/test_llm_input_generation.py
+++ b/tests/unit/test_llm_input_generation.py
@@ -9,7 +9,7 @@
     _get_match_expressions,
 )
 from apolo_app_types.inputs.args import app_type_to_vals
-from apolo_app_types.protocols.common import ApoloFilesPath, Ingress, Preset
+from apolo_app_types.protocols.common import ApoloFilesPath, IngressHttp, Preset
 from apolo_app_types.protocols.common.secrets_ import ApoloSecret
 from apolo_app_types.protocols.huggingface_cache import (
     HuggingFaceCache,
@@ -27,8 +27,7 @@ async def test_values_llm_generation_cpu(setup_clients, mock_get_preset_cpu):
             preset=Preset(
                 name="cpu-large",
             ),
-            ingress=Ingress(
-                enabled=True,
+            ingress_http=IngressHttp(
                 clusterName="test",
             ),
             llm=LLMModel(
@@ -108,8 +107,7 @@ async def test_values_llm_generation_gpu(setup_clients, mock_get_preset_gpu):
             preset=Preset(
                 name="gpu-small",
             ),
-            ingress=Ingress(
-                enabled=True,
+            ingress_http=IngressHttp(
                 clusterName="test",
             ),
             llm=LLMModel(
@@ -217,8 +215,7 @@ async def test_values_llm_generation_cpu_apolo_secret(
             preset=Preset(
                 name="cpu-large",
             ),
-            ingress=Ingress(
-                enabled=True,
+            ingress_http=IngressHttp(
                 clusterName="test",
             ),
             llm=LLMModel(
@@ -300,7 +297,7 @@ async def test_values_llm_generation_gpu_4x(setup_clients, mock_get_preset_gpu):
     _, helm_params = await app_type_to_vals(
         input_=LLMInputs(
             preset=Preset(name="gpu-large"),  # triggers nvidia_gpu=4 in conftest
-            ingress=Ingress(enabled=True, clusterName="test"),
+            ingress_http=IngressHttp(clusterName="test"),
             llm=LLMModel(
                 hugging_face_model=HuggingFaceModel(
                     model_hf_name="test", hf_token="xxx"
@@ -323,7 +320,7 @@ async def test_values_llm_generation_gpu_8x(setup_clients, mock_get_preset_gpu):
     _, helm_params = await app_type_to_vals(
         input_=LLMInputs(
             preset=Preset(name="gpu-xlarge"),  # triggers nvidia_gpu=8 in conftest
-            ingress=Ingress(enabled=True, clusterName="test"),
+            ingress_http=IngressHttp(clusterName="test"),
             llm=LLMModel(
                 hugging_face_model=HuggingFaceModel(
                     model_hf_name="test2", hf_token="yyy"
@@ -346,7 +343,7 @@ async def test_values_llm_generation_gpu_8x_pps(setup_clients, mock_get_preset_g
     _, helm_params = await app_type_to_vals(
         input_=LLMInputs(
             preset=Preset(name="gpu-xlarge"),  # triggers nvidia_gpu=8 in conftest
-            ingress=Ingress(enabled=True, clusterName="test"),
+            ingress_http=IngressHttp(clusterName="test"),
             llm=LLMModel(
                 hugging_face_model=HuggingFaceModel(
                     model_hf_name="test2", hf_token="yyy"
@@ -371,7 +368,7 @@ async def test_values_llm_generation_gpu_8x_pps_and_tps(
     _, helm_params = await app_type_to_vals(
         input_=LLMInputs(
             preset=Preset(name="gpu-xlarge"),  # triggers nvidia_gpu=8 in conftest
-            ingress=Ingress(enabled=True, clusterName="test"),
+            ingress_http=IngressHttp(clusterName="test"),
             llm=LLMModel(
                 hugging_face_model=HuggingFaceModel(
                     model_hf_name="test2",
@@ -407,8 +404,7 @@ async def test_values_llm_generation__storage_integrated(
             preset=Preset(
                 name="gpu-small",
             ),
-            ingress=Ingress(
-                enabled=False,
+            ingress_http=IngressHttp(
                 clusterName="",
             ),
             llm=LLMModel(
@@ -481,9 +477,26 @@ async def test_values_llm_generation__storage_integrated(
             }
         },
         "ingress": {
+            "enabled": True,
             "grpc": {"enabled": False},
-            "annotations": {},
-            "enabled": False,
+            "annotations": {
+                "traefik.ingress.kubernetes.io/router.middlewares": (
+                    f"{DEFAULT_NAMESPACE}-forwardauth@kubernetescrd"
+                )
+            },
+            "className": "traefik",
+            "hosts": [
+                {
+                    "host": "default.apps.some.org.neu.ro",
+                    "paths": [{"path": "/", "pathType": "Prefix", "portName": "http"}],
+                }
+            ],
+            "forwardAuth": {
+                "enabled": True,
+                "name": "forwardauth",
+                "address": ANY,
+                "trustForwardHeader": True,
+            },
         },
         "podAnnotations": {
             APOLO_STORAGE_LABEL: '[{"storage_uri": "storage://some-cluster/some-org/some-proj/some-folder", "mount_path": "/root/.cache/huggingface", "mount_mode": "rw"}]'  # noqa: E501
diff --git a/tests/unit/test_mlflow_input_generation.py b/tests/unit/test_mlflow_input_generation.py
index 6d15ba45..cf692653 100644
--- a/tests/unit/test_mlflow_input_generation.py
+++ b/tests/unit/test_mlflow_input_generation.py
@@ -4,11 +4,10 @@
 from apolo_app_types.inputs.args import app_type_to_vals
 from apolo_app_types.protocols.common import (
     ApoloFilesPath,
-    Ingress,
+    IngressHttp,
     Preset,
 )
 from apolo_app_types.protocols.mlflow import (
-    ArtifactStoreConfig,
     MLFlowAppInputs,
     MLFlowMetadataPostgres,
     MLFlowMetadataSQLite,
@@ -28,12 +27,10 @@ async def test_values_mlflow_generation_default_sqlite(
     """
     input_data = MLFlowAppInputs(
         preset=Preset(name="cpu-small"),
-        ingress=Ingress(enabled=True, clusterName="test"),
-        metadata_storage=None,
-        artifact_store=ArtifactStoreConfig(
-            apolo_files=ApoloFilesPath(
-                path="storage://test-cluster/myorg/proj/mlflow-artifacts"
-            )
+        ingress_http=IngressHttp(clusterName="test"),
+        metadata_storage=MLFlowMetadataSQLite(),
+        artifact_store=ApoloFilesPath(
+            path="storage://test-cluster/myorg/proj/mlflow-artifacts"
         ),
     )
 
@@ -90,9 +87,9 @@ async def test_values_mlflow_generation_sqlite_explicit_no_pvc_name(
     """
     input_data = MLFlowAppInputs(
         preset=Preset(name="cpu-small"),
-        ingress=Ingress(enabled=True, clusterName="test"),
+        ingress_http=IngressHttp(clusterName="test"),
         metadata_storage=MLFlowMetadataSQLite(),
-        artifact_store=None,
+        artifact_store=ApoloFilesPath(path="storage://foo/bar/baz"),
     )
 
     helm_args, helm_params = await app_type_to_vals(
@@ -129,9 +126,9 @@ async def test_values_mlflow_generation_sqlite_explicit_custom_pvc_name(
     custom_pvc_name = "my-custom-pvc"
     input_data = MLFlowAppInputs(
         preset=Preset(name="cpu-small"),
-        ingress=Ingress(enabled=True, clusterName="test"),
+        ingress_http=IngressHttp(clusterName="test"),
         metadata_storage=MLFlowMetadataSQLite(pvc_name=custom_pvc_name),
-        artifact_store=None,
+        artifact_store=ApoloFilesPath(path="storage://foo/bar/baz"),
     )
 
     helm_args, helm_params = await app_type_to_vals(
@@ -167,16 +164,14 @@ async def test_values_mlflow_generation_postgres_uri(
     """
     input_data = MLFlowAppInputs(
         preset=Preset(name="cpu-small"),
-        ingress=Ingress(enabled=False, clusterName="test-cluster"),
+        ingress_http=IngressHttp(clusterName="test-cluster"),
         metadata_storage=MLFlowMetadataPostgres(
             postgres_uri=PostgresURI(
                 uri="postgresql://user:pass@custom-host:5432/mlflow"
             ),
         ),
-        artifact_store=ArtifactStoreConfig(
-            apolo_files=ApoloFilesPath(
-                path="storage://test-cluster/myorg/proj/mlflow-artifacts"
-            )
+        artifact_store=ApoloFilesPath(
+            path="storage://test-cluster/myorg/proj/mlflow-artifacts"
         ),
     )
 
diff --git a/tests/unit/test_privategpt_input_generation.py b/tests/unit/test_privategpt_input_generation.py
index 8a7524a7..6ab620ed 100644
--- a/tests/unit/test_privategpt_input_generation.py
+++ b/tests/unit/test_privategpt_input_generation.py
@@ -3,7 +3,7 @@
 from apolo_app_types import CrunchyPostgresUserCredentials, HuggingFaceModel
 from apolo_app_types.app_types import AppType
 from apolo_app_types.inputs.args import app_type_to_vals
-from apolo_app_types.protocols.common import Ingress, Preset
+from apolo_app_types.protocols.common import IngressHttp, Preset
 from apolo_app_types.protocols.common.openai_compat import (
     OpenAICompatChatAPI,
     OpenAICompatEmbeddingsAPI,
@@ -23,9 +23,7 @@ async def test_privategpt_values_generation(setup_clients):
     helm_args, helm_params = await app_type_to_vals(
         input_=PrivateGPTAppInputs(
             preset=Preset(name="cpu-small"),
-            ingress=Ingress(
-                enabled=True,
-            ),
+            ingress_http=IngressHttp(),
             llm_chat_api=OpenAICompatChatAPI(
                 host="llm-host",
                 port=8000,
@@ -100,9 +98,7 @@ async def test_privategpt_values_generation_custom_temperature(setup_clients):
     helm_args, helm_params = await app_type_to_vals(
         input_=PrivateGPTAppInputs(
             preset=Preset(name="cpu-small"),
-            ingress=Ingress(
-                enabled=True,
-            ),
+            ingress_http=IngressHttp(),
             llm_chat_api=OpenAICompatChatAPI(
                 host="llm-host",
                 port=8000,
diff --git a/tests/unit/test_sd_input_generation.py b/tests/unit/test_sd_input_generation.py
index 044c55b0..8afdecf5 100644
--- a/tests/unit/test_sd_input_generation.py
+++ b/tests/unit/test_sd_input_generation.py
@@ -3,7 +3,7 @@
 from apolo_app_types import HuggingFaceModel, StableDiffusionInputs
 from apolo_app_types.app_types import AppType
 from apolo_app_types.helm.apps.common import _get_match_expressions
-from apolo_app_types.protocols.common import Ingress, Preset
+from apolo_app_types.protocols.common import IngressHttp, Preset
 from apolo_app_types.protocols.stable_diffusion import StableDiffusionParams
 
 from tests.unit.constants import APP_SECRETS_NAME, CPU_POOL, DEFAULT_NAMESPACE
@@ -19,10 +19,7 @@ async def test_values_sd_generation(setup_clients, mock_get_preset_cpu):
             preset=Preset(
                 name="cpu-large",
             ),
-            ingress=Ingress(
-                enabled=True,
-                clusterName="test",
-            ),
+            ingress_http=IngressHttp(),
             stable_diffusion=StableDiffusionParams(
                 replica_count=1,
                 stablestudio=None,
@@ -81,10 +78,7 @@ async def test_values_sd_generation_with_gpu(setup_clients, mock_get_preset_gpu)
             preset=Preset(
                 name="gpu_preset",
             ),
-            ingress=Ingress(
-                enabled=True,
-                clusterName="test",
-            ),
+            ingress_http=IngressHttp(),
             stable_diffusion=StableDiffusionParams(
                 replicaCount=1,
                 stablestudio=None,
diff --git a/tests/unit/test_tei_input_generation.py b/tests/unit/test_tei_input_generation.py
index 7c789aa7..1e4462bf 100644
--- a/tests/unit/test_tei_input_generation.py
+++ b/tests/unit/test_tei_input_generation.py
@@ -3,7 +3,7 @@
 from apolo_app_types import HuggingFaceModel
 from apolo_app_types.app_types import AppType
 from apolo_app_types.inputs.args import app_type_to_vals
-from apolo_app_types.protocols.common import Ingress, Preset
+from apolo_app_types.protocols.common import IngressHttp, Preset
 from apolo_app_types.protocols.text_embeddings import TextEmbeddingsInferenceAppInputs
 
 from tests.unit.constants import (
@@ -16,8 +16,7 @@ async def test_tei_values_generation(setup_clients):
     helm_args, helm_params = await app_type_to_vals(
         input_=TextEmbeddingsInferenceAppInputs(
             preset=Preset(name="cpu-small"),
-            ingress=Ingress(
-                enabled=True,
+            ingress_http=IngressHttp(
                 clusterName="default",
             ),
             model=HuggingFaceModel(model_hf_name="random/name"),
diff --git a/tests/unit/test_weaviate_input_generation.py b/tests/unit/test_weaviate_input_generation.py
index 3f111472..f7dffaba 100644
--- a/tests/unit/test_weaviate_input_generation.py
+++ b/tests/unit/test_weaviate_input_generation.py
@@ -1,9 +1,9 @@
 import pytest
 
-from apolo_app_types import BasicAuth, Bucket, WeaviateInputs
+from apolo_app_types import Bucket, WeaviateInputs
 from apolo_app_types.app_types import AppType
 from apolo_app_types.helm.apps.common import _get_match_expressions
-from apolo_app_types.protocols.common import Ingress, IngressGrpc, Preset, StorageGB
+from apolo_app_types.protocols.common import IngressGrpc, IngressHttp, Preset, StorageGB
 from apolo_app_types.protocols.common.buckets import (
     BucketProvider,
     CredentialsType,
@@ -40,14 +40,13 @@ async def test_values_weaviate_generation_basic(setup_clients, mock_get_preset_c
                 ],
                 bucket_provider=BucketProvider.AWS,
             ),
-            ingress=Ingress(
-                enabled=False,
+            ingress_http=IngressHttp(
                 clusterName="test",
             ),
-            cluster_api=BasicAuth(  # noqa: N815
-                username="testuser",
-                password="testpass",
-            ),
+            # cluster_api=BasicAuth(  # noqa: N815
+            #     username="testuser",
+            #     password="testpass",
+            # ),
         ),
         apolo_client=apolo_client,
         app_type=AppType.Weaviate,
@@ -81,7 +80,9 @@ async def test_values_weaviate_generation_basic(setup_clients, mock_get_preset_c
         "requiredDuringSchedulingIgnoredDuringExecution"
     ]["nodeSelectorTerms"][0]["matchExpressions"]
     assert match_expressions == _get_match_expressions(["cpu_pool"])
-    assert helm_params["ingress"]["enabled"] is False
+    # Check that ingress key is present and enabled because IngressHttp was provided
+    assert "ingress" in helm_params
+    assert helm_params["ingress"]["enabled"] is True
     assert helm_params["ingress"]["grpc"]["enabled"] is False
 
 
@@ -114,15 +115,14 @@ async def test_values_weaviate_generation_with_ingress(
                 ],
                 bucket_provider=BucketProvider.AWS,
             ),
-            ingress=Ingress(
-                enabled=True,
+            ingress_http=IngressHttp(
                 clusterName="test-cluster",
-                grpc=IngressGrpc(enabled=True),
-            ),
-            cluster_api=BasicAuth(  # noqa: N815
-                username="testuser",
-                password="testpass",
             ),
+            ingress_grpc=IngressGrpc(enabled=True),
+            # cluster_api=BasicAuth(  # noqa: N815
+            #     username="testuser",
+            #     password="testpass",
+            # ),
         ),
         apolo_client=apolo_client,
         app_type=AppType.Weaviate,
@@ -146,6 +146,9 @@ async def test_values_weaviate_generation_with_ingress(
     assert helm_params["ingress"]["grpc"]["annotations"] == {
         "traefik.ingress.kubernetes.io/router.entrypoints": "websecure",
         "traefik.ingress.kubernetes.io/service.serversscheme": "h2c",
+        "traefik.ingress.kubernetes.io/router.middlewares": (
+            f"{DEFAULT_NAMESPACE}-forwardauth@kubernetescrd"
+        ),
     }
 
 
@@ -160,14 +163,15 @@ async def test_values_weaviate_generation_with_auth(setup_clients, mock_get_pres
                 name="cpu-large",
             ),
             persistence=StorageGB(size=64),
-            ingress=Ingress(
-                enabled=True,
+            ingress_http=IngressHttp(
                 clusterName="test-cluster",
-                grpc=IngressGrpc(enabled=True),
             ),
-            cluster_api=BasicAuth(  # noqa: N815
-                username="testuser",
-                password="testpass",
+            # cluster_api=BasicAuth(  # noqa: N815
+            #     username="testuser",
+            #     password="testpass",
+            # ),
+            ingress_grpc=IngressGrpc(
+                clusterName="test-cluster",
             ),
         ),
         apolo_client=apolo_client,
@@ -177,17 +181,17 @@ async def test_values_weaviate_generation_with_auth(setup_clients, mock_get_pres
         app_secrets_name=APP_SECRETS_NAME,
     )
 
-    assert helm_params["clusterApi"]["username"] == "testuser"
-    assert helm_params["clusterApi"]["password"] == "testpass"
-    assert helm_params["authentication"]["anonymous_access"]["enabled"] is False
-    assert helm_params["authentication"]["apikey"]["enabled"] is True
-    assert helm_params["authentication"]["apikey"]["allowed_keys"] == ["testpass"]
-    assert helm_params["authentication"]["apikey"]["users"] == ["testuser"]
-    assert helm_params["authorization"]["admin_list"]["enabled"] is True
-    assert helm_params["authorization"]["admin_list"]["users"] == ["testuser"]
-    assert helm_params["env"]["AUTHENTICATION_APIKEY_ENABLED"] is True
-    assert helm_params["env"]["AUTHENTICATION_APIKEY_ALLOWED_KEYS"] == "testpass"
-    assert helm_params["env"]["AUTHENTICATION_APIKEY_USERS"] == "testuser"
+    # assert helm_params["clusterApi"]["username"] == "testuser"
+    # assert helm_params["clusterApi"]["password"] == "testpass"
+    # assert helm_params["authentication"]["anonymous_access"]["enabled"] is False
+    # assert helm_params["authentication"]["apikey"]["enabled"] is True
+    # assert helm_params["authentication"]["apikey"]["allowed_keys"] == ["testpass"]
+    # assert helm_params["authentication"]["apikey"]["users"] == ["testuser"]
+    # assert helm_params["authorization"]["admin_list"]["enabled"] is True
+    # assert helm_params["authorization"]["admin_list"]["users"] == ["testuser"]
+    # assert helm_params["env"]["AUTHENTICATION_APIKEY_ENABLED"] is True
+    # assert helm_params["env"]["AUTHENTICATION_APIKEY_ALLOWED_KEYS"] == "testpass"
+    # assert helm_params["env"]["AUTHENTICATION_APIKEY_USERS"] == "testuser"
 
 
 @pytest.mark.asyncio
@@ -219,14 +223,15 @@ async def test_values_weaviate_generation_with_backup(
                 ],
                 bucket_provider=BucketProvider.AWS,
             ),
-            ingress=Ingress(
-                enabled=True,
+            ingress_http=IngressHttp(
                 clusterName="test-cluster",
-                grpc=IngressGrpc(enabled=True),
             ),
-            clusterApi=BasicAuth(  # noqa: N815
-                username="testuser",
-                password="testpass",
+            # clusterApi=BasicAuth(  # noqa: N815
+            #     username="testuser",
+            #     password="testpass",
+            # ),
+            ingress_grpc=IngressGrpc(
+                clusterName="test-cluster",
             ),
         ),
         apolo_client=apolo_client,


Reviews:
user: login: YevheniiSemendiak
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T20:04:30Z
user: login: YevheniiSemendiak
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T20:08:39Z
user: login: YevheniiSemendiak
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T20:09:23Z
user: login: YevheniiSemendiak
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T20:11:04Z
user: login: YevheniiSemendiak
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T20:11:17Z
user: login: YevheniiSemendiak
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T20:12:09Z
user: login: YevheniiSemendiak
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T20:13:09Z
user: login: YevheniiSemendiak
body: Some minors,

Great job, sir! :clap: 
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T20:14:18Z
user: login: taddeusb90
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T07:36:29Z
user: login: YevheniiSemendiak
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T12:15:33Z
user: login: YevheniiSemendiak
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T12:16:38Z
user: login: YevheniiSemendiak
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T12:23:56Z
user: login: YevheniiSemendiak
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T12:24:48Z
user: login: YevheniiSemendiak
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T12:25:16Z

Review comments:
diff_hunk: @@ -83,23 +83,54 @@ async def _generate_ingress_config(
 
 async def get_ingress_values(
     apolo_client: apolo_sdk.Client,
-    ingress: Ingress,
+    ingress_http: IngressHttp | None,
+    ingress_grpc: IngressGrpc | None,
     namespace: str,
     port_configurations: list[Port] | None = None,
 ) -> dict[str, t.Any]:
path: src/apolo_app_types/helm/apps/ingress.py
user: login: YevheniiSemendiak
body: maybe, let's split it to dedicated generators?
created_at: 2025-04-29T20:04:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,7 +31,7 @@ class NetworkingConfig(BaseModel):
         description="Whether to enable the service.",
     )
 
-    ingress: Ingress = Field(default_factory=lambda: Ingress(enabled=True))
+    ingress_http: IngressHttp = Field(default_factory=lambda: IngressHttp(enabled=True))
path: src/apolo_app_types/protocols/custom_deployment.py
user: login: YevheniiSemendiak
body: enabled was dropped, isn't it?
created_at: 2025-04-29T20:08:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,7 +47,10 @@ class FooocusSpecificAppInputs(BaseModel):
 class FooocusAppInputs(AppInputs):
     preset: Preset
     fooocus_specific: FooocusSpecificAppInputs
-    ingress: Ingress
+    ingress_http: IngressHttp | None = Field(
path: src/apolo_app_types/protocols/fooocus.py
user: login: YevheniiSemendiak
body: let's enable it by default (maybe even making it obligatory), since wo ingress it doesn't make much sense 
created_at: 2025-04-29T20:09:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -106,9 +90,17 @@ class MLFlowAppInputs(AppInputs):
     """
 
     preset: Preset
-    ingress: Ingress
-    metadata_storage: MLFlowMetaStorage | None = None
-    artifact_store: ArtifactStoreConfig | None = None
+    ingress_http: IngressHttp | None
+    metadata_storage: MLFlowMetaStorage
+    artifact_store: ApoloFilesPath | None = Field(
path: src/apolo_app_types/protocols/mlflow.py
user: login: YevheniiSemendiak
body: maybe, let's make it obligatory? 
created_at: 2025-04-29T20:11:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,7 +57,10 @@ class PrivateGptSpecific(BaseModel):
 
 class PrivateGPTAppInputs(AppInputs):
     preset: Preset
-    ingress: Ingress
+    ingress_http: IngressHttp | None = Field(
path: src/apolo_app_types/protocols/private_gpt.py
user: login: YevheniiSemendiak
body: this too
created_at: 2025-04-29T20:11:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -41,7 +41,10 @@ class StableDiffusionParams(AbstractAppFieldType):
 
 
 class StableDiffusionInputs(AppInputs):
-    ingress: Ingress
+    ingress_http: IngressHttp | None = Field(
path: src/apolo_app_types/protocols/stable_diffusion.py
user: login: YevheniiSemendiak
body: and this

I mean, each app, which is mainly consumed from it's web interface (not via API), probably should always have http_ingress enabled
created_at: 2025-04-29T20:12:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -44,8 +44,7 @@ async def test_custom_deployment_values_generation(setup_clients):
                 ports=[
                     Port(name="http", port=8080),
                 ],
-                ingress=Ingress(
-                    enabled=True,
+                ingress_http=IngressHttp(
                     clusterName="default",
path: tests/unit/test_custom_deployment_input_generation.py
user: login: YevheniiSemendiak
body: nit: `clusterName` redundant?
created_at: 2025-04-29T20:13:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -83,23 +83,54 @@ async def _generate_ingress_config(
 
 async def get_ingress_values(
     apolo_client: apolo_sdk.Client,
-    ingress: Ingress,
+    ingress_http: IngressHttp | None,
+    ingress_grpc: IngressGrpc | None,
     namespace: str,
     port_configurations: list[Port] | None = None,
 ) -> dict[str, t.Any]:
path: src/apolo_app_types/helm/apps/ingress.py
user: login: taddeusb90
body: You mean `get_http_ingress_values` and `get_grpc_ingress_values`?
created_at: 2025-04-30T07:36:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,44 +56,29 @@ class SQLitePVCConfig(AbstractAppFieldType):
     )
 
 
-class ArtifactStoreConfig(AbstractAppFieldType):
-    """
-    Configuration for MLFlow artifact storage.
-    Use Apolo Files to store your MLFlow artifacts
-    (model binaries, dependency files, etc).
-    """
-
+class MLFlowMetadataPostgres(AbstractAppFieldType):
     model_config = ConfigDict(
         protected_namespaces=(),
         json_schema_extra=SchemaExtraMetadata(
-            title="Artifact Store",
-            description="Configuration for MLFlow artifact storage.",
+            title="Postgres",
+            description="MLFlow backend on Postgres.",
path: src/apolo_app_types/protocols/mlflow.py
user: login: YevheniiSemendiak
body: ```suggestion
            description="Use PostgreSQL server as metadata storage for MLFlow.",
```
created_at: 2025-04-30T12:15:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,44 +56,29 @@ class SQLitePVCConfig(AbstractAppFieldType):
     )
 
 
-class ArtifactStoreConfig(AbstractAppFieldType):
-    """
-    Configuration for MLFlow artifact storage.
-    Use Apolo Files to store your MLFlow artifacts
-    (model binaries, dependency files, etc).
-    """
-
+class MLFlowMetadataPostgres(AbstractAppFieldType):
     model_config = ConfigDict(
         protected_namespaces=(),
         json_schema_extra=SchemaExtraMetadata(
-            title="Artifact Store",
-            description="Configuration for MLFlow artifact storage.",
+            title="Postgres",
+            description="MLFlow backend on Postgres.",
         ).as_json_schema_extra(),
     )
-    apolo_files: ApoloFilesPath | None = Field(
-        default=None,
-        description=(
-            "Use Apolo Files to store your MLFlow artifacts "
-            "(model binaries, dependency files, etc). "
-            "E.g. 'storage://cluster/myorg/proj/mlflow-artifacts'"
-        ),
-        title="Storage Path",
-    )
-
-
-class MLFlowMetadataPostgres(AbstractAppFieldType):
-    type: Literal["postgres"] = "postgres"
     postgres_uri: PostgresURI
 
 
 class MLFlowMetadataSQLite(AbstractAppFieldType):
-    type: Literal["sqlite"] = "sqlite"
+    model_config = ConfigDict(
+        protected_namespaces=(),
+        json_schema_extra=SchemaExtraMetadata(
+            title="SQLite",
+            description="MLFlow backend on local SQLite.",
path: src/apolo_app_types/protocols/mlflow.py
user: login: YevheniiSemendiak
body: ```suggestion
            description="Use SQLite on a dedicated block device as metadata store for MLFlow.",
```
created_at: 2025-04-30T12:16:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -106,9 +90,17 @@ class MLFlowAppInputs(AppInputs):
     """
 
     preset: Preset
-    ingress: Ingress
-    metadata_storage: MLFlowMetaStorage | None = None
-    artifact_store: ArtifactStoreConfig | None = None
+    ingress_http: IngressHttp | None
+    metadata_storage: MLFlowMetaStorage
+    artifact_store: ApoloFilesPath | None = Field(
path: src/apolo_app_types/protocols/mlflow.py
user: login: YevheniiSemendiak
body: artifact_store too, mate

sorry for ambiguity 
created_at: 2025-04-30T12:23:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,7 +19,7 @@ async def test_values_sd_generation(setup_clients, mock_get_preset_cpu):
             preset=Preset(
                 name="cpu-large",
             ),
-            ingress=Ingress(
+            ingress_http=IngressHttp(
                 enabled=True,
                 clusterName="test",
path: tests/unit/test_sd_input_generation.py
user: login: YevheniiSemendiak
body: let's cleanup here too
created_at: 2025-04-30T12:24:48Z
author_association: CONTRIBUTOR

PR comments:
user: login: linear[bot]
created_at: 2025-04-25T07:41:25Z
body: <p><a href="https://linear.app/apolo/issue/MLO-212/mlflow-app-improvements">MLO-212 MLFlow app improvements</a></p>
author_association: NONE
user: login: taddeusb90
created_at: 2025-04-30T12:04:13Z
body: > Some minors,
> 
> Great job, sir! 👏

@YevheniiSemendiak  Why, thank you most graciously, good sir! Doff of the hat — but I must protest: the laurels are hardly mine alone. It was a sterling effort on both our parts, what-what. Three cheers for our joint triumph!
author_association: CONTRIBUTOR