diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1a6c81a94c34a9caf1ce566111e10c30f5c6098b
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestModule.kt
@@ -0,0 +1,6 @@
+package de.rki.coronawarnapp.coronatest
+
+import dagger.Module
+
+@Module
+class CoronaTestModule
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..832198cf3a59fa31bbda8f0bb55a31fc896f3a6c
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/CoronaTestRepository.kt
@@ -0,0 +1,50 @@
+package de.rki.coronawarnapp.coronatest
+
+import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestGUID
+import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestQRCode
+import de.rki.coronawarnapp.coronatest.server.CoronaTestServer
+import de.rki.coronawarnapp.coronatest.storage.CoronaTestStorage
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class CoronaTestRepository @Inject constructor(
+    private val storage: CoronaTestStorage,
+    private val server: CoronaTestServer,
+) {
+
+    val coronaTests: Flow<Set<CoronaTest>> = emptyFlow()
+
+    /**
+     * When this returns and there was no exception, the test was registered and a valid registrationToken obtained.
+     * Your new test should be available via **coronaTests**.
+     */
+    suspend fun registerTest(request: CoronaTestQRCode) {
+        Timber.tag(TAG).i("registerTest(request=%s)", request)
+    }
+
+    suspend fun removeTest(guid: CoronaTestGUID): CoronaTest {
+        Timber.tag(TAG).i("removeTest(guid=%s)", guid)
+
+        throw NotImplementedError()
+    }
+
+    suspend fun markAsSubmitted(guid: CoronaTestGUID) {
+        Timber.tag(TAG).i("markAsSubmitted(guid=%s)", guid)
+    }
+
+    /**
+     * Passing **null** will refresh all test types.
+     */
+    fun refresh(type: CoronaTest.Type? = null) {
+        Timber.tag(TAG).d("refresh(type=%s)", type)
+    }
+
+    companion object {
+        const val TAG = "CoronaTestRepo"
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCode.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCode.kt
new file mode 100644
index 0000000000000000000000000000000000000000..36eda1768e6b139014ba46e35fc13b3fb68d4f0c
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCode.kt
@@ -0,0 +1,30 @@
+package de.rki.coronawarnapp.coronatest.qrcode
+
+import android.os.Parcelable
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import kotlinx.parcelize.Parcelize
+import org.joda.time.Instant
+
+sealed class CoronaTestQRCode : Parcelable {
+
+    abstract val type: CoronaTest.Type
+    abstract val guid: CoronaTestGUID
+
+    @Parcelize
+    data class PCR(
+        override val type: CoronaTest.Type,
+        override val guid: CoronaTestGUID,
+    ) : CoronaTestQRCode()
+
+    @Parcelize
+    data class RapidAntigen(
+        override val type: CoronaTest.Type,
+        override val guid: CoronaTestGUID,
+        val createdAt: Instant,
+        val firstName: String?,
+        val lastName: String?,
+        val dateOfBirth: String?,
+    ) : CoronaTestQRCode()
+}
+
+typealias CoronaTestGUID = String
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCodeValidation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCodeValidation.kt
new file mode 100644
index 0000000000000000000000000000000000000000..717aaf78317c7822d4fc7225da3d76ea5a746839
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/qrcode/CoronaTestQRCodeValidation.kt
@@ -0,0 +1,12 @@
+package de.rki.coronawarnapp.coronatest.qrcode
+
+import dagger.Reusable
+import javax.inject.Inject
+
+@Reusable
+class CoronaTestQRCodeValidation @Inject constructor() {
+
+    suspend fun validate(qrCode: String): CoronaTestQRCode {
+        throw NotImplementedError()
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/server/CoronaTestServer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/server/CoronaTestServer.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7319755a4eb97a49def0752e2daf003d3afd0b39
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/server/CoronaTestServer.kt
@@ -0,0 +1,7 @@
+package de.rki.coronawarnapp.coronatest.server
+
+import dagger.Reusable
+import javax.inject.Inject
+
+@Reusable
+class CoronaTestServer @Inject constructor()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/storage/CoronaTestStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/storage/CoronaTestStorage.kt
new file mode 100644
index 0000000000000000000000000000000000000000..771397027a879b3817c8c516904865cfcf79b088
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/storage/CoronaTestStorage.kt
@@ -0,0 +1,23 @@
+package de.rki.coronawarnapp.coronatest.storage
+
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class CoronaTestStorage @Inject constructor() {
+
+    suspend fun load(): Set<CoronaTest> {
+        Timber.tag(TAG).d("load()")
+        throw NotImplementedError()
+    }
+
+    suspend fun save(tests: Set<CoronaTest>) {
+        Timber.tag(TAG).d("save(tests=%s)", tests)
+    }
+
+    companion object {
+        private const val TAG = "CoronaTestStorage"
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..08041c76e154830db21c59e6595e416067c038ca
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt
@@ -0,0 +1,23 @@
+package de.rki.coronawarnapp.coronatest.type
+
+import com.google.gson.annotations.SerializedName
+import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestGUID
+
+interface CoronaTest {
+    val testGUID: CoronaTestGUID
+    val registrationToken: RegistrationToken
+    val type: Type
+    val isRefreshing: Boolean
+    val isSubmissionAllowed: Boolean
+    val isSubmitted: Boolean
+
+    enum class Type {
+        @SerializedName("PCR")
+        PCR,
+
+        @SerializedName("RAPID_ANTIGEN")
+        RAPID_ANTIGEN,
+    }
+}
+
+typealias RegistrationToken = String
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/antigen/RapidAntigenCoronaTest.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/antigen/RapidAntigenCoronaTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..654a4cdb5701e51401ca60f12af99afd45011a5e
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/antigen/RapidAntigenCoronaTest.kt
@@ -0,0 +1,26 @@
+package de.rki.coronawarnapp.coronatest.type.antigen
+
+import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestGUID
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.RegistrationToken
+
+data class RapidAntigenCoronaTest(
+    override val testGUID: CoronaTestGUID,
+    override val registrationToken: RegistrationToken,
+    override val isRefreshing: Boolean,
+    override val isSubmissionAllowed: Boolean,
+    override val isSubmitted: Boolean,
+    val state: State,
+) : CoronaTest {
+
+    override val type: CoronaTest.Type = CoronaTest.Type.RAPID_ANTIGEN
+
+    enum class State {
+        PENDING,
+        INVALID,
+        POSITIVE,
+        NEGATIVE,
+        REDEEMED,
+        OUTDATED,
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRCoronaTest.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRCoronaTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9d4030826fe6fd3671757b5e1b1ecda8b23e4b40
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRCoronaTest.kt
@@ -0,0 +1,25 @@
+package de.rki.coronawarnapp.coronatest.type.pcr
+
+import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestGUID
+import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.coronatest.type.RegistrationToken
+
+data class PCRCoronaTest(
+    override val testGUID: CoronaTestGUID,
+    override val registrationToken: RegistrationToken,
+    override val isRefreshing: Boolean,
+    override val isSubmissionAllowed: Boolean,
+    override val isSubmitted: Boolean,
+    val state: State,
+) : CoronaTest {
+
+    override val type: CoronaTest.Type = CoronaTest.Type.PCR
+
+    enum class State {
+        PENDING,
+        INVALID,
+        POSITIVE,
+        NEGATIVE,
+        REDEEMED,
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt
index dbc57fbeb57043aa52ef75185797fdaae410f5ed..98551b2125158d86076118ad18f2c089a9fe56c5 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt
@@ -11,6 +11,7 @@ import de.rki.coronawarnapp.bugreporting.BugReporter
 import de.rki.coronawarnapp.bugreporting.BugReportingModule
 import de.rki.coronawarnapp.bugreporting.BugReportingSharedModule
 import de.rki.coronawarnapp.bugreporting.debuglog.DebugLogger
+import de.rki.coronawarnapp.coronatest.CoronaTestModule
 import de.rki.coronawarnapp.datadonation.DataDonationModule
 import de.rki.coronawarnapp.diagnosiskeys.DiagnosisKeysModule
 import de.rki.coronawarnapp.diagnosiskeys.DownloadDiagnosisKeysTaskModule
@@ -77,6 +78,7 @@ import javax.inject.Singleton
         DataDonationModule::class,
         SecurityModule::class,
         EventRegistrationModule::class,
+        CoronaTestModule::class,
     ]
 )
 interface ApplicationComponent : AndroidInjector<CoronaWarnApplication> {