diff --git a/common/protocols/src/main/proto/app/coronawarn/server/common/protocols/internal/risk_score_classification.proto b/common/protocols/src/main/proto/app/coronawarn/server/common/protocols/internal/risk_score_classification.proto
new file mode 100644
--- /dev/null
+++ b/common/protocols/src/main/proto/app/coronawarn/server/common/protocols/internal/risk_score_classification.proto
@@ -0,0 +1,15 @@
+syntax = "proto3";
+package app.coronawarn.server.common.protocols.internal;
+option java_package = "app.coronawarn.server.common.protocols.internal";
+option java_multiple_files = true;
+
+message RiskScoreClassification {
+  repeated RiskScoreClass risk_classes = 1;
+}
+
+message RiskScoreClass {
+  string label = 1;
+  int32 min = 2;
+  int32 max = 3;
+  string url = 4;
+}
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/ExposureConfigurationProvider.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/ExposureConfigurationProvider.java
similarity index 60%
rename from services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/ExposureConfigurationProvider.java
rename to services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/ExposureConfigurationProvider.java
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/ExposureConfigurationProvider.java
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/ExposureConfigurationProvider.java
@@ -17,18 +17,9 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig;
+package app.coronawarn.server.services.distribution.assembly.appconfig;

 import app.coronawarn.server.common.protocols.internal.RiskScoreParameters;
-import app.coronawarn.server.common.protocols.internal.RiskScoreParameters.Builder;
-import app.coronawarn.server.services.distribution.assembly.exposureconfig.parsing.YamlConstructorForProtoBuf;
-import java.io.IOException;
-import java.io.InputStream;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.core.io.Resource;
-import org.yaml.snakeyaml.Yaml;
-import org.yaml.snakeyaml.error.YAMLException;
-import org.yaml.snakeyaml.introspector.BeanAccess;

 /**
  * Provides the Exposure Configuration based on a file in the file system.<br> The existing file must be a valid YAML
@@ -62,21 +53,6 @@ public static RiskScoreParameters readMasterFile() throws UnableToLoadFileExcept
    * @throws UnableToLoadFileException when the file/transformation did not succeed
    */
   public static RiskScoreParameters readFile(String path) throws UnableToLoadFileException {
-    Yaml yaml = new Yaml(new YamlConstructorForProtoBuf());
-    yaml.setBeanAccess(BeanAccess.FIELD); /* no setters on RiskScoreParameters available */
-
-    Resource riskScoreParametersResource = new ClassPathResource(path);
-    try (InputStream inputStream = riskScoreParametersResource.getInputStream()) {
-      Builder loaded = yaml.loadAs(inputStream, RiskScoreParameters.newBuilder().getClass());
-      if (loaded == null) {
-        throw new UnableToLoadFileException(path);
-      }
-
-      return loaded.build();
-    } catch (YAMLException e) {
-      throw new UnableToLoadFileException("Parsing failed", e);
-    } catch (IOException e) {
-      throw new UnableToLoadFileException("Failed to load file " + path, e);
-    }
+    return YamlLoader.loadYamlIntoProtobufBuilder(path, RiskScoreParameters.Builder.class).build();
   }
 }
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/RiskScoreClassificationProvider.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/RiskScoreClassificationProvider.java
new file mode 100644
--- /dev/null
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/RiskScoreClassificationProvider.java
@@ -0,0 +1,58 @@
+/*
+ * Corona-Warn-App
+ *
+ * SAP SE and all other contributors /
+ * copyright owners license this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package app.coronawarn.server.services.distribution.assembly.appconfig;
+
+import app.coronawarn.server.common.protocols.internal.RiskScoreClassification;
+
+/**
+ * Provides the risk score classification based on a file on the file system. The existing file must be a valid YAML
+ * file, and must match the specification of the proto file risk_score_classification.proto.
+ */
+public class RiskScoreClassificationProvider {
+
+  private RiskScoreClassificationProvider() {
+  }
+
+  /**
+   * The location of the risk score classification master file.
+   */
+  public static final String MASTER_FILE = "risk-score-classification/master.yaml";
+
+  /**
+   * Fetches the master configuration as a {@link RiskScoreClassification} instance.
+   *
+   * @return the risk score classification as {@link RiskScoreClassification}
+   * @throws UnableToLoadFileException when the file/transformation did not succeed
+   */
+  public static RiskScoreClassification readMasterFile() throws UnableToLoadFileException {
+    return readFile(MASTER_FILE);
+  }
+
+  /**
+   * Fetches a risk score classification file based on the given path. The path must be available in the classloader.
+   *
+   * @param path The path, e.g. folder/my-risk-score-classification.yaml
+   * @return the RiskScoreClassification
+   * @throws UnableToLoadFileException when the file access/transformation did not succeed
+   */
+  public static RiskScoreClassification readFile(String path) throws UnableToLoadFileException {
+    return YamlLoader.loadYamlIntoProtobufBuilder(path, RiskScoreClassification.Builder.class).build();
+  }
+}
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/UnableToLoadFileException.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/UnableToLoadFileException.java
similarity index 92%
rename from services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/UnableToLoadFileException.java
rename to services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/UnableToLoadFileException.java
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/UnableToLoadFileException.java
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/UnableToLoadFileException.java
@@ -17,7 +17,7 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig;
+package app.coronawarn.server.services.distribution.assembly.appconfig;

 /**
  * The file could not be loaded/parsed correctly.
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/YamlLoader.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/YamlLoader.java
new file mode 100644
--- /dev/null
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/YamlLoader.java
@@ -0,0 +1,66 @@
+/*
+ * Corona-Warn-App
+ *
+ * SAP SE and all other contributors /
+ * copyright owners license this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package app.coronawarn.server.services.distribution.assembly.appconfig;
+
+import app.coronawarn.server.services.distribution.assembly.appconfig.parsing.YamlConstructorForProtoBuf;
+import com.google.protobuf.Message;
+import java.io.IOException;
+import java.io.InputStream;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.error.YAMLException;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+
+public class YamlLoader {
+
+  private YamlLoader() {
+  }
+
+  /**
+   * Returns a protobuf {@link Message.Builder message builder} of the specified type, whose fields have been set to the
+   * corresponding values from the yaml file at the specified path.
+   *
+   * @param path        The absolute path of the yaml file within the class path.
+   * @param builderType The specific {@link com.google.protobuf.Message.Builder} implementation that will be returned.
+   * @return A prepared protobuf {@link Message.Builder message builder} of the specified type.
+   * @throws UnableToLoadFileException if either the file access or subsequent yaml parsing fails.
+   */
+  public static <T extends Message.Builder> T loadYamlIntoProtobufBuilder(String path, Class<T> builderType)
+      throws UnableToLoadFileException {
+    Yaml yaml = new Yaml(new YamlConstructorForProtoBuf());
+    // no setters for generated message classes available
+    yaml.setBeanAccess(BeanAccess.FIELD);
+
+    Resource riskScoreParametersResource = new ClassPathResource(path);
+    try (InputStream inputStream = riskScoreParametersResource.getInputStream()) {
+      T loaded = yaml.loadAs(inputStream, builderType);
+      if (loaded == null) {
+        throw new UnableToLoadFileException(path);
+      }
+
+      return loaded;
+    } catch (YAMLException e) {
+      throw new UnableToLoadFileException("Parsing failed", e);
+    } catch (IOException e) {
+      throw new UnableToLoadFileException("Failed to load file " + path, e);
+    }
+  }
+}
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/parsing/YamlConstructorForProtoBuf.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/parsing/YamlConstructorForProtoBuf.java
similarity index 95%
rename from services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/parsing/YamlConstructorForProtoBuf.java
rename to services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/parsing/YamlConstructorForProtoBuf.java
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/parsing/YamlConstructorForProtoBuf.java
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/parsing/YamlConstructorForProtoBuf.java
@@ -17,7 +17,7 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig.parsing;
+package app.coronawarn.server.services.distribution.assembly.appconfig.parsing;

 import java.util.Arrays;
 import org.yaml.snakeyaml.constructor.Constructor;
