diff --git a/.ci/generateIndex.py b/.ci/generateIndex.py
index b09107308449bb917b322e95a5c8edb901ccf3e9..b60cac50d05d2ca84d52ab2c06884907f365b7a0 100644
--- a/.ci/generateIndex.py
+++ b/.ci/generateIndex.py
@@ -1,7 +1,9 @@
 import os, re
 from os import path
+from os.path import exists
 from natsort import natsorted
 from pathlib import Path
+import yaml
 
 def line_prepender(filename, line):
     with open(filename, 'r+') as f:
@@ -9,6 +11,16 @@ def line_prepender(filename, line):
         f.seek(0, 0)
         f.write(line.rstrip('\r\n') + '\n' + content)
 
+def get_subdirs(p):
+  for fname in os.listdir(p):
+    if os.path.isdir(os.path.join(p, fname)):
+      yield os.path.join(p, fname)
+
+def has_subdirs(p):
+  folders = list(get_subdirs(p))
+  return len(folders) != 0
+
+
 def build_link(title, href):
 
     # strip the number of the title
@@ -20,16 +32,13 @@ def build_link(title, href):
 
     return f'\t\t\t<li><a href="{href}">{title}</a></li>\n'
 
-def root_handbook(href):
+def root_href(href):
     # remove sym link reference in href
     if ('handbook-additional' in href):
         href = href.replace('handbook-additional', 'handbook').strip()
     elif ('handbook-annexes' in href):
         href = href.replace('handbook-annexes', 'handbook').strip()
 
-    return href
-
-def root_lab(href):
     # remove sym link reference in href
     if ('lab-software' in href):
         href = href.replace('lab-software', 'lab').strip()
@@ -37,6 +46,14 @@ def root_lab(href):
         href = href.replace('lab-equipment', 'lab').strip()
     elif ('lab-hsa' in href):
         href = href.replace('lab-hsa', 'lab').strip()
+    elif ('lab-integrity' in href):
+        href = href.replace('lab-integrity', 'lab').strip()
+
+    # remove sym link reference in href
+    if ('qms-policies' in href):
+        href = href.replace('qms-policies', 'qms').strip()
+    elif ('qms-sops' in href):
+        href = href.replace('qms-sops', 'qms').strip()
 
     return href
 
@@ -50,6 +67,9 @@ def build_section_start(title, shortcut):
     title = title.replace("Lab software", "Lab: Software")
     title = title.replace("Lab equipment", "Lab: Equipment")
     title = title.replace("Lab hsa", "Lab: Health & Safety, Access")
+    title = title.replace("Lab integrity", "Lab: Integrity")
+    title = title.replace("Qms sops", "QMS: Standard Operating Procedures (SOPS)")
+    title = title.replace("Qms policies", "QMS: Policies")
 
     return f'\n\t<div class="index-box noborderbox" id="{shortcut}-card">\n\t\t<h3>{title}</h3>\n\t\t<ul>\n'
 
@@ -62,12 +82,23 @@ def save_tag(localroot, root, filename, tag):
 
     length_tag = len(tag)
 
-    with open(filename, 'r') as f:
-        for line in f:
-            # check for the start of the section
-            if line[0:length_tag+1] == tag + ":":
-                return_tag = line[length_tag+2:]
-                break
+    if "yml" in filename:
+        with open(filename, "r") as stream:
+            try:
+                metadata = list(yaml.load_all(stream, Loader=yaml.FullLoader))
+            except yaml.YAMLError as exc:
+                print(exc)
+
+        return_tag = metadata[0][tag]
+
+    else:
+        with open(filename, 'r') as f:
+            for line in f:
+                # check for the start of the section
+                if line[0:length_tag+1] == tag + ":":
+                    return_tag = line[length_tag+2:]
+                    return_tag = return_tag.replace('"', '')
+                    break
 
     # change back to the local root
     os.chdir(localroot)
@@ -84,7 +115,8 @@ def get_ignore():
             "assets",
             "help.md",
             "index.md",
-            "pagination.md"
+            "pagination.md",
+            ".gitkeep",
             ]
 
 def save_legacy_from(localroot, root, filename):
@@ -149,7 +181,19 @@ def remove_header(localroot, root, filename):
 
     return n
 
-def generate_header(folder, permalink, shortcut, order, legacy_from, title, description):
+def element_header(prefix, permalink, element):
+
+    if (
+         ("handbook-annexes" in permalink or "handbook-additional" in permalink) or
+         ("lab-software" in permalink or "lab-equipment" in permalink or "lab-hsa" in permalink) or
+         ("qms-policies" in permalink or "qms-sops" in permalink)
+       ):
+        element += prefix + "/cards/" + root_href(shortcut) + "\n"
+        element += prefix + "/" + folder + "/cards/" + root_href(shortcut) + "\n"
+
+    return element
+
+def generate_header(folder, permalink, shortcut, order, legacy_from, title, description, qms_yml):
     header = "---\n"
 
     if len(order) > 0:
