diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b7c4877013dae500fc335b8abce2d59f54837540..dcab0fa811311fe185f38c2e659b000a34d4a2ee 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -53,11 +53,8 @@ test:
 light-deploy-testing:
   stage: deploy
   # only run when master is updated, unless the pipeline was triggered via the web UI
-  only:
-    - master
-  except:
-    - tags
-    - web
+  rules:
+    - if: ($CI_COMMIT_BRANCH == "master" && $MANUAL_FULL_DEPLOY !~ /true/ )
   <<: *ssh_setup
   environment: Testing
   script:
@@ -67,10 +64,8 @@ light-deploy-testing:
 light-deploy-production:
   stage: deploy
   # only run when stable tag is updated, unless the pipeline was triggered via the web UI
-  only:
-    - tags
-  except:
-    - web
+  rules:
+    - if: ($CI_COMMIT_TAG =~ /stable/ && $MANUAL_FULL_DEPLOY !~ /true/)
   tags: [stable]
   <<: *ssh_setup
   environment: Production
@@ -81,9 +76,8 @@ light-deploy-production:
 full-deploy-production:
   stage: deploy
   # only run when stable tag is assigned and the pipeline is triggered in the web UI
-  only:
-    - web
-    - tags
+  rules:
+     - if: ($CI_COMMIT_TAG =~ /stable/ && $MANUAL_FULL_DEPLOY == "true")
   <<: *ssh_setup
   environment: Production
   script:
@@ -108,9 +102,8 @@ full-deploy-production:
 full-deploy-testing:
   stage: deploy 
   # only run when master is updated and the pipeline is triggered in the web UI
-  only:
-    variables:
-      - ($CI_PIPELINE_SOURCE == "web" && $CI_COMMIT_REF_NAME == "master")
+  rules:
+    - if: ($CI_COMMIT_BRANCH == "master" && $MANUAL_FULL_DEPLOY == "true")
   <<: *ssh_setup
   environment: Testing
   script:
@@ -136,8 +129,8 @@ cleanup-failed-full-deployment:
   # this does not guarantee a successful rollback, but unless the old instance was faulty, this should work
   stage: cleanup
   when: on_failure
-  only:
-    - web
+  rules:
+     - if: $MANUAL_FULL_DEPLOY == "true"
   <<: *ssh_setup
   script:
     - echo "This is the cleanup for the full-redeployment of the testing or production servers"
@@ -172,8 +165,8 @@ cleanup-successful-full-deployment:
   # check if there is an old prod or test instance, and delete it if present
   stage: cleanup
   when: on_success
-  only:
-    - web
+  rules:
+     - if: $MANUAL_FULL_DEPLOY == "true"
   <<: *ssh_setup
   script:
     - echo "This is the cleanup for the full-redeployment of the testing or production servers"
@@ -186,11 +179,8 @@ cleanup-failed-light-test-deployment:
   # if there is a failure with the light deployments, this tries to git checkout an earlier version and rollback to that.
   stage: cleanup
   when: on_failure
-  only:
-    - master
-  except:
-    - tags
-    - web
+  rules:
+    - if: ($CI_COMMIT_BRANCH == "master" && $MANUAL_FULL_DEPLOY !~ /true/ )
   <<: *ssh_setup
   script:
     - echo "This is the cleanup for the light-redeployment of the testing servers"
@@ -205,10 +195,8 @@ cleanup-failed-light-production-deployment:
   # if there is a failure with the light deployments, this tries to git checkout an earlier version and rollback to that.
   stage: cleanup
   when: on_failure
-  only:
-    - tags
-  except:
-    - web
+  rules:
+    - if: ($CI_COMMIT_TAG =~ /stable/ && $MANUAL_FULL_DEPLOY !~ /true/)
   tags: [stable]
   <<: *ssh_setup
   script:
@@ -222,10 +210,9 @@ cleanup-failed-light-production-deployment:
 test-testing:
   cache: {}
   stage: test-deployment 
-  only:
-    - master
-  except:
-    - tags
+  when: on_failure
+  rules:
+    - if: $CI_COMMIT_BRANCH == "master"
   script:
     - apt update && apt -y install curl
     - echo "For now, this will be a basic health check i.e. GET / and check for 2xx code."
@@ -235,8 +222,8 @@ test-testing:
 test-production:
   cache: {}
   stage: test-deployment
-  only:
-    - tags
+  rules:
+    - if: $CI_COMMIT_TAG =~ /stable/
   tags: [stable]
   script:
     - apt update && apt -y install curl
diff --git a/README.md b/README.md
index 66380f1385ed64089733b8ed17e8d00af9ae0f3b..3f7e93e2956ea601aed8321db98505857427b63d 100644
--- a/README.md
+++ b/README.md
@@ -158,3 +158,11 @@ docker rm <container name>
 ```
 
 For more information about docker, please see the [docker docs](https://docs.docker.com)
+
+
+## CI/CD
+The gitlab repository is set up to automatically build the datacat image and deploy to the production and testing environment. The pipeline and jobs for this are defined in the [.gitlab-ci.yml](.gitlab-ci.yml) file.
+In general, pushes to the master branch update the testing deployment, and tags containing "stable" update the production deployment.
+
+To avoid unneeded downtime, the VMs hosting the deployments are usuallly not re-created, and instead only the updated docker image, as well as updated config is uploaded to the VM. After this, the docker containers are restarted.
+If a "full-deployment" is required (i.e. the VMs shuld be newly created), the pipeline has to be started with a variable ```MANUAL_FULL_DEPLOY=true```. This can be done while starting the pipeline via the web interface.
\ No newline at end of file