> ## Documentation Index
> Fetch the complete documentation index at: https://docs.prisme.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Install Prisme.ai with Helm

> Unified Helm install reference for the core and apps namespaces, with the values, env vars and ingress annotations you actually need to configure.

Prisme.ai is deployed with two Helm releases: **`prismeai-core`** (API gateway, console, runtime, workspaces, events) and **`prismeai-apps`** (functions, crawler, searchengine). This page is the single source of truth for installation — provider-specific notes live under [Cloud Providers](/self-hosting/cloud/aws).

***

## Prerequisites

* Kubernetes **1.26+** cluster on at least 3 nodes (multi-AZ recommended).
* **Helm 3+**.
* Databases provisioned and reachable from the cluster — see [Databases](/self-hosting/databases/overview).
* Object storage (S3-compatible, Azure Blob, GCS)  — see [Requirements](/self-hosting/requirements#object-storage).
* a **RWX persistent volume** — see [Requirements](/self-hosting/requirements#filesystems).
* A way to inject secrets: Kubernetes Secrets, External Secrets Operator, Vault, AWS/Azure/GCP Secret Manager.
* A TLS certificate covering `api.<your-domain>` and `studio.<your-domain>`.
* Registry credentials for `registry.gitlab.com` (provided by Prisme.ai) — required for the `apps` namespace.

***

## 1. Add the Helm repository

```bash theme={null}
helm repo add prismeai https://helm.prisme.ai/charts
helm repo update
```

***

## 2. Configure the `core` namespace

Bootstrap `prismeai-core-values.yaml` from the chart's full default values so nothing is silently left unset, then trim it down to what you actually override:

```bash theme={null}
helm show values prismeai/prismeai-core > prismeai-core-values.yaml
```

The block below lists every **critical** key you'll typically need to set or override — the rest of the file can stay at its defaults until you have a reason to touch it.

<Note>
  **Self-signed TLS on your databases / Redis?**\
  Mount the CA bundle as a `volume` / `volumeMounts` on the relevant services and point the matching `*_TLS_CA_FILE` env var (e.g. `BROKER_TLS_CA_FILE`, `PERMISSIONS_STORAGE_TLS_CA_FILE`, `SESSIONS_STORAGE_TLS_CA_FILE`, `CONTEXTS_CACHE_TLS_CA_FILE`, `USERS_STORAGE_TLS_CA_FILE`, `COLLECTIONS_STORAGE_TLS_CA_FILE`, `EVENTS_TOPICS_CACHE_TLS_CA_FILE`) at the mounted filepath. The full list is in [Environment Variables](/self-hosting/kubernetes/environment-variables).
</Note>

### Global configuration

```yaml theme={null}
global:
  # Public URLs — REQUIRED
  apiUrl: "https://api.studio.example.com/v2"
  consoleUrl: "https://studio.example.com"            # Comma-separated list for multi-domain (e.g. "https://studio.example.com,https://studio.partner.com")

  # Optional: force internal traffic over a private URL (avoids egress + extra ingress hops)
  internalApiUrl: "http://prismeai-core-prismeai-api-gateway.prismeai-core/v2"

  # Event broker (Redis Streams)
  broker:
    driver: redis # Driver used
    url: '' # URL to the broker: redis://localhost:6379/1
    user: ''
    password: "" # Broker password 
    maxLen: "700" # Default redis streams maxlen (how many events per stream stay in cache before being dropped, whether they have been read or not)
    tlsCaFile: '' # Path to a PEM CA bundle to validate the broker TLS cert. Combine with global.extraCABundle.mountPath, e.g. '/etc/ssl/prismeai-extra-ca/ca-bundle.crt'
    existingSecret: "core-broker" 
    secretKeys: # Supported keys in this secret, set a value to rename the key
      password: ''
      url: ''
                                # Events kept per stream

  storage:
    permissions:
      driver: mongodb # Driver user : mongodb | postgresql
      url: '' # Your MongoDB URI: mongodb+srv://prisme:password@mongodbcluster.example/permissions?authSource=admin Note the /permissions path
      user: ''
      password: '' 
      tlsCaFile: '' # Path to a PEM CA bundle to validate the permissions storage TLS cert. Combine with global.extraCABundle.mountPath, e.g. '/etc/ssl/prismeai-extra-ca/ca-bundle.crt'
      existingSecret: "core-permissions"  
      secretKeys: # Supported keys in this secret, set a value to rename the key
        url: ''
        password: ''


    workspaces:
      driver: S3_LIKE                                 # FILESYSTEM | S3_LIKE | AZURE_BLOB | GCS
      s3_like_bucketName: "prismeai-models"
      existingSecret: "core-workspaces"

    uploads:
      driver: S3_LIKE
      s3_like_bucketName: "prismeai-uploads"          # Single bucket for both public and private uploads (default)
      s3_like_baseUrl: ""                           # Leave unset → downloads are proxied by the api-gateway (no CDN, no public bucket needed)
      s3_like_public_bucketName: ""  # Fill only if you want a separate bucket + CDN for direct public downloads
      existingSecret: "core-uploads"

    events:
      driver: '' # elasticsearch, opensearch
      url: '' # Data lake URL: http://core-es:9200
      user: ''
      password: '' 
      tlsCaFile: '' # Path to a PEM CA bundle to validate the events storage (ES/OpenSearch) TLS cert. Combine with global.extraCABundle.mountPath, e.g. '/etc/ssl/prismeai-extra-ca/ca-bundle.crt'
      existingSecret: "core-prismeai-events-store"
      prefix: '' # Optional prefix for ES indexes, useful for sharing same ES cluster between different platforms
      secretKeys: # Supported keys in this secret, set a value to rename the key
        password: ''
        user: ''
        url: ''
```

<Tip>
  **Multi-domain frontends.** `global.consoleUrl` (env var `CONSOLE_URL`) accepts a **comma-separated list of URLs**. Every URL serves the same frontend and all of them call the single `apiUrl` — so you can expose the Studio under several hostnames (e.g. a vanity domain and an internal one) without standing up a second API. All listed origins are auto-allowlisted for CORS and for OIDC auth redirects.
</Tip>

#### Secret bootstrapping — `global.secrets.allowCreation`

```yaml theme={null}
global:
  secrets:
    allowCreation: true   # First install only — flip to false afterwards
```

This flag gates **only the internal secrets the chart generates on its own** — OIDC signing keys (`oidc`), the internal API key shared between services (`internalSecurity.apiKey`), and the workspace secrets encryption keys (`secretsEncryption.masterKeys` / `refKeys`). It does **not** affect user-provided secrets (broker, storage, cache, mailgun, …) — those are controlled by their respective `existingSecret` fields (see below).

**Required workflow:**

1. **First install** — keep `allowCreation: true` so the chart seeds the internal secrets (OIDC, internal API key, encryption keys) with freshly generated values. Without this the platform cannot start.
2. **After the first install** — set `allowCreation: false` and keep it that way for every subsequent `helm template` render or **ArgoCD** sync. (`helm upgrade` itself has cluster API access and preserves existing secrets correctly even with `allowCreation: true`, but you still want `false` everywhere to stay safe against any pipeline that doesn't.)

<Warning>
  **Why flipping to `false` is mandatory for ArgoCD / `helm template`.** With `allowCreation: true`, the chart preserves the internal secrets across upgrades by calling `lookup "v1" "Secret"` against the live cluster. **That lookup returns nothing under `helm template` and under ArgoCD's diff** (both render the chart offline, without API access). The chart then regenerates fresh random values on every render and the resulting Secret manifests overwrite the live ones — invalidating OIDC sessions, breaking inter-service auth, and **making every previously-encrypted workspace secret unrecoverable**. Setting `allowCreation: false` skips the internal-secret manifests entirely so the live secrets are left untouched.
</Warning>

#### User-provided secrets — `existingSecret` is authoritative

For every external credential (broker, `storage.*`, `cache.*`, `providers.mailgun`, object storage, …), the chart follows a strict rule:

* **If `existingSecret` is set** → the chart **never** creates or overrides that Secret. The deployment references the named Secret as-is. Any `url` / `password` value left in your values file is silently ignored for that resource. Pre-create the Secret out of band (ExternalSecrets Operator, sealed-secrets, Vault, `kubectl create secret`, …) — this is the **recommended** GitOps-friendly pattern.
* **If `existingSecret` is empty AND you provide `url` / `password`** → the chart generates the Secret from those inline values. Useful for quick local trials; not recommended for production because plaintext credentials end up in your values file.
* **If both are empty** → no Secret is created and the deployment fails to start. Pick one of the two patterns above.

This is independent of `global.secrets.allowCreation`: a user secret with `existingSecret` set is safe under `helm template`, ArgoCD, restricted RBAC, or any offline render — no `lookup` is performed.

#### Secrets encryption keys

Prisme.ai encrypts workspace secrets at rest with **envelope encryption** (AES-256-GCM). The master key (KEK) and short-lived reference keys live in one Kubernetes Secret, read by the services as `SECRETS_MASTER_KEYS` / `SECRETS_REF_KEYS`.

The chart *can* auto-generate them, but auto-generation depends on `lookup` to preserve the keys across renders — and **`lookup` returns empty under `helm template` and ArgoCD**, so every render would emit new keys and make all encrypted data unrecoverable. **For GitOps / `helm template` (the recommended setup), pre-create the Secret yourself** and reference it with `existingSecret`; the chart then generates nothing and runs no `lookup`.

<Steps>
  <Step title="Generate the keys into a Secret you own (run once, before the first install)">
    ```bash theme={null}
    kubectl create secret generic prismeai-core-secrets-encryption -n prismeai-core \
      --from-literal=masterKeys="[{\"kid\":\"kek-v1\",\"key\":\"$(openssl rand -hex 32)\",\"active\":true}]" \
      --from-literal=refKeys="[{\"kid\":\"ref-v1\",\"key\":\"$(openssl rand -hex 32)\",\"active\":true}]"
    ```

    `openssl rand -hex 32` produces the 64-hex-character key the chart expects. **Back up both values immediately — this Secret is your only copy.** In GitOps, create it through your secret manager (Sealed Secrets, External Secrets, SOPS) so it is reproducible without committing plaintext keys.
  </Step>

  <Step title="Reference it from global.secretsEncryption">
    ```yaml theme={null}
    global:
      secretsEncryption:
        existingSecret: "prismeai-core-secrets-encryption"   # pre-created above — chart skips generation entirely
    ```

    With `existingSecret` set, the chart emits no encryption Secret and runs no `lookup`, so `helm template` output is identical on every run.
  </Step>
</Steps>

<Warning>
  If the master keys are lost, **all encrypted workspace data is permanently unrecoverable.** Keep your backup of `masterKeys` / `refKeys` somewhere safe (vault, password manager).
</Warning>

For a quick, non-GitOps `helm install` you can instead let the chart auto-generate the keys — see [auto-generation and the full value reference](/self-hosting/kubernetes/configuration#secrets-encryption-keys) in Configuration.

### `prismeai-api-gateway`

Authentication, mail, sessions, super-admin emails.

```yaml theme={null}
prismeai-api-gateway:
  storage:
    users:
      driver: mongodb # Driver user : mongodb | postgresql
      url: '' # Your MongoDB URI : "mongodb+srv://prisme:password@mongodbcluster.example/users?authSource=admin" <-- Note the /users path
      user: ''
      password: '' # Optional: provide the password separately from the URL. Read via USERS_STORAGE_PASSWORD env var.
      tlsCaFile: '' # Path to a PEM CA bundle to validate the users storage TLS cert. Combine with global.extraCABundle.mountPath, e.g. '/etc/ssl/prismeai-extra-ca/ca-bundle.crt'
      existingSecret: "core-prismeai-api-gateway-users"
      secretKeys: # Supported keys in this secret, set a value to rename the key
        url: ''
        password: ''

    sessions:
      driver: redis
      url: '' # example: redis://localhost:6379/3
      user: ''
      password: "" 
      tlsCaFile: '' # Path to a PEM CA bundle to validate the sessions storage TLS cert. Combine with global.extraCABundle.mountPath, e.g. '/etc/ssl/prismeai-extra-ca/ca-bundle.crt'
      existingSecret: "core-prismeai-api-gateway-sessions-store"
      secretKeys: # Supported keys in this secret, set a value to rename the key
        password: ''
        url: ''

  config:
    admins: "admin@example.com"                       # Comma-separated super-admin emails, start with your own email
```

### `prismeai-workspaces`

Workspace models, custom domains, upload limits.  No specific env vars required.

### `prismeai-runtime`

Automation engine — multi-threaded.

```yaml theme={null}
prismeai-runtime:
  storage:
    collections:
      driver: 'mongodb' # Collections db driver: mongodb, postgresql
      url: '' # Collections db URI, example: mongodb+srv://prisme:password@mongodbcluster.example/collections?authSource=admin. Note the /collections path
      user: ''
      password: '' # Optional: provide the password separately from the URL. Read via COLLECTIONS_STORAGE_PASSWORD env var.
      tlsCaFile: '' # Path to a PEM CA bundle to validate the collections storage TLS cert. Combine with global.extraCABundle.mountPath, e.g. '/etc/ssl/prismeai-extra-ca/ca-bundle.crt'
      existingSecret: "core-prismeai-runtime-collections"
      secretKeys: # Supported keys in this secret, set a value to rename the key
        url: ''
        password: ''      

  cache:
    contexts:
      driver: redis
      url: ''
      user: ''
      password: ""
      tlsCaFile: '' # Path to a PEM CA bundle to validate the contexts cache TLS cert. Combine with global.extraCABundle.mountPath, e.g. '/etc/ssl/prismeai-extra-ca/ca-bundle.crt'
      existingSecret: "core-prismeai-runtime-cache"
      secretKeys: # Supported keys in this secret, set a value to rename the key
        password: ''
        url: ''      
```

Also declare your **LLM and vector store credentials** now as `WORKSPACE_SECRET_*` env vars on `prismeai-runtime` — the LLM Gateway and Storage workspaces won't function without them. See [LLM & vector store credentials](/self-hosting/kubernetes/configuration#llm-and-vector-store-credentials) for the full list.

Example with OpenSearch as the vector store and OpenAI as the LLM provider (prefer `existingSecret` / `valueFrom.secretKeyRef` in production):

```yaml theme={null}
prismeai-runtime:
  env:
    # Vector store — OpenSearch
    - name: WORKSPACE_SECRET_storage_opensearch_host
      value: "https://opensearch.example.com:9200"
    - name: WORKSPACE_SECRET_storage_opensearch_username
      value: "prismeai"
    - name: WORKSPACE_SECRET_storage_opensearch_password
      valueFrom:
        secretKeyRef:
          name: core-prismeai-runtime-vectorstore
          key: password
    # Prefix for every RAG index — applies to both elastic and opensearch drivers.
    # Must NOT end with '-' or '_' (the platform appends '_' automatically).
    - name: WORKSPACE_SECRET_storage_index_prefix
      value: "rag"

    # LLM provider — OpenAI
    - name: WORKSPACE_SECRET_llm-gateway_openaiApiKey
      valueFrom:
        secretKeyRef:
          name: core-prismeai-runtime-llm
          key: openaiApiKey
```

### `prismeai-events`

Activity log + retention.

```yaml theme={null}
prismeai-events:
  events:
    cleanupjob: true                                        # Enable scheduled cleanup
    retention: 1080                                         # Days before events are deleted (3 years)
    workspaceMaxEvents: 5000                                # Cap for small/inactive workspaces
    workspaceInactivityDays: 14                             # Inactivity threshold for cleanup
    automationExecutedExpiration: "14d"                     # Retention for automation traces
```

### Ingress and load balancer

The `prismeai-core` chart ships a default `core-ingress` object — you only need to override its annotations, hosts and TLS secret to match your environment. Use a single ingress for both `api.<your-domain>` and `studio.<your-domain>`. Below is an **AWS ALB** example; equivalent annotations exist for [Azure Application Gateway](/self-hosting/cloud/azure), [GKE Ingress](/self-hosting/cloud/gcp), [OpenShift Routes](/self-hosting/cloud/openshift).

#### Two timeouts to tune

These are **two different settings** on the load balancer and they must both be set:

* **`client_keep_alive`** — how long the LB keeps a client TCP connection open between requests so the browser can reuse the same socket. Set to **60 s** (must be **under** the api-gateway server keep-alive of **70 s**, otherwise the LB sends requests on a socket the gateway just closed and you get 502s).
* **`idle_timeout`** — the longest period of inactivity allowed on an in-flight request before the LB cuts it. Set to **300 s** so server-sent events and long LLM streaming responses don't get killed mid-flight.

#### ALB example

Make sure the annotations match the ones expected by your Ingress Controller.

```yaml theme={null}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: core-ingress
  namespace: core
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443},{"HTTP": 80}]'
    alb.ingress.kubernetes.io/ssl-policy: "ELBSecurityPolicy-TLS13-1-2-2021-06"
    alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:..."
    alb.ingress.kubernetes.io/subnets: "subnet-a,subnet-b,subnet-c"
    # Two distinct timeouts:
    #   idle_timeout       — kill an in-flight request after N s of inactivity (raise it for SSE / long LLM streams)
    #   client_keep_alive  — keep client TCP socket open across requests (must be < api-gateway server keep-alive of 70 s)
    alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=300,client_keep_alive.seconds=60
spec:
  rules:
    - host: api.example.com
      http:
        paths:
          - path: "/"
            pathType: Prefix
            backend:
              service:
                name: prismeai-core-prismeai-api-gateway
                port:
                  number: 80
    - host: studio.example.com
      http:
        paths:
          - path: "/"
            pathType: Prefix
            backend:
              service:
                name: prismeai-core-prismeai-console
                port:
                  number: 80
  tls:
    - hosts:
        - api.example.com
        - studio.example.com
      secretName: prismeai-tls
```

`prismeai-events` benefits from sticky sessions — pin clients via a header (e.g. `user-agent` consistent hash) at the ingress or via an Istio `DestinationRule`.

***

## 3. Configure the `apps` namespace

Bootstrap `prismeai-apps-values.yaml` the same way — dump the chart defaults first, then override only what you need:

```bash theme={null}
helm show values prismeai/prismeai-apps > prismeai-apps-values.yaml
```

The `apps` namespace pulls images from a private registry, so the registry credentials below are mandatory.

<Note>
  **License + registry credentials.** The `apps` chart (functions, crawler, searchengine) is gated by your subscription license. Credentials for `registry.gitlab.com` are issued as a GitLab Deploy Token — contact [support@prisme.ai](mailto:support@prisme.ai) if you don't have them yet.
</Note>

```yaml theme={null}
global:
  repository:
    host: registry.gitlab.com
    username: ""                                            # Provided by Prisme.ai
    token: ""                                               # Provided by Prisme.ai
    create: true
    imagePullSecretName: "registry-secret"

  storage:
    documents:
      url: '' # URL, example: http://core-es-http.core.svc:9200
      user: ''
      password: ''
      existingSecret: 'apps-crawler-documents' 
      secretKeys: # Supported keys in this secret, set a value to rename the key
        url: '' 
        user: ''
        password: ''

    searchengines:
      url: '' # URL (i.e redis://user:password@redis:6379/4) with credentials to your Redis, specify a dedicated database such as "/4" in the example.
      password: '' # Optional: provide the password separately from the URL. Read via REDIS_PASSWORD env var.
      tlsCaFile: '' # Path to a PEM CA bundle to validate the Redis TLS cert. Combine with global.extraCABundle.mountPath, e.g. '/etc/ssl/prismeai-extra-ca/ca-bundle.crt'
      existingSecret: 'apps-crawler-searchengines' 
      secretKeys: # Supported keys in this secret, set a value to rename the key
        url: ''
        password: ''  
```

### `prismeai-functions`

Custom code execution (JavaScript / Python).

```yaml theme={null}
prismeai-functions:
  persistence:
    existingClaim: "apps-prismeai-sfsturbo"                 # Shared RWX PVC (EFS / Azure Files / Filestore)
```

The PVC can be declared in the same value file with `extraObjects` :

```yaml theme={null}
extraObjects:
  - apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      annotations:
        helm.sh/resource-policy: keep
      finalizers:
        - kubernetes.io/pvc-protection
      name: apps-prismeai-sfsturbo
      namespace: apps
    spec:
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 100Gi
      storageClassName: 'efs-sc' # Secify your storageClassName
```

### `prismeai-crawler`

Web crawler and document indexing.

```yaml theme={null}
prismeai-crawler:
  env:
    - name: ELASTIC_INDICES_PREFIX
      value: &ELASTIC_INDICES_PREFIX ""             # Set when sharing Elasticsearch
```

### `prismeai-searchengine`

Query routing on top of crawled indices.\
Make sure the `ELASTIC_INDICES_PREFIX` match the one in `prismeai-crawler` with a yaml anchor :

```yaml theme={null}
prismeai-searchengine:
  env:
    - name: ELASTIC_INDICES_PREFIX
      value: *ELASTIC_INDICES_PREFIX
```

***

## 4. Cross-cutting configuration (both charts)

The next two settings live under `global.*` and behave identically on both `prismeai-core` and `prismeai-apps`. Define them in **both** values files when applicable — same block, same Secret reference.

### Trusting an extra CA bundle (private PKI / self-signed)

**Mandatory** if any URL the platform calls — LLM gateway, vector store, OIDC IdP, managed Elasticsearch or OpenSearch, internal HTTP APIs, third-party APIs hit by user Custom Code — is signed by a private PKI or a self-signed certificate. Configure `global.extraCABundle` to propagate your CA bundle to every pod in one shot. On `prismeai-apps`, an init container automatically merges your bundle with the service image's system trust store so public HTTPS keeps working.

Full step-by-step → [Trusting an extra CA bundle](/self-hosting/kubernetes/configuration#trusting-an-extra-ca-bundle).

### HTTP/HTTPS proxy

**Mandatory** if the cluster has no direct egress to the internet (LLM providers, OIDC IdP, public sites for the crawler, third-party APIs called by automations or user Custom Code). Configure `global.proxy` (httpProxy / httpsProxy / noProxy) to set `HTTP_PROXY` & friends on every pod.

Don't forget to append your **HTTP-based** external hosts to `noProxy` (managed Elasticsearch or OpenSearch, S3 / Blob / GCS, internal LLM gateway, OIDC IdP) — Mongo/Postgres/Redis are binary protocols and bypass the proxy natively.

Full step-by-step → [HTTP/HTTPS Proxy](/self-hosting/kubernetes/configuration#http-proxy).

***

## 5. Cloud-specific configuration

Beyond the cross-cutting settings above, each cloud provider exposes its own Helm-level tweaks — most often **ingress annotations** (load balancer class, TLS / ACM certificates, keep-alive and idle timeouts, sticky sessions), but also persistent storage classes, workload identity bindings and registry pull secrets.

Before installing, open the page matching your target platform and apply the provider-specific values it documents:

* [AWS](/self-hosting/cloud/aws) — ALB ingress, IRSA, EFS / EBS storage classes.
* [Azure](/self-hosting/cloud/azure) — Application Gateway / NGINX ingress, Workload Identity, Azure Files / Disk.
* [GCP](/self-hosting/cloud/gcp) — GCE ingress, Workload Identity, Filestore / PD storage classes.
* [OVHcloud](/self-hosting/cloud/ovh) — Managed Kubernetes ingress and storage.
* [OpenShift](/self-hosting/cloud/openshift) — Routes vs. ingress, SCCs, operators.

<Warning>Ingress configuration in particular is **not portable** between providers — copying annotations from one cloud to another will silently break health checks, TLS termination or long-lived SSE / websocket streams. Always start from the provider page.</Warning>

***

## 6. Install both charts

```bash theme={null}
helm install prismeai-core prismeai/prismeai-core \
  --namespace prismeai-core \
  --create-namespace \
  -f prismeai-core-values.yaml

helm install prismeai-apps prismeai/prismeai-apps \
  --namespace prismeai-apps \
  --create-namespace \
  -f prismeai-apps-values.yaml
```

Both releases are independent — order doesn't matter and you can re-run either one with `helm upgrade` after editing the matching values file.

<Warning>
  **Once `prismeai-core` is up, set `global.secrets.allowCreation: false`** in `prismeai-core-values.yaml` and re-run `helm upgrade`. Leaving it at `true` will silently overwrite the **internal** OIDC / encryption / internal-API-key secrets the first install just seeded as soon as the chart is rendered without cluster API access — typically an ArgoCD sync or a `helm template`-based pipeline. User-provided secrets (broker, storage, …) are unaffected by this flag — they are governed by their `existingSecret` field. See [Secret bootstrapping](#secret-bootstrapping-global-secrets-allowcreation) for the full rationale.
</Warning>

<Accordion title="Troubleshooting: ImagePullBackOff on the apps namespace">
  If pods stay in `ImagePullBackOff`, the registry secret was not created or doesn't carry the right credentials. The chart creates it automatically when `global.repository.create: true` — if you manage secrets externally, create it by hand:

  ```bash theme={null}
  kubectl create secret docker-registry registry-secret \
    --docker-server=registry.gitlab.com \
    --docker-username=YOUR_USERNAME \
    --docker-password=YOUR_TOKEN \
    --namespace prismeai-apps
  ```

  Then set `global.repository.create: false` and keep `imagePullSecretName: "registry-secret"` so the chart references the existing secret.
</Accordion>

***

## 7. Readiness check

Once both charts are installed and pods are running, validate the deployment from the UI:

1. Open the platform URL and sign in with a superadmin account — any email listed in `admins` on the API gateway values (see [`prismeai-api-gateway`](#prismeai-api-gateway)).
2. On first login, initialize the first organization by filling only its **name** and **slug**. The platform then loads with a left menu exposing **Builder** and **Govern**.
3. Open the native **Govern** app from the left menu and go to the **Infrastructure** page. Verify the platform is healthy by testing native Services & databases connectivity with the **Test** buttons at the bottom of the page.

<Note>
  Vector store connectivity is validated later, once the **Storage** workspace has been imported — see [Install products → Vector store](/self-hosting/install-products#34-vector-store). The `WORKSPACE_SECRET_storage_*` env vars set on `prismeai-runtime` in [step 2](#prismeai-runtime) are consumed by that workspace at import time.
</Note>

If any service reports an error, revisit the corresponding values in steps 2–5 and re-run `helm upgrade` before continuing.

***

## 8. PostgreSQL

Compared to MongoDB, only three keys change. Each is marked with a `postgresql` comment in the values file.

#### Database permissions

**Key:** `global.storage.permissions`

Set `driver: postgresql` and the connection URL in `url` (not recommended for production) or via the `existingSecret`.

```
postgres://user:password@db.example.com:5432/permissions?sslmode=require
```

<Note>`sslmode=require` is mandatory.</Note>

#### Database users

**Key:** `prismeai-api-gateway.storage.users` — same structure.

#### Database collections

**Key:** `prismeai-runtime.storage.collections` — same structure.

See the [PostgreSQL page](/self-hosting/databases/postgresql) for version requirements and managed service recommendations.

***

## 9. Upgrade, rollback, uninstall

```bash theme={null}
# Upgrade
helm upgrade prismeai-core prismeai/prismeai-core \
  --namespace prismeai-core -f prismeai-core-values.yaml

# Release history
helm history prismeai-core -n prismeai-core

# Rollback to a previous revision
helm rollback prismeai-core <revision> -n prismeai-core

# Uninstall
helm uninstall prismeai-core -n prismeai-core
```

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Configuration" icon="sliders" href="/self-hosting/kubernetes/configuration">
    Post-install settings: image tags, LLM / vector store credentials, auth, mail, retention, uploads, readiness check.
  </Card>

  <Card title="Cloud Providers" icon="cloud" href="/self-hosting/cloud/aws">
    Provider-specific managed services, IaC modules and ingress annotations.
  </Card>

  <Card title="Databases" icon="database" href="/self-hosting/databases/overview">
    PostgreSQL or MongoDB, Redis, Elasticsearch or OpenSearch.
  </Card>

  <Card title="Resources & HPA" icon="gauge-high" href="/self-hosting/kubernetes/resources">
    Resource requests, limits and Horizontal Pod Autoscaling.
  </Card>

  <Card title="Environment Variables" icon="list" href="/self-hosting/kubernetes/environment-variables">
    Full env-var reference per service.
  </Card>

  <Card title="Operations" icon="tools" href="/self-hosting/operations/scaling">
    Scaling, updates and backups.
  </Card>
</CardGroup>
