diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b8cc189eb86c68d8a0d834fe4b11b9d02911b3d3..0674d6678ba3d07812cfbef68b526a49b595a88a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,88 +1,136 @@
 workflow:
   rules:
-    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
-      when: always
     - if: >-
-        $CI_PIPELINE_SOURCE == "push"
-        && ($CI_COMMIT_BRANCH == "staging" || $CI_COMMIT_BRANCH == "master")
+        $CI_COMMIT_BRANCH == "staging" || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
       when: always
     - when: never
 
 variables:
-  DOCKER_VERSION: '20.10.12'
-  K8S_NAMESPACE: 'devops-s22-deployable'
+  DOCKER_VERSION: '20.10.17'
+  K8S_VERSION: '1.24'
+  GOOGLE_CLOUD_SDK_IMAGE_VERSION: '400.0.0'
+  K8S_NAMESPACE: 'todoapp-devops'
   CONTAINER_TAG: '${CI_REGISTRY_IMAGE}:${CI_PIPELINE_IID}-${CI_COMMIT_SHORT_SHA}'
 
 stages:
   - test
   - build
+  - release
   - deploy
 
-job_test-image:
+.gke-initialization:
+    before_script:
+    - echo $BASE64_GOOGLE_CREDENTIALS | base64 -d > ~/service_account.json
+    - gcloud auth activate-service-account --key-file ~/service_account.json
+    - gcloud config set project ${GCP_PROJECT_ID}
+    - gcloud config set compute/zone ${GCP_COMPUTE_REGION}
+    - gcloud container clusters get-credentials ${GCP_PROJECT_ID}-gke
+
+test-image:
   stage: test
   tags:
     - docker-priviliged
-  image: docker:$DOCKER_VERSION
+  image: docker:${DOCKER_VERSION}
   services:
-    - name: docker:$DOCKER_VERSION-dind
+    - name: docker:${DOCKER_VERSION}-dind
   script:
     - docker build
       --tag "${CONTAINER_TAG}-test"
       --target=test
       "./"
   after_script:
-    - docker image rm --force "${CI_REGISTRY_IMAGE}:${CI_PIPELINE_IID}-${CI_COMMIT_SHORT_SHA}"
+    - docker image rm --force "${CONTAINER_TAG}-test"
 
-job_build-image:
+build-image:
   stage: build
   needs:
-    - 'job_test-image'
-  rules:
-    - if: $CI_COMMIT_BRANCH != "staging" && $CI_COMMIT_BRANCH != "master"
-      when: 'never'
+    - 'test-image'
   tags:
     - docker-priviliged
-  image: docker:$DOCKER_VERSION
+  image: docker:${DOCKER_VERSION}
   services:
-    - name: docker:$DOCKER_VERSION-dind
+    - name: docker:${DOCKER_VERSION}-dind
+  before_script:
+    - docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY}
   script:
-    - SERVER_PUBLIC_URL=""
-    - DB_HOST=""
-    - docker build
+    - docker image build
       --tag "${CONTAINER_TAG}"
-      --build-arg JWT_SECRET=${JWT_SECRET}
-      --build-arg SERVER_PUBLIC_URL=${SERVER_PUBLIC_URL}
-      --build-arg DB_HOST=${DB_HOST}
-      "./"
+      "./app"
+    # - docker image build
+    #   --tag "${CONTAINER_TAG}-google-sdk"
+    #   "./gcloud-image"
+    - docker push "${CONTAINER_TAG}"
+    # - docker push "${CONTAINER_TAG}-google-sdk"
+  after_script:
+    - docker image rm --force "${CONTAINER_TAG}"
+    # - docker image rm --force "${CONTAINER_TAG}-google-sdk"
+
+create-release_image:
+  stage: release
+  rules:
+    - if: $CI_COMMIT_REF_NAME =~ /main/
+      when: 'always'
+  tags:
+    - docker-privileged
+  image: docker:${DOCKER_VERSION}
+  services:
+    - name: docker:${DOCKER_VERSION}-dind
+  before_script:
     - docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY}
-    - docker push "${CI_REGISTRY_IMAGE}:${CI_PIPELINE_IID}-${CI_COMMIT_SHORT_SHA}"
+    - docker pull "${CONTAINER_TAG}"
+  script:
+    - VERSION=$(cat ./app/client/package.json | docker run --interactive stedolan/jq --raw-output '.version')
+    - docker tag "${CONTAINER_TAG}" "${CI_REGISTRY_IMAGE}:${VERSION}"
+    - docker push "${CI_REGISTRY_IMAGE}:${VERSION}"
   after_script:
