Repository: nautobot/nautobot-app-golden-config (language: python)

Issue:
Multiple golden config settings
### Proposed Functionality

Multiple GoldenConfigSetting instances

### Use Case

Increase Tenancy support in configuration management (ie. Team A of Customer A requires their firewall configs stored in Repository_1, Team B requires their DC configurations stored in Repository_2)

**Current Solution**:
Currently multiple repositories are attached to a global settings instance. This allows for only one scope to be defined and sophisticated assignment of devices per repositories.

**Solution Proposal**:
- **Allow for multiple GoldenConfigSetting model instances.**
- **Add weight parameter to GoldenConfigSetting models.**

- Preserve existing patterns:
  - Each device is dynamically resolved to maximum one GoldenConfigSetting instance via scope and weight. This is determined based on priorities where the first top match is used.
  - Minimised impact on existing UI views and complexity
  - Assume device is logically related to only one Backup, Intended and Jinja repository at a time

**Migration Path**
- GoldenConfigSetting (global) migrated to instance of GoldenConfigSetting called `default`



Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f3a2c824..2bd48518 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,15 +1,14 @@
 # Changelog
 
-## v1.0.0 - 2021-XX-XX
+## v1.0.0 - 2022-XX-XX
 
 ### Added
 
-- GoldenConfigSettings enforces a `template path` be provided if more than 1 backup or intended repository is configured.
-- Updated backup job to execute against multiple repos if available based on pattern matching.
-- Updated intended job to execute against multiple repos if available based on pattern matching.
-- Updated compliance job to execute from multiple repos if available based on pattern matching.
 - Added utility function to determine the local filesystem path which stores the backup and intended repository files for a given device.
 
