diff --git a/.github/workflows/postgres.yml b/.github/workflows/postgres.yml
index 4ceb7a7..258f692 100644
--- a/.github/workflows/postgres.yml
+++ b/.github/workflows/postgres.yml
@@ -63,6 +63,8 @@ jobs:
 
       - name: Create manifest
         run: |
-          docker buildx imagetools create -t code.icb4dc0.de/prskr/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }} \
+          docker buildx imagetools create \
+              -t code.icb4dc0.de/prskr/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }} \
+              -t code.icb4dc0.de/prskr/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }} \
               code.icb4dc0.de/prskr/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }}-arm64 \
               code.icb4dc0.de/prskr/supabase-operator/postgres:${{ matrix.postgres_major }}.${{ fromJSON(env.MINOR_VERSIONS)[matrix.postgres_major] }}.${{ github.run_number }}-amd64
diff --git a/Dockerfile b/Dockerfile
index 8c65e73..2338b64 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
 # Build the manager binary
-FROM golang:1.23.4 AS builder
+FROM golang:1.23.6-alpine AS builder
 ARG TARGETOS
 ARG TARGETARCH
 
@@ -16,10 +16,7 @@ COPY [ "go.*", "./" ]
 COPY [ "api", "api" ]
 COPY [ "assets/migrations", "assets/migrations" ]
 COPY [ "cmd", "cmd" ]
-COPY [ "infrastructure", "infrastructure" ]
 COPY [ "internal", "internal" ]
-COPY [ "magefiles", "magefiles" ]
-COPY [ "tools", "tools" ]
 
 # Build
 # the GOARCH has not a default value to allow the binary be built according to the host where the command
diff --git a/Makefile b/Makefile
index 0c4be10..faf388e 100644
--- a/Makefile
+++ b/Makefile
@@ -148,7 +148,7 @@ uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified
 
 .PHONY: deploy
 deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
-	cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
+	cd config/manager && $(KUSTOMIZE) edit set image supabase-operator=${IMG}
 	$(KUSTOMIZE) build config/default | $(KUBECTL) apply -f -
 
 .PHONY: undeploy
diff --git a/Tiltfile b/Tiltfile
index adaed2b..6f29284 100644
--- a/Tiltfile
+++ b/Tiltfile
@@ -7,13 +7,6 @@ k8s_yaml(kustomize('config/dev'))
 
 compile_cmd = 'CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o out/supabase-operator ./cmd/'
 