-    - docker image rm --force "${CI_REGISTRY_IMAGE}:${CI_PIPELINE_IID}-${CI_COMMIT_SHORT_SHA}"
+    - docker image rm --force
+        $(docker images --format '{{.Repository}}{{.Tag}}' | grep '${CI_REGISTRY_IMAGE}')
+
+# create-release_tag:
+#   stage: release
+#   needs:
+#     - 'create-release_image'
+#   rules:
+#     - if: $CI_COMMIT_REF_NAME =~ /main/
+#       when: 'always'
+#   tags:
+#     - docker-privileged
+#   image: docker:${DOCKER_VERSION}-git
+#   services:
+#     - name: docker:${DOCKER_VERSION}-dind
+#   script:
+#     - VERSION=$(cat ./src/package.json | docker run --interactive stedolan/jq --raw-output '.version')
+#     - echo ${VERSION}
+#     #- git tag "v${VERSION}" && git push origin "v${VERSION}"
+
 
-job_deploy-image:
+deploy-image:
+  extends: .gke-initialization
   stage: deploy
   needs:
-    - 'job_build-image'
+    - 'build-image'
   rules:
     - if: $CI_COMMIT_REF_NAME =~ /staging/
       when: 'always'
       variables:
         ENVIRONMENT_NAME: 'staging'
-    - if: $CI_COMMIT_REF_NAME !~ /staging/
+    - if: $CI_COMMIT_REF_NAME !~ /main/
       when: 'always'
       variables:
-        ENVIRONMENT_NAME: 'prod'
+        ENVIRONMENT_NAME: 'production'
   tags:
     - docker
-  image:
-    name: k8s-image
-    entrypoint: ['']
+  image: google/cloud-sdk:${GOOGLE_CLOUD_SDK_IMAGE_VERSION}
   script:
-    # - IMAGE="${CI_REGISTRY_IMAGE}:${VERSION}"
-    - kubectl apply
-        --kubeconfig ${SECRET_KUBECONFIG_PATH}
-        --namespace "${ENVIRONMENT_NAME}-${K8S_NAMESPACE}"
-        --kustomize -
+    - VERSION="${CI_PIPELINE_IID}-${CI_COMMIT_SHORT_SHA}"
+    - IMAGE="${CI_REGISTRY_IMAGE}:${VERSION}"
+    - cd "app/k8s-manifests"
+    - kubectl apply secrets.yaml --namespace "${ENVIRONMENT_NAME}-${K8S_NAMESPACE}"
+    - kubectl apply gitlab-registry-credentials.yaml --namespace "${ENVIRONMENT_NAME}-${K8S_NAMESPACE}"
+    - kubectl apply configmap.yaml --namespace "${ENVIRONMENT_NAME}-${K8S_NAMESPACE}"
+    - kubectl apply deployment.yaml --namespace "${ENVIRONMENT_NAME}-${K8S_NAMESPACE}"
+    - kubectl apply service.yaml --namespace "${ENVIRONMENT_NAME}-${K8S_NAMESPACE}"
+    - kubectl apply ingress.yaml --namespace "${ENVIRONMENT_NAME}-${K8S_NAMESPACE}"
 
 
 
diff --git a/app/.dockerignore b/app/.dockerignore
index 5734ba9c6b204ea1f73f9464e3ccc2588ef34b8a..114cdfa370b22bc268c72cbaca6e5e0bfa142f77 100644
--- a/app/.dockerignore
+++ b/app/.dockerignore
@@ -2,3 +2,5 @@ client/node_modules
 server/node_modules
 .dockerignore
 Dockerfile
+README.md
+npm-debug.log
diff --git a/app/Dockerfile b/app/Dockerfile
index 2ac29aaa73300b4afd5e6bc8e0a979e427f0b3dc..e2085b54bb78cb0f1bb350c5a0fb5cb21ec10e39 100644
--- a/app/Dockerfile
+++ b/app/Dockerfile
@@ -6,7 +6,7 @@ ARG NODEJS_VERSION='16.17.0'
 FROM node:$NODEJS_VERSION-alpine AS base
 
 ENV \
-    PORT=3002 \
+    PORT=3000 \
     # For local dev - mongodb://host.docker.internal:27017/todo-app
     MONGODB_URL=<should-be-dynamically-set> \
     JWT_SECRET=<should-be-dynamically-set>
diff --git a/app/README.md b/app/README.md
index 50acb84f248753553cecf00728626276be21b869..61839f4e246f1f7f4ce9a2bdfc5de254f3c43791 100644
--- a/app/README.md
+++ b/app/README.md
@@ -1,6 +1,6 @@
 Todo-App
 ========
