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

# PostgreSQL Setup

> Deploy PostgreSQL in-cluster via the Helm subchart, or connect to an existing standalone database instance

## Overview

The backend uses two PostgreSQL databases: `dashboard_auth` for authentication/session data and `cobi_core` for core application data.

Set both connection strings in the backend Secret:

```
DATABASE_URL=postgres://<user>:<password>@<host>:5432/dashboard_auth?schema=public
CORE_DATABASE_URL=postgres://<user>:<password>@<host>:5432/cobi_core?schema=public
```

Choose one of the two setup options below.

***

## Option A — In-cluster PostgreSQL (Bitnami subchart)

The chart bundles the [Bitnami PostgreSQL](https://github.com/bitnami/charts/tree/main/bitnami/postgresql) subchart. Enable it and the chart creates a StatefulSet with a PersistentVolumeClaim.

### Helm values

```yaml theme={null}
postgresql:
  enabled: true
  image:
    tag: "16"
  auth:
    username: postgres
    password: "<strong-password>"
    database: dashboard_auth
  primary:
    initdb:
      scripts:
        create-core-db.sql: |
          CREATE DATABASE cobi_core;
    resources:
      requests:
        cpu: 250m
        memory: 512Mi
      limits:
        cpu: "1"
        memory: 2Gi
    persistence:
      enabled: true
      storageClass: ""    # use cluster default; set to "local-path" for on-prem
      size: 10Gi
```

### Internal service address

Once deployed, PostgreSQL is reachable within the namespace at:

```
<release-name>-postgresql:5432
```

### Backend connection string

```bash theme={null}
--from-literal=DATABASE_URL="postgres://postgres:<password>@cobi-dashboard-postgresql:5432/dashboard_auth?schema=public" \
--from-literal=CORE_DATABASE_URL="postgres://postgres:<password>@cobi-dashboard-postgresql:5432/cobi_core?schema=public"
```

### On-premises StorageClass

```yaml theme={null}
postgresql:
  primary:
    persistence:
      storageClass: "local-path"
      size: 20Gi
```

***

## Option B — External / standalone PostgreSQL

Use this option when you have an existing PostgreSQL instance (on-prem server, managed service, etc.).

### Disable the subchart

```yaml theme={null}
postgresql:
  enabled: false
```

### Create the database

```sql theme={null}
CREATE DATABASE dashboard_auth;
CREATE DATABASE cobi_core;
GRANT ALL PRIVILEGES ON DATABASE dashboard_auth TO <username>;
GRANT ALL PRIVILEGES ON DATABASE cobi_core TO <username>;
```

### Set the backend connection string

```bash theme={null}
kubectl create secret generic cobi-backend-secrets \
  --namespace cobi \
  --from-literal=DATABASE_URL="postgres://<user>:<password>@<pg-host>:<port>/dashboard_auth?schema=public" \
  --from-literal=CORE_DATABASE_URL="postgres://<user>:<password>@<pg-host>:<port>/cobi_core?schema=public" \
  # ... other variables
```

#### Connection string formats

| Scenario                 | Example                                                                                   |
| ------------------------ | ----------------------------------------------------------------------------------------- |
| On-prem server (no TLS)  | `postgres://cobi:secret@192.168.1.50:5432/dashboard_auth?schema=public`                   |
| On-prem server (TLS)     | `postgres://cobi:secret@db.internal:5432/dashboard_auth?schema=public&sslmode=require`    |
| External managed service | `postgres://cobi:secret@db.example.com:5432/dashboard_auth?schema=public&sslmode=require` |

#### SSL mode options

| `sslmode`     | When to use                                                      |
| ------------- | ---------------------------------------------------------------- |
| `disable`     | Internal cluster traffic with no TLS requirement                 |
| `require`     | Enforce TLS, skip certificate verification                       |
| `verify-full` | Full CA verification — compliance or internet-facing connections |

### Connecting to an external database from inside the cluster

**ExternalName Service** (DNS alias):

```yaml theme={null}
apiVersion: v1
kind: Service
metadata:
  name: postgres-external
  namespace: cobi
spec:
  type: ExternalName
  externalName: db.internal.example.com
```

Use `postgres-external:5432` as the host in the connection string.

**Endpoints object** (IP-based):

```yaml theme={null}
apiVersion: v1
kind: Service
metadata:
  name: postgres-external
  namespace: cobi
spec:
  ports:
    - port: 5432
---
apiVersion: v1
kind: Endpoints
metadata:
  name: postgres-external
  namespace: cobi
subsets:
  - addresses:
      - ip: 192.168.1.50
    ports:
      - port: 5432
```

***

## Verify the Connection

```bash theme={null}
kubectl logs -n cobi deploy/cobi-dashboard-backend | grep -i "database\|migration\|postgres"
```

A successful startup shows migration completion logs and no `ECONNREFUSED` errors.