@@ -39,6 +39,7 @@ public YamlConstructorForProtoBuf() {

   private static class ProtoBufPropertyUtils extends PropertyUtils {

+    @Override
     public Property getProperty(Class<?> type, String name, BeanAccess beanAccess) {
       return super.getProperty(type, transformToProtoNaming(name), beanAccess);
     }
@@ -55,5 +56,4 @@ private String snakeToCamelCase(String snakeCase) {
       return Character.toLowerCase(camelCase.charAt(0)) + camelCase.substring(1);
     }
   }
-
 }
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/structure/directory/AppConfigurationDirectory.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/structure/directory/AppConfigurationDirectory.java
new file mode 100644
--- /dev/null
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/structure/directory/AppConfigurationDirectory.java
@@ -0,0 +1,113 @@
+/*
+ * Corona-Warn-App
+ *
+ * SAP SE and all other contributors /
+ * copyright owners license this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package app.coronawarn.server.services.distribution.assembly.appconfig.structure.directory;
+
+import app.coronawarn.server.common.protocols.internal.RiskScoreClassification;
+import app.coronawarn.server.common.protocols.internal.RiskScoreParameters;
+import app.coronawarn.server.services.distribution.assembly.appconfig.ExposureConfigurationProvider;
+import app.coronawarn.server.services.distribution.assembly.appconfig.RiskScoreClassificationProvider;
+import app.coronawarn.server.services.distribution.assembly.appconfig.UnableToLoadFileException;
+import app.coronawarn.server.services.distribution.assembly.appconfig.structure.directory.decorator.AppConfigurationSigningDecorator;
+import app.coronawarn.server.services.distribution.assembly.appconfig.validation.AppConfigurationValidator;
+import app.coronawarn.server.services.distribution.assembly.appconfig.validation.ExposureConfigurationValidator;
+import app.coronawarn.server.services.distribution.assembly.appconfig.validation.RiskScoreClassificationValidator;
+import app.coronawarn.server.services.distribution.assembly.appconfig.validation.ValidationResult;
+import app.coronawarn.server.services.distribution.assembly.component.CryptoProvider;
+import app.coronawarn.server.services.distribution.assembly.structure.archive.ArchiveOnDisk;
+import app.coronawarn.server.services.distribution.assembly.structure.directory.DirectoryOnDisk;
+import app.coronawarn.server.services.distribution.assembly.structure.directory.IndexDirectoryOnDisk;
+import app.coronawarn.server.services.distribution.assembly.structure.directory.decorator.indexing.IndexingDecoratorOnDisk;
+import app.coronawarn.server.services.distribution.assembly.structure.file.FileOnDisk;
+import com.google.protobuf.Message;
+import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Creates the directory structure {@code /parameters/country/:country} and writes two files. One containing {@link
+ * RiskScoreParameters} and the another containing the {@link RiskScoreClassification}, wrapped in a signed zip
+ * archive.
+ */
+public class AppConfigurationDirectory extends DirectoryOnDisk {
+
+  private static final Logger logger = LoggerFactory.getLogger(AppConfigurationDirectory.class);
+  private static final String PARAMETERS_DIRECTORY = "configuration";
+  private static final String COUNTRY_DIRECTORY = "country";
+  private static final String COUNTRY = "DE";
+  private static final String EXPOSURE_CONFIGURATION_FILE_NAME = "exposure_configuration";
+  private static final String RISK_SCORE_CLASSIFICATION_FILE_NAME = "risk_score_classification";
+
+  private final IndexDirectoryOnDisk<String> countryDirectory =
+      new IndexDirectoryOnDisk<>(COUNTRY_DIRECTORY, __ -> Set.of(COUNTRY), Object::toString);
+
+  private final CryptoProvider cryptoProvider;
+
+  /**
+   * Creates an {@link AppConfigurationDirectory} for the exposure configuration and risk score classification.
+   *
+   * @param cryptoProvider The {@link CryptoProvider} whose artifacts to use for creating the signature.
+   */
+  public AppConfigurationDirectory(CryptoProvider cryptoProvider) {
+    super(PARAMETERS_DIRECTORY);
+
+    this.cryptoProvider = cryptoProvider;
+    addExposureConfigurationIfValid();
+    addRiskScoreClassificationIfValid();
+
+    this.addWritable(new IndexingDecoratorOnDisk<>(countryDirectory));
+  }
+
+  private void addExposureConfigurationIfValid() {
+    try {
+      RiskScoreParameters exposureConfig = ExposureConfigurationProvider.readMasterFile();
+      AppConfigurationValidator validator = new ExposureConfigurationValidator(exposureConfig);
+      addArchiveIfMessageValid(EXPOSURE_CONFIGURATION_FILE_NAME, exposureConfig, validator);
+    } catch (UnableToLoadFileException e) {
+      logger.error("Exposure configuration will not be published! Unable to read configuration file from disk.");
+    }
+  }
+
+  private void addRiskScoreClassificationIfValid() {
+    try {
+      RiskScoreClassification riskScoreClassification = RiskScoreClassificationProvider.readMasterFile();
+      AppConfigurationValidator validator = new RiskScoreClassificationValidator(riskScoreClassification);
+      addArchiveIfMessageValid(RISK_SCORE_CLASSIFICATION_FILE_NAME, riskScoreClassification, validator);
+    } catch (UnableToLoadFileException e) {
+      logger.error("Risk score classification will not be published! Unable to read configuration file from disk.");
+    }
+  }
+
+  /**
+   * If validation of the {@link Message} succeeds, it is written into a file, put into an archive with the specified
+   * name and added to the specified parent directory.
+   */
+  private void addArchiveIfMessageValid(String archiveName, Message message, AppConfigurationValidator validator) {
+    ValidationResult validationResult = validator.validate();
+
+    if (validationResult.hasErrors()) {
+      logger.error("App configuration file creation failed. Validation failed for {}./n{}",
+          archiveName, validationResult);
+    }
+
+    ArchiveOnDisk appConfigurationFile = new ArchiveOnDisk(archiveName);
+    appConfigurationFile.addWritable(new FileOnDisk("export.bin", message.toByteArray()));
+    countryDirectory.addWritableToAll(__ -> new AppConfigurationSigningDecorator(appConfigurationFile, cryptoProvider));
+  }
+}
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/structure/directory/decorator/ExposureConfigSigningDecorator.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/structure/directory/decorator/AppConfigurationSigningDecorator.java
similarity index 78%
rename from services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/structure/directory/decorator/ExposureConfigSigningDecorator.java
rename to services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/structure/directory/decorator/AppConfigurationSigningDecorator.java
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/structure/directory/decorator/ExposureConfigSigningDecorator.java
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/structure/directory/decorator/AppConfigurationSigningDecorator.java
@@ -1,4 +1,4 @@
-package app.coronawarn.server.services.distribution.assembly.exposureconfig.structure.directory.decorator;
+package app.coronawarn.server.services.distribution.assembly.appconfig.structure.directory.decorator;

 import app.coronawarn.server.services.distribution.assembly.component.CryptoProvider;
 import app.coronawarn.server.services.distribution.assembly.structure.Writable;