-update_settings(suppress_unused_image_warnings=["localhost:5005/cnpg-postgres:17.2"])
-custom_build(
-    'localhost:5005/cnpg-postgres:17.2',
-    'docker build -t $EXPECTED_REF --push -f postgres/Dockerfile --build-arg POSTGRES_MAJOR=17 --build-arg=POSTGRES_MINOR=2 .',
-    ['postgres/Dockerfile']
-)
-
 local_resource(
   'manager-go-compile',
   compile_cmd,
diff --git a/api/v1alpha1/core_types.go b/api/v1alpha1/core_types.go
index bbd6148..744035c 100644
--- a/api/v1alpha1/core_types.go
+++ b/api/v1alpha1/core_types.go
@@ -429,12 +429,12 @@ func (s DatabaseStatus) IsMigrationUpToDate(name string, hash []byte) (found boo
 	return false, false
 }
 
-func (s DatabaseStatus) RecordMigrationCondition(name string, hash []byte, err error) {
+func (s *DatabaseStatus) RecordMigrationCondition(name string, hash []byte, err error) error {
 	var (
 		now                = time.Now()
 		newStatus          = MigrationConditionStatusApplied
 		lastProbeTime      = metav1.NewTime(now)
-		lastTransitionTime metav1.Time
+		lastTransitionTime = metav1.NewTime(now)
 		message            string
 	)
 
@@ -456,8 +456,22 @@ func (s DatabaseStatus) RecordMigrationCondition(name string, hash []byte, err e
 			cond.LastTransitionTime = lastTransitionTime
 			cond.Reason = "Outdated"
 			cond.Message = message
+
+			s.MigrationConditions[idx] = cond
+			return err
 		}
 	}
+
+	s.MigrationConditions = append(s.MigrationConditions, MigrationScriptCondition{
+		Name:               name,
+		Hash:               hash,
+		Status:             newStatus,
+		LastProbeTime:      lastProbeTime,
+		LastTransitionTime: lastTransitionTime,
+		Message:            message,
+	})
+
+	return err
 }
 
 type CoreConditionType string
diff --git a/assets/migrations/setup/realtime.sql b/assets/migrations/setup/realtime.sql
new file mode 100644
index 0000000..2d354df
--- /dev/null
+++ b/assets/migrations/setup/realtime.sql
@@ -0,0 +1,3 @@
+create schema if not exists _realtime;
+
+alter schema _realtime owner to supabase_admin;
diff --git a/config/dev/cnpg-cluster.yaml b/config/dev/cnpg-cluster.yaml
index 089167f..c2a5b57 100644
--- a/config/dev/cnpg-cluster.yaml
+++ b/config/dev/cnpg-cluster.yaml
@@ -44,7 +44,7 @@ metadata:
   namespace: supabase-demo
 spec:
   instances: 1
-  imageName: localhost:5005/cnpg-postgres:17.2
+  imageName: code.icb4dc0.de/prskr/supabase-operator/postgres:17.2.258
   imagePullPolicy: Always
   postgresUID: 26
   postgresGID: 102
diff --git a/config/dev/kustomizeconfig/cnpg-cluster.yaml b/config/dev/kustomizeconfig/cnpg-cluster.yaml
new file mode 100644
index 0000000..4dc7de1
--- /dev/null
+++ b/config/dev/kustomizeconfig/cnpg-cluster.yaml
@@ -0,0 +1,4 @@
+images:
+  - kind: Cluster
+    group: postgresql.cnpg.io
+    path: spec/imageName
diff --git a/dev/cluster.yaml b/dev/cluster.yaml
index 30355bb..265701c 100644
--- a/dev/cluster.yaml
+++ b/dev/cluster.yaml
@@ -1,12 +1,13 @@
 apiVersion: ctlptl.dev/v1alpha1
 kind: Registry
-name: ctlptl-registry
+name: supabase-operator-registry
 port: 5005
 ---
 apiVersion: ctlptl.dev/v1alpha1
 kind: Cluster
 product: kind
-registry: ctlptl-registry
+registry: supabase-operator-registry
 kindV1Alpha4Cluster:
+  name: supabase-operator-debug
   networking:
     ipFamily: dual
diff --git a/docs/api/supabase.k8s.icb4dc0.de.md b/docs/api/supabase.k8s.icb4dc0.de.md
index a017fa6..33b92cf 100644
--- a/docs/api/supabase.k8s.icb4dc0.de.md
+++ b/docs/api/supabase.k8s.icb4dc0.de.md
@@ -518,7 +518,7 @@ _Appears in:_
 
 | Field | Description | Default | Validation |
 | --- | --- | --- | --- |
-| `appliedMigrations` _[MigrationStatus](#migrationstatus)_ |  |  |  |
+| `migrationConditions` _[MigrationScriptCondition](#migrationscriptcondition) array_ |  |  |  |
 | `roles` _object (keys:string, values:integer array)_ |  |  |  |
 
 
@@ -773,9 +773,11 @@ _Appears in:_
 | `serviceKey` _string_ | ServiceKey - key in secret where to read the service JWT from | service_key |  |
 
 
-#### MigrationStatus
 
-_Underlying type:_ _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#time-v1-meta)_
+
+#### MigrationScriptCondition
+
+
 
 
 
@@ -784,6 +786,14 @@ _Underlying type:_ _[Time](https://kubernetes.io/docs/reference/generated/kubern
 _Appears in:_
 - [DatabaseStatus](#databasestatus)
 
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `name` _string_ | Name - file name of the migration script |  |  |
+| `hash` _integer array_ | Hash - SHA256 hash of the script when it was last successfully applied |  |  |
+| `lastProbeTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#time-v1-meta)_ | LastProbeTime - last time the operator tried to execute the migration script |  |  |
+| `lastTransitionTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#time-v1-meta)_ | LastTransitionTime - last time the condition transitioned from one status to another |  |  |
+| `reason` _string_ | Reason - one-word, CamcelCase reason for the condition's last transition |  |  |
+| `message` _string_ | Message - human-readable message indicating details about the last transition |  |  |
 
 
 #### OAuthProvider
diff --git a/internal/controller/core_db_controller.go b/internal/controller/core_db_controller.go
index 14dfb40..bac200f 100644
--- a/internal/controller/core_db_controller.go
+++ b/internal/controller/core_db_controller.go
@@ -105,11 +105,7 @@ func (r *CoreDbReconciler) applyMissingMigrations(
 
 	var appliedSomething bool
 
-	if core.Status.Database.AppliedMigrations == nil {
-		core.Status.Database.AppliedMigrations = make(supabasev1alpha1.MigrationStatus)
-	}
-
-	if appliedSomething, err = migrator.ApplyAll(ctx, core.Status.Database.AppliedMigrations, migrations.InitScripts()); err != nil {
+	if appliedSomething, err = migrator.ApplyAll(ctx, &core.Status, migrations.InitScripts(), true); err != nil {
 		return err
 	}
 
@@ -120,7 +116,7 @@ func (r *CoreDbReconciler) applyMissingMigrations(
 		logger.Info("Init scripts were up to date - did not run any")
 	}
 
-	if appliedSomething, err = migrator.ApplyAll(ctx, core.Status.Database.AppliedMigrations, migrations.MigrationScripts()); err != nil {
+	if appliedSomething, err = migrator.ApplyAll(ctx, &core.Status, migrations.MigrationScripts(), false); err != nil {
 		return err
 	}
 
diff --git a/internal/db/migrator.go b/internal/db/migrator.go
index c1acce2..62d8130 100644
--- a/internal/db/migrator.go
+++ b/internal/db/migrator.go
@@ -32,7 +32,12 @@ type Migrator struct {
 	Conn *pgx.Conn
 }
 
-func (m Migrator) ApplyAll(ctx context.Context, status *supabasev1alpha1.CoreStatus, seq iter.Seq2[migrations.Script, error], areInitScripts bool) (appliedSomething bool, err error) {
+func (m Migrator) ApplyAll(
+	ctx context.Context,
+	status *supabasev1alpha1.CoreStatus,
+	seq iter.Seq2[migrations.Script, error],
+	areInitScripts bool,
+) (appliedSomething bool, err error) {
 	logger := log.FromContext(ctx)
 
 	for s, err := range seq {
@@ -48,12 +53,12 @@ func (m Migrator) ApplyAll(ctx context.Context, status *supabasev1alpha1.CoreSta
 		}
 
 		logger.Info("Applying missing or outdated migration", "filename", s.FileName)
-		if err := m.Apply(ctx, s.Content); err != nil {
+		err := status.Database.RecordMigrationCondition(s.FileName, s.Hash, m.Apply(ctx, s.Content))
+		if err != nil {
 			return false, err
 		}
 
 		appliedSomething = true
-		status.Record(s.FileName)
 	}
 
 	return appliedSomething, nil
diff --git a/internal/webhook/v1alpha1/apigateway_webhook_validator.go b/internal/webhook/v1alpha1/apigateway_webhook_validator.go
index 6c7a1a3..d8cbab9 100644
--- a/internal/webhook/v1alpha1/apigateway_webhook_validator.go
+++ b/internal/webhook/v1alpha1/apigateway_webhook_validator.go
@@ -106,6 +106,7 @@ func (v *APIGatewayCustomValidator) ValidateDelete(ctx context.Context, obj runt
 	return nil, nil
 }
 
+//nolint:unparam // keep the warnings for future use cases
 func validateEnvoyControlPlane(gateway *supabasev1alpha1.APIGateway) (admission.Warnings, error) {
 	envoySpec := gateway.Spec.Envoy
 
diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go
index b5e4381..f98c79a 100644
--- a/test/e2e/e2e_suite_test.go
+++ b/test/e2e/e2e_suite_test.go
@@ -43,7 +43,7 @@ var (
 
 	// projectImage is the name of the image which will be build and loaded
 	// with the code source changes to be tested.
-	projectImage = "example.com/supabase-operator:v0.0.1"
+	projectImage = "code.icb4dc0.de/prskr/supabase-operator:v0.0.1"
 )
 
 // TestE2E runs the end-to-end (e2e) test suite for the project. These tests execute in an isolated,
diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go
index e54e1e1..9c84ccf 100644
--- a/test/e2e/e2e_test.go
+++ b/test/e2e/e2e_test.go
@@ -31,13 +31,13 @@ import (
 )
 
 // namespace where the project is deployed in
-const namespace = "supabase-operator-system"
+const namespace = "supabase-system"
 
 // serviceAccountName created for the project
 const serviceAccountName = "supabase-operator-controller-manager"
 
 // metricsServiceName is the name of the metrics service of the project
-const metricsServiceName = "supabase-operator-controller-manager-metrics-service"
+const metricsServiceName = "supabase-controller-manager-metrics-service"
 
 // metricsRoleBindingName is the name of the RBAC that will be created to allow get the metrics data
 const metricsRoleBindingName = "supabase-operator-metrics-binding"