-
+d
 
 This application represents the *deployable workload* for the
 [lecture assignment](https://github.com/lucendio/lecture-devops-material/blob/master/assignments/exercise.md). 
diff --git a/app/k8s-manifests/configmap.yaml b/app/k8s-manifests/configmap.yaml
deleted file mode 100644
index 967de9f7d051a9e1147df7e38a0d4bbbd0d68682..0000000000000000000000000000000000000000
--- a/app/k8s-manifests/configmap.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
-  name: app-config
-data:
-  PORT: 3000
-  # MONGODB_URL: mongo-service.namespace (from infra repo. Does this work? Or do I have to dynamically set it?)
-  MONGODB_URL: mongodb://<mongo-service>:27017/todo-app
diff --git a/app/k8s-manifests/service.yaml b/app/k8s-manifests/service.yaml
deleted file mode 100644
index c5a84a2260de00652aef4030547308593b3d7a85..0000000000000000000000000000000000000000
--- a/app/k8s-manifests/service.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-apiVersion: v1
-kind: Service
-metadata:
-  name: todo-app-service
-spec:
-  selector:
-      app: todo-app
-  ports:
-    - port: 8080
-      targetPort: 3000
-      # port for external IP address (that you need to put in your browser)
-      # nodePort: 30000
-  # type: LoadBalancer
diff --git a/k8s-manifests/configmap.yaml b/k8s-manifests/configmap.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..30146169f0677f4cc8bd819ae191f69bde0dc17f
--- /dev/null
+++ b/k8s-manifests/configmap.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: todo-app-config
+data:
+  PORT: 3000
+  # MONGODB_URL: mongodb://<mongo-service>:27017/todo-app
+  # mongodb-service.<namespace>?
+  MONGODB_URL: mongodb-service
diff --git a/app/k8s-manifests/deployment.yaml b/k8s-manifests/deployment.yaml
similarity index 79%
rename from app/k8s-manifests/deployment.yaml
rename to k8s-manifests/deployment.yaml
index 97eb0bf960f6a39814da2ce7fee6cd25bc54ffb4..2de3f43c765498278154fba0a25f3ee2cb4758c6 100644
--- a/app/k8s-manifests/deployment.yaml
+++ b/k8s-manifests/deployment.yaml
@@ -1,7 +1,7 @@
 apiVersion: apps/v1
 kind: Deployment
 metadata:
-  name: app-deployment
+  name: todo-app-deployment
   labels:
     app: todo-app
 spec:
@@ -24,8 +24,9 @@ spec:
         ports:
         - containerPort: 3000
           # imagePullPolicy: IfNotPresent
+        # env for mongodb username and pass?
         envFrom:
         - configMapRef:
-          name: app-config
+          name: todo-app-config
         - secretRef:
-          name: app-secrets
+          name: todo-app-secrets
diff --git a/app/registry-credentials.yaml b/k8s-manifests/gitlab-registry-credentials.yaml
similarity index 100%
rename from app/registry-credentials.yaml
rename to k8s-manifests/gitlab-registry-credentials.yaml
diff --git a/k8s-manifests/ingress.yaml b/k8s-manifests/ingress.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..675762207cbe8609b5b265db97b48d3ce8e356fb
--- /dev/null
+++ b/k8s-manifests/ingress.yaml
@@ -0,0 +1,23 @@
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: todo-app-ingress
+  annotations:
+    kubernetes.io/ingress.class: "gce" # an external load-balancer
+    kubernetes.io/ingress.allow-http: "false" # disabling HTTP
+    kubernetes.io/ingress.global-static-ip-name: todoapp-ip # staging-todoapp-ip for staging
+    networking.gke.io/managed-certificates: todoapp-managed-cert # defined in the infrastructure repository
+spec:
+  # rules:
+  # - http:
+  #     paths:
+  #     - path: /*
+  #       pathType: ImplementationSpecific
+  #       backend:
+  #         serviceName: todo-app-service
+  #         servicePort: 80
+  defaultBackend:
+    service:
+      name: todo-app-service
+      port:
+        number: 8080
diff --git a/app/k8s-manifests/secrets.yaml b/k8s-manifests/secrets.yaml
similarity index 78%
rename from app/k8s-manifests/secrets.yaml
rename to k8s-manifests/secrets.yaml
index 9097a62158fe9bcd8d67f77802123b0d176069fd..c61ce1a2dd0ce707d504b2ccb64d92130327c68a 100644
--- a/app/k8s-manifests/secrets.yaml
+++ b/k8s-manifests/secrets.yaml
@@ -1,7 +1,7 @@
 apiVersion: v1
 kind: Secret
 metadata:
-  name: app-secrets
+  name: todo-app-secrets
 type: Opaque
 data:
   JWT_SECRET: <jwt-secret in base64>
diff --git a/k8s-manifests/service.yaml b/k8s-manifests/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4a69e79411f9e844ef6c3bc223cb38081d5f3970
--- /dev/null
+++ b/k8s-manifests/service.yaml
@@ -0,0 +1,17 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: todo-app-service
+  annotations:
+    cloud.google.com/app-protocols: '{"https-port":"HTTPS","http-port":"HTTP"}'
+spec:
+  type: NodePort
+  selector:
+      app: todo-app
+  ports:
+    - name: https-port
+      port: 443
+      targetPort: 3000
+    - name: http-port
+      port: 8080
+      targetPort: 3000