diff --git a/Corona-Warn-App/schemas/de.rki.coronawarnapp.contactdiary.storage.ContactDiaryDatabase/1.json b/Corona-Warn-App/schemas/de.rki.coronawarnapp.contactdiary.storage.ContactDiaryDatabase/1.json
new file mode 100644
index 0000000000000000000000000000000000000000..2b4c5f5e342a67902bd23aa0c3492586dac09a1d
--- /dev/null
+++ b/Corona-Warn-App/schemas/de.rki.coronawarnapp.contactdiary.storage.ContactDiaryDatabase/1.json
@@ -0,0 +1,154 @@
+{
+  "formatVersion": 1,
+  "database": {
+    "version": 1,
+    "identityHash": "02f231d9ba162399bf1884e74266fa0e",
+    "entities": [
+      {
+        "tableName": "ContactDiaryLocationEntity",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`locationId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `locationName` TEXT NOT NULL)",
+        "fields": [
+          {
+            "fieldPath": "locationId",
+            "columnName": "locationId",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "locationName",
+            "columnName": "locationName",
+            "affinity": "TEXT",
+            "notNull": true
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "locationId"
+          ],
+          "autoGenerate": true
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "ContactDiaryLocationVisitEntity",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `date` TEXT NOT NULL, `fkLocationId` INTEGER NOT NULL, FOREIGN KEY(`fkLocationId`) REFERENCES `ContactDiaryLocationEntity`(`locationId`) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "date",
+            "columnName": "date",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "fkLocationId",
+            "columnName": "fkLocationId",
+            "affinity": "INTEGER",
+            "notNull": true
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": true
+        },
+        "indices": [],
+        "foreignKeys": [
+          {
+            "table": "ContactDiaryLocationEntity",
+            "onDelete": "CASCADE",
+            "onUpdate": "CASCADE",
+            "columns": [
+              "fkLocationId"
+            ],
+            "referencedColumns": [
+              "locationId"
+            ]
+          }
+        ]
+      },
+      {
+        "tableName": "ContactDiaryPersonEntity",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`personId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `fullName` TEXT NOT NULL)",
+        "fields": [
+          {
+            "fieldPath": "personId",
+            "columnName": "personId",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "fullName",
+            "columnName": "fullName",
+            "affinity": "TEXT",
+            "notNull": true
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "personId"
+          ],
+          "autoGenerate": true
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "ContactDiaryPersonEncounterEntity",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `date` TEXT NOT NULL, `fkPersonId` INTEGER NOT NULL, FOREIGN KEY(`fkPersonId`) REFERENCES `ContactDiaryPersonEntity`(`personId`) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "date",
+            "columnName": "date",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "fkPersonId",
+            "columnName": "fkPersonId",
+            "affinity": "INTEGER",
+            "notNull": true
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": true
+        },
+        "indices": [],
+        "foreignKeys": [
+          {
+            "table": "ContactDiaryPersonEntity",
+            "onDelete": "CASCADE",
+            "onUpdate": "CASCADE",
+            "columns": [
+              "fkPersonId"
+            ],
+            "referencedColumns": [
+              "personId"
+            ]
+          }
+        ]
+      }
+    ],
+    "views": [],
+    "setupQueries": [
+      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '02f231d9ba162399bf1884e74266fa0e')"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/contactdiary/storage/ContactDiaryDatabaseTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/contactdiary/storage/ContactDiaryDatabaseTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..11fb352a5b7f982f910ade41c89c384dd121783c
--- /dev/null
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/contactdiary/storage/ContactDiaryDatabaseTest.kt
@@ -0,0 +1,130 @@
+package de.rki.coronawarnapp.contactdiary.storage
+
+import androidx.room.Room
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryLocationEntity
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryLocationVisitEntity
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryLocationVisitWrapper
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryPersonEncounterEntity
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryPersonEncounterWrapper
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryPersonEntity
+import io.kotest.matchers.shouldBe
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.runBlocking
+import org.joda.time.LocalDate
+import org.junit.After
+import org.junit.Test
+import org.junit.runner.RunWith
+import testhelpers.BaseTest
+
+@RunWith(AndroidJUnit4::class)
+class ContactDiaryDatabaseTest : BaseTest() {
+
+    // TestData
+    private val date = LocalDate.now()
+    private val person = ContactDiaryPersonEntity(personId = 1, fullName = "Peter")
+    private val location = ContactDiaryLocationEntity(locationId = 2, locationName = "Rewe Wiesloch")
+    private val personEncounter = ContactDiaryPersonEncounterEntity(id = 3, date = date, fkPersonId = person.personId)
+    private val locationVisit = ContactDiaryLocationVisitEntity(id = 4, date = date, fkLocationId = location.locationId)
+
+    // DB
+    private val contactDiaryDatabase: ContactDiaryDatabase =
+        Room.inMemoryDatabaseBuilder(
+            ApplicationProvider.getApplicationContext(),
+            ContactDiaryDatabase::class.java
+        )
+            .build()
+
+    private val personDao = contactDiaryDatabase.personDao()
+    private val locationDao = contactDiaryDatabase.locationDao()
+    private val personEncounterDao = contactDiaryDatabase.personEncounterDao()
+    private val locationVisitDao = contactDiaryDatabase.locationVisitDao()
+
+    private fun List<ContactDiaryPersonEncounterWrapper>.toContactDiaryPersonEncounterEntityList(): List<ContactDiaryPersonEncounterEntity> =
+        this.map { it.contactDiaryPersonEncounterEntity }
+
+    private fun List<ContactDiaryLocationVisitWrapper>.toContactDiaryLocationVisitEntityList(): List<ContactDiaryLocationVisitEntity> =
+        this.map { it.contactDiaryLocationVisitEntity }
+
+    @After
+    fun teardown() {
+        contactDiaryDatabase.clearAllTables()
+    }
+
+    @Test
+    fun checkPersonEncounterDeletedWhenReferencedPersonDeleted() = runBlocking {
+        val personFlow = personDao.allEntries()
+        val personEncounterFlow = personEncounterDao
+            .allEntries()
+            .map { it.toContactDiaryPersonEncounterEntityList() }
+
+        personFlow.first() shouldBe emptyList()
+        personEncounterFlow.first() shouldBe emptyList()
+
+        personDao.insert(person)
+        personEncounterDao.insert(personEncounter)
+        personFlow.first() shouldBe listOf(person)
+        personEncounterFlow.first() shouldBe listOf(personEncounter)
+
+        personDao.delete(person)
+        personFlow.first() shouldBe emptyList()
+        personEncounterFlow.first() shouldBe emptyList()
+    }
+
+    @Test
+    fun checkLocationVisitDeletedWhenReferencedLocationDeleted() = runBlocking {
+        val locationFlow = locationDao.allEntries()
+        val locationVisitFlow = locationVisitDao
+            .allEntries()
+            .map { it.toContactDiaryLocationVisitEntityList() }
+
+        locationFlow.first() shouldBe emptyList()
+        locationVisitFlow.first() shouldBe emptyList()
+
+        locationDao.insert(location)
+        locationVisitDao.insert(locationVisit)
+        locationFlow.first() shouldBe listOf(location)
+        locationVisitFlow.first() shouldBe listOf(locationVisit)
+
+        locationDao.delete(location)
+        locationFlow.first() shouldBe emptyList()
+        locationVisitFlow.first() shouldBe emptyList()
+    }
+
+    @Test
+    fun getCorrectEntityForDate() = runBlocking {
+        val yesterday = LocalDate.now().minusDays(1)
+        val tomorrow = LocalDate.now().plusDays(1)
+        val personEncounterYesterday =
+            ContactDiaryPersonEncounterEntity(id = 5, date = yesterday, fkPersonId = person.personId)
+        val personEncounterTomorrow =
+            ContactDiaryPersonEncounterEntity(id = 6, date = tomorrow, fkPersonId = person.personId)
+        val locationVisitYesterday =
+            ContactDiaryLocationVisitEntity(id = 7, date = yesterday, fkLocationId = location.locationId)
+        val locationVisitTomorrow =
+            ContactDiaryLocationVisitEntity(id = 8, date = tomorrow, fkLocationId = location.locationId)
+        val encounterList = listOf(personEncounter, personEncounterYesterday, personEncounterTomorrow)
+        val visitList = listOf(locationVisit, locationVisitYesterday, locationVisitTomorrow)
+        val personEncounterFlow = personEncounterDao.allEntries().map { it.toContactDiaryPersonEncounterEntityList() }
+        val locationVisitFlow = locationVisitDao.allEntries()
+            .map { it.toContactDiaryLocationVisitEntityList() }
+
+        personDao.insert(person)
+        personEncounterDao.insert(encounterList)
+        locationDao.insert(location)
+        locationVisitDao.insert(visitList)
+
+        personEncounterFlow.first() shouldBe encounterList
+        locationVisitFlow.first() shouldBe visitList
+
+        personEncounterDao.entitiesForDate(yesterday).first().toContactDiaryPersonEncounterEntityList() shouldBe listOf(personEncounterYesterday)
+        personEncounterDao.entitiesForDate(date).first().toContactDiaryPersonEncounterEntityList() shouldBe listOf(personEncounter)
+        personEncounterDao.entitiesForDate(tomorrow).first().toContactDiaryPersonEncounterEntityList() shouldBe listOf(personEncounterTomorrow)
+
+        locationVisitDao.entitiesForDate(yesterday).first().toContactDiaryLocationVisitEntityList() shouldBe listOf(locationVisitYesterday)
+        locationVisitDao.entitiesForDate(date).first().toContactDiaryLocationVisitEntityList() shouldBe listOf(locationVisit)
+        locationVisitDao.entitiesForDate(tomorrow).first().toContactDiaryLocationVisitEntityList() shouldBe listOf(locationVisitTomorrow)
+    }
+}
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionDoneFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionDoneFragmentTest.kt
deleted file mode 100644
index 989bbcdcbeb17fcc04c3e0df15b236c11da33df8..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionDoneFragmentTest.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package de.rki.coronawarnapp.ui.submission
-
-import androidx.fragment.app.testing.launchFragment
-import androidx.fragment.app.testing.launchFragmentInContainer
-import androidx.test.espresso.Espresso.onView
-import androidx.test.espresso.action.ViewActions.click
-import androidx.test.espresso.matcher.ViewMatchers.withId
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import dagger.Module
-import dagger.android.ContributesAndroidInjector
-import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.ui.submission.fragment.SubmissionDoneFragment
-import de.rki.coronawarnapp.ui.submission.viewmodel.SubmissionDoneViewModel
-import io.mockk.MockKAnnotations
-import io.mockk.impl.annotations.MockK
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import testhelpers.BaseUITest
-
-@RunWith(AndroidJUnit4::class)
-class SubmissionDoneFragmentTest : BaseUITest() {
-
-    @MockK lateinit var viewModel: SubmissionDoneViewModel
-
-    @Before
-    fun setup() {
-        MockKAnnotations.init(this, relaxed = true)
-        setupMockViewModel(object : SubmissionDoneViewModel.Factory {
-            override fun create(): SubmissionDoneViewModel = viewModel
-        })
-    }
-
-    @After
-    fun teardown() {
-        clearAllViewModels()
-    }
-
-    @Test
-    fun launch_fragment() {
-        launchFragment<SubmissionDoneFragment>()
-    }
-
-    @Test fun testDoneClicked() {
-        val scenario = launchFragmentInContainer<SubmissionDoneFragment>()
-        onView(withId(R.id.submission_done_button_done))
-            .perform(click())
-
-        // TODO verify result
-    }
-}
-
-@Module
-abstract class SubmissionDoneTestModule {
-    @ContributesAndroidInjector
-    abstract fun submissionDoneScreen(): SubmissionDoneFragment
-}
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionOtherWarningFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionOtherWarningFragmentTest.kt
deleted file mode 100644
index eb4a3dba7d25d21d9461208ff1d5604a5cf1f794..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionOtherWarningFragmentTest.kt
+++ /dev/null
@@ -1,83 +0,0 @@
-package de.rki.coronawarnapp.ui.submission
-
-import androidx.fragment.app.testing.launchFragment
-import androidx.fragment.app.testing.launchFragmentInContainer
-import androidx.test.espresso.Espresso.onView
-import androidx.test.espresso.action.ViewActions.click
-import androidx.test.espresso.action.ViewActions.scrollTo
-import androidx.test.espresso.matcher.ViewMatchers.withId
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import dagger.Module
-import dagger.android.ContributesAndroidInjector
-import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.submission.Symptoms
-import de.rki.coronawarnapp.ui.submission.symptoms.calendar.SubmissionSymptomCalendarViewModel
-import de.rki.coronawarnapp.ui.submission.symptoms.introduction.SubmissionSymptomIntroductionViewModel
-import de.rki.coronawarnapp.ui.submission.warnothers.SubmissionResultPositiveOtherWarningFragment
-import de.rki.coronawarnapp.ui.submission.warnothers.SubmissionResultPositiveOtherWarningViewModel
-import io.mockk.MockKAnnotations
-import io.mockk.impl.annotations.MockK
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import testhelpers.BaseUITest
-
-@RunWith(AndroidJUnit4::class)
-class SubmissionOtherWarningFragmentTest : BaseUITest() {
-
-    @MockK lateinit var viewModel: SubmissionResultPositiveOtherWarningViewModel
-    @MockK lateinit var symptomIntroViewModel: SubmissionSymptomIntroductionViewModel
-    @MockK lateinit var symptomCalendarViewModel: SubmissionSymptomCalendarViewModel
-
-    //  @MockK lateinit var symptoms: Symptoms
-
-    @Before
-    fun setup() {
-        MockKAnnotations.init(this, relaxed = true)
-        setupMockViewModel(object : SubmissionSymptomIntroductionViewModel.Factory {
-            override fun create(): SubmissionSymptomIntroductionViewModel = symptomIntroViewModel
-        })
-
-        /* every { symptomIntroViewModel.symptomIndication } returns MutableLiveData()
-         every { symptomIntroViewModel. } returns MutableLiveData()
-
-         symptomIntroViewModel.onPositiveSymptomIndication()
-         symptomIntroViewModel.symptomIndication.postValue("tesasdf") */
-
-        setupMockViewModel(object : SubmissionSymptomCalendarViewModel.Factory {
-            override fun create(symptomIndication: Symptoms.Indication): SubmissionSymptomCalendarViewModel =
-                symptomCalendarViewModel
-        })
-
-        setupMockViewModel(object : SubmissionResultPositiveOtherWarningViewModel.Factory {
-            override fun create(symptoms: Symptoms): SubmissionResultPositiveOtherWarningViewModel =
-                viewModel
-        })
-    }
-
-    @After
-    fun teardown() {
-        clearAllViewModels()
-    }
-
-    @Test
-    fun launch_fragment() {
-        launchFragment<SubmissionResultPositiveOtherWarningFragment>()
-    }
-
-    @Test fun testOtherWarningNextClicked() {
-        val scenario = launchFragmentInContainer<SubmissionResultPositiveOtherWarningFragment>()
-        onView(withId(R.id.submission_positive_other_warning_button_next))
-            .perform(scrollTo())
-            .perform(click())
-
-        // TODO verify result
-    }
-}
-
-@Module
-abstract class SubmissionOtherWarningTestModule {
-    @ContributesAndroidInjector
-    abstract fun submissionOtherWarningScreen(): SubmissionResultPositiveOtherWarningFragment
-}
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomCalendarFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomCalendarFragmentTest.kt
deleted file mode 100644
index b592443c863b3a5d634d83696455ae1b42252418..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionSymptomCalendarFragmentTest.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-package de.rki.coronawarnapp.ui.submission
-
-import androidx.fragment.app.testing.launchFragment
-import androidx.fragment.app.testing.launchFragmentInContainer
-import androidx.test.espresso.Espresso.onView
-import androidx.test.espresso.action.ViewActions.click
-import androidx.test.espresso.action.ViewActions.scrollTo
-import androidx.test.espresso.matcher.ViewMatchers.withId
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import dagger.Module
-import dagger.android.ContributesAndroidInjector
-import de.rki.coronawarnapp.R
-import de.rki.coronawarnapp.submission.Symptoms
-import de.rki.coronawarnapp.ui.submission.symptoms.calendar.SubmissionSymptomCalendarFragment
-import de.rki.coronawarnapp.ui.submission.symptoms.calendar.SubmissionSymptomCalendarViewModel
-import io.mockk.MockKAnnotations
-import io.mockk.impl.annotations.MockK
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import testhelpers.BaseUITest
-
-@RunWith(AndroidJUnit4::class)
-class SubmissionSymptomCalendarFragmentTest : BaseUITest() {
-
-    @MockK lateinit var viewModel: SubmissionSymptomCalendarViewModel
-
-    /*  private val symptoms = Symptoms(Symptoms.StartOf.OneToTwoWeeksAgo, POSITIVE)
-      private val positiveSymptomIndication = POSITIVE;
-      private val negativeSymptomIndication = Symptoms.Indication.NEGATIVE;
-      private val noSymptomIndication = Symptoms.Indication.NO_INFORMATION;*/
-
-    @Before
-    fun setup() {
-        MockKAnnotations.init(this, relaxed = true)
-
-        setupMockViewModel(object : SubmissionSymptomCalendarViewModel.Factory {
-            override fun create(symptomIndication: Symptoms.Indication): SubmissionSymptomCalendarViewModel =
-                viewModel
-        })
-    }
-
-    @After
-    fun teardown() {
-        clearAllViewModels()
-    }
-
-    @Test
-    fun launch_fragment() {
-        launchFragment<SubmissionSymptomCalendarFragment>()
-    }
-
-    @Test fun testSymptomCalendarNextClicked() {
-        val scenario = launchFragmentInContainer<SubmissionSymptomCalendarFragment>()
-        onView(withId(R.id.symptom_button_next))
-            .perform(scrollTo())
-            .perform(click())
-
-        // TODO verify result
-    }
-}
-
-@Module
-abstract class SubmissionSymptomCalendarFragmentTestModule {
-    @ContributesAndroidInjector
-    abstract fun submissionSymptomCalendarScreen(): SubmissionSymptomCalendarFragment
-}
diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultConsentGivenFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultConsentGivenFragmentTest.kt
index 993882d9306c564008e1ba4f3efee7be8e2b8538..cc999d6c3f93320ac4c2f84c447d0d29d6b307d5 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultConsentGivenFragmentTest.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/submission/SubmissionTestResultConsentGivenFragmentTest.kt
@@ -15,12 +15,12 @@ import de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultConsent
 import de.rki.coronawarnapp.ui.submission.testresult.SubmissionTestResultConsentGivenViewModel
 import io.mockk.MockKAnnotations
 import io.mockk.impl.annotations.MockK
+import io.mockk.mockk
+import io.mockk.verify
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
 import testhelpers.BaseUITest
 
 @RunWith(AndroidJUnit4::class)
@@ -49,7 +49,7 @@ class SubmissionTestResultConsentGivenFragmentTest : BaseUITest() {
     @Test
     fun testEventConsentGivenContinueWithSymptomsClicked() {
 
-        val mockNavController = mock(NavController::class.java)
+        val mockNavController = mockk<NavController>()
         val scenario = launchFragmentInContainer<SubmissionTestResultConsentGivenFragment>()
 
         scenario.onFragment { fragment ->
@@ -57,7 +57,9 @@ class SubmissionTestResultConsentGivenFragmentTest : BaseUITest() {
         }
         // Verify that performing a click prompts the correct Navigation action
         onView(ViewMatchers.withId(R.id.submission_test_result_button_consent_given_continue)).perform(ViewActions.click())
-        verify(mockNavController).navigate(R.id.action_submissionTestResultConsentGivenFragment_to_submissionSymptomIntroductionFragment)
+        verify {
+            mockNavController.navigate(R.id.action_submissionTestResultConsentGivenFragment_to_submissionSymptomIntroductionFragment)
+        }
     }
 }
 
diff --git a/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt b/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt
index 2e7625e1fc676f8106f7e15034a670ff387547e9..1370a3a2bc1b1e7af66cf722933061d02bb15fa6 100644
--- a/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt
+++ b/Corona-Warn-App/src/androidTest/java/testhelpers/FragmentTestModuleRegistrar.kt
@@ -10,11 +10,8 @@ import de.rki.coronawarnapp.ui.onboarding.OnboardingTestFragmentModule
 import de.rki.coronawarnapp.ui.onboarding.OnboardingTracingFragmentTestModule
 import de.rki.coronawarnapp.ui.submission.SubmissionContactTestModule
 import de.rki.coronawarnapp.ui.submission.SubmissionDispatcherTestModule
-import de.rki.coronawarnapp.ui.submission.SubmissionDoneTestModule
 import de.rki.coronawarnapp.ui.submission.SubmissionIntroTestModule
-import de.rki.coronawarnapp.ui.submission.SubmissionOtherWarningTestModule
 import de.rki.coronawarnapp.ui.submission.SubmissionQRScanFragmentModule
-import de.rki.coronawarnapp.ui.submission.SubmissionSymptomCalendarFragmentTestModule
 import de.rki.coronawarnapp.ui.submission.SubmissionSymptomIntroFragmentTestModule
 import de.rki.coronawarnapp.ui.submission.SubmissionTanTestModule
 import de.rki.coronawarnapp.ui.submission.SubmissionTestResultConsentGivenTestModule
@@ -36,11 +33,8 @@ import de.rki.coronawarnapp.ui.submission.SubmissionTestResultTestModule
         SubmissionTanTestModule::class,
         SubmissionTestResultTestModule::class,
         SubmissionTestResultConsentGivenTestModule::class,
-        SubmissionOtherWarningTestModule::class,
         SubmissionSymptomIntroFragmentTestModule::class,
-        SubmissionSymptomCalendarFragmentTestModule::class,
         SubmissionContactTestModule::class,
-        SubmissionDoneTestModule::class,
         SubmissionQRScanFragmentModule::class
     ]
 )
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ContactDiaryModule.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ContactDiaryModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b32ac7a951a0aaf8c05e6ad11f7abf7cf73f9c98
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/ContactDiaryModule.kt
@@ -0,0 +1,42 @@
+package de.rki.coronawarnapp.contactdiary
+
+import dagger.Module
+import dagger.Provides
+import de.rki.coronawarnapp.contactdiary.storage.ContactDiaryDatabase
+import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryLocationDao
+import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryLocationVisitDao
+import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryPersonDao
+import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryPersonEncounterDao
+import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository
+import de.rki.coronawarnapp.contactdiary.storage.repo.DefaultContactDiaryRepository
+import javax.inject.Singleton
+
+@Module
+class ContactDiaryModule {
+
+    @Singleton
+    @Provides
+    fun contactDiaryDatabase(contactDiaryDatabaseFactory: ContactDiaryDatabase.Factory): ContactDiaryDatabase =
+        contactDiaryDatabaseFactory.create()
+
+    @Provides
+    fun locationDao(contactDiaryDatabase: ContactDiaryDatabase): ContactDiaryLocationDao =
+        contactDiaryDatabase.locationDao()
+
+    @Provides
+    fun locationVisitDao(contactDiaryDatabase: ContactDiaryDatabase): ContactDiaryLocationVisitDao =
+        contactDiaryDatabase.locationVisitDao()
+
+    @Provides
+    fun personDao(contactDiaryDatabase: ContactDiaryDatabase): ContactDiaryPersonDao =
+        contactDiaryDatabase.personDao()
+
+    @Provides
+    fun personEncounterDao(contactDiaryDatabase: ContactDiaryDatabase): ContactDiaryPersonEncounterDao =
+        contactDiaryDatabase.personEncounterDao()
+
+    @Singleton
+    @Provides
+    fun contactDiaryRepo(defaultContactDiaryRepository: DefaultContactDiaryRepository): ContactDiaryRepository =
+        defaultContactDiaryRepository
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryElement.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryElement.kt
deleted file mode 100644
index ec1a863b74e3e3a09b905aba791f2219a05a2c0d..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryElement.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package de.rki.coronawarnapp.contactdiary.model
-
-import java.time.Instant
-
-interface ContactDiaryElement {
-
-    val createdAt: Instant
-
-    val people: List<Person>
-    val locations: List<Location>
-
-    val numberOfPersons: Int
-        get() = people.size
-
-    val numberOfLocations: Int
-        get() = locations.size
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocation.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4618a0b9da3230445c696dde7aae7834289dbc13
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocation.kt
@@ -0,0 +1,9 @@
+package de.rki.coronawarnapp.contactdiary.model
+
+interface ContactDiaryLocation {
+    val locationId: Long
+    var locationName: String
+}
+
+fun List<ContactDiaryLocation>.sortByNameAndIdASC(): List<ContactDiaryLocation> =
+    this.sortedWith(compareBy({ it.locationName }, { it.locationId }))
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocationVisit.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocationVisit.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a1f4061d7966086715a548e5c50784a8f9f1a085
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryLocationVisit.kt
@@ -0,0 +1,12 @@
+package de.rki.coronawarnapp.contactdiary.model
+
+import org.joda.time.LocalDate
+
+interface ContactDiaryLocationVisit {
+    val id: Long
+    val date: LocalDate
+    val contactDiaryLocation: ContactDiaryLocation
+}
+
+fun List<ContactDiaryLocationVisit>.sortByNameAndIdASC(): List<ContactDiaryLocationVisit> =
+    this.sortedWith(compareBy({ it.contactDiaryLocation.locationName }, { it.contactDiaryLocation.locationId }))
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPerson.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPerson.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5657484a05b1e2c808c21c69808a8d456f5ab4a0
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPerson.kt
@@ -0,0 +1,9 @@
+package de.rki.coronawarnapp.contactdiary.model
+
+interface ContactDiaryPerson {
+    val personId: Long
+    var fullName: String
+}
+
+fun List<ContactDiaryPerson>.sortByNameAndIdASC(): List<ContactDiaryPerson> =
+    this.sortedWith(compareBy({ it.fullName }, { it.personId }))
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPersonEncounter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPersonEncounter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..60bf3887a3680388cbb6ec527eaf5e0bfc86ffec
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/ContactDiaryPersonEncounter.kt
@@ -0,0 +1,12 @@
+package de.rki.coronawarnapp.contactdiary.model
+
+import org.joda.time.LocalDate
+
+interface ContactDiaryPersonEncounter {
+    val id: Long
+    val date: LocalDate
+    val contactDiaryPerson: ContactDiaryPerson
+}
+
+fun List<ContactDiaryPersonEncounter>.sortByNameAndIdASC(): List<ContactDiaryPersonEncounter> =
+    this.sortedWith(compareBy({ it.contactDiaryPerson.fullName }, { it.contactDiaryPerson.personId }))
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryElement.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryElement.kt
deleted file mode 100644
index 0bd0eaf80c02fb4f55021845dfefd0498c0d6359..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryElement.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package de.rki.coronawarnapp.contactdiary.model
-
-import java.time.Instant
-
-data class DefaultContactDiaryElement(
-    override val createdAt: Instant,
-    override val people: List<Person>,
-    override val locations: List<Location>
-) : ContactDiaryElement
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryLocation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryLocation.kt
new file mode 100644
index 0000000000000000000000000000000000000000..65bf6c6e5be5df3b6215d18c2bc2e371bec46e29
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryLocation.kt
@@ -0,0 +1,6 @@
+package de.rki.coronawarnapp.contactdiary.model
+
+data class DefaultContactDiaryLocation(
+    override val locationId: Long = 0L,
+    override var locationName: String
+) : ContactDiaryLocation
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryLocationVisit.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryLocationVisit.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0c2124a3c625123c3bac258c68db6e82e92e6702
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryLocationVisit.kt
@@ -0,0 +1,9 @@
+package de.rki.coronawarnapp.contactdiary.model
+
+import org.joda.time.LocalDate
+
+data class DefaultContactDiaryLocationVisit(
+    override val id: Long = 0L,
+    override val date: LocalDate,
+    override val contactDiaryLocation: ContactDiaryLocation
+) : ContactDiaryLocationVisit
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryPerson.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryPerson.kt
new file mode 100644
index 0000000000000000000000000000000000000000..fdf73bd6e014940d71c58ea54726050df3519c20
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryPerson.kt
@@ -0,0 +1,6 @@
+package de.rki.coronawarnapp.contactdiary.model
+
+data class DefaultContactDiaryPerson(
+    override val personId: Long = 0L,
+    override var fullName: String
+) : ContactDiaryPerson
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryPersonEncounter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryPersonEncounter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..bdd303ef066b478fc64b0063e8800bab7a098285
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultContactDiaryPersonEncounter.kt
@@ -0,0 +1,9 @@
+package de.rki.coronawarnapp.contactdiary.model
+
+import org.joda.time.LocalDate
+
+data class DefaultContactDiaryPersonEncounter(
+    override val id: Long = 0L,
+    override val date: LocalDate,
+    override val contactDiaryPerson: ContactDiaryPerson
+) : ContactDiaryPersonEncounter
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultLocation.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultLocation.kt
deleted file mode 100644
index 37ed6bfa0ace2d4019dcfe7d70beeaf699edc954..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultLocation.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package de.rki.coronawarnapp.contactdiary.model
-
-data class DefaultLocation(override var locationName: String) : Location
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultPerson.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultPerson.kt
deleted file mode 100644
index 9a8ed3414b8bba6e45294e61877fefba2fdef1a7..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/DefaultPerson.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package de.rki.coronawarnapp.contactdiary.model
-
-data class DefaultPerson(override var fullName: String) : Person
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/Location.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/Location.kt
deleted file mode 100644
index b2195b3339876962cadbda7eb0e6f4a3f4f08981..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/Location.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package de.rki.coronawarnapp.contactdiary.model
-
-interface Location {
-    var locationName: String
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/Person.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/Person.kt
deleted file mode 100644
index 7fcc04e912e97153438e196efa0d959d4ef317af..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/model/Person.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package de.rki.coronawarnapp.contactdiary.model
-
-interface Person {
-    var fullName: String
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/ContactDiaryDatabase.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/ContactDiaryDatabase.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b80474dca2a053ec526af698686352a6904cb838
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/ContactDiaryDatabase.kt
@@ -0,0 +1,48 @@
+package de.rki.coronawarnapp.contactdiary.storage
+
+import android.content.Context
+import androidx.room.Database
+import androidx.room.Room
+import androidx.room.RoomDatabase
+import androidx.room.TypeConverters
+import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryLocationDao
+import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryLocationVisitDao
+import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryPersonDao
+import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryPersonEncounterDao
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryLocationEntity
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryLocationVisitEntity
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryPersonEncounterEntity
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryPersonEntity
+import de.rki.coronawarnapp.util.database.CommonConverters
+import de.rki.coronawarnapp.util.di.AppContext
+import javax.inject.Inject
+
+@Database(
+    entities = [
+        ContactDiaryLocationEntity::class,
+        ContactDiaryLocationVisitEntity::class,
+        ContactDiaryPersonEntity::class,
+        ContactDiaryPersonEncounterEntity::class
+    ],
+    version = 1,
+    exportSchema = true
+)
+@TypeConverters(CommonConverters::class)
+abstract class ContactDiaryDatabase : RoomDatabase() {
+
+    abstract fun locationDao(): ContactDiaryLocationDao
+    abstract fun locationVisitDao(): ContactDiaryLocationVisitDao
+    abstract fun personDao(): ContactDiaryPersonDao
+    abstract fun personEncounterDao(): ContactDiaryPersonEncounterDao
+
+    class Factory @Inject constructor(@AppContext private val ctx: Context) {
+        fun create(): ContactDiaryDatabase = Room
+            .databaseBuilder(ctx, ContactDiaryDatabase::class.java, CONTACT_DIARY_DATABASE_NAME)
+            .fallbackToDestructiveMigration()
+            .build()
+    }
+
+    companion object {
+        private const val CONTACT_DIARY_DATABASE_NAME = "ContactDiary-db"
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/ContactDiaryRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/ContactDiaryRepository.kt
deleted file mode 100644
index e4dd8e0dca43eef4c54053e3c70b720fd278da6b..0000000000000000000000000000000000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/ContactDiaryRepository.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package de.rki.coronawarnapp.contactdiary.storage
-
-class ContactDiaryRepository
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/BaseDao.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/BaseDao.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f6c96c1a458a47a32305fb63f9bfbb313aba0ea6
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/BaseDao.kt
@@ -0,0 +1,15 @@
+package de.rki.coronawarnapp.contactdiary.storage.dao
+
+import kotlinx.coroutines.flow.Flow
+
+interface BaseDao<in T, out U> {
+    suspend fun insert(entity: T)
+    suspend fun insert(entities: List<T>)
+    suspend fun update(entity: T)
+    suspend fun update(entities: List<T>)
+    suspend fun delete(entity: T)
+    suspend fun delete(entities: List<T>)
+    suspend fun deleteAll()
+    suspend fun entityForId(id: Long): U
+    fun allEntries(): Flow<List<U>>
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/BaseRoomDao.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/BaseRoomDao.kt
new file mode 100644
index 0000000000000000000000000000000000000000..22776a74dcd7f6327730d0435f529c71a793a128
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/BaseRoomDao.kt
@@ -0,0 +1,25 @@
+package de.rki.coronawarnapp.contactdiary.storage.dao
+
+import androidx.room.Delete
+import androidx.room.Insert
+import androidx.room.Update
+
+abstract class BaseRoomDao<T, U> : BaseDao<T, U> {
+    @Insert
+    abstract override suspend fun insert(entity: T)
+
+    @Insert
+    abstract override suspend fun insert(entities: List<T>)
+
+    @Update
+    abstract override suspend fun update(entity: T)
+
+    @Update
+    abstract override suspend fun update(entities: List<T>)
+
+    @Delete
+    abstract override suspend fun delete(entity: T)
+
+    @Delete
+    abstract override suspend fun delete(entities: List<T>)
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/ContactDiaryLocationDao.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/ContactDiaryLocationDao.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4d9cfa474c3b876266969d55767b95650d3d6efe
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/ContactDiaryLocationDao.kt
@@ -0,0 +1,19 @@
+package de.rki.coronawarnapp.contactdiary.storage.dao
+
+import androidx.room.Dao
+import androidx.room.Query
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryLocationEntity
+import kotlinx.coroutines.flow.Flow
+
+@Dao
+abstract class ContactDiaryLocationDao : BaseRoomDao<ContactDiaryLocationEntity, ContactDiaryLocationEntity>() {
+
+    @Query("SELECT * FROM locations")
+    abstract override fun allEntries(): Flow<List<ContactDiaryLocationEntity>>
+
+    @Query("SELECT * FROM locations WHERE locationId = :id")
+    abstract override suspend fun entityForId(id: Long): ContactDiaryLocationEntity
+
+    @Query("DELETE FROM locations")
+    abstract override suspend fun deleteAll()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/ContactDiaryLocationVisitDao.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/ContactDiaryLocationVisitDao.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ac587cc8ca8d311674633f459b3bcace1f5d0abe
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/ContactDiaryLocationVisitDao.kt
@@ -0,0 +1,29 @@
+package de.rki.coronawarnapp.contactdiary.storage.dao
+
+import androidx.room.Dao
+import androidx.room.Query
+import androidx.room.Transaction
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryLocationVisitEntity
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryLocationVisitWrapper
+import kotlinx.coroutines.flow.Flow
+import org.joda.time.LocalDate
+
+@Dao
+abstract class ContactDiaryLocationVisitDao :
+    BaseRoomDao<ContactDiaryLocationVisitEntity, ContactDiaryLocationVisitWrapper>() {
+
+    @Transaction
+    @Query("SELECT * FROM locationvisits")
+    abstract override fun allEntries(): Flow<List<ContactDiaryLocationVisitWrapper>>
+
+    @Transaction
+    @Query("SELECT * FROM locationvisits WHERE id = :id")
+    abstract override suspend fun entityForId(id: Long): ContactDiaryLocationVisitWrapper
+
+    @Transaction
+    @Query("SELECT * FROM locationvisits WHERE date = :date")
+    abstract fun entitiesForDate(date: LocalDate): Flow<List<ContactDiaryLocationVisitWrapper>>
+
+    @Query("DELETE FROM locationvisits")
+    abstract override suspend fun deleteAll()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/ContactDiaryPersonDao.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/ContactDiaryPersonDao.kt
new file mode 100644
index 0000000000000000000000000000000000000000..4889c64f5c13de5bf361c69a86748f7a358267fa
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/ContactDiaryPersonDao.kt
@@ -0,0 +1,19 @@
+package de.rki.coronawarnapp.contactdiary.storage.dao
+
+import androidx.room.Dao
+import androidx.room.Query
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryPersonEntity
+import kotlinx.coroutines.flow.Flow
+
+@Dao
+abstract class ContactDiaryPersonDao : BaseRoomDao<ContactDiaryPersonEntity, ContactDiaryPersonEntity>() {
+
+    @Query("SELECT * FROM persons")
+    abstract override fun allEntries(): Flow<List<ContactDiaryPersonEntity>>
+
+    @Query("SELECT * FROM persons WHERE personId = :id")
+    abstract override suspend fun entityForId(id: Long): ContactDiaryPersonEntity
+
+    @Query("DELETE FROM persons")
+    abstract override suspend fun deleteAll()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/ContactDiaryPersonEncounterDao.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/ContactDiaryPersonEncounterDao.kt
new file mode 100644
index 0000000000000000000000000000000000000000..696370f45f1127cce5f09b40f21eb5ff3e5cb1ce
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/dao/ContactDiaryPersonEncounterDao.kt
@@ -0,0 +1,29 @@
+package de.rki.coronawarnapp.contactdiary.storage.dao
+
+import androidx.room.Dao
+import androidx.room.Query
+import androidx.room.Transaction
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryPersonEncounterEntity
+import de.rki.coronawarnapp.contactdiary.storage.entity.ContactDiaryPersonEncounterWrapper
+import kotlinx.coroutines.flow.Flow
+import org.joda.time.LocalDate
+
+@Dao
+abstract class ContactDiaryPersonEncounterDao :
+    BaseRoomDao<ContactDiaryPersonEncounterEntity, ContactDiaryPersonEncounterWrapper>() {
+
+    @Transaction
+    @Query("SELECT * FROM personencounters")
+    abstract override fun allEntries(): Flow<List<ContactDiaryPersonEncounterWrapper>>
+
+    @Transaction
+    @Query("SELECT * FROM personencounters WHERE id = :id")
+    abstract override suspend fun entityForId(id: Long): ContactDiaryPersonEncounterWrapper
+
+    @Transaction
+    @Query("SELECT * FROM personencounters WHERE date = :date")
+    abstract fun entitiesForDate(date: LocalDate): Flow<List<ContactDiaryPersonEncounterWrapper>>
+
+    @Query("DELETE FROM personencounters")
+    abstract override suspend fun deleteAll()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryLocationEntity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryLocationEntity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ffd350e419111ae73d764ef4f5aae5564e244d9d
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryLocationEntity.kt
@@ -0,0 +1,15 @@
+package de.rki.coronawarnapp.contactdiary.storage.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocation
+
+@Entity(tableName = "locations")
+data class ContactDiaryLocationEntity(
+    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "locationId") override val locationId: Long = 0L,
+    @ColumnInfo(name = "locationName") override var locationName: String
+) : ContactDiaryLocation
+
+fun ContactDiaryLocation.toContactDiaryLocationEntity(): ContactDiaryLocationEntity =
+    ContactDiaryLocationEntity(this.locationId, this.locationName)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryLocationVisitEntity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryLocationVisitEntity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3bfdd7541c082e0559f490ae39a3fda5bef1ff6b
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryLocationVisitEntity.kt
@@ -0,0 +1,32 @@
+package de.rki.coronawarnapp.contactdiary.storage.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.ForeignKey
+import androidx.room.Index
+import androidx.room.PrimaryKey
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocationVisit
+import org.joda.time.LocalDate
+
+@Entity(
+    tableName = "locationvisits",
+    foreignKeys = [
+        ForeignKey(
+            entity = ContactDiaryLocationEntity::class,
+            parentColumns = ["locationId"],
+            childColumns = ["fkLocationId"],
+            onDelete = ForeignKey.CASCADE,
+            onUpdate = ForeignKey.CASCADE,
+            deferred = true
+        )
+    ],
+    indices = [Index("fkLocationId")]
+)
+data class ContactDiaryLocationVisitEntity(
+    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") val id: Long = 0L,
+    @ColumnInfo(name = "date") val date: LocalDate,
+    @ColumnInfo(name = "fkLocationId") val fkLocationId: Long
+)
+
+fun ContactDiaryLocationVisit.toContactDiaryLocationVisitEntity(): ContactDiaryLocationVisitEntity =
+    ContactDiaryLocationVisitEntity(id = this.id, date = this.date, fkLocationId = this.contactDiaryLocation.locationId)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryLocationVisitWrapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryLocationVisitWrapper.kt
new file mode 100644
index 0000000000000000000000000000000000000000..333659e2cdb0f3e8a116457c1bea579581906dcc
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryLocationVisitWrapper.kt
@@ -0,0 +1,24 @@
+package de.rki.coronawarnapp.contactdiary.storage.entity
+
+import androidx.room.Embedded
+import androidx.room.Relation
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocationVisit
+import de.rki.coronawarnapp.contactdiary.model.DefaultContactDiaryLocationVisit
+import de.rki.coronawarnapp.contactdiary.model.sortByNameAndIdASC
+
+class ContactDiaryLocationVisitWrapper(
+    @Embedded val contactDiaryLocationVisitEntity: ContactDiaryLocationVisitEntity,
+    @Relation(parentColumn = "fkLocationId", entityColumn = "locationId")
+    val contactDiaryLocationEntity: ContactDiaryLocationEntity
+)
+
+fun ContactDiaryLocationVisitWrapper.toContactDiaryLocationVisit(): ContactDiaryLocationVisit =
+    DefaultContactDiaryLocationVisit(
+        id = this.contactDiaryLocationVisitEntity.id,
+        date = this.contactDiaryLocationVisitEntity.date,
+        contactDiaryLocation = this.contactDiaryLocationEntity
+    )
+
+fun List<ContactDiaryLocationVisitWrapper>.toContactDiaryLocationVisitSortedList(): List<ContactDiaryLocationVisit> =
+    this.map { it.toContactDiaryLocationVisit() }
+        .sortByNameAndIdASC()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryPersonEncounterEntity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryPersonEncounterEntity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a98ba8661d9f28757e2adee4ce7cdd28f6655e89
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryPersonEncounterEntity.kt
@@ -0,0 +1,32 @@
+package de.rki.coronawarnapp.contactdiary.storage.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.ForeignKey
+import androidx.room.Index
+import androidx.room.PrimaryKey
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPersonEncounter
+import org.joda.time.LocalDate
+
+@Entity(
+    tableName = "personencounters",
+    foreignKeys = [
+        ForeignKey(
+            entity = ContactDiaryPersonEntity::class,
+            parentColumns = ["personId"],
+            childColumns = ["fkPersonId"],
+            onDelete = ForeignKey.CASCADE,
+            onUpdate = ForeignKey.CASCADE,
+            deferred = true
+        )
+    ],
+    indices = [Index("fkPersonId")]
+)
+data class ContactDiaryPersonEncounterEntity(
+    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") val id: Long = 0L,
+    @ColumnInfo(name = "date") val date: LocalDate,
+    @ColumnInfo(name = "fkPersonId") val fkPersonId: Long
+)
+
+fun ContactDiaryPersonEncounter.toContactDiaryPersonEncounterEntity(): ContactDiaryPersonEncounterEntity =
+    ContactDiaryPersonEncounterEntity(id = this.id, date = this.date, fkPersonId = this.contactDiaryPerson.personId)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryPersonEncounterWrapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryPersonEncounterWrapper.kt
new file mode 100644
index 0000000000000000000000000000000000000000..26acf434fef972a91e789c3f2286fe2629f5ca23
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryPersonEncounterWrapper.kt
@@ -0,0 +1,25 @@
+package de.rki.coronawarnapp.contactdiary.storage.entity
+
+import androidx.room.Embedded
+import androidx.room.Relation
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPersonEncounter
+import de.rki.coronawarnapp.contactdiary.model.DefaultContactDiaryPersonEncounter
+import de.rki.coronawarnapp.contactdiary.model.sortByNameAndIdASC
+
+data class ContactDiaryPersonEncounterWrapper(
+    @Embedded val contactDiaryPersonEncounterEntity: ContactDiaryPersonEncounterEntity,
+    @Relation(parentColumn = "fkPersonId", entityColumn = "personId")
+    val contactDiaryPersonEntity: ContactDiaryPersonEntity
+)
+
+fun ContactDiaryPersonEncounterWrapper.toContactDiaryPersonEncounter(): ContactDiaryPersonEncounter =
+    DefaultContactDiaryPersonEncounter(
+        id = this.contactDiaryPersonEncounterEntity.id,
+        date = this.contactDiaryPersonEncounterEntity.date,
+        contactDiaryPerson = contactDiaryPersonEntity
+    )
+
+fun List<ContactDiaryPersonEncounterWrapper>.toContactDiaryPersonEncounterSortedList():
+    List<ContactDiaryPersonEncounter> =
+    this.map { it.toContactDiaryPersonEncounter() }
+        .sortByNameAndIdASC()
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryPersonEntity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryPersonEntity.kt
new file mode 100644
index 0000000000000000000000000000000000000000..be31909b96e9b1e8141fb9048cd4316f649a510d
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/entity/ContactDiaryPersonEntity.kt
@@ -0,0 +1,15 @@
+package de.rki.coronawarnapp.contactdiary.storage.entity
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPerson
+
+@Entity(tableName = "persons")
+data class ContactDiaryPersonEntity(
+    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "personId") override val personId: Long = 0L,
+    @ColumnInfo(name = "fullName") override var fullName: String
+) : ContactDiaryPerson
+
+fun ContactDiaryPerson.toContactDiaryPersonEntity(): ContactDiaryPersonEntity =
+    ContactDiaryPersonEntity(this.personId, this.fullName)
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/ContactDiaryRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/ContactDiaryRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..04d042a3cd64b99ccab73af2ef2b0f2fdfaa44d6
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/ContactDiaryRepository.kt
@@ -0,0 +1,41 @@
+package de.rki.coronawarnapp.contactdiary.storage.repo
+
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocation
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocationVisit
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPerson
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPersonEncounter
+import kotlinx.coroutines.flow.Flow
+import org.joda.time.LocalDate
+
+interface ContactDiaryRepository {
+
+    // Location
+    val locations: Flow<List<ContactDiaryLocation>>
+    suspend fun addLocation(contactDiaryLocation: ContactDiaryLocation)
+    suspend fun updateLocation(contactDiaryLocation: ContactDiaryLocation)
+    suspend fun deleteLocation(contactDiaryLocation: ContactDiaryLocation)
+    suspend fun deleteLocations(contactDiaryLocations: List<ContactDiaryLocation>)
+    suspend fun deleteAllLocations()
+
+    // Location visit
+    val locationVisits: Flow<List<ContactDiaryLocationVisit>>
+    fun locationVisitsForDate(date: LocalDate): Flow<List<ContactDiaryLocationVisit>>
+    suspend fun addLocationVisit(contactDiaryLocationVisit: ContactDiaryLocationVisit)
+    suspend fun deleteLocationVisit(contactDiaryLocationVisit: ContactDiaryLocationVisit)
+    suspend fun deleteAllLocationVisits()
+
+    // Person
+    val people: Flow<List<ContactDiaryPerson>>
+    suspend fun addPerson(contactDiaryPerson: ContactDiaryPerson)
+    suspend fun updatePerson(contactDiaryPerson: ContactDiaryPerson)
+    suspend fun deletePerson(contactDiaryPerson: ContactDiaryPerson)
+    suspend fun deletePeople(contactDiaryPeople: List<ContactDiaryPerson>)
+    suspend fun deleteAllPeople()
+
+    // Person encounter
+    val personEncounters: Flow<List<ContactDiaryPersonEncounter>>
+    fun personEncountersForDate(date: LocalDate): Flow<List<ContactDiaryPersonEncounter>>
+    suspend fun addPersonEncounter(contactDiaryPersonEncounter: ContactDiaryPersonEncounter)
+    suspend fun deletePersonEncounter(contactDiaryPersonEncounter: ContactDiaryPersonEncounter)
+    suspend fun deleteAllPersonEncounters()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/DefaultContactDiaryRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/DefaultContactDiaryRepository.kt
new file mode 100644
index 0000000000000000000000000000000000000000..91a482917bc8649c569c0e8e6d827b4eab4487e4
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/storage/repo/DefaultContactDiaryRepository.kt
@@ -0,0 +1,186 @@
+package de.rki.coronawarnapp.contactdiary.storage.repo
+
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocation
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocationVisit
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPerson
+import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPersonEncounter
+import de.rki.coronawarnapp.contactdiary.model.sortByNameAndIdASC
+import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryLocationDao
+import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryLocationVisitDao
+import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryPersonDao
+import de.rki.coronawarnapp.contactdiary.storage.dao.ContactDiaryPersonEncounterDao
+import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryLocationEntity
+import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryLocationVisitEntity
+import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryLocationVisitSortedList
+import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryPersonEncounterEntity
+import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryPersonEncounterSortedList
+import de.rki.coronawarnapp.contactdiary.storage.entity.toContactDiaryPersonEntity
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+import org.joda.time.LocalDate
+import timber.log.Timber
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class DefaultContactDiaryRepository @Inject constructor(
+    private val contactDiaryLocationDao: ContactDiaryLocationDao,
+    private val contactDiaryLocationVisitDao: ContactDiaryLocationVisitDao,
+    private val contactDiaryPersonDao: ContactDiaryPersonDao,
+    private val contactDiaryPersonEncounterDao: ContactDiaryPersonEncounterDao
+) : ContactDiaryRepository {
+
+    // Location
+    override val locations: Flow<List<ContactDiaryLocation>> = contactDiaryLocationDao
+        .allEntries()
+        .map { it.sortByNameAndIdASC() }
+
+    override suspend fun addLocation(contactDiaryLocation: ContactDiaryLocation) {
+        Timber.d("Adding location $contactDiaryLocation")
+        contactDiaryLocationDao.insert(contactDiaryLocation.toContactDiaryLocationEntity())
+    }
+
+    override suspend fun updateLocation(contactDiaryLocation: ContactDiaryLocation) {
+        Timber.d("Updating location $contactDiaryLocation")
+        val contactDiaryContactDiaryLocationEntity = contactDiaryLocation.toContactDiaryLocationEntity()
+        executeWhenIdNotDefault(contactDiaryContactDiaryLocationEntity.locationId) {
+            contactDiaryLocationDao.insert(contactDiaryContactDiaryLocationEntity)
+        }
+    }
+
+    override suspend fun deleteLocation(contactDiaryLocation: ContactDiaryLocation) {
+        Timber.d("Deleting location $contactDiaryLocation")
+        val contactDiaryContactDiaryLocationEntity = contactDiaryLocation.toContactDiaryLocationEntity()
+        executeWhenIdNotDefault(contactDiaryContactDiaryLocationEntity.locationId) {
+            contactDiaryLocationDao.delete(contactDiaryContactDiaryLocationEntity)
+        }
+    }
+
+    override suspend fun deleteLocations(contactDiaryLocations: List<ContactDiaryLocation>) {
+        Timber.d("Deleting location $contactDiaryLocations")
+        val contactDiaryLocationEntities = contactDiaryLocations
+            .map {
+                val contactDiaryLocationEntity = it.toContactDiaryLocationEntity()
+                executeWhenIdNotDefault(contactDiaryLocationEntity.locationId)
+                return@map contactDiaryLocationEntity
+            }
+        contactDiaryLocationDao.delete(contactDiaryLocationEntities)
+    }
+
+    override suspend fun deleteAllLocations() {
+        Timber.d("Clearing contact diary location table")
+        contactDiaryLocationDao.deleteAll()
+    }
+
+    // Location visit
+    override val locationVisits: Flow<List<ContactDiaryLocationVisit>> =
+        contactDiaryLocationVisitDao
+            .allEntries()
+            .map { it.toContactDiaryLocationVisitSortedList() }
+
+    override fun locationVisitsForDate(date: LocalDate): Flow<List<ContactDiaryLocationVisit>> =
+        contactDiaryLocationVisitDao
+            .entitiesForDate(date)
+            .map { it.toContactDiaryLocationVisitSortedList() }
+
+    override suspend fun addLocationVisit(contactDiaryLocationVisit: ContactDiaryLocationVisit) {
+        Timber.d("Adding location visit $contactDiaryLocationVisit")
+        executeWhenIdNotDefault(contactDiaryLocationVisit.id) {
+            val contactDiaryLocationVisitEntity = contactDiaryLocationVisit.toContactDiaryLocationVisitEntity()
+            contactDiaryLocationVisitDao.insert(contactDiaryLocationVisitEntity)
+        }
+    }
+
+    override suspend fun deleteLocationVisit(contactDiaryLocationVisit: ContactDiaryLocationVisit) {
+        Timber.d("Deleting location visit $contactDiaryLocationVisit")
+        executeWhenIdNotDefault(contactDiaryLocationVisit.id) {
+            val contactDiaryLocationVisitEntity = contactDiaryLocationVisit.toContactDiaryLocationVisitEntity()
+            contactDiaryLocationVisitDao.delete(contactDiaryLocationVisitEntity)
+        }
+    }
+
+    override suspend fun deleteAllLocationVisits() {
+        Timber.d("Clearing contact diary location visit table")
+        contactDiaryLocationVisitDao.deleteAll()
+    }
+
+    // Person
+    override val people: Flow<List<ContactDiaryPerson>> = contactDiaryPersonDao
+        .allEntries()
+        .map { it.sortByNameAndIdASC() }
+
+    override suspend fun addPerson(contactDiaryPerson: ContactDiaryPerson) {
+        Timber.d("Adding person $contactDiaryPerson")
+        contactDiaryPersonDao.insert(contactDiaryPerson.toContactDiaryPersonEntity())
+    }
+
+    override suspend fun updatePerson(contactDiaryPerson: ContactDiaryPerson) {
+        Timber.d("Updating person $contactDiaryPerson")
+        val contactDiaryPersonEntity = contactDiaryPerson.toContactDiaryPersonEntity()
+        executeWhenIdNotDefault(contactDiaryPersonEntity.personId) {
+            contactDiaryPersonDao.update(contactDiaryPersonEntity)
+        }
+    }
+
+    override suspend fun deletePerson(contactDiaryPerson: ContactDiaryPerson) {
+        Timber.d("Deleting person $contactDiaryPerson")
+        val contactDiaryPersonEntity = contactDiaryPerson.toContactDiaryPersonEntity()
+        executeWhenIdNotDefault(contactDiaryPersonEntity.personId) {
+            contactDiaryPersonDao.delete(contactDiaryPersonEntity)
+        }
+    }
+
+    override suspend fun deletePeople(contactDiaryPeople: List<ContactDiaryPerson>) {
+        Timber.d("Deleting people $contactDiaryPeople")
+        val contactDiaryPersonEntities = contactDiaryPeople
+            .map {
+                val contactDiaryPersonEntity = it.toContactDiaryPersonEntity()
+                executeWhenIdNotDefault(contactDiaryPersonEntity.personId)
+                return@map contactDiaryPersonEntity
+            }
+        contactDiaryPersonDao.delete(contactDiaryPersonEntities)
+    }
+
+    override suspend fun deleteAllPeople() {
+        Timber.d("Clearing contact diary person table")
+        contactDiaryPersonDao.deleteAll()
+    }
+
+    // Person encounter
+    override val personEncounters: Flow<List<ContactDiaryPersonEncounter>> =
+        contactDiaryPersonEncounterDao
+            .allEntries()
+            .map { it.toContactDiaryPersonEncounterSortedList() }
+
+    override fun personEncountersForDate(date: LocalDate): Flow<List<ContactDiaryPersonEncounter>> =
+        contactDiaryPersonEncounterDao
+            .entitiesForDate(date)
+            .map { it.toContactDiaryPersonEncounterSortedList() }
+
+    override suspend fun addPersonEncounter(contactDiaryPersonEncounter: ContactDiaryPersonEncounter) {
+        Timber.d("Adding person encounter $contactDiaryPersonEncounter")
+        val contactDiaryPersonEncounterEntity = contactDiaryPersonEncounter.toContactDiaryPersonEncounterEntity()
+        contactDiaryPersonEncounterDao.insert(contactDiaryPersonEncounterEntity)
+    }
+
+    override suspend fun deletePersonEncounter(contactDiaryPersonEncounter: ContactDiaryPersonEncounter) {
+        Timber.d("Deleting person encounter $contactDiaryPersonEncounter")
+        executeWhenIdNotDefault(contactDiaryPersonEncounter.id) {
+            val contactDiaryPersonEncounterEntity = contactDiaryPersonEncounter.toContactDiaryPersonEncounterEntity()
+            contactDiaryPersonEncounterDao.delete(contactDiaryPersonEncounterEntity)
+        }
+    }
+
+    override suspend fun deleteAllPersonEncounters() {
+        Timber.d("Clearing contact diary person encounter table")
+        contactDiaryPersonEncounterDao.deleteAll()
+    }
+
+    private suspend fun executeWhenIdNotDefault(id: Long, action: (suspend () -> Unit) = { }) {
+        if (id != 0L) {
+            action()
+        } else {
+            throw IllegalArgumentException("Entity has default id")
+        }
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt
index 7673f4e16733553d6e9817bc3f604e55aa7206c5..33e6de9bfa70e0ef27a5b06a82b9d66789927796 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/DataReset.kt
@@ -22,6 +22,7 @@ package de.rki.coronawarnapp.util
 import android.annotation.SuppressLint
 import android.content.Context
 import de.rki.coronawarnapp.appconfig.AppConfigProvider
+import de.rki.coronawarnapp.contactdiary.storage.ContactDiaryDatabase
 import de.rki.coronawarnapp.diagnosiskeys.download.KeyPackageSyncSettings
 import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker
@@ -50,7 +51,8 @@ class DataReset @Inject constructor(
     private val submissionRepository: SubmissionRepository,
     private val exposureDetectionTracker: ExposureDetectionTracker,
     private val keyPackageSyncSettings: KeyPackageSyncSettings,
-    private val riskLevelStorage: RiskLevelStorage
+    private val riskLevelStorage: RiskLevelStorage,
+    private val contactDiaryDatabase: ContactDiaryDatabase
 ) {
 
     private val mutex = Mutex()
@@ -78,6 +80,9 @@ class DataReset @Inject constructor(
         keyPackageSyncSettings.clear()
         riskLevelStorage.clear()
 
+        // Clear contact diary database
+        contactDiaryDatabase.clearAllTables()
+
         Timber.w("CWA LOCAL DATA DELETION COMPLETED.")
     }
 }
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 6a869aa15a472ceb4d54b28ebbb2413f016556d4..9e23785a4d36a4bfeaff26b44520258ec36cede2 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
@@ -9,6 +9,7 @@ import de.rki.coronawarnapp.appconfig.AppConfigModule
 import de.rki.coronawarnapp.appconfig.AppConfigProvider
 import de.rki.coronawarnapp.bugreporting.BugReporter
 import de.rki.coronawarnapp.bugreporting.BugReportingModule
+import de.rki.coronawarnapp.contactdiary.ContactDiaryModule
 import de.rki.coronawarnapp.diagnosiskeys.DiagnosisKeysModule
 import de.rki.coronawarnapp.diagnosiskeys.DownloadDiagnosisKeysTaskModule
 import de.rki.coronawarnapp.diagnosiskeys.storage.KeyCacheRepository
@@ -68,7 +69,8 @@ import javax.inject.Singleton
         DeviceForTestersModule::class,
         BugReportingModule::class,
         SerializationModule::class,
-        WorkerBinder::class
+        WorkerBinder::class,
+        ContactDiaryModule::class
     ]
 )
 interface ApplicationComponent : AndroidInjector<CoronaWarnApplication> {