+### Changed
+- [#205](https://github.com/nautobot/nautobot-plugin-golden-config/pull/205) - Multiple Golden Config Settings allows for multiple instances of the plugin settings
+
 ## v0.9.10 - 2021-11
 
 ### Announcements
diff --git a/README.md b/README.md
index a24dc41f..44c11bc0 100644
--- a/README.md
+++ b/README.md
@@ -34,6 +34,8 @@ but not want to use other features, which is perfectly fine to do so.
 - [Navigating JSON Compliance](./docs/navigating-compliance-json.md)
 - [Navigating Custom Compliance](./docs/navigating-compliance-custom.md)
 - [FAQ](./docs/FAQ.md)
+- [Upgrade Notes](./docs/upgrade.md)
+
 
 ## Screenshots
 
diff --git a/docs/img/navigate-compliance-rules.png b/docs/img/navigate-compliance-rules.png
index da8e609f..7d5cb0dd 100644
Binary files a/docs/img/navigate-compliance-rules.png and b/docs/img/navigate-compliance-rules.png differ
diff --git a/docs/installation.md b/docs/installation.md
index 74b9ddf8..77f9178c 100644
--- a/docs/installation.md
+++ b/docs/installation.md
@@ -41,7 +41,7 @@ PLUGINS_CONFIG = {
 
 ```
 
-## Plugin Settings
+## Plugin Configuration
 
 The plugin behavior can be controlled with the following list of settings. 
 
diff --git a/docs/navigating-backup.md b/docs/navigating-backup.md
index 2571bbce..06e31a36 100644
--- a/docs/navigating-backup.md
+++ b/docs/navigating-backup.md
@@ -21,65 +21,10 @@ uses cases, the following settings are available and further documented below.
 
 ### Backup Repositories
 
-In the `Backup Repositories` field of the UI, configure all of the repositories which you intend to use for backed-up device configurations as part of Golden Config.
+In the `Backup Repository` field of the Settings, configure the repository which you intend to use for backed-up device configurations as part of Golden Config.
 
 Backup repositories must first be configured under **Extensibility -> Git Repositories**. When you configure a repository, look for the `Provides` field in the UI. To serve as a configuration backup store, the repository must be configured with the `backup configs` capability under the `Provides` field. For further details, refer to [Navigating Nautobot Git Settings](./navigating-golden.md#git-settings).
 
-### Backup Repository Matching Rule
-
-.. Note::
-    Only use a Backup Repository Matching Rule if you have **more than one** backup repository. It is not needed if you only have one, and will cause backup failures for any devices which do not match the rule. The setting is mandatory if you have more than one repository.
-
-The `backup_match_rule` setting allows you to match a given `Device` Django ORM object to a backup Git repository. This field should contain a Jinja2-formatted template. The plugin populates the variables in the Jinja2 template via the GraphQL query configured on the plugin.
-
-Say that in your environment you have three regions in which your devices reside: North America, Asia Pacific, and Africa. You have populated these values as `Region` objects in Nautobot, and assigned a `Region` value to each of your devices. You want your backup solution to scale well, so you have a dedicated backup Git repository for each region. Every Nautobot object has a `slug` (URL compatible) name in addition to its human-friendly name; our regions' slugs are `north-america`, `asia-pacific`, and `africa`. To configure the plugin to match devices to the desired Git repository, you must first configure the GraphQL query; a _VERY_ simple one might look like this:
-```
-query ($device_id: ID!) {
-  device(id: $device_id) {
-    config_context
-    hostname: name
-    platform {
-      manufacturer {
-        name
-      }
-      name
-      napalm_driver
-      slug
-    }
-    primary_ip4 {
-      address
-      interface {
-        name
-      }
-      id
-    }
-    site {
-      name
-      region {
-        name
-        slug
-      }
-      slug
-    }
-  }
-}
-```
-
-The query will look at the `Device` ORM object, and return the values from the query as keys under the top-level `obj` key. The `obj` key represents the Device object. With this GraphQL query, we can make a Jinja2 template to translate the returned values into a string. For example, say that you have a device which is in your Sydney, AU office, which is in the `asia-pacific` region in Nautobot. If you made a Jinja2 template based on that, which looked like this:
-
-```
-{{obj.site.region.slug}}
-```
-Then the template would be rendered to the string:
-```
-asia-pacific
-```
-
-When you create backup repositories, pay attention to your naming scheme. You should name each repository in a way that matches the value of whatever parameter from the Device object which you wish to use to sort devices into repositories. So, for our Sydney device above, it would work to name your Asia Pacific repository something "Asia Pacific Device Backups". This would give it a `slug` value of `asia-pacific-device-backups`, and you could use this in a backup repository matching rule with a template like this:
-
-```
-{{obj.site.region.slug}}-device-backups
-```
 
 ### Backup Path Template
 
diff --git a/docs/navigating-golden.md b/docs/navigating-golden.md
index 3a4258d1..bff8621e 100644
--- a/docs/navigating-golden.md
+++ b/docs/navigating-golden.md
@@ -36,19 +36,24 @@ Each Job attempts to provide sane error handling, and respects the `debug` flag
 
 ## Application Settings
 
-The golden configuration plugin settings can be found by navigating to `Plugins -> Settings` button. Under the `Golden Configuration` section.
+The golden configuration plugin settings can be found by navigating to `Plugins -> Settings` button. Select one of the Settings, under the `Golden Configuration` section.
+Since Golden Configuration Plugin version 1.0, the plugin allows for multiple settings to be configured by the User.
+Each of the settings, has the individual repositories and configuration details, as well as the scope.
+You could use a combination of settings to customize Your Configuration Compliance behaviour.
+Settings have a name and a weight. The weight parameter indicates the priority of given Settings - the higher the weight, the device matching the scope defined will be assigned to the scope.
+At the same moment, each device will be matched up to maximum of only one `Settings.` In case of the same weight, the sorting is performed by the name.
 
 ![Navigate to Settings](./img/navigate-compliance-rules.png)
 
-To configure or update the settings click the pencil icon to edit.
+To create new settings click on the `+Add` button.
+To update existing settings click on one of the `Settings` name.
+
 
 |Setting|Explanation|
 |:--|:--|
-|Backup Repositories |One or more Git repositories where your backup configurations will be found. |
-|Backup Repository Matching Rule |A Jinja template to match a device to a backup repositories `slug` value. Required if you configure more than one backup repository. E.g. `my-backup-repo-{{obj.site.region.slug}}` |
+|Backup Repositories |The Git Repository where your backup configurations will be found. |
 |Backup Path|A Jinja template which defines the path and name of backup files within the backup repository. The variable `obj` is available as the device instance object of a given device, as is the case for all Jinja templates. e.g. `{{obj.site.slug}}/{{obj.name}}.cfg`|
-|Intended Repositories |One or more Git repository where your intended configuration state files will be found. |
-|Intended Repository Matching Rule |A Jinja template to match a device to an intended state repository's `slug` value. Required if you configure more than one intended repository. E.g. `best-of-intentions-repo-{{obj.site.region.slug}}` |
+|Intended Repositories |The Git Repository where your intended configuration state files will be found. |
 |Intended Path|A Jinja template which defines the path and name of intended configuration state files within the intended state repository. e.g. `{{obj.site.slug}}/{{obj.name}}.intended_cfg`|
 |Jinja Repository |The Git Repository where your jinja templates will be found. |
 |Jinja Path|A Jinja template which defines the path (within the repository) and name of the Jinja template file. e.g. `{{obj.platform.slug}}/{{obj.role.slug}}/main.j2`|
diff --git a/docs/navigating-intended.md b/docs/navigating-intended.md
index bade01a1..7a02790b 100644
--- a/docs/navigating-intended.md
+++ b/docs/navigating-intended.md
@@ -2,7 +2,7 @@
 
 ## Configuration Generation
 
-The Golden Config plugin **Intended Configuration** job generates intended state files for each device in the plugin's configured scope. An intended state file contains the output from rendering the device's Source of Truth Aggregation values through the Jinja templates used by the plugin.
+The Golden Config plugin **Intended Configuration** job generates intended state files for each device in the plugin setting's configured scope. An intended state file contains the output from rendering the device's Source of Truth Aggregation values through the Jinja templates used by the plugin.
 
 The job itself is a Nornir play which uses a single Jinja template per device. Source of Truth Aggregation data comes from the GraphQL query configured in the Golden Config plugin's settings. An important component of the SoT Aggregation data are the `config_context` values. `config_context` should contain a vendor-neutral, JSON structured representation of a device's configuration values: a list of NTP/AAA/Syslog servers, common VRFs, etc. See [Config Contexts](https://nautobot.readthedocs.io/en/latest/additional-features/config-contexts/#configuration-contexts) for more information. 
 
diff --git a/docs/quick-start.md b/docs/quick-start.md
index fda9437b..ee3030d2 100644
--- a/docs/quick-start.md
+++ b/docs/quick-start.md
@@ -17,13 +17,14 @@ Follow the steps below to get up and running for the configuration backup elemen
    3. Make sure to select the **Provides** called `backup configs`.
    4. Click Create.
 
-3. Next, make sure to update the Plugins **Settings** with the backup details.
+3. Next, make sure to create new or update existing Plugins **Settings** with the backup details.
 
    1. Navigate to `Plugins -> Settings` under the Golden Configuration Section.
-   2. Fill out the Backup Repository. (The dropdown will show the repository that was just created.)
-   3. Fill out Backup Path Template. Typically `{{obj.site.slug}}/{{obj.name}}.cfg`, see [Setting Details](./navigating-golden.md#application-settings)
-   4. Select whether or not to do a connectivity check per device.
-   5. Click Save.
+   2. Create new or select one of the existing `Settings` objects
+   3. Fill out the Backup Repository. (The dropdown will show the repository that was just created.)
+   4. Fill out Backup Path Template. Typically `{{obj.site.slug}}/{{obj.name}}.cfg`, see [Setting Details](./navigating-golden.md#application-settings)
+   5. Select whether or not to do a connectivity check per device.
+   6. Click Save.
 
 4. Create Configuration Removals and Replacements.
 
@@ -61,13 +62,14 @@ Follow the steps below to get up and running for the intended configuration elem
    3. Make sure to select the **Provides** called `jinja templates`.
    4. Click Create.
 
-4. Next, make sure to update the Plugins **Settings** with the intended and jinja2 template details.
+4. Next, make sure to create new or update existing Plugins **Settings** with the intended and jinja2 template details.
 
    1. Navigate to `Plugins -> Settings` under the Golden Configuration Section.
-   2. Fill out the Intended Repository. (The dropdown will show the repository that was just created.)
-   3. Fill out Intended Path Template. Typically `{{obj.site.slug}}/{{obj.name}}.cfg`, see [Setting Details](./navigating-golden.md#application-settings)
-   4. Fill out Jinja Repository. (The dropdown will show the repository that was just created.)
-   5. Fill out Jinja Path Template. Typically `{{obj.platform.slug}}.j2`.
+   2. Create new or select one of the existing `Settings` objects
+   3. Fill out the Intended Repository. (The dropdown will show the repository that was just created.)
+   4. Fill out Intended Path Template. Typically `{{obj.site.slug}}/{{obj.name}}.cfg`, see [Setting Details](./navigating-golden.md#application-settings)
+   5. Fill out Jinja Repository. (The dropdown will show the repository that was just created.)
+   6. Fill out Jinja Path Template.  Typically `{{obj.platform.slug}}.j2`.
 
 5. Determine what data(variables) the Jinja2 templates need from Nautobot.
 
diff --git a/docs/upgrade.md b/docs/upgrade.md
new file mode 100644
index 00000000..c01f9f3c
--- /dev/null
+++ b/docs/upgrade.md
@@ -0,0 +1,10 @@
+# Upgrade
+
+When a new release comes out it may be necessary to run a migration of the database to account for any changes in the data models used by this plugin. Execute the command nautobot-server migrate from the Nautobot install nautobot/ directory after updating the package.
+
+## v1.0.0
+v1.0.0 Provides a breaking change for the users running pre 1.0.0 code sourced from `develop` branch of the plugin. Only users of the `Backup Repository Matching Rule` and `Intended Repository Matching Rule` features are affected by following behaviour: migration script will only migrate the first repository from the list into the new default settings.
+ 
+Because of this specific behaviour, please review your configuration and capture it before attempting to upgrade if using above features.
+
+Users running the released packages are not affected by this behaviour.
diff --git a/nautobot_golden_config/api/serializers.py b/nautobot_golden_config/api/serializers.py
index a92c6364..0546fc67 100644
--- a/nautobot_golden_config/api/serializers.py
+++ b/nautobot_golden_config/api/serializers.py
@@ -75,33 +75,6 @@ class Meta:
         model = models.GoldenConfigSetting
         fields = "__all__"
 
-    def validate(self, data):
-        """Verify that the values in the GoldenConfigSetting API call make sense."""
-        validation_error_list = []
-
-        if len(data["backup_repository"]) == 1 and data["backup_match_rule"]:
-            validation_error_list.append(
-                "If you configure only one backup repository, do not enter the backup repository matching rule template."
-            )
-        elif len(data["backup_repository"]) > 1 and not data["backup_match_rule"]:
-            validation_error_list.append(
-                "If you specify more than one backup repository, you must provide the backup repository matching rule template."
-            )
-
-        if len(data["intended_repository"]) == 1 and data["intended_match_rule"]:
-            validation_error_list.append(
-                "If you configure only one intended repository, do not enter the intended repository matching rule template."
-            )
-        elif len(data["intended_repository"]) > 1 and not data["intended_match_rule"]:
-            validation_error_list.append(
-                "If you specify more than one intended repository, you must provide the intended repository matching rule template."
-            )
-
-        if validation_error_list:
-            raise serializers.ValidationError(validation_error_list)
-
-        return data
-
 
 class ConfigRemoveSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
     """Serializer for ConfigRemove object."""
diff --git a/nautobot_golden_config/api/views.py b/nautobot_golden_config/api/views.py
index 1da1d40f..6604c3ac 100644
--- a/nautobot_golden_config/api/views.py
+++ b/nautobot_golden_config/api/views.py
@@ -12,6 +12,7 @@
 from nautobot_golden_config import models
 from nautobot_golden_config import filters
 from nautobot_golden_config.utilities.graphql import graph_ql_query
+from nautobot_golden_config.utilities.helper import get_device_to_settings_map
 
 
 class GoldenConfigRootView(APIRootView):
@@ -30,8 +31,8 @@ class SOTAggDeviceDetailView(APIView):
     def get(self, request, *args, **kwargs):
         """Get method serialize for a dictionary to json response."""
         device = Device.objects.get(pk=kwargs["pk"])
-        global_settings = models.GoldenConfigSetting.objects.first()
-        status_code, data = graph_ql_query(request, device, global_settings.sot_agg_query)
+        settings = get_device_to_settings_map(queryset=Device.objects.filter(pk=device.pk))[device]
+        status_code, data = graph_ql_query(request, device, settings.sot_agg_query)
         data = json.loads(json.dumps(data))
         return Response(serializers.GraphQLSerializer(data=data).initial_data, status=status_code)
 
diff --git a/nautobot_golden_config/forms.py b/nautobot_golden_config/forms.py
index 90b4feb5..11088cb7 100644
--- a/nautobot_golden_config/forms.py
+++ b/nautobot_golden_config/forms.py
@@ -6,13 +6,11 @@
 import nautobot.utilities.forms as utilities_forms
 from nautobot.dcim.models import Device, Platform, Region, Site, DeviceRole, DeviceType, Manufacturer, Rack, RackGroup
 from nautobot.extras.models import Status
-from nautobot.extras.models import GitRepository
 from nautobot.tenancy.models import Tenant, TenantGroup
-from nautobot.utilities.forms import StaticSelect2Multiple, SlugField
+from nautobot.utilities.forms import SlugField
 
 
 from nautobot_golden_config import models
-from nautobot_golden_config.utilities.helper import clean_config_settings
 
 # ConfigCompliance
 
@@ -336,25 +334,20 @@ class GoldenConfigSettingFeatureForm(
 ):
     """Filter Form for GoldenConfigSettingFeatureForm instances."""
 
-    backup_repository = forms.ModelMultipleChoiceField(
-        queryset=GitRepository.objects.filter(provided_contents__contains="nautobot_golden_config.backupconfigs"),
-        widget=StaticSelect2Multiple(),
-    )
-    intended_repository = forms.ModelMultipleChoiceField(
-        queryset=GitRepository.objects.filter(provided_contents__contains="nautobot_golden_config.intendedconfigs"),
-        widget=StaticSelect2Multiple(),
-    )
+    slug = SlugField()
 
     class Meta:
         """Filter Form Meta Data for GoldenConfigSettingFeatureForm instances."""
 
         model = models.GoldenConfigSetting
         fields = (
+            "name",
+            "slug",
+            "weight",
+            "description",
             "backup_repository",
-            "backup_match_rule",
             "backup_path_template",
             "intended_repository",
-            "intended_match_rule",
             "intended_path_template",
             "jinja_repository",
             "jinja_path_template",
@@ -362,15 +355,3 @@ class Meta:
             "scope",
             "sot_agg_query",
         )
-
-    def clean(self):
-        """Clean."""
-        super().clean()
-        # This custom clean function validates logic of when or when not to
-        # have a template matching path in GlobalConfigSettings for repos.
-        for repo_type in ["intended", "backup"]:
-            clean_config_settings(
-                repo_type=repo_type,
-                repo_count=self.cleaned_data.get(f"{repo_type}_repository").count(),
-                match_rule=self.cleaned_data.get(f"{repo_type}_match_rule"),
-            )
diff --git a/nautobot_golden_config/jobs.py b/nautobot_golden_config/jobs.py
index 5c14de63..c291d341 100644
--- a/nautobot_golden_config/jobs.py
+++ b/nautobot_golden_config/jobs.py
@@ -22,18 +22,19 @@
 name = "Golden Configuration"  # pylint: disable=invalid-name
 
 
-def git_wrapper(obj, repository_record, git_type):
+def get_refreshed_repos(job_obj, repo_type):
     """Small wrapper to pull latest branch, and return a GitRepo plugin specific object."""
-    if not repository_record:
-        obj.log_failure(
-            obj,
-            f"FATAL ERROR: There is not a valid Git repositories for Git type {git_type}, please see pre-requisite instructions to configure an appropriate Git repositories.",
-        )
-        raise  # pylint: disable=misplaced-bare-raise
+    repository_records = set(
+        getattr(gcs, repo_type) for gcs in GoldenConfigSetting.objects.all() if getattr(gcs, repo_type, None)
+    )
 
-    ensure_git_repository(repository_record, obj.job_result)
-    git_repo = GitRepo(repository_record)
-    return git_repo
+    repositories = []
+    for repository_record in repository_records:
+        ensure_git_repository(repository_record, job_obj.job_result)
+        git_repo = GitRepo(repository_record)
+        repositories.append(git_repo)
+
+    return repositories
 
 
 def commit_check(method):
@@ -96,11 +97,8 @@ def run(self, data, commit):  # pylint: disable=too-many-branches
         """Run config compliance report script."""
         # pylint: disable=unused-argument
 
-        _ = [
-            git_wrapper(self, repo, "intended")
-            for repo in GoldenConfigSetting.objects.first().intended_repository.all()
-        ]
-        _ = [git_wrapper(self, repo, "backup") for repo in GoldenConfigSetting.objects.first().backup_repository.all()]
+        get_refreshed_repos(job_obj=self, repo_type="intended_repository")
+        get_refreshed_repos(job_obj=self, repo_type="backup_repository")
 
         config_compliance(self, data)
 
@@ -133,16 +131,15 @@ def run(self, data, commit):
         """Run config generation script."""
         now = datetime.now()
 
-        LOGGER.debug("Pull Jinja template repo.")
-        jinja_repo = git_wrapper(self, GoldenConfigSetting.objects.first().jinja_repository, "jinja")
+        LOGGER.debug("Pull Jinja template repos.")
+        get_refreshed_repos(job_obj=self, repo_type="jinja_repository")
 
-        LOGGER.debug("Pull Intended config repo.")
-        golden_config = GoldenConfigSetting.objects.first()
+        LOGGER.debug("Pull Intended config repos.")
         # Instantiate a GitRepo object for each GitRepository in GoldenConfigSettings.
-        intended_repos = [git_wrapper(self, repo, "intended") for repo in golden_config.intended_repository.all()]
+        intended_repos = get_refreshed_repos(job_obj=self, repo_type="intended_repository")
 
         LOGGER.debug("Run config intended nornir play.")
-        config_intended(self, data, jinja_repo.path)
+        config_intended(self, data)
 
         # Commit / Push each repo after job is completed.
         for intended_repo in intended_repos:
@@ -179,10 +176,10 @@ def run(self, data, commit):
         """Run config backup process."""
         now = datetime.now()
         LOGGER.debug("Pull Backup config repo.")
-        golden_settings = GoldenConfigSetting.objects.first()
 
         # Instantiate a GitRepo object for each GitRepository in GoldenConfigSettings.
-        backup_repos = [git_wrapper(self, repo, "backup") for repo in golden_settings.backup_repository.all()]
+        backup_repos = get_refreshed_repos(job_obj=self, repo_type="backup_repository")
+
         LOGGER.debug("Starting backup jobs to the following repos: %s", backup_repos)
 
         LOGGER.debug("Run nornir play.")
diff --git a/nautobot_golden_config/migrations/0009_multiple_gc_settings.py b/nautobot_golden_config/migrations/0009_multiple_gc_settings.py
new file mode 100644
index 00000000..703371a9
--- /dev/null
+++ b/nautobot_golden_config/migrations/0009_multiple_gc_settings.py
@@ -0,0 +1,123 @@
+# Generated by Django 3.1.14 on 2022-02-04 09:52
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+def convert_many_repos_part1(apps, schema_editor):
+    """
+    Add the current `backup_repository` and `intended_repository` objects values
+    to the `FK` additional intermediary attritbute to retain data.`
+    """
+    GoldenConfigSetting = apps.get_model("nautobot_golden_config", "GoldenConfigSetting")
+
+    settings_obj = GoldenConfigSetting.objects.first()
+
+    if settings_obj.backup_repository:
+        settings_obj.backup_repository_tmp = settings_obj.backup_repository.first()
+        settings_obj.save()
+
+    if settings_obj.intended_repository:
+        settings_obj.intended_repository_tmp = settings_obj.intended_repository.first()
+        settings_obj.save()
+
+
+def convert_many_repos_part2(apps, schema_editor):
+    """
+    Add the current `backup_repository_tmp` and `intended_repository_tmp` object values
+    to the FKs final attributes to retain data.`
+    """
+    GoldenConfigSetting = apps.get_model("nautobot_golden_config", "GoldenConfigSetting")
+
+    settings_obj = GoldenConfigSetting.objects.first()
+
+    if settings_obj.backup_repository_tmp:
+        settings_obj.backup_repository = settings_obj.backup_repository_tmp
+        settings_obj.save()
+
+    if settings_obj.intended_repository_tmp:
+        settings_obj.intended_repository = settings_obj.intended_repository_tmp
+        settings_obj.save()
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('extras', '0018_joblog_data_migration'),
+        ('nautobot_golden_config', '0008_multi_repo_support_final'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='goldenconfigsetting',
+            options={'ordering': ['-weight', 'name'], 'verbose_name': 'Golden Config Setting'},
+        ),
+        migrations.RemoveField(
+            model_name='goldenconfigsetting',
+            name='backup_match_rule',
+        ),
+        migrations.RemoveField(
+            model_name='goldenconfigsetting',
+            name='intended_match_rule',
+        ),
+        migrations.AddField(
+            model_name='goldenconfigsetting',
+            name='description',
+            field=models.CharField(blank=True, max_length=200),
+        ),
+        migrations.AddField(
+            model_name='goldenconfigsetting',
+            name='name',
+            field=models.CharField(default='Default Settings', max_length=100, unique=True),
+            preserve_default=False,
+        ),
+        migrations.AddField(
+            model_name='goldenconfigsetting',
+            name='slug',
+            field=models.SlugField(default='default', max_length=100, unique=True),
+            preserve_default=False,
+        ),
+        migrations.AddField(
+            model_name='goldenconfigsetting',
+            name='weight',
+            field=models.PositiveSmallIntegerField(default=1000),
+        ),
+        migrations.AddField(
+            model_name='goldenconfigsetting',
+            name='backup_repository_tmp',
+            field=models.ForeignKey(blank=True, limit_choices_to={'provided_contents__contains': 'nautobot_golden_config.backupconfigs'}, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='backup_repository', to='extras.gitrepository'),
+        ),
+        migrations.AddField(
+            model_name='goldenconfigsetting',
+            name='intended_repository_tmp',
+            field=models.ForeignKey(blank=True, limit_choices_to={'provided_contents__contains': 'nautobot_golden_config.intendedconfigs'}, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='intended_repository', to='extras.gitrepository'),
+        ),
+        migrations.RunPython(convert_many_repos_part1),
+        migrations.RemoveField(
+            model_name='goldenconfigsetting',
+            name='backup_repository',
+        ),
+        migrations.RemoveField(
+            model_name='goldenconfigsetting',
+            name='intended_repository',
+        ),
+        migrations.AddField(
+            model_name='goldenconfigsetting',
+            name='backup_repository',
+            field=models.ForeignKey(blank=True, limit_choices_to={'provided_contents__contains': 'nautobot_golden_config.backupconfigs'}, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='backup_repository', to='extras.gitrepository'),
+        ),
+        migrations.AddField(
+            model_name='goldenconfigsetting',
+            name='intended_repository',
+            field=models.ForeignKey(blank=True, limit_choices_to={'provided_contents__contains': 'nautobot_golden_config.intendedconfigs'}, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='intended_repository', to='extras.gitrepository'),
+        ),
+        migrations.RunPython(convert_many_repos_part2),
+        migrations.RemoveField(
+            model_name='goldenconfigsetting',
+            name='backup_repository_tmp',
+        ),
+        migrations.RemoveField(
+            model_name='goldenconfigsetting',
+            name='intended_repository_tmp',
+        ),
+    ]
diff --git a/nautobot_golden_config/models.py b/nautobot_golden_config/models.py
index 2b3a8a36..dd39978d 100644
--- a/nautobot_golden_config/models.py
+++ b/nautobot_golden_config/models.py
@@ -416,19 +416,21 @@ def __str__(self):
 class GoldenConfigSetting(PrimaryModel):
     """GoldenConfigSetting Model defintion. This provides global configs instead of via configs.py."""
 
-    backup_repository = models.ManyToManyField(
+    name = models.CharField(max_length=100, unique=True, blank=False)
+    slug = models.SlugField(max_length=100, unique=True, blank=False)
+    weight = models.PositiveSmallIntegerField(default=1000, blank=False)
+    description = models.CharField(
+        max_length=200,
+        blank=True,
+    )
+    backup_repository = models.ForeignKey(
         to="extras.GitRepository",
+        on_delete=models.SET_NULL,
+        null=True,
         blank=True,
         related_name="backup_repository",
         limit_choices_to={"provided_contents__contains": "nautobot_golden_config.backupconfigs"},
     )
-    backup_match_rule = models.CharField(
-        max_length=255,
-        null=False,
-        blank=True,
-        verbose_name="Rule to match a device to a Backup Repository.",
-        help_text="The Jinja path representation of a Backup Repository slug. The variable `obj` is available as the device instance object of a given device, as is the case for all Jinja templates. e.g. `backup-{{obj.site.region.slug}}`",
-    )
     backup_path_template = models.CharField(
         max_length=255,
         null=False,
@@ -436,19 +438,14 @@ class GoldenConfigSetting(PrimaryModel):
         verbose_name="Backup Path in Jinja Template Form",
         help_text="The Jinja path representation of where the backup file will be found. The variable `obj` is available as the device instance object of a given device, as is the case for all Jinja templates. e.g. `{{obj.site.slug}}/{{obj.name}}.cfg`",
     )
-    intended_repository = models.ManyToManyField(
+    intended_repository = models.ForeignKey(
         to="extras.GitRepository",
+        on_delete=models.SET_NULL,
+        null=True,
         blank=True,
         related_name="intended_repository",
         limit_choices_to={"provided_contents__contains": "nautobot_golden_config.intendedconfigs"},
     )
-    intended_match_rule = models.CharField(
-        max_length=255,
-        null=False,
-        blank=True,
-        verbose_name="Rule to match a device to an Intended Repository.",
-        help_text="The Jinja path representation of a Intended Repository slug. The variable `obj` is available as the device instance object of a given device, as is the case for all Jinja templates. e.g. `intended-{{obj.site.region.slug}}`",
-    )
     intended_path_template = models.CharField(
         max_length=255,
         null=False,
@@ -492,29 +489,25 @@ class GoldenConfigSetting(PrimaryModel):
 
     def get_absolute_url(self):  # pylint: disable=no-self-use
         """Return absolute URL for instance."""
-        return reverse("plugins:nautobot_golden_config:goldenconfigsetting")
+        return reverse("plugins:nautobot_golden_config:goldenconfigsetting", args=[self.slug])
 
     def __str__(self):
         """Return a simple string if model is called."""
-        return "Configuration Object"
-
-    def delete(self, *args, **kwargs):
-        """Enforce the singleton pattern, there is no way to delete the configurations."""
+        return f"Golden Config Setting - {self.name}"
 
     class Meta:
-        """Set unique fields for model."""
+        """Set unique fields for model.
 
-        verbose_name = "Golden Config Setting"
+        Provide ordering used in tables and get_device_to_settings_map.
+        Sorting on weight is performed from the highest weight value to the lowest weight value.
+        This is to ensure only one plugin settings could be applied per single device based on priority and name.
+        """
 
-    @classmethod
-    def load(cls):
-        """Enforce the singleton pattern, fail it somehow more than one instance."""
-        if len(cls.objects.all()) != 1:
-            raise ValidationError("There was an error where more than one instance existed for a setting.")
-        return cls.objects.first()
+        verbose_name = "Golden Config Setting"
+        ordering = ["-weight", "name"]  # Refer to weight comment in class docstring.
 
     def clean(self):
-        """Validate there is only one model and if there is a GraphQL query, that it is valid."""
+        """Validate the scope and GraphQL query."""
         super().clean()
 
         if self.sot_agg_query:
diff --git a/nautobot_golden_config/navigation.py b/nautobot_golden_config/navigation.py
index 7591b172..5f668fc9 100644
--- a/nautobot_golden_config/navigation.py
+++ b/nautobot_golden_config/navigation.py
@@ -90,16 +90,16 @@
 
 plugin_items.append(
     PluginMenuItem(
-        link="plugins:nautobot_golden_config:goldenconfigsetting",
+        link="plugins:nautobot_golden_config:goldenconfigsetting_list",
         link_text="Settings",
-        permissions=["nautobot_golden_config.view_compliancereplace"],
+        permissions=["nautobot_golden_config.view_goldenconfigsetting"],
         buttons=(
             PluginMenuButton(
-                link="plugins:nautobot_golden_config:goldenconfigsetting_edit",
-                title="Golden Config Settings",
-                icon_class="mdi mdi-pencil",
-                color=ButtonColorChoices.YELLOW,
-                permissions=["nautobot_golden_config.edit_goldenconfigsetting"],
+                link="plugins:nautobot_golden_config:goldenconfigsetting_add",
+                title="Add",
+                icon_class="mdi mdi-plus-thick",
+                color=ButtonColorChoices.GREEN,
+                permissions=["nautobot_golden_config.change_goldenconfigsetting"],
             ),
         ),
     ),
diff --git a/nautobot_golden_config/nornir_plays/config_backup.py b/nautobot_golden_config/nornir_plays/config_backup.py
index 8cd9b8f8..6e73450d 100644
--- a/nautobot_golden_config/nornir_plays/config_backup.py
+++ b/nautobot_golden_config/nornir_plays/config_backup.py
@@ -16,13 +16,12 @@
 
 
 from nautobot_golden_config.utilities.helper import (
+    get_device_to_settings_map,
     get_job_filter,
-    get_repository_working_dir,
-    verify_global_settings,
+    verify_settings,
     render_jinja_template,
 )
 from nautobot_golden_config.models import (
-    GoldenConfigSetting,
     GoldenConfig,
     ConfigRemove,
     ConfigReplace,
@@ -33,7 +32,7 @@
 
 
 def run_backup(  # pylint: disable=too-many-arguments
-    task: Task, logger, global_settings, remove_regex_dict, replace_regex_dict
+    task: Task, logger, device_to_settings_map, remove_regex_dict, replace_regex_dict
 ) -> Result:
     r"""Backup configurations to disk.
 
@@ -46,6 +45,7 @@ def run_backup(  # pylint: disable=too-many-arguments
         result (Result): Result from Nornir task
     """
     obj = task.host.data["obj"]
+    settings = device_to_settings_map[obj.id]
 
     backup_obj = GoldenConfig.objects.filter(device=obj).first()
     if not backup_obj:
@@ -55,11 +55,11 @@ def run_backup(  # pylint: disable=too-many-arguments
     backup_obj.backup_last_attempt_date = task.host.defaults.data["now"]
     backup_obj.save()
 
-    backup_directory = get_repository_working_dir("backup", obj, logger, global_settings)
-    backup_path_template_obj = render_jinja_template(obj, logger, global_settings.backup_path_template)
+    backup_directory = settings.backup_repository.filesystem_path
+    backup_path_template_obj = render_jinja_template(obj, logger, settings.backup_path_template)
     backup_file = os.path.join(backup_directory, backup_path_template_obj)
 
-    if global_settings.backup_test_connectivity is not False:
+    if settings.backup_test_connectivity is not False:
         task.run(
             task=dispatcher,
             name="TEST CONNECTIVITY",
@@ -93,8 +93,12 @@ def config_backup(job_result, data):
     """Nornir play to backup configurations."""
     now = datetime.now()
     logger = NornirLogger(__name__, job_result, data.get("debug"))
-    global_settings = GoldenConfigSetting.objects.first()
-    verify_global_settings(logger, global_settings, ["backup_path_template"])
+
+    qs = get_job_filter(data)
+    device_to_settings_map = get_device_to_settings_map(queryset=qs)
+
+    for settings in set(device_to_settings_map.values()):
+        verify_settings(logger, settings, ["backup_path_template"])
 
     # Build a dictionary, with keys of platform.slug, and the regex line in it for the netutils func.
     remove_regex_dict = {}
@@ -118,7 +122,7 @@ def config_backup(job_result, data):
                 "options": {
                     "credentials_class": NORNIR_SETTINGS.get("credentials"),
                     "params": NORNIR_SETTINGS.get("inventory_params"),
-                    "queryset": get_job_filter(data),
+                    "queryset": qs,
                     "defaults": {"now": now},
                 },
             },
@@ -130,7 +134,7 @@ def config_backup(job_result, data):
                 task=run_backup,
                 name="BACKUP CONFIG",
                 logger=logger,
-                global_settings=global_settings,
+                device_to_settings_map=device_to_settings_map,
                 remove_regex_dict=remove_regex_dict,
                 replace_regex_dict=replace_regex_dict,
             )
diff --git a/nautobot_golden_config/nornir_plays/config_compliance.py b/nautobot_golden_config/nornir_plays/config_compliance.py
index 3a30ed80..33279164 100644
--- a/nautobot_golden_config/nornir_plays/config_compliance.py
+++ b/nautobot_golden_config/nornir_plays/config_compliance.py
@@ -19,9 +19,9 @@
 
 from nautobot_golden_config.models import ComplianceRule, ConfigCompliance, GoldenConfigSetting, GoldenConfig
 from nautobot_golden_config.utilities.helper import (
+    get_device_to_settings_map,
     get_job_filter,
-    get_repository_working_dir,
-    verify_global_settings,
+    verify_settings,
     render_jinja_template,
 )
 from nautobot_golden_config.nornir_plays.processor import ProcessGoldenConfig
@@ -56,7 +56,7 @@ def diff_files(backup_file, intended_file):
 def run_compliance(  # pylint: disable=too-many-arguments,too-many-locals
     task: Task,
     logger,
-    global_settings,
+    device_to_settings_map,
     rules,
 ) -> Result:
     """Prepare data for compliance task.
@@ -68,6 +68,7 @@ def run_compliance(  # pylint: disable=too-many-arguments,too-many-locals
         result (Result): Result from Nornir task
     """
     obj = task.host.data["obj"]
+    settings = device_to_settings_map[obj.id]
 
     compliance_obj = GoldenConfig.objects.filter(device=obj).first()
     if not compliance_obj:
@@ -75,18 +76,18 @@ def run_compliance(  # pylint: disable=too-many-arguments,too-many-locals
     compliance_obj.compliance_last_attempt_date = task.host.defaults.data["now"]
     compliance_obj.save()
 
-    intended_directory = get_repository_working_dir("intended", obj, logger, global_settings)
-
-    intended_path_template_obj = render_jinja_template(obj, logger, global_settings.intended_path_template)
+    intended_directory = settings.intended_repository.filesystem_path
+    intended_path_template_obj = render_jinja_template(obj, logger, settings.intended_path_template)
     intended_file = os.path.join(intended_directory, intended_path_template_obj)
+
     if not os.path.exists(intended_file):
         logger.log_failure(obj, f"Unable to locate intended file for device at {intended_file}")
         raise NornirNautobotException()
 
-    backup_directory = get_repository_working_dir("backup", obj, logger, global_settings)
-
-    backup_template = render_jinja_template(obj, logger, global_settings.backup_path_template)
+    backup_directory = settings.backup_repository.filesystem_path
+    backup_template = render_jinja_template(obj, logger, settings.backup_path_template)
     backup_file = os.path.join(backup_directory, backup_template)
+
     if not os.path.exists(backup_file):
         logger.log_failure(obj, f"Unable to locate backup file for device at {backup_file}")
         raise NornirNautobotException()
@@ -130,8 +131,13 @@ def config_compliance(job_result, data):
     now = datetime.now()
     rules = get_rules()
     logger = NornirLogger(__name__, job_result, data.get("debug"))
-    global_settings = GoldenConfigSetting.objects.first()
-    verify_global_settings(logger, global_settings, ["backup_path_template", "intended_path_template"])
+
+    qs = get_job_filter(data)
+    device_to_settings_map = get_device_to_settings_map(queryset=qs)
+
+    for settings in set(device_to_settings_map.values()):
+        verify_settings(logger, settings, ["backup_path_template", "intended_path_template"])
+
     try:
         with InitNornir(
             runner=NORNIR_SETTINGS.get("runner"),
@@ -141,7 +147,7 @@ def config_compliance(job_result, data):
                 "options": {
                     "credentials_class": NORNIR_SETTINGS.get("credentials"),
                     "params": NORNIR_SETTINGS.get("inventory_params"),
-                    "queryset": get_job_filter(data),
+                    "queryset": qs,
                     "defaults": {"now": now},
                 },
             },
@@ -153,7 +159,7 @@ def config_compliance(job_result, data):
                 task=run_compliance,
                 name="RENDER COMPLIANCE TASK GROUP",
                 logger=logger,
-                global_settings=global_settings,
+                device_to_settings_map=device_to_settings_map,
                 rules=rules,
             )
 
diff --git a/nautobot_golden_config/nornir_plays/config_intended.py b/nautobot_golden_config/nornir_plays/config_intended.py
index 42078c39..2ee3663a 100644
--- a/nautobot_golden_config/nornir_plays/config_intended.py
+++ b/nautobot_golden_config/nornir_plays/config_intended.py
@@ -20,9 +20,9 @@
 
 from nautobot_golden_config.models import GoldenConfigSetting, GoldenConfig
 from nautobot_golden_config.utilities.helper import (
+    get_device_to_settings_map,
     get_job_filter,
-    get_repository_working_dir,
-    verify_global_settings,
+    verify_settings,
     render_jinja_template,
 )
 from nautobot_golden_config.utilities.graphql import graph_ql_query
@@ -36,7 +36,7 @@
 
 
 def run_template(  # pylint: disable=too-many-arguments
-    task: Task, logger, global_settings, nautobot_job, jinja_root_path
+    task: Task, logger, device_to_settings_map, nautobot_job
 ) -> Result:
     """Render Jinja Template.
 
@@ -47,12 +47,12 @@ def run_template(  # pylint: disable=too-many-arguments
         logger (NornirLogger): Logger to log messages to.
         global_settings (GoldenConfigSetting): The settings for GoldenConfigPlugin.
         nautobot_job (Result): The the output from the Nautobot Job instance being run.
-        jinja_root_path (str): The root path to the Jinja2 intended config file.
 
     Returns:
         result (Result): Result from Nornir task
     """
     obj = task.host.data["obj"]
+    settings = device_to_settings_map[obj.id]
 
     intended_obj = GoldenConfig.objects.filter(device=obj).first()
     if not intended_obj:
@@ -60,12 +60,12 @@ def run_template(  # pylint: disable=too-many-arguments
     intended_obj.intended_last_attempt_date = task.host.defaults.data["now"]
     intended_obj.save()
 
-    intended_directory = get_repository_working_dir("intended", obj, logger, global_settings)
-    intended_path_template_obj = render_jinja_template(obj, logger, global_settings.intended_path_template)
+    intended_directory = settings.intended_repository.filesystem_path
+    intended_path_template_obj = render_jinja_template(obj, logger, settings.intended_path_template)
     output_file_location = os.path.join(intended_directory, intended_path_template_obj)
 
-    jinja_template = render_jinja_template(obj, logger, global_settings.jinja_path_template)
-    status, device_data = graph_ql_query(nautobot_job.request, obj, global_settings.sot_agg_query)
+    jinja_template = render_jinja_template(obj, logger, settings.jinja_path_template)
+    status, device_data = graph_ql_query(nautobot_job.request, obj, settings.sot_agg_query)
     if status != 200:
         logger.log_failure(obj, f"The GraphQL query return a status of {str(status)} with error of {str(device_data)}")
         raise NornirNautobotException()
@@ -78,7 +78,7 @@ def run_template(  # pylint: disable=too-many-arguments
         obj=obj,
         logger=logger,
         jinja_template=jinja_template,
-        jinja_root_path=jinja_root_path,
+        jinja_root_path=settings.jinja_repository.path,
         output_file_location=output_file_location,
         default_drivers_mapping=get_dispatcher(),
         jinja_filters=jinja_env.filters,
@@ -92,22 +92,26 @@ def run_template(  # pylint: disable=too-many-arguments
     return Result(host=task.host, result=generated_config)
 
 
-def config_intended(nautobot_job, data, jinja_root_path):
+def config_intended(nautobot_job, data):
     """
     Nornir play to generate configurations.
 
     Args:
         nautobot_job (Result): The Nautobot Job instance being run.
         data (dict): Form data from Nautobot Job.
-        jinja_root_path (str): The root path to the Jinja2 intended config file.
 
     Returns:
         None: Intended configuration files are written to filesystem.
     """
     now = datetime.now()
     logger = NornirLogger(__name__, nautobot_job, data.get("debug"))
-    global_settings = GoldenConfigSetting.objects.first()
-    verify_global_settings(logger, global_settings, ["jinja_path_template", "intended_path_template", "sot_agg_query"])
+
+    qs = get_job_filter(data)
+    device_to_settings_map = get_device_to_settings_map(queryset=qs)
+
+    for settings in set(device_to_settings_map.values()):
+        verify_settings(logger, settings, ["jinja_path_template", "intended_path_template", "sot_agg_query"])
+
     try:
         with InitNornir(
             runner=NORNIR_SETTINGS.get("runner"),
@@ -117,7 +121,7 @@ def config_intended(nautobot_job, data, jinja_root_path):
                 "options": {
                     "credentials_class": NORNIR_SETTINGS.get("credentials"),
                     "params": NORNIR_SETTINGS.get("inventory_params"),
-                    "queryset": get_job_filter(data),
+                    "queryset": qs,
                     "defaults": {"now": now},
                 },
             },
@@ -130,9 +134,8 @@ def config_intended(nautobot_job, data, jinja_root_path):
                 task=run_template,
                 name="RENDER CONFIG",
                 logger=logger,
-                global_settings=global_settings,
+                device_to_settings_map=device_to_settings_map,
                 nautobot_job=nautobot_job,
-                jinja_root_path=jinja_root_path,
             )
 
     except Exception as err:
diff --git a/nautobot_golden_config/tables.py b/nautobot_golden_config/tables.py
index e01ee415..e9faced2 100644
--- a/nautobot_golden_config/tables.py
+++ b/nautobot_golden_config/tables.py
@@ -357,3 +357,55 @@ class Meta(BaseTable.Meta):
         model = models.ConfigReplace
         fields = ("pk", "name", "platform", "description", "regex", "replace")
         default_columns = ("pk", "name", "platform", "description", "regex", "replace")
+
+
+class GoldenConfigSettingTable(BaseTable):
+    # pylint: disable=R0903
+    """Table for list view."""
+
+    pk = ToggleColumn()
+    name = Column(order_by=("_name",), linkify=True)
+    jinja_repository = Column(
+        verbose_name="Jinja Repository",
+        empty_values=(),
+    )
+    intended_repository = Column(
+        verbose_name="Intended Repository",
+        empty_values=(),
+    )
+    backup_repository = Column(
+        verbose_name="Backup Repository",
+        empty_values=(),
+    )
+
+    def _render_capability(self, record, column, record_attribute):  # pylint: disable=unused-argument, no-self-use
+        if getattr(record, record_attribute, None):  # pylint: disable=no-else-return
+            return "✔"
+
+        return "✘"
+
+    def render_backup_repository(self, record, column):  # pylint: disable=no-self-use
+        """Render backup repository YES/NO value."""
+        return self._render_capability(record=record, column=column, record_attribute="backup_repository")
+
+    def render_intended_repository(self, record, column):  # pylint: disable=no-self-use
+        """Render intended repository YES/NO value."""
+        return self._render_capability(record=record, column=column, record_attribute="intended_repository")
+
+    def render_jinja_repository(self, record, column):  # pylint: disable=no-self-use
+        """Render jinja repository YES/NO value."""
+        return self._render_capability(record=record, column=column, record_attribute="jinja_repository")
+
+    class Meta(BaseTable.Meta):
+        """Meta attributes."""
+
+        model = models.GoldenConfigSetting
+        fields = (
+            "pk",
+            "name",
+            "weight",
+            "description",
+            "backup_repository",
+            "intended_repository",
+            "jinja_repository",
+        )
diff --git a/nautobot_golden_config/templates/nautobot_golden_config/goldenconfigsetting.html b/nautobot_golden_config/templates/nautobot_golden_config/goldenconfigsetting.html
index 549a0f6e..3a022bc3 100644
--- a/nautobot_golden_config/templates/nautobot_golden_config/goldenconfigsetting.html
+++ b/nautobot_golden_config/templates/nautobot_golden_config/goldenconfigsetting.html
@@ -1,139 +1,247 @@
 {% extends 'base.html' %}
 {% load buttons %}
-{% load static %}
 {% load custom_links %}
 {% load helpers %}
-
-{% block title %}{{ object }}{% endblock %}
+{% load perms %}
+{% load plugins %}
+{% load static %}
+{% load tz %}
 
 {% block header %}
-<div class="pull-right noprint">
-    {% if perms.nautobot_golden_config.change_goldenconfigsetting %}
-    <a href="{% url 'plugins:nautobot_golden_config:goldenconfigsetting_edit' %}" class="btn btn-warning">
-        <span class="mdi mdi-pencil" aria-hidden="true"></span> Edit
-    </a>
-    {% endif %}
-</div>
-<h1>Golden Configuration Settings</h1>
-{% include 'inc/created_updated.html' %}
-<div class="pull-right noprint">
-    {% custom_links object %}
-</div>
-<ul class="nav nav-tabs">
-    <li role="presentation" {% if not active_tab %} class="active" {% endif %}>
-        <a href="{{ object.get_absolute_url }}">Settings</a>
-    </li>
-    {% if perms.extras.view_objectchange %}
-    <li role="presentation" {% if active_tab == 'changelog' %} class="active" {% endif %}>
-        <a href="{% url 'plugins:nautobot_golden_config:goldenconfigsetting_changelog' %}">Change Log</a>
-    </li>
-    {% endif %}
-</ul>
-{% endblock %}
+    <div class="row noprint">
+        {% with list_url=object|validated_viewname:"list" %}
+        <div class="col-sm-8 col-md-9">
+            <ol class="breadcrumb">
+                <li><a href="{% url list_url %}">
+                    {{ verbose_name_plural|bettertitle }}
+                </a></li>
+                {% if object.name %}
+                    <li><a href="{{ object.get_absolute_url }}">{{ object.name }}</a></li>
+                {% else %}
+                    <li><a href="{{ object.get_absolute_url }}">{{ object }}</a></li>
+                {% endif %}
+            </ol>
+        </div>
+        <div class="col-sm-4 col-md-3">
+            <form action="{% url list_url %}" method="get">
+                <div class="input-group">
+                    <input type="text" name="q" class="form-control" placeholder="Search {{ verbose_name_plural }}" />
+                    <span class="input-group-btn">
+                        <button type="submit" class="btn btn-primary">
+                            <span class="mdi mdi-magnify" aria-hidden="true"></span>
+                        </button>
+                    </span>
+                </div>
+            </form>
+        </div>
+        {% endwith %}
+    </div>
+    <div class="pull-right noprint">
+    {% block buttons %}
+        {% if user|can_change:object %}
+            {% edit_button object %}
+        {% endif %}
+        {% if user|can_delete:object %}
+            {% delete_button object %}
+        {% endif %}
+    {% endblock buttons %}
+    </div>
+    <h1>{{ object }}</h1>
+    {% include 'inc/created_updated.html' %}
+    <div class="pull-right noprint">
+    </div>
+
+    <ul class="nav nav-tabs">
+        <li role="presentation"{% if not active_tab and not request.GET.tab or request.GET.tab == "main" %} class="active"{% endif %}>
+            <a href="{{ object.get_absolute_url }}#main" onclick="switch_tab(this.href)" aria-controls="main" role="tab" data-toggle="tab">
+                {{ verbose_name|bettertitle }}
+            </a>
+        </li>
+        <li role="presentation"{% if request.GET.tab == 'advanced' %} class="active"{% endif %}>
+            <a href="{{ object.get_absolute_url }}#advanced" onclick="switch_tab(this.href)" aria-controls="advanced" role="tab" data-toggle="tab">
+                Advanced
+            </a>
+        </li>
+        {% if perms.extras.view_objectchange %}
+            {% if active_tab != 'changelog' and changelog_url or active_tab == 'changelog' %}
+            <li role="presentation"{% if active_tab == 'changelog' %} class="active"{% endif %}>
+                <a href="{{ changelog_url }}">Change Log</a>
+            </li>
+            {% endif %}
+        {% endif %}
+    </ul>
+{% endblock header %}
 
 {% block content %}
-<style>
-    pre {
-        font-size: 10px;
-        display: inline-block;
-    }
-</style>
-<div class="row">
-    <div class="col-md-8">
-        <div class="panel panel-default">
-            <div class="panel-heading">
-                <strong>Settings</strong>
+    <div class="tab-content">
+        <div id="main" role="tabpanel" class="tab-pane {% if not active_tab and not request.GET.tab or request.GET.tab == "main" %}active{% else %}fade{% endif %}">
+            <div class="row">
+                <div class="col-md-6">
+                    <div class="panel panel-default">
+                        <div class="panel-heading">
+                            <strong>General Settings</strong>
+                        </div>
+                        <table class="table table-hover panel-body attr-table">
+                            <tr>
+                                <td>Weight</td>
+                                <td>{{ object.weight }}</td>
+                            </tr>
+                            <tr>
+                                <td>Description</td>
+                                <td>{{ object.description|placeholder }}</td>
+                            </tr>
+                            <tr>
+                                <td><a href="{{ object.get_url_to_filtered_device_list }}">Scope of Devices</td>
+                                <td>
+                                    <pre>{{ object.scope|render_json }}</pre></a>
+                                </td>
+                            </tr>
+                        </table>
+                    </div>
+                </div>
+                <div class="col-md-6">
+                    <div class="panel panel-default">
+                        <div class="panel-heading">
+                            <strong>Backup Configuration</strong>
+                        </div>
+                        <table class="table table-hover panel-body attr-table">
+                            <tr>
+                                <td>
+                                    Backup Repository
+                                </td>
+                                <td>
+                                    {% if object.backup_repository %}
+                                        <a href="{{ object.backup_repository.get_absolute_url }}">{{ object.backup_repository }}</a>
+                                    {% else %}
+                                        <span class="text-muted">None</span>
+                                    {% endif %}
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    Backup Path in Jinja Template Form
+                                </td>
+                                <td>
+                                    {{ object.backup_path_template|placeholder }}
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    Backup Test
+                                </td>
+                                <td>
+                                    {{ object.backup_test_connectivity|placeholder }}
+                                </td>
+                            </tr>
+                        </table>
+                    </div>
+                    <div class="panel panel-default">
+                        <div class="panel-heading">
+                            <strong>Intended Configuration</strong>
+                        </div>
+                        <table class="table table-hover panel-body attr-table">
+                            <tr>
+                                <td>
+                                    Intended Repository
+                                </td>
+                                <td>
+                                    {% if object.intended_repository %}
+                                        <a href="{{ object.intended_repository.get_absolute_url }}">{{ object.intended_repository }}</a>
+                                    {% else %}
+                                        <span class="text-muted">None</span>
+                                    {% endif %}
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    Intended Path in Jinja Template Form
+                                </td>
+                                <td>
+                                    {{ object.intended_path_template|placeholder }}
+                                </td>
+                            </tr>
+                        </table>
+                    </div>
+                    <div class="panel panel-default">
+                        <div class="panel-heading">
+                            <strong>Templates Configuration</strong>
+                        </div>
+                        <table class="table table-hover panel-body attr-table">
+                            <tr>
+                                <td>
+                                    Jinja Repository
+                                </td>
+                                <td>
+                                    {% if object.jinja_repository %}
+                                        <a href="{{ object.jinja_repository.get_absolute_url }}">{{ object.jinja_repository }}</a>
+                                    {% else %}
+                                        <span class="text-muted">None</span>
+                                    {% endif %}
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    Template Path in Jinja Template Form
+                                </td>
+                                <td>
+                                    {{ object.jinja_path_template|placeholder }}
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>GraphQL Query</td>
+                                <td>
+                                    <pre>{{ object.sot_agg_query|render_json }}</pre>
+                                </td>
+                            </tr>
+
+                        </table>
+                    </div>
+                </div>
+            </div>
+
+            <div class="row">
+                <div class="col-md-12">
+                    {% block content_full_width_page %}{% endblock content_full_width_page %}
+                    {% plugin_full_width_page object %}
+                </div>
+            </div>
+        </div>
+        <div id="advanced" role="tabpanel" class="tab-pane {% if request.GET.tab == 'advanced' %}active{% else %}fade{% endif %}">
+            <div class="row">
+                <div class="col-md-6">
+                    {% include 'inc/object_details_advanced_panel.html' %}
+                </div>
+                <div class="col-md-6">
+                    {% block advanced_content_right_page %}{% endblock advanced_content_right_page %}
+                </div>
+            </div>
+            <div class="row">
+                <div class="col-md-12">
+                    {% block advanced_content_full_width_page %}{% endblock advanced_content_full_width_page %}
+                </div>
             </div>
-            <table class="table table-hover panel-body attr-table">
-                <tr>
-                    <td>Backup Repositories</td>
-                    <td>
-                    {% for item in object.backup_repository.all %}
-                    {% if object.backup_repository %}
-                    {% include "nautobot_golden_config/manytomany.html" with url_name="extras:gitrepository" %}
-                    {% endif %}
-                    {% endfor %}
-                    </td>
-                </tr>
-                <tr>
-                    <td>Backup Repository Matching Rule</td>
-                    <td>
-                        <pre>{{ object.backup_match_rule }}</pre>
-                    </td>
-                </tr>
-                <tr>
-                    <td>Backup Path Template</td>
-                    <td>
-                        <pre>{{ object.backup_path_template }}</pre>
-                    </td>
-                </tr>
-                <tr>
-                    <td>Intended Repositories</td>
-                    <td>
-                    {% for item in object.intended_repository.all %}
-                    {% if object.intended_repository %}
-                    {% include "nautobot_golden_config/manytomany.html" with url_name="extras:gitrepository" %}
-                    {% endif %}
-                    {% endfor %}
-                    </td>
-                </tr>
-                <tr>
-                    <td>Intended Repository Matching Rule</td>
-                    <td>
-                        <pre>{{ object.intended_match_rule }}</pre>
-                    </td>
-                </tr>
-                <tr>
-                    <td>Intended Path Template</td>
-                    <td>
-                        <pre>{{ object.intended_path_template }}</pre>
-                    </td>
-                </tr>
-                <tr>
-                    <td>Jinja Repository</td>
-                    <td>
-                        {% if object.jinja_repository %}
-                        <a href="{% url 'extras:gitrepository' slug=object.jinja_repository.slug %}">{{ object.jinja_repository }}</a>
-                        {% endif %}
-                    </td>
-                </tr>
-                <tr>
-                    <td>Jinja Path Template</td>
-                    <td>
-                        <pre>{{ object.jinja_path_template }}</pre>
-                    </td>
-                </tr>
-                <tr>
-                    <td>Backup Test Connectivity</td>
-                    <td>
-                        {% if object.backup_test_connectivity %}
-                        <span class="text-success">
-                            <i class="mdi mdi-check-bold"></i>
-                        </span>
-                        {% else %}
-                        <span class="text-danger">
-                            <i class="mdi mdi-close"></i>
-                        </span>
-                        {% endif %}
-                    </td>
-                </tr>
-                <tr>
-                    <td><a href="{{ object.get_url_to_filtered_device_list }}">Scope of Devices</td>
-                    <td>
-                        <pre>{{ object.scope|render_json }}</pre></a>
-                    </td>
-                </tr>
-                <tr>
-                    <td>SoT Aggregation Query</td>
-                    <td>
-                        <pre>{{ object.sot_agg_query }}</pre>
-                    </td>
-                </tr>
         </div>
-        </table>
     </div>
-    {% include 'inc/custom_fields_panel.html' %}
-    {% include 'inc/relationships_panel.html' %}
-</div>
-</div>
-{% endblock %}
\ No newline at end of file
+{% endblock content %}
+
+{% block javascript %}
+<script src="{% static 'clipboard.js/clipboard-2.0.6.min.js' %}"
+    onerror="window.location='{% url 'media_failure' %}?filename=clipboard.js/clipboard-2.0.6.min.js'">
+</script>
+<script>
+    url = window.location.href.split("?")[0];
+    window.history.pushState({}, document.title, url);
+    var clipboard = new ClipboardJS('.btn');
+
+    clipboard.on('success', function (e) {});
+
+    clipboard.on('error', function (e) {});
+
+    function switch_tab(tab_href) {
+        if (location.pathname != "{{ object.get_absolute_url }}") {
+            tab_location = tab_href.split("#");
+            window.location.href = `${tab_location[0]}?tab=${tab_location[1]}`;
+        };
+    }
+</script>
+{% endblock javascript %}
diff --git a/nautobot_golden_config/templates/nautobot_golden_config/goldenconfigsetting_edit.html b/nautobot_golden_config/templates/nautobot_golden_config/goldenconfigsetting_edit.html
new file mode 100644
index 00000000..5f785609
--- /dev/null
+++ b/nautobot_golden_config/templates/nautobot_golden_config/goldenconfigsetting_edit.html
@@ -0,0 +1,42 @@
+{% extends 'generic/object_edit.html' %}
+{% load form_helpers %}
+
+{% block form %}
+    <div class="panel panel-default">
+        <div class="panel-heading"><strong>GoldenConfigSetting</strong></div>
+        <div class="panel-body">
+            {% render_field form.name %}
+            {% render_field form.slug %}
+            {% render_field form.weight %}
+            {% render_field form.description %}
+            {% render_field form.scope %}
+        </div>
+    </div>
+
+    <div class="panel panel-default">
+        <div class="panel-heading"><strong>Backup Configuration</strong></div>
+        <div class="panel-body">
+            {% render_field form.backup_repository %}
+            {% render_field form.backup_path_template %}
+            {% render_field form.backup_test_connectivity %}
+        </div>
+    </div>
+
+    <div class="panel panel-default">
+        <div class="panel-heading"><strong>Intended Configuration</strong></div>
+        <div class="panel-body">
+            {% render_field form.intended_repository %}
+            {% render_field form.intended_path_template %}
+        </div>
+    </div>
+
+    <div class="panel panel-default">
+        <div class="panel-heading"><strong>Templates Configuration</strong></div>
+        <div class="panel-body">
+            {% render_field form.jinja_repository %}
+            {% render_field form.jinja_path_template %}
+            {% render_field form.sot_agg_query %}
+        </div>
+    </div>
+
+{% endblock %}
diff --git a/nautobot_golden_config/urls.py b/nautobot_golden_config/urls.py
index 52d49fc6..86c61814 100644
--- a/nautobot_golden_config/urls.py
+++ b/nautobot_golden_config/urls.py
@@ -88,14 +88,20 @@
         name="compliancefeature_changelog",
         kwargs={"model": models.ComplianceFeature},
     ),
-    path("setting/", views.GoldenConfigSettingView.as_view(), name="goldenconfigsetting"),
-    path("setting/edit/", views.GoldenConfigSettingEditView.as_view(), name="goldenconfigsetting_edit"),
+    path("setting/", views.GoldenConfigSettingListView.as_view(), name="goldenconfigsetting_list"),
+    path("setting/add/", views.GoldenConfigSettingCreateView.as_view(), name="goldenconfigsetting_add"),
+    path("setting/delete/", views.GoldenConfigSettingBulkDeleteView.as_view(), name="goldenconfigsetting_bulk_delete"),
     path(
-        "setting/changelog/",
+        "setting/<slug:slug>/delete/", views.GoldenConfigSettingDeleteView.as_view(), name="goldenconfigsetting_delete"
+    ),
+    path("setting/<slug:slug>/edit/", views.GoldenConfigSettingEditView.as_view(), name="goldenconfigsetting_edit"),
+    path(
+        "setting/<slug:slug>/changelog/",
         ObjectChangeLogView.as_view(),
         name="goldenconfigsetting_changelog",
         kwargs={"model": models.GoldenConfigSetting},
     ),
+    path("setting/<slug:slug>/", views.GoldenConfigSettingView.as_view(), name="goldenconfigsetting"),
     path("config-remove/", views.ConfigRemoveListView.as_view(), name="configremove_list"),
     path("config-remove/add/", views.ConfigRemoveEditView.as_view(), name="configremove_add"),
     path(
diff --git a/nautobot_golden_config/utilities/helper.py b/nautobot_golden_config/utilities/helper.py
index 3bc27cfe..5e4bf174 100644
--- a/nautobot_golden_config/utilities/helper.py
+++ b/nautobot_golden_config/utilities/helper.py
@@ -3,15 +3,11 @@
 
 from jinja2 import exceptions as jinja_errors
 
-from django import forms
-from django.conf import settings
-
 from nautobot.dcim.models import Device
 from nautobot.dcim.filters import DeviceFilterSet
 from nautobot.utilities.utils import render_jinja2
 
 from nornir_nautobot.exceptions import NornirNautobotException
-from nornir_nautobot.utils.logger import NornirLogger
 
 from nautobot_golden_config import models
 
@@ -43,7 +39,10 @@ def get_job_filter(data=None):
     elif data.get("device"):
         query.update({"id": data["device"].values_list("pk", flat=True)})
 
-    base_qs = models.GoldenConfigSetting.objects.first().get_queryset()
+    base_qs = Device.objects.none()
+    for obj in models.GoldenConfigSetting.objects.all():
+        base_qs = base_qs | obj.get_queryset().distinct()
+
     if base_qs.count() == 0:
         raise NornirNautobotException(
             "The base queryset didn't find any devices. Please check the Golden Config Setting scope."
@@ -69,7 +68,7 @@ def null_to_empty(val):
     return val
 
 
-def verify_global_settings(logger, global_settings, attrs):
+def verify_settings(logger, global_settings, attrs):
     """Helper function to verify required attributes are set before a Nornir play start."""
     for item in attrs:
         if not getattr(global_settings, item):
@@ -118,58 +117,13 @@ def render_jinja_template(obj, logger, template):
         raise NornirNautobotException from error
 
 
-def clean_config_settings(repo_type: str, repo_count: int, match_rule: str):
-    """Custom clean for `GoldenConfigSettingFeatureForm`.
-
-    Args:
-        repo_type (str): `intended` or `backup`.
-        repo_count (int): Total number of repos.
-        match_rule (str): Template str provided by user to match repos.
-
-    Raises:
-        ValidationError: Custom Validation on form.
-    """
-    if repo_count > 1:
-        if not match_rule:
-            raise forms.ValidationError(
-                f"If you specify more than one {repo_type} repository, you must provide the {repo_type} repository matching rule template."
-            )
-    elif repo_count == 1 and match_rule:
-        raise forms.ValidationError(
-            f"If you configure only one {repo_type} repository, do not enter the {repo_type} repository matching rule template."
-        )
+def get_device_to_settings_map(queryset):
+    """Helper function to map settings to devices."""
+    device_to_settings_map = {}
+    queryset_ids = queryset.values_list("id", flat=True)
+    for golden_config_setting in models.GoldenConfigSetting.objects.all():
+        for device_id in golden_config_setting.get_queryset().values_list("id", flat=True):
+            if (device_id in queryset_ids) and (device_id not in device_to_settings_map):
+                device_to_settings_map[device_id] = golden_config_setting
 
-
-def get_repository_working_dir(
-    repo_type: str,
-    obj: Device,
-    logger: NornirLogger,
-    global_settings: models.GoldenConfigSetting,
-) -> str:
-    """Match the Device to a repository working directory, based on the repository matching rule.
-
-    Assume that the working directory == the slug of the repo.
-
-    Args:
-        repo_type (str): Either `intended` or `backup` repository
-        obj (Device): Django ORM Device object.
-        logger (NornirLogger): Logger object
-        global_settings (models.GoldenConfigSetting): Golden Config global settings.
-
-    Returns:
-        str: The local filesystem working directory corresponding to the repo slug.
-    """
-    match_rule = getattr(global_settings, f"{repo_type}_match_rule")
-
-    if not match_rule:
-        return getattr(global_settings, f"{repo_type}_repository").first().filesystem_path
-
-    desired_repository_slug = render_jinja_template(obj, logger, match_rule)
-    matching_repo = getattr(global_settings, f"{repo_type}_repository").filter(slug=desired_repository_slug)
-    if len(matching_repo) == 1:
-        return f"{settings.GIT_ROOT}/{matching_repo[0].slug}"
-    logger.log_failure(
-        obj,
-        f"There is no repository slug matching '{desired_repository_slug}' for device. Verify the matching rule and configured Git repositories.",
-    )
-    return None
+    return device_to_settings_map
diff --git a/nautobot_golden_config/views.py b/nautobot_golden_config/views.py
index c309bd79..607455ce 100644
--- a/nautobot_golden_config/views.py
+++ b/nautobot_golden_config/views.py
@@ -1,4 +1,4 @@
-"""Django views for Nautobot Golden Configuration."""
+"""Django views for Nautobot Golden Configuration."""  # pylint: disable=too-many-lines
 import base64
 import difflib
 import io
@@ -30,6 +30,7 @@
 from nautobot_golden_config import filters, forms, models, tables
 from nautobot_golden_config.utilities.constant import CONFIG_FEATURES, ENABLE_COMPLIANCE, PLUGIN_CFG
 from nautobot_golden_config.utilities.graphql import graph_ql_query
+from nautobot_golden_config.utilities.helper import get_device_to_settings_map
 
 LOGGER = logging.getLogger(__name__)
 
@@ -57,7 +58,11 @@ def extra_context(self):
 
     def alter_queryset(self, request):
         """Build actual runtime queryset as the build time queryset provides no information."""
-        return self.queryset.filter(id__in=models.GoldenConfigSetting.objects.first().get_queryset())
+        qs = Device.objects.none()
+        for obj in models.GoldenConfigSetting.objects.all():
+            qs = qs | obj.get_queryset().distinct()
+
+        return self.queryset.filter(id__in=qs)
 
     def queryset_to_csv(self):
         """Override nautobot default to account for using Device model for GoldenConfig data."""
@@ -391,8 +396,8 @@ def diff_structured_data(backup_data, intended_data):
             if request.GET.get("format") in ["json", "yaml"]:
                 structure_format = request.GET.get("format")
 
-            global_settings = models.GoldenConfigSetting.objects.first()
-            _, output = graph_ql_query(request, device, global_settings.sot_agg_query)
+            settings = get_device_to_settings_map(queryset=Device.objects.filter(pk=device.pk))[device]
+            _, output = graph_ql_query(request, device, settings.sot_agg_query)
 
             if structure_format == "yaml":
                 output = yaml.dump(json.loads(json.dumps(output)), default_flow_style=False)
@@ -824,41 +829,55 @@ class ComplianceRuleBulkEditView(generic.BulkEditView):
 #
 # GoldenConfigSetting
 #
+class GoldenConfigSettingView(generic.ObjectView):
+    """View for single GoldenConfigSetting instance."""
 
+    queryset = models.GoldenConfigSetting.objects.all()
 
-class GoldenConfigSettingView(generic.ObjectView):
-    """View for the only GoldenConfigSetting instance."""
+    # def get_extra_context(self, request, instance):
+    #     """Add extra data to detail view for Nautobot."""
+    #     return {}
 
+
+class GoldenConfigSettingCreateView(generic.ObjectEditView):
+    """Create view."""
+
+    model = models.GoldenConfigSetting
     queryset = models.GoldenConfigSetting.objects.all()
+    model_form = forms.GoldenConfigSettingFeatureForm
+    template_name = "nautobot_golden_config/goldenconfigsetting_edit.html"
 
-    def get(self, request, *args, **kwargs):
-        """Override the get parameter to get the first instance to enforce singleton pattern."""
-        instance = self.queryset.first()
 
-        return render(
-            request,
-            self.get_template_name(),
-            {
-                "object": instance,
-                **self.get_extra_context(request, instance),
-            },
-        )
+class GoldenConfigSettingDeleteView(generic.ObjectDeleteView):
+    """Delete view."""
 
-    def get_extra_context(self, request, instance):
-        """Add extra data to detail view for Nautobot."""
-        return {}
+    model = models.GoldenConfigSetting
+    queryset = models.GoldenConfigSetting.objects.all()
+
+
+class GoldenConfigSettingBulkDeleteView(generic.BulkDeleteView):
+    """Delete view."""
+
+    queryset = models.GoldenConfigSetting.objects.all()
+    table = tables.GoldenConfigSettingTable
 
 
 class GoldenConfigSettingEditView(generic.ObjectEditView):
-    """View for editing the Global configurations."""
+    """Edit view."""
 
+    model = models.GoldenConfigSetting
     queryset = models.GoldenConfigSetting.objects.all()
     model_form = forms.GoldenConfigSettingFeatureForm
-    default_return_url = "plugins:nautobot_golden_config:goldenconfigsetting"
+    template_name = "nautobot_golden_config/goldenconfigsetting_edit.html"
+
+
+class GoldenConfigSettingListView(generic.ObjectListView):
+    """List view."""
 
-    def get_object(self, kwargs):
-        """Override method to get first object to enforce the singleton pattern."""
-        return self.queryset.first()
+    queryset = models.GoldenConfigSetting.objects.all()
+    table = tables.GoldenConfigSettingTable
+    # TODO: Get import working
+    action_buttons = ("add", "export")
 
 
 #


Test patch:
diff --git a/nautobot_golden_config/tests/forms/test_golden_config_settings.py b/nautobot_golden_config/tests/forms/test_golden_config_settings.py
index 9af047ce..c4f6c82a 100644
--- a/nautobot_golden_config/tests/forms/test_golden_config_settings.py
+++ b/nautobot_golden_config/tests/forms/test_golden_config_settings.py
@@ -21,17 +21,13 @@ def test_no_query_no_scope_success(self):
         """Testing GoldenConfigForm without specifying a unique scope or GraphQL Query."""
         form = GoldenConfigSettingFeatureForm(
             data={
-                "backup_repository": [
-                    GitRepository.objects.get(name="test-backup-repo-1"),
-                    GitRepository.objects.get(name="test-backup-repo-2"),
-                ],
-                "backup_match_rule": "backup-{{ obj.site.region.parent.slug }}",
+                "name": "test",
+                "slug": "test",
+                "weight": 1000,
+                "description": "Test description.",
+                "backup_repository": GitRepository.objects.get(name="test-backup-repo-1"),
                 "backup_path_template": "{{ obj.site.region.parent.slug }}/{{obj.name}}.cfg",
-                "intended_repository": [
-                    GitRepository.objects.get(name="test-intended-repo-1"),
-                    GitRepository.objects.get(name="test-intended-repo-2"),
-                ],
-                "intended_match_rule": "intended-{{ obj.site.region.parent.slug }}",
+                "intended_repository": GitRepository.objects.get(name="test-intended-repo-1"),
                 "intended_path_template": "{{ obj.site.slug }}/{{ obj.name }}.cfg",
                 "backup_test_connectivity": True,
             }
@@ -39,102 +35,6 @@ def test_no_query_no_scope_success(self):
         self.assertTrue(form.is_valid())
         self.assertTrue(form.save())
 
-    def test_clean_backup_template(self):
-        """Testing clean method for single backup repo with a matching pattern."""
-        form = GoldenConfigSettingFeatureForm(
-            data={
-                "backup_repository": [GitRepository.objects.get(name="test-backup-repo-2")],
-                "backup_match_rule": "backup-{{ obj.site.region.parent.slug }}",
-                "backup_path_template": "{{ obj.site.region.parent.slug }}/{{obj.name}}.cfg",
-                "intended_repository": [
-                    GitRepository.objects.get(name="test-intended-repo-1"),
-                    GitRepository.objects.get(name="test-intended-repo-2"),
-                ],
-                "intended_match_rule": "intended-{{ obj.site.region.parent.slug }}",
-                "intended_path_template": "{{ obj.site.slug }}/{{ obj.name }}.cfg",
-                "backup_test_connectivity": True,
-            }
-        )
-        self.assertFalse(form.is_valid())
-        self.assertEqual(
-            form.non_field_errors(),
-            ["If you configure only one backup repository, do not enter the backup repository matching rule template."],
-        )
-
-    def test_clean_backup_template_missing_match_rule(self):
-        """Testing clean method for multiple backup repos without a matching pattern."""
-        form = GoldenConfigSettingFeatureForm(
-            data={
-                "backup_repository": [
-                    GitRepository.objects.get(name="test-backup-repo-1"),
-                    GitRepository.objects.get(name="test-backup-repo-2"),
-                ],
-                "backup_match_rule": "",
-                "backup_path_template": "{{ obj.site.region.parent.slug }}/{{obj.name}}.cfg",
-                "intended_repository": [
-                    GitRepository.objects.get(name="test-intended-repo-1"),
-                    GitRepository.objects.get(name="test-intended-repo-2"),
-                ],
-                "intended_match_rule": "intended-{{ obj.site.region.parent.slug }}",
-                "intended_path_template": "{{ obj.site.slug }}/{{ obj.name }}.cfg",
-                "backup_test_connectivity": True,
-            }
-        )
-        self.assertFalse(form.is_valid())
-        self.assertEqual(
-            form.non_field_errors(),
-            [
-                "If you specify more than one backup repository, you must provide the backup repository matching rule template."
-            ],
-        )
-
-    def test_clean_intended_template(self):
-        """Testing clean method for single intended repo with a matching pattern."""
-        form = GoldenConfigSettingFeatureForm(
-            data={
-                "backup_repository": [GitRepository.objects.get(name="test-backup-repo-2")],
-                "backup_path_template": "{{ obj.site.region.parent.slug }}/{{obj.name}}.cfg",
-                "intended_repository": [GitRepository.objects.get(name="test-intended-repo-1")],
-                "intended_match_rule": "intended-{{ obj.site.region.parent.slug }}",
-                "intended_path_template": "{{ obj.site.slug }}/{{ obj.name }}.cfg",
-                "backup_test_connectivity": True,
-            }
-        )
-        self.assertFalse(form.is_valid())
-        self.assertEqual(
-            form.non_field_errors(),
-            [
-                "If you configure only one intended repository, do not enter the intended repository matching rule template."
-            ],
-        )
-
-    def test_clean_intended_template_missing_match_rule(self):
-        """Testing clean method for multiple intended repos without a matching pattern."""
-        form = GoldenConfigSettingFeatureForm(
-            data={
-                "backup_repository": [
-                    GitRepository.objects.get(name="test-backup-repo-1"),
-                    GitRepository.objects.get(name="test-backup-repo-2"),
-                ],
-                "backup_match_rule": "backup-{{ obj.site.region.parent.slug }}",
-                "backup_path_template": "{{ obj.site.region.parent.slug }}/{{obj.name}}.cfg",
-                "intended_repository": [
-                    GitRepository.objects.get(name="test-intended-repo-1"),
-                    GitRepository.objects.get(name="test-intended-repo-2"),
-                ],
-                "intended_match_rule": "",
-                "intended_path_template": "{{ obj.site.slug }}/{{ obj.name }}.cfg",
-                "backup_test_connectivity": True,
-            }
-        )
-        self.assertFalse(form.is_valid())
-        self.assertEqual(
-            form.non_field_errors(),
-            [
-                "If you specify more than one intended repository, you must provide the intended repository matching rule template."
-            ],
-        )
-
     def test_clean_up(self):
         """Transactional custom model, unable to use `get_or_create`.
 
@@ -142,7 +42,3 @@ def test_clean_up(self):
         """
         GitRepository.objects.all().delete()
         self.assertEqual(GitRepository.objects.all().count(), 0)
-
-        # Put back a general GoldenConfigSetting object.
-        global_settings = GoldenConfigSetting.objects.create()
-        global_settings.save()
diff --git a/nautobot_golden_config/tests/test_api.py b/nautobot_golden_config/tests/test_api.py
index 6ef0df03..b42c2d7b 100644
--- a/nautobot_golden_config/tests/test_api.py
+++ b/nautobot_golden_config/tests/test_api.py
@@ -97,121 +97,27 @@ def setUp(self):
         self.add_permissions("nautobot_golden_config.change_goldenconfigsetting")
         self.base_view = reverse("plugins-api:nautobot_golden_config-api:goldenconfigsetting-list")
         self.data = {
+            "name": "test-setting-1",
+            "slug": "test_setting_1",
+            "description": "This is a description field of test-setting-1.",
+            "weight": 5000,
             "tags": [],
             "computed_fields": {},
             "custom_fields": {},
             "_custom_field_data": {},
-            "backup_match_rule": "backup-{{obj.site.region.parent.slug}}",
             "backup_path_template": "{{obj.site.region.slug}}/{{obj.site.slug}}/{{obj.name}}.cfg",
-            "intended_match_rule": "intended-{{obj.site.region.parent.slug}}",
             "intended_path_template": "{{obj.site.region.slug}}/{{obj.site.slug}}/{{obj.name}}.cfg",
             "jinja_path_template": "templates/{{obj.platform.slug}}/{{obj.platform.slug}}_main.j2",
             "backup_test_connectivity": False,
             "scope": {"has_primary_ip": "True"},
             "sot_agg_query": "query ($device_id: ID!) {\r\n  device(id: $device_id) {\r\n    config_context\r\n    device_role {\r\n      name\r\n      slug\r\n    }\r\n    hostname: name\r\n    platform {\r\n      manufacturer {\r\n        name\r\n      }\r\n      name\r\n      napalm_driver\r\n      slug\r\n    }\r\n    primary_ip4 {\r\n      address\r\n      interface {\r\n        name\r\n      }\r\n      id\r\n    }\r\n    site {\r\n      name\r\n      region {\r\n        name\r\n        slug\r\n        parent {\r\n          name\r\n          slug\r\n        }\r\n      }\r\n      slug\r\n    }\r\n  }\r\n}",
             "jinja_repository": str(GitRepository.objects.get(name="test-jinja-repo-1").id),
-            "backup_repository": [
-                str(GitRepository.objects.get(name="test-backup-repo-1").id),
-                str(GitRepository.objects.get(name="test-backup-repo-2").id),
-            ],
-            "intended_repository": [
-                str(GitRepository.objects.get(name="test-intended-repo-1").id),
-                str(GitRepository.objects.get(name="test-intended-repo-2").id),
-            ],
+            "backup_repository": str(GitRepository.objects.get(name="test-backup-repo-1").id),
+            "intended_repository": str(GitRepository.objects.get(name="test-intended-repo-1").id),
         }
-        # Since we enforce a singleton pattern on this model, nuke any auto-created objects.
+        # Since we enforced a singleton pattern on this model in 0.9 release migrations, nuke any auto-created objects.
         GoldenConfigSetting.objects.all().delete()
 
-    def test_golden_config_settings_create_1backup_with_match_rule(self):
-        """Verify that an invalid POST with an unnecessary match_rule returns an error."""
-        bad_data = deepcopy(self.data)
-        bad_data["backup_repository"] = [str(GitRepository.objects.get(name="test-backup-repo-1").id)]
-        response = self.client.post(
-            self.base_view,
-            data=bad_data,
-            format="json",
-            **self.header,
-        )
-        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertEqual(
-            response.data["non_field_errors"][0],
-            "If you configure only one backup repository, do not enter the backup repository matching rule template.",
-        )
-        self.assertEqual(GoldenConfigSetting.objects.all().count(), 0)
-
-    def test_golden_config_settings_create_backup_match_rule_missing(self):
-        """Verify that an invalid POST with a missing backup_match_rule returns an error."""
-        bad_data = deepcopy(self.data)
-        bad_data["backup_match_rule"] = ""
-        response = self.client.post(
-            self.base_view,
-            data=bad_data,
-            format="json",
-            **self.header,
-        )
-        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertEqual(
-            response.data["non_field_errors"][0],
-            "If you specify more than one backup repository, you must provide the backup repository matching rule template.",
-        )
-        self.assertEqual(GoldenConfigSetting.objects.all().count(), 0)
-
-    def test_golden_config_settings_create_1intended_with_match_rule(self):
-        """Verify that an invalid POST with an unnecessary match_rule returns an error."""
-        bad_data = deepcopy(self.data)
-        bad_data["intended_repository"] = [str(GitRepository.objects.get(name="test-intended-repo-2").id)]
-        response = self.client.post(
-            self.base_view,
-            data=bad_data,
-            format="json",
-            **self.header,
-        )
-        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertEqual(
-            response.data["non_field_errors"][0],
-            "If you configure only one intended repository, do not enter the intended repository matching rule template.",
-        )
-        self.assertEqual(GoldenConfigSetting.objects.all().count(), 0)
-
-    def test_golden_config_settings_create_intended_match_rule_missing(self):
-        """Verify that an invalid POST with a missing intended_match_rule returns an error."""
-        bad_data = deepcopy(self.data)
-        bad_data["intended_match_rule"] = ""
-        response = self.client.post(
-            self.base_view,
-            data=bad_data,
-            format="json",
-            **self.header,
-        )
-        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertEqual(
-            response.data["non_field_errors"][0],
-            "If you specify more than one intended repository, you must provide the intended repository matching rule template.",
-        )
-        self.assertEqual(GoldenConfigSetting.objects.all().count(), 0)
-
-    def test_golden_config_settings_create_multiple_problems(self):
-        """Verify that an invalid POST with multiple problems return multiple, correct errors."""
-        bad_data = deepcopy(self.data)
-        bad_data["backup_repository"] = [str(GitRepository.objects.get(name="test-backup-repo-1").id)]
-        bad_data["intended_match_rule"] = ""
-        response = self.client.post(
-            self.base_view,
-            data=bad_data,
-            format="json",
-            **self.header,
-        )
-        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertEqual(
-            response.data["non_field_errors"][0],
-            "If you configure only one backup repository, do not enter the backup repository matching rule template.",
-        )
-        self.assertEqual(
-            response.data["non_field_errors"][1],
-            "If you specify more than one intended repository, you must provide the intended repository matching rule template.",
-        )
-        self.assertEqual(GoldenConfigSetting.objects.all().count(), 0)
-
     def test_golden_config_settings_create_good(self):
         """Test a POST with good values."""
         response = self.client.post(
@@ -223,11 +129,9 @@ def test_golden_config_settings_create_good(self):
         self.assertEqual(response.status_code, status.HTTP_201_CREATED)
         self.assertTrue(response.data["created"])
         self.assertTrue(response.data["id"])
-        self.assertEqual(response.data["backup_match_rule"], "backup-{{obj.site.region.parent.slug}}")
         self.assertEqual(
             response.data["backup_path_template"], "{{obj.site.region.slug}}/{{obj.site.slug}}/{{obj.name}}.cfg"
         )
-        self.assertEqual(response.data["intended_match_rule"], "intended-{{obj.site.region.parent.slug}}")
         self.assertEqual(
             response.data["intended_path_template"], "{{obj.site.region.slug}}/{{obj.site.slug}}/{{obj.name}}.cfg"
         )
@@ -241,19 +145,9 @@ def test_golden_config_settings_create_good(self):
             "query ($device_id: ID!) {\r\n  device(id: $device_id) {\r\n    config_context\r\n    device_role {\r\n      name\r\n      slug\r\n    }\r\n    hostname: name\r\n    platform {\r\n      manufacturer {\r\n        name\r\n      }\r\n      name\r\n      napalm_driver\r\n      slug\r\n    }\r\n    primary_ip4 {\r\n      address\r\n      interface {\r\n        name\r\n      }\r\n      id\r\n    }\r\n    site {\r\n      name\r\n      region {\r\n        name\r\n        slug\r\n        parent {\r\n          name\r\n          slug\r\n        }\r\n      }\r\n      slug\r\n    }\r\n  }\r\n}",
         )
         self.assertEqual(response.data["jinja_repository"], GitRepository.objects.get(name="test-jinja-repo-1").id)
+        self.assertEqual(response.data["backup_repository"], GitRepository.objects.get(name="test-backup-repo-1").id)
         self.assertEqual(
-            response.data["backup_repository"],
-            [
-                GitRepository.objects.get(name="test-backup-repo-1").id,
-                GitRepository.objects.get(name="test-backup-repo-2").id,
-            ],
-        )
-        self.assertEqual(
-            response.data["intended_repository"],
-            [
-                GitRepository.objects.get(name="test-intended-repo-1").id,
-                GitRepository.objects.get(name="test-intended-repo-2").id,
-            ],
+            response.data["intended_repository"], GitRepository.objects.get(name="test-intended-repo-1").id
         )
         # Clean up
         GoldenConfigSetting.objects.all().delete()
@@ -268,8 +162,7 @@ def test_golden_config_settings_update_good(self):
             **self.header,
         )
         new_data = deepcopy(self.data)
-        new_data["backup_repository"] = [str(GitRepository.objects.get(name="test-backup-repo-1").id)]
-        new_data["backup_match_rule"] = ""
+        new_data["backup_repository"] = str(GitRepository.objects.get(name="test-backup-repo-1").id)
         response = self.client.put(
             f"{self.base_view}{response_post.data['id']}/",
             data=new_data,
@@ -277,11 +170,9 @@ def test_golden_config_settings_update_good(self):
             **self.header,
         )
         self.assertEqual(response.status_code, status.HTTP_200_OK)
-        self.assertEqual(response.data["backup_match_rule"], "")
         self.assertEqual(
             response.data["backup_path_template"], "{{obj.site.region.slug}}/{{obj.site.slug}}/{{obj.name}}.cfg"
         )
-        self.assertEqual(response.data["intended_match_rule"], "intended-{{obj.site.region.parent.slug}}")
         self.assertEqual(
             response.data["intended_path_template"], "{{obj.site.region.slug}}/{{obj.site.slug}}/{{obj.name}}.cfg"
         )
@@ -295,118 +186,9 @@ def test_golden_config_settings_update_good(self):
             "query ($device_id: ID!) {\r\n  device(id: $device_id) {\r\n    config_context\r\n    device_role {\r\n      name\r\n      slug\r\n    }\r\n    hostname: name\r\n    platform {\r\n      manufacturer {\r\n        name\r\n      }\r\n      name\r\n      napalm_driver\r\n      slug\r\n    }\r\n    primary_ip4 {\r\n      address\r\n      interface {\r\n        name\r\n      }\r\n      id\r\n    }\r\n    site {\r\n      name\r\n      region {\r\n        name\r\n        slug\r\n        parent {\r\n          name\r\n          slug\r\n        }\r\n      }\r\n      slug\r\n    }\r\n  }\r\n}",
         )
         self.assertEqual(response.data["jinja_repository"], GitRepository.objects.get(name="test-jinja-repo-1").id)
+        self.assertEqual(response.data["backup_repository"], GitRepository.objects.get(name="test-backup-repo-1").id)
         self.assertEqual(
-            response.data["backup_repository"],
-            [
-                GitRepository.objects.get(name="test-backup-repo-1").id,
-            ],
-        )
-        self.assertEqual(
-            response.data["intended_repository"],
-            [
-                GitRepository.objects.get(name="test-intended-repo-1").id,
-                GitRepository.objects.get(name="test-intended-repo-2").id,
-            ],
-        )
-        # Clean up
-        GoldenConfigSetting.objects.all().delete()
-        self.assertEqual(GoldenConfigSetting.objects.all().count(), 0)
-
-    def test_golden_config_settings_update_1backup_with_match_rule(self):
-        """Verify a PUT to the valid settings object, with an invalid backup repo set, returns a 400."""
-        response_post = self.client.post(
-            self.base_view,
-            data=self.data,
-            format="json",
-            **self.header,
-        )
-        bad_data = deepcopy(self.data)
-        bad_data["backup_repository"] = [str(GitRepository.objects.get(name="test-backup-repo-1").id)]
-        response = self.client.put(
-            f"{self.base_view}{response_post.data['id']}/",
-            data=bad_data,
-            format="json",
-            **self.header,
-        )
-        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertEqual(
-            response.data["non_field_errors"][0],
-            "If you configure only one backup repository, do not enter the backup repository matching rule template.",
-        )
-        # Clean up
-        GoldenConfigSetting.objects.all().delete()
-        self.assertEqual(GoldenConfigSetting.objects.all().count(), 0)
-
-    def test_golden_config_settings_update_backup_match_rule_missing(self):
-        """Verify a PUT to the valid settings object, with an invalid backup repo set, returns a 400."""
-        response_post = self.client.post(
-            self.base_view,
-            data=self.data,
-            format="json",
-            **self.header,
-        )
-        bad_data = deepcopy(self.data)
-        bad_data["backup_match_rule"] = ""
-        response = self.client.put(
-            f"{self.base_view}{response_post.data['id']}/",
-            data=bad_data,
-            format="json",
-            **self.header,
-        )
-        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertEqual(
-            response.data["non_field_errors"][0],
-            "If you specify more than one backup repository, you must provide the backup repository matching rule template.",
-        )
-        # Clean up
-        GoldenConfigSetting.objects.all().delete()
-        self.assertEqual(GoldenConfigSetting.objects.all().count(), 0)
-
-    def test_golden_config_settings_update_1intended_with_match_rule(self):
-        """Verify a PUT to the valid settings object, with an invalid intended repo set, returns a 400."""
-        response_post = self.client.post(
-            self.base_view,
-            data=self.data,
-            format="json",
-            **self.header,
-        )
-        bad_data = deepcopy(self.data)
-        bad_data["intended_repository"] = [str(GitRepository.objects.get(name="test-intended-repo-1").id)]
-        response = self.client.put(
-            f"{self.base_view}{response_post.data['id']}/",
-            data=bad_data,
-            format="json",
-            **self.header,
-        )
-        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertEqual(
-            response.data["non_field_errors"][0],
-            "If you configure only one intended repository, do not enter the intended repository matching rule template.",
-        )
-        # Clean up
-        GoldenConfigSetting.objects.all().delete()
-        self.assertEqual(GoldenConfigSetting.objects.all().count(), 0)
-
-    def test_golden_config_settings_update_intended_match_rule_missing(self):
-        """Verify a PUT to the valid settings object, with an invalid intended repo set, returns a 400."""
-        response_post = self.client.post(
-            self.base_view,
-            data=self.data,
-            format="json",
-            **self.header,
-        )
-        bad_data = deepcopy(self.data)
-        bad_data["intended_match_rule"] = ""
-        response = self.client.put(
-            f"{self.base_view}{response_post.data['id']}/",
-            data=bad_data,
-            format="json",
-            **self.header,
-        )
-        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertEqual(
-            response.data["non_field_errors"][0],
-            "If you specify more than one intended repository, you must provide the intended repository matching rule template.",
+            response.data["intended_repository"], GitRepository.objects.get(name="test-intended-repo-1").id
         )
         # Clean up
         GoldenConfigSetting.objects.all().delete()
diff --git a/nautobot_golden_config/tests/test_graphql.py b/nautobot_golden_config/tests/test_graphql.py
index 6e82faf2..4ff4746f 100644
--- a/nautobot_golden_config/tests/test_graphql.py
+++ b/nautobot_golden_config/tests/test_graphql.py
@@ -118,26 +118,30 @@ def setUp(self):
             git_obj = GitRepository.objects.create(**item)
             git_obj.save()
 
-        backup_repo_list = GitRepository.objects.filter(
-            provided_contents__contains="nautobot_golden_config.backupconfigs"
-        )
-        intended_repo_list = GitRepository.objects.filter(
-            provided_contents__contains="nautobot_golden_config.intendedconfigs"
-        )
-
-        GoldenConfigSetting.objects.update(
+        # Since we enforce a singleton pattern on this model, nuke the auto-created object.
+        GoldenConfigSetting.objects.all().delete()
+
+        GoldenConfigSetting.objects.create(
+            name="test_name",
+            slug="test_slug",
+            weight=1000,
+            description="Test Description.",
             backup_path_template="test/backup",
             intended_path_template="test/intended",
-            jinja_repository=GitRepository.objects.get(
-                provided_contents__contains="nautobot_golden_config.jinjatemplate"
-            ),
             jinja_path_template="{{jinja_path}}",
             backup_test_connectivity=True,
             scope={"platform": ["platform1"]},
             sot_agg_query="{test_model}",
+            backup_repository=GitRepository.objects.get(
+                provided_contents__contains="nautobot_golden_config.backupconfigs"
+            ),
+            intended_repository=GitRepository.objects.get(
+                provided_contents__contains="nautobot_golden_config.intendedconfigs"
+            ),
+            jinja_repository=GitRepository.objects.get(
+                provided_contents__contains="nautobot_golden_config.jinjatemplate"
+            ),
         )
-        GoldenConfigSetting.objects.first().backup_repository.set(backup_repo_list)
-        GoldenConfigSetting.objects.first().intended_repository.set(intended_repo_list)
 
         self.feature1 = ComplianceFeature.objects.create(
             name="aaa",
@@ -295,6 +299,9 @@ def test_query_golden_config_setting(self):
         query = """
             query {
                 golden_config_settings {
+                    name
+                    slug
+                    weight
                     backup_path_template
                     intended_path_template
                     jinja_path_template
@@ -306,6 +313,9 @@ def test_query_golden_config_setting(self):
         response_data = {
             "golden_config_settings": [
                 {
+                    "name": "test_name",
+                    "slug": "test_slug",
+                    "weight": 1000,
                     "backup_path_template": "test/backup",
                     "intended_path_template": "test/intended",
                     "jinja_path_template": "{{jinja_path}}",
diff --git a/nautobot_golden_config/tests/test_models.py b/nautobot_golden_config/tests/test_models.py
index 86b60203..d93cfae9 100644
--- a/nautobot_golden_config/tests/test_models.py
+++ b/nautobot_golden_config/tests/test_models.py
@@ -88,12 +88,29 @@ class GoldenConfigSettingModelTestCase(TestCase):
 
     def setUp(self):
         """Get the golden config settings with the only allowed id."""
-        self.global_settings = GoldenConfigSetting.objects.first()
+        create_git_repos()
+
+        # Since we enforce a singleton pattern on this model, nuke the auto-created object.
+        GoldenConfigSetting.objects.all().delete()
+
+        self.global_settings = GoldenConfigSetting.objects.create(  # pylint: disable=attribute-defined-outside-init
+            name="test",
+            slug="test",
+            weight=1000,
+            description="Test Description.",
+            backup_path_template="{{ obj.site.region.parent.slug }}/{{obj.name}}.cfg",
+            intended_path_template="{{ obj.site.slug }}/{{ obj.name }}.cfg",
+            backup_test_connectivity=True,
+            jinja_repository=GitRepository.objects.get(name="test-jinja-repo-1"),
+            jinja_path_template="{{ obj.platform.slug }}/main.j2",
+            backup_repository=GitRepository.objects.get(name="test-backup-repo-1"),
+            intended_repository=GitRepository.objects.get(name="test-intended-repo-1"),
+        )
 
     def test_absolute_url_success(self):
         """Verify that get_absolute_url() returns the expected URL."""
         url_string = self.global_settings.get_absolute_url()
-        self.assertEqual(url_string, "/plugins/golden-config/setting/")
+        self.assertEqual(url_string, f"/plugins/golden-config/setting/{self.global_settings.slug}/")
 
     def test_bad_graphql_query(self):
         """Invalid graphql query."""
@@ -135,71 +152,51 @@ class GoldenConfigSettingGitModelTestCase(TestCase):
     def setUp(self) -> None:
         """Setup test data."""
         create_git_repos()
-        # Since we enforce a singleton pattern on this model, nuke the auto-created object.
+
+        # Since we enforced a singleton pattern on this model in 0.9 release migrations, nuke any auto-created objects.
         GoldenConfigSetting.objects.all().delete()
 
         # Create fresh new object, populate accordingly.
-
         self.golden_config = GoldenConfigSetting.objects.create(  # pylint: disable=attribute-defined-outside-init
-            backup_match_rule="backup-{{ obj.site.region.parent.slug }}",
+            name="test",
+            slug="test",
+            weight=1000,
+            description="Test Description.",
             backup_path_template="{{ obj.site.region.parent.slug }}/{{obj.name}}.cfg",
-            intended_match_rule="intended-{{ obj.site.region.parent.slug }}",
             intended_path_template="{{ obj.site.slug }}/{{ obj.name }}.cfg",
             backup_test_connectivity=True,
             jinja_repository=GitRepository.objects.get(name="test-jinja-repo-1"),
             jinja_path_template="{{ obj.platform.slug }}/main.j2",
+            backup_repository=GitRepository.objects.get(name="test-backup-repo-1"),
+            intended_repository=GitRepository.objects.get(name="test-intended-repo-1"),
         )
-        self.golden_config.backup_repository.set(
-            [
-                GitRepository.objects.get(name="test-backup-repo-1"),
-                GitRepository.objects.get(name="test-backup-repo-2"),
-            ]
-        )
-        self.golden_config.intended_repository.set(
-            [
-                GitRepository.objects.get(name="test-intended-repo-1"),
-                GitRepository.objects.get(name="test-intended-repo-2"),
-            ]
-        )
-        self.golden_config.save()
 
     def test_model_success(self):
         """Create a new instance of the GoldenConfigSettings model."""
-
-        self.assertEqual(self.golden_config.backup_match_rule, "backup-{{ obj.site.region.parent.slug }}")
+        self.assertEqual(self.golden_config.name, "test")
+        self.assertEqual(self.golden_config.slug, "test")
+        self.assertEqual(self.golden_config.weight, 1000)
+        self.assertEqual(self.golden_config.description, "Test Description.")
         self.assertEqual(self.golden_config.backup_path_template, "{{ obj.site.region.parent.slug }}/{{obj.name}}.cfg")
-        self.assertEqual(self.golden_config.intended_match_rule, "intended-{{ obj.site.region.parent.slug }}")
         self.assertEqual(self.golden_config.intended_path_template, "{{ obj.site.slug }}/{{ obj.name }}.cfg")
         self.assertTrue(self.golden_config.backup_test_connectivity)
         self.assertEqual(self.golden_config.jinja_repository, GitRepository.objects.get(name="test-jinja-repo-1"))
         self.assertEqual(self.golden_config.jinja_path_template, "{{ obj.platform.slug }}/main.j2")
-        self.assertEqual(
-            self.golden_config.backup_repository.first(), GitRepository.objects.get(name="test-backup-repo-1")
-        )
-        self.assertEqual(
-            self.golden_config.backup_repository.last(), GitRepository.objects.get(name="test-backup-repo-2")
-        )
-        self.assertEqual(
-            self.golden_config.intended_repository.first(), GitRepository.objects.get(name="test-intended-repo-1")
-        )
-        self.assertEqual(
-            self.golden_config.intended_repository.last(), GitRepository.objects.get(name="test-intended-repo-2")
-        )
+        self.assertEqual(self.golden_config.backup_repository, GitRepository.objects.get(name="test-backup-repo-1"))
+        self.assertEqual(self.golden_config.intended_repository, GitRepository.objects.get(name="test-intended-repo-1"))
 
     def test_removing_git_repos(self):
         """Ensure we can remove the Git Repository obejcts from GoldenConfigSetting."""
         GitRepository.objects.all().delete()
-        self.assertEqual(self.golden_config.intended_repository.count(), 0)
-        self.assertEqual(self.golden_config.backup_repository.count(), 0)
+        gc = GoldenConfigSetting.objects.all().first()  # pylint: disable=invalid-name
+        self.assertEqual(gc.intended_repository, None)
+        self.assertEqual(gc.backup_repository, None)
         self.assertEqual(GoldenConfigSetting.objects.all().count(), 1)
 
     def test_clean_up(self):
-        """Delete all objects created of GitRepository type."""
+        """Delete all objects created of GoldenConfigSetting type."""
         GoldenConfigSetting.objects.all().delete()
-        # Put back a general GoldenConfigSetting object.
-        global_settings = GoldenConfigSetting.objects.create()
-        global_settings.save()
-        self.assertEqual(GoldenConfigSetting.objects.all().count(), 1)
+        self.assertEqual(GoldenConfigSetting.objects.all().count(), 0)
 
 
 class ConfigRemoveModelTestCase(TestCase):
diff --git a/nautobot_golden_config/tests/test_utilities/test_helpers.py b/nautobot_golden_config/tests/test_utilities/test_helpers.py
index 8a01dd18..5713e3b9 100644
--- a/nautobot_golden_config/tests/test_utilities/test_helpers.py
+++ b/nautobot_golden_config/tests/test_utilities/test_helpers.py
@@ -16,14 +16,14 @@
     null_to_empty,
     render_jinja_template,
     get_job_filter,
-    get_repository_working_dir,
+    get_device_to_settings_map,
 )
 
 
 # pylint: disable=no-self-use
 
 
-class HelpersTest(TestCase):
+class HelpersTest(TestCase):  # pylint: disable=too-many-instance-attributes
     """Test Helper Functions."""
 
     def setUp(self):
@@ -34,18 +34,59 @@ def setUp(self):
         create_helper_repo(name="backup-parent_region-1", provides="backupconfigs")
         create_helper_repo(name="intended-parent_region-1", provides="intendedconfigs")
         create_helper_repo(name="test-jinja-repo", provides="jinjatemplate")
-        self.global_settings = GoldenConfigSetting.objects.first()
-        self.global_settings.backup_repository.set([GitRepository.objects.get(name="backup-parent_region-1")])
-        self.global_settings.intended_repository.set([GitRepository.objects.get(name="intended-parent_region-1")])
-        self.global_settings.jinja_repository = GitRepository.objects.get(name="test-jinja-repo")
-        self.global_settings.backup_match_rule = "backup-{{ obj.site.region.parent.slug }}"
-        self.global_settings.intended_match_rule = "intended-{{ obj.site.region.parent.slug }}"
+
+        create_helper_repo(name="backup-parent_region-2", provides="backupconfigs")
+        create_helper_repo(name="intended-parent_region-2", provides="intendedconfigs")
+        create_helper_repo(name="test-jinja-repo-2", provides="jinjatemplate")
+
+        create_helper_repo(name="backup-parent_region-3", provides="backupconfigs")
+        create_helper_repo(name="intended-parent_region-3", provides="intendedconfigs")
+        create_helper_repo(name="test-jinja-repo-3", provides="jinjatemplate")
+
+        # Since we enforce a singleton pattern on this model, nuke the auto-created object.
+        GoldenConfigSetting.objects.all().delete()
+
+        self.test_settings_a = GoldenConfigSetting.objects.create(
+            name="test_a",
+            slug="test_a",
+            description="test_a",
+            weight=1000,
+            backup_repository=GitRepository.objects.get(name="backup-parent_region-1"),
+            intended_repository=GitRepository.objects.get(name="intended-parent_region-1"),
+            jinja_repository=GitRepository.objects.get(name="test-jinja-repo"),
+            # Limit scope to orphaned device only
+            scope={"site": ["site-4"]},
+        )
+
+        self.test_settings_b = GoldenConfigSetting.objects.create(
+            name="test_b",
+            slug="test_b",
+            description="test_b",
+            weight=2000,
+            backup_repository=GitRepository.objects.get(name="backup-parent_region-2"),
+            intended_repository=GitRepository.objects.get(name="intended-parent_region-2"),
+            jinja_repository=GitRepository.objects.get(name="test-jinja-repo-2"),
+            # Limit scope to orphaned device only
+            scope={"site": ["site-4"]},
+        )
+
+        self.test_settings_c = GoldenConfigSetting.objects.create(
+            name="test_c",
+            slug="test_c",
+            description="test_c",
+            weight=1000,
+            backup_repository=GitRepository.objects.get(name="backup-parent_region-3"),
+            intended_repository=GitRepository.objects.get(name="intended-parent_region-3"),
+            jinja_repository=GitRepository.objects.get(name="test-jinja-repo-3"),
+        )
+
         # Device.objects.all().delete()
         create_device(name="test_device")
         create_orphan_device(name="orphan_device")
         self.job_result = MagicMock()
         self.data = MagicMock()
         self.logger = NornirLogger(__name__, self.job_result, self.data)
+        self.device_to_settings_map = get_device_to_settings_map(queryset=Device.objects.all())
 
     def test_null_to_empty_null(self):
         """Ensure None returns with empty string."""
@@ -106,49 +147,25 @@ def test_render_jinja_template_exceptions_templateerror(self, template_mock, moc
                 render_jinja_template(mock_device, mock_nornir_logger, "template")
         mock_nornir_logger.log_failure.assert_called_once()
 
-    def test_get_backup_repository_working_dir_success(self):
+    def test_get_backup_repository_dir_success(self):
         """Verify that we successfully look up the path from a provided repo object."""
-        repo_type = "backup"
-        result = get_repository_working_dir(
-            repo_type, Device.objects.get(name="test_device"), self.logger, self.global_settings
-        )
-        self.assertEqual(result, "/opt/nautobot/git/backup-parent_region-1")
+        device = Device.objects.get(name="test_device")
+        backup_directory = self.device_to_settings_map[device.id].backup_repository.filesystem_path
+        self.assertEqual(backup_directory, "/opt/nautobot/git/backup-parent_region-3")
+
+        device = Device.objects.get(name="orphan_device")
+        backup_directory = self.device_to_settings_map[device.id].backup_repository.filesystem_path
+        self.assertEqual(backup_directory, "/opt/nautobot/git/backup-parent_region-2")
 
-    def test_get_intended_repository_working_dir_success(self):
+    def test_get_intended_repository_dir_success(self):
         """Verify that we successfully look up the path from a provided repo object."""
-        repo_type = "intended"
-        result = get_repository_working_dir(
-            repo_type, Device.objects.get(name="test_device"), self.logger, self.global_settings
-        )
-        self.assertEqual(result, "/opt/nautobot/git/intended-parent_region-1")
-
-    def test_get_backup_repository_working_dir_no_match(self):
-        """Verify that we return the correct error when there is no matching backup repo."""
-        repo_type = "backup"
-        logger = MagicMock()
-        result = get_repository_working_dir(
-            repo_type, Device.objects.get(name="orphan_device"), logger, self.global_settings
-        )
-        self.assertEqual(result, None)
-        self.assertEqual(logger.log_failure.call_count, 1)
-        self.assertEqual(
-            logger.log_failure.call_args[0][1],
-            "There is no repository slug matching 'backup-parent_region-4' for device. Verify the matching rule and configured Git repositories.",
-        )
+        device = Device.objects.get(name="test_device")
+        intended_directory = self.device_to_settings_map[device.id].intended_repository.filesystem_path
+        self.assertEqual(intended_directory, "/opt/nautobot/git/intended-parent_region-3")
 
-    def test_get_intended_repository_working_dir_no_match(self):
-        """Verify that we return the correct error when there is no matching intended repo."""
-        repo_type = "intended"
-        logger = MagicMock()
-        result = get_repository_working_dir(
-            repo_type, Device.objects.get(name="orphan_device"), logger, self.global_settings
-        )
-        self.assertEqual(result, None)
-        self.assertEqual(logger.log_failure.call_count, 1)
-        self.assertEqual(
-            logger.log_failure.call_args[0][1],
-            "There is no repository slug matching 'intended-parent_region-4' for device. Verify the matching rule and configured Git repositories.",
-        )
+        device = Device.objects.get(name="orphan_device")
+        intended_directory = self.device_to_settings_map[device.id].intended_repository.filesystem_path
+        self.assertEqual(intended_directory, "/opt/nautobot/git/intended-parent_region-2")
 
     def test_get_job_filter_no_data_success(self):
         """Verify we get two devices returned when providing no data."""
@@ -173,9 +190,9 @@ def test_get_job_filter_device_filter_success(self):
     def test_get_job_filter_base_queryset_raise(self):
         """Verify we get raise for having a base_qs with no objects due to bad Golden Config Setting scope."""
         Platform.objects.create(name="Placeholder Platform", slug="placeholder-platform")
-        golden_settings = GoldenConfigSetting.objects.first()
-        golden_settings.scope = {"platform": ["placeholder-platform"]}
-        golden_settings.validated_save()
+        for golden_settings in GoldenConfigSetting.objects.all():
+            golden_settings.scope = {"platform": ["placeholder-platform"]}
+            golden_settings.validated_save()
         with self.assertRaises(NornirNautobotException) as failure:
             get_job_filter()
         self.assertEqual(
@@ -205,3 +222,11 @@ def test_get_job_filter_device_no_platform_raise(self):
             failure.exception.args[0],
             "The following device(s) test_device have no platform defined. Platform is required.",
         )
+
+    def test_device_to_settings_map(self):
+        """Verify Golden Config Settings are properly mapped to devices."""
+        test_device = Device.objects.get(name="test_device")
+        orphan_device = Device.objects.get(name="orphan_device")
+        self.assertEqual(self.device_to_settings_map[test_device.id], self.test_settings_c)
+        self.assertEqual(self.device_to_settings_map[orphan_device.id], self.test_settings_b)
+        self.assertEqual(get_device_to_settings_map(queryset=Device.objects.none()), {})