@@ -7,9 +7,9 @@
 import app.coronawarn.server.services.distribution.assembly.structure.archive.decorator.signing.SigningDecoratorOnDisk;
 import app.coronawarn.server.services.distribution.assembly.structure.file.FileOnDisk;

-public class ExposureConfigSigningDecorator extends SigningDecoratorOnDisk {
+public class AppConfigurationSigningDecorator extends SigningDecoratorOnDisk {

-  public ExposureConfigSigningDecorator(Archive<WritableOnDisk> archive, CryptoProvider cryptoProvider) {
+  public AppConfigurationSigningDecorator(Archive<WritableOnDisk> archive, CryptoProvider cryptoProvider) {
     super(archive, cryptoProvider);
   }

diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/AppConfigurationValidator.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/AppConfigurationValidator.java
new file mode 100644
--- /dev/null
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/AppConfigurationValidator.java
@@ -0,0 +1,37 @@
+/*
+ * Corona-Warn-App
+ *
+ * SAP SE and all other contributors /
+ * copyright owners license this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package app.coronawarn.server.services.distribution.assembly.appconfig.validation;
+
+/**
+ * Classes that extend {@link AppConfigurationValidator} validate the values of an associated {@link
+ * com.google.protobuf.Message} instance.
+ */
+public abstract class AppConfigurationValidator {
+
+  protected ValidationResult errors;
+
+  /**
+   * Performs a validation of the associated {@link com.google.protobuf.Message} instance and returns information about
+   * validation failures.
+   *
+   * @return The ValidationResult instance, containing information about possible errors.
+   */
+  public abstract ValidationResult validate();
+}
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ExposureConfigurationValidator.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ExposureConfigurationValidator.java
similarity index 93%
rename from services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ExposureConfigurationValidator.java
rename to services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ExposureConfigurationValidator.java
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ExposureConfigurationValidator.java
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ExposureConfigurationValidator.java
@@ -17,11 +17,11 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig.validation;
+package app.coronawarn.server.services.distribution.assembly.appconfig.validation;

 import app.coronawarn.server.common.protocols.internal.RiskLevel;
 import app.coronawarn.server.common.protocols.internal.RiskScoreParameters;
-import app.coronawarn.server.services.distribution.assembly.exposureconfig.validation.WeightValidationError.ErrorType;
+import app.coronawarn.server.services.distribution.assembly.appconfig.validation.WeightValidationError.ErrorType;
 import java.beans.BeanInfo;
 import java.beans.IntrospectionException;
 import java.beans.Introspector;
@@ -36,12 +36,10 @@
  * <br>
  * Weights must be in the range of 0.001 to 100.<br> Scores must be in the range of 1 to 8.<br>
  */
-public class ExposureConfigurationValidator {
+public class ExposureConfigurationValidator extends AppConfigurationValidator {

   private final RiskScoreParameters config;

-  private ValidationResult errors;
-
   public ExposureConfigurationValidator(RiskScoreParameters config) {
     this.config = config;
   }
@@ -52,6 +50,7 @@ public ExposureConfigurationValidator(RiskScoreParameters config) {
    * @return the ValidationResult instance, containing information about possible errors.
    * @throws ValidationExecutionException in case the validation could not be performed
    */
+  @Override
   public ValidationResult validate() {
     this.errors = new ValidationResult();

diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ParameterSpec.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ParameterSpec.java
similarity index 93%
rename from services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ParameterSpec.java
rename to services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ParameterSpec.java
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ParameterSpec.java
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ParameterSpec.java
@@ -17,7 +17,7 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig.validation;
+package app.coronawarn.server.services.distribution.assembly.appconfig.validation;

 /**
  * Definition of the spec according to Apple/Google:
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/RiskLevelValidationError.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/RiskLevelValidationError.java
similarity index 95%
rename from services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/RiskLevelValidationError.java
rename to services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/RiskLevelValidationError.java
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/RiskLevelValidationError.java
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/RiskLevelValidationError.java
@@ -17,7 +17,7 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig.validation;
+package app.coronawarn.server.services.distribution.assembly.appconfig.validation;

 import java.util.Objects;

diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/RiskScoreClassificationValidationError.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/RiskScoreClassificationValidationError.java
new file mode 100644
--- /dev/null
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/RiskScoreClassificationValidationError.java
@@ -0,0 +1,81 @@
+/*
+ * Corona-Warn-App
+ *
+ * SAP SE and all other contributors /
+ * copyright owners license this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package app.coronawarn.server.services.distribution.assembly.appconfig.validation;
+
+import java.util.Objects;
+
+public class RiskScoreClassificationValidationError implements ValidationError {
+
+  private final String errorSource;
+
+  private final Object value;
+
+  private final ErrorType reason;
+
+  /**
+   * Creates a {@link RiskScoreClassificationValidationError} that stores the specified validation error source,
+   * erroneous value and a reason for the error to occur.
+   *
+   * @param errorSource A label that describes the property associated with this validation error.
+   * @param value       The value that caused the validation error.
+   * @param reason      A validation error specifier.
+   */
+  public RiskScoreClassificationValidationError(String errorSource, Object value, ErrorType reason) {
+    this.errorSource = errorSource;
+    this.value = value;
+    this.reason = reason;
+  }
+
+  @Override
+  public String toString() {
+    return "RiskScoreClassificationValidationError{"
+        + "errorType=" + reason
+        + ", parameter='" + errorSource + '\''
+        + ", givenValue=" + value
+        + '}';
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    RiskScoreClassificationValidationError that = (RiskScoreClassificationValidationError) o;
+    return Objects.equals(errorSource, that.errorSource)
+        && Objects.equals(value, that.value)
+        && Objects.equals(reason, that.reason);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(errorSource, value, reason);
+  }
+
+  public enum ErrorType {
+    BLANK_LABEL,
+    MIN_GREATER_THAN_MAX,
+    VALUE_OUT_OF_BOUNDS,
+    INVALID_URL,
+    INVALID_PARTITIONING
+  }
+}
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/RiskScoreClassificationValidator.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/RiskScoreClassificationValidator.java
new file mode 100644
--- /dev/null
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/RiskScoreClassificationValidator.java
@@ -0,0 +1,113 @@
+/*
+ * Corona-Warn-App
+ *
+ * SAP SE and all other contributors /
+ * copyright owners license this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package app.coronawarn.server.services.distribution.assembly.appconfig.validation;
+
+import static app.coronawarn.server.services.distribution.assembly.appconfig.validation.RiskScoreClassificationValidationError.ErrorType.BLANK_LABEL;
+import static app.coronawarn.server.services.distribution.assembly.appconfig.validation.RiskScoreClassificationValidationError.ErrorType.INVALID_PARTITIONING;
+import static app.coronawarn.server.services.distribution.assembly.appconfig.validation.RiskScoreClassificationValidationError.ErrorType.INVALID_URL;
+import static app.coronawarn.server.services.distribution.assembly.appconfig.validation.RiskScoreClassificationValidationError.ErrorType.MIN_GREATER_THAN_MAX;
+import static app.coronawarn.server.services.distribution.assembly.appconfig.validation.RiskScoreClassificationValidationError.ErrorType.VALUE_OUT_OF_BOUNDS;
+
+import app.coronawarn.server.common.protocols.internal.RiskScoreClass;
+import app.coronawarn.server.common.protocols.internal.RiskScoreClassification;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * The RiskScoreClassificationValidator validates the values of an associated {@link RiskScoreClassification} instance.
+ */
+public class RiskScoreClassificationValidator extends AppConfigurationValidator {
+
+  /**
+   * This defines the number of possible values (0 ... RISK_SCORE_VALUE_RANGE - 1) for the total risk score.
+   */
+  public static final int RISK_SCORE_VALUE_RANGE = 256;
+
+  private final RiskScoreClassification riskScoreClassification;
+
+  public RiskScoreClassificationValidator(RiskScoreClassification riskScoreClassification) {
+    this.riskScoreClassification = riskScoreClassification;
+  }
+
+  /**
+   * Performs a validation of the associated {@link RiskScoreClassification} instance and returns information about
+   * validation failures.
+   *
+   * @return The ValidationResult instance, containing information about possible errors.
+   */
+  @Override
+  public ValidationResult validate() {
+    errors = new ValidationResult();
+
+    validateValues();
+    validateValueRangeCoverage();
+
+    return errors;
+  }
+
+  private void validateValues() {
+    for (RiskScoreClass riskScoreClass : riskScoreClassification.getRiskClassesList()) {
+      int minRiskLevel = riskScoreClass.getMin();
+      int maxRiskLevel = riskScoreClass.getMax();
+
+      validateLabel(riskScoreClass.getLabel());
+      validateRiskScoreValueBounds(minRiskLevel);
+      validateRiskScoreValueBounds(maxRiskLevel);
+      validateUrl(riskScoreClass.getUrl());
+
+      if (minRiskLevel > maxRiskLevel) {
+        errors.add(new RiskScoreClassificationValidationError(
+            "minRiskLevel, maxRiskLevel", minRiskLevel + ", " + maxRiskLevel, MIN_GREATER_THAN_MAX));
+      }
+    }
+  }
+
+  private void validateLabel(String label) {
+    if (label.isBlank()) {
+      errors.add(new RiskScoreClassificationValidationError("label", label, BLANK_LABEL));
+    }
+  }
+
+  private void validateRiskScoreValueBounds(int value) {
+    if (value < 0 || value > RISK_SCORE_VALUE_RANGE - 1) {
+      errors.add(new RiskScoreClassificationValidationError("minRiskLevel/maxRiskLevel", value, VALUE_OUT_OF_BOUNDS));
+    }
+  }
+
+  private void validateUrl(String url) {
+    if (!url.isBlank()) {
+      try {
+        new URL(url);
+      } catch (MalformedURLException e) {
+        errors.add(new RiskScoreClassificationValidationError("url", url, INVALID_URL));
+      }
+    }
+  }
+
+  private void validateValueRangeCoverage() {
+    int partitionSum = riskScoreClassification.getRiskClassesList().stream()
+        .mapToInt(riskScoreClass -> (riskScoreClass.getMax() - riskScoreClass.getMin() + 1))
+        .sum();
+
+    if (partitionSum != RISK_SCORE_VALUE_RANGE) {
+      errors.add(new RiskScoreClassificationValidationError("covered value range", partitionSum, INVALID_PARTITIONING));
+    }
+  }
+}
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ValidationError.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ValidationError.java
similarity index 76%
rename from services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ValidationError.java
rename to services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ValidationError.java
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ValidationError.java
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ValidationError.java
@@ -17,11 +17,10 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig.validation;
+package app.coronawarn.server.services.distribution.assembly.appconfig.validation;

 /**
- * A validation error, found during the process of validating the Exposure Configuration. Can either be score or weight
- * related.
+ * A validation error, found during validation of a generated protocol buffers message class instance.
  */
 public interface ValidationError {

diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ValidationExecutionException.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ValidationExecutionException.java
similarity index 91%
rename from services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ValidationExecutionException.java
rename to services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ValidationExecutionException.java
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ValidationExecutionException.java
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ValidationExecutionException.java
@@ -17,7 +17,7 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig.validation;
+package app.coronawarn.server.services.distribution.assembly.appconfig.validation;

 /**
  * The validation could not be executed. Find more information about the root cause in the cause element, and in the
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ValidationResult.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ValidationResult.java
similarity index 87%
rename from services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ValidationResult.java
rename to services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ValidationResult.java
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ValidationResult.java
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ValidationResult.java
@@ -17,7 +17,7 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig.validation;
+package app.coronawarn.server.services.distribution.assembly.appconfig.validation;

 import java.util.HashSet;
 import java.util.Objects;
@@ -40,11 +40,6 @@ public boolean add(ValidationError error) {
     return this.errors.add(error);
   }

-  @Override
-  public String toString() {
-    return errors.toString();
-  }
-
   /**
    * Checks whether this validation result instance has at least one error.
    *
@@ -54,13 +49,9 @@ public boolean hasErrors() {
     return !this.errors.isEmpty();
   }

-  /**
-   * Checks whether this validation result instance has no errors.
-   *
-   * @return true if yes, false otherwise
-   */
-  public boolean isSuccessful() {
-    return !hasErrors();
+  @Override
+  public String toString() {
+    return errors.toString();
   }

   @Override
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/WeightValidationError.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/WeightValidationError.java
similarity index 96%
rename from services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/WeightValidationError.java
rename to services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/WeightValidationError.java
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/WeightValidationError.java
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/WeightValidationError.java
@@ -17,7 +17,7 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig.validation;
+package app.coronawarn.server.services.distribution.assembly.appconfig.validation;

 import java.util.Objects;

diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/component/AppConfigurationStructureProvider.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/component/AppConfigurationStructureProvider.java
new file mode 100644
--- /dev/null
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/component/AppConfigurationStructureProvider.java
@@ -0,0 +1,45 @@
+/*
+ * Corona-Warn-App
+ *
+ * SAP SE and all other contributors /
+ * copyright owners license this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package app.coronawarn.server.services.distribution.assembly.component;
+
+import app.coronawarn.server.services.distribution.assembly.appconfig.structure.directory.AppConfigurationDirectory;
+import app.coronawarn.server.services.distribution.assembly.structure.WritableOnDisk;
+import app.coronawarn.server.services.distribution.assembly.structure.directory.Directory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * Reads configuration parameters from the respective files in the class path and builds a {@link
+ * AppConfigurationDirectory} with them.
+ */
+@Component
+public class AppConfigurationStructureProvider {
+
+  private final CryptoProvider cryptoProvider;
+
+  @Autowired
+  public AppConfigurationStructureProvider(CryptoProvider cryptoProvider) {
+    this.cryptoProvider = cryptoProvider;
+  }
+
+  public Directory<WritableOnDisk> getAppConfiguration() {
+    return new AppConfigurationDirectory(cryptoProvider);
+  }
+}
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/component/CwaApiStructureProvider.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/component/CwaApiStructureProvider.java
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/component/CwaApiStructureProvider.java
+++ b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/component/CwaApiStructureProvider.java
@@ -36,15 +36,15 @@ public class CwaApiStructureProvider {
   public static final String VERSION_DIRECTORY = "version";
   public static final String VERSION_V1 = "v1";

-  private final ExposureConfigurationStructureProvider exposureConfigurationStructureProvider;
+  private final AppConfigurationStructureProvider appConfigurationStructureProvider;

   private final DiagnosisKeysStructureProvider diagnosisKeysStructureProvider;

   @Autowired
   public CwaApiStructureProvider(
-      ExposureConfigurationStructureProvider exposureConfigurationStructureProvider,
+      AppConfigurationStructureProvider appConfigurationStructureProvider,
       DiagnosisKeysStructureProvider diagnosisKeysStructureProvider) {
-    this.exposureConfigurationStructureProvider = exposureConfigurationStructureProvider;
+    this.appConfigurationStructureProvider = appConfigurationStructureProvider;
     this.diagnosisKeysStructureProvider = diagnosisKeysStructureProvider;
   }

@@ -56,7 +56,7 @@ public Directory<WritableOnDisk> getDirectory() {
         new IndexDirectoryOnDisk<>(VERSION_DIRECTORY, __ -> Set.of(VERSION_V1), Object::toString);

     versionDirectory
-        .addWritableToAll(__ -> exposureConfigurationStructureProvider.getExposureConfiguration());
+        .addWritableToAll(__ -> appConfigurationStructureProvider.getAppConfiguration());
     versionDirectory.addWritableToAll(__ -> diagnosisKeysStructureProvider.getDiagnosisKeys());

     return new IndexingDecoratorOnDisk<>(versionDirectory);
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/component/ExposureConfigurationStructureProvider.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/component/ExposureConfigurationStructureProvider.java
deleted file mode 100644
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/component/ExposureConfigurationStructureProvider.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Corona-Warn-App
- *
- * SAP SE and all other contributors /
- * copyright owners license this file to you under the Apache
- * License, Version 2.0 (the "License"); you may not use this
- * file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package app.coronawarn.server.services.distribution.assembly.component;
-
-import app.coronawarn.server.common.protocols.internal.RiskScoreParameters;
-import app.coronawarn.server.services.distribution.assembly.exposureconfig.ExposureConfigurationProvider;
-import app.coronawarn.server.services.distribution.assembly.exposureconfig.UnableToLoadFileException;
-import app.coronawarn.server.services.distribution.assembly.exposureconfig.structure.directory.ExposureConfigurationDirectory;
-import app.coronawarn.server.services.distribution.assembly.structure.WritableOnDisk;
-import app.coronawarn.server.services.distribution.assembly.structure.directory.Directory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-/**
- * Reads the exposure configuration parameters from the respective file in the class path and builds a {@link
- * ExposureConfigurationDirectory} with them.
- */
-@Component
-public class ExposureConfigurationStructureProvider {
-
-  private static final Logger logger = LoggerFactory
-      .getLogger(ExposureConfigurationStructureProvider.class);
-
-  private final CryptoProvider cryptoProvider;
-
-  @Autowired
-  public ExposureConfigurationStructureProvider(CryptoProvider cryptoProvider) {
-    this.cryptoProvider = cryptoProvider;
-  }
-
-  public Directory<WritableOnDisk> getExposureConfiguration() {
-    var riskScoreParameters = readExposureConfiguration();
-    return new ExposureConfigurationDirectory(riskScoreParameters, cryptoProvider);
-  }
-
-  private RiskScoreParameters readExposureConfiguration() {
-    logger.debug("Reading exposure configuration...");
-    try {
-      return ExposureConfigurationProvider.readMasterFile();
-    } catch (UnableToLoadFileException e) {
-      logger.error("Could not load exposure configuration parameters", e);
-      throw new RuntimeException(e);
-    }
-  }
-}
diff --git a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/structure/directory/ExposureConfigurationDirectory.java b/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/structure/directory/ExposureConfigurationDirectory.java
deleted file mode 100644
--- a/services/distribution/src/main/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/structure/directory/ExposureConfigurationDirectory.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Corona-Warn-App
- *
- * SAP SE and all other contributors /
- * copyright owners license this file to you under the Apache
- * License, Version 2.0 (the "License"); you may not use this
- * file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package app.coronawarn.server.services.distribution.assembly.exposureconfig.structure.directory;
-
-import app.coronawarn.server.common.protocols.internal.RiskScoreParameters;
-import app.coronawarn.server.services.distribution.assembly.component.CryptoProvider;
-import app.coronawarn.server.services.distribution.assembly.exposureconfig.structure.directory.decorator.ExposureConfigSigningDecorator;
-import app.coronawarn.server.services.distribution.assembly.structure.archive.ArchiveOnDisk;
-import app.coronawarn.server.services.distribution.assembly.structure.directory.DirectoryOnDisk;
-import app.coronawarn.server.services.distribution.assembly.structure.directory.IndexDirectoryOnDisk;
-import app.coronawarn.server.services.distribution.assembly.structure.directory.decorator.indexing.IndexingDecoratorOnDisk;
-import app.coronawarn.server.services.distribution.assembly.structure.file.FileOnDisk;
-import java.util.Set;
-
-/**
- * Creates the directory structure {@code /parameters/country/:country} and writes a file called {@code index}
- * containing {@link RiskScoreParameters} wrapped in a signed zip archive.
- */
-public class ExposureConfigurationDirectory extends DirectoryOnDisk {
-
-  private static final String PARAMETERS_DIRECTORY = "parameters";
-  private static final String COUNTRY_DIRECTORY = "country";
-  private static final String COUNTRY = "DE";
-  private static final String INDEX_FILE_NAME = "index";
-
-  /**
-   * Constructor.
-   *
-   * @param exposureConfig The {@link RiskScoreParameters} to sign and write.
-   * @param cryptoProvider The {@link CryptoProvider} whose artifacts to use for creating the signature.
-   */
-  public ExposureConfigurationDirectory(RiskScoreParameters exposureConfig,
-      CryptoProvider cryptoProvider) {
-    super(PARAMETERS_DIRECTORY);
-
-    ArchiveOnDisk archive = new ArchiveOnDisk(INDEX_FILE_NAME);
-    archive.addWritable(new FileOnDisk("export.bin", exposureConfig.toByteArray()));
-
-    IndexDirectoryOnDisk<String> country =
-        new IndexDirectoryOnDisk<>(COUNTRY_DIRECTORY, __ -> Set.of(COUNTRY), Object::toString);
-    country.addWritableToAll(__ ->
-        new ExposureConfigSigningDecorator(archive, cryptoProvider));
-
-    this.addWritable(new IndexingDecoratorOnDisk<>(country));
-  }
-}
diff --git a/services/distribution/src/main/resources/risk-score-classification/master.yaml b/services/distribution/src/main/resources/risk-score-classification/master.yaml
new file mode 100644
--- /dev/null
+++ b/services/distribution/src/main/resources/risk-score-classification/master.yaml
@@ -0,0 +1,27 @@
+# This is the Risk Score Classification master file which partitions the risk
+# score value range (0-255) into distinct risk classes that will be used to by
+# the app in order to present the correct risk classification in a user
+# friendly manner, based on the underlying total risk score, to the user.
+#
+# The risk classes must not overlap and
+# cover the full risk score value range (0-255).
+#
+# Change this file with caution!
+
+risk_classes:
+  -
+    label: "LOW"
+    min: 0
+    max: 100
+    url: "https://www..."
+  -
+    label: "MID"
+    min: 101
+    max: 200
+    url: "https://www..."
+  -
+    label: "HIGH"
+    min: 201
+    max: 255
+    url: "https://www..."
+
\ No newline at end of file

diff --git a/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/ExposureConfigurationProviderMasterFileTest.java b/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/ExposureConfigurationProviderMasterFileTest.java
similarity index 82%
rename from services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/ExposureConfigurationProviderMasterFileTest.java
rename to services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/ExposureConfigurationProviderMasterFileTest.java
--- a/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/ExposureConfigurationProviderMasterFileTest.java
+++ b/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/ExposureConfigurationProviderMasterFileTest.java
@@ -17,12 +17,12 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig;
+package app.coronawarn.server.services.distribution.assembly.appconfig;

 import static org.assertj.core.api.Assertions.assertThat;

-import app.coronawarn.server.services.distribution.assembly.exposureconfig.validation.ExposureConfigurationValidator;
-import app.coronawarn.server.services.distribution.assembly.exposureconfig.validation.ValidationResult;
+import app.coronawarn.server.services.distribution.assembly.appconfig.validation.ExposureConfigurationValidator;
+import app.coronawarn.server.services.distribution.assembly.appconfig.validation.ValidationResult;
 import org.junit.jupiter.api.Test;

 /**
diff --git a/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/ExposureConfigurationProviderTest.java b/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/ExposureConfigurationProviderTest.java
similarity index 95%
rename from services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/ExposureConfigurationProviderTest.java
rename to services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/ExposureConfigurationProviderTest.java
--- a/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/ExposureConfigurationProviderTest.java
+++ b/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/ExposureConfigurationProviderTest.java
@@ -17,7 +17,7 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig;
+package app.coronawarn.server.services.distribution.assembly.appconfig;

 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.catchThrowable;
diff --git a/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/RiskScoreClassificationProviderMasterFileTest.java b/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/RiskScoreClassificationProviderMasterFileTest.java
new file mode 100644
--- /dev/null
+++ b/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/RiskScoreClassificationProviderMasterFileTest.java
@@ -0,0 +1,46 @@
+/*
+ * Corona-Warn-App
+ *
+ * SAP SE and all other contributors /
+ * copyright owners license this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package app.coronawarn.server.services.distribution.assembly.appconfig;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import app.coronawarn.server.services.distribution.assembly.appconfig.validation.ExposureConfigurationValidator;
+import app.coronawarn.server.services.distribution.assembly.appconfig.validation.RiskScoreClassificationValidator;
+import app.coronawarn.server.services.distribution.assembly.appconfig.validation.ValidationResult;
+import org.junit.jupiter.api.Test;
+
+/**
+ * This test will verify that the provided risk score classification master file is syntactically correct and according
+ * to spec.
+ * There should never be any deployment when this test is failing.
+ */
+public class RiskScoreClassificationProviderMasterFileTest {
+
+  private static final ValidationResult SUCCESS = new ValidationResult();
+
+  @Test
+  public void testMasterFile() throws UnableToLoadFileException {
+    var config = RiskScoreClassificationProvider.readMasterFile();
+
+    var validator = new RiskScoreClassificationValidator(config);
+
+    assertThat(validator.validate()).isEqualTo(SUCCESS);
+  }
+}
diff --git a/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ExposureConfigurationValidatorTest.java b/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ExposureConfigurationValidatorTest.java
similarity index 91%
rename from services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ExposureConfigurationValidatorTest.java
rename to services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ExposureConfigurationValidatorTest.java
--- a/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/ExposureConfigurationValidatorTest.java
+++ b/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/ExposureConfigurationValidatorTest.java
@@ -17,14 +17,14 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig.validation;
+package app.coronawarn.server.services.distribution.assembly.appconfig.validation;

 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.catchThrowable;

-import app.coronawarn.server.services.distribution.assembly.exposureconfig.ExposureConfigurationProvider;
-import app.coronawarn.server.services.distribution.assembly.exposureconfig.UnableToLoadFileException;
-import app.coronawarn.server.services.distribution.assembly.exposureconfig.validation.WeightValidationError.ErrorType;
+import app.coronawarn.server.services.distribution.assembly.appconfig.ExposureConfigurationProvider;
+import app.coronawarn.server.services.distribution.assembly.appconfig.UnableToLoadFileException;
+import app.coronawarn.server.services.distribution.assembly.appconfig.validation.WeightValidationError.ErrorType;
 import java.util.stream.Stream;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
diff --git a/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/RiskScoreClassificationValidatorTest.java b/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/RiskScoreClassificationValidatorTest.java
new file mode 100644
--- /dev/null
+++ b/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/RiskScoreClassificationValidatorTest.java
@@ -0,0 +1,173 @@
+/*
+ * Corona-Warn-App
+ *
+ * SAP SE and all other contributors /
+ * copyright owners license this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package app.coronawarn.server.services.distribution.assembly.appconfig.validation;
+
+import static app.coronawarn.server.services.distribution.assembly.appconfig.validation.RiskScoreClassificationValidator.RISK_SCORE_VALUE_RANGE;
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static app.coronawarn.server.services.distribution.assembly.appconfig.validation.RiskScoreClassificationValidationError.ErrorType.*;
+
+import app.coronawarn.server.common.protocols.internal.RiskScoreClass;
+import app.coronawarn.server.common.protocols.internal.RiskScoreClassification;
+import app.coronawarn.server.services.distribution.assembly.appconfig.validation.RiskScoreClassificationValidationError.ErrorType;
+import java.util.Arrays;
+import java.util.stream.Stream;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class RiskScoreClassificationValidatorTest {
+
+  private final static int MAX_SCORE = RISK_SCORE_VALUE_RANGE - 1;
+  private final static String VALID_LABEL = "myLabel";
+  private final static String VALID_URL = "";
+
+  @ParameterizedTest
+  @ValueSource(strings = {"", " "})
+  void failsForBlankLabels(String invalidLabel) {
+    var validator = buildValidator(buildRiskClass(invalidLabel, 0, MAX_SCORE, ""));
+    var expectedResult = buildExpectedResult(buildError("label", invalidLabel, ErrorType.BLANK_LABEL));
+
+    assertThat(validator.validate()).isEqualTo(expectedResult);
+  }
+
+  @ParameterizedTest
+  @ValueSource(strings = {"invalid.Url", "invalid-url", "$$$://invalid.url"})
+  void failsForInvalidUrl(String invalidUrl) {
+    var validator = buildValidator(buildRiskClass(VALID_LABEL, 0, MAX_SCORE, invalidUrl));
+    var expectedResult = buildExpectedResult(buildError("url", invalidUrl, ErrorType.INVALID_URL));
+
+    assertThat(validator.validate()).isEqualTo(expectedResult);
+  }
+
+  @Test
+  void failsForNegativeRiskValues() {
+    // must cover value range of equal size in order to avoid INVALID_PARTITIONING error
+    int negativeMin = -MAX_SCORE - 1;
+    int negativeMax = -1;
+    var validator = buildValidator(buildRiskClass(VALID_LABEL, negativeMin, negativeMax, VALID_URL));
+    var expectedResult = buildExpectedResult(
+        buildError("minRiskLevel/maxRiskLevel", negativeMin, ErrorType.VALUE_OUT_OF_BOUNDS),
+        buildError("minRiskLevel/maxRiskLevel", negativeMax, ErrorType.VALUE_OUT_OF_BOUNDS));
+
+    assertThat(validator.validate()).isEqualTo(expectedResult);
+  }
+
+  @Test
+  void failsForTooLargeRiskValues() {
+    // must cover value range of equal size in order to avoid INVALID_PARTITIONING error
+    int tooLargeMin = MAX_SCORE + 1;
+    int tooLargeMax = 2 * MAX_SCORE + 1;
+    var validator = buildValidator(buildRiskClass(VALID_LABEL, tooLargeMin, tooLargeMax, VALID_URL));
+    var expectedResult = buildExpectedResult(
+        buildError("minRiskLevel/maxRiskLevel", tooLargeMin, ErrorType.VALUE_OUT_OF_BOUNDS),
+        buildError("minRiskLevel/maxRiskLevel", tooLargeMax, ErrorType.VALUE_OUT_OF_BOUNDS));
+
+    assertThat(validator.validate()).isEqualTo(expectedResult);
+  }
+
+  @Test
+  void failsIfMinGreaterThanMax() {
+    int min = 1;
+    int max = 0;
+    // Note: additional classes have to be added in order to reach the expected value range size
+    var validator = buildValidator(buildRiskClass(VALID_LABEL, min, max, VALID_URL),
+        buildRiskClass(VALID_LABEL, 0, MAX_SCORE, VALID_URL));
+    var expectedResult = buildExpectedResult(
+        buildError("minRiskLevel, maxRiskLevel", (min + ", " + max), MIN_GREATER_THAN_MAX));
+
+    assertThat(validator.validate()).isEqualTo(expectedResult);
+  }
+
+  @ParameterizedTest
+  @MethodSource("createInvalidPartitionings")
+  void failsIfPartitioningInvalid(RiskScoreClassification invalidClassification) {
+    var validator = new RiskScoreClassificationValidator(invalidClassification);
+    int coveredRange = invalidClassification.getRiskClassesList().stream()
+        .mapToInt(riskScoreClass -> (riskScoreClass.getMax() - riskScoreClass.getMin() + 1))
+        .sum();
+    var expectedResult = buildExpectedResult(
+        buildError("covered value range", coveredRange, INVALID_PARTITIONING));
+
+    assertThat(validator.validate()).isEqualTo(expectedResult);
+  }
+
+  private static Stream<Arguments> createInvalidPartitionings() {
+    return Stream.of(
+        buildClassification(buildRiskClass(VALID_LABEL, 0, 0, VALID_URL)),
+        buildClassification(
+            buildRiskClass(VALID_LABEL, 0, MAX_SCORE / 2, VALID_URL),
+            buildRiskClass(VALID_LABEL, MAX_SCORE / 2 + 1, MAX_SCORE, VALID_URL),
+            buildRiskClass(VALID_LABEL, 0, MAX_SCORE, VALID_URL)),
+        buildClassification(
+            buildRiskClass(VALID_LABEL, 0, MAX_SCORE, VALID_URL),
+            buildRiskClass(VALID_LABEL, 0, MAX_SCORE, VALID_URL))
+    ).map(Arguments::of);
+  }
+
+  @ParameterizedTest
+  @MethodSource("createValidClassifications")
+  void doesNotFailForValidClassification(RiskScoreClassification validClassification) {
+    var validator = new RiskScoreClassificationValidator(validClassification);
+    assertThat(validator.validate()).isEqualTo(new ValidationResult());
+  }
+
+  private static Stream<Arguments> createValidClassifications() {
+    return Stream.of(
+        // blank url
+        buildClassification(buildRiskClass(VALID_LABEL, 0, MAX_SCORE, "")),
+        // legit url
+        buildClassification(buildRiskClass(VALID_LABEL, 0, MAX_SCORE, "http://www.sap.com")),
+        // [0:MAX_SCORE/2][MAX_SCORE/2:MAX_SCORE]
+        buildClassification(
+            buildRiskClass(VALID_LABEL, 0, MAX_SCORE / 2, VALID_URL),
+            buildRiskClass(VALID_LABEL, MAX_SCORE / 2 + 1, MAX_SCORE, VALID_URL)),
+        // [0:MAX_SCORE-10][MAX_SCORE-9][MAX_SCORE-8:MAX_SCORE]
+        buildClassification(
+            buildRiskClass(VALID_LABEL, 0, MAX_SCORE - 10, VALID_URL),
+            buildRiskClass(VALID_LABEL, MAX_SCORE - 9, MAX_SCORE - 9, VALID_URL),
+            buildRiskClass(VALID_LABEL, MAX_SCORE - 8, MAX_SCORE, VALID_URL))
+    ).map(Arguments::of);
+  }
+
+  private static RiskScoreClassificationValidationError buildError(String parameter, Object value, ErrorType reason) {
+    return new RiskScoreClassificationValidationError(parameter, value, reason);
+  }
+
+  private static RiskScoreClassificationValidator buildValidator(RiskScoreClass... riskScoreClasses) {
+    return new RiskScoreClassificationValidator(buildClassification(riskScoreClasses));
+  }
+
+  private static RiskScoreClassification buildClassification(RiskScoreClass... riskScoreClasses) {
+    return RiskScoreClassification.newBuilder().addAllRiskClasses(asList(riskScoreClasses)).build();
+  }
+
+  private static RiskScoreClass buildRiskClass(String label, int min, int max, String url) {
+    return RiskScoreClass.newBuilder().setLabel(label).setMin(min).setMax(max).setUrl(url).build();
+  }
+
+  private static ValidationResult buildExpectedResult(RiskScoreClassificationValidationError... errors) {
+    var validationResult = new ValidationResult();
+    Arrays.stream(errors).forEach(validationResult::add);
+    return validationResult;
+  }
+}
diff --git a/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/TestWithExpectedResult.java b/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/TestWithExpectedResult.java
similarity index 92%
rename from services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/TestWithExpectedResult.java
rename to services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/TestWithExpectedResult.java
--- a/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/exposureconfig/validation/TestWithExpectedResult.java
+++ b/services/distribution/src/test/java/app/coronawarn/server/services/distribution/assembly/appconfig/validation/TestWithExpectedResult.java
@@ -17,7 +17,7 @@
  * under the License.
  */

-package app.coronawarn.server.services.distribution.assembly.exposureconfig.validation;
+package app.coronawarn.server.services.distribution.assembly.appconfig.validation;

 public class TestWithExpectedResult {

Exposure configuration parameters not validated
The exposure configuration parameters are currently not validated after being read from the respective yml file. The validation code in ``ExposureConfigurationValidator`` is currently used in tests only.

However, the expected behavior shall be the following:
 - The ``RiskScoreParameters`` object is constructed based on yml file. (✅)
 - ``ExposureConfigurationValidator`` performs validation of the parameters.
 - In case of a failed validation, **do not** publish the exposure configuration parameters, **but do** generate and publish the diagnosis key bundles.
 - Clarify whether to keep any previously present (valid) configuration parameters on the object store if a validation error occurs.
 - Any validation errors shall be logged appropriately.