@@ -157,18 +201,13 @@ def generate_header(folder, permalink, shortcut, order, legacy_from, title, desc
 
     header += "layout: page\n"
     header += "permalink: " + permalink + "\n"
-    header += "shortcut: " + root_handbook(shortcut) + "\n"
+    header += "shortcut: " + root_href(shortcut) + "\n"
     header += "redirect_from:\n"
     header += "  - /cards/" + shortcut + "\n"
     header += "  - /" + folder + "/cards/" + shortcut + "\n"
-    # special case of handbook
-    if "handbook-annexes" in permalink or "handbook-additional" in permalink:
-        header += "  - /cards/" + root_handbook(shortcut) + "\n"
-        header += "  - /" + folder + "/cards/" + root_handbook(shortcut) + "\n"
-    # separate lab section
-    if "lab-software" in permalink or "lab-equipment" in permalink or "lab-hsa" in permalink:
-        header += "  - /cards/" + root_lab(shortcut) + "\n"
-        header += "  - /" + folder + "/cards/" + root_lab(shortcut) + "\n"
+
+    # generate specific redirects
+    header = element_header("  - ", shortcut, header)
 
     # include the legacy section in the redirect_from section
     if len(legacy_from) > 0:
@@ -188,6 +227,10 @@ def generate_header(folder, permalink, shortcut, order, legacy_from, title, desc
     else:
         header += "---"
 
+    # add title for QMS documents
+    if "qms" in shortcut and qms_yml:
+        header += "\n# " + title
+
     return header
 
 def generate_whitelist_entry(folder, permalink, shortcut):
@@ -195,16 +238,40 @@ def generate_whitelist_entry(folder, permalink, shortcut):
     wl_entry += "/?" + shortcut + "\n"
     wl_entry += "/cards/" + shortcut + "\n"
     wl_entry += "/" + folder + "/cards/" + shortcut + "\n"
-    if "handbook-annexes" in permalink or "handbook-additional" in permalink:
-        wl_entry += "/cards/" + root_handbook(shortcut) + "\n"
-        wl_entry += "/" + folder + "/cards/" + root_handbook(shortcut) + "\n"
-    # separate lab section
-    if "lab-software" in permalink or "lab-equipment" in permalink or "lab-hsa" in permalink:
-        wl_entry += "/cards/" + root_lab(shortcut) + "\n"
-        wl_entry += "/" + folder + "/cards/" + root_lab(shortcut) + "\n"
+
+    wl_entry = element_header("", permalink, wl_entry)
 
     return wl_entry
 
+def prepare_qms(localroot, root, filename):
+
+    os.chdir(root)
+
+    filedata = ""
+    with open(filename, 'r') as file :
+        for line in file:
+            filedata += line
+
+    # shift the subtitles by 1 level down
+    filedata = filedata.replace("# ", "## ")
+
+    # replace latex command for titles
+    filedata = filedata.replace("{-}", "##")
+
+    # deal with img location
+    filedata = filedata.replace("policies/"+filename[:-3]+"/", "")
+    filedata = filedata.replace("sops/"+filename[:-3]+"/", "")
+
+    # replace img attributes
+    filedata = filedata.replace("{ width=50% }", "")
+
+    # Write the file out again
+    with open(filename, 'w') as file:
+        file.write(filedata)
+
+    # change back to the local root
+    os.chdir(localroot)
+
 # loop through the entire internal tree
 localroot = os.getcwd()
 
@@ -212,17 +279,17 @@ localroot = os.getcwd()
 ignore = get_ignore()
 
 # generate the index properly speaking
-cardDirs = ["internal", "external", "policies"]
+cardDirs = ["internal", "external"]
 sections = []
 
 # determine first the directories
 for direct in cardDirs:
-    if path.isdir(direct):
+    if path.isdir(direct) and has_subdirs(direct):
         dirs = os.listdir(direct)
         dirs = natsorted(dirs)
 
         for d in dirs:
-            if d[0] != "." and d not in ignore:
+            if d[0] != "." and d not in ignore and has_subdirs(direct + "/" + d):
                 sections.append(d)
 
 sections = list(set(sections))
@@ -246,7 +313,7 @@ for folder in cardDirs:
         dirs = natsorted(dirs)
 
         for d in dirs:
-            if d[0] != "." and d not in ignore:
+            if d[0] != "." and d not in ignore and has_subdirs(folder + "/" + d):
                 # set the header of the section
                 #index += "\n### " + d.replace("-", " ").capitalize() + "\n"
 
@@ -273,6 +340,16 @@ for folder in cardDirs:
                                 title = save_tag(localroot, root, file, "title")
                                 description = save_tag(localroot, root, file, "description")
 
+                                # extract the title from the QMS metadata
+                                qms_yml = False
+                                if "qms" in root:
+                                    if exists(os.path.join(root, file[:-3] + ".yml")):
+                                        title = save_tag(localroot, root, file[:-3] + ".yml", "title")
+                                        prepare_qms(localroot, root, file)
+                                        qms_yml = True
+                                    else:
+                                        print("QMS document is not formatted properly.")
+
                                 # remove the previous header
                                 n = remove_header(localroot, root, file)
 
@@ -305,7 +382,7 @@ for folder in cardDirs:
                                     orderArr[indexS] = []
 
                                 # generate the header for each card
-                                header = generate_header(folder, permalink, shortcut, order, legacy_from, title, description)
+                                header = generate_header(folder, permalink, shortcut, order, legacy_from, title, description, qms_yml)
 
                                 # add autogenerated links to whitelist
                                 whiteList += generate_whitelist_entry(folder, permalink, shortcut)
@@ -314,23 +391,29 @@ for folder in cardDirs:
                                 line_prepender(fileName, header)
 
                                 # open file and get the title after the header
-                                count = 0
-                                title = ""
-                                bp = n + 1
-
-                                with open(fileName, 'r') as f:
-                                    for line in f:
-                                        count += 1
-                                        if count == bp:
-                                            if len(line) > 2:
-                                                title = line
-                                                break
-                                            else:
-                                                bp += 1
-
-                                # remove first and last chars
-                                title = title.rstrip("\n\r")
-                                title = title[2:]
+                                if "qms" in root:
+                                    header_offset = 3
+                                else:
+                                    header_offset = 1
+
+                                if not qms_yml:
+                                    count = 0
+                                    title = ""
+                                    bp = n + header_offset
+
+                                    with open(fileName, 'r') as f:
+                                        for line in f:
+                                            count += 1
+                                            if count == bp:
+                                                if len(line) > 2:
+                                                    title = line
+                                                    break
+                                                else:
+                                                    bp += 1
+
+                                    # remove first and last chars
+                                    title = title.rstrip("\n\r")
+                                    title = title[2:]
 
                                 localIndexArr[indexS].append(build_link(title, root))
 
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d960dae7c6d6b4728082dda94b7aae702a061a09..01a1a01873a9091267c14a74e8ea92a102680140 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -24,7 +24,7 @@ prepare:index:
     - if: $CI_COMMIT_REF_NAME
     - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_COMMIT_MESSAGE !~ /tmpBranch/ && $CI_COMMIT_MESSAGE !~ /Update index/'
   before_script:
-    - pip install natsort
+    - pip install -r requirements.txt
   script:
     - python .ci/generateIndex.py
     - mkdir .tmp
diff --git a/assets/js/box_hider.js b/assets/js/box_hider.js
index 48aa48bdb0009749a279c59ef4143a08cc858af6..bd20a7d4b6f34bac94d7a42bc5e398620a1c4805 100644
--- a/assets/js/box_hider.js
+++ b/assets/js/box_hider.js
@@ -24,7 +24,7 @@ window.boxHider = (function() {
     function GetSelectedBoxElement(id) {
         var allBoxesArray = GetAllBoxElementsArray();
         // note: handbook and lab are actually grouped sections
-        if (id.startsWith('handbook') || id.startsWith('lab')) {
+        if (id.startsWith('handbook') || id.startsWith('lab') || id.startsWith('qms')) {
             return true;
         } else {
             var element = document.getElementById(id);
@@ -96,6 +96,14 @@ window.boxHider = (function() {
                     ShowElement(box);
                 }
             });
+        } else if (boxId.startsWith('qms')) {
+            allBoxes.map(function(box) {
+                if (!box.id.startsWith('qms')) {
+                    HideElement(box);
+                } else {
+                    ShowElement(box);
+                }
+            });
         } else {
             allBoxes.map(function(box) {
                 if (box != selectedBox) {
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..594a2568e1ee92ed7e0e59b474401de45016b358
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,15 @@
+appnope~=0.1.2
+backcall~=0.2.0
+decorator~=5.1.0
+jedi~=0.18.1
+matplotlib-inline~=0.1.3
+natsort~=7.1.1
+parso~=0.8.3
+pexpect~=4.8.0
+pickleshare~=0.7.5
+prompt-toolkit~=3.0.24
+ptyprocess~=0.7.0
+Pygments~=2.10.0
+PyYAML~=6.0
+traitlets~=5.1.1
+wcwidth~=0.2.5