diff --git a/Dockerfile b/Dockerfile
index 00addd9fd022f6645a79ad3958a0df1c069e09ab..c20ff5a887f6295e801f91417942500d9430245b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,7 @@
 FROM tomcat:9-jdk11
 
 RUN rm -rf /usr/local/tomcat/webapps/*
-COPY build/2.6.1/BudgetMaster-v2.6.1.war $CATALINA_HOME/webapps/ROOT.war
+COPY build/2.7.0/BudgetMaster-v2.7.0.war $CATALINA_HOME/webapps/ROOT.war
 COPY src/main/resources/config/templates/settings-docker.properties /root/.Deadlocker/BudgetMaster/settings.properties
 
 EXPOSE 8080
\ No newline at end of file
diff --git a/README.md b/README.md
index b9f4333b62faa77ae2829a1a8d927a19f9a40a71..fede3de435e025bdaa9212ab609501a07c8cde3a 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 Manage your monthly budget easily with BudgetMaster
 
 - __start:__ 17.12.16
-- __current release:__ v2.6.1 (32) from 30.05.21
+- __current release:__ v2.7.0 (33) from 03.08.21
 
 ## Key Features
 - Keep your data private - Host your own BudgetMaster server or use it in standalone mode. All data remains on your machines.
diff --git a/build/screenshots/dark/accounts.png b/build/screenshots/dark/accounts.png
index 5585ce2510e92875596baa1b9e4a25a459370ab0..4169178a0d368f8a404e0b89a67cb72fd55d3982 100644
Binary files a/build/screenshots/dark/accounts.png and b/build/screenshots/dark/accounts.png differ
diff --git a/build/screenshots/dark/categories.png b/build/screenshots/dark/categories.png
index f36628df0e69591f7270d6c52162dd4f7b4b9402..29254189d4de03b7e9db7c0087e5348d67e31d36 100644
Binary files a/build/screenshots/dark/categories.png and b/build/screenshots/dark/categories.png differ
diff --git a/build/screenshots/dark/chart_1.png b/build/screenshots/dark/chart_1.png
index ff89f909763460690144fa5aad7b0d6683e8876b..8f8f7cc32e9692394ec9f3eeae23c7ffbb3c22f7 100644
Binary files a/build/screenshots/dark/chart_1.png and b/build/screenshots/dark/chart_1.png differ
diff --git a/build/screenshots/dark/chart_2.png b/build/screenshots/dark/chart_2.png
index 599739025cd2e94b5e9f69c38d88b1604688b1d9..2e18002efd406819ca925d15c092c21878f152d2 100644
Binary files a/build/screenshots/dark/chart_2.png and b/build/screenshots/dark/chart_2.png differ
diff --git a/build/screenshots/dark/chart_3.png b/build/screenshots/dark/chart_3.png
index 107e1c0b99cb9d526325e6d419cad8715d6810bd..3196cc44e99a5cf5db1e492fe1b9a207f699cd5d 100644
Binary files a/build/screenshots/dark/chart_3.png and b/build/screenshots/dark/chart_3.png differ
diff --git a/build/screenshots/dark/chart_4.png b/build/screenshots/dark/chart_4.png
deleted file mode 100644
index 48dc2c95d03105c297bbff7047dee780df6770ef..0000000000000000000000000000000000000000
Binary files a/build/screenshots/dark/chart_4.png and /dev/null differ
diff --git a/build/screenshots/dark/filter_1.png b/build/screenshots/dark/filter_1.png
index 19f0052eddf315be02021591f292b9af62a07555..b8f935e7e89088d8ef32597a8fa77bac5bb96759 100644
Binary files a/build/screenshots/dark/filter_1.png and b/build/screenshots/dark/filter_1.png differ
diff --git a/build/screenshots/dark/filter_2.png b/build/screenshots/dark/filter_2.png
index fd9bf5f3208aea752a1621dc0ec0643de7428701..273a533ae719787cafd17c6a2d545ed68639cfd4 100644
Binary files a/build/screenshots/dark/filter_2.png and b/build/screenshots/dark/filter_2.png differ
diff --git a/build/screenshots/dark/home.png b/build/screenshots/dark/home.png
index 992288ab89be6694186ac7db973ad7bb39d2158b..e2800bdc0afff2d9f3c1a7401f2643dd2c1de2d1 100644
Binary files a/build/screenshots/dark/home.png and b/build/screenshots/dark/home.png differ
diff --git a/build/screenshots/dark/hotkeys.png b/build/screenshots/dark/hotkeys.png
index 5f5baf2b4967c53275ed327fcda12878afae45c6..18aab94c61fed51cb346309319ecf4dd59ea7fcd 100644
Binary files a/build/screenshots/dark/hotkeys.png and b/build/screenshots/dark/hotkeys.png differ
diff --git a/build/screenshots/dark/new_category.png b/build/screenshots/dark/new_category.png
index c835cd2527fc5f0a874fb7aa5017dd69c5694b87..cc1a13f94a613f95dc452c3f4e989a1655649fbb 100644
Binary files a/build/screenshots/dark/new_category.png and b/build/screenshots/dark/new_category.png differ
diff --git a/build/screenshots/dark/new_normal_transaction.png b/build/screenshots/dark/new_normal_transaction.png
index b2619eda676c346b1d3c1ccd9291d40de19b78d3..3f6bf6dbee3353226e5dbfaa579e7fae3410cc51 100644
Binary files a/build/screenshots/dark/new_normal_transaction.png and b/build/screenshots/dark/new_normal_transaction.png differ
diff --git a/build/screenshots/dark/new_transaction_1.png b/build/screenshots/dark/new_transaction_1.png
index 6111c9e1ca2e222692f0676df3cd6a1569f95a3c..5b0481c155493c909ccfed72df01e50a48bae7a6 100644
Binary files a/build/screenshots/dark/new_transaction_1.png and b/build/screenshots/dark/new_transaction_1.png differ
diff --git a/build/screenshots/dark/new_transaction_2.png b/build/screenshots/dark/new_transaction_2.png
index 1832e708a02fcf82fac4efdb23ed65d496bbe316..92ad904ca4ad49aa54608133dde0f10e73d9124e 100644
Binary files a/build/screenshots/dark/new_transaction_2.png and b/build/screenshots/dark/new_transaction_2.png differ
diff --git a/build/screenshots/dark/new_transfer_transaction.png b/build/screenshots/dark/new_transfer_transaction.png
index e326d5fb85aa8a206d2cccc7ed56f8a811e8ef99..29592b8b1f2f9f010a3ddac471e3ecf90cb400d0 100644
Binary files a/build/screenshots/dark/new_transfer_transaction.png and b/build/screenshots/dark/new_transfer_transaction.png differ
diff --git a/build/screenshots/dark/reports.png b/build/screenshots/dark/reports.png
index 7d2629f962fa10eb7eed2da412941d7b05b200aa..8331f2f94bc441f651d695295f9b6365b2fbf16f 100644
Binary files a/build/screenshots/dark/reports.png and b/build/screenshots/dark/reports.png differ
diff --git a/build/screenshots/dark/search.png b/build/screenshots/dark/search.png
index 509762cf6d36f19c2d65d4cf7d53127751461415..b1aafc3d73a4e87d88851a35169f4583da620887 100644
Binary files a/build/screenshots/dark/search.png and b/build/screenshots/dark/search.png differ
diff --git a/build/screenshots/dark/settings_1.png b/build/screenshots/dark/settings_1.png
index 4256b0a954cafb9f3c68a47644bf8134b3c72bce..d0335b81eeef15064fa5b7f89ad38e0b728284bb 100644
Binary files a/build/screenshots/dark/settings_1.png and b/build/screenshots/dark/settings_1.png differ
diff --git a/build/screenshots/dark/settings_2.png b/build/screenshots/dark/settings_2.png
index 6aeb2ec7bf39d6538e8f09c8e5f1fcc59e695f38..4d3842cd198f85a24f71097aeb29f5975954dfb4 100644
Binary files a/build/screenshots/dark/settings_2.png and b/build/screenshots/dark/settings_2.png differ
diff --git a/build/screenshots/dark/settings_3.png b/build/screenshots/dark/settings_3.png
index 2bea84c75c5f3da2366ea3f171dc815bee09d29c..26f8f56d0a7d2001f7dd00a2bf7acb6634976c9e 100644
Binary files a/build/screenshots/dark/settings_3.png and b/build/screenshots/dark/settings_3.png differ
diff --git a/build/screenshots/dark/statistics.png b/build/screenshots/dark/statistics.png
index b7db69547f15795d6f539fe06dbe7d3b598785d7..b362162dc98c973fb0f81d923347503c25990e15 100644
Binary files a/build/screenshots/dark/statistics.png and b/build/screenshots/dark/statistics.png differ
diff --git a/build/screenshots/dark/templates_1.png b/build/screenshots/dark/templates_1.png
index 37162f02639bef060ffce2d7ad13c130e19543bc..ff8c025088d339b533323cb8f3326cfabff9ce88 100644
Binary files a/build/screenshots/dark/templates_1.png and b/build/screenshots/dark/templates_1.png differ
diff --git a/build/screenshots/dark/transactions.png b/build/screenshots/dark/transactions.png
index e361b32fa3260ba3a6e1acc15f2e3afdc6f30dc6..b21cd599728db0569409d88ee314b41ac41f8909 100644
Binary files a/build/screenshots/dark/transactions.png and b/build/screenshots/dark/transactions.png differ
diff --git a/build/screenshots/light/accounts.png b/build/screenshots/light/accounts.png
index d605ede1986d94001f87259529e57056bfb6e45a..c35e7703b966ab0668e0471f3dae30d1788f378a 100644
Binary files a/build/screenshots/light/accounts.png and b/build/screenshots/light/accounts.png differ
diff --git a/build/screenshots/light/categories.png b/build/screenshots/light/categories.png
index 63e15e004e5b36afc5fbe3498695344744046cc8..2ddd9184e5c3640970dcd36ca1ea0f9b414c4e1f 100644
Binary files a/build/screenshots/light/categories.png and b/build/screenshots/light/categories.png differ
diff --git a/build/screenshots/light/chart_1.png b/build/screenshots/light/chart_1.png
index c740fc305a8e3d4dad8b17fe3d62dd3e99acefde..756374199f4a0542aee012dfeae9b5ccdf1ba43b 100644
Binary files a/build/screenshots/light/chart_1.png and b/build/screenshots/light/chart_1.png differ
diff --git a/build/screenshots/light/chart_2.png b/build/screenshots/light/chart_2.png
index d1e1f63aea3ed4c640b55e50c118ba4cf3e3b100..755c53144f6a484e53f187f1b69ad8a39055a1f5 100644
Binary files a/build/screenshots/light/chart_2.png and b/build/screenshots/light/chart_2.png differ
diff --git a/build/screenshots/light/chart_3.png b/build/screenshots/light/chart_3.png
index 83949ee0c19e92001fd5d0dc312412a546899380..5ebbb6473b64d14c0d7572f3920433c6054ff44e 100644
Binary files a/build/screenshots/light/chart_3.png and b/build/screenshots/light/chart_3.png differ
diff --git a/build/screenshots/light/chart_4.png b/build/screenshots/light/chart_4.png
deleted file mode 100644
index c03337fb3b1860259aa85efcf38406e6d34060a4..0000000000000000000000000000000000000000
Binary files a/build/screenshots/light/chart_4.png and /dev/null differ
diff --git a/build/screenshots/light/filter_1.png b/build/screenshots/light/filter_1.png
index 7bd90a1586969e4d1c1622c885ceb0a4f134a7f5..f7a51066ecfa096b66d833e923b193f0dafbc093 100644
Binary files a/build/screenshots/light/filter_1.png and b/build/screenshots/light/filter_1.png differ
diff --git a/build/screenshots/light/filter_2.png b/build/screenshots/light/filter_2.png
index a2f20376c8beb4678b9694aa79e01b5e9e3fb778..30e6e5973e37755f67fe266e8291753b84cf6bac 100644
Binary files a/build/screenshots/light/filter_2.png and b/build/screenshots/light/filter_2.png differ
diff --git a/build/screenshots/light/home.png b/build/screenshots/light/home.png
index 3f29a5f29ba3dce7bd55cdeb66e8f66d96a182e9..524cd279418570a68f8d3e4342e5971d46093f69 100644
Binary files a/build/screenshots/light/home.png and b/build/screenshots/light/home.png differ
diff --git a/build/screenshots/light/hotkeys.png b/build/screenshots/light/hotkeys.png
index 2558f6128cea5329af45bc612d5b250b411e04f4..2fcc39d58eb3d41ce9952f0c5e0b53203c987d0b 100644
Binary files a/build/screenshots/light/hotkeys.png and b/build/screenshots/light/hotkeys.png differ
diff --git a/build/screenshots/light/new_category.png b/build/screenshots/light/new_category.png
index ff6534fc787a31ee4154f63c5b44804c79852fb1..d316d371f69c7679a12d4ad3ed01500d73161a29 100644
Binary files a/build/screenshots/light/new_category.png and b/build/screenshots/light/new_category.png differ
diff --git a/build/screenshots/light/new_normal_transaction.png b/build/screenshots/light/new_normal_transaction.png
index be5aded924e22edae4250507d2a58e25d6f73860..f14ad330e201cebc693a7b87f3983836f35ceaf4 100644
Binary files a/build/screenshots/light/new_normal_transaction.png and b/build/screenshots/light/new_normal_transaction.png differ
diff --git a/build/screenshots/light/new_transaction_1.png b/build/screenshots/light/new_transaction_1.png
index 71de0a017bed4c0bf06707132e539b889ac3deb1..4b4e4d4acafc4843f1ab67c7bcb30be661e9ed3b 100644
Binary files a/build/screenshots/light/new_transaction_1.png and b/build/screenshots/light/new_transaction_1.png differ
diff --git a/build/screenshots/light/new_transaction_2.png b/build/screenshots/light/new_transaction_2.png
index 45f12a6474f0eed63807676ab6926d56c1eeed62..f8f8f058a82a7771f5816de87be1e5450d87c819 100644
Binary files a/build/screenshots/light/new_transaction_2.png and b/build/screenshots/light/new_transaction_2.png differ
diff --git a/build/screenshots/light/new_transfer_transaction.png b/build/screenshots/light/new_transfer_transaction.png
index d29a718679426a1c68e22047f8c8abaa829945a9..fbe0007373b80220357f5f32992b9302ad09e158 100644
Binary files a/build/screenshots/light/new_transfer_transaction.png and b/build/screenshots/light/new_transfer_transaction.png differ
diff --git a/build/screenshots/light/reports.png b/build/screenshots/light/reports.png
index 552b2475dcf69db99510894d016db1a20d248ab8..ecd780d1e89353219e83bdcb9a9e934bc47bc0cf 100644
Binary files a/build/screenshots/light/reports.png and b/build/screenshots/light/reports.png differ
diff --git a/build/screenshots/light/search.png b/build/screenshots/light/search.png
index e0142d34315ad311a5c455274171b14901143404..784a49cb8c709b0514bc24703817dd7f1bb30b3a 100644
Binary files a/build/screenshots/light/search.png and b/build/screenshots/light/search.png differ
diff --git a/build/screenshots/light/settings_1.png b/build/screenshots/light/settings_1.png
index 53caf5efd478c539a48ef315dacb9a0c385441ee..6f60236d12a1056779a2b3d49c9e4a7e8c4b1f95 100644
Binary files a/build/screenshots/light/settings_1.png and b/build/screenshots/light/settings_1.png differ
diff --git a/build/screenshots/light/settings_2.png b/build/screenshots/light/settings_2.png
index 4038ee1487d8692d9cc3f48bbbbd55c26ea8e803..658f580968c1c58c830d8c18d0a26472ea5fbc2d 100644
Binary files a/build/screenshots/light/settings_2.png and b/build/screenshots/light/settings_2.png differ
diff --git a/build/screenshots/light/settings_3.png b/build/screenshots/light/settings_3.png
index 80f77c837a9f5a2cccb5890c34e696fb7ffd5504..7ecafefb83d6e9a252d05ddcd73316d25a1a6e11 100644
Binary files a/build/screenshots/light/settings_3.png and b/build/screenshots/light/settings_3.png differ
diff --git a/build/screenshots/light/statistics.png b/build/screenshots/light/statistics.png
index 48f7bf09899367d4532ac7cfc1da27e0201fea92..54e5aa9727642226d6da3db20baaa5ae81589371 100644
Binary files a/build/screenshots/light/statistics.png and b/build/screenshots/light/statistics.png differ
diff --git a/build/screenshots/light/templates_1.png b/build/screenshots/light/templates_1.png
index e4c459ce0c0de6d77cafc3bbd871ebd5ba2c3e52..013ca88b4335088d733db272b45f9e32be593a4b 100644
Binary files a/build/screenshots/light/templates_1.png and b/build/screenshots/light/templates_1.png differ
diff --git a/build/screenshots/light/transactions.png b/build/screenshots/light/transactions.png
index 174c018c44cf589cb5452f4707429fdde0acb83b..1e8ad91dc37eb65a09f9f9bef551a3724ca7a916 100644
Binary files a/build/screenshots/light/transactions.png and b/build/screenshots/light/transactions.png differ
diff --git a/pom.xml b/pom.xml
index 0bc83e802fc72f29091134021ddd6043dfd278bb..146a060414496b0a225958db20e18de078b1c31a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
 
     <groupId>de.deadlocker8</groupId>
     <artifactId>BudgetMaster</artifactId>
-    <version>2.6.1</version>
+    <version>2.7.0</version>
     <name>BudgetMaster</name>
 
     <repositories>
@@ -35,7 +35,7 @@
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
-        <version>2.4.5</version>
+        <version>2.5.3</version>
         <relativePath/>
     </parent>
 
@@ -58,17 +58,17 @@
 
         <jlibs.version>3.2.0</jlibs.version>
         <versionizer.version>3.0.1</versionizer.version>
-        <webjars-locator.version>0.40</webjars-locator.version>
+        <webjars-locator.version>0.41</webjars-locator.version>
         <jquery.version>3.6.0</jquery.version>
         <materializecss.version>1.0.0</materializecss.version>
-        <fontawesome.version>5.15.2</fontawesome.version>
+        <fontawesome.version>5.15.3</fontawesome.version>
         <sortablejs.version>1.13.0</sortablejs.version>
         <mousetrap.version>1.6.5</mousetrap.version>
-        <codemirror.version>5.50.0</codemirror.version>
+        <codemirror.version>5.62.0</codemirror.version>
         <selenium.version>3.141.59</selenium.version>
-        <assertj-core.version>3.19.0</assertj-core.version>
-        <jgit.version>5.11.0.202103091610-r</jgit.version>
-        <natorder.version>1.0.1</natorder.version>
+        <assertj-core.version>3.20.2</assertj-core.version>
+        <jgit.version>5.12.0.202106070339-r</jgit.version>
+        <natorder.version>1.0.2</natorder.version>
         <h2database.version>1.4.199</h2database.version>
         <itextpdf.version>5.5.13.2</itextpdf.version>
         <usertype-core.version>6.0.1.GA</usertype-core.version>
@@ -76,7 +76,7 @@
 
         <app.versionDate>${maven.build.timestamp}</app.versionDate>
         <maven.build.timestamp.format>dd.MM.yy</maven.build.timestamp.format>
-        <app.versionCode>32</app.versionCode>
+        <app.versionCode>33</app.versionCode>
         <app.author>Robert Goldmann</app.author>
 
         <project.outputDirectory>build/${project.version}</project.outputDirectory>
@@ -247,18 +247,6 @@
             <version>${assertj-core.version}</version>
             <scope>test</scope>
         </dependency>
-
-        <dependency>
-            <groupId>org.junit.vintage</groupId>
-            <artifactId>junit-vintage-engine</artifactId>
-            <scope>test</scope>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.hamcrest</groupId>
-                    <artifactId>hamcrest-core</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
     </dependencies>
 
     <build>
@@ -312,7 +300,7 @@
                             <headerType>gui</headerType>
                             <jar>${project.outputDirectory}/${project.artifactName}.jar</jar>
                             <outfile>${project.exe}</outfile>
-                            <downloadUrl>https://java.com/download</downloadUrl>
+                            <downloadUrl>https://adoptopenjdk.net/</downloadUrl>
                             <classPath>
                                 <mainClass>${project.groupId}${project.artifactId}.Main</mainClass>
                             </classPath>
@@ -321,7 +309,7 @@
                                 <bundledJreAsFallback>false</bundledJreAsFallback>
                                 <minVersion>11</minVersion>
                                 <jdkPreference>preferJre</jdkPreference>
-                                <runtimeBits>64/32</runtimeBits>
+                                <runtimeBits>64</runtimeBits>
                             </jre>
                             <icon>build/icon.ico</icon>
                         </configuration>
diff --git a/src/main/java/de/deadlocker8/budgetmaster/Main.java b/src/main/java/de/deadlocker8/budgetmaster/Main.java
index 577c74b2e5191a04140587e46914a22177479c72..6edcedf145b6fbd48aff439c207965c42a92e32a 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/Main.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/Main.java
@@ -50,7 +50,7 @@ public class Main extends SpringBootServletInitializer implements ApplicationRun
 			@Override
 			public String[] getBaseResources()
 			{
-				return new String[]{"languages/base", "languages/news"};
+				return new String[]{"languages/base", "languages/news", "languages/hints"};
 			}
 
 			@Override
diff --git a/src/main/java/de/deadlocker8/budgetmaster/accounts/Account.java b/src/main/java/de/deadlocker8/budgetmaster/accounts/Account.java
index 8f2adfa3ad25882da8fb2c1296526ed837ddb84e..fd3f7c0bbd144f3881ef04be1d98ccbc41af3037 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/accounts/Account.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/accounts/Account.java
@@ -1,6 +1,8 @@
 package de.deadlocker8.budgetmaster.accounts;
 
 import com.google.gson.annotations.Expose;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.Iconizable;
 import de.deadlocker8.budgetmaster.images.Image;
 import de.deadlocker8.budgetmaster.transactions.Transaction;
 import de.deadlocker8.budgetmaster.utils.ProvidesID;
@@ -12,7 +14,7 @@ import java.util.List;
 import java.util.Objects;
 
 @Entity
-public class Account implements ProvidesID
+public class Account implements ProvidesID, Iconizable
 {
 	@Id
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -31,27 +33,31 @@ public class Account implements ProvidesID
 	private Boolean isSelected = false;
 	private Boolean isDefault = false;
 
-	@Deprecated
+	@Deprecated(since = "v2.6.0", forRemoval = true)
 	private Boolean isReadOnly = false;
 
 	@Expose
 	private AccountState accountState;
 
 	@ManyToOne
-	@Expose
+	@Deprecated(since = "v2.7.0", forRemoval = true)
 	private Image icon;
 
+	@OneToOne(cascade = CascadeType.REMOVE)
+	@Expose
+	private Icon iconReference;
+
 	@Expose
 	private AccountType type;
 
-	public Account(String name, AccountType type, Image icon)
+	public Account(String name, AccountType type, Icon iconReference)
 	{
 		this.name = name;
 		this.type = type;
 		this.isSelected = false;
 		this.isDefault = false;
 		this.accountState = AccountState.FULL_ACCESS;
-		this.icon = icon;
+		this.iconReference = iconReference;
 	}
 
 	public Account(String name, AccountType type)
@@ -113,18 +119,12 @@ public class Account implements ProvidesID
 		isDefault = aDefault;
 	}
 
-	@Deprecated
+	@Deprecated(since = "v2.6.0", forRemoval = true)
 	public Boolean isReadOnly()
 	{
 		return isReadOnly;
 	}
 
-	@Deprecated
-	public void setReadOnly(Boolean readOnly)
-	{
-		isReadOnly = readOnly;
-	}
-
 	public AccountState getAccountState()
 	{
 		return accountState;
@@ -145,16 +145,28 @@ public class Account implements ProvidesID
 		this.type = type;
 	}
 
+	@Deprecated(since = "v2.7.0", forRemoval = true)
 	public Image getIcon()
 	{
 		return icon;
 	}
 
+	@Deprecated(since = "v2.7.0", forRemoval = true)
 	public void setIcon(Image icon)
 	{
 		this.icon = icon;
 	}
 
+	public Icon getIconReference()
+	{
+		return iconReference;
+	}
+
+	public void setIconReference(Icon iconReference)
+	{
+		this.iconReference = iconReference;
+	}
+
 	@Override
 	public String toString()
 	{
@@ -166,7 +178,7 @@ public class Account implements ProvidesID
 				", isDefault=" + isDefault +
 				", accountState=" + accountState +
 				", type=" + type +
-				", icon=" + icon +
+				", iconReference=" + iconReference +
 				'}';
 	}
 
@@ -181,12 +193,14 @@ public class Account implements ProvidesID
 				Objects.equals(isSelected, account.isSelected) &&
 				Objects.equals(isDefault, account.isDefault) &&
 				accountState == account.accountState &&
-				Objects.equals(icon, account.icon) && type == account.type;
+				Objects.equals(icon, account.icon) &&
+				Objects.equals(iconReference, account.iconReference) &&
+				type == account.type;
 	}
 
 	@Override
 	public int hashCode()
 	{
-		return Objects.hash(ID, name, isSelected, isDefault, accountState, icon, type);
+		return Objects.hash(ID, name, isSelected, isDefault, accountState, icon, iconReference, type);
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountController.java b/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountController.java
index 3f3423a64012588326ba69d1f83e7ca2fdc9403e..d4942b683a7ac3f7778ec564b6e8214e014e4f6c 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountController.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountController.java
@@ -1,7 +1,9 @@
 package de.deadlocker8.budgetmaster.accounts;
 
 import de.deadlocker8.budgetmaster.controller.BaseController;
+import de.deadlocker8.budgetmaster.icon.IconService;
 import de.deadlocker8.budgetmaster.images.ImageService;
+import de.deadlocker8.budgetmaster.utils.FontAwesomeIcons;
 import de.deadlocker8.budgetmaster.utils.Mappings;
 import de.deadlocker8.budgetmaster.utils.ResourceNotFoundException;
 import de.deadlocker8.budgetmaster.utils.WebRequestUtils;
@@ -27,12 +29,14 @@ public class AccountController extends BaseController
 {
 	private final AccountService accountService;
 	private final ImageService imageService;
+	private final IconService iconService;
 
 	@Autowired
-	public AccountController(AccountService accountService, ImageService imageService)
+	public AccountController(AccountService accountService, ImageService imageService, IconService iconService)
 	{
 		this.accountService = accountService;
 		this.imageService = imageService;
+		this.iconService = iconService;
 	}
 
 	@GetMapping(value = "/{ID}/select")
@@ -72,15 +76,15 @@ public class AccountController extends BaseController
 	public String requestDeleteAccount(Model model, @PathVariable("ID") Integer ID)
 	{
 		model.addAttribute("accounts", accountService.getAllEntitiesAsc());
-		model.addAttribute("currentAccount", accountService.getRepository().getOne(ID));
-		return "accounts/accounts";
+		model.addAttribute("accountToDelete", accountService.getRepository().getById(ID));
+		return "accounts/deleteAccountModal";
 	}
 
 	@GetMapping("/{ID}/delete")
 	public String deleteAccountAndReferringTransactions(WebRequest request, Model model, @PathVariable("ID") Integer ID)
 	{
 		// at least one account is required (to delete a sole account another one has to be created first)
-		final Account accountToDelete = accountService.getRepository().getOne(ID);
+		final Account accountToDelete = accountService.getRepository().getById(ID);
 		if(accountService.getRepository().findAllByType(AccountType.CUSTOM).size() > 1)
 		{
 			accountService.deleteAccount(ID);
@@ -99,8 +103,8 @@ public class AccountController extends BaseController
 	{
 		Account emptyAccount = new Account();
 		model.addAttribute("account", emptyAccount);
-		model.addAttribute("availableImages", imageService.getRepository().findAll());
 		model.addAttribute("availableAccountStates", AccountState.values());
+		model.addAttribute("fontawesomeIcons", FontAwesomeIcons.ICONS);
 		return "accounts/newAccount";
 	}
 
@@ -114,14 +118,16 @@ public class AccountController extends BaseController
 		}
 
 		model.addAttribute("account", accountOptional.get());
-		model.addAttribute("availableImages", imageService.getRepository().findAll());
 		model.addAttribute("availableAccountStates", AccountState.values());
+		model.addAttribute("fontawesomeIcons", FontAwesomeIcons.ICONS);
 		return "accounts/newAccount";
 	}
 
 	@PostMapping(value = "/newAccount")
 	public String post(HttpServletRequest request, WebRequest webRequest, Model model,
 					   @ModelAttribute("NewAccount") Account account,
+					   @RequestParam(value = "iconImageID", required = false) Integer iconImageID,
+					   @RequestParam(value = "builtinIconIdentifier", required = false) String builtinIconIdentifier,
 					   BindingResult bindingResult)
 	{
 		AccountValidator accountValidator = new AccountValidator();
@@ -151,6 +157,8 @@ public class AccountController extends BaseController
 			return "accounts/newAccount";
 		}
 
+		account.updateIcon(iconService, iconImageID, builtinIconIdentifier, accountService);
+
 		if(isNewAccount)
 		{
 			account.setType(AccountType.CUSTOM);
@@ -161,7 +169,7 @@ public class AccountController extends BaseController
 			accountService.updateExistingAccount(account);
 		}
 
-		if(request.getSession().getAttribute("database") != null)
+		if(request.getSession().getAttribute("accountMatchList") != null)
 		{
 			return "redirect:/settings/database/import/step2";
 		}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountService.java b/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountService.java
index 067a1354e57bf5fc073a9bff5d34ad9d5bbf2915..1d756f109182bbcd2b2abc40140ed16c3b5f7072 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountService.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountService.java
@@ -2,9 +2,14 @@ package de.deadlocker8.budgetmaster.accounts;
 
 import de.deadlocker8.budgetmaster.authentication.User;
 import de.deadlocker8.budgetmaster.authentication.UserRepository;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.IconService;
+import de.deadlocker8.budgetmaster.images.Image;
+import de.deadlocker8.budgetmaster.images.ImageService;
 import de.deadlocker8.budgetmaster.services.AccessAllEntities;
 import de.deadlocker8.budgetmaster.services.Resettable;
 import de.deadlocker8.budgetmaster.transactions.TransactionService;
+import de.deadlocker8.budgetmaster.services.AccessEntityByID;
 import de.deadlocker8.budgetmaster.utils.Strings;
 import de.thecodelabs.utils.util.Localization;
 import org.padler.natorder.NaturalOrderComparator;
@@ -20,20 +25,24 @@ import java.util.List;
 import java.util.Optional;
 
 @Service
-public class AccountService implements Resettable, AccessAllEntities<Account>
+public class AccountService implements Resettable, AccessAllEntities<Account>, AccessEntityByID<Account>
 {
 	private static final Logger LOGGER = LoggerFactory.getLogger(AccountService.class);
 
 	private final AccountRepository accountRepository;
 	private final TransactionService transactionService;
 	private final UserRepository userRepository;
+	private final ImageService imageService;
+	private final IconService iconService;
 
 	@Autowired
-	public AccountService(AccountRepository accountRepository, TransactionService transactionService, UserRepository userRepository)
+	public AccountService(AccountRepository accountRepository, TransactionService transactionService, UserRepository userRepository, ImageService imageService, IconService iconService)
 	{
 		this.accountRepository = accountRepository;
 		this.transactionService = transactionService;
 		this.userRepository = userRepository;
+		this.imageService = imageService;
+		this.iconService = iconService;
 
 		createDefaults();
 	}
@@ -69,6 +78,12 @@ public class AccountService implements Resettable, AccessAllEntities<Account>
 		return accounts;
 	}
 
+	@Override
+	public Optional<Account> findById(Integer ID)
+	{
+		return accountRepository.findById(ID);
+	}
+
 	public void deleteAccount(int ID)
 	{
 		Optional<Account> accountToDeleteOptional = accountRepository.findById(ID);
@@ -135,25 +150,43 @@ public class AccountService implements Resettable, AccessAllEntities<Account>
 
 	private void updateMissingAttributes()
 	{
-		// handle null values for new field "accountState"
 		for(Account account : accountRepository.findAll())
 		{
-			if(account.getAccountState() == null)
+			handleNullValuesForAccountState(account);
+
+			if(account.getIcon() != null && account.getIconReference() == null)
 			{
-				if(account.isReadOnly() == null || !account.isReadOnly())
-				{
-					account.setAccountState(AccountState.FULL_ACCESS);
-				}
-				else
-				{
-					account.setAccountState(AccountState.READ_ONLY);
-				}
-				LOGGER.debug(MessageFormat.format("Updated account {0}: Set missing attribute \"accountState\" to {1}", account.getName(), account.getAccountState()));
+				Integer imageID = account.getIcon().getID();
+				Image image = imageService.getRepository().findById(imageID).orElseThrow();
+
+				Icon iconReference = new Icon(image);
+				iconService.getRepository().save(iconReference);
+
+				account.setIconReference(iconReference);
+				account.setIcon(null);
+				LOGGER.debug(MessageFormat.format("Updated account {0}: Converted attribute \"icon\" to \"iconReference\" {1}", account.getName(), image.getFileName()));
 			}
+
 			accountRepository.save(account);
 		}
 	}
 
+	private void handleNullValuesForAccountState(Account account)
+	{
+		if(account.getAccountState() == null)
+		{
+			if(account.isReadOnly() == null || !account.isReadOnly())
+			{
+				account.setAccountState(AccountState.FULL_ACCESS);
+			}
+			else
+			{
+				account.setAccountState(AccountState.READ_ONLY);
+			}
+			LOGGER.debug(MessageFormat.format("Updated account {0}: Set missing attribute \"accountState\" to {1}", account.getName(), account.getAccountState()));
+		}
+	}
+
 	private void deselectAllAccounts()
 	{
 		List<Account> accounts = accountRepository.findAll();
@@ -229,7 +262,7 @@ public class AccountService implements Resettable, AccessAllEntities<Account>
 
 		Account existingAccount = existingAccountOptional.get();
 		existingAccount.setName(newAccount.getName());
-		existingAccount.setIcon(newAccount.getIcon());
+		existingAccount.setIconReference(newAccount.getIconReference());
 		existingAccount.setType(AccountType.CUSTOM);
 		existingAccount.setAccountState(newAccount.getAccountState());
 		accountRepository.save(existingAccount);
diff --git a/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountState.java b/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountState.java
index 993d680ea9a84dde4218c234aaf06419c1ad50c7..aeeda3462a4b4797c12f4f001b26205e1748f92a 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountState.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/accounts/AccountState.java
@@ -1,6 +1,9 @@
 package de.deadlocker8.budgetmaster.accounts;
 
-public enum AccountState
+
+import de.deadlocker8.budgetmaster.utils.LocalizedEnum;
+
+public enum AccountState implements LocalizedEnum
 {
 	FULL_ACCESS("fas fa-edit", "account.state.full.access"),
 	READ_ONLY("fas fa-lock", "account.state.read.only"),
@@ -20,6 +23,7 @@ public enum AccountState
 		return icon;
 	}
 
+	@Override
 	public String getLocalizationKey()
 	{
 		return localizationKey;
diff --git a/src/main/java/de/deadlocker8/budgetmaster/backup/AutoBackupStrategy.java b/src/main/java/de/deadlocker8/budgetmaster/backup/AutoBackupStrategy.java
index da45a1e42133dd59d6d86d8027a99660516a91c8..c2ef57c8a6f3fa93727fb493e4cc2f51b71b082b 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/backup/AutoBackupStrategy.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/backup/AutoBackupStrategy.java
@@ -2,12 +2,13 @@ package de.deadlocker8.budgetmaster.backup;
 
 import de.deadlocker8.budgetmaster.database.DatabaseService;
 import de.deadlocker8.budgetmaster.settings.SettingsService;
+import de.deadlocker8.budgetmaster.utils.LocalizedEnum;
 import de.thecodelabs.utils.util.Localization;
 
 import java.lang.reflect.InvocationTargetException;
 import java.util.Optional;
 
-public enum AutoBackupStrategy
+public enum AutoBackupStrategy implements LocalizedEnum
 {
 	NONE("settings.backup.auto.strategy.none", null),
 	LOCAL("settings.backup.auto.strategy.local", LocalBackupTask.class),
@@ -23,6 +24,7 @@ public enum AutoBackupStrategy
 		this.backupTaskType = backupTaskType;
 	}
 
+	@Override
 	public String getLocalizationKey()
 	{
 		return localizationKey;
diff --git a/src/main/java/de/deadlocker8/budgetmaster/categories/Category.java b/src/main/java/de/deadlocker8/budgetmaster/categories/Category.java
index 502aef8cbe4f1129cb4650f516da1fc5175a3dff..1476414776e57e9aa79850391d808ea8138690bb 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/categories/Category.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/categories/Category.java
@@ -1,6 +1,8 @@
 package de.deadlocker8.budgetmaster.categories;
 
 import com.google.gson.annotations.Expose;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.Iconizable;
 import de.deadlocker8.budgetmaster.transactions.Transaction;
 import de.deadlocker8.budgetmaster.utils.ProvidesID;
 import de.thecodelabs.utils.util.Color;
@@ -13,7 +15,7 @@ import java.util.List;
 import java.util.Objects;
 
 @Entity
-public class Category implements ProvidesID
+public class Category implements ProvidesID, Iconizable
 {
 	@Id
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -32,8 +34,13 @@ public class Category implements ProvidesID
 	private CategoryType type;
 
 	@Expose
+	@Deprecated(since = "v2.7.0", forRemoval = true)
 	private String icon;
 
+	@OneToOne(cascade = CascadeType.REMOVE)
+	@Expose
+	private Icon iconReference;
+
 	@OneToMany(mappedBy = "category", fetch = FetchType.LAZY)
 	private List<Transaction> referringTransactions;
 
@@ -42,12 +49,12 @@ public class Category implements ProvidesID
 		this(name, color, type, null);
 	}
 
-	public Category(String name, String color, CategoryType type, String icon)
+	public Category(String name, String color, CategoryType type, Icon iconReference)
 	{
 		this.name = name;
 		this.color = color;
 		this.type = type;
-		this.icon = icon;
+		this.iconReference = iconReference;
 	}
 
 	public Category()
@@ -94,16 +101,28 @@ public class Category implements ProvidesID
 		this.type = type;
 	}
 
+	@Deprecated(since = "v2.7.0", forRemoval = true)
 	public String getIcon()
 	{
 		return icon;
 	}
 
+	@Deprecated(since = "v2.7.0", forRemoval = true)
 	public void setIcon(String icon)
 	{
 		this.icon = icon;
 	}
 
+	public Icon getIconReference()
+	{
+		return iconReference;
+	}
+
+	public void setIconReference(Icon iconReference)
+	{
+		this.iconReference = iconReference;
+	}
+
 	public List<Transaction> getReferringTransactions()
 	{
 		return referringTransactions;
@@ -127,7 +146,7 @@ public class Category implements ProvidesID
 				", name='" + name + '\'' +
 				", color='" + color + '\'' +
 				", type=" + type +
-				", icon='" + icon + '\'' +
+				", iconReference='" + iconReference + '\'' +
 				'}';
 	}
 
@@ -141,12 +160,13 @@ public class Category implements ProvidesID
 				Objects.equals(name, category.name) &&
 				Objects.equals(color, category.color) &&
 				type == category.type &&
-				Objects.equals(icon, category.icon);
+				Objects.equals(icon, category.icon) &&
+				Objects.equals(iconReference, category.iconReference);
 	}
 
 	@Override
 	public int hashCode()
 	{
-		return Objects.hash(ID, name, color, type, icon);
+		return Objects.hash(ID, name, color, type, icon, iconReference);
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/de/deadlocker8/budgetmaster/categories/CategoryController.java b/src/main/java/de/deadlocker8/budgetmaster/categories/CategoryController.java
index 5f74fff5b199eb1a5ddfa3d11252484cf1b504db..d775978b90b0a0839894958fc44fe9b538aecc62 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/categories/CategoryController.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/categories/CategoryController.java
@@ -1,6 +1,7 @@
 package de.deadlocker8.budgetmaster.categories;
 
 import de.deadlocker8.budgetmaster.controller.BaseController;
+import de.deadlocker8.budgetmaster.icon.IconService;
 import de.deadlocker8.budgetmaster.services.HelpersService;
 import de.deadlocker8.budgetmaster.utils.*;
 import de.deadlocker8.budgetmaster.utils.notification.Notification;
@@ -27,12 +28,14 @@ public class CategoryController extends BaseController
 
 	private final CategoryService categoryService;
 	private final HelpersService helpers;
+	private final IconService iconService;
 
 	@Autowired
-	public CategoryController(CategoryService categoryService, HelpersService helpers)
+	public CategoryController(CategoryService categoryService, HelpersService helpers, IconService iconService)
 	{
 		this.categoryService = categoryService;
 		this.helpers = helpers;
+		this.iconService = iconService;
 	}
 
 	@GetMapping
@@ -57,8 +60,8 @@ public class CategoryController extends BaseController
 		model.addAttribute("availableCategories", availableCategories);
 		model.addAttribute("preselectedCategory", categoryService.findByType(CategoryType.NONE));
 
-		model.addAttribute("currentCategory", categoryService.findById(ID).orElseThrow());
-		return "categories/categories";
+		model.addAttribute("categoryToDelete", categoryService.findById(ID).orElseThrow());
+		return "categories/deleteCategoryModal";
 	}
 
 	@PostMapping(value = "/{ID}/delete")
@@ -109,7 +112,9 @@ public class CategoryController extends BaseController
 	}
 
 	@PostMapping(value = "/newCategory")
-	public String post(Model model, @ModelAttribute("NewCategory") Category category, BindingResult bindingResult)
+	public String post(Model model, @ModelAttribute("NewCategory") Category category, BindingResult bindingResult,
+					   @RequestParam(value = "iconImageID", required = false) Integer iconImageID,
+					   @RequestParam(value = "builtinIconIdentifier", required = false) String builtinIconIdentifier)
 	{
 		CategoryValidator userValidator = new CategoryValidator();
 		userValidator.validate(category, bindingResult);
@@ -126,6 +131,9 @@ public class CategoryController extends BaseController
 		{
 			category.setType(CategoryType.CUSTOM);
 		}
+
+		category.updateIcon(iconService, iconImageID, builtinIconIdentifier, categoryService);
+
 		categoryService.save(category);
 
 		return "redirect:/categories";
diff --git a/src/main/java/de/deadlocker8/budgetmaster/categories/CategoryService.java b/src/main/java/de/deadlocker8/budgetmaster/categories/CategoryService.java
index 7f0f22d1ef148121c547876094c9ac51da6509c2..707b2a3392e0321871065b8b57fa288005064d31 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/categories/CategoryService.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/categories/CategoryService.java
@@ -1,8 +1,11 @@
 package de.deadlocker8.budgetmaster.categories;
 
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.IconService;
 import de.deadlocker8.budgetmaster.services.AccessAllEntities;
 import de.deadlocker8.budgetmaster.services.Resettable;
 import de.deadlocker8.budgetmaster.transactions.Transaction;
+import de.deadlocker8.budgetmaster.services.AccessEntityByID;
 import de.deadlocker8.budgetmaster.utils.Strings;
 import de.thecodelabs.utils.util.Localization;
 import org.padler.natorder.NaturalOrderComparator;
@@ -11,24 +14,28 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.text.MessageFormat;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Optional;
 
 @Service
-public class CategoryService implements Resettable, AccessAllEntities<Category>
+public class CategoryService implements Resettable, AccessAllEntities<Category>, AccessEntityByID<Category>
 {
 	private static final Logger LOGGER = LoggerFactory.getLogger(CategoryService.class);
 	private final CategoryRepository categoryRepository;
+	private final IconService iconService;
 
 	@Autowired
-	public CategoryService(CategoryRepository categoryRepository)
+	public CategoryService(CategoryRepository categoryRepository, IconService iconService)
 	{
 		this.categoryRepository = categoryRepository;
+		this.iconService = iconService;
 
 		createDefaults();
 	}
 
+	@Override
 	public Optional<Category> findById(Integer ID)
 	{
 		return categoryRepository.findById(ID);
@@ -97,6 +104,27 @@ public class CategoryService implements Resettable, AccessAllEntities<Category>
 			categoryRepository.save(new Category(Localization.getString(Strings.CATEGORY_REST), "#FFFF00", CategoryType.REST));
 			LOGGER.debug("Created default category REST");
 		}
+
+		updateMissingAttributes();
+	}
+
+	private void updateMissingAttributes()
+	{
+		for(Category category : categoryRepository.findAll())
+		{
+			if(category.getIcon() != null && !category.getIcon().isEmpty() &&category.getIconReference() == null)
+			{
+				final String iconName = category.getIcon();
+				Icon iconReference = new Icon(iconName);
+				iconService.getRepository().save(iconReference);
+
+				category.setIconReference(iconReference);
+				category.setIcon(null);
+
+				categoryRepository.save(category);
+				LOGGER.debug(MessageFormat.format("Updated category {0}: Converted attribute \"icon\" to \"iconReference\" {1}", category.getName(), iconName));
+			}
+		}
 	}
 
 	@Override
diff --git a/src/main/java/de/deadlocker8/budgetmaster/charts/Chart.java b/src/main/java/de/deadlocker8/budgetmaster/charts/Chart.java
index 28bfbf51c9d906cb704343c2d516991118ef1d96..45362237f01e714f25b16d0378960bd4729e47de 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/charts/Chart.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/charts/Chart.java
@@ -2,7 +2,9 @@ package de.deadlocker8.budgetmaster.charts;
 
 import com.google.gson.annotations.Expose;
 
-import javax.persistence.*;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Size;
 import java.util.Objects;
@@ -26,12 +28,19 @@ public class Chart
 	@Expose
 	private int version;
 
-	public Chart(String name, String script, ChartType type, int version)
+	private ChartDisplayType displayType;
+	private ChartGroupType groupType;
+	private String previewImageFileName;
+
+	public Chart(String name, String script, ChartType type, int version, ChartDisplayType displayType, ChartGroupType groupType, String previewImageFileName)
 	{
 		this.name = name;
 		this.script = script;
 		this.type = type;
 		this.version = version;
+		this.displayType = displayType;
+		this.groupType = groupType;
+		this.previewImageFileName = previewImageFileName;
 	}
 
 	public Chart()
@@ -88,6 +97,36 @@ public class Chart
 		this.version = version;
 	}
 
+	public ChartDisplayType getDisplayType()
+	{
+		return displayType;
+	}
+
+	public void setDisplayType(ChartDisplayType displayType)
+	{
+		this.displayType = displayType;
+	}
+
+	public ChartGroupType getGroupType()
+	{
+		return groupType;
+	}
+
+	public void setGroupType(ChartGroupType chartGroupType)
+	{
+		this.groupType = chartGroupType;
+	}
+
+	public String getPreviewImageFileName()
+	{
+		return previewImageFileName;
+	}
+
+	public void setPreviewImageFileName(String previewImageFileName)
+	{
+		this.previewImageFileName = previewImageFileName;
+	}
+
 	@Override
 	public String toString()
 	{
@@ -97,6 +136,9 @@ public class Chart
 				", script='" + script + '\'' +
 				", type=" + type +
 				", version=" + version +
+				", displayType=" + displayType +
+				", chartGroupType=" + groupType +
+				", previewImageFileName=" + previewImageFileName +
 				'}';
 	}
 
@@ -106,16 +148,12 @@ public class Chart
 		if(this == o) return true;
 		if(o == null || getClass() != o.getClass()) return false;
 		Chart chart = (Chart) o;
-		return version == chart.version &&
-				Objects.equals(ID, chart.ID) &&
-				Objects.equals(name, chart.name) &&
-				Objects.equals(script, chart.script) &&
-				type == chart.type;
+		return version == chart.version && Objects.equals(ID, chart.ID) && Objects.equals(name, chart.name) && Objects.equals(script, chart.script) && type == chart.type && displayType == chart.displayType && groupType == chart.groupType && Objects.equals(previewImageFileName, chart.previewImageFileName);
 	}
 
 	@Override
 	public int hashCode()
 	{
-		return Objects.hash(ID, name, script, type, version);
+		return Objects.hash(ID, name, script, type, version, displayType, groupType, previewImageFileName);
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/de/deadlocker8/budgetmaster/charts/ChartController.java b/src/main/java/de/deadlocker8/budgetmaster/charts/ChartController.java
index cebdce507fa895bbdc8cf62ef91ede5183289e05..f987972bbe1768676faed38eb3efb4c88948584b 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/charts/ChartController.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/charts/ChartController.java
@@ -62,10 +62,13 @@ public class ChartController extends BaseController
 		defaultFilterConfiguration.setFilterCategories(filterHelpersService.getFilterCategories());
 		defaultFilterConfiguration.setFilterTags(filterHelpersService.getFilterTags());
 
-		ChartSettings defaultChartSettings = ChartSettings.getDefault(charts.get(0).getID(), defaultFilterConfiguration);
+		ChartSettings defaultChartSettings = ChartSettings.getDefault(defaultFilterConfiguration);
 
 		model.addAttribute("chartSettings", defaultChartSettings);
 		model.addAttribute("charts", charts);
+		model.addAttribute("displayTypes", ChartDisplayType.values());
+		model.addAttribute("groupTypes", ChartGroupType.values());
+
 		return "charts/charts";
 	}
 
@@ -87,6 +90,8 @@ public class ChartController extends BaseController
 		model.addAttribute("chart", chartOptional.get());
 		model.addAttribute("containerID", UUID.randomUUID());
 		model.addAttribute("transactionData", transactionJson);
+		model.addAttribute("displayTypes", ChartDisplayType.values());
+		model.addAttribute("groupTypes", ChartGroupType.values());
 		return "charts/charts";
 	}
 
@@ -124,10 +129,9 @@ public class ChartController extends BaseController
 		ChartValidator userValidator = new ChartValidator();
 		userValidator.validate(chart, bindingResult);
 
-		if(chart.getType() == null)
-		{
-			chart.setType(ChartType.CUSTOM);
-		}
+		chart.setType(ChartType.CUSTOM);
+		chart.setDisplayType(ChartDisplayType.CUSTOM);
+		chart.setGroupType(ChartGroupType.NONE);
 
 		if(bindingResult.hasErrors())
 		{
@@ -166,8 +170,8 @@ public class ChartController extends BaseController
 		}
 
 		model.addAttribute("charts", chartService.getAllEntitiesAsc());
-		model.addAttribute("currentChart", chartService.getRepository().getOne(ID));
-		return "charts/manage";
+		model.addAttribute("chartToDelete", chartService.getRepository().getById(ID));
+		return "charts/deleteChartModal";
 	}
 
 	@GetMapping(value = "/{ID}/delete")
@@ -175,7 +179,7 @@ public class ChartController extends BaseController
 	{
 		if(chartService.isDeletable(ID))
 		{
-			final Chart chartToDelete = chartService.getRepository().getOne(ID);
+			final Chart chartToDelete = chartService.getRepository().getById(ID);
 			chartService.getRepository().deleteById(ID);
 			WebRequestUtils.putNotification(request, new Notification(Localization.getString("notification.chart.delete.success", chartToDelete.getName()), NotificationType.SUCCESS));
 		}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/charts/ChartDisplayType.java b/src/main/java/de/deadlocker8/budgetmaster/charts/ChartDisplayType.java
new file mode 100644
index 0000000000000000000000000000000000000000..de2470534d1f4a534fffb04742e21d207c161300
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/charts/ChartDisplayType.java
@@ -0,0 +1,36 @@
+package de.deadlocker8.budgetmaster.charts;
+
+import de.deadlocker8.budgetmaster.utils.LocalizedEnum;
+
+public enum ChartDisplayType implements LocalizedEnum
+{
+	PIE("fas fa-chart-pie", "pie"),
+	BAR("fas fa-chart-bar", "bar"),
+	LINE("fas fa-chart-line", "line"),
+	CUSTOM("insights", "custom");
+
+	private final String icon;
+	private final String localizationKey;
+
+	ChartDisplayType(String icon, String localizationKey)
+	{
+		this.icon = icon;
+		this.localizationKey = localizationKey;
+	}
+
+	public boolean hasFontAwesomeIcon()
+	{
+		return icon.startsWith("fa");
+	}
+
+	public String getIcon()
+	{
+		return icon;
+	}
+
+	@Override
+	public String getLocalizationKey()
+	{
+		return "chart.display.type." + localizationKey;
+	}
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/charts/ChartGroupType.java b/src/main/java/de/deadlocker8/budgetmaster/charts/ChartGroupType.java
new file mode 100644
index 0000000000000000000000000000000000000000..b1f7e24adf2a262a852e0773dc48356ac4577528
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/charts/ChartGroupType.java
@@ -0,0 +1,35 @@
+package de.deadlocker8.budgetmaster.charts;
+
+import de.deadlocker8.budgetmaster.utils.LocalizedEnum;
+
+public enum ChartGroupType implements LocalizedEnum
+{
+	NONE("far fa-calendar-times", "none"),
+	MONTH("far fa-calendar", "month"),
+	YEAR("far fa-calendar-alt", "year");
+
+	private final String icon;
+	private final String localizationKey;
+
+	ChartGroupType(String icon, String localizationKey)
+	{
+		this.icon = icon;
+		this.localizationKey = localizationKey;
+	}
+
+	public boolean hasFontAwesomeIcon()
+	{
+		return icon.startsWith("fa");
+	}
+
+	public String getIcon()
+	{
+		return icon;
+	}
+
+	@Override
+	public String getLocalizationKey()
+	{
+		return "chart.group.type." + localizationKey;
+	}
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/charts/ChartService.java b/src/main/java/de/deadlocker8/budgetmaster/charts/ChartService.java
index 850e688fc9207cea2e819b08e777db0a3a99193c..b0beea706b7821743a021b73e84de212bec62ab4 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/charts/ChartService.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/charts/ChartService.java
@@ -71,6 +71,9 @@ public class ChartService implements Resettable, AccessAllEntities<Chart>
 				LOGGER.debug(MessageFormat.format("Update default chart ''{0}'' from version {1} to {2}", chart.getName(), currentChart.getVersion(), chart.getVersion()));
 				currentChart.setVersion(chart.getVersion());
 				currentChart.setScript(chart.getScript());
+				currentChart.setDisplayType(chart.getDisplayType());
+				currentChart.setGroupType(chart.getGroupType());
+				currentChart.setPreviewImageFileName(chart.getPreviewImageFileName());
 				chartRepository.save(currentChart);
 			}
 		}
@@ -88,6 +91,13 @@ public class ChartService implements Resettable, AccessAllEntities<Chart>
 	}
 
 	private void updateUserCharts()
+	{
+		updateContainerIdUsage();
+
+		updateMissingAttributes();
+	}
+
+	private void updateContainerIdUsage()
 	{
 		final List<Chart> userCharts = getRepository().findAllByType(ChartType.CUSTOM);
 		for(Chart userChart : userCharts)
@@ -95,7 +105,7 @@ public class ChartService implements Resettable, AccessAllEntities<Chart>
 			String script = userChart.getScript();
 			if(script.contains(PATTERN_OLD_CONTAINER_ID))
 			{
-				LOGGER.debug(MessageFormat.format("Updating user chart ''{0}'' with ID {1}", userChart.getName(), userChart.getID()));
+				LOGGER.debug(MessageFormat.format("Updating container id usage for user chart ''{0}'' with ID {1}", userChart.getName(), userChart.getID()));
 				script = script.replace(PATTERN_OLD_CONTAINER_ID, PATTERN_DYNAMIC_CONTAINER_ID);
 				userChart.setScript(script);
 				getRepository().save(userChart);
@@ -103,6 +113,31 @@ public class ChartService implements Resettable, AccessAllEntities<Chart>
 		}
 	}
 
+	private void updateMissingAttributes()
+	{
+		final List<Chart> userCharts = getRepository().findAllByType(ChartType.CUSTOM);
+		for(Chart userChart : userCharts)
+		{
+			boolean changed = false;
+			if(userChart.getDisplayType() == null)
+			{
+				userChart.setDisplayType(ChartDisplayType.CUSTOM);
+				changed = true;
+			}
+			if(userChart.getGroupType() == null)
+			{
+				userChart.setGroupType(ChartGroupType.NONE);
+				changed = true;
+			}
+
+			if(changed)
+			{
+				LOGGER.debug(MessageFormat.format("Updating missing attributes for user chart ''{0}'' with ID {1}", userChart.getName(), userChart.getID()));
+				getRepository().save(userChart);
+			}
+		}
+	}
+
 	@Override
 	public List<Chart> getAllEntitiesAsc()
 	{
diff --git a/src/main/java/de/deadlocker8/budgetmaster/charts/ChartSettings.java b/src/main/java/de/deadlocker8/budgetmaster/charts/ChartSettings.java
index e5ef9a4ce046694225d9834f7ae0a4249eab9255..aac9e2d9fb6f00fa6e8537fe2db7800b4d93dc97 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/charts/ChartSettings.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/charts/ChartSettings.java
@@ -7,36 +7,61 @@ import org.springframework.format.annotation.DateTimeFormat;
 
 public class ChartSettings
 {
-	private int chartID;
+	private ChartDisplayType displayType;
+	private ChartGroupType groupType;
+
+	private Integer chartID;
 	@DateTimeFormat(pattern = "dd.MM.yyyy")
 	private DateTime startDate;
 	@DateTimeFormat(pattern = "dd.MM.yyyy")
 	private DateTime endDate;
 	private FilterConfiguration filterConfiguration;
 
-	public static ChartSettings getDefault(int chartID, FilterConfiguration filterConfiguration)
+	public static ChartSettings getDefault(FilterConfiguration filterConfiguration)
 	{
-		return new ChartSettings(chartID, DateTime.now().withDayOfMonth(1), DateTime.now().dayOfMonth().withMaximumValue(), filterConfiguration);
+		return new ChartSettings(ChartDisplayType.BAR, ChartGroupType.MONTH, null, DateTime.now().withDayOfMonth(1), DateTime.now().dayOfMonth().withMaximumValue(), filterConfiguration);
 	}
 
 	public ChartSettings()
 	{
 	}
 
-	public ChartSettings(int chartID, DateTime startDate, DateTime endDate, FilterConfiguration filterConfiguration)
+	public ChartSettings(ChartDisplayType displayType, ChartGroupType groupType, Integer chartID, DateTime startDate, DateTime endDate, FilterConfiguration filterConfiguration)
 	{
+		this.displayType = displayType;
+		this.groupType = groupType;
 		this.chartID = chartID;
 		this.startDate = startDate;
 		this.endDate = endDate;
 		this.filterConfiguration = filterConfiguration;
 	}
 
-	public int getChartID()
+	public ChartDisplayType getDisplayType()
+	{
+		return displayType;
+	}
+
+	public void setDisplayType(ChartDisplayType displayType)
+	{
+		this.displayType = displayType;
+	}
+
+	public ChartGroupType getGroupType()
+	{
+		return groupType;
+	}
+
+	public void setGroupType(ChartGroupType groupType)
+	{
+		this.groupType = groupType;
+	}
+
+	public Integer getChartID()
 	{
 		return chartID;
 	}
 
-	public void setChartID(int chartID)
+	public void setChartID(Integer chartID)
 	{
 		this.chartID = chartID;
 	}
@@ -71,11 +96,18 @@ public class ChartSettings
 		this.filterConfiguration = filterConfiguration;
 	}
 
+	public boolean isChartSelected()
+	{
+		return chartID != null;
+	}
+
 	@Override
 	public String toString()
 	{
 		return "ChartSettings{" +
-				"chartID=" + chartID +
+				"displayType=" + displayType +
+				", groupType=" + groupType +
+				", chartID=" + chartID +
 				", startDate=" + startDate +
 				", endDate=" + endDate +
 				", filterConfiguration=" + filterConfiguration +
diff --git a/src/main/java/de/deadlocker8/budgetmaster/charts/DefaultCharts.java b/src/main/java/de/deadlocker8/budgetmaster/charts/DefaultCharts.java
index 846537a8a8ac4a5cba3f15d316fbe4a77ffb79e7..d5852eee942705b019a680d292c242cd83473162 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/charts/DefaultCharts.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/charts/DefaultCharts.java
@@ -16,39 +16,39 @@ public class DefaultCharts
 
 	public static final Chart CHART_DEFAULT = new Chart(null,
 			getChartFromFile("charts/Default.js"),
-			ChartType.CUSTOM, -1);
+			ChartType.CUSTOM, -1, ChartDisplayType.CUSTOM, ChartGroupType.NONE, null);
 
 	private static final Chart CHART_ACCOUNT_SUM_PER_DAY = new Chart("charts.default.accountSumPerDay",
 			getChartFromFile("charts/AccountSumPerDay.js"),
-			ChartType.DEFAULT, 7);
+			ChartType.DEFAULT, 11, ChartDisplayType.LINE, ChartGroupType.NONE, "accountSumPerDay.png");
 
 	private static final Chart CHART_INCOMES_AND_EXPENDITURES_PER_MONTH_BAR = new Chart("charts.default.incomesAndExpendituresPerMonthBar",
 			getChartFromFile("charts/IncomesAndExpendituresPerMonthBar.js"),
-			ChartType.DEFAULT, 7);
+			ChartType.DEFAULT, 11, ChartDisplayType.BAR, ChartGroupType.MONTH, "incomesAndExpendituresPerMonthBar.png");
 
 	private static final Chart CHART_INCOMES_AND_EXPENDITURES_PER_MONTH_LINE = new Chart("charts.default.incomesAndExpendituresPerMonthLine",
 			getChartFromFile("charts/IncomesAndExpendituresPerMonthLine.js"),
-			ChartType.DEFAULT, 7);
+			ChartType.DEFAULT, 11, ChartDisplayType.LINE, ChartGroupType.MONTH, "incomesAndExpendituresPerMonthLine.png");
 
 	private static final Chart CHART_INCOMES_AND_EXPENDITURES_BY_CATEGORY_BAR = new Chart("charts.default.incomesAndExpendituresByCategoryBar",
 			getChartFromFile("charts/IncomesAndExpendituresByCategoryBar.js"),
-			ChartType.DEFAULT, 2);
+			ChartType.DEFAULT, 6, ChartDisplayType.BAR, ChartGroupType.NONE, "incomesAndExpendituresByCategoryBar.png");
 
 	private static final Chart CHART_INCOMES_AND_EXPENDITURES_BY_CATEGORY_PIE = new Chart("charts.default.incomesAndExpendituresByCategoryPie",
 			getChartFromFile("charts/IncomesAndExpendituresByCategoryPie.js"),
-			ChartType.DEFAULT, 3);
+			ChartType.DEFAULT, 7, ChartDisplayType.PIE, ChartGroupType.NONE, "incomesAndExpendituresByCategoryPie.png");
 
 	private static final Chart CHART_INCOMES_AND_EXPENDITURES_PER_MONTH_BY_CATEGORIES = new Chart("charts.default.incomesAndExpendituresPerMonthByCategories",
 			getChartFromFile("charts/IncomesAndExpendituresPerMonthByCategories.js"),
-			ChartType.DEFAULT, 17);
+			ChartType.DEFAULT, 21, ChartDisplayType.BAR, ChartGroupType.MONTH, "incomesAndExpendituresPerMonthByCategories.png");
 
 	private static final Chart CHART_REST_PER_MONTH = new Chart("charts.default.restPerMonth",
 			getChartFromFile("charts/RestPerMonth.js"),
-			ChartType.DEFAULT, 3);
+			ChartType.DEFAULT, 7, ChartDisplayType.BAR, ChartGroupType.MONTH, "restPerMonth.png");
 
 	private static final Chart CHART_INCOMES_AND_EXPENDITURES_PER_YEAR_BAR = new Chart("charts.default.incomesAndExpendituresPerYearBar",
 			getChartFromFile("charts/IncomesAndExpendituresPerYearBar.js"),
-			ChartType.DEFAULT, 2);
+			ChartType.DEFAULT, 6, ChartDisplayType.BAR, ChartGroupType.YEAR, "incomesAndExpendituresPerYearBar.png");
 
 	private DefaultCharts()
 	{
diff --git a/src/main/java/de/deadlocker8/budgetmaster/controller/AboutController.java b/src/main/java/de/deadlocker8/budgetmaster/controller/AboutController.java
index f0a0563ddf3aa105914d6d75eba1f1cb7e32d044..257a5b5ee22db9eb9265e7a69f90988084f53f13 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/controller/AboutController.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/controller/AboutController.java
@@ -36,17 +36,15 @@ public class AboutController extends BaseController
 	public String whatsNewModal(Model model)
 	{
 		final List<NewsEntry> newsEntries = new ArrayList<>();
-		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.fix.backup.size.headline", "news.fix.backup.size.description"));
-		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.fix.readonly.accounts.headline", "news.fix.readonly.accounts.description"));
-		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.designOffensive.headline", "news.designOffensive.description"));
-		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.gitBackup.headline", "news.gitBackup.description"));
-		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.backupCharts.headline", "news.backupCharts.description"));
-		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.importProcess.headline", "news.importProcess.description"));
-		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.hideAccounts.headline", "news.hideAccounts.description"));
-		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.statistics.headline", "news.statistics.description"));
-		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.hotkeysMonth.headline", "news.hotkeysMonth.description"));
-		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.importBugfixes.headline", "news.importBugfixes.description"));
-		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.chartRelative.headline", "news.chartRelative.description"));
+		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.chartChooser.headline", "news.chartChooser.description"));
+		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.jumpToSearch.headline", "news.jumpToSearch.description"));
+		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.fontAwesomeIcons.headline", "news.fontAwesomeIcons.description"));
+		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.nonSquareImages.headline", "news.nonSquareImages.description"));
+		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.hints.headline", "news.hints.description"));
+		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.tagOverview.headline", "news.tagOverview.description"));
+		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.accountImport.headline", "news.accountImport.description"));
+		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.performance.headline", "news.performance.description"));
+		newsEntries.add(NewsEntry.createWithLocalizationKeys("news.fix.transfersFromHiddenAccounts.headline", "news.fix.transfersFromHiddenAccounts.description"));
 
 		model.addAttribute("newsEntries", newsEntries);
 		return "whatsNewModal";
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser.java b/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser.java
index 67209c484ada1ae4005deaa4b3e18139e76c3184..f0b6a573deac1d007e3234c2d0f3f6a2336f919a 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser.java
@@ -6,6 +6,7 @@ import de.deadlocker8.budgetmaster.database.model.BackupDatabase;
 import de.deadlocker8.budgetmaster.database.model.v4.BackupDatabase_v4;
 import de.deadlocker8.budgetmaster.database.model.v5.BackupDatabase_v5;
 import de.deadlocker8.budgetmaster.database.model.v6.BackupDatabase_v6;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupDatabase_v7;
 import de.thecodelabs.utils.util.Localization;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -17,7 +18,7 @@ public class DatabaseParser
 	final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
 
 	private static final int MINIMUM_VERSION = 4;
-	public static final int LATEST_VERSION = 6;
+	public static final int LATEST_VERSION = 7;
 
 	private final String jsonString;
 
@@ -58,6 +59,13 @@ public class DatabaseParser
 			importedDatabase = parsedDatabase;
 		}
 
+		if(version == 7)
+		{
+			BackupDatabase_v7 parsedDatabase = new DatabaseParser_v7(jsonString).parseDatabaseFromJSON();
+			LOGGER.debug(MessageFormat.format("Parsed database with {0} transactions, {1} categories, {2} accounts, {3} templates {4} charts {5} images and {6} icons", parsedDatabase.getTransactions().size(), parsedDatabase.getCategories().size(), parsedDatabase.getAccounts().size(), parsedDatabase.getTemplates().size(), parsedDatabase.getCharts().size(), parsedDatabase.getImages().size(), parsedDatabase.getIcons().size()));
+			importedDatabase = parsedDatabase;
+		}
+
 		if(importedDatabase == null)
 		{
 			throw new IllegalArgumentException(Localization.getString("error.database.import.unknown.version"));
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser_v7.java b/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser_v7.java
new file mode 100644
index 0000000000000000000000000000000000000000..06d85db12404446a3db55ea54af956f372a33e5e
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseParser_v7.java
@@ -0,0 +1,37 @@
+package de.deadlocker8.budgetmaster.database;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import de.deadlocker8.budgetmaster.database.model.v5.BackupChart_v5;
+import de.deadlocker8.budgetmaster.database.model.v5.BackupImage_v5;
+import de.deadlocker8.budgetmaster.database.model.v6.BackupTransaction_v6;
+import de.deadlocker8.budgetmaster.database.model.v7.*;
+
+public class DatabaseParser_v7
+{
+	private final String jsonString;
+
+	private BackupDatabase_v7 database;
+
+	public DatabaseParser_v7(String json)
+	{
+		this.jsonString = json;
+		this.database = new BackupDatabase_v7();
+	}
+
+	public BackupDatabase_v7 parseDatabaseFromJSON() throws IllegalArgumentException
+	{
+		database = new BackupDatabase_v7();
+
+		final JsonObject root = JsonParser.parseString(jsonString).getAsJsonObject();
+		database.setImages(BackupItemParser.parseItems(root.get("images").getAsJsonArray(), BackupImage_v5.class));
+		database.setIcons(BackupItemParser.parseItems(root.get("icons").getAsJsonArray(), BackupIcon_v7.class));
+		database.setAccounts(BackupItemParser.parseItems(root.get("accounts").getAsJsonArray(), BackupAccount_v7.class));
+		database.setCategories(BackupItemParser.parseItems(root.get("categories").getAsJsonArray(), BackupCategory_v7.class));
+		database.setTransactions(BackupItemParser.parseItems(root.get("transactions").getAsJsonArray(), BackupTransaction_v6.class));
+		database.setTemplates(BackupItemParser.parseItems(root.get("templates").getAsJsonArray(), BackupTemplate_v7.class));
+		database.setCharts(BackupItemParser.parseItems(root.get("charts").getAsJsonArray(), BackupChart_v5.class));
+
+		return database;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseService.java b/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseService.java
index d6f74c31cb40bde0ba419797ba646756dde4d59a..4f906c186922a926cf763dd7f3249a53b2d2a552 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseService.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/DatabaseService.java
@@ -9,8 +9,9 @@ import de.deadlocker8.budgetmaster.categories.CategoryService;
 import de.deadlocker8.budgetmaster.charts.Chart;
 import de.deadlocker8.budgetmaster.charts.ChartService;
 import de.deadlocker8.budgetmaster.charts.ChartType;
-import de.deadlocker8.budgetmaster.database.model.v5.BackupDatabase_v5;
-import de.deadlocker8.budgetmaster.database.model.v6.BackupDatabase_v6;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupDatabase_v7;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.IconService;
 import de.deadlocker8.budgetmaster.images.Image;
 import de.deadlocker8.budgetmaster.images.ImageService;
 import de.deadlocker8.budgetmaster.repeating.RepeatingOption;
@@ -54,9 +55,10 @@ public class DatabaseService
 	private final ChartService chartService;
 	private final SettingsService settingsService;
 	private final ImageService imageService;
+	private final IconService iconService;
 
 	@Autowired
-	public DatabaseService(AccountService accountService, CategoryService categoryService, TransactionService transactionService, TagService tagService, TemplateService templateService, ChartService chartService, SettingsService settingsService, ImageService imageService)
+	public DatabaseService(AccountService accountService, CategoryService categoryService, TransactionService transactionService, TagService tagService, TemplateService templateService, ChartService chartService, SettingsService settingsService, ImageService imageService, IconService iconService)
 	{
 		this.accountService = accountService;
 		this.categoryService = categoryService;
@@ -66,6 +68,7 @@ public class DatabaseService
 		this.chartService = chartService;
 		this.settingsService = settingsService;
 		this.imageService = imageService;
+		this.iconService = iconService;
 	}
 
 	public void reset()
@@ -76,6 +79,7 @@ public class DatabaseService
 		resetAccounts();
 		resetTags();
 		resetCharts();
+		resetIcons();
 		resetImages();
 	}
 
@@ -135,6 +139,14 @@ public class DatabaseService
 		LOGGER.info("All images reset.");
 	}
 
+	private void resetIcons()
+	{
+		LOGGER.info("Resetting icons...");
+		iconService.deleteAll();
+		iconService.createDefaults();
+		LOGGER.info("All icons reset.");
+	}
+
 	public void rotatingBackup(Path backupFolderPath)
 	{
 		final List<Path> filesToDelete = determineFilesToDelete(backupFolderPath);
@@ -218,7 +230,7 @@ public class DatabaseService
 	@Transactional
 	public void exportDatabase(Path backupPath)
 	{
-		final BackupDatabase_v6 database = getDatabaseForJsonSerialization();
+		final BackupDatabase_v7 database = getDatabaseForJsonSerialization();
 
 		try(Writer writer = new FileWriter(backupPath.toString()))
 		{
@@ -243,7 +255,7 @@ public class DatabaseService
 		return "BudgetMasterDatabase_" + DateTime.now().toString(formatString) + ".json";
 	}
 
-	public BackupDatabase_v6 getDatabaseForJsonSerialization()
+	public BackupDatabase_v7 getDatabaseForJsonSerialization()
 	{
 		List<Category> categories = categoryService.getAllEntitiesAsc();
 		List<Account> accounts = accountService.getRepository().findAll();
@@ -252,12 +264,13 @@ public class DatabaseService
 		List<Template> templates = templateService.getRepository().findAll();
 		List<Chart> charts = chartService.getRepository().findAllByType(ChartType.CUSTOM);
 		List<Image> images = imageService.getRepository().findAll();
+		List<Icon> icons = iconService.getRepository().findAll();
 		LOGGER.debug(MessageFormat.format("Reduced {0} transactions to {1}", transactions.size(), filteredTransactions.size()));
 
-		InternalDatabase database = new InternalDatabase(categories, accounts, filteredTransactions, templates, charts, images);
-		LOGGER.debug(MessageFormat.format("Created database for JSON with {0} transactions, {1} categories, {2} accounts, {3} templates, {4} charts and {5} images", database.getTransactions().size(), database.getCategories().size(), database.getAccounts().size(), database.getTemplates().size(), database.getCharts().size(), database.getImages()));
+		InternalDatabase database = new InternalDatabase(categories, accounts, filteredTransactions, templates, charts, images, icons);
+		LOGGER.debug(MessageFormat.format("Created database for JSON with {0} transactions, {1} categories, {2} accounts, {3} templates, {4} charts {5} images and {6} icons", database.getTransactions().size(), database.getCategories().size(), database.getAccounts().size(), database.getTemplates().size(), database.getCharts().size(), database.getImages().size(), database.getIcons().size()));
 
-		BackupDatabase_v6 databaseInExternalForm = BackupDatabase_v6.createFromInternalEntities(database);
+		BackupDatabase_v7 databaseInExternalForm = BackupDatabase_v7.createFromInternalEntities(database);
 		LOGGER.debug("Converted database to external form");
 		return databaseInExternalForm;
 	}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/InternalDatabase.java b/src/main/java/de/deadlocker8/budgetmaster/database/InternalDatabase.java
index a3a1f0d6d693aa5c114c93e41bb6fff3775b45b5..a0e96c10127e63ca7d3a3c50836c7de6e1af787a 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/InternalDatabase.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/InternalDatabase.java
@@ -4,6 +4,7 @@ import de.deadlocker8.budgetmaster.accounts.Account;
 import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.categories.Category;
 import de.deadlocker8.budgetmaster.charts.Chart;
+import de.deadlocker8.budgetmaster.icon.Icon;
 import de.deadlocker8.budgetmaster.images.Image;
 import de.deadlocker8.budgetmaster.services.EntityType;
 import de.deadlocker8.budgetmaster.templates.Template;
@@ -22,12 +23,13 @@ public class InternalDatabase
 	private List<Template> templates;
 	private List<Chart> charts;
 	private List<Image> images;
+	private List<Icon> icons;
 
 	public InternalDatabase()
 	{
 	}
 
-	public InternalDatabase(List<Category> categories, List<Account> accounts, List<Transaction> transactions, List<Template> templates, List<Chart> charts, List<Image> images)
+	public InternalDatabase(List<Category> categories, List<Account> accounts, List<Transaction> transactions, List<Template> templates, List<Chart> charts, List<Image> images, List<Icon> icons)
 	{
 		this.categories = categories;
 		this.accounts = accounts;
@@ -35,6 +37,7 @@ public class InternalDatabase
 		this.templates = templates;
 		this.charts = charts;
 		this.images = images;
+		this.icons = icons;
 	}
 
 	public List<Category> getCategories()
@@ -67,6 +70,11 @@ public class InternalDatabase
 		return images;
 	}
 
+	public List<Icon> getIcons()
+	{
+		return icons;
+	}
+
 	public Map<EntityType, Integer> getNumberOfEntitiesByType()
 	{
 		final Map<EntityType, Integer> numberOfEntitiesByType = new LinkedHashMap<>();
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/BackupDatabase.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/BackupDatabase.java
index 07a2070f75ce187f07ec1b40a508992a030535ac..e00ee119d9a074d7fe9f4123f5073e9093302ed5 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/BackupDatabase.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/BackupDatabase.java
@@ -13,12 +13,12 @@ public interface BackupDatabase
 
 	InternalDatabase convertToInternal();
 
-	default <T> List<T> upgradeItems(List<? extends Upgradeable<T>> items)
+	default <T> List<T> upgradeItems(List<? extends Upgradeable<T>> items, List<BackupInfo> backupInfoItems)
 	{
 		List<T> upgradedItems = new ArrayList<>();
 		for(Upgradeable<T> item : items)
 		{
-			upgradedItems.add(item.upgrade());
+			upgradedItems.add(item.upgrade(backupInfoItems));
 		}
 		return upgradedItems;
 	}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/BackupInfo.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/BackupInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..7856c17ae6cab9d68fab3ae8c610c6989fd55313
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/BackupInfo.java
@@ -0,0 +1,5 @@
+package de.deadlocker8.budgetmaster.database.model;
+
+public interface BackupInfo
+{
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/Upgradeable.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/Upgradeable.java
index 4da81d2064df374be9b07025b9d734ee232ccc84..465bd22675e8134d53d1d7ec373b8329b6fbf9b1 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/Upgradeable.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/Upgradeable.java
@@ -1,6 +1,8 @@
 package de.deadlocker8.budgetmaster.database.model;
 
+import java.util.List;
+
 public interface Upgradeable<T>
 {
-	T upgrade();
+	T upgrade(List<BackupInfo> backupInfoItems);
 }
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/AccountConverter.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/AccountConverter.java
index 0c1d1c851de8171b562777ea0d4bfaebbb4c7a23..c6d66100101a7713ffc814882ba6cf24490f83b9 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/AccountConverter.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/AccountConverter.java
@@ -2,21 +2,21 @@ package de.deadlocker8.budgetmaster.database.model.converter;
 
 import de.deadlocker8.budgetmaster.accounts.Account;
 import de.deadlocker8.budgetmaster.database.model.Converter;
-import de.deadlocker8.budgetmaster.database.model.v6.BackupAccount_v6;
-import de.deadlocker8.budgetmaster.images.Image;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupAccount_v7;
+import de.deadlocker8.budgetmaster.icon.Icon;
 
 import java.util.List;
 
-public class AccountConverter implements Converter<Account, BackupAccount_v6>
+public class AccountConverter implements Converter<Account, BackupAccount_v7>
 {
-	private final List<Image> availableIcons;
+	private final List<Icon> availableIcons;
 
-	public AccountConverter(List<Image> availableIcons)
+	public AccountConverter(List<Icon> availableIcons)
 	{
 		this.availableIcons = availableIcons;
 	}
 
-	public Account convertToInternalForm(BackupAccount_v6 backupAccount)
+	public Account convertToInternalForm(BackupAccount_v7 backupAccount)
 	{
 		if(backupAccount == null)
 		{
@@ -30,34 +30,28 @@ public class AccountConverter implements Converter<Account, BackupAccount_v6>
 		account.setSelected(false);
 		account.setAccountState(backupAccount.getAccountState());
 		account.setType(backupAccount.getType());
-		account.setIcon(getIconById(backupAccount.getIconID()));
+		account.setIconReference(getItemById(availableIcons, backupAccount.getIconReferenceID()));
 		return account;
 	}
 
-	private Image getIconById(Integer iconID)
-	{
-		return availableIcons.stream()
-				.filter(icon -> icon.getID().equals(iconID))
-				.findFirst().orElse(null);
-	}
-
 	@Override
-	public BackupAccount_v6 convertToExternalForm(Account internalAccount)
+	public BackupAccount_v7 convertToExternalForm(Account internalAccount)
 	{
 		if(internalAccount == null)
 		{
 			return null;
 		}
 
-		final BackupAccount_v6 account = new BackupAccount_v6();
+		final BackupAccount_v7 account = new BackupAccount_v7();
 		account.setID(internalAccount.getID());
 		account.setName(internalAccount.getName());
 		account.setAccountState(internalAccount.getAccountState());
 		account.setType(internalAccount.getType());
 
-		if(internalAccount.getIcon() != null)
+		final Icon icon = internalAccount.getIconReference();
+		if(icon != null)
 		{
-			account.setIconID(internalAccount.getIcon().getID());
+			account.setIconReferenceID(icon.getID());
 		}
 		return account;
 	}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/CategoryConverter.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/CategoryConverter.java
index 51c40bc0306a5e2b295c2b107bf6b7d2dd30a8f5..b8af25616fadf2f2942d2c79c3446c8e7796bf6e 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/CategoryConverter.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/CategoryConverter.java
@@ -2,11 +2,22 @@ package de.deadlocker8.budgetmaster.database.model.converter;
 
 import de.deadlocker8.budgetmaster.categories.Category;
 import de.deadlocker8.budgetmaster.database.model.Converter;
-import de.deadlocker8.budgetmaster.database.model.v5.BackupCategory_v5;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupCategory_v7;
+import de.deadlocker8.budgetmaster.icon.Icon;
 
-public class CategoryConverter implements Converter<Category, BackupCategory_v5>
+import java.util.List;
+
+public class CategoryConverter implements Converter<Category, BackupCategory_v7>
 {
-	public Category convertToInternalForm(BackupCategory_v5 backupCategory)
+	private final List<Icon> availableIcons;
+
+	public CategoryConverter(List<Icon> availableIcons)
+	{
+		this.availableIcons = availableIcons;
+	}
+
+
+	public Category convertToInternalForm(BackupCategory_v7 backupCategory)
 	{
 		if(backupCategory == null)
 		{
@@ -18,24 +29,31 @@ public class CategoryConverter implements Converter<Category, BackupCategory_v5>
 		category.setName(backupCategory.getName());
 		category.setColor(backupCategory.getColor());
 		category.setType(backupCategory.getType());
-		category.setIcon(backupCategory.getIcon());
+		category.setIconReference(getItemById(availableIcons, backupCategory.getIconReferenceID()));
+
 		return category;
 	}
 
 	@Override
-	public BackupCategory_v5 convertToExternalForm(Category internalItem)
+	public BackupCategory_v7 convertToExternalForm(Category internalItem)
 	{
 		if(internalItem == null)
 		{
 			return null;
 		}
 
-		final BackupCategory_v5 category = new BackupCategory_v5();
+		final BackupCategory_v7 category = new BackupCategory_v7();
 		category.setID(internalItem.getID());
 		category.setName(internalItem.getName());
 		category.setColor(internalItem.getColor());
 		category.setType(internalItem.getType());
-		category.setIcon(internalItem.getIcon());
+
+		final Icon icon = internalItem.getIconReference();
+		if(icon != null)
+		{
+			category.setIconReferenceID(icon.getID());
+		}
+
 		return category;
 	}
 }
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/ChartConverter.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/ChartConverter.java
index 77525beb6d89e44b8a7337ab4ae65537598acc97..fb0bf54e3d008979d0b0ce76675747e9cd6b585d 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/ChartConverter.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/ChartConverter.java
@@ -1,6 +1,8 @@
 package de.deadlocker8.budgetmaster.database.model.converter;
 
 import de.deadlocker8.budgetmaster.charts.Chart;
+import de.deadlocker8.budgetmaster.charts.ChartDisplayType;
+import de.deadlocker8.budgetmaster.charts.ChartGroupType;
 import de.deadlocker8.budgetmaster.database.model.Converter;
 import de.deadlocker8.budgetmaster.database.model.v5.BackupChart_v5;
 
@@ -19,6 +21,8 @@ public class ChartConverter implements Converter<Chart, BackupChart_v5>
 		chart.setType(backupChart.getType());
 		chart.setVersion(backupChart.getVersion());
 		chart.setScript(backupChart.getScript());
+		chart.setDisplayType(ChartDisplayType.CUSTOM);
+		chart.setGroupType(ChartGroupType.NONE);
 		return chart;
 	}
 
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/IconConverter.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/IconConverter.java
new file mode 100644
index 0000000000000000000000000000000000000000..013fd3a6478a49c5775dd7cc6fbda10843539c2f
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/IconConverter.java
@@ -0,0 +1,62 @@
+package de.deadlocker8.budgetmaster.database.model.converter;
+
+import de.deadlocker8.budgetmaster.database.model.Converter;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupIcon_v7;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.images.Image;
+
+import java.util.List;
+
+public class IconConverter implements Converter<Icon, BackupIcon_v7>
+{
+	private final List<Image> availableImages;
+
+	public IconConverter(List<Image> availableImages)
+	{
+		this.availableImages = availableImages;
+	}
+
+
+	public Icon convertToInternalForm(BackupIcon_v7 backupIcon)
+	{
+		if(backupIcon == null)
+		{
+			return null;
+		}
+
+		final Icon icon = new Icon();
+		icon.setID(backupIcon.getID());
+		icon.setImage(getImageById(backupIcon.getImageID()));
+		icon.setBuiltinIdentifier(backupIcon.getBuiltinIdentifier());
+
+		return icon;
+	}
+
+	private Image getImageById(Integer iconID)
+	{
+		return availableImages.stream()
+				.filter(icon -> icon.getID().equals(iconID))
+				.findFirst().orElse(null);
+	}
+
+	@Override
+	public BackupIcon_v7 convertToExternalForm(Icon internalItem)
+	{
+		if(internalItem == null)
+		{
+			return null;
+		}
+
+		final BackupIcon_v7 icon = new BackupIcon_v7();
+		icon.setID(internalItem.getID());
+
+		if(internalItem.getImage() != null)
+		{
+			icon.setImageID(internalItem.getImage().getID());
+		}
+
+		icon.setBuiltinIdentifier(internalItem.getBuiltinIdentifier());
+
+		return icon;
+	}
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/TemplateConverter.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/TemplateConverter.java
index f1374ae3d7c300ac0dd9e20e66282056662df7b4..2dc16fc3b1e01f31f09094ee5dbaf853552ebcd6 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/TemplateConverter.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/converter/TemplateConverter.java
@@ -4,28 +4,28 @@ import de.deadlocker8.budgetmaster.accounts.Account;
 import de.deadlocker8.budgetmaster.categories.Category;
 import de.deadlocker8.budgetmaster.database.model.Converter;
 import de.deadlocker8.budgetmaster.database.model.v4.BackupTag_v4;
-import de.deadlocker8.budgetmaster.database.model.v6.BackupTemplate_v6;
-import de.deadlocker8.budgetmaster.images.Image;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupTemplate_v7;
+import de.deadlocker8.budgetmaster.icon.Icon;
 import de.deadlocker8.budgetmaster.tags.Tag;
 import de.deadlocker8.budgetmaster.templates.Template;
 
 import java.util.ArrayList;
 import java.util.List;
 
-public class TemplateConverter implements Converter<Template, BackupTemplate_v6>
+public class TemplateConverter implements Converter<Template, BackupTemplate_v7>
 {
-	private final List<Image> availableIcons;
+	private final List<Icon> availableIcons;
 	private final List<Category> availableCategories;
 	private final List<Account> availableAccounts;
 
-	public TemplateConverter(List<Image> availableIcons, List<Category> availableCategories, List<Account> availableAccounts)
+	public TemplateConverter(List<Icon> availableIcons, List<Category> availableCategories, List<Account> availableAccounts)
 	{
 		this.availableIcons = availableIcons;
 		this.availableCategories = availableCategories;
 		this.availableAccounts = availableAccounts;
 	}
 
-	public Template convertToInternalForm(BackupTemplate_v6 backupTemplate)
+	public Template convertToInternalForm(BackupTemplate_v7 backupTemplate)
 	{
 		if(backupTemplate == null)
 		{
@@ -59,19 +59,19 @@ public class TemplateConverter implements Converter<Template, BackupTemplate_v6>
 		template.setTags(convertedTags);
 
 		template.setTemplateName(backupTemplate.getTemplateName());
-		template.setIcon(getItemById(availableIcons, backupTemplate.getIconID()));
+		template.setIconReference(getItemById(availableIcons, backupTemplate.getIconReferenceID()));
 		return template;
 	}
 
 	@Override
-	public BackupTemplate_v6 convertToExternalForm(Template internalItem)
+	public BackupTemplate_v7 convertToExternalForm(Template internalItem)
 	{
 		if(internalItem == null)
 		{
 			return null;
 		}
 
-		final BackupTemplate_v6 template = new BackupTemplate_v6();
+		final BackupTemplate_v7 template = new BackupTemplate_v7();
 		template.setAmount(internalItem.getAmount());
 		template.setName(internalItem.getName());
 
@@ -103,10 +103,12 @@ public class TemplateConverter implements Converter<Template, BackupTemplate_v6>
 
 		template.setTemplateName(internalItem.getTemplateName());
 
-		if(internalItem.getIcon() != null)
+		final Icon icon = internalItem.getIconReference();
+		if(icon != null)
 		{
-			template.setIconID(internalItem.getIcon().getID());
+			template.setIconReferenceID(icon.getID());
 		}
+
 		return template;
 	}
 }
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupAccount_v4.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupAccount_v4.java
index a6c890fb16ed59c26548c51ed63223e5952cf406..3a9201ab34e5378765403de1a67b90bf9dd83293 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupAccount_v4.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupAccount_v4.java
@@ -2,9 +2,11 @@ package de.deadlocker8.budgetmaster.database.model.v4;
 
 import de.deadlocker8.budgetmaster.accounts.AccountState;
 import de.deadlocker8.budgetmaster.accounts.AccountType;
+import de.deadlocker8.budgetmaster.database.model.BackupInfo;
 import de.deadlocker8.budgetmaster.database.model.Upgradeable;
 import de.deadlocker8.budgetmaster.database.model.v5.BackupAccount_v5;
 
+import java.util.List;
 import java.util.Objects;
 
 public class BackupAccount_v4 implements Upgradeable<BackupAccount_v5>
@@ -81,7 +83,8 @@ public class BackupAccount_v4 implements Upgradeable<BackupAccount_v5>
 				'}';
 	}
 
-	public BackupAccount_v5 upgrade()
+	@Override
+	public BackupAccount_v5 upgrade(List<BackupInfo> backupInfoItems)
 	{
 		return new BackupAccount_v5(ID, name, AccountState.FULL_ACCESS, type, null);
 	}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupCategory_v4.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupCategory_v4.java
index deb61fbe872351eb6d1d00e8603ae11937e79873..e276c842a956f92fa3c95c53a79aa9aca9f80966 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupCategory_v4.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupCategory_v4.java
@@ -1,9 +1,11 @@
 package de.deadlocker8.budgetmaster.database.model.v4;
 
 import de.deadlocker8.budgetmaster.categories.CategoryType;
+import de.deadlocker8.budgetmaster.database.model.BackupInfo;
 import de.deadlocker8.budgetmaster.database.model.Upgradeable;
 import de.deadlocker8.budgetmaster.database.model.v5.BackupCategory_v5;
 
+import java.util.List;
 import java.util.Objects;
 
 public class BackupCategory_v4 implements Upgradeable<BackupCategory_v5>
@@ -92,7 +94,8 @@ public class BackupCategory_v4 implements Upgradeable<BackupCategory_v5>
 				'}';
 	}
 
-	public BackupCategory_v5 upgrade()
+	@Override
+	public BackupCategory_v5 upgrade(List<BackupInfo> backupInfoItems)
 	{
 		return new BackupCategory_v5(ID, name, color, type, null);
 	}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupDatabase_v4.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupDatabase_v4.java
index 1e86a765687a1ebcc9266cb47c6d628582651b61..85645d4a55ef131e293c6751240c60ef5ea091fa 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupDatabase_v4.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupDatabase_v4.java
@@ -85,10 +85,10 @@ public class BackupDatabase_v4 implements BackupDatabase
 	{
 		final BackupDatabase_v5 upgradedDatabase = new BackupDatabase_v5();
 
-		upgradedDatabase.setCategories(upgradeItems(categories));
-		upgradedDatabase.setAccounts(upgradeItems(accounts));
-		upgradedDatabase.setTransactions(upgradeItems(transactions));
-		upgradedDatabase.setTemplates(upgradeItems(templates));
+		upgradedDatabase.setCategories(upgradeItems(categories, List.of()));
+		upgradedDatabase.setAccounts(upgradeItems(accounts, List.of()));
+		upgradedDatabase.setTransactions(upgradeItems(transactions, List.of()));
+		upgradedDatabase.setTemplates(upgradeItems(templates, List.of()));
 		upgradedDatabase.setCharts(new ArrayList<>());
 		upgradedDatabase.setImages(new ArrayList<>());
 
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupTemplate_v4.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupTemplate_v4.java
index 75aa699855670a1e2bf8914b6406d27e3348774d..e986f3ca16942cf6e67d4a3901f21c35d795ed40 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupTemplate_v4.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupTemplate_v4.java
@@ -1,10 +1,10 @@
 package de.deadlocker8.budgetmaster.database.model.v4;
 
+import de.deadlocker8.budgetmaster.database.model.BackupInfo;
 import de.deadlocker8.budgetmaster.database.model.Upgradeable;
 import de.deadlocker8.budgetmaster.database.model.v5.BackupAccount_v5;
 import de.deadlocker8.budgetmaster.database.model.v5.BackupCategory_v5;
 import de.deadlocker8.budgetmaster.database.model.v5.BackupTemplate_v5;
-import de.deadlocker8.budgetmaster.tags.Tag;
 
 import java.util.List;
 import java.util.Objects;
@@ -146,24 +146,25 @@ public class BackupTemplate_v4 implements BackupTransactionBase_v4, Upgradeable<
 				'}';
 	}
 
-	public BackupTemplate_v5 upgrade()
+	@Override
+	public BackupTemplate_v5 upgrade(List<BackupInfo> backupInfoItems)
 	{
 		BackupAccount_v5 upgradedAccount = null;
 		if(account != null)
 		{
-			upgradedAccount = account.upgrade();
+			upgradedAccount = account.upgrade(backupInfoItems);
 		}
 
 		BackupCategory_v5 upgradedCategory = null;
 		if(category != null)
 		{
-			upgradedCategory = category.upgrade();
+			upgradedCategory = category.upgrade(backupInfoItems);
 		}
 
 		BackupAccount_v5 upgradedTransferAccount = null;
 		if(transferAccount != null)
 		{
-			upgradedTransferAccount = transferAccount.upgrade();
+			upgradedTransferAccount = transferAccount.upgrade(backupInfoItems);
 		}
 
 		return new BackupTemplate_v5(templateName, amount, isExpenditure, upgradedAccount, upgradedCategory, name, description, null, tags, upgradedTransferAccount);
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupTransaction_v4.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupTransaction_v4.java
index 8d6814c7ca01dbad48f6eb7631d1e0c5077ab22a..a899422199c4d12c60ffccb9e85821f1eccef1c3 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupTransaction_v4.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v4/BackupTransaction_v4.java
@@ -1,10 +1,10 @@
 package de.deadlocker8.budgetmaster.database.model.v4;
 
+import de.deadlocker8.budgetmaster.database.model.BackupInfo;
 import de.deadlocker8.budgetmaster.database.model.Upgradeable;
 import de.deadlocker8.budgetmaster.database.model.v5.BackupAccount_v5;
 import de.deadlocker8.budgetmaster.database.model.v5.BackupCategory_v5;
 import de.deadlocker8.budgetmaster.database.model.v5.BackupTransaction_v5;
-import de.deadlocker8.budgetmaster.tags.Tag;
 
 import java.util.List;
 import java.util.Objects;
@@ -158,15 +158,16 @@ public class BackupTransaction_v4 implements BackupTransactionBase_v4, Upgradeab
 				'}';
 	}
 
-	public BackupTransaction_v5 upgrade()
+	@Override
+	public BackupTransaction_v5 upgrade(List<BackupInfo> backupInfoItems)
 	{
-		BackupAccount_v5 upgradedAccount = account.upgrade();
-		BackupCategory_v5 upgradedCategory = category.upgrade();
+		BackupAccount_v5 upgradedAccount = account.upgrade(backupInfoItems);
+		BackupCategory_v5 upgradedCategory = category.upgrade(backupInfoItems);
 
 		BackupAccount_v5 upgradedTransferAccount = null;
 		if(transferAccount != null)
 		{
-			upgradedTransferAccount = transferAccount.upgrade();
+			upgradedTransferAccount = transferAccount.upgrade(backupInfoItems);
 		}
 
 		return new BackupTransaction_v5(amount, isExpenditure, date, upgradedAccount, upgradedCategory, name, description, tags, repeatingOption, upgradedTransferAccount);
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupAccount_v5.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupAccount_v5.java
index 2e1c80c3869eb6a78afd7069c2e1afad274cfbf6..5bc78eaef0726cbf2641550f4009ee98eaf35e2a 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupAccount_v5.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupAccount_v5.java
@@ -2,9 +2,11 @@ package de.deadlocker8.budgetmaster.database.model.v5;
 
 import de.deadlocker8.budgetmaster.accounts.AccountState;
 import de.deadlocker8.budgetmaster.accounts.AccountType;
+import de.deadlocker8.budgetmaster.database.model.BackupInfo;
 import de.deadlocker8.budgetmaster.database.model.Upgradeable;
 import de.deadlocker8.budgetmaster.database.model.v6.BackupAccount_v6;
 
+import java.util.List;
 import java.util.Objects;
 
 public class BackupAccount_v5 implements Upgradeable<BackupAccount_v6>
@@ -106,7 +108,8 @@ public class BackupAccount_v5 implements Upgradeable<BackupAccount_v6>
 				'}';
 	}
 
-	public BackupAccount_v6 upgrade()
+	@Override
+	public BackupAccount_v6 upgrade(List<BackupInfo> backupInfoItems)
 	{
 		Integer iconID = null;
 		if(icon != null)
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupCategory_v5.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupCategory_v5.java
index 44591eee0af5a1d7f1107c592ed321e70047480d..6a12087c88e17997559a3989124d34e4e9c9cf28 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupCategory_v5.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupCategory_v5.java
@@ -1,10 +1,15 @@
 package de.deadlocker8.budgetmaster.database.model.v5;
 
 import de.deadlocker8.budgetmaster.categories.CategoryType;
+import de.deadlocker8.budgetmaster.database.model.BackupInfo;
+import de.deadlocker8.budgetmaster.database.model.Upgradeable;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupCategory_v7;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupIcon_v7;
 
+import java.util.List;
 import java.util.Objects;
 
-public class BackupCategory_v5
+public class BackupCategory_v5 implements Upgradeable<BackupCategory_v7>
 {
 	private Integer ID;
 	private String name;
@@ -102,4 +107,19 @@ public class BackupCategory_v5
 				", icon='" + icon + '\'' +
 				'}';
 	}
+
+	@Override
+	public BackupCategory_v7 upgrade(List<BackupInfo> backupInfoItems)
+	{
+		Integer iconReferenceID = null;
+		if(icon != null)
+		{
+			BackupIcon_v7 iconReference = new BackupIcon_v7(backupInfoItems.size(), null, icon);
+			backupInfoItems.add(iconReference);
+
+			iconReferenceID = iconReference.getID();
+		}
+
+		return new BackupCategory_v7(ID, name, color, type, iconReferenceID);
+	}
 }
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupDatabase_v5.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupDatabase_v5.java
index e0fccca42657d82b41ef3a868f7db016d7f6afdc..c020ff082aae4989459cbb0517ab7de3dc0a7031 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupDatabase_v5.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupDatabase_v5.java
@@ -114,9 +114,9 @@ public class BackupDatabase_v5 implements BackupDatabase
 		final BackupDatabase_v6 upgradedDatabase = new BackupDatabase_v6();
 
 		upgradedDatabase.setCategories(categories);
-		upgradedDatabase.setAccounts(upgradeItems(accounts));
-		upgradedDatabase.setTransactions(upgradeItems(transactions));
-		upgradedDatabase.setTemplates(upgradeItems(templates));
+		upgradedDatabase.setAccounts(upgradeItems(accounts, List.of()));
+		upgradedDatabase.setTransactions(upgradeItems(transactions, List.of()));
+		upgradedDatabase.setTemplates(upgradeItems(templates, List.of()));
 		upgradedDatabase.setCharts(charts);
 		upgradedDatabase.setImages(images);
 
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupTemplate_v5.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupTemplate_v5.java
index 2b846d174603ec3d11a354b143d22cbf6e915eab..27b72b9270ca99030de2c3403c369bea52dd9f4c 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupTemplate_v5.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupTemplate_v5.java
@@ -1,5 +1,6 @@
 package de.deadlocker8.budgetmaster.database.model.v5;
 
+import de.deadlocker8.budgetmaster.database.model.BackupInfo;
 import de.deadlocker8.budgetmaster.database.model.Upgradeable;
 import de.deadlocker8.budgetmaster.database.model.v4.BackupTag_v4;
 import de.deadlocker8.budgetmaster.database.model.v6.BackupTemplate_v6;
@@ -171,7 +172,7 @@ public class BackupTemplate_v5 implements Upgradeable<BackupTemplate_v6>
 	}
 
 	@Override
-	public BackupTemplate_v6 upgrade()
+	public BackupTemplate_v6 upgrade(List<BackupInfo> backupInfoItems)
 	{
 		Integer accountID = null;
 		if(account != null)
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupTransaction_v5.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupTransaction_v5.java
index d6043623c58871f5697f132754824c6c3fe0bce6..cba4d5d880e0a03545fa7050708257202c1c1169 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupTransaction_v5.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v5/BackupTransaction_v5.java
@@ -1,5 +1,6 @@
 package de.deadlocker8.budgetmaster.database.model.v5;
 
+import de.deadlocker8.budgetmaster.database.model.BackupInfo;
 import de.deadlocker8.budgetmaster.database.model.Upgradeable;
 import de.deadlocker8.budgetmaster.database.model.v4.BackupRepeatingOption_v4;
 import de.deadlocker8.budgetmaster.database.model.v4.BackupTag_v4;
@@ -172,7 +173,7 @@ public class BackupTransaction_v5 implements Upgradeable<BackupTransaction_v6>
 	}
 
 	@Override
-	public BackupTransaction_v6 upgrade()
+	public BackupTransaction_v6 upgrade(List<BackupInfo> backupInfoItems)
 	{
 		Integer transferAccountID = null;
 		if(transferAccount != null)
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v6/BackupAccount_v6.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v6/BackupAccount_v6.java
index 48b47bba4a64336445b1264b7640d5410ed6b45d..c32ec9a5f5582a95480543f1af3512174020e2c5 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/v6/BackupAccount_v6.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v6/BackupAccount_v6.java
@@ -2,10 +2,15 @@ package de.deadlocker8.budgetmaster.database.model.v6;
 
 import de.deadlocker8.budgetmaster.accounts.AccountState;
 import de.deadlocker8.budgetmaster.accounts.AccountType;
+import de.deadlocker8.budgetmaster.database.model.BackupInfo;
+import de.deadlocker8.budgetmaster.database.model.Upgradeable;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupAccount_v7;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupIcon_v7;
 
+import java.util.List;
 import java.util.Objects;
 
-public class BackupAccount_v6
+public class BackupAccount_v6 implements Upgradeable<BackupAccount_v7>
 {
 	private Integer ID;
 	private String name;
@@ -103,4 +108,21 @@ public class BackupAccount_v6
 				", iconID=" + iconID +
 				'}';
 	}
+
+	@Override
+	public BackupAccount_v7 upgrade(List<BackupInfo> backupInfoItems)
+	{
+		Integer iconReferenceID = null;
+		if(iconID != null)
+		{
+			BackupIcon_v7 iconReference = new BackupIcon_v7(backupInfoItems.size(), iconID, null);
+			backupInfoItems.add(iconReference);
+
+			iconReferenceID = iconReference.getID();
+		}
+
+		return new BackupAccount_v7(ID, name, accountState, type, iconReferenceID);
+	}
+
+
 }
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v6/BackupDatabase_v6.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v6/BackupDatabase_v6.java
index 6ce3d66c3e95586528571a8d73ae9c47d0912299..ea7b615d34e09b39cec241cc3c68352d184fbf68 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/v6/BackupDatabase_v6.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v6/BackupDatabase_v6.java
@@ -1,20 +1,18 @@
 package de.deadlocker8.budgetmaster.database.model.v6;
 
-import de.deadlocker8.budgetmaster.accounts.Account;
-import de.deadlocker8.budgetmaster.categories.Category;
-import de.deadlocker8.budgetmaster.charts.Chart;
 import de.deadlocker8.budgetmaster.database.InternalDatabase;
 import de.deadlocker8.budgetmaster.database.JSONIdentifier;
 import de.deadlocker8.budgetmaster.database.model.BackupDatabase;
-import de.deadlocker8.budgetmaster.database.model.converter.*;
+import de.deadlocker8.budgetmaster.database.model.BackupInfo;
 import de.deadlocker8.budgetmaster.database.model.v5.BackupCategory_v5;
 import de.deadlocker8.budgetmaster.database.model.v5.BackupChart_v5;
 import de.deadlocker8.budgetmaster.database.model.v5.BackupImage_v5;
-import de.deadlocker8.budgetmaster.images.Image;
-import de.deadlocker8.budgetmaster.templates.Template;
-import de.deadlocker8.budgetmaster.transactions.Transaction;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupDatabase_v7;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupIcon_v7;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
 public class BackupDatabase_v6 implements BackupDatabase
 {
@@ -108,14 +106,7 @@ public class BackupDatabase_v6 implements BackupDatabase
 
 	public InternalDatabase convertToInternal()
 	{
-		final List<Image> convertedImages = convertItemsToInternal(this.images, new ImageConverter());
-		final List<Category> convertedCategories = convertItemsToInternal(categories, new CategoryConverter());
-		final List<Account> convertedAccounts = convertItemsToInternal(accounts, new AccountConverter(convertedImages));
-		final List<Transaction> convertedTransactions = convertItemsToInternal(this.transactions, new TransactionConverter(convertedCategories, convertedAccounts));
-		final List<Template> convertedTemplates = convertItemsToInternal(this.templates, new TemplateConverter(convertedImages, convertedCategories, convertedAccounts));
-		final List<Chart> convertedCharts = convertItemsToInternal(this.charts, new ChartConverter());
-
-		return new InternalDatabase(convertedCategories, convertedAccounts, convertedTransactions, convertedTemplates, convertedCharts, convertedImages);
+		throw new UnsupportedOperationException();
 	}
 
 	@Override
@@ -127,20 +118,22 @@ public class BackupDatabase_v6 implements BackupDatabase
 	@Override
 	public BackupDatabase upgrade()
 	{
-		throw new UnsupportedOperationException();
-	}
+		final BackupDatabase_v7 upgradedDatabase = new BackupDatabase_v7();
 
-	public static BackupDatabase_v6 createFromInternalEntities(InternalDatabase database)
-	{
-		final BackupDatabase_v6 externalDatabase = new BackupDatabase_v6();
+		final List<BackupInfo> newIcons = new ArrayList<>();
+
+		upgradedDatabase.setCategories(upgradeItems(categories, newIcons));
+		upgradedDatabase.setAccounts(upgradeItems(accounts, newIcons));
+		upgradedDatabase.setTransactions(transactions);
+		upgradedDatabase.setTemplates(upgradeItems(templates, newIcons));
+		upgradedDatabase.setCharts(charts);
+		upgradedDatabase.setImages(images);
 
-		externalDatabase.setCategories(externalDatabase.convertItemsToExternal(database.getCategories(), new CategoryConverter()));
-		externalDatabase.setAccounts(externalDatabase.convertItemsToExternal(database.getAccounts(), new AccountConverter(null)));
-		externalDatabase.setTransactions(externalDatabase.convertItemsToExternal(database.getTransactions(), new TransactionConverter(null, null)));
-		externalDatabase.setTemplates(externalDatabase.convertItemsToExternal(database.getTemplates(), new TemplateConverter(null, null, null)));
-		externalDatabase.setCharts(externalDatabase.convertItemsToExternal(database.getCharts(), new ChartConverter()));
-		externalDatabase.setImages(externalDatabase.convertItemsToExternal(database.getImages(), new ImageConverter()));
+		List<BackupIcon_v7> castedIcons = newIcons.stream()
+				.map(BackupIcon_v7.class::cast)
+				.collect(Collectors.toList());
+		upgradedDatabase.setIcons(castedIcons);
 
-		return externalDatabase;
+		return upgradedDatabase;
 	}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v6/BackupTemplate_v6.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v6/BackupTemplate_v6.java
index d36a35ab8107e7edead5afbd6f8ba81833ad99aa..932362f8b2454900ad2afcad49cf59308b1bd79e 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/database/model/v6/BackupTemplate_v6.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v6/BackupTemplate_v6.java
@@ -1,11 +1,15 @@
 package de.deadlocker8.budgetmaster.database.model.v6;
 
+import de.deadlocker8.budgetmaster.database.model.BackupInfo;
+import de.deadlocker8.budgetmaster.database.model.Upgradeable;
 import de.deadlocker8.budgetmaster.database.model.v4.BackupTag_v4;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupIcon_v7;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupTemplate_v7;
 
 import java.util.List;
 import java.util.Objects;
 
-public class BackupTemplate_v6
+public class BackupTemplate_v6 implements Upgradeable<BackupTemplate_v7>
 {
 	private String templateName;
 	private Integer amount;
@@ -167,4 +171,19 @@ public class BackupTemplate_v6
 				", transferAccountID=" + transferAccountID +
 				'}';
 	}
+
+	@Override
+	public BackupTemplate_v7 upgrade(List<BackupInfo> backupInfoItems)
+	{
+		Integer iconReferenceID = null;
+		if(iconID != null)
+		{
+			BackupIcon_v7 iconReference = new BackupIcon_v7(backupInfoItems.size(), iconID, null);
+			backupInfoItems.add(iconReference);
+
+			iconReferenceID = iconReference.getID();
+		}
+
+		return new BackupTemplate_v7(templateName, amount, isExpenditure, accountID, categoryID, name, description, iconReferenceID, tags, transferAccountID);
+	}
 }
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupAccount_v7.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupAccount_v7.java
new file mode 100644
index 0000000000000000000000000000000000000000..89880d3636799f7021f2648b9df3f4334117eabd
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupAccount_v7.java
@@ -0,0 +1,106 @@
+package de.deadlocker8.budgetmaster.database.model.v7;
+
+import de.deadlocker8.budgetmaster.accounts.AccountState;
+import de.deadlocker8.budgetmaster.accounts.AccountType;
+
+import java.util.Objects;
+
+public class BackupAccount_v7
+{
+	private Integer ID;
+	private String name;
+	private AccountState accountState;
+	private AccountType type;
+	private Integer iconReferenceID;
+
+	public BackupAccount_v7()
+	{
+		// for GSON
+	}
+
+	public BackupAccount_v7(Integer ID, String name, AccountState accountState, AccountType type, Integer iconReferenceID)
+	{
+		this.ID = ID;
+		this.name = name;
+		this.accountState = accountState;
+		this.type = type;
+		this.iconReferenceID = iconReferenceID;
+	}
+
+	public Integer getID()
+	{
+		return ID;
+	}
+
+	public void setID(Integer ID)
+	{
+		this.ID = ID;
+	}
+
+	public String getName()
+	{
+		return name;
+	}
+
+	public void setName(String name)
+	{
+		this.name = name;
+	}
+
+	public AccountState getAccountState()
+	{
+		return accountState;
+	}
+
+	public void setAccountState(AccountState accountState)
+	{
+		this.accountState = accountState;
+	}
+
+	public AccountType getType()
+	{
+		return type;
+	}
+
+	public void setType(AccountType type)
+	{
+		this.type = type;
+	}
+
+	public Integer getIconReferenceID()
+	{
+		return iconReferenceID;
+	}
+
+	public void setIconReferenceID(Integer iconReferenceID)
+	{
+		this.iconReferenceID = iconReferenceID;
+	}
+
+	@Override
+	public boolean equals(Object o)
+	{
+		if(this == o) return true;
+		if(o == null || getClass() != o.getClass()) return false;
+		BackupAccount_v7 that = (BackupAccount_v7) o;
+		return Objects.equals(ID, that.ID) && Objects.equals(name, that.name) && accountState == that.accountState && type == that.type && Objects.equals(iconReferenceID, that.iconReferenceID);
+	}
+
+	@Override
+	public int hashCode()
+	{
+		return Objects.hash(ID, name, accountState, type, iconReferenceID);
+	}
+
+	@Override
+	public String toString()
+	{
+		return "BackupAccount_v7{" +
+				"ID=" + ID +
+				", name='" + name + '\'' +
+				", accountState=" + accountState +
+				", type=" + type +
+				", iconReferenceID=" + iconReferenceID +
+				'}';
+	}
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupCategory_v7.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupCategory_v7.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd036b5a1f630f16a31da95c0b500d7eb9396197
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupCategory_v7.java
@@ -0,0 +1,105 @@
+package de.deadlocker8.budgetmaster.database.model.v7;
+
+import de.deadlocker8.budgetmaster.categories.CategoryType;
+
+import java.util.Objects;
+
+public class BackupCategory_v7
+{
+	private Integer ID;
+	private String name;
+	private String color;
+	private CategoryType type;
+	private Integer iconReferenceID;
+
+	public BackupCategory_v7()
+	{
+		// for GSON
+	}
+
+	public BackupCategory_v7(Integer ID, String name, String color, CategoryType type, Integer iconReferenceID)
+	{
+		this.ID = ID;
+		this.name = name;
+		this.color = color;
+		this.type = type;
+		this.iconReferenceID = iconReferenceID;
+	}
+
+	public Integer getID()
+	{
+		return ID;
+	}
+
+	public void setID(Integer ID)
+	{
+		this.ID = ID;
+	}
+
+	public String getName()
+	{
+		return name;
+	}
+
+	public void setName(String name)
+	{
+		this.name = name;
+	}
+
+	public String getColor()
+	{
+		return color;
+	}
+
+	public void setColor(String color)
+	{
+		this.color = color;
+	}
+
+	public CategoryType getType()
+	{
+		return type;
+	}
+
+	public void setType(CategoryType type)
+	{
+		this.type = type;
+	}
+
+	public Integer getIconReferenceID()
+	{
+		return iconReferenceID;
+	}
+
+	public void setIconReferenceID(Integer iconReferenceID)
+	{
+		this.iconReferenceID = iconReferenceID;
+	}
+
+	@Override
+	public boolean equals(Object o)
+	{
+		if(this == o) return true;
+		if(o == null || getClass() != o.getClass()) return false;
+		BackupCategory_v7 that = (BackupCategory_v7) o;
+		return Objects.equals(ID, that.ID) && Objects.equals(name, that.name) && Objects.equals(color, that.color) && type == that.type && Objects.equals(iconReferenceID, that.iconReferenceID);
+	}
+
+	@Override
+	public int hashCode()
+	{
+		return Objects.hash(ID, name, color, type, iconReferenceID);
+	}
+
+	@Override
+	public String toString()
+	{
+		return "BackupCategory_v7{" +
+				"ID=" + ID +
+				", name='" + name + '\'' +
+				", color='" + color + '\'' +
+				", type=" + type +
+				", iconReferenceID='" + iconReferenceID + '\'' +
+				'}';
+	}
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupDatabase_v7.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupDatabase_v7.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c33e0e9af14712f0d89e2d2c8c09b7e1326186c
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupDatabase_v7.java
@@ -0,0 +1,161 @@
+package de.deadlocker8.budgetmaster.database.model.v7;
+
+import de.deadlocker8.budgetmaster.accounts.Account;
+import de.deadlocker8.budgetmaster.categories.Category;
+import de.deadlocker8.budgetmaster.charts.Chart;
+import de.deadlocker8.budgetmaster.database.InternalDatabase;
+import de.deadlocker8.budgetmaster.database.JSONIdentifier;
+import de.deadlocker8.budgetmaster.database.model.BackupDatabase;
+import de.deadlocker8.budgetmaster.database.model.converter.*;
+import de.deadlocker8.budgetmaster.database.model.v5.BackupChart_v5;
+import de.deadlocker8.budgetmaster.database.model.v5.BackupImage_v5;
+import de.deadlocker8.budgetmaster.database.model.v6.BackupTransaction_v6;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.images.Image;
+import de.deadlocker8.budgetmaster.templates.Template;
+import de.deadlocker8.budgetmaster.transactions.Transaction;
+
+import java.util.List;
+
+public class BackupDatabase_v7 implements BackupDatabase
+{
+	@SuppressWarnings("unused")
+	private final String TYPE = JSONIdentifier.BUDGETMASTER_DATABASE.toString();
+
+	@SuppressWarnings("FieldCanBeLocal")
+	private final int VERSION = 7;
+
+	private List<BackupCategory_v7> categories;
+	private List<BackupAccount_v7> accounts;
+	private List<BackupTransaction_v6> transactions;
+	private List<BackupTemplate_v7> templates;
+	private List<BackupChart_v5> charts;
+	private List<BackupImage_v5> images;
+	private List<BackupIcon_v7> icons;
+
+	public BackupDatabase_v7()
+	{
+		// for GSON
+	}
+
+	public BackupDatabase_v7(List<BackupCategory_v7> categories, List<BackupAccount_v7> accounts, List<BackupTransaction_v6> transactions, List<BackupTemplate_v7> templates, List<BackupChart_v5> charts, List<BackupImage_v5> images, List<BackupIcon_v7> icons)
+	{
+		this.categories = categories;
+		this.accounts = accounts;
+		this.transactions = transactions;
+		this.templates = templates;
+		this.charts = charts;
+		this.images = images;
+		this.icons = icons;
+	}
+
+	public List<BackupCategory_v7> getCategories()
+	{
+		return categories;
+	}
+
+	public void setCategories(List<BackupCategory_v7> categories)
+	{
+		this.categories = categories;
+	}
+
+	public List<BackupAccount_v7> getAccounts()
+	{
+		return accounts;
+	}
+
+	public void setAccounts(List<BackupAccount_v7> accounts)
+	{
+		this.accounts = accounts;
+	}
+
+	public List<BackupTransaction_v6> getTransactions()
+	{
+		return transactions;
+	}
+
+	public void setTransactions(List<BackupTransaction_v6> transactions)
+	{
+		this.transactions = transactions;
+	}
+
+	public List<BackupTemplate_v7> getTemplates()
+	{
+		return templates;
+	}
+
+	public void setTemplates(List<BackupTemplate_v7> templates)
+	{
+		this.templates = templates;
+	}
+
+	public List<BackupChart_v5> getCharts()
+	{
+		return charts;
+	}
+
+	public void setCharts(List<BackupChart_v5> charts)
+	{
+		this.charts = charts;
+	}
+
+	public List<BackupImage_v5> getImages()
+	{
+		return images;
+	}
+
+	public void setImages(List<BackupImage_v5> images)
+	{
+		this.images = images;
+	}
+
+	public List<BackupIcon_v7> getIcons()
+	{
+		return icons;
+	}
+
+	public void setIcons(List<BackupIcon_v7> icons)
+	{
+		this.icons = icons;
+	}
+
+	public InternalDatabase convertToInternal()
+	{
+		final List<Image> convertedImages = convertItemsToInternal(this.images, new ImageConverter());
+		final List<Icon> convertedIcons = convertItemsToInternal(this.icons, new IconConverter(convertedImages));
+		final List<Category> convertedCategories = convertItemsToInternal(categories, new CategoryConverter(convertedIcons));
+		final List<Account> convertedAccounts = convertItemsToInternal(accounts, new AccountConverter(convertedIcons));
+		final List<Transaction> convertedTransactions = convertItemsToInternal(this.transactions, new TransactionConverter(convertedCategories, convertedAccounts));
+		final List<Template> convertedTemplates = convertItemsToInternal(this.templates, new TemplateConverter(convertedIcons, convertedCategories, convertedAccounts));
+		final List<Chart> convertedCharts = convertItemsToInternal(this.charts, new ChartConverter());
+
+		return new InternalDatabase(convertedCategories, convertedAccounts, convertedTransactions, convertedTemplates, convertedCharts, convertedImages, convertedIcons);
+	}
+
+	@Override
+	public int getVersion()
+	{
+		return VERSION;
+	}
+
+	@Override
+	public BackupDatabase upgrade()
+	{
+		throw new UnsupportedOperationException();
+	}
+
+	public static BackupDatabase_v7 createFromInternalEntities(InternalDatabase database)
+	{
+		final BackupDatabase_v7 externalDatabase = new BackupDatabase_v7();
+
+		externalDatabase.setIcons(externalDatabase.convertItemsToExternal(database.getIcons(), new IconConverter(null)));
+		externalDatabase.setCategories(externalDatabase.convertItemsToExternal(database.getCategories(), new CategoryConverter(null)));
+		externalDatabase.setAccounts(externalDatabase.convertItemsToExternal(database.getAccounts(), new AccountConverter(null)));
+		externalDatabase.setTransactions(externalDatabase.convertItemsToExternal(database.getTransactions(), new TransactionConverter(null, null)));
+		externalDatabase.setTemplates(externalDatabase.convertItemsToExternal(database.getTemplates(), new TemplateConverter(null, null, null)));
+		externalDatabase.setCharts(externalDatabase.convertItemsToExternal(database.getCharts(), new ChartConverter()));
+		externalDatabase.setImages(externalDatabase.convertItemsToExternal(database.getImages(), new ImageConverter()));
+
+		return externalDatabase;
+	}
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupIcon_v7.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupIcon_v7.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed7c5e88ed3e2969d6f16c7e31d9f205d256a29f
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupIcon_v7.java
@@ -0,0 +1,79 @@
+package de.deadlocker8.budgetmaster.database.model.v7;
+
+import de.deadlocker8.budgetmaster.database.model.BackupInfo;
+
+import java.util.Objects;
+
+public class BackupIcon_v7 implements BackupInfo
+{
+	private Integer ID;
+	private Integer imageID;
+	private String builtinIdentifier;
+
+	public BackupIcon_v7()
+	{
+		// for GSON
+	}
+
+	public BackupIcon_v7(Integer ID, Integer imageID, String builtinIdentifier)
+	{
+		this.ID = ID;
+		this.imageID = imageID;
+		this.builtinIdentifier = builtinIdentifier;
+	}
+
+	public Integer getID()
+	{
+		return ID;
+	}
+
+	public void setID(Integer ID)
+	{
+		this.ID = ID;
+	}
+
+	public Integer getImageID()
+	{
+		return imageID;
+	}
+
+	public void setImageID(Integer imageID)
+	{
+		this.imageID = imageID;
+	}
+
+	public String getBuiltinIdentifier()
+	{
+		return builtinIdentifier;
+	}
+
+	public void setBuiltinIdentifier(String builtinIdentifier)
+	{
+		this.builtinIdentifier = builtinIdentifier;
+	}
+
+	@Override
+	public boolean equals(Object o)
+	{
+		if(this == o) return true;
+		if(o == null || getClass() != o.getClass()) return false;
+		BackupIcon_v7 that = (BackupIcon_v7) o;
+		return Objects.equals(ID, that.ID) && Objects.equals(imageID, that.imageID) && Objects.equals(builtinIdentifier, that.builtinIdentifier);
+	}
+
+	@Override
+	public int hashCode()
+	{
+		return Objects.hash(ID, imageID, builtinIdentifier);
+	}
+
+	@Override
+	public String toString()
+	{
+		return "BackupIcon_v7{" +
+				"ID=" + ID +
+				", imageID=" + imageID +
+				", builtinIdentifier='" + builtinIdentifier + '\'' +
+				'}';
+	}
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupTemplate_v7.java b/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupTemplate_v7.java
new file mode 100644
index 0000000000000000000000000000000000000000..0353f580ec670831a4f1df048b0fc4031c005c70
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/database/model/v7/BackupTemplate_v7.java
@@ -0,0 +1,170 @@
+package de.deadlocker8.budgetmaster.database.model.v7;
+
+import de.deadlocker8.budgetmaster.database.model.v4.BackupTag_v4;
+
+import java.util.List;
+import java.util.Objects;
+
+public class BackupTemplate_v7
+{
+	private String templateName;
+	private Integer amount;
+	private Boolean isExpenditure;
+	private Integer accountID;
+	private Integer categoryID;
+	private String name;
+	private String description;
+	private Integer iconReferenceID;
+	private List<BackupTag_v4> tags;
+	private Integer transferAccountID;
+
+	public BackupTemplate_v7()
+	{
+		// for GSON
+	}
+
+	public BackupTemplate_v7(String templateName, Integer amount, Boolean isExpenditure, Integer accountID, Integer categoryID, String name, String description, Integer iconReferenceID, List<BackupTag_v4> tags, Integer transferAccountID)
+	{
+		this.templateName = templateName;
+		this.amount = amount;
+		this.isExpenditure = isExpenditure;
+		this.accountID = accountID;
+		this.categoryID = categoryID;
+		this.name = name;
+		this.description = description;
+		this.iconReferenceID = iconReferenceID;
+		this.tags = tags;
+		this.transferAccountID = transferAccountID;
+	}
+
+	public String getTemplateName()
+	{
+		return templateName;
+	}
+
+	public void setTemplateName(String templateName)
+	{
+		this.templateName = templateName;
+	}
+
+	public Integer getAmount()
+	{
+		return amount;
+	}
+
+	public void setAmount(Integer amount)
+	{
+		this.amount = amount;
+	}
+
+	public Boolean getExpenditure()
+	{
+		return isExpenditure;
+	}
+
+	public void setExpenditure(Boolean expenditure)
+	{
+		isExpenditure = expenditure;
+	}
+
+	public Integer getAccountID()
+	{
+		return accountID;
+	}
+
+	public void setAccountID(Integer accountID)
+	{
+		this.accountID = accountID;
+	}
+
+	public Integer getCategoryID()
+	{
+		return categoryID;
+	}
+
+	public void setCategoryID(Integer categoryID)
+	{
+		this.categoryID = categoryID;
+	}
+
+	public String getName()
+	{
+		return name;
+	}
+
+	public void setName(String name)
+	{
+		this.name = name;
+	}
+
+	public String getDescription()
+	{
+		return description;
+	}
+
+	public void setDescription(String description)
+	{
+		this.description = description;
+	}
+
+	public Integer getIconReferenceID()
+	{
+		return iconReferenceID;
+	}
+
+	public void setIconReferenceID(Integer iconReferenceID)
+	{
+		this.iconReferenceID = iconReferenceID;
+	}
+
+	public List<BackupTag_v4> getTags()
+	{
+		return tags;
+	}
+
+	public void setTags(List<BackupTag_v4> tags)
+	{
+		this.tags = tags;
+	}
+
+	public Integer getTransferAccountID()
+	{
+		return transferAccountID;
+	}
+
+	public void setTransferAccountID(Integer transferAccountID)
+	{
+		this.transferAccountID = transferAccountID;
+	}
+
+	@Override
+	public boolean equals(Object o)
+	{
+		if(this == o) return true;
+		if(o == null || getClass() != o.getClass()) return false;
+		BackupTemplate_v7 that = (BackupTemplate_v7) o;
+		return Objects.equals(templateName, that.templateName) && Objects.equals(amount, that.amount) && Objects.equals(isExpenditure, that.isExpenditure) && Objects.equals(accountID, that.accountID) && Objects.equals(categoryID, that.categoryID) && Objects.equals(name, that.name) && Objects.equals(description, that.description) && Objects.equals(iconReferenceID, that.iconReferenceID) && Objects.equals(tags, that.tags) && Objects.equals(transferAccountID, that.transferAccountID);
+	}
+
+	@Override
+	public int hashCode()
+	{
+		return Objects.hash(templateName, amount, isExpenditure, accountID, categoryID, name, description, iconReferenceID, tags, transferAccountID);
+	}
+
+	@Override
+	public String toString()
+	{
+		return "BackupTemplate_v7{templateName='" + templateName + '\'' +
+				", amount=" + amount +
+				", isExpenditure=" + isExpenditure +
+				", accountID=" + accountID +
+				", categoryID=" + categoryID +
+				", name='" + name + '\'' +
+				", description='" + description + '\'' +
+				", iconReferenceID=" + iconReferenceID +
+				", tags=" + tags +
+				", transferAccountID=" + transferAccountID +
+				'}';
+	}
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/hints/Hint.java b/src/main/java/de/deadlocker8/budgetmaster/hints/Hint.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3226b51d7da02174e0360e79ce8ff732341fd5d
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/hints/Hint.java
@@ -0,0 +1,67 @@
+package de.deadlocker8.budgetmaster.hints;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Hint
+{
+	@Id
+	@GeneratedValue(strategy = GenerationType.IDENTITY)
+	private int ID;
+
+	private String localizationKey;
+	private boolean isDismissed;
+
+	public Hint(String localizationKey, boolean isDismissed)
+	{
+		this.localizationKey = localizationKey;
+		this.isDismissed = isDismissed;
+	}
+
+	public Hint()
+	{
+	}
+
+	public int getID()
+	{
+		return ID;
+	}
+
+	public void setID(int ID)
+	{
+		this.ID = ID;
+	}
+
+	public String getLocalizationKey()
+	{
+		return localizationKey;
+	}
+
+	public void setLocalizationKey(String localizationKey)
+	{
+		this.localizationKey = localizationKey;
+	}
+
+	public boolean isDismissed()
+	{
+		return isDismissed;
+	}
+
+	public void setDismissed(boolean dismissed)
+	{
+		isDismissed = dismissed;
+	}
+
+	@Override
+	public String toString()
+	{
+		return "Hint{" +
+				"ID=" + ID +
+				", localizationKey='" + localizationKey + '\'' +
+				", isDismissed=" + isDismissed +
+				'}';
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/de/deadlocker8/budgetmaster/hints/HintController.java b/src/main/java/de/deadlocker8/budgetmaster/hints/HintController.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6f0863cff2d1e15ef8eaf7e014ddccefe1a85d8
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/hints/HintController.java
@@ -0,0 +1,45 @@
+package de.deadlocker8.budgetmaster.hints;
+
+import de.deadlocker8.budgetmaster.controller.BaseController;
+import de.deadlocker8.budgetmaster.utils.Mappings;
+import de.deadlocker8.budgetmaster.utils.WebRequestUtils;
+import de.deadlocker8.budgetmaster.utils.notification.Notification;
+import de.deadlocker8.budgetmaster.utils.notification.NotificationType;
+import de.thecodelabs.utils.util.Localization;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.context.request.WebRequest;
+
+
+@Controller
+@RequestMapping(Mappings.HINTS)
+public class HintController extends BaseController
+{
+	private final HintService hintService;
+
+	@Autowired
+	public HintController(HintService hintService)
+	{
+		this.hintService = hintService;
+	}
+
+	@RequestMapping("/dismiss/{ID}")
+	@ResponseStatus(value = HttpStatus.OK)
+	public void dismissHint(@PathVariable("ID") Integer ID)
+	{
+		hintService.dismiss(ID);
+	}
+
+	@RequestMapping("/resetAll")
+	public String resetAll(WebRequest request)
+	{
+		hintService.resetAll();
+		
+		WebRequestUtils.putNotification(request, new Notification(Localization.getString("notification.hints.reset"), NotificationType.SUCCESS));
+		return "redirect:/settings";
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/de/deadlocker8/budgetmaster/hints/HintRepository.java b/src/main/java/de/deadlocker8/budgetmaster/hints/HintRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf815d90355fbfa82b884bd6a02a52c0143ec3a8
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/hints/HintRepository.java
@@ -0,0 +1,9 @@
+package de.deadlocker8.budgetmaster.hints;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+
+public interface HintRepository extends JpaRepository<Hint, Integer>
+{
+	Hint findByLocalizationKey(String localizationKey);
+}
\ No newline at end of file
diff --git a/src/main/java/de/deadlocker8/budgetmaster/hints/HintService.java b/src/main/java/de/deadlocker8/budgetmaster/hints/HintService.java
new file mode 100644
index 0000000000000000000000000000000000000000..e96ee9a655fe522578bc45281cb2f3d83ccf7e36
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/hints/HintService.java
@@ -0,0 +1,73 @@
+package de.deadlocker8.budgetmaster.hints;
+
+import de.deadlocker8.budgetmaster.services.Resettable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Service
+public class HintService implements Resettable
+{
+	private static final Logger LOGGER = LoggerFactory.getLogger(HintService.class);
+
+	private final HintRepository hintRepository;
+
+	@Autowired
+	public HintService(HintRepository hintRepository)
+	{
+		this.hintRepository = hintRepository;
+
+		createDefaults();
+	}
+
+	public Hint findByLocalizationKey(String localizationKey)
+	{
+		return hintRepository.findByLocalizationKey(localizationKey);
+	}
+
+	@Transactional
+	public void dismiss(Integer ID)
+	{
+		final Hint hint = hintRepository.findById(ID).orElseThrow();
+		hint.setDismissed(true);
+	}
+
+	@Transactional
+	public void resetAll()
+	{
+		for(Hint hint : hintRepository.findAll())
+		{
+			hint.setDismissed(false);
+		}
+	}
+
+	@Override
+	public void deleteAll()
+	{
+		// deletion of hints is never needed
+	}
+
+	@Override
+	public void createDefaults()
+	{
+		final List<String> hintKeys = List.of("hint.first.use.teaser",
+				"hint.report.columns",
+				"hint.template.arrow.keys",
+				"hint.transaction.save",
+				"hint.globalDatePicker.hotkeys",
+				"hint.icon.upload.image.size");
+
+		for(String localizationKey : hintKeys)
+		{
+			final Hint existingHint = hintRepository.findByLocalizationKey(localizationKey);
+			if(existingHint == null)
+			{
+				hintRepository.save(new Hint(localizationKey, false));
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/de/deadlocker8/budgetmaster/icon/Icon.java b/src/main/java/de/deadlocker8/budgetmaster/icon/Icon.java
new file mode 100644
index 0000000000000000000000000000000000000000..8308304f1b94e33bd561c14c75de9ff2339683ea
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/icon/Icon.java
@@ -0,0 +1,125 @@
+package de.deadlocker8.budgetmaster.icon;
+
+import com.google.gson.annotations.Expose;
+import de.deadlocker8.budgetmaster.accounts.Account;
+import de.deadlocker8.budgetmaster.categories.Category;
+import de.deadlocker8.budgetmaster.images.Image;
+import de.deadlocker8.budgetmaster.templates.Template;
+import de.deadlocker8.budgetmaster.utils.ProvidesID;
+
+import javax.persistence.*;
+import java.util.Objects;
+
+@Entity
+public class Icon implements ProvidesID
+{
+	@Id
+	@GeneratedValue(strategy = GenerationType.IDENTITY)
+	@Expose
+	private Integer ID;
+
+	@ManyToOne(fetch = FetchType.LAZY)
+	@Expose
+	private Image image;
+
+	@Expose
+	private String builtinIdentifier;
+
+	@OneToOne(mappedBy = "iconReference", fetch = FetchType.LAZY)
+	private Account referringAccount;
+
+	@OneToOne(mappedBy = "iconReference", fetch = FetchType.LAZY)
+	private Template referringTemplate;
+
+	@OneToOne(mappedBy = "iconReference", fetch = FetchType.LAZY)
+	private Category referringCategory;
+
+	public Icon()
+	{
+	}
+
+	public Icon(Image image)
+	{
+		this.image = image;
+	}
+
+	public Icon(String builtinIdentifier)
+	{
+		this.builtinIdentifier = builtinIdentifier;
+	}
+
+	public Integer getID()
+	{
+		return ID;
+	}
+
+	public void setID(Integer ID)
+	{
+		this.ID = ID;
+	}
+
+	public Image getImage()
+	{
+		return image;
+	}
+
+	public void setImage(Image image)
+	{
+		this.image = image;
+	}
+
+	public String getBuiltinIdentifier()
+	{
+		return builtinIdentifier;
+	}
+
+	public void setBuiltinIdentifier(String builtinIdentifier)
+	{
+		this.builtinIdentifier = builtinIdentifier;
+	}
+
+	public boolean isBuiltinIcon()
+	{
+		return image == null;
+	}
+
+	public Account getReferringAccount()
+	{
+		return referringAccount;
+	}
+
+	public Template getReferringTemplate()
+	{
+		return referringTemplate;
+	}
+
+	public Category getReferringCategory()
+	{
+		return referringCategory;
+	}
+
+	@Override
+	public boolean equals(Object o)
+	{
+		if(this == o) return true;
+		if(o == null || getClass() != o.getClass()) return false;
+		Icon icon = (Icon) o;
+		return Objects.equals(ID, icon.ID) && Objects.equals(image, icon.image) && Objects.equals(builtinIdentifier, icon.builtinIdentifier);
+	}
+
+	@Override
+	public int hashCode()
+	{
+		return Objects.hash(ID, image, builtinIdentifier);
+	}
+
+	@Override
+	public String toString()
+	{
+		return "Icon{" +
+				"ID=" + ID +
+				", image=" + image +
+				", builtinIdentifier='" + builtinIdentifier + '\'' +
+				'}';
+	}
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/icon/IconRepository.java b/src/main/java/de/deadlocker8/budgetmaster/icon/IconRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..e12e3eba35faff43fa0592605e8c1b4a64af4758
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/icon/IconRepository.java
@@ -0,0 +1,8 @@
+package de.deadlocker8.budgetmaster.icon;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+
+public interface IconRepository extends JpaRepository<Icon, Integer>
+{
+}
\ No newline at end of file
diff --git a/src/main/java/de/deadlocker8/budgetmaster/icon/IconService.java b/src/main/java/de/deadlocker8/budgetmaster/icon/IconService.java
new file mode 100644
index 0000000000000000000000000000000000000000..63fdda4cd22cc9dc2be3ea53a42314ccfcce4d6e
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/icon/IconService.java
@@ -0,0 +1,102 @@
+package de.deadlocker8.budgetmaster.icon;
+
+import de.deadlocker8.budgetmaster.accounts.Account;
+import de.deadlocker8.budgetmaster.categories.Category;
+import de.deadlocker8.budgetmaster.images.Image;
+import de.deadlocker8.budgetmaster.images.ImageRepository;
+import de.deadlocker8.budgetmaster.services.Resettable;
+import de.deadlocker8.budgetmaster.templates.Template;
+import de.deadlocker8.budgetmaster.utils.ResourceNotFoundException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public class IconService implements Resettable
+{
+	private final IconRepository iconRepository;
+	private final ImageRepository imageRepository;
+
+	@Autowired
+	public IconService(IconRepository iconRepository, ImageRepository imageRepository)
+	{
+		this.iconRepository = iconRepository;
+		this.imageRepository = imageRepository;
+	}
+
+	public IconRepository getRepository()
+	{
+		return iconRepository;
+	}
+
+	@Override
+	@Transactional
+	public void deleteAll()
+	{
+		final List<Icon> icons = iconRepository.findAll();
+		for(Icon icon : icons)
+		{
+			deleteIcon(icon);
+		}
+
+		iconRepository.deleteAll();
+	}
+
+	@Transactional
+	public void deleteIcon(Icon icon)
+	{
+		if(icon == null)
+		{
+			return;
+		}
+
+		Account referringAccount = icon.getReferringAccount();
+		if(referringAccount != null)
+		{
+			referringAccount.setIconReference(null);
+		}
+
+		Template referringTemplate = icon.getReferringTemplate();
+		if(referringTemplate != null)
+		{
+			referringTemplate.setIconReference(null);
+		}
+
+		Category referringCategory = icon.getReferringCategory();
+		if(referringCategory != null)
+		{
+			referringCategory.setIconReference(null);
+		}
+
+		getRepository().delete(icon);
+	}
+
+	@Override
+	public void createDefaults()
+	{
+	}
+
+	public Optional<Icon> createIconReference(Integer iconImageID, String builtinIconIdentifier)
+	{
+		if(iconImageID != null)
+		{
+			final Optional<Image> imageByIdOptional = imageRepository.findById(iconImageID);
+			if(imageByIdOptional.isEmpty())
+			{
+				throw new ResourceNotFoundException();
+			}
+
+			return Optional.of(new Icon(imageByIdOptional.get()));
+		}
+
+		if(builtinIconIdentifier != null && !builtinIconIdentifier.isEmpty())
+		{
+			return Optional.of(new Icon(builtinIconIdentifier));
+		}
+
+		return Optional.empty();
+	}
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/icon/Iconizable.java b/src/main/java/de/deadlocker8/budgetmaster/icon/Iconizable.java
new file mode 100644
index 0000000000000000000000000000000000000000..76f5c9ede9b654191dafd01afa796d3152b950e7
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/icon/Iconizable.java
@@ -0,0 +1,40 @@
+package de.deadlocker8.budgetmaster.icon;
+
+import de.deadlocker8.budgetmaster.services.AccessEntityByID;
+import de.deadlocker8.budgetmaster.utils.ProvidesID;
+
+import java.util.Optional;
+
+public interface Iconizable extends ProvidesID
+{
+	void setIconReference(Icon icon);
+
+	Icon getIconReference();
+
+	default <T extends Iconizable> void updateIcon(IconService iconService, Integer iconImageID, String builtinIconIdentifier, AccessEntityByID<T> itemService)
+	{
+		// the reference to an existing icon may already be null in the item that should be updated
+		// (e.g. user deletes the icon for the item and hit the save button)
+		// therefore the existing item must be retrieved from database by id
+		if(this.getID() != null)
+		{
+			final Optional<T> existingItemOptional = itemService.findById(this.getID());
+			if(existingItemOptional.isPresent())
+			{
+				final Iconizable existingItem = existingItemOptional.get();
+				iconService.deleteIcon(existingItem.getIconReference());
+			}
+		}
+
+		final Optional<Icon> iconOptional = iconService.createIconReference(iconImageID, builtinIconIdentifier);
+		if(iconOptional.isEmpty())
+		{
+			this.setIconReference(null);
+			return;
+		}
+
+		final Icon icon = iconOptional.get();
+		iconService.getRepository().save(icon);
+		this.setIconReference(icon);
+	}
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/images/Image.java b/src/main/java/de/deadlocker8/budgetmaster/images/Image.java
index 5dfce63bdc876d0f37fbfd8ba4d577839fef0d06..7a16fbfd60e9e955c8286e911881a2b151f03093 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/images/Image.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/images/Image.java
@@ -1,7 +1,7 @@
 package de.deadlocker8.budgetmaster.images;
 
 import com.google.gson.annotations.Expose;
-import de.deadlocker8.budgetmaster.accounts.Account;
+import de.deadlocker8.budgetmaster.icon.Icon;
 import de.deadlocker8.budgetmaster.utils.ProvidesID;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.tomcat.util.codec.binary.Base64;
@@ -33,8 +33,8 @@ public class Image implements ProvidesID
 	@Expose
 	private ImageFileExtension fileExtension;
 
-	@OneToMany(mappedBy = "icon", fetch = FetchType.LAZY)
-	private List<Account> referringAccounts;
+	@OneToMany(mappedBy = "image", fetch = FetchType.LAZY)
+	private List<Icon> referringIcons;
 
 	private static final String BASE_64_IMAGE_FORMAT = "data:image/{0};base64,{1}";
 
@@ -95,9 +95,9 @@ public class Image implements ProvidesID
 		this.fileExtension = fileExtension;
 	}
 
-	public List<Account> getReferringAccounts()
+	public List<Icon> getReferringIcons()
 	{
-		return referringAccounts;
+		return referringIcons;
 	}
 
 	@Override
diff --git a/src/main/java/de/deadlocker8/budgetmaster/images/ImageService.java b/src/main/java/de/deadlocker8/budgetmaster/images/ImageService.java
index ccc0a61ef8b1d4d1669d69e568d43d2a5bc69f18..40dcec5d3f6f8e849dbaf5b8e9f571bdfb441c61 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/images/ImageService.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/images/ImageService.java
@@ -1,6 +1,7 @@
 package de.deadlocker8.budgetmaster.images;
 
-import de.deadlocker8.budgetmaster.accounts.Account;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.IconService;
 import de.deadlocker8.budgetmaster.services.Resettable;
 import de.thecodelabs.utils.util.Localization;
 import org.apache.commons.lang3.ArrayUtils;
@@ -17,11 +18,13 @@ import java.util.Optional;
 public class ImageService implements Resettable
 {
 	private final ImageRepository imageRepository;
+	private final IconService iconService;
 
 	@Autowired
-	public ImageService(ImageRepository imageRepository)
+	public ImageService(ImageRepository imageRepository, IconService iconService)
 	{
 		this.imageRepository = imageRepository;
+		this.iconService = iconService;
 	}
 
 	public ImageRepository getRepository()
@@ -45,10 +48,10 @@ public class ImageService implements Resettable
 	@Transactional
 	public void deleteImage(Image image)
 	{
-		final List<Account> referringAccounts = image.getReferringAccounts();
-		for(Account account : referringAccounts)
+		final List<Icon> referringIcons = image.getReferringIcons();
+		for(Icon icon : referringIcons)
 		{
-			account.setIcon(null);
+			iconService.deleteIcon(icon);
 		}
 
 		getRepository().delete(image);
diff --git a/src/main/java/de/deadlocker8/budgetmaster/images/MediaController.java b/src/main/java/de/deadlocker8/budgetmaster/images/MediaController.java
index 3e0e9b21ca72552a77b7ed20735a0dc59d362500..46eb79736233e82bf5b0d8dd9bac710e24733005 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/images/MediaController.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/images/MediaController.java
@@ -25,10 +25,16 @@ public class MediaController extends BaseController
 		this.imageService = imageService;
 	}
 
-	@GetMapping("/getAvailableImages")
-	public String getAvailableImages(Model model)
+	@GetMapping(value = {"/getAvailableImages", "/getAvailableImages/{selectedImageID}"})
+	public String getAvailableImages(Model model, @PathVariable(value = "selectedImageID", required = false) Integer selectedImageID)
 	{
+		if(selectedImageID == null)
+		{
+			selectedImageID = -1;
+		}
+
 		model.addAttribute("availableImages", imageService.getRepository().findAll());
+		model.addAttribute("selectedImageID", selectedImageID);
 		return "helpers/availableImages";
 	}
 
diff --git a/src/main/java/de/deadlocker8/budgetmaster/services/AccessEntityByID.java b/src/main/java/de/deadlocker8/budgetmaster/services/AccessEntityByID.java
new file mode 100644
index 0000000000000000000000000000000000000000..e544d7aad99c4d76edb51ca0ad33f92c0a2c15f6
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/services/AccessEntityByID.java
@@ -0,0 +1,10 @@
+package de.deadlocker8.budgetmaster.services;
+
+import de.deadlocker8.budgetmaster.icon.Iconizable;
+
+import java.util.Optional;
+
+public interface AccessEntityByID<T extends Iconizable>
+{
+	Optional<T> findById(Integer ID);
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/services/EntityType.java b/src/main/java/de/deadlocker8/budgetmaster/services/EntityType.java
index 867f77f67d501ec5b7e75de96aee5622d965a143..23ef363ab5d9d196332330fa5dce7ed4caf6f5c2 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/services/EntityType.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/services/EntityType.java
@@ -1,6 +1,8 @@
 package de.deadlocker8.budgetmaster.services;
 
-public enum EntityType
+import de.deadlocker8.budgetmaster.utils.LocalizedEnum;
+
+public enum EntityType implements LocalizedEnum
 {
 	HOME("home", "background-blue", ImportRequired.NONE),
 	ACCOUNT("account_balance", "background-red", ImportRequired.REQUIRED),
@@ -9,6 +11,7 @@ public enum EntityType
 	CHART("show_chart", "background-purple", ImportRequired.OPTIONAL),
 	REPORT("description", "background-green", ImportRequired.NONE),
 	CATEGORY("label", "background-orange", ImportRequired.REQUIRED),
+	TAGS("local_offer", "background-grey", ImportRequired.NONE),
 	STATISTICS("insert_chart", "background-grey", ImportRequired.NONE),
 	SETTINGS("settings", "background-red", ImportRequired.NONE),
 	IMAGE("image", "background-grey", ImportRequired.REQUIRED),
@@ -54,6 +57,7 @@ public enum EntityType
 		return color.replace("background", "text");
 	}
 
+	@Override
 	public String getLocalizationKey()
 	{
 		return "entity." + this.name().toLowerCase();
diff --git a/src/main/java/de/deadlocker8/budgetmaster/services/ErrorCodeController.java b/src/main/java/de/deadlocker8/budgetmaster/services/ErrorCodeController.java
index bdd296d24f18b3c5c04450403a67bdee065d1ada..e4aec361d05585412bda1fe00f67e64605b99751 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/services/ErrorCodeController.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/services/ErrorCodeController.java
@@ -12,10 +12,9 @@ import javax.servlet.http.HttpServletRequest;
 @Controller
 public class ErrorCodeController implements ErrorController
 {
-	@Override
 	public String getErrorPath()
 	{
-		return Mappings.ERROR;
+		return null;
 	}
 
 	@RequestMapping(Mappings.ERROR)
diff --git a/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java b/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java
index 95a4709504156082147c217dd4fc04ba444d75b6..418d89a353f9ebc1ee163b8a7ca2aac40953a0e8 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/services/HelpersService.java
@@ -9,6 +9,8 @@ import de.deadlocker8.budgetmaster.categories.Category;
 import de.deadlocker8.budgetmaster.categories.CategoryRepository;
 import de.deadlocker8.budgetmaster.database.accountmatches.AccountMatch;
 import de.deadlocker8.budgetmaster.filter.FilterConfiguration;
+import de.deadlocker8.budgetmaster.hints.Hint;
+import de.deadlocker8.budgetmaster.hints.HintService;
 import de.deadlocker8.budgetmaster.images.ImageFileExtension;
 import de.deadlocker8.budgetmaster.repeating.modifier.RepeatingModifierType;
 import de.deadlocker8.budgetmaster.reports.Budget;
@@ -52,6 +54,9 @@ public class HelpersService
 	@Autowired
 	private CategoryRepository categoryRepository;
 
+	@Autowired
+	private HintService hintService;
+
 	@Value("${budgetmaster.datepicker.simple:false}")
 	private boolean useSimpleDatepickerForTransactions;
 
@@ -220,4 +225,9 @@ public class HelpersService
 				.map(e -> "image/" + e.getBase64Type())
 				.collect(Collectors.joining(", "));
 	}
+
+	public Hint getHintByLocalizationKey(String localizationKey)
+	{
+		return hintService.findByLocalizationKey(localizationKey);
+	}
 }
\ No newline at end of file
diff --git a/src/main/java/de/deadlocker8/budgetmaster/services/ImportService.java b/src/main/java/de/deadlocker8/budgetmaster/services/ImportService.java
index a8671a0f3cacf463f01da4d878febae279ebd0c1..e08635e51fad4ed0b35c04735d88fb77fe397184 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/services/ImportService.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/services/ImportService.java
@@ -1,6 +1,7 @@
 package de.deadlocker8.budgetmaster.services;
 
 import de.deadlocker8.budgetmaster.accounts.Account;
+import de.deadlocker8.budgetmaster.accounts.AccountRepository;
 import de.deadlocker8.budgetmaster.categories.Category;
 import de.deadlocker8.budgetmaster.categories.CategoryRepository;
 import de.deadlocker8.budgetmaster.categories.CategoryType;
@@ -9,6 +10,9 @@ import de.deadlocker8.budgetmaster.charts.ChartService;
 import de.deadlocker8.budgetmaster.database.InternalDatabase;
 import de.deadlocker8.budgetmaster.database.accountmatches.AccountMatch;
 import de.deadlocker8.budgetmaster.database.accountmatches.AccountMatchList;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.IconService;
+import de.deadlocker8.budgetmaster.icon.Iconizable;
 import de.deadlocker8.budgetmaster.images.Image;
 import de.deadlocker8.budgetmaster.images.ImageService;
 import de.deadlocker8.budgetmaster.repeating.RepeatingTransactionUpdater;
@@ -41,13 +45,16 @@ public class ImportService
 	private final ChartService chartService;
 	private final ImageService imageService;
 	private final RepeatingTransactionUpdater repeatingTransactionUpdater;
+	private final AccountRepository accountRepository;
+	private final IconService iconService;
+
 
 	private InternalDatabase database;
 	private List<String> collectedErrorMessages;
 
 	@Autowired
 	public ImportService(CategoryRepository categoryRepository, TransactionRepository transactionRepository, TemplateRepository templateRepository,
-						 TagRepository tagRepository, ChartService chartService, ImageService imageService, RepeatingTransactionUpdater repeatingTransactionUpdater)
+						 TagRepository tagRepository, ChartService chartService, ImageService imageService, RepeatingTransactionUpdater repeatingTransactionUpdater, AccountRepository accountRepository, IconService iconService)
 	{
 		this.categoryRepository = categoryRepository;
 		this.transactionRepository = transactionRepository;
@@ -56,6 +63,8 @@ public class ImportService
 		this.chartService = chartService;
 		this.imageService = imageService;
 		this.repeatingTransactionUpdater = repeatingTransactionUpdater;
+		this.accountRepository = accountRepository;
+		this.iconService = iconService;
 	}
 
 	public List<ImportResultItem> importDatabase(InternalDatabase database, AccountMatchList accountMatchList, Boolean importTemplates, Boolean importCharts)
@@ -66,13 +75,13 @@ public class ImportService
 		final List<ImportResultItem> importResultItems = new ArrayList<>();
 
 		LOGGER.debug("Importing database...");
+		importResultItems.add(importImages());
+		importIcons();
 		importResultItems.add(importCategories());
 		importResultItems.add(importAccounts(accountMatchList));
 		importResultItems.add(importTransactions());
 
-		importResultItems.add(importImages());
 		if(importTemplates)
-
 		{
 			importResultItems.add(importTemplates());
 		}
@@ -173,7 +182,7 @@ public class ImportService
 		if(existingCategory == null)
 		{
 			//category does not exist --> create it
-			Category categoryToCreate = new Category(category.getName(), category.getColor(), category.getType(), category.getIcon());
+			Category categoryToCreate = new Category(category.getName(), category.getColor(), category.getType(), category.getIconReference());
 			categoryRepository.save(categoryToCreate);
 
 			Category newCategory = categoryRepository.findByNameAndColorAndType(category.getName(), category.getColor(), category.getType());
@@ -224,6 +233,21 @@ public class ImportService
 
 			try
 			{
+				Account sourceAccount = database.getAccounts().stream()
+						.filter(account -> account.getID().equals(accountMatch.getAccountSource().getID()))
+						.findFirst()
+						.orElseThrow();
+
+				Account destinationAccount = accountRepository.findById(accountMatch.getAccountDestination().getID()).orElseThrow();
+
+				Icon sourceIcon = sourceAccount.getIconReference();
+				if(sourceIcon != null)
+				{
+					LOGGER.debug("Overwriting destination account icon");
+					destinationAccount.setIconReference(sourceIcon);
+					accountRepository.save(destinationAccount);
+				}
+
 				List<TransactionBase> transactions = new ArrayList<>(database.getTransactions());
 				transactions.removeAll(alreadyUpdatedTransactions);
 				alreadyUpdatedTransactions.addAll(updateAccountsForItems(transactions, accountMatch.getAccountSource().getID(), accountMatch.getAccountDestination()));
@@ -371,7 +395,7 @@ public class ImportService
 			}
 			catch(Exception e)
 			{
-				final String errorMessage = MessageFormat.format("Error while importing template with name \"{0}\"", template.getName());
+				final String errorMessage = MessageFormat.format("Error while importing template with name \"{0}\"", template.getTemplateName());
 				LOGGER.error(errorMessage, e);
 				collectedErrorMessages.add(formatErrorMessage(errorMessage, e));
 			}
@@ -419,8 +443,7 @@ public class ImportService
 	{
 		List<Image> images = database.getImages();
 		LOGGER.debug(MessageFormat.format("Importing {0} images...", images.size()));
-		List<Account> alreadyUpdatedAccounts = new ArrayList<>();
-		List<Template> alreadyUpdatedTemplates = new ArrayList<>();
+		List<Icon> alreadyUpdatedIcons = new ArrayList<>();
 
 		int numberOfImportedImages = 0;
 
@@ -438,13 +461,9 @@ public class ImportService
 				final Image savedImage = imageService.getRepository().save(imageToCreate);
 				int newImageID = savedImage.getID();
 
-				List<Account> accounts = new ArrayList<>(database.getAccounts());
-				accounts.removeAll(alreadyUpdatedAccounts);
-				alreadyUpdatedAccounts.addAll(updateImagesForAccounts(accounts, oldImageID, newImageID));
-
-				List<Template> templates = new ArrayList<>(database.getTemplates());
-				templates.removeAll(alreadyUpdatedTemplates);
-				alreadyUpdatedTemplates.addAll(updateImagesForTemplates(templates, oldImageID, newImageID));
+				List<Icon> icons = new ArrayList<>(database.getIcons());
+				icons.removeAll(alreadyUpdatedIcons);
+				alreadyUpdatedIcons.addAll(updateImagesForIcons(icons, oldImageID, newImageID));
 
 				numberOfImportedImages++;
 			}
@@ -460,12 +479,12 @@ public class ImportService
 		return new ImportResultItem(EntityType.IMAGE, numberOfImportedImages, images.size());
 	}
 
-	public List<Account> updateImagesForAccounts(List<Account> items, int oldImageId, int newImageID)
+	public List<Icon> updateImagesForIcons(List<Icon> items, int oldImageId, int newImageID)
 	{
-		List<Account> updatedItems = new ArrayList<>();
-		for(Account item : items)
+		List<Icon> updatedItems = new ArrayList<>();
+		for(Icon item : items)
 		{
-			final Image image = item.getIcon();
+			final Image image = item.getImage();
 			if(image == null)
 			{
 				continue;
@@ -481,20 +500,71 @@ public class ImportService
 		return updatedItems;
 	}
 
-	public List<Template> updateImagesForTemplates(List<Template> items, int oldImageId, int newImageID)
+	private void importIcons()
 	{
-		List<Template> updatedItems = new ArrayList<>();
-		for(Template item : items)
+		List<Icon> icons = database.getIcons();
+		LOGGER.debug(MessageFormat.format("Importing {0} icons...", icons.size()));
+		List<Iconizable> alreadyUpdatedAccounts = new ArrayList<>();
+		List<Iconizable> alreadyUpdatedTemplates = new ArrayList<>();
+		List<Iconizable> alreadyUpdatedCategories = new ArrayList<>();
+
+		int numberOfImportedIcons = 0;
+
+		for(int i = 0; i < icons.size(); i++)
 		{
-			final Image image = item.getIcon();
-			if(image == null)
+			Icon icon = icons.get(i);
+			try
+			{
+				LOGGER.debug(MessageFormat.format("Importing icon {0}/{1} (ID: {2})", i + 1, icons.size(), icon.getID()));
+
+				// always create new icon
+				int oldIconID = icon.getID();
+				Icon iconToCreate = new Icon();
+				iconToCreate.setImage(icon.getImage());
+				iconToCreate.setBuiltinIdentifier(icon.getBuiltinIdentifier());
+
+				final Icon savedIcon = iconService.getRepository().save(iconToCreate);
+				int newIconID = savedIcon.getID();
+
+				List<Iconizable> accounts = new ArrayList<>(database.getAccounts());
+				accounts.removeAll(alreadyUpdatedAccounts);
+				alreadyUpdatedAccounts.addAll(updateIconsForItems(accounts, oldIconID, newIconID));
+
+				List<Iconizable> templates = new ArrayList<>(database.getTemplates());
+				templates.removeAll(alreadyUpdatedTemplates);
+				alreadyUpdatedTemplates.addAll(updateIconsForItems(templates, oldIconID, newIconID));
+
+				List<Iconizable> categories = new ArrayList<>(database.getCategories());
+				categories.removeAll(alreadyUpdatedCategories);
+				alreadyUpdatedCategories.addAll(updateIconsForItems(categories, oldIconID, newIconID));
+
+				numberOfImportedIcons++;
+			}
+			catch(Exception e)
+			{
+				final String errorMessage = MessageFormat.format("Error while importing icon with ID {0}", icon.getID());
+				LOGGER.error(errorMessage, e);
+				collectedErrorMessages.add(formatErrorMessage(errorMessage, e));
+			}
+		}
+
+		LOGGER.debug(MessageFormat.format("Importing icon DONE ({0}/{1})", numberOfImportedIcons, icons.size()));
+	}
+
+	public List<Iconizable> updateIconsForItems(List<? extends Iconizable> items, int oldIconID, int newIconID)
+	{
+		List<Iconizable> updatedItems = new ArrayList<>();
+		for(Iconizable item : items)
+		{
+			final Icon iconReference = item.getIconReference();
+			if(iconReference == null)
 			{
 				continue;
 			}
 
-			if(image.getID() == oldImageId)
+			if(iconReference.getID() == oldIconID)
 			{
-				image.setID(newImageID);
+				iconReference.setID(newIconID);
 				updatedItems.add(item);
 			}
 		}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/services/LocalizationService.java b/src/main/java/de/deadlocker8/budgetmaster/services/LocalizationService.java
index 487118834172fd4cfeee9a8a5b6391343c6f4942..d162dc2848628e176547b12a42fc9801c2dca44f 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/services/LocalizationService.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/services/LocalizationService.java
@@ -32,7 +32,7 @@ public class LocalizationService implements  Localization.LocalizationDelegate
 	@Override
 	public String[] getBaseResources()
 	{
-		return new String[]{"languages/base", "languages/news"};
+		return new String[]{"languages/base", "languages/news", "languages/hints"};
 	}
 
 	@Override
diff --git a/src/main/java/de/deadlocker8/budgetmaster/settings/Settings.java b/src/main/java/de/deadlocker8/budgetmaster/settings/Settings.java
index ea5c7fecbe63f94fd1bd03c93ee1efd1669eb884..3947233ef297ed613025ee781c92648bb2bbc911 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/settings/Settings.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/settings/Settings.java
@@ -1,7 +1,7 @@
 package de.deadlocker8.budgetmaster.settings;
 
-import de.deadlocker8.budgetmaster.backup.AutoBackupTime;
 import de.deadlocker8.budgetmaster.backup.AutoBackupStrategy;
+import de.deadlocker8.budgetmaster.backup.AutoBackupTime;
 import de.deadlocker8.budgetmaster.utils.LanguageType;
 import org.joda.time.DateTime;
 import org.springframework.format.annotation.DateTimeFormat;
@@ -41,7 +41,6 @@ public class Settings
 
 	private Integer installedVersionCode;
 	private Boolean whatsNewShownForCurrentVersion;
-	private Boolean showFirstUseBanner;
 
 	public Settings()
 	{
@@ -69,7 +68,6 @@ public class Settings
 		defaultSettings.setAutoBackupGitToken("");
 		defaultSettings.setInstalledVersionCode(0);
 		defaultSettings.setWhatsNewShownForCurrentVersion(false);
-		defaultSettings.setShowFirstUseBanner(true);
 
 		return defaultSettings;
 	}
@@ -288,16 +286,6 @@ public class Settings
 		return !this.whatsNewShownForCurrentVersion;
 	}
 
-	public Boolean getShowFirstUseBanner()
-	{
-		return showFirstUseBanner;
-	}
-
-	public void setShowFirstUseBanner(Boolean showFirstUseBanner)
-	{
-		this.showFirstUseBanner = showFirstUseBanner;
-	}
-
 	@Override
 	public String toString()
 	{
@@ -322,7 +310,6 @@ public class Settings
 				", autoBackupGitToken='" + autoBackupGitToken + '\'' +
 				", installedVersionCode=" + installedVersionCode +
 				", whatsNewShownForCurrentVersion=" + whatsNewShownForCurrentVersion +
-				", showFirstUseBanner=" + showFirstUseBanner +
 				'}';
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsController.java b/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsController.java
index 33440497e4d83a0cf8fcc5ca29f8e7137b6af3d3..8323224982edc1b2cc0f93a2d8bf40d99bf55ac3 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsController.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsController.java
@@ -10,7 +10,7 @@ import de.deadlocker8.budgetmaster.database.DatabaseParser;
 import de.deadlocker8.budgetmaster.database.DatabaseService;
 import de.deadlocker8.budgetmaster.database.InternalDatabase;
 import de.deadlocker8.budgetmaster.database.accountmatches.AccountMatchList;
-import de.deadlocker8.budgetmaster.database.model.v6.BackupDatabase_v6;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupDatabase_v7;
 import de.deadlocker8.budgetmaster.services.ImportResultItem;
 import de.deadlocker8.budgetmaster.services.ImportService;
 import de.deadlocker8.budgetmaster.services.UpdateCheckService;
@@ -34,7 +34,6 @@ import org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.RequestAttributes;
 import org.springframework.web.context.request.WebRequest;
 import org.springframework.web.multipart.MultipartFile;
-import org.springframework.web.servlet.mvc.support.RedirectAttributes;
 
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletResponse;
@@ -219,7 +218,7 @@ public class SettingsController extends BaseController
 	{
 		LOGGER.debug("Exporting database...");
 
-		final BackupDatabase_v6 databaseForJsonSerialization = databaseService.getDatabaseForJsonSerialization();
+		final BackupDatabase_v7 databaseForJsonSerialization = databaseService.getDatabaseForJsonSerialization();
 		String data = DatabaseService.GSON.toJson(databaseForJsonSerialization);
 		byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
 
@@ -281,7 +280,7 @@ public class SettingsController extends BaseController
 	}
 
 	@RequestMapping("/database/upload")
-	public String upload(WebRequest request, Model model, @RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes)
+	public String upload(WebRequest request, Model model, @RequestParam("file") MultipartFile file)
 	{
 		if(file.isEmpty())
 		{
@@ -330,11 +329,26 @@ public class SettingsController extends BaseController
 	@GetMapping("/database/import/step2")
 	public String importStepTwo(WebRequest request, Model model)
 	{
+		Object accountMatches = request.getAttribute("accountMatchList", RequestAttributes.SCOPE_SESSION);
+		if(accountMatches != null)
+		{
+			final AccountMatchList accountMatchList = (AccountMatchList) accountMatches;
+			model.addAttribute("accountMatchList", accountMatchList);
+			request.removeAttribute("accountMatchList", RequestAttributes.SCOPE_SESSION);
+		}
+
 		model.addAttribute("database", request.getAttribute("database", RequestAttributes.SCOPE_SESSION));
 		model.addAttribute("availableAccounts", accountService.getAllEntitiesAsc());
 		return "settings/importStepTwo";
 	}
 
+	@PostMapping("/database/import/step2/createAccount")
+	public String importCreateAccount(WebRequest request, @ModelAttribute("Import") AccountMatchList accountMatchList, Model model)
+	{
+		request.setAttribute("accountMatchList", accountMatchList, RequestAttributes.SCOPE_SESSION);
+		return "redirect:/accounts/newAccount";
+	}
+
 	@PostMapping("/database/import/step3")
 	public String importDatabase(WebRequest request, @ModelAttribute("Import") AccountMatchList accountMatchList, Model model)
 	{
@@ -402,13 +416,6 @@ public class SettingsController extends BaseController
 		return "";
 	}
 
-	@RequestMapping("/hideFirstUseBanner")
-	public String hideFirstUseBanner()
-	{
-		settingsService.disableFirstUseBanner();
-		return "redirect:/";
-	}
-
 	@PostMapping("/git/test")
 	@ResponseBody
 	public String testGit(@RequestParam(value = "autoBackupGitUrl") String autoBackupGitUrl,
diff --git a/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsService.java b/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsService.java
index 6277fb8827dd8520c0dff97818977ae8ec7bc0ac..80e8f383585541eab43054166c419f7a5c2565bb 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsService.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/settings/SettingsService.java
@@ -111,10 +111,6 @@ public class SettingsService
 		{
 			settings.setWhatsNewShownForCurrentVersion(defaultSettings.getWhatsNewShownForCurrentVersion());
 		}
-		if(settings.getShowFirstUseBanner() == null)
-		{
-			settings.setShowFirstUseBanner(defaultSettings.getShowFirstUseBanner());
-		}
 		if(settings.getShowCategoriesAsCircles() == null)
 		{
 			settings.setShowCategoriesAsCircles(defaultSettings.getShowCategoriesAsCircles());
@@ -133,13 +129,6 @@ public class SettingsService
 		settings.setLastBackupReminderDate(DateTime.now());
 	}
 
-	@Transactional
-	public void disableFirstUseBanner()
-	{
-		Settings settings = getSettings();
-		settings.setShowFirstUseBanner(false);
-	}
-
 	@Transactional
 	public void updateSettings(Settings newSettings)
 	{
diff --git a/src/main/java/de/deadlocker8/budgetmaster/tags/TagController.java b/src/main/java/de/deadlocker8/budgetmaster/tags/TagController.java
new file mode 100644
index 0000000000000000000000000000000000000000..d90d0c76639ddf5d517c015c8580f728f42c0366
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/tags/TagController.java
@@ -0,0 +1,30 @@
+package de.deadlocker8.budgetmaster.tags;
+
+import de.deadlocker8.budgetmaster.controller.BaseController;
+import de.deadlocker8.budgetmaster.utils.Mappings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+
+@Controller
+@RequestMapping(Mappings.TAGS)
+public class TagController extends BaseController
+{
+	private final TagService tagService;
+
+	@Autowired
+	public TagController(TagService tagService)
+	{
+		this.tagService = tagService;
+	}
+
+	@GetMapping
+	public String tags(Model model)
+	{
+		model.addAttribute("tagUsages", tagService.getUsageCounts());
+		return "tags/tags";
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/de/deadlocker8/budgetmaster/tags/TagService.java b/src/main/java/de/deadlocker8/budgetmaster/tags/TagService.java
index 7cad4b707f9f8b91616910b86929e77fc98e6fac..6a1b692f195ede22a4b51e450571e53cb866ae2f 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/tags/TagService.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/tags/TagService.java
@@ -6,7 +6,9 @@ import org.padler.natorder.NaturalOrderComparator;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 @Service
 public class TagService implements Resettable, AccessAllEntities<Tag>
@@ -42,4 +44,18 @@ public class TagService implements Resettable, AccessAllEntities<Tag>
 		tags.sort((t1, t2) -> new NaturalOrderComparator().compare(t1.getName(), t2.getName()));
 		return tags;
 	}
+
+	public Map<String, Integer> getUsageCounts()
+	{
+		HashMap<String, Integer> usageCounts = new HashMap<>();
+
+		final List<Tag> tags = getAllEntitiesAsc();
+		for(Tag tag : tags)
+		{
+			int numberOfTransactions = tag.getReferringTransactions().size();
+			usageCounts.put(tag.getName(), numberOfTransactions);
+		}
+
+		return usageCounts;
+	}
 }
diff --git a/src/main/java/de/deadlocker8/budgetmaster/templates/Template.java b/src/main/java/de/deadlocker8/budgetmaster/templates/Template.java
index d1b7ed8ee8abe66d3fed6112e7430f6e61e0620e..2bf0922f5566be91985702a1281abe30f42d6786 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/templates/Template.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/templates/Template.java
@@ -3,6 +3,8 @@ package de.deadlocker8.budgetmaster.templates;
 import com.google.gson.annotations.Expose;
 import de.deadlocker8.budgetmaster.accounts.Account;
 import de.deadlocker8.budgetmaster.categories.Category;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.Iconizable;
 import de.deadlocker8.budgetmaster.images.Image;
 import de.deadlocker8.budgetmaster.tags.Tag;
 import de.deadlocker8.budgetmaster.transactions.Transaction;
@@ -14,7 +16,7 @@ import java.util.List;
 import java.util.Objects;
 
 @Entity
-public class Template implements TransactionBase
+public class Template implements TransactionBase, Iconizable
 {
 	@Id
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -44,9 +46,13 @@ public class Template implements TransactionBase
 	private String description;
 
 	@ManyToOne
-	@Expose
+	@Deprecated(since = "v2.7.0", forRemoval = true)
 	private Image icon;
 
+	@OneToOne(cascade = CascadeType.REMOVE)
+	@Expose
+	private Icon iconReference;
+
 	@ManyToMany
 	@Expose
 	@JoinTable(
@@ -76,6 +82,7 @@ public class Template implements TransactionBase
 		this.name = template.getName();
 		this.description = template.getDescription();
 		this.icon = template.getIcon();
+		this.iconReference = template.getIconReference();
 		this.tags = new ArrayList<>(template.getTags());
 		this.transferAccount = template.getTransferAccount();
 	}
@@ -94,7 +101,7 @@ public class Template implements TransactionBase
 		this.category = transaction.getCategory();
 		this.name = transaction.getName();
 		this.description = transaction.getDescription();
-		this.icon = null;
+		this.iconReference = null;
 		if(transaction.getTags() == null)
 		{
 			this.tags = new ArrayList<>();
@@ -191,16 +198,28 @@ public class Template implements TransactionBase
 		this.description = description;
 	}
 
+	@Deprecated(since = "v2.7.0", forRemoval = true)
 	public Image getIcon()
 	{
 		return icon;
 	}
 
+	@Deprecated(since = "v2.7.0", forRemoval = true)
 	public void setIcon(Image icon)
 	{
 		this.icon = icon;
 	}
 
+	public Icon getIconReference()
+	{
+		return iconReference;
+	}
+
+	public void setIconReference(Icon iconReference)
+	{
+		this.iconReference = iconReference;
+	}
+
 	public List<Tag> getTags()
 	{
 		return tags;
@@ -237,7 +256,7 @@ public class Template implements TransactionBase
 				", category=" + category +
 				", name='" + name + '\'' +
 				", description='" + description + '\'' +
-				", icon='" + icon + '\'' +
+				", iconReference='" + iconReference + '\'' +
 				", tags=" + tags;
 
 		if(account == null)
@@ -277,6 +296,7 @@ public class Template implements TransactionBase
 				Objects.equals(name, template.name) &&
 				Objects.equals(description, template.description) &&
 				Objects.equals(icon, template.icon) &&
+				Objects.equals(iconReference, template.iconReference) &&
 				Objects.equals(tags, template.tags) &&
 				Objects.equals(transferAccount, template.transferAccount);
 	}
@@ -284,6 +304,6 @@ public class Template implements TransactionBase
 	@Override
 	public int hashCode()
 	{
-		return Objects.hash(ID, templateName, amount, isExpenditure, account, category, name, description, icon, tags, transferAccount);
+		return Objects.hash(ID, templateName, amount, isExpenditure, account, category, name, description, icon, iconReference, tags, transferAccount);
 	}
 }
diff --git a/src/main/java/de/deadlocker8/budgetmaster/templates/TemplateController.java b/src/main/java/de/deadlocker8/budgetmaster/templates/TemplateController.java
index 2b280ca9f10a0754d2ace3413f5d2f5067c98151..f2ffc45f21499389bb609e63680aa5c7fd27ab6e 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/templates/TemplateController.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/templates/TemplateController.java
@@ -4,6 +4,7 @@ import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import de.deadlocker8.budgetmaster.accounts.AccountService;
 import de.deadlocker8.budgetmaster.controller.BaseController;
+import de.deadlocker8.budgetmaster.icon.IconService;
 import de.deadlocker8.budgetmaster.services.DateService;
 import de.deadlocker8.budgetmaster.settings.SettingsService;
 import de.deadlocker8.budgetmaster.transactions.Transaction;
@@ -39,14 +40,16 @@ public class TemplateController extends BaseController
 	private final TransactionService transactionService;
 	private final DateService dateService;
 	private final AccountService accountService;
+	private final IconService iconService;
 
 	@Autowired
-	public TemplateController(TemplateService templateService, SettingsService settingsService, TransactionService transactionService, DateService dateService, AccountService accountService)
+	public TemplateController(TemplateService templateService, SettingsService settingsService, TransactionService transactionService, DateService dateService, AccountService accountService, IconService iconService)
 	{
 		this.templateService = templateService;
 		this.transactionService = transactionService;
 		this.dateService = dateService;
 		this.accountService = accountService;
+		this.iconService = iconService;
 	}
 
 	@GetMapping
@@ -98,14 +101,14 @@ public class TemplateController extends BaseController
 		}
 
 		model.addAttribute("templates", templateService.getAllEntitiesAsc());
-		model.addAttribute("currentTemplate", templateOptional.get());
-		return "templates/templates";
+		model.addAttribute("templateToDelete", templateOptional.get());
+		return "templates/deleteTemplateModal";
 	}
 
 	@GetMapping("/{ID}/delete")
 	public String deleteTemplate(WebRequest request, @PathVariable("ID") Integer ID)
 	{
-		final Template templateToDelete = templateService.getRepository().getOne(ID);
+		final Template templateToDelete = templateService.getRepository().getById(ID);
 		templateService.getRepository().deleteById(ID);
 
 		WebRequestUtils.putNotification(request, new Notification(Localization.getString("notification.template.delete.success", templateToDelete.getTemplateName()), NotificationType.SUCCESS));
@@ -165,7 +168,9 @@ public class TemplateController extends BaseController
 	public String post(Model model,
 					   @ModelAttribute("NewTemplate") Template template, BindingResult bindingResult,
 					   @RequestParam(value = "includeAccount", required = false) boolean includeAccount,
-					   @RequestParam(value = "includeTransferAccount", required = false) boolean includeTransferAccount)
+					   @RequestParam(value = "includeTransferAccount", required = false) boolean includeTransferAccount,
+					   @RequestParam(value = "iconImageID", required = false) Integer iconImageID,
+					   @RequestParam(value = "builtinIconIdentifier", required = false) String builtinIconIdentifier)
 	{
 		template.setTemplateName(template.getTemplateName().trim());
 
@@ -211,6 +216,8 @@ public class TemplateController extends BaseController
 			template.setTransferAccount(null);
 		}
 
+		template.updateIcon(iconService, iconImageID, builtinIconIdentifier, templateService);
+
 		templateService.getRepository().save(template);
 		return "redirect:/templates";
 	}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/templates/TemplateService.java b/src/main/java/de/deadlocker8/budgetmaster/templates/TemplateService.java
index f03ee377c2ec4617730a8df5a273983ebc946355..dcd09c14234d5529f015332de5c408a8c53d8fbc 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/templates/TemplateService.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/templates/TemplateService.java
@@ -7,23 +7,35 @@ import de.deadlocker8.budgetmaster.accounts.AccountService;
 import de.deadlocker8.budgetmaster.accounts.AccountState;
 import de.deadlocker8.budgetmaster.categories.CategoryService;
 import de.deadlocker8.budgetmaster.categories.CategoryType;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.IconService;
+import de.deadlocker8.budgetmaster.images.Image;
+import de.deadlocker8.budgetmaster.images.ImageService;
 import de.deadlocker8.budgetmaster.services.AccessAllEntities;
 import de.deadlocker8.budgetmaster.services.Resettable;
 import de.deadlocker8.budgetmaster.settings.SettingsService;
 import de.deadlocker8.budgetmaster.transactions.Transaction;
 import de.deadlocker8.budgetmaster.transactions.TransactionBase;
+import de.deadlocker8.budgetmaster.services.AccessEntityByID;
+import de.deadlocker8.budgetmaster.utils.FontAwesomeIcons;
 import org.padler.natorder.NaturalOrderComparator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.ui.Model;
 
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 @Service
-public class TemplateService implements Resettable, AccessAllEntities<Template>
+public class TemplateService implements Resettable, AccessAllEntities<Template>, AccessEntityByID<Template>
 {
+	private static final Logger LOGGER = LoggerFactory.getLogger(TemplateService.class);
+
 	private static final Gson GSON = new GsonBuilder()
 			.setPrettyPrinting()
 			.create();
@@ -31,14 +43,19 @@ public class TemplateService implements Resettable, AccessAllEntities<Template>
 	private final TemplateRepository templateRepository;
 	private final AccountService accountService;
 	private final CategoryService categoryService;
-
+	private final ImageService imageService;
+	private final IconService iconService;
 
 	@Autowired
-	public TemplateService(TemplateRepository templateRepository, AccountService accountService, CategoryService categoryService, SettingsService settingsService)
+	public TemplateService(TemplateRepository templateRepository, AccountService accountService, CategoryService categoryService, SettingsService settingsService, ImageService imageService, IconService iconService)
 	{
 		this.templateRepository = templateRepository;
 		this.accountService = accountService;
 		this.categoryService = categoryService;
+		this.imageService = imageService;
+		this.iconService = iconService;
+
+		createDefaults();
 	}
 
 	public TemplateRepository getRepository()
@@ -55,6 +72,28 @@ public class TemplateService implements Resettable, AccessAllEntities<Template>
 	@Override
 	public void createDefaults()
 	{
+		updateMissingAttributes();
+	}
+
+	private void updateMissingAttributes()
+	{
+		for(Template template : templateRepository.findAll())
+		{
+			if(template.getIcon() != null && template.getIconReference() == null)
+			{
+				Integer imageID = template.getIcon().getID();
+				Image image = imageService.getRepository().findById(imageID).orElseThrow();
+
+				Icon iconReference = new Icon(image);
+				iconService.getRepository().save(iconReference);
+
+				template.setIconReference(iconReference);
+				template.setIcon(null);
+
+				templateRepository.save(template);
+				LOGGER.debug(MessageFormat.format("Updated template {0}: Converted attribute \"icon\" to \"iconReference\" {1}", template.getName(), image.getFileName()));
+			}
+		}
 	}
 
 	public void createFromTransaction(String templateName, Transaction transaction, boolean includeCategory, boolean includeAccount)
@@ -82,8 +121,7 @@ public class TemplateService implements Resettable, AccessAllEntities<Template>
 
 		if(prepareAccount && template.getAccount() == null)
 		{
-			final Account selectedAccount = accountService.getRepository().findByIsSelected(true);
-			template.setAccount(selectedAccount);
+			template.setAccount(accountService.getRepository().findByIsDefault(true));
 		}
 
 		final Account account = template.getAccount();
@@ -106,6 +144,7 @@ public class TemplateService implements Resettable, AccessAllEntities<Template>
 		model.addAttribute("accounts", accounts);
 		model.addAttribute("template", item);
 		model.addAttribute("suggestionsJSON", GSON.toJson(new ArrayList<String>()));
+		model.addAttribute("fontawesomeIcons", FontAwesomeIcons.ICONS);
 	}
 
 	public List<String> getExistingTemplateNames()
@@ -122,4 +161,11 @@ public class TemplateService implements Resettable, AccessAllEntities<Template>
 		templates.sort((t1, t2) -> new NaturalOrderComparator().compare(t1.getName(), t2.getName()));
 		return templates;
 	}
+
+	@Override
+	public Optional<Template> findById(Integer ID)
+	{
+		return templateRepository.findById(ID);
+	}
+
 }
diff --git a/src/main/java/de/deadlocker8/budgetmaster/transactions/Transaction.java b/src/main/java/de/deadlocker8/budgetmaster/transactions/Transaction.java
index af010b146f88b88f2398f25fa03ac94949e9a363..b802a127fcea6a4860e53580fc84a9c9c33d7a33 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/transactions/Transaction.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/transactions/Transaction.java
@@ -2,7 +2,9 @@ package de.deadlocker8.budgetmaster.transactions;
 
 import com.google.gson.annotations.Expose;
 import de.deadlocker8.budgetmaster.accounts.Account;
+import de.deadlocker8.budgetmaster.accounts.AccountState;
 import de.deadlocker8.budgetmaster.categories.Category;
+import de.deadlocker8.budgetmaster.categories.CategoryType;
 import de.deadlocker8.budgetmaster.repeating.RepeatingOption;
 import de.deadlocker8.budgetmaster.tags.Tag;
 import org.joda.time.DateTime;
@@ -211,6 +213,25 @@ public class Transaction implements TransactionBase
 		return date.isAfter(DateTime.now());
 	}
 
+	public boolean isEditable()
+	{
+		boolean isRestCategory = category.getType().equals(CategoryType.REST);
+		if(isRestCategory)
+		{
+			return false;
+		}
+
+		boolean isAccountEditable = account.getAccountState().equals(AccountState.FULL_ACCESS);
+
+		if(!isTransfer())
+		{
+			return isAccountEditable;
+		}
+
+		boolean isTransferAccountEditable = transferAccount.getAccountState().equals(AccountState.FULL_ACCESS);
+		return isAccountEditable && isTransferAccountEditable;
+	}
+
 	@Override
 	public String toString()
 	{
diff --git a/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionController.java b/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionController.java
index 2668621bb91f488237d2287a410be65ba6468a80..6fc12e7d3da76f6fdc708ef5b2ab5158939e39bf 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionController.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionController.java
@@ -86,9 +86,9 @@ public class TransactionController extends BaseController
 
 		DateTime date = dateService.getDateTimeFromCookie(cookieDate);
 		prepareModelTransactions(filterHelpers.getFilterConfiguration(request), model, date);
-		model.addAttribute("currentTransaction", transactionService.getRepository().getOne(ID));
+		model.addAttribute("transactionToDelete", transactionService.getRepository().getById(ID));
 
-		return "transactions/transactions";
+		return "transactions/deleteTransactionModal";
 	}
 
 	private void prepareModelTransactions(FilterConfiguration filterConfiguration, Model model, DateTime date)
@@ -106,7 +106,7 @@ public class TransactionController extends BaseController
 	@GetMapping("/{ID}/delete")
 	public String deleteTransaction(WebRequest request, @PathVariable("ID") Integer ID)
 	{
-		final Transaction transactionToDelete = transactionService.getRepository().getOne(ID);
+		final Transaction transactionToDelete = transactionService.getRepository().getById(ID);
 		transactionService.deleteTransaction(ID);
 
 		WebRequestUtils.putNotification(request, new Notification(Localization.getString("notification.transaction.delete.success", transactionToDelete.getName()), NotificationType.SUCCESS));
@@ -285,7 +285,7 @@ public class TransactionController extends BaseController
 	@GetMapping("/{ID}/highlight")
 	public String highlight(Model model, @PathVariable("ID") Integer ID)
 	{
-		Transaction transaction = transactionService.getRepository().getOne(ID);
+		Transaction transaction = transactionService.getRepository().getById(ID);
 
 		Account currentAccount = helpers.getCurrentAccount();
 		if(currentAccount.getType() != AccountType.ALL || transaction.isTransfer())
diff --git a/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionSpecifications.java b/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionSpecifications.java
index 38bfda8fb4c45de2ffed7c3a5236da691f60beaa..f58d7299cf3536c1fead7ea5dc69af9fa76b7f91 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionSpecifications.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/transactions/TransactionSpecifications.java
@@ -91,8 +91,6 @@ public class TransactionSpecifications
 				predicates.add(builder.like(builder.lower(transaction.get(Transaction_.name)), "%" + name.toLowerCase() + "%"));
 			}
 
-			predicates.add(transaction.get(Transaction_.account).get("accountState").in(List.of(AccountState.FULL_ACCESS, AccountState.READ_ONLY)));
-
 			query.orderBy(builder.desc(transaction.get(Transaction_.date)));
 
 			Predicate[] predicatesArray = new Predicate[predicates.size()];
diff --git a/src/main/java/de/deadlocker8/budgetmaster/utils/LocalizedEnum.java b/src/main/java/de/deadlocker8/budgetmaster/utils/LocalizedEnum.java
new file mode 100644
index 0000000000000000000000000000000000000000..0e0ce079fcacc41ad79574a5fbdbb79354aa2491
--- /dev/null
+++ b/src/main/java/de/deadlocker8/budgetmaster/utils/LocalizedEnum.java
@@ -0,0 +1,6 @@
+package de.deadlocker8.budgetmaster.utils;
+
+public interface LocalizedEnum
+{
+	String getLocalizationKey();
+}
diff --git a/src/main/java/de/deadlocker8/budgetmaster/utils/Mappings.java b/src/main/java/de/deadlocker8/budgetmaster/utils/Mappings.java
index 10985ab6a3358d2681dde9c763950461816d5f49..5b2cccc2cd2fd87484c6bce5cf97d1ebe4d62ba0 100644
--- a/src/main/java/de/deadlocker8/budgetmaster/utils/Mappings.java
+++ b/src/main/java/de/deadlocker8/budgetmaster/utils/Mappings.java
@@ -22,4 +22,6 @@ public final class Mappings
 	public static final String TEAPOT = "/418";
 	public static final String TEMPLATES = "/templates";
 	public static final String TRANSACTIONS = "/transactions";
+	public static final String TAGS = "/tags";
+	public static final String HINTS = "/hints";
 }
diff --git a/src/main/resources/languages/base_de.properties b/src/main/resources/languages/base_de.properties
index b98a9810b3c8d8e3394ebc04d7530d43bfdf3599..42dd1aaac61aae1ae9c934fb20dce8790f8ff153 100644
--- a/src/main/resources/languages/base_de.properties
+++ b/src/main/resources/languages/base_de.properties
@@ -1,7 +1,7 @@
 locale=de
 
 # DEFAULT
-credits=Verwendete Schriftarten: Roboto<br>Verwendete Bibliotheken:<br>spring-boot-starter-parent 2.4.5<br>spring-boot-devtools 2.4.5<br>spring-boot-starter-web 2.4.5<br>spring-boot-starter-test 2.4.5<br>spring-boot-starter-data-jpa 2.4.5<br>spring-boot-starter-security 2.4.5<br>spring-boot-starter-tomcat 2.4.5<br>spring-boot-starter-freemarker 2.4.5<br>spring-boot-starter-validation 2.4.5<br>h2 1.4.199<br>joda-time 2.10.10<br>usertype.core 6.0.1.GA<br>maven-surefire-plugin 2.22.2<br>launch4j-maven-plugin 1.7.25<br>jquery 3.6.0<br>materialize 1.0.0<br>fontawesome 5.15.2<br>Google Material Icons<br>Spectrum Colorpicker 1.8.0<br>SortableJS 1.13.0<br>jlibs 3.2.0<br>itextpdf 5.5.13.2<br>mousetrap 1.6.5<br>plotly 1.58.4<br>momentjs 2.29.1<br>codemirror 5.50.0<br>webjars-locator 0.40<br>libUtils 3.2.7<br>libStorage 3.2.3<br>natorder 1.0.1<br>
+credits=Verwendete Schriftarten: Roboto<br>Verwendete Bibliotheken:<br>spring-boot-starter-parent 2.4.5<br>spring-boot-devtools 2.4.5<br>spring-boot-starter-web 2.4.5<br>spring-boot-starter-test 2.4.5<br>spring-boot-starter-data-jpa 2.4.5<br>spring-boot-starter-security 2.4.5<br>spring-boot-starter-tomcat 2.4.5<br>spring-boot-starter-freemarker 2.4.5<br>spring-boot-starter-validation 2.4.5<br>h2 1.4.199<br>joda-time 2.10.10<br>usertype.core 6.0.1.GA<br>maven-surefire-plugin 2.22.2<br>launch4j-maven-plugin 1.7.25<br>jquery 3.6.0<br>materialize 1.0.0<br>fontawesome 5.15.3<br>Google Material Icons<br>Spectrum Colorpicker 1.8.0<br>SortableJS 1.13.0<br>jlibs 3.2.0<br>itextpdf 5.5.13.2<br>mousetrap 1.6.5<br>plotly 1.58.4<br>momentjs 2.29.1<br>codemirror 5.62.0<br>webjars-locator 0.41<br>libUtils 3.2.7<br>libStorage 3.2.3<br>natorder 1.0.2<br>jgit 5.12.0.202106070339-r<br>
 folder=Deadlocker/BudgetMaster
 roadmap.url=https://roadmaps.thecodelabs.de/roadmap/1
 github.url=https://github.com/deadlocker8/BudgetMaster
@@ -125,8 +125,8 @@ notification.template.delete.success=Die Vorlage "{0}" wurde erfolgreich gelösc
 notification.template.add.success=Die Vorlage "{0}" wurde erfolgreich angelegt.
 
 info.title.database.delete=Datenbank löschen
-info.header.text.database.delete=Soll die Datenbank wirklich unwiderruflich gelöscht werden?<br>Hinweis: Beim Löschen der Datenbank werden alle Buchungen, Kategorien, Konten, Diagramme, Vorlagen und Bilder unwiderruflich gelöscht.
-info.text.database.delete=Zur Bestätigung gib folgenden Code ein:\t{0}
+info.header.text.database.delete=Soll die Datenbank wirklich unwiderruflich gelöscht werden?<br>Hinweis: Beim Löschen der Datenbank werden alle Buchungen, Kategorien, Konten, Diagramme, Vorlagen und Bilder unwiderruflich gelöscht. Alle Einstellungen bleiben erhalten.
+info.text.database.delete=Gib den folgenden Code zur Bestätigung ein:
 info.title.database.import.dialog=Datenbank importieren
 info.database.import=Folgende Daten werden importiert
 info.database.import.result=Import abgeschlossen
@@ -134,7 +134,6 @@ info.database.import.result.errors=Aufgetretene Fehler
 info.database.import.match.accounts=Konten zuordnen
 info.database.import.source=Buchungen aus
 info.database.import.destination=importieren in
-info.database.import.or=oder
 info.title.update=Update verfügbar
 info.text.update=Es ist ein Update für BudgetMaster verfügbar<br><br>Installiert: v{0}<br>Verfügbar: {1}<br><br>Möchtest du das Update jetzt durchführen?<br><br>Hinweis: Das Aktualisieren kann je nach Internetverbindung eine Weile dauern. Der BudgetMaster Server wird danach automatisch nuegestartet. Bitte führe nach dem Start des Updates keine Änderungen an Konten, Buchungen, Kategorien, etc. durch.
 info.title.backup.reminder=Zeit für ein Backup
@@ -153,6 +152,9 @@ delete.image.success=Erfolgreich gelöscht
 delete.image.error.not.existing=Fehler: Bild mit ID {0} existiert nicht
 upload.image.headline=Bild hochladen
 available.images=Verfügbare Bilder
+icons.images=Eigene Bilder
+icons.builtin=Mitgelieferte Icons
+icons.numberOf=Icons
 
 notification.transaction.add.warning=Konto mit Sichtbarkeit "{0}" erlaubt keine neuen Buchungen!
 
@@ -190,6 +192,7 @@ menu.templates=Vorlagen
 menu.categories=Kategorien
 menu.charts=Diagramme
 menu.reports=Berichte
+menu.tags=Tags
 menu.statistics=Statistiken
 menu.settings=Einstellungen
 menu.settings.database=Datenbank
@@ -205,7 +208,6 @@ category.new.label.name=Name
 category.new.label.icon=Icon
 category.new.icon.remove=Entfernen
 category.new.icon.placeholder=Hier klicken um ein Icon auszuwählen
-category.new.icons=Icons
 categories.usages=Verweise
 categories.actions=Aktionen
 
@@ -353,7 +355,6 @@ about.credits=Credits:
 # REPORT
 report.settings=Einstellungen
 report.columns=Spalten auswählen
-report.columns.advice=Hinweis: Du kannst die Reihenfolge der Spalten per Drag&Drop anpassen.
 report.checkbox.include.budget=Budgetkalkulation hinzufügen
 report.checkbox.split.tables=Einnahmen und Ausgaben als getrennte Tabellen
 report.checkbox.inclue.categorybudgets=Verbrauch nach Kategorien hinzufügen
@@ -387,6 +388,7 @@ report.budget.rest=Restbudget:
 
 # filter
 filter.active=Filter aktiv
+filter.active.short=aktiv
 filter.apply=Filter anwenden
 filter.reset=Zurücksetzen
 filter.type=Art
@@ -406,7 +408,6 @@ filter.tags.button.all=Alle
 filter.tags.button.none=Keine
 
 # home menu
-home.first.use.teaser=Neu im BudgetMaster? Sieh dir die Einführung an!
 home.first.use=Tipps für die erste Benutzung
 
 home.menu.accounts=Konten erlauben es mehrere Buchungen zu gruppieren. Du kannst so viele Konten erstellen, wie du möchtest.
@@ -491,22 +492,31 @@ hotkeys.global.datepicker.today=Aktueller Monat
 
 
 # charts
+chart.display.type.pie=Torte
+chart.display.type.bar=Balken
+chart.display.type.line=Linien
+chart.display.type.custom=Benutzerdefiniert
+
+chart.group.type.none=keine
+chart.group.type.month=Monat
+chart.group.type.year=Jahr
+
 charts.default.accountSumPerDay=Kontostand pro Tag
 charts.default.accountSumPerDay.localization='{"axisY": "Summe in "'}
 charts.default.categories=Eingaben/Ausgaben nach Kategorien
-charts.default.incomesAndExpendituresPerMonthBar=Eingaben/Ausgaben pro Monat (Balkendiagramm)
+charts.default.incomesAndExpendituresPerMonthBar=Eingaben/Ausgaben
 charts.default.incomesAndExpendituresPerMonthBar.localization='{"axisY": "Summe in ", "traceName1": "Einnahmen", "traceName2": "Ausgaben"'}
-charts.default.incomesAndExpendituresPerMonthLine=Eingaben/Ausgaben pro Monat (Liniendiagramm)
+charts.default.incomesAndExpendituresPerMonthLine=Eingaben/Ausgaben
 charts.default.incomesAndExpendituresPerMonthLine.localization='{"axisY": "Summe in ", "traceName1": "Einnahmen", "traceName2": "Ausgaben"'}
-charts.default.incomesAndExpendituresByCategoryBar=Eingaben/Ausgaben nach Kategorien (Balkendiagramm)
+charts.default.incomesAndExpendituresByCategoryBar=Eingaben/Ausgaben nach Kategorien
 charts.default.incomesAndExpendituresByCategoryBar.localization='{"label1": "Ausgaben", "label2": "Einnahmen"'}
-charts.default.incomesAndExpendituresByCategoryPie=Eingaben/Ausgaben nach Kategorien (Tortendiagramm)
+charts.default.incomesAndExpendituresByCategoryPie=Eingaben/Ausgaben nach Kategorien
 charts.default.incomesAndExpendituresByCategoryPie.localization='{"label1": "Ausgaben", "label2": "Einnahmen"'}
-charts.default.incomesAndExpendituresPerMonthByCategories=Eingaben/Ausgaben pro Monat (nach Kategorien)
+charts.default.incomesAndExpendituresPerMonthByCategories=Eingaben/Ausgaben nach Kategorien
 charts.default.incomesAndExpendituresPerMonthByCategories.localization='{"label1": "Ausgaben", "label2": "Einnahmen"'}
-charts.default.restPerMonth=Rest pro Monat
+charts.default.restPerMonth=Rest
 charts.default.restPerMonth.localization='{"label1": "Rest in "'}
-charts.default.incomesAndExpendituresPerYearBar=Eingaben/Ausgaben pro Jahr (Balkendiagramm)
+charts.default.incomesAndExpendituresPerYearBar=Eingaben/Ausgaben
 charts.default.incomesAndExpendituresPerYearBar.localization='{"axisY": "Summe in ", "traceName1": "Einnahmen", "traceName2": "Ausgaben"'}
 
 chart.new.label.name=Name
@@ -543,6 +553,9 @@ chart.quick.last.month.days=Letzte 30 Tage
 chart.quick.last.year.days=Letzte 365 Tage
 chart.quick.until.today=Alle bis heute
 
+chart.button.manage=Eigene Diagramme verwalten
+chart.button.settings=Diagramm ändern
+
 statistics.number.of.accounts={0} Konten
 statistics.number.of.transactions={0} Buchungen
 statistics.number.of.templates={0} Vorlagen
@@ -557,9 +570,11 @@ entity.template=Vorlagen
 entity.chart=Diagramme
 entity.image=Bilder
 
-import.entity.category=Alle Kategorien werden nacheinander importiert.<br>Wird dabei eine Kategorie mit gleichem Namen und gleicher Farbe in der bestehenden BudgetMaster Datenbank gefunden, so werden alle Buchungen und Vorlagen, die zur Kategorie gehören in diese bestehende Kategorie verschoben.<br>Wenn keine bestehende Kategorie den gleichen Namen und die gleiche Farbe aufweist, so wird eine neue Kategorie angelegt.
-import.entity.account=Jedes zu importierende Konto wird in den weiteren Schritten des Importvorgangs einem Konto in der bestehenden Datenbank zugeordnet.<br>Die zugehörigen Buchungen und Vorlagen werden dann mit dem zugordneten Konto verknüpft.<br>Falls nicht ausreichend Konten oder kein passendes Konto existiert, können neue Konten während des Importvorgangs angelegt werden.
+import.entity.category=Alle Kategorien werden nacheinander importiert.<br>Wird dabei eine Kategorie mit gleichem Namen und gleicher Farbe in der bestehenden BudgetMaster Datenbank gefunden, so werden alle Buchungen und Vorlagen, die zur Kategorie gehören in diese bestehende Kategorie verschoben.<br>Das Icon der Kategorie wird in diesem Fall nicht angepasst.<br>Wenn keine bestehende Kategorie den gleichen Namen und die gleiche Farbe aufweist, so wird eine neue Kategorie angelegt.
+import.entity.account=Jedes zu importierende Konto wird in den weiteren Schritten des Importvorgangs einem Konto in der bestehenden Datenbank zugeordnet.<br>Die zugehörigen Buchungen und Vorlagen werden dann mit dem zugordneten Konto verknüpft.<br>Falls nicht ausreichend Konten oder kein passendes Konto existiert, können neue Konten während des Importvorgangs angelegt werden.<br>Wenn ein zu importierendes Konto ein Icon gesetzt hat, so wird das Icon im bestehenden Konto ersetzt.
 import.entity.transaction=Alle Buchungen werden nacheinander importiert und dabei dem jeweils verknüpften Konto zugeordnet.<br>Wiederholende Buchungen werden am Ende des Importvorgangs automatisch bis zum aktuellen Datum aktualisiert.
 import.entity.template=Alle Vorlagen werden nacheinander importiert und dabei die verknüpften Konten neu zugeordnet.<br>Der Import von Vorlagen ist optional.
-import.entity.image=Icons werden automatisch mit den zugehörigen Konten und Vorlagen importiert.
+import.entity.image=Icons werden automatisch mit den zugehörigen Konten, Vorlagen und Kategorien importiert.
 import.entity.chart=Es werden nur die benutzerdefinierten Diagramme importiert.<br>Der Import von Diagrammen ist optional.
+
+copied=Kopiert!
diff --git a/src/main/resources/languages/base_en.properties b/src/main/resources/languages/base_en.properties
index 5f2b3f655033105f947c3d47b1ad0022404f96fe..97c8db5b970a0daaf3422a979cc16667ede20cd2 100644
--- a/src/main/resources/languages/base_en.properties
+++ b/src/main/resources/languages/base_en.properties
@@ -1,7 +1,7 @@
 locale=en
 
 # DEFAULT
-credits=Fonts used: Roboto<br>Libraries used:<br>spring-boot-starter-parent 2.4.5<br>spring-boot-devtools 2.4.5<br>spring-boot-starter-web 2.4.5<br>spring-boot-starter-test 2.4.5<br>spring-boot-starter-data-jpa 2.4.5<br>spring-boot-starter-security 2.4.5<br>spring-boot-starter-tomcat 2.4.5<br>spring-boot-starter-freemarker 2.4.5<br>spring-boot-starter-validation 2.4.5<br>h2 1.4.199<br>joda-time 2.10.10<br>usertype.core 6.0.1.GA<br>maven-surefire-plugin 2.22.2<br>launch4j-maven-plugin 1.7.25<br>jquery 3.6.0<br>materialize 1.0.0<br>fontawesome 5.15.2<br>Google Material Icons<br>Spectrum Colorpicker 1.8.0<br>SortableJS 1.13.0<br>jlibs 3.2.0<br>itextpdf 5.5.13.2<br>mousetrap 1.6.5<br>plotly 1.58.4<br>momentjs 2.29.1<br>codemirror 5.50.0<br>webjars-locator 0.40<br>libUtils 3.2.7<br>libStorage 3.2.3<br>natorder 1.0.1<br>
+credits=Fonts used: Roboto<br>Libraries used:<br>spring-boot-starter-parent 2.4.5<br>spring-boot-devtools 2.4.5<br>spring-boot-starter-web 2.4.5<br>spring-boot-starter-test 2.4.5<br>spring-boot-starter-data-jpa 2.4.5<br>spring-boot-starter-security 2.4.5<br>spring-boot-starter-tomcat 2.4.5<br>spring-boot-starter-freemarker 2.4.5<br>spring-boot-starter-validation 2.4.5<br>h2 1.4.199<br>joda-time 2.10.10<br>usertype.core 6.0.1.GA<br>maven-surefire-plugin 2.22.2<br>launch4j-maven-plugin 1.7.25<br>jquery 3.6.0<br>materialize 1.0.0<br>fontawesome 5.15.2<br>Google Material Icons<br>Spectrum Colorpicker 1.8.0<br>SortableJS 1.13.0<br>jlibs 3.2.0<br>itextpdf 5.5.13.2<br>mousetrap 1.6.5<br>plotly 1.58.4<br>momentjs 2.29.1<br>codemirror 5.62.0<br>webjars-locator 0.41<br>libUtils 3.2.7<br>libStorage 3.2.3<br>natorder 1.0.2<br>jgit 5.12.0.202106070339-r<br>
 folder=Deadlocker/BudgetMaster
 roadmap.url=https://roadmaps.thecodelabs.de/roadmap/2
 github.url=https://github.com/deadlocker8/BudgetMaster
@@ -126,8 +126,8 @@ notification.template.delete.success=Successfully deleted template "{0}".
 notification.template.add.success=Successfully added new template "{0}".
 
 info.title.database.delete=Delete Database
-info.header.text.database.delete=Do you really want to delete the database? This can''t be undone.<br>Note: Deleting the database will delete all transactions, categories, accounts, charts, templates and images permanently.
-info.text.database.delete=Please enter the following code for verification:\t{0}
+info.header.text.database.delete=Do you really want to delete the database? This can''t be undone.<br>Note: Deleting the database will delete all transactions, categories, accounts, charts, templates and images permanently. All settings will be preserved. 
+info.text.database.delete=Please enter the following code for verification:
 info.title.database.import.dialog=Import database
 info.database.import=The following data will be imported
 info.database.import.result=Import completed
@@ -135,7 +135,6 @@ info.database.import.result.errors=Errors during import
 info.database.import.match.accounts=Assign accounts
 info.database.import.source=Import transactions from
 info.database.import.destination=to
-info.database.import.or=or
 info.title.update=Update available
 info.text.update=An update for BudgetMaster is available<br><br>Installed: v{0}<br>Available: {1}<br><br>Would you like to update now?<br><br>Note: The update may take a while depending on your internet connection. The BudgetMaster server will be restarted automatically. Please do not make any changes to accounts, transactions, categories, etc. after starting the update.
 info.title.backup.reminder=Time for a backup
@@ -154,6 +153,9 @@ delete.image.success=Successfully deleted
 delete.image.error.not.existing=Error: Image with ID {0} does not exist
 upload.image.headline=Upload image
 available.images=Available Images
+icons.images=Custom Images
+icons.builtin=Built-in Icons
+icons.numberOf=Icons
 
 notification.transaction.add.warning=Account with visibility "{0}" does not allow new transactions!
 
@@ -191,6 +193,7 @@ menu.templates=Templates
 menu.categories=Categories
 menu.charts=Charts
 menu.reports=Reports
+menu.tags=Tags
 menu.statistics=Statistics
 menu.settings=Settings
 menu.settings.database=Database
@@ -206,7 +209,6 @@ category.new.label.name=Name
 category.new.label.icon=Icon
 category.new.icon.remove=Remove
 category.new.icon.placeholder=Click here to select an icon
-category.new.icons=Icons
 categories.usages=Usages
 categories.actions=Actions
 
@@ -354,7 +356,6 @@ about.credits=Credits:
 # REPORT
 report.settings=Settings
 report.columns=Select columns
-report.columns.advice=Note: You can change the order of the columns by drag&drop.
 report.checkbox.include.budget=Include budget calculation
 report.checkbox.split.tables=Split incomes and payments into separate tables
 report.checkbox.inclue.categorybudgets=Include consumption by categories
@@ -388,6 +389,7 @@ report.budget.rest=Remaining Budget:
 
 # filter
 filter.active=Filter active
+filter.active.short=active
 filter.apply=Apply Filter
 filter.reset=Reset
 filter.type=Type
@@ -407,7 +409,6 @@ filter.tags.button.all=All
 filter.tags.button.none=None
 
 # home menu
-home.first.use.teaser=New to BudgetMaster? Check out the first use guide!
 home.first.use=First use guide
 
 home.menu.accounts=Accounts allow you to group multiple transactions. You can create as many accounts as you want.
@@ -491,22 +492,31 @@ hotkeys.global.datepicker.today.key=0
 hotkeys.global.datepicker.today=Current month
 
 # charts
+chart.display.type.pie=Pie
+chart.display.type.bar=Bar
+chart.display.type.line=Line
+chart.display.type.custom=Custom
+
+chart.group.type.none=None
+chart.group.type.month=Month
+chart.group.type.year=Year
+
 charts.default.accountSumPerDay=Account sum per day
 charts.default.accountSumPerDay.localization='{"axisY": "Sum in "'}
 charts.default.categories=Incomes/Expenditures per category
-charts.default.incomesAndExpendituresPerMonthBar=Incomes/Expenditures per month (Bar chart)
+charts.default.incomesAndExpendituresPerMonthBar=Incomes/Expenditures
 charts.default.incomesAndExpendituresPerMonthBar.localization='{"axisY": "Sum in ", "traceName1": "Incomes", "traceName2": "Expenditures"'}
-charts.default.incomesAndExpendituresPerMonthLine=Incomes/Expenditures per month (Line chart)
+charts.default.incomesAndExpendituresPerMonthLine=Incomes/Expenditures
 charts.default.incomesAndExpendituresPerMonthLine.localization='{"axisY": "Sum in ", "traceName1": "Incomes", "traceName2": "Expenditures"'}
-charts.default.incomesAndExpendituresByCategoryBar=Incomes/Expenditures by categories (Bar chart)
+charts.default.incomesAndExpendituresByCategoryBar=Incomes/Expenditures by categories
 charts.default.incomesAndExpendituresByCategoryBar.localization='{"label1": "Expenditures", "label2": "Incomes"'}
-charts.default.incomesAndExpendituresByCategoryPie=Incomes/Expenditures by categories (Pie chart)
+charts.default.incomesAndExpendituresByCategoryPie=Incomes/Expenditures by categories
 charts.default.incomesAndExpendituresByCategoryPie.localization='{"label1": "Expenditures", "label2": "Incomes"'}
-charts.default.incomesAndExpendituresPerMonthByCategories=Incomes/Expenditures per month (By categories)
+charts.default.incomesAndExpendituresPerMonthByCategories=Incomes/Expenditures by categories
 charts.default.incomesAndExpendituresPerMonthByCategories.localization='{"label1": "Expenditures", "label2": "Incomes"'}
-charts.default.restPerMonth=Rest per month
+charts.default.restPerMonth=Rest
 charts.default.restPerMonth.localization='{"label1": "Rest in "'}
-charts.default.incomesAndExpendituresPerYearBar=Incomes/Expenditures per year (Bar chart)
+charts.default.incomesAndExpendituresPerYearBar=Incomes/Expenditures
 charts.default.incomesAndExpendituresPerYearBar.localization='{"axisY": "Sum in ", "traceName1": "Incomes", "traceName2": "Expenditures"'}
 
 chart.new.label.name=Name
@@ -542,6 +552,9 @@ chart.quick.last.month.days=Last 30 days
 chart.quick.last.year.days=Last 365 days
 chart.quick.until.today=Until today
 
+chart.button.manage=Manage custom charts
+chart.button.settings=Change chart
+
 statistics.number.of.accounts={0} Accounts
 statistics.number.of.transactions={0} Transactions
 statistics.number.of.templates={0} Templates
@@ -556,9 +569,11 @@ entity.template=Templates
 entity.chart=Charts
 entity.image=Images
 
-import.entity.category=All categories will be imported one by one.<br>If a category with the same name and color already exists in the BudgetMaster database, all transactions and templates belonging to the category will be moved to this existing category.<br>If no existing category has the same name and color, a new category will be created.
-import.entity.account=Each account to be imported will be assigned to an existing account in the database during the next steps of the import process.<br>The associated transactions and templates will then be linked to the assigned account.<br>If there are not enough accounts or no matching account, new accounts can be created during the import process.
+import.entity.category=All categories will be imported one by one.<br>If a category with the same name and color already exists in the BudgetMaster database, all transactions and templates belonging to the category will be moved to this existing category.<br>The category icon will not be updated in this case.<br>If no existing category has the same name and color, a new category will be created.
+import.entity.account=Each account to be imported will be assigned to an existing account in the database during the next steps of the import process.<br>The associated transactions and templates will then be linked to the assigned account.<br>If there are not enough accounts or no matching account, new accounts can be created during the import process.<br>If an account has an icon set, the icon in the existing account will be replaced.
 import.entity.transaction=All transactions will be imported one by one, assigning them to the respective linked account.<br>Recurring transactions are automatically updated to the current date at the end of the import process.
 import.entity.template=All templates will be imported one by one, reassigning the linked accounts.<br>The import of templates is optional.
-import.entity.image=Icons are automatically imported with their associated accounts and templates.
+import.entity.image=Icons are automatically imported with their associated accounts, templates and categories.
 import.entity.chart=Only user-defined charts will be imported.<br>The import of charts is optional.
+
+copied=Copied!
diff --git a/src/main/resources/languages/hints_de.properties b/src/main/resources/languages/hints_de.properties
new file mode 100644
index 0000000000000000000000000000000000000000..3ac80895806ab9e8887a75bc2e164f5a4c25627d
--- /dev/null
+++ b/src/main/resources/languages/hints_de.properties
@@ -0,0 +1,10 @@
+headline.hints=Tipps
+button.hints.reset=Alle Tipps zurücksetzen
+notification.hints.reset=Alle Tipps zurückgesetzt
+
+hint.first.use.teaser=Neu im BudgetMaster? Sieh dir die Einführung an!
+hint.report.columns=Tipp: Du kannst die Reihenfolge der Spalten per Drag&Drop anpassen
+hint.template.arrow.keys=Tipp: Du kannst eine Vorlage mit den Pfeiltasten auswählen und mit Enter bestätigen
+hint.transaction.save=Tipp: Nutze Strg+Enter zum Speichern der Buchung
+hint.globalDatePicker.hotkeys=Tipp: Sieh dir die Tastenkombinationen für die Monatsauswahl an
+hint.icon.upload.image.size=Tipp: Quadratische Bilder sind am besten geeignet
diff --git a/src/main/resources/languages/hints_en.properties b/src/main/resources/languages/hints_en.properties
new file mode 100644
index 0000000000000000000000000000000000000000..1eb9d1fe533fbd54b8ada4e7cb4ba68c0fdc97ed
--- /dev/null
+++ b/src/main/resources/languages/hints_en.properties
@@ -0,0 +1,10 @@
+headline.hints=Hints
+button.hints.reset=Reset all hints
+notification.hints.reset=All hints reset
+
+hint.first.use.teaser=New to BudgetMaster? Check out the first use guide!
+hint.report.columns=Hint: You can change the order of the columns by drag&drop
+hint.template.arrow.keys=Hint: You can select a template by using the arrow keys and confirm with enter
+hint.transaction.save=Hint: Use Ctrl+Enter to save the transaction
+hint.globalDatePicker.hotkeys=Hint: Have a look at the hotkeys for month selection
+hint.icon.upload.image.size=Hint: Square images will be best choice
diff --git a/src/main/resources/languages/news_de.properties b/src/main/resources/languages/news_de.properties
index d07e783300435e0637ffbfddfc61bb1d179fe692..b068042cb224d99a260fe2ae325beffa2954a4cf 100644
--- a/src/main/resources/languages/news_de.properties
+++ b/src/main/resources/languages/news_de.properties
@@ -2,35 +2,29 @@ news.further.information=Weitere Informationen
 news.all.releases=Alle veröffentlichten und geplanten Versionen:
 news.detailed=Ausführliches Changelog (nur auf Englisch):
 
-news.fix.backup.size.headline=Fix für Dateigröße des Backups
-news.fix.backup.size.description=Größe der Backupdateien massiv optimiert.
+news.chartChooser.headline=Neue Diagrammauswahl
+news.chartChooser.description=Vollständige Neugestaltung der Diagrammauswahlseite für bessere Benutzbarkeit.
 
-news.fix.readonly.accounts.headline=Fix für Konten mit Lesezugriff
-news.fix.readonly.accounts.description=Verhindert das Anlegen neuer Buchungen für Konten mit der Sichtbarkeit "Lesezugriff".
+news.jumpToSearch.headline=Zur Suche springen
+news.jumpToSearch.description=Direkt aus der Übersicht der Konten, Kategorien und Tags kann nun zur Suche gesprungen werden.
 
-news.designOffensive.headline=Die Designoffensive
-news.designOffensive.description=Wähle für Kategorien ein Icon aus einer vordefinierten Bibliothek oder lade für Konten und Vorlagen eigene Bilder als Icon hoch.<br>Kategorien können in der Buchungsübersicht jetzt auch als Quadrate statt Kreise dargestellt werden.<br>Das gesamte Design wurde verbessert, z.B. durch Icons an Überschriften und Formularfeldern, Benachrichtigungsbannern, uvm.
+news.fontAwesomeIcons.headline=Fontawesome Icons
+news.fontAwesomeIcons.description=Neben Kategorien können nun auch für Konten und Vorlagen Fontawesome Icons gewählt werden, anstatt nur eigene Bilder.
 
-news.gitBackup.headline=Git Backup
-news.gitBackup.description=Backups der Datenbank können nun auch automatisch in ein lokaless oder entferntes Git-Repository eingecheckt werden.
+news.nonSquareImages.headline=Nicht quadratische Bilder
+news.nonSquareImages.description=Unterstützung für nicht quadratische Konto-, Kategorie- und Vorlagenicons hinzugefügt.
 
-news.backupCharts.headline=Diagramme ins Backup aufnehmen
-news.backupCharts.description=Benutzerdefinierte Diagramme werden beim Exportieren der Datenbank mit gesichert.
+news.hints.headline=Tipps zur Benutzung
+news.hints.description=Diverse nützliche Tipps hinzugefügt, die als Informationsboxen angezeigt werden. Die Tipps lassen sich ausblenden.
 
-news.importProcess.headline=Neugestaltung des Importvorgangs
-news.importProcess.description=Der Importvorgang wurde in mehrere Schritte aufgeteilt, es wurden Erklärungen hinzugefügt und das Design verbessert.
+news.tagOverview.headline=Tagübersicht
+news.tagOverview.description=Neue Seite hinzugefügt, die die verwendeten Tag-Namen und ihre Verwendungsanzahl zeigt.
 
-news.hideAccounts.headline=Konten ausblenden
-news.hideAccounts.description=Konten und die zugehörigen Buchungen lassen sich neben schreibgeschützt auch auch in den Zustand "versteckt" versetzen und damit komplett ausblenden.
+news.accountImport.headline=Verbesserter Import von Konten
+news.accountImport.description=Die Kontozuweisung im Importvorgang wird gespeichert und es wird nur noch ein Button zum Anlegen eines neuen Kontos angezeigt.
 
-news.statistics.headline=Statistiken
-news.statistics.description=Einige Statistiken der BudgetMaster-Instant werden auf der neuen Statistikseite visualisiert.
+news.performance.headline=Verbesserung der Performance
+news.performance.description=Bilder werden nur noch aus der Datenbank geladen, wenn diese auch benötigt werden. Insbesondere bei der Anzeige von Diagrammen sorgt das für verbesserte Performance.
 
-news.hotkeysMonth.headline=Tastenkombinationen zum Wechseln des Monats
-news.hotkeysMonth.description=Zum vorherigen oder nächsten Monat mithilfe der Pfeiltasten springen.
-
-news.importBugfixes.headline=Bugfixes beim Datenbankimport
-news.importBugfixes.description=Mehrere Bugfixes für Probleme beim Datenbankimport.
-
-news.chartRelative.headline=Diagramm: "Eingaben/Ausgaben pro Monat (nach Kategorien)"
-news.chartRelative.description=Die Balkengrößen sind nun relativ zueinander statt zu jeweils 100% anzuzeigen.
+news.fix.transfersFromHiddenAccounts.headline=Bugfix für versteckte Konten
+news.fix.transfersFromHiddenAccounts.description=Behebt das Problem, dass Umbuchungen aus versteckten Konten ebenfalls versteckt wurden.
diff --git a/src/main/resources/languages/news_en.properties b/src/main/resources/languages/news_en.properties
index 360a97e0cebff13aca8e4d91abdc1994ca33c598..bd3fafa72e6953b44d594599af07d7569184a45a 100644
--- a/src/main/resources/languages/news_en.properties
+++ b/src/main/resources/languages/news_en.properties
@@ -2,35 +2,29 @@ news.further.information=Further information
 news.all.releases=All published and planned releases:
 news.detailed=More detailed changelog (english only):
 
-news.fix.backup.size.headline=Fix for backup file size
-news.fix.backup.size.description=Dramatically optimized the size of the backup files.
+news.chartChooser.headline=Improved chart chooser
+news.chartChooser.description=Completely re-design the chart chooser page to increase usability.
 
-news.fix.readonly.accounts.headline=Fix for read-only accounts
-news.fix.readonly.accounts.description=Prevents the creation of new transactions for read-only accounts.
+news.jumpToSearch.headline=Jump to search
+news.jumpToSearch.description=Directly jump to search from accounts, categories and tags overview.
 
-news.designOffensive.headline=The design offensive
-news.designOffensive.description=Choose from a set of pre-defined set of icons for categories or upload your own images for accounts and templates.<br>Category circles can now be displayed as squares.<br>Improved overall design by adding icons to headlines and form inputs, notification banners, etc.
+news.fontAwesomeIcons.headline=Fontawesome Icons
+news.fontAwesomeIcons.description=Fontawesome icons can now be used for accounts and templates too instead of only for categories.
 
-news.gitBackup.headline=Git backup
-news.gitBackup.description=Schedule an automatic export of your database content and commit to a local or remote git repository.
+news.nonSquareImages.headline=Non square images
+news.nonSquareImages.description=Added support for non square account, category and template icons.
 
-news.backupCharts.headline=Backup charts
-news.backupCharts.description=Custom charts are now included in the in backups.
+news.hints.headline=Usability hints
+news.hints.description=Added several dismissible information boxes showing useful hints.
 
-news.importProcess.headline=Re-designed import process
-news.importProcess.description=The import process is now split into multiple steps, featuring explanations and an improved design.
+news.tagOverview.headline=Tag overview
+news.tagOverview.description=New page for viewing tag names and how often they are used.
 
-news.hideAccounts.headline=Hide accounts
-news.hideAccounts.description=In addition to mark an account as readonly it is now possible to hide the account and all corresponding transactions completely.
+news.accountImport.headline=Improved account import
+news.accountImport.description=Remember account matching during import and show only one button to create a new account.
 
-news.statistics.headline=Statistics
-news.statistics.description=Some numbers of your BudgetMaster instance will be visualized on the new statistics page.
+news.performance.headline=Improve performance
+news.performance.description=Images are only loaded from database when needed. This improves performance, especially when displaying charts.
 
-news.hotkeysMonth.headline=Hotkeys to switch months
-news.hotkeysMonth.description=Switch to the previous or next month using the arrow keys.
-
-news.importBugfixes.headline=Bugfixes for database import
-news.importBugfixes.description=Several bugfixes for problems during database import.
-
-news.chartRelative.headline=Chart: "incomes and expenditures per month by categories"
-news.chartRelative.description=The bar sizes are now relative to each other instead of 100% each.
+news.fix.transfersFromHiddenAccounts.headline=Bugfix hidden accounts
+news.fix.transfersFromHiddenAccounts.description=Fixes a bug that caused transfers from hidden accounts to be hidden as well.
diff --git a/src/main/resources/static/css/categories.css b/src/main/resources/static/css/categories.css
index a67f029e2561c89473ff0d4aa60edbf1744319fd..6f457fe3e66b0ccaf0b11f2e1cd7acfc62b6c831 100644
--- a/src/main/resources/static/css/categories.css
+++ b/src/main/resources/static/css/categories.css
@@ -9,6 +9,10 @@
     font-size: 20px;
 }
 
+.category-circle img {
+    object-fit: contain;
+}
+
 .category-circle .fa,
 .category-circle .fab,
 .category-circle .fad,
@@ -18,6 +22,12 @@
     line-height: 40px;
 }
 
+.category-icon:not(i) {
+    height: 100%;
+    width: 100%;
+    padding: 15%;
+}
+
 .category-circle-small {
     width: 34px;
     height: 34px;
@@ -67,56 +77,6 @@
     overflow-y: visible !important;
 }
 
-#category-icon {
-    margin-top: 3rem;
-    justify-content: center;
-}
-
-#category-icon-preview {
-    text-align: center;
-    border: 2px solid var(--color-text);
-    padding: 1rem;
-    color: var(--color-text);
-}
-
-#category-icon-preview i {
-    font-size: 3rem;
-}
-
-#button-remove-category-icon {
-    margin-left: 1rem;
-}
-
-#button-remove-category-icon i {
-    font-size: 1.8rem;
-}
-
-.category-icon-option-column {
-    text-align: center;
-    margin-bottom: 1.5rem;
-}
-
-.category-icon-option {
-    padding: 0.5rem;
-    border: 2px solid transparent;
-}
-
-.category-icon-option:hover {
-    cursor: pointer;
-}
-
-.category-icon-option.selected {
-    border: 2px solid var(--color-text);
-}
-
-.category-icon-option-icon {
-    font-size: 2rem;
-}
-
-#numberOfIcons {
-    font-size: 1.1rem;
-}
-
 /*style spectrum color picker*/
 
 /*hide spectrum color picker arrow*/
diff --git a/src/main/resources/static/css/charts.css b/src/main/resources/static/css/charts.css
index 26fb34b1055d2fd4299b65c019ccedf6e654e612..5f67ce9a50ddb99566ec0e6fdc6d52327705c54a 100644
--- a/src/main/resources/static/css/charts.css
+++ b/src/main/resources/static/css/charts.css
@@ -3,16 +3,25 @@
 }
 
 .quick-date {
-    color: #039be5;
+    color: var(--color-blue);
     text-align: center;
     padding: 0 0 10px 0;
 }
 
+[data-theme="dark"]  .quick-date {
+    color: #BDFF3F;
+}
+
 .quick-date:hover {
     cursor: pointer;
     text-decoration: underline var(--color-blue);
 }
 
+[data-theme="dark"] .quick-date:hover {
+    cursor: pointer;
+    text-decoration: underline #BDFF3F;
+}
+
 .container-chart {
     width: 90%;
     margin: auto;
@@ -30,4 +39,62 @@
 
 .CodeMirror-scroll {
     height: auto;
+}
+
+.headline-chart-step {
+    font-size: 1.2rem;
+}
+
+.chart-preview {
+    background-color: var(--color-grey-ccc);
+}
+
+[data-theme="dark"] .chart-preview {
+    background-color: var(--color-grey-dark);
+}
+
+.chart-preview:hover {
+    cursor: pointer;
+}
+
+.chart-preview .card-action {
+    word-break: break-word;
+    color: #212121;
+    min-height: 5rem;
+    padding: 1rem;
+}
+
+[data-theme="dark"] .button-display-type,
+[data-theme="dark"] .button-group-type {
+    background-color: var(--color-grey) !important;
+}
+
+.button-display-type,
+.button-group-type {
+    background-color: var(--color-grey-ccc) !important;
+}
+
+.button-display-type.active {
+    background-color: var(--color-green) !important;
+}
+
+.button-group-type.active {
+    background-color: var(--color-blue-baby) !important;
+}
+
+.chart-preview.active .card-action {
+    background-color: var(--color-red-light) !important;
+}
+
+#chart-date-card {
+    background-color: var(--color-white);
+}
+
+[data-theme="dark"] #chart-date-card {
+    background-color: var(--color-background-light);
+}
+
+#filterActiveBadge {
+    float: none;
+    margin-left: 1rem;
 }
\ No newline at end of file
diff --git a/src/main/resources/static/css/colors.css b/src/main/resources/static/css/colors.css
index e0a884ec1a760e57f1b0a02f765ede531f5478e7..1180c620228b1cbc519d06d06cea682b76f319a0 100644
--- a/src/main/resources/static/css/colors.css
+++ b/src/main/resources/static/css/colors.css
@@ -19,6 +19,7 @@
     --color-grey: #696969;
     --color-grey-dark: rgba(0, 0, 0, 0.25);
     --color-grey-dark-almost-transparent: rgba(0, 0, 0, 0.08);
+    --color-grey-ccc: #CCCCCC;
     --color-black: rgba(0, 0, 0, 0.87);
 
     --color-text: #212121;
@@ -34,7 +35,7 @@
     --color-blue-light: rgba(80, 115, 146, 0.8);
     --color-yellow: #E9C46A;
     --color-grey-light: #333333;
-    --color-grey: #CCCCCC;
+    --color-grey: var(--color-grey-ccc);
     --color-grey-dark: rgba(255, 255, 255, 0.5);
     --color-grey-dark-almost-transparent: rgba(255, 255, 255, 0.125);
 
diff --git a/src/main/resources/static/css/imageSelect.css b/src/main/resources/static/css/iconSelect.css
similarity index 61%
rename from src/main/resources/static/css/imageSelect.css
rename to src/main/resources/static/css/iconSelect.css
index 8d3d947f05d5b2863bf9b7cacd323fc0b07f8e35..23cc2987afcb40d4af2844559fa3e14a9572d750 100644
--- a/src/main/resources/static/css/imageSelect.css
+++ b/src/main/resources/static/css/iconSelect.css
@@ -10,6 +10,10 @@
     color: var(--color-text);
 }
 
+#item-icon-preview i {
+    font-size: 3rem;
+}
+
 .button-remove-icon-from-item {
     margin-left: 1rem;
 }
@@ -18,24 +22,36 @@
     font-size: 1.8rem;
 }
 
-.item-icon-option-column {
+.item-icon-option-column,
+.builtin-icon-option-column {
     text-align: center;
     margin-bottom: 1.5rem;
 }
 
-.item-icon-option {
+.item-icon-option,
+.builtin-icon-option {
     padding: 0.5rem;
     border: 2px solid transparent;
 }
 
-.item-icon-option:hover {
+.item-icon-option:hover,
+.builtin-icon-option:hover {
     cursor: pointer;
 }
 
-.item-icon-option.selected {
+.item-icon-option.selected,
+.builtin-icon-option.selected {
     border: 2px solid var(--color-text);
 }
 
+.builtin-icon-option-icon {
+    font-size: 2rem;
+}
+
+#numberOfIcons {
+    font-size: 1.1rem;
+}
+
 .item-icon-preview-icon {
     height: 5rem;
 }
@@ -44,8 +60,10 @@
     cursor: pointer;
 }
 
-.item-icon-preview  {
+.item-icon-preview {
     height: 5rem;
+    width: 100%;
+    object-fit: contain;
 }
 
 .item-icon-option-delete span {
@@ -62,4 +80,12 @@
 
 .item-icon-option-delete-confirm span {
     display: inline-block;
+}
+
+#progressIndicator {
+    margin-top: 3rem;
+}
+
+#progressIndicator .spinner-blue-only {
+    border-color: var(--color-blue);
 }
\ No newline at end of file
diff --git a/src/main/resources/static/css/reports.css b/src/main/resources/static/css/reports.css
index f3dc35b785ce43af4ae9bc6a775b663c746c62b2..796f133be1867fd1626d57982218abc0074f8729 100644
--- a/src/main/resources/static/css/reports.css
+++ b/src/main/resources/static/css/reports.css
@@ -17,6 +17,7 @@
     padding: 0.5rem 1rem;
     border-bottom: 1px solid rgba(0, 0, 0, 0.25);
     background-color: var(--color-white);
+    cursor: pointer;
 }
 
 .columnName-checkbox-label {
@@ -36,24 +37,6 @@
     color: #878787;
 }
 
-.table-advice {
-    width: auto;
-    margin: 1vmin;
-    border: 2px solid var(--color-text);
-    border-radius: 5px;
-    padding: 0 1vmin;
-    display: inline-block;
-}
-
-.table-advice td {
-    padding: 10px;
-    font-size: 1.5vmin;
-}
-
-.table-advice i {
-    font-size: 2.5vmin;
-}
-
 .columnName-selected {
     background-color: var(--color-blue-light);
 }
diff --git a/src/main/resources/static/css/settings.css b/src/main/resources/static/css/settings.css
index 40077499bafbb3fd4d092369ec6ffb22c422aeb6..f51ab4bd82713f613b6ccc58ca272e79272f0441 100644
--- a/src/main/resources/static/css/settings.css
+++ b/src/main/resources/static/css/settings.css
@@ -19,4 +19,15 @@
     height: 1.5em;
     margin-top: 2em;
     margin-bottom: 2em;
+}
+
+#verificationCode {
+    font-weight: bold;
+    margin-left: 1rem;
+    border: 2px solid var(--color-text);
+    padding: 0.3rem 0.5rem;
+}
+
+#verificationCode:hover {
+    cursor: pointer;
 }
\ No newline at end of file
diff --git a/src/main/resources/static/css/style.css b/src/main/resources/static/css/style.css
index b9dbc957be20c29fec019b602aa510fd0f6c399a..679e36d1bfc55bcffa6d4a4b6ddb6525ff152b57 100644
--- a/src/main/resources/static/css/style.css
+++ b/src/main/resources/static/css/style.css
@@ -20,7 +20,7 @@ main {
     margin-bottom: 24px;
 }
 
-.btn, .btn-flat {
+.btn, .btn-flat, .btn-large {
     text-transform: none;
     font-weight: 600;
 }
@@ -236,11 +236,13 @@ main {
     font-size: 2vmin;
 }
 
-.notification-clear i {
+.notification-clear i,
+.hint-clear i {
     font-size: 1.8vmin;
 }
 
-.notification-clear:hover {
+.notification-clear:hover,
+.hint-clear:hover {
     cursor: pointer;
 }
 
@@ -445,7 +447,7 @@ input[type="radio"]:checked + span::after, [type="radio"].with-gap:checked + spa
     line-height: 2.6rem;
 }
 
-.account-icon  {
+.account-icon {
     height: 2.6rem;
 }
 
@@ -457,6 +459,40 @@ input[type="radio"]:checked + span::after, [type="radio"].with-gap:checked + spa
     cursor: pointer;
 }
 
+.tabs {
+    margin-bottom: 1.5rem;
+}
+
+.tabs .tab {
+    text-transform: none;
+    font-weight: bold;
+}
+
+.tabs .tab i {
+    font-size: 1.5rem;
+    margin-right: 0.5rem;
+}
+
+.tabs .tab a {
+    font-size: 1.1rem;
+    background-color: #DDDDDD;
+}
+
+.tabs .tab a:hover {
+    background-color: #EEEEEE;
+}
+
+.tabs .tab a:focus,
+.tabs .tab a:focus.active,
+.tabs .tab a.active {
+    background-color: #EEEEEE;
+}
+
+.tabs .indicator {
+    background-color: var(--color-blue);
+    height: 3px;
+}
+
 .invisible {
     opacity: 0;
 }
@@ -527,6 +563,19 @@ input[type="radio"]:checked + span::after, [type="radio"].with-gap:checked + spa
     .template-header-name {
         max-width: 40% !important;
     }
+
+    .notification {
+        font-size: 3.5vmin;
+    }
+
+    .notification i {
+        font-size: 4.3vmin;
+    }
+
+    .notification-clear i,
+    .hint-clear i {
+        font-size: 4vmin;
+    }
 }
 
 /* dark theme */
@@ -680,7 +729,6 @@ input[type="radio"]:checked + span::after, [type="radio"].with-gap:checked + spa
     box-shadow: 0 1px 0 0 var(--color-blue) !important;
 }
 
-
 .debug {
     border: 1px solid red;
 }
\ No newline at end of file
diff --git a/src/main/resources/static/images/charts/accountSumPerDay.png b/src/main/resources/static/images/charts/accountSumPerDay.png
new file mode 100644
index 0000000000000000000000000000000000000000..7a877f9bbaf360158e9f691bfb2338e5a41e62af
Binary files /dev/null and b/src/main/resources/static/images/charts/accountSumPerDay.png differ
diff --git a/src/main/resources/static/images/charts/incomesAndExpendituresByCategoryBar.png b/src/main/resources/static/images/charts/incomesAndExpendituresByCategoryBar.png
new file mode 100644
index 0000000000000000000000000000000000000000..e14fcbee12e1397f9578638cf8930c0734b3a6fe
Binary files /dev/null and b/src/main/resources/static/images/charts/incomesAndExpendituresByCategoryBar.png differ
diff --git a/src/main/resources/static/images/charts/incomesAndExpendituresByCategoryPie.png b/src/main/resources/static/images/charts/incomesAndExpendituresByCategoryPie.png
new file mode 100644
index 0000000000000000000000000000000000000000..5d9adfbe5a7186f8e0793597fa728993e65d369d
Binary files /dev/null and b/src/main/resources/static/images/charts/incomesAndExpendituresByCategoryPie.png differ
diff --git a/src/main/resources/static/images/charts/incomesAndExpendituresPerMonthBar.png b/src/main/resources/static/images/charts/incomesAndExpendituresPerMonthBar.png
new file mode 100644
index 0000000000000000000000000000000000000000..fefe0f517e41be7a9a3101b5f4dbf7bd365eb980
Binary files /dev/null and b/src/main/resources/static/images/charts/incomesAndExpendituresPerMonthBar.png differ
diff --git a/src/main/resources/static/images/charts/incomesAndExpendituresPerMonthByCategories.png b/src/main/resources/static/images/charts/incomesAndExpendituresPerMonthByCategories.png
new file mode 100644
index 0000000000000000000000000000000000000000..ed2ff0f59f6729db7c5e5431ecdd750654c51856
Binary files /dev/null and b/src/main/resources/static/images/charts/incomesAndExpendituresPerMonthByCategories.png differ
diff --git a/src/main/resources/static/images/charts/incomesAndExpendituresPerMonthLine.png b/src/main/resources/static/images/charts/incomesAndExpendituresPerMonthLine.png
new file mode 100644
index 0000000000000000000000000000000000000000..ca1b90cda14c27424e44ce253d45f0e5c2406b07
Binary files /dev/null and b/src/main/resources/static/images/charts/incomesAndExpendituresPerMonthLine.png differ
diff --git a/src/main/resources/static/images/charts/incomesAndExpendituresPerYearBar.png b/src/main/resources/static/images/charts/incomesAndExpendituresPerYearBar.png
new file mode 100644
index 0000000000000000000000000000000000000000..7e89163734c2c7a1fbbac7c4d5481937e18afdd3
Binary files /dev/null and b/src/main/resources/static/images/charts/incomesAndExpendituresPerYearBar.png differ
diff --git a/src/main/resources/static/images/charts/placeholder.png b/src/main/resources/static/images/charts/placeholder.png
new file mode 100644
index 0000000000000000000000000000000000000000..0d5a321ff69150bd2ca80b811c93f65fcead2387
Binary files /dev/null and b/src/main/resources/static/images/charts/placeholder.png differ
diff --git a/src/main/resources/static/images/charts/restPerMonth.png b/src/main/resources/static/images/charts/restPerMonth.png
new file mode 100644
index 0000000000000000000000000000000000000000..0687ca6a120adae266833f7cae41cacd622dfe32
Binary files /dev/null and b/src/main/resources/static/images/charts/restPerMonth.png differ
diff --git a/src/main/resources/static/js/accounts.js b/src/main/resources/static/js/accounts.js
index fa8533f9d8046356df466c344294f63f7b2c3987..011c41f15f42a2a1907ba7f63d525259947ec8d9 100644
--- a/src/main/resources/static/js/accounts.js
+++ b/src/main/resources/static/js/accounts.js
@@ -1,10 +1,5 @@
 $(document).ready(function()
 {
-    if($('#modalConfirmDelete').length)
-    {
-        $('#modalConfirmDelete').modal('open');
-    }
-
     if($('#modalAccountNotDeletable').length)
     {
         $('#modalAccountNotDeletable').modal('open');
@@ -14,4 +9,9 @@ $(document).ready(function()
     {
         document.getElementById('account-name').focus();
     }
+
+    $('.button-request-delete-account').click(function()
+    {
+        fetchAndShowModalContent(this.dataset.url, '#deleteModalContainerOnDemand', '#modalConfirmDelete', function(){});
+    });
 });
diff --git a/src/main/resources/static/js/categories.js b/src/main/resources/static/js/categories.js
index 810838aa93ba7e3ea55f60f459d4922a5bf15369..b3479347e2ff0a843a36757efda57f0fa04097c5 100644
--- a/src/main/resources/static/js/categories.js
+++ b/src/main/resources/static/js/categories.js
@@ -1,7 +1,5 @@
 $(document).ready(function()
 {
-    $('#modalConfirmDelete').modal('open');
-
     if($('#category-name').length)
     {
         document.getElementById('category-name').focus();
@@ -35,75 +33,17 @@ $(document).ready(function()
         });
     }
 
-    $('#buttonDeleteCategory').click(function()
-    {
-        document.getElementById("formDestinationCategory").submit();
-    });
-
-    $('#button-remove-category-icon').click(function()
-    {
-        document.getElementById("category-icon-preview-icon").classList.toggle('hidden', true);
-        document.getElementById("category-icon-placeholder").classList.toggle('hidden', false);
-        document.getElementById("hidden-input-category-icon").value = '';
-    });
-
-    $('#button-category-icon-confirm').click(function()
-    {
-        let icon = document.querySelector('.category-icon-option.selected .category-icon-option-name');
-        if(icon === null)
-        {
-            return false;
-        }
-
-        icon = icon.textContent;
-
-        let previewIcon = document.getElementById("category-icon-preview-icon");
-        previewIcon.className = '';  // clear class list
-
-        icon.split(' ').forEach(function(cssClass)
-        {
-            previewIcon.classList.add(cssClass);
-        });
-
-        document.getElementById("category-icon-placeholder").classList.toggle('hidden', true);
-        document.getElementById("hidden-input-category-icon").value = icon;
-    });
-
-    // select an icon option
-    $('.category-icon-option').click(function()
-    {
-        let allIconOptions = document.querySelectorAll('.category-icon-option');
-        for(let i = 0; i < allIconOptions.length; i++)
-        {
-            allIconOptions[i].classList.remove('selected');
-        }
-
-        this.classList.add('selected');
-        document.getElementById('button-category-icon-confirm').removeAttribute('disabled');
-    });
-
-    if($('#modalIconSelect').length)
+    $('.button-request-delete-category').click(function()
     {
-        let modalIconSelect = document.getElementById('modalIconSelect');
-        M.Modal.init(modalIconSelect, {
-            onOpenEnd: function f()
-            {
-                document.getElementById('searchIcons').focus();
-            },
-            onCloseEnd: function f()
-            {
-                document.getElementById('category-name').focus();
-            }
-        });
+        fetchAndShowModalContent(this.dataset.url, '#deleteModalContainerOnDemand', '#modalConfirmDelete', function(){
+            initCustomSelects();
 
-        modalIconSelect.addEventListener('keypress', function(event)
-        {
-            if(event.key === 'Enter')
+            $('#buttonDeleteCategory').click(function()
             {
-                event.preventDefault();
-            }
-        });
-    }
+                document.getElementById("formDestinationCategory").submit();
+            });
+         });
+    });
 });
 
 function removeActive()
@@ -114,26 +54,3 @@ function removeActive()
         removeClass(colors[i], "category-color-active");
     }
 }
-
-function searchCategoryIcons()
-{
-    let searchWord = document.getElementById('searchIcons').value.toLowerCase();
-
-    let allIcons = document.querySelectorAll('.category-icon-option-column');
-    let numberOfMatchingIcons = 0;
-    for(let i = 0; i < allIcons.length; i++)
-    {
-        let iconName = allIcons[i].querySelector('.category-icon-option-name').textContent;
-        if(iconName.toLowerCase().includes(searchWord))
-        {
-            allIcons[i].classList.toggle('hidden', false);
-            numberOfMatchingIcons++;
-        }
-        else
-        {
-            allIcons[i].classList.toggle('hidden', true);
-        }
-    }
-
-    document.getElementById('numberOfMatchingIcons').innerText = numberOfMatchingIcons.toString();
-}
\ No newline at end of file
diff --git a/src/main/resources/static/js/charts.js b/src/main/resources/static/js/charts.js
index a832f062a9dbf9dde54e4c13471aab55a3fec446..a1eddfc840e9fba5e8c918f7beb962983265460f 100644
--- a/src/main/resources/static/js/charts.js
+++ b/src/main/resources/static/js/charts.js
@@ -1,4 +1,3 @@
-let modalFilter;
 let chartPickerStartDate;
 let chartPickerEndDate;
 
@@ -14,16 +13,6 @@ $(document).ready(function()
         editor.save();
     }
 
-    if($("#modalConfirmDelete").length)
-    {
-        $('#modalConfirmDelete').modal('open');
-    }
-
-    if($("#modalFilter").length)
-    {
-        modalFilter = $('#modalFilter').modal();
-    }
-
     if($(".datepicker").length)
     {
         chartPickerStartDate = M.Datepicker.init(document.getElementById('chart-datepicker'), {
@@ -42,6 +31,7 @@ $(document).ready(function()
                 weekdaysAbbrev: weekDaysLetters,
 
                 // Buttons
+                cancel: buttonCancel,
                 done: buttonClose,
 
                 // Accessibility labels
@@ -71,21 +61,77 @@ $(document).ready(function()
         }
     }
 
-    $(".filter-button-close").click(function()
-    {
-        applyFilter(modalFilter);
-    });
-
     $(".filter-button-reset").click(function()
     {
         resetFilter();
-        applyFilter(modalFilter);
+        applyFilter();
     });
 
     $(".quick-date").click(function()
     {
         handleQuickDate(this);
     });
+
+    $('.button-display-type').click(function()
+    {
+        toggleChartTypeButtons('button-display-type', this);
+        hideGroupTypeButtonsIfOnlyOneDistinctGroup();
+        filterChartPreviews('');
+    });
+
+    $('.button-group-type').click(function()
+    {
+        toggleChartTypeButtons('button-group-type', this);
+        filterChartPreviews('');
+    });
+
+    $('.chart-preview-column').click(function()
+    {
+        unsetActiveChartPreview('');
+
+        this.querySelector('.chart-preview').classList.toggle('active', true);
+        document.getElementsByName('displayType')[0].value = this.dataset.displayType;
+        document.getElementsByName('groupType')[0].value = this.dataset.groupType;
+        document.getElementsByName('chartID')[0].value = this.dataset.id;
+        checkShowChartButton();
+    });
+
+    let filterCheckBoxes = document.querySelectorAll('#filterSettings input[type=checkbox]');
+    for(let i = 0; i < filterCheckBoxes.length; i++)
+    {
+        filterCheckBoxes[i].addEventListener('change', (event) =>
+        {
+            applyFilter();
+        });
+    }
+
+    $('#filter-name').on('change keydown paste input', function()
+    {
+        applyFilter();
+    });
+
+    $('#buttonShowChartSettings').click(function()
+    {
+        document.getElementsByName('NewChartSettings')[0].classList.toggle('hidden', false);
+        document.getElementById('buttonShowChartSettings').classList.toggle('hidden', true);
+
+        checkShowChartButton();
+    });
+
+    if($(".chart-preview-column").length)
+    {
+        filterChartPreviews(document.getElementsByName('chartID')[0].value);
+
+        let showEditSettingsButton = document.getElementsByName('NewChartSettings')[0].classList.contains('hidden');
+        document.getElementById('buttonShowChartSettings').classList.toggle('hidden', !showEditSettingsButton);
+
+        hideGroupTypeButtonsIfOnlyOneDistinctGroup();
+    }
+
+    $('.button-request-delete-chart').click(function()
+    {
+        fetchAndShowModalContent(this.dataset.url, '#deleteModalContainerOnDemand', '#modalConfirmDelete', function(){});
+    });
 });
 
 function createDatePickerEnd(minDate, selectedDate)
@@ -112,6 +158,7 @@ function createDatePickerEnd(minDate, selectedDate)
             weekdaysAbbrev: weekDaysLetters,
 
             // Buttons
+            cancel: buttonCancel,
             done: buttonClose,
 
             // Accessibility labels
@@ -125,23 +172,10 @@ function createDatePickerEnd(minDate, selectedDate)
     });
 }
 
-function applyFilter(modal)
+function applyFilter()
 {
-    let filterButton = document.getElementById("modalFilterTrigger");
-
-    if(isDefaultFilter())
-    {
-        filterButton.classList.toggle("background-blue", true);
-        filterButton.classList.toggle("background-red", false);
-        filterButton.childNodes[1].nodeValue = filterNotActive;
-    } else
-    {
-        filterButton.classList.toggle("background-blue", false);
-        filterButton.classList.toggle("background-red", true);
-        filterButton.childNodes[1].nodeValue = filterActive;
-    }
-
-    modal.modal('close');
+    let badge = document.getElementById("filterActiveBadge");
+    badge.classList.toggle("hidden", isDefaultFilter());
 }
 
 function isDefaultFilter()
@@ -182,16 +216,16 @@ function handleQuickDate(element)
             endDate = moment("2100-01-01");
             break;
         case '4':
-            startDate = moment().subtract(1,'weeks').startOf('isoWeek');
-            endDate = moment().subtract(1,'weeks').endOf('isoWeek');
+            startDate = moment().subtract(1, 'weeks').startOf('isoWeek');
+            endDate = moment().subtract(1, 'weeks').endOf('isoWeek');
             break;
         case '5':
-            startDate = moment().subtract(1,'months').startOf('month');
-            endDate = moment().subtract(1,'months').endOf('month');
+            startDate = moment().subtract(1, 'months').startOf('month');
+            endDate = moment().subtract(1, 'months').endOf('month');
             break;
         case '6':
-            startDate = moment().subtract(1,'years').startOf('year');
-            endDate = moment().subtract(1,'years').endOf('year');
+            startDate = moment().subtract(1, 'years').startOf('year');
+            endDate = moment().subtract(1, 'years').endOf('year');
             break;
         case '7':
             startDate = moment("2000-01-01");
@@ -225,4 +259,90 @@ function setDateRange(startDate, endDate)
 
     chartPickerEndDate.destroy();
     chartPickerEndDate = createDatePickerEnd(chartPickerStartDate.date, endDate.startOf('day').toDate());
-}
\ No newline at end of file
+}
+
+function toggleChartTypeButtons(styleClassName, item)
+{
+    let siblings = document.getElementsByClassName(styleClassName);
+    for(let i = 0; i < siblings.length; i++)
+    {
+        siblings[i].classList.toggle('active', false);
+    }
+
+    item.classList.toggle('active', true);
+}
+
+function hideGroupTypeButtonsIfOnlyOneDistinctGroup()
+{
+    let displayTypeName = document.querySelector('.button-display-type.active').dataset.value;
+    let chartsWithCurrentDisplayType = document.querySelectorAll('.chart-preview-column[data-display-type="' + displayTypeName + '"]');
+
+    let groupTypes = new Set();
+    for(let i = 0; i < chartsWithCurrentDisplayType.length; i++)
+    {
+        groupTypes.add(chartsWithCurrentDisplayType[i].dataset.groupType);
+    }
+
+    let hasOnlyOneDistinctGroupType = groupTypes.size <= 1;
+    document.getElementById('chart-group-type-buttons').classList.toggle('hidden', hasOnlyOneDistinctGroupType);
+}
+
+function filterChartPreviews(initiallySelectedChartID)
+{
+    let displayTypeName = document.querySelector('.button-display-type.active').dataset.value;
+    let groupTypeName = document.querySelector('.button-group-type.active').dataset.value;
+
+    let allChartPreviews = document.getElementsByClassName('chart-preview-column');
+    for(let i = 0; i < allChartPreviews.length; i++)
+    {
+        allChartPreviews[i].classList.toggle('hidden', true);
+    }
+
+    let isGroupTypeDisabled = document.getElementById('chart-group-type-buttons').classList.contains('hidden');
+
+    if(isGroupTypeDisabled)
+    {
+        let chartPreviews = document.querySelectorAll('.chart-preview-column[data-display-type="' + displayTypeName + '"]');
+        for(let i = 0; i < chartPreviews.length; i++)
+        {
+            chartPreviews[i].classList.toggle('hidden', false);
+        }
+    }
+    else
+    {
+        let chartPreviews = document.querySelectorAll('.chart-preview-column[data-display-type="' + displayTypeName + '"][data-group-type="' + groupTypeName + '"]');
+        for(let i = 0; i < chartPreviews.length; i++)
+        {
+            chartPreviews[i].classList.toggle('hidden', false);
+        }
+    }
+
+    unsetActiveChartPreview(initiallySelectedChartID);
+    toggleCustomChartButton(displayTypeName === 'CUSTOM');
+}
+
+function unsetActiveChartPreview(initiallySelectedChartID)
+{
+    let allChartPreviewColumns = document.getElementsByClassName('chart-preview-column');
+    for(let i = 0; i < allChartPreviewColumns.length; i++)
+    {
+        let column = allChartPreviewColumns[i];
+        column.querySelector('.chart-preview').classList.toggle('active', column.dataset.id === initiallySelectedChartID);
+    }
+
+    document.getElementsByName('chartID')[0].value = initiallySelectedChartID;
+    checkShowChartButton();
+}
+
+function checkShowChartButton()
+{
+    let buttonShowChart = document.getElementsByName('buttonSave')[0];
+
+    let selectedChartID = document.getElementsByName('chartID')[0].value;
+    buttonShowChart.disabled = selectedChartID === '';
+}
+
+function toggleCustomChartButton(show)
+{
+    document.getElementById('buttonCustomCharts').classList.toggle('hidden', !show);
+}
diff --git a/src/main/resources/static/js/customSelect.js b/src/main/resources/static/js/customSelect.js
index e192cca63b52fb4c9a5df2b9297d1f195846f350..dfdc4ab6e518fbf3bf3a9c6429af945494a7aa55 100644
--- a/src/main/resources/static/js/customSelect.js
+++ b/src/main/resources/static/js/customSelect.js
@@ -1,4 +1,9 @@
 $(document).ready(function()
+{
+    initCustomSelects();
+});
+
+function initCustomSelects()
 {
     let allCustomSelects = [];
 
@@ -75,7 +80,7 @@ $(document).ready(function()
             }
         }
     });
-});
+}
 
 class CustomSelect
 {
diff --git a/src/main/resources/static/js/fetchModalContent.js b/src/main/resources/static/js/fetchModalContent.js
new file mode 100644
index 0000000000000000000000000000000000000000..936610af475437a9a5434975e3c32b1b4fc925e5
--- /dev/null
+++ b/src/main/resources/static/js/fetchModalContent.js
@@ -0,0 +1,21 @@
+function fetchAndShowModalContent(url, containerID, modalID, callback)
+{
+    let modal = $(modalID).modal();
+    if(modal.isOpen)
+    {
+        return;
+    }
+
+    $.ajax({
+        type: 'GET',
+        url: url,
+        data: {},
+        success: function(data)
+        {
+            $(containerID).html(data);
+            $(modalID).modal();
+            $(modalID).modal('open');
+            callback();
+        }
+    });
+}
\ No newline at end of file
diff --git a/src/main/resources/static/js/filter.js b/src/main/resources/static/js/filter.js
index 294013addb96ba6e6ddd2647316e04b6887b9dfa..d4f10997d335be14e33c3ca2ee3cb7ee8749a7bc 100644
--- a/src/main/resources/static/js/filter.js
+++ b/src/main/resources/static/js/filter.js
@@ -36,6 +36,10 @@ $(document).ready(function()
         updateStatus();
     });
 
+    $('#buttonApplyFilter').click(function(){
+       document.getElementsByName('NewFilterConfiguration')[0].submit();
+    });
+
     updateStatus();
 });
 
@@ -89,5 +93,6 @@ function setAll(identifier, checked)
     for(let i = 0; i < checkboxes.length; i++)
     {
         checkboxes[i].checked = checked;
+        checkboxes[i].dispatchEvent(new Event('change'));
     }
 }
\ No newline at end of file
diff --git a/src/main/resources/static/js/iconSelect.js b/src/main/resources/static/js/iconSelect.js
new file mode 100644
index 0000000000000000000000000000000000000000..2cd93926e1bd6fd606eefa71d170e8d9b414e469
--- /dev/null
+++ b/src/main/resources/static/js/iconSelect.js
@@ -0,0 +1,272 @@
+$(document).ready(function()
+{
+    $('.button-remove-icon-from-item').click(function()
+    {
+        removeIcon();
+    });
+
+    $('#button-icon-confirm').click(function()
+    {
+        let activeTabName = document.querySelector('#iconTabs .tab a.active').dataset.name;
+        if(activeTabName === 'images')
+        {
+            confirmImageIcon();
+        }
+        else
+        {
+            confirmBuiltinIcon();
+        }
+    });
+
+    $('#item-icon-preview').click(function()
+    {
+        let modalID = '#modalIconSelect';
+        let modalIconSelect = document.getElementById('modalIconSelect');
+        let idToFocusOnClose = modalIconSelect.dataset.focusOnClose;
+
+        $(modalID).modal({
+            onOpenEnd: function f()
+            {
+                M.Tabs.init(document.querySelector('#iconTabs'), {
+                    onShow: function()
+                    {
+                        deselectAll();
+                    }
+                });
+            },
+            onCloseEnd: function f()
+            {
+                document.getElementById(idToFocusOnClose).focus();
+            }
+        });
+        $(modalID).modal('open');
+
+        getAvailableImages();
+    });
+
+    $('#button-upload-new-image').click(function()
+    {
+        uploadImage();
+    });
+
+    if($('#modalIconSelect').length)
+    {
+        // prevent modal closing if "ENTER" is pressed in search
+        let modalIconSelect = document.getElementById('modalIconSelect');
+        modalIconSelect.addEventListener('keypress', function(event)
+        {
+            if(event.key === 'Enter')
+            {
+                event.preventDefault();
+            }
+        });
+    }
+
+    // select a built-in icon option
+    $('.builtin-icon-option').click(function()
+    {
+        selectIcon(this, '.builtin-icon-option');
+    });
+});
+
+function getAvailableImages()
+{
+    let progressIndicator = document.getElementById('progressIndicator');
+    progressIndicator.style.setProperty('display', '', 'important')
+
+    let availableImages = document.getElementById('available-images');
+    availableImages.style.setProperty('display', 'none', 'important')
+
+    $.ajax({
+        type: 'GET',
+        url: $('#available-images').attr('data-url'),
+        data: {},
+        success: function(data)
+        {
+            $('#available-images').html(data);
+
+            // select an icon option
+            $('.item-icon-option').click(function()
+            {
+                selectIcon(this, '.item-icon-option');
+            });
+
+            let classDeleteConfirm = 'item-icon-option-delete-confirm';
+            $('.item-icon-option-delete').click(function()
+            {
+                if(this.classList.contains(classDeleteConfirm))
+                {
+                    deleteImage(this);
+                    removeIcon();
+                }
+                else
+                {
+                    this.classList.add(classDeleteConfirm);
+                }
+            });
+
+            progressIndicator.style.setProperty('display', 'none', 'important')
+            availableImages.style.setProperty('display', '', 'important')
+        }
+    });
+}
+
+function deselectAll()
+{
+    let allIconOptions = document.querySelectorAll('.builtin-icon-option, .item-icon-option');
+    for(let i = 0; i < allIconOptions.length; i++)
+    {
+        allIconOptions[i].classList.remove('selected');
+    }
+
+    document.getElementById('button-icon-confirm').setAttribute('disabled', 'true');
+}
+
+function selectIcon(item)
+{
+    deselectAll();
+
+    item.classList.add('selected');
+    document.getElementById('button-icon-confirm').removeAttribute('disabled');
+}
+
+function uploadImage()
+{
+    let formID = 'form-upload-image';
+    let form = document.getElementById(formID);
+
+    $.ajax({
+        url: form.action,
+        enctype: 'multipart/form-data',
+        type: 'post',
+        processData: false,
+        contentType: false,
+        cache: false,
+        data: new FormData(form),
+        success: function(response)
+        {
+            let parsedData = JSON.parse(response);
+            let isUploadSuccessful = parsedData['isUploadSuccessful']
+            M.toast({
+                html: parsedData['localizedMessage'],
+                classes: isUploadSuccessful ? 'green' : 'red'
+            });
+
+            getAvailableImages();
+        },
+        error: function(response)
+        {
+            let parsedData = JSON.parse(response);
+            M.toast({
+                html: parsedData['localizedMessage'],
+                classes: 'red'
+            });
+        }
+    });
+}
+
+function deleteImage(item)
+{
+    $.ajax({
+        type: 'GET',
+        url: $(item).attr('data-url'),
+        data: {},
+        success: function(response)
+        {
+            let parsedData = JSON.parse(response);
+            let isDeleteSuccessful = parsedData['isDeleteSuccessful']
+            M.toast({
+                html: parsedData['localizedMessage'],
+                classes: isDeleteSuccessful ? 'green' : 'red'
+            });
+
+            getAvailableImages();
+        },
+        error: function(response)
+        {
+            let parsedData = JSON.parse(response);
+            M.toast({
+                html: parsedData['localizedMessage'],
+                classes: 'red'
+            });
+        }
+    });
+}
+
+function confirmImageIcon()
+{
+    let icon = document.querySelector('.item-icon-option.selected .item-icon-preview');
+    if(icon === null)
+    {
+        return false;
+    }
+
+    let iconPath = icon.src;
+    let iconId = icon.dataset.imageId;
+
+    let previewIcon = document.getElementById("item-icon-preview-icon");
+    previewIcon.src = iconPath;
+
+    document.getElementById("item-icon-preview-icon").classList.toggle('hidden', false);
+    document.getElementById("builtin-icon-preview-icon").classList.toggle('hidden', true);
+    document.getElementById("item-icon-placeholder").classList.toggle('hidden', true);
+    document.getElementById("hidden-input-icon-image-id").value = iconId;
+    document.getElementById("hidden-input-icon-builtin-identifier").value = null;
+}
+
+function confirmBuiltinIcon()
+{
+    let icon = document.querySelector('.builtin-icon-option.selected .builtin-icon-option-name');
+    if(icon === null)
+    {
+        return false;
+    }
+
+    let iconIdentifier = icon.textContent;
+
+    let previewIcon = document.getElementById("builtin-icon-preview-icon");
+    previewIcon.className = '';  // clear class list
+
+    iconIdentifier.split(' ').forEach(function(cssClass)
+    {
+        previewIcon.classList.add(cssClass);
+    });
+
+    document.getElementById("item-icon-preview-icon").classList.toggle('hidden', true);
+    document.getElementById("builtin-icon-preview-icon").classList.toggle('hidden', false);
+    document.getElementById("item-icon-placeholder").classList.toggle('hidden', true);
+    document.getElementById("hidden-input-icon-image-id").value = null;
+    document.getElementById("hidden-input-icon-builtin-identifier").value = iconIdentifier;
+}
+
+function searchBuiltinIcons()
+{
+    let searchWord = document.getElementById('searchIcons').value.toLowerCase();
+
+    let allIcons = document.querySelectorAll('.builtin-icon-option-column');
+    let numberOfMatchingIcons = 0;
+    for(let i = 0; i < allIcons.length; i++)
+    {
+        let iconName = allIcons[i].querySelector('.builtin-icon-option-name').textContent;
+        if(iconName.toLowerCase().includes(searchWord))
+        {
+            allIcons[i].classList.toggle('hidden', false);
+            numberOfMatchingIcons++;
+        }
+        else
+        {
+            allIcons[i].classList.toggle('hidden', true);
+        }
+    }
+
+    document.getElementById('numberOfMatchingIcons').innerText = numberOfMatchingIcons.toString();
+}
+
+function removeIcon()
+{
+    document.getElementById("item-icon-preview-icon").classList.toggle('hidden', true);
+    document.getElementById("item-icon-placeholder").classList.toggle('hidden', false);
+    document.getElementById("hidden-input-icon-image-id").value = null;
+    document.getElementById("builtin-icon-preview-icon").classList.toggle('hidden', true);
+    document.getElementById("hidden-input-icon-builtin-identifier").value = null;
+}
\ No newline at end of file
diff --git a/src/main/resources/static/js/imageSelect.js b/src/main/resources/static/js/imageSelect.js
deleted file mode 100644
index 55511a61449aa034afd7cb15d62dc009d44fe5ea..0000000000000000000000000000000000000000
--- a/src/main/resources/static/js/imageSelect.js
+++ /dev/null
@@ -1,164 +0,0 @@
-$(document).ready(function()
-{
-    $('.button-remove-icon-from-item').click(function()
-    {
-        document.getElementById("item-icon-preview-icon").classList.toggle('hidden', true);
-        document.getElementById("item-icon-placeholder").classList.toggle('hidden', false);
-        document.getElementById("hidden-input-icon").value = '';
-    });
-
-    $('#button-icon-confirm').click(function()
-    {
-        let icon = document.querySelector('.item-icon-option.selected .item-icon-preview');
-        if(icon === null)
-        {
-            return false;
-        }
-
-        let iconPath = icon.src;
-        let iconId = icon.dataset.imageId;
-
-        let previewIcon = document.getElementById("item-icon-preview-icon");
-        previewIcon.src = iconPath;
-
-        document.getElementById("item-icon-preview-icon").classList.toggle('hidden', false);
-        document.getElementById("item-icon-placeholder").classList.toggle('hidden', true);
-        document.getElementById("hidden-input-icon").value = iconId;
-    });
-
-    $('#item-icon-preview').click(function()
-    {
-        getAvailableImages(function()
-        {
-            let modalID = '#modalIconSelect';
-            let modalIconSelect = document.getElementById('modalIconSelect');
-            let idToFocusOnClose = modalIconSelect.dataset.focusOnClose;
-
-            $(modalID).modal({
-                onCloseEnd: function f()
-                {
-                    document.getElementById(idToFocusOnClose).focus();
-                }
-            });
-            $(modalID).modal('open');
-        });
-    });
-
-    $('#button-upload-new-image').click(function()
-    {
-        uploadImage();
-    });
-});
-
-function getAvailableImages(callback)
-{
-    $.ajax({
-        type: 'GET',
-        url: $('#item-icon-preview').attr('data-url'),
-        data: {},
-        success: function(data)
-        {
-            $('#available-images').html(data);
-
-            // select an icon option
-            $('.item-icon-option').click(function()
-            {
-                selectIcon(this);
-            });
-
-            let classDeleteConfirm = 'item-icon-option-delete-confirm';
-            $('.item-icon-option-delete').click(function()
-            {
-                if(this.classList.contains(classDeleteConfirm))
-                {
-                    deleteImage(this);
-                }
-                else
-                {
-                    this.classList.add(classDeleteConfirm);
-                }
-            });
-
-            callback();
-        }
-    });
-}
-
-function selectIcon(item)
-{
-    let allIconOptions = document.querySelectorAll('.item-icon-option');
-    for(let i = 0; i < allIconOptions.length; i++)
-    {
-        allIconOptions[i].classList.remove('selected');
-    }
-
-    item.classList.add('selected');
-    document.getElementById('button-icon-confirm').removeAttribute('disabled');
-}
-
-function uploadImage()
-{
-    let formID = 'form-upload-image';
-    let form = document.getElementById(formID);
-
-    $.ajax({
-        url: form.action,
-        enctype: 'multipart/form-data',
-        type: 'post',
-        processData: false,
-        contentType: false,
-        cache: false,
-        data: new FormData(form),
-        success: function(response)
-        {
-            let parsedData = JSON.parse(response);
-            let isUploadSuccessful = parsedData['isUploadSuccessful']
-            M.toast({
-                html: parsedData['localizedMessage'],
-                classes: isUploadSuccessful ? 'green' : 'red'
-            });
-
-            getAvailableImages(function()
-            {
-            });
-        },
-        error: function(response)
-        {
-            let parsedData = JSON.parse(response);
-            M.toast({
-                html: parsedData['localizedMessage'],
-                classes: 'red'
-            });
-        }
-    });
-}
-
-function deleteImage(item)
-{
-    $.ajax({
-        type: 'GET',
-        url: $(item).attr('data-url'),
-        data: {},
-        success: function(response)
-        {
-            let parsedData = JSON.parse(response);
-            let isUploadSuccessful = parsedData['isDeleteSuccessful']
-            M.toast({
-                html: parsedData['localizedMessage'],
-                classes: isUploadSuccessful ? 'green' : 'red'
-            });
-
-            getAvailableImages(function()
-            {
-            });
-        },
-        error: function(response)
-        {
-            let parsedData = JSON.parse(response);
-            M.toast({
-                html: parsedData['localizedMessage'],
-                classes: 'red'
-            });
-        }
-    });
-}
\ No newline at end of file
diff --git a/src/main/resources/static/js/main.js b/src/main/resources/static/js/main.js
index 5699844eae5628f092e6575ae2fb22b6c024847e..69f305f93ec798418e1506aae96a6b7602fe84ef 100644
--- a/src/main/resources/static/js/main.js
+++ b/src/main/resources/static/js/main.js
@@ -50,6 +50,17 @@ $(document).ready(function()
     {
         document.getElementById(this.dataset.id).style.display = "none";
     });
+
+    $('.hint-clear').click(function()
+    {
+        document.getElementById(this.dataset.id).style.display = "none";
+
+        $.ajax({
+            type: 'GET',
+            url: $(this).attr('data-url'),
+            data: {}
+        });
+    });
 });
 
 
diff --git a/src/main/resources/static/js/settings.js b/src/main/resources/static/js/settings.js
index ba1246cc5eb7052b4bcfd8210c62067332745902..eff674f342b826094fddd98b0744051deffbfd2a 100644
--- a/src/main/resources/static/js/settings.js
+++ b/src/main/resources/static/js/settings.js
@@ -76,6 +76,17 @@ $(document).ready(function()
         document.getElementById('runBackupInput').value = 1;
     });
 
+    $('#verificationCode').click(function()
+    {
+        let verificationCodeElement = document.getElementsByName('verificationCode')[0];
+        verificationCodeElement.type = 'text';
+        verificationCodeElement.select();
+        document.execCommand('copy');
+        verificationCodeElement.type = 'hidden';
+
+        M.toast({html: copiedToClipboard, classes: 'green'});
+    });
+
     // on initial page load
     let autoBackupCheckbox = document.getElementsByName("autoBackupActivated")[0];
     $('#settings-auto-backup').toggle(autoBackupCheckbox.checked);
diff --git a/src/main/resources/static/js/templates.js b/src/main/resources/static/js/templates.js
index a094beb60987070acbba33ec1539095226653e97..06d11716c6b3e0c211b797ca27244e99417c2fa4 100644
--- a/src/main/resources/static/js/templates.js
+++ b/src/main/resources/static/js/templates.js
@@ -1,10 +1,5 @@
 $(document).ready(function()
 {
-    if($('#modalConfirmDelete').length)
-    {
-        $('#modalConfirmDelete').modal('open');
-    }
-
     M.Collapsible.init(document.querySelector('.collapsible.expandable'), {
         accordion: false
     });
@@ -39,6 +34,11 @@ $(document).ready(function()
         document.getElementById('searchTemplate').focus();
         enableTemplateHotKeys();
     }
+
+    $('.button-request-delete-template').click(function()
+    {
+        fetchAndShowModalContent(this.dataset.url, '#deleteModalContainerOnDemand', '#modalConfirmDelete', function(){});
+    });
 });
 
 let selectedTemplateName = null;
diff --git a/src/main/resources/static/js/transactions.js b/src/main/resources/static/js/transactions.js
index 8c0c7d27489e02b720b1b60e98e61a74949a9271..9a4bc75c8bb102a4f793005d8009609c5eb94c19 100644
--- a/src/main/resources/static/js/transactions.js
+++ b/src/main/resources/static/js/transactions.js
@@ -1,7 +1,5 @@
 $(document).ready(function()
 {
-    $('#modalConfirmDelete').modal('open');
-
     // open filter modal if corresponding anchor is in url (originating from hotkeys.js)
     if(window.location.href.endsWith('#modalFilter'))
     {
@@ -260,6 +258,11 @@ $(document).ready(function()
             scrollTop: $(highlightedLarge).offset().top
         }, 500);
     }
+
+    $('.button-request-delete-transaction').click(function()
+    {
+        fetchAndShowModalContent(this.dataset.url, '#deleteModalContainerOnDemand', '#modalConfirmDelete', function(){});
+    });
 });
 
 function isHidden(el)
diff --git a/src/main/resources/templates/accounts/accounts.ftl b/src/main/resources/templates/accounts/accounts.ftl
index 51d9fa6b381f97e0d899e847e528f2a8a09722fc..23f3a3acd0a1a376301e1de972af6d82412eafa7 100644
--- a/src/main/resources/templates/accounts/accounts.ftl
+++ b/src/main/resources/templates/accounts/accounts.ftl
@@ -9,6 +9,8 @@
         <#import "../helpers/navbar.ftl" as navbar>
         <@navbar.navbar "accounts" settings/>
 
+        <#import "../helpers/customSelectMacros.ftl" as customSelectMacros>
+
         <main>
             <div class="card main-card background-color">
                 <div class="container">
@@ -38,11 +40,11 @@
                                             <i class="fas fa-edit"></i>
                                         </#if>
                                     </td>
-                                    <td><#if account.getIcon()??><img src="${account.getIcon().getBase64EncodedImage()}" class="account-icon"/></#if></td>
+                                    <td><@customSelectMacros.accountIcon account account.getName() "text-blue"/></td>
                                     <td>${account.getName()}</td>
                                     <td>
                                         <a href="<@s.url '/accounts/${account.getID()?c}/edit'/>" class="btn-flat no-padding text-default"><i class="material-icons left">edit</i></a>
-                                        <a href="<@s.url '/accounts/${account.getID()?c}/requestDelete'/>" class="btn-flat no-padding text-default"><i class="material-icons left no-margin">delete</i></a>
+                                        <@header.buttonFlat url='/accounts/' + account.ID?c + '/requestDelete' icon='delete' localizationKey='' classes="no-padding text-default button-request-delete-account" isDataUrl=true/>
                                     </td>
                                 </tr>
                             </#if>
@@ -54,13 +56,10 @@
                 </div>
                 </@header.content>
             </div>
+
+            <div id="deleteModalContainerOnDemand"></div>
         </main>
 
-        <#if currentAccount??>
-            <@header.modalConfirmDelete title=locale.getString("info.title.account.delete") confirmUrl='/accounts' cancelUrlBase="/accounts" itemId=currentAccount.getID() confirmButtonTextKey="info.button.account.delete">
-                <p>${locale.getString("info.text.account.delete", currentAccount.getName(), currentAccount.getReferringTransactions()?size)}</p>
-            </@header.modalConfirmDelete>
-        </#if>
 
         <#if accountNotDeletable??>
             <!-- warning account not deletable -->
diff --git a/src/main/resources/templates/accounts/deleteAccountModal.ftl b/src/main/resources/templates/accounts/deleteAccountModal.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..71b93122bcec8ec4428cbb193e0b37560ab67638
--- /dev/null
+++ b/src/main/resources/templates/accounts/deleteAccountModal.ftl
@@ -0,0 +1,7 @@
+<#global locale = static["de.thecodelabs.utils.util.Localization"]>
+<#import "/spring.ftl" as s>
+<#import "../helpers/header.ftl" as header>
+
+<@header.modalConfirmDelete title=locale.getString("info.title.account.delete") confirmUrl='/accounts' itemId=accountToDelete.getID() confirmButtonTextKey="info.button.account.delete">
+    <p>${locale.getString("info.text.account.delete", accountToDelete.getName(), accountToDelete.getReferringTransactions()?size)}</p>
+</@header.modalConfirmDelete>
\ No newline at end of file
diff --git a/src/main/resources/templates/accounts/newAccount.ftl b/src/main/resources/templates/accounts/newAccount.ftl
index e2dcc136944d055302f6b511520cab9fa3e4b4e6..85bc0e05792a928bde8de9aac38af7422dd40d1c 100644
--- a/src/main/resources/templates/accounts/newAccount.ftl
+++ b/src/main/resources/templates/accounts/newAccount.ftl
@@ -10,7 +10,7 @@
         </#if>
 
         <@header.header "BudgetMaster - ${title}"/>
-        <@header.style "imageSelect"/>
+        <@header.style "iconSelect"/>
         <#import "/spring.ftl" as s>
     </head>
     <@header.body>
@@ -18,7 +18,7 @@
         <@navbar.navbar "accounts" settings/>
 
         <#import "../helpers/customSelectMacros.ftl" as customSelectMacros>
-        <#import "../helpers/imageSelect.ftl" as imageSelectMacros>
+        <#import "../helpers/iconSelect.ftl" as iconSelectMacros>
 
         <main>
             <div class="card main-card background-color">
@@ -47,7 +47,7 @@
                         </div>
 
                         <#-- icon -->
-                        <@imageSelectMacros.imageSelect id="account-icon" item=account/>
+                        <@iconSelectMacros.iconSelect id="account-icon" item=account/>
 
                         <#-- state -->
                         <#if account.getAccountState()??>
@@ -87,12 +87,12 @@
             </div>
         </main>
 
-        <@imageSelectMacros.modalIconSelect idToFocusOnClose="account-name"/>
+        <@iconSelectMacros.modalIconSelect idToFocusOnClose="account-name" item=account/>
 
         <!-- Scripts-->
         <#import "../helpers/scripts.ftl" as scripts>
         <@scripts.scripts/>
         <script src="<@s.url '/js/accounts.js'/>"></script>
-        <script src="<@s.url '/js/imageSelect.js'/>"></script>
+        <script src="<@s.url '/js/iconSelect.js'/>"></script>
     </@header.body>
 </html>
\ No newline at end of file
diff --git a/src/main/resources/templates/categories/categories.ftl b/src/main/resources/templates/categories/categories.ftl
index ed33159c9cf9eabeec6aa676ab111736a3f4800c..3101d388afb302f826d2b37ea2bcd5485ca797d4 100644
--- a/src/main/resources/templates/categories/categories.ftl
+++ b/src/main/resources/templates/categories/categories.ftl
@@ -42,13 +42,14 @@
                             <#assign categoryName=categoriesFunctions.getCategoryName(category)>
                             <#assign usageCount=helpers.getUsageCountForCategory(category)/>
                             <tr>
-                                <td><@categoriesFunctions.categoryCircle category/></td>
+                                <td><@categoriesFunctions.categoryCircle category=category enableSearchWrapper=true/></td>
                                 <td>${categoryName} </td>
-                                <td>${usageCount}</td>
+                                <td><a href="<@s.url '/search?searchCategory=true&searchText=' + categoryName/>" class="waves-effect waves-light text-default">${usageCount}</a></td>
                                 <td>
                                     <@header.buttonFlat url='/categories/' + category.ID?c + '/edit' icon='edit' localizationKey='' classes="no-padding text-default"/>
+                                    <@header.buttonFlat url='/search?searchCategory=true&searchText=' + categoryName icon='search' localizationKey='' classes="no-padding text-default"/>
                                     <#if (category.getType().name() == "CUSTOM")>
-                                        <@header.buttonFlat url='/categories/' + category.ID?c + '/requestDelete' icon='delete' localizationKey='' classes="no-padding text-default"/>
+                                        <@header.buttonFlat url='/categories/' + category.ID?c + '/requestDelete' icon='delete' localizationKey='' classes="no-padding text-default button-request-delete-category" isDataUrl=true/>
                                     </#if>
                                 </td>
                             </tr>
@@ -61,27 +62,7 @@
                 </@header.content>
             </div>
 
-            <#if currentCategory??>
-                <!-- confirm delete modal -->
-                <div id="modalConfirmDelete" class="modal categoryDeleteModal background-color">
-                    <div class="modal-content">
-                        <h4>${locale.getString("info.title.category.delete")}</h4>
-                        <p>${locale.getString("info.text.category.delete", currentCategory.name)}</p>
-                        <p>${locale.getString("info.text.category.delete.move")}</p>
-
-                        <form name="DestinationCategory" id="formDestinationCategory" action="<@s.url '/categories/${currentCategory.ID?c}/delete'/>" method="post">
-                            <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
-                            <#import "../helpers/validation.ftl" as validation>
-                            <@customSelectMacros.customCategorySelect availableCategories preselectedCategory "col s12 m12 l8 offset-l2" locale.getString("info.title.category.delete.move")/>
-                        </form>
-                    </div>
-
-                    <div class="modal-footer background-color">
-                        <@header.buttonLink url='/categories' icon='clear' localizationKey='cancel' color='red' classes='modal-action modal-close text-white'/>
-                        <@header.buttonLink url='' icon='delete' localizationKey='delete' color='green' id='buttonDeleteCategory' classes='modal-action modal-close text-white' noUrl=true/>
-                    </div>
-                </div>
-            </#if>
+            <div id="deleteModalContainerOnDemand"></div>
         </main>
 
         <!--  Scripts-->
diff --git a/src/main/resources/templates/categories/categoriesFunctions.ftl b/src/main/resources/templates/categories/categoriesFunctions.ftl
index 40d7d7e592861e52c7e7a4807a30fab50fa4cd91..7cac61357c403f23c67957662e803c1d52f209d3 100644
--- a/src/main/resources/templates/categories/categoriesFunctions.ftl
+++ b/src/main/resources/templates/categories/categoriesFunctions.ftl
@@ -1,4 +1,5 @@
 <#import "../helpers/header.ftl" as header>
+<#import "/spring.ftl" as s>
 
 <#function getCategoryName category>
     <#if category?? && category.getName()??>
@@ -14,41 +15,32 @@
     </#if>
 </#function>
 
-<#macro categoryCircle category classes="" datasetValue="">
+<#macro categoryCircle category classes="" datasetValue=false enableSearchWrapper=false>
     <#assign categoryName=getCategoryName(category)>
 
-    <div class="category-circle ${classes} <#if settings.getShowCategoriesAsCircles()?? && settings.getShowCategoriesAsCircles() == false>category-square</#if>" style="background-color: ${category.color}" <#if datasetValue?has_content>data-value="${category.getID()}"</#if>>
+    <#if enableSearchWrapper>
+        <a href="<@s.url '/search?searchCategory=true&searchText=' + category.getName()/>">
+    </#if>
+
+    <div class="category-circle ${classes} <#if settings.getShowCategoriesAsCircles()?? && settings.getShowCategoriesAsCircles() == false>category-square</#if>" style="background-color: ${category.color}" <#if datasetValue>data-value="${category.getID()}"</#if>>
         <span style="color: ${category.getAppropriateTextColor()}">
-            <#if category.getIcon()?has_content>
-                <i class="${category.getIcon()}"></i>
+            <#if category.getIconReference()??>
+                <@header.entityIcon entity=category classes="category-icon"/>
             <#else>
                 ${categoryName?capitalize[0]}
             </#if>
         </span>
     </div>
+
+    <#if enableSearchWrapper>
+        </a>
+    </#if>
 </#macro>
 
 <#macro modalIconSelect>
     <div id="modalIconSelect" class="modal modal-fixed-footer background-color">
         <div class="modal-content">
-            <div class="row no-margin-bottom">
-                <div class="input-field col s12 m12 l8 offset-l2">
-                    <i class="material-icons prefix">search</i>
-                    <input id="searchIcons" type="text" onchange="searchCategoryIcons();" onkeypress="searchCategoryIcons();" onpaste="searchCategoryIcons()" oninput="searchCategoryIcons();">
-                    <label for="searchIcons">${locale.getString("search")}</label>
-                </div>
-            </div>
-            <div class="row">
-                <div class="col s12 center-align" id="numberOfIcons"><span id="numberOfMatchingIcons">${fontawesomeIcons?size?c}</span>/${fontawesomeIcons?size?c} ${locale.getString("category.new.icons")}</div>
-            </div>
 
-            <hr>
-
-            <div class="row">
-                <#list fontawesomeIcons as icon>
-                    <@categoryIconOption icon/>
-                </#list>
-            </div>
 
         </div>
         <div class="modal-footer background-color">
@@ -58,11 +50,3 @@
     </div>
 </#macro>
 
-<#macro categoryIconOption icon>
-    <div class="col s4 m2 l2 category-icon-option-column">
-        <div class="category-icon-option">
-            <i class="category-icon-option-icon ${icon}"></i>
-            <div class="category-icon-option-name truncate">${icon}</div>
-        </div>
-    </div>
-</#macro>
\ No newline at end of file
diff --git a/src/main/resources/templates/categories/deleteCategoryModal.ftl b/src/main/resources/templates/categories/deleteCategoryModal.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..705490ea2577c4d3484890f9ca8ccadadb15ee55
--- /dev/null
+++ b/src/main/resources/templates/categories/deleteCategoryModal.ftl
@@ -0,0 +1,23 @@
+<#global locale = static["de.thecodelabs.utils.util.Localization"]>
+<#import "/spring.ftl" as s>
+<#import "../helpers/header.ftl" as header>
+<#import "../helpers/customSelectMacros.ftl" as customSelectMacros>
+
+<div id="modalConfirmDelete" class="modal categoryDeleteModal background-color">
+    <div class="modal-content">
+        <h4>${locale.getString("info.title.category.delete")}</h4>
+        <p>${locale.getString("info.text.category.delete", categoryToDelete.name)}</p>
+        <p>${locale.getString("info.text.category.delete.move")}</p>
+
+        <form name="DestinationCategory" id="formDestinationCategory" action="<@s.url '/categories/${categoryToDelete.ID?c}/delete'/>" method="post">
+            <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
+            <#import "../helpers/validation.ftl" as validation>
+            <@customSelectMacros.customCategorySelect availableCategories preselectedCategory "col s12 m12 l8 offset-l2" locale.getString("info.title.category.delete.move")/>
+        </form>
+    </div>
+
+    <div class="modal-footer background-color">
+        <@header.buttonLink url='' icon='clear' localizationKey='cancel' color='red' classes='modal-action modal-close text-white' noUrl=true/>
+        <@header.buttonLink url='' icon='delete' localizationKey='delete' color='green' id='buttonDeleteCategory' classes='modal-action modal-close text-white' noUrl=true/>
+    </div>
+</div>
\ No newline at end of file
diff --git a/src/main/resources/templates/categories/newCategory.ftl b/src/main/resources/templates/categories/newCategory.ftl
index 23a5f265463bee6324b4a3d123f909c19926c739..72caa4d879360617844053a7721cef49ccedd600 100644
--- a/src/main/resources/templates/categories/newCategory.ftl
+++ b/src/main/resources/templates/categories/newCategory.ftl
@@ -14,12 +14,14 @@
         <@header.header "BudgetMaster - ${title}"/>
         <link type="text/css" rel="stylesheet" href="<@s.url '${"/css/libs/spectrum.css"}'/>"/>
         <@header.style "spectrum"/>
+        <@header.style "iconSelect"/>
     </head>
     <@header.body>
         <#import "../helpers/navbar.ftl" as navbar>
         <@navbar.navbar "categories" settings/>
 
         <#import "categoriesFunctions.ftl" as categoriesFunctions>
+        <#import "../helpers/iconSelect.ftl" as iconSelectMacros>
 
         <main>
             <div class="card main-card background-color">
@@ -77,22 +79,7 @@
                             </div>
 
                             <#-- icon -->
-                            <div class="row">
-                                <div class="input-field col s12 m12 l8 offset-l2">
-                                    <i class="fas fa-icons prefix"></i>
-                                    <label class="input-label" for="category-icon">${locale.getString("category.new.label.icon")}</label>
-                                    <div id="category-icon" class="valign-wrapper">
-                                        <a href="#modalIconSelect" id="category-icon-preview" class="modal-trigger">
-                                            <i id="category-icon-preview-icon" class="<#if category.getIcon()?has_content>${category.getIcon()}<#else>hidden</#if>"></i>
-                                            <div id="category-icon-placeholder" class="<#if category.getIcon()?has_content>hidden</#if>">${locale.getString("category.new.icon.placeholder")}</div>
-                                        </a>
-                                    <@header.buttonFlat url='' icon='delete' id='button-remove-category-icon' localizationKey='' classes="no-padding text-default" noUrl=true/>
-                                    </div>
-                                    <input id="hidden-input-category-icon" type="hidden" name="icon" value="<#if category.getIcon()??>${category.getIcon()}</#if>">
-                                </div>
-                            </div>
-
-                            <@categoriesFunctions.modalIconSelect/>
+                            <@iconSelectMacros.iconSelect id="account-icon" item=category/>
 
                             <br>
 
@@ -120,14 +107,17 @@
                             </div>
                         </form>
                     </div>
-                </@header.content>
+            </@header.content>
             </div>
         </main>
 
+        <@iconSelectMacros.modalIconSelect idToFocusOnClose="category-name" item=category/>
+
         <!-- Scripts-->
         <#import "../helpers/scripts.ftl" as scripts>
         <@scripts.scripts/>
         <script src="<@s.url '/js/libs/spectrum.js'/>"></script>
         <script src="<@s.url '/js/categories.js'/>"></script>
+        <script src="<@s.url '/js/iconSelect.js'/>"></script>
     </@header.body>
 </html>
\ No newline at end of file
diff --git a/src/main/resources/templates/charts/charts.ftl b/src/main/resources/templates/charts/charts.ftl
index 07611e2ea5b8ec3cc41edee67afabf21d19a448b..5db5d1610ae940669323a59e1b86e7d7e8132544 100644
--- a/src/main/resources/templates/charts/charts.ftl
+++ b/src/main/resources/templates/charts/charts.ftl
@@ -20,45 +20,69 @@
             <div class="card main-card background-color">
                 <div class="container">
                     <div class="section center-align">
-                        <div class="headline">
-                            <i class="material-icons">show_chart</i> ${locale.getString("title.charts")}</div>
+                        <div class="headline"><i class="material-icons">show_chart</i> ${locale.getString("title.charts")}</div>
                     </div>
                 </div>
 
                 <@header.content>
-                    <br>
-                    <div class="center-align"><@header.buttonLink url='/charts/manage' icon='edit' localizationKey='home.menu.charts.action.manage'/></div>
-                    <br>
+                    <div class="row">
+                        <div class="col s12 center-align">
+                            <@header.buttonLink url='' icon='edit' localizationKey='chart.button.settings' noUrl=true id='buttonShowChartSettings' classes='hidden'/>
+                        </div>
+                    </div>
 
-                    <div class="container">
-                        <form name="NewChartSettings" action="<@s.url '/charts'/>" method="post">
-                            <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
+                    <form name="NewChartSettings" action="<@s.url '/charts'/>" method="post" class="<#if chartSettings.isChartSelected()>hidden</#if>">
+                        <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
 
+                        <div class="container">
                             <div class="row">
-                                <div class="col s12">
-                                    <ul class="collapsible z-depth-2">
-                                        <@stepOne/>
+                                <div class="col s12 center-align">
+                                    <#list displayTypes as displayType>
+                                        <@chartTypeButton item=displayType buttonClass="button-display-type" initialItem=chartSettings.getDisplayType()/>
+                                    </#list>
+                                </div>
+                            </div>
+                        </div>
+                        <input type="hidden" name="displayType" value="${chartSettings.getDisplayType().name()}">
 
-                                        <@stepTwo/>
+                        <div class="container" id="chart-group-type-buttons">
+                            <div class="row">
+                                <div class="col s12 center-align">
+                                    <#list groupTypes as groupType>
+                                        <@chartTypeButton item=groupType buttonClass="button-group-type" initialItem=chartSettings.getGroupType()/>
+                                    </#list>
+                                </div>
+                            </div>
+                        </div>
+                        <input type="hidden" name="groupType" value="${chartSettings.getGroupType().name()}">
 
-                                        <@stepThree/>
-                                    </ul>
+                        <div class="container">
+                            <div class="row">
+                                <#list charts as chart>
+                                    <@chartPreview chart/>
+                                </#list>
+                                <div class="col s12 center-align hidden" id="buttonCustomCharts">
+                                    <@header.buttonLink url='/charts/manage' icon='edit' localizationKey='chart.button.manage'/>
                                 </div>
                             </div>
+                        </div>
+                        <input type="hidden" name="chartID" value="${chartSettings.getChartID()!''}">
 
-                            <@filterMacros.filterModalCharts chartSettings.getFilterConfiguration()/>
+                        <@dateSelect/>
 
-                            <#-- buttons -->
-                            <div class="row center-align">
-                                <div class="col s12">
-                                    <button class="btn waves-effect waves-light background-blue" type="submit"
-                                            name="buttonSave">
-                                        <i class="material-icons left">show_chart</i>${locale.getString("chart.show")}
-                                    </button>
-                                </div>
+                        <@filterOptions/>
+
+                        <#-- buttons -->
+                        <div class="row center-align">
+                            <div class="col s12">
+                                <button class="btn waves-effect waves-light background-blue" type="submit" name="buttonSave" disabled>
+                                    <i class="material-icons left">show_chart</i>${locale.getString("chart.show")}
+                                </button>
                             </div>
-                        </form>
-                    </div>
+                        </div>
+                    </form>
+
+                    <br>
 
                     <div class="container-chart">
                         <#if containerID??>
@@ -104,93 +128,117 @@
 </html>
 
 
-<#macro stepCollapsible step stepName isActive>
-    <li <#if isActive>class="active"</#if>>
-        <div class="collapsible-header">
-            <span class="bold">${step}</span>
-            <span class="step-name">${stepName}</span>
-        </div>
-        <div class="collapsible-body">
-            <div class="row no-margin-bottom">
-                <#nested>
-            </div>
-        </div>
-    </li>
+<#macro chartTypeButton item buttonClass initialItem>
+    <#assign isInitialItem=item.name()==initialItem.name()/>
+
+    <a class="waves-effect waves-light btn-large text-black ${buttonClass} <#if isInitialItem>active</#if>" data-value="${item.name()}">
+        <#if item.hasFontAwesomeIcon()>
+            <i class="${item.getIcon()} left"></i> ${locale.getString(item.getLocalizationKey())}
+        <#else>
+            <i class="material-icons left">${item.getIcon()}</i> ${locale.getString(item.getLocalizationKey())}
+        </#if>
+    </a>
 </#macro>
 
-<#macro stepOne>
-    <@stepCollapsible step=locale.getString("chart.steps.first.step") stepName=locale.getString("chart.steps.first") isActive=!chart??>
-        <div class="input-field col s12 m12 l8 offset-l2 no-margin-top">
-            <select name="chartID">
-                <#list charts as chart>
-                    <#assign chartName=chartFunctions.getChartName(chart)>
-                    <#if chartSettings.getChartID() == chart.getID()>
-                        <option selected value="${chart.getID()?c}">${chartName}</option>
-                        <#continue>
-                    </#if>
-
-                    <option value="${chart.getID()?c}">${chartName}</option>
-                </#list>
-            </select>
+<#macro chartPreview chart>
+    <div class="col s6 m4 l3 center-align chart-preview-column hidden" data-display-type="${chart.getDisplayType()}" data-group-type="${chart.getGroupType()}" data-id="${chart.getID()?c}">
+        <div class="card chart-preview">
+            <div class="card-image">
+                <img src="<@s.url '/images/charts/' + chart.getPreviewImageFileName()!"placeholder.png"/>">
+            </div>
+            <div class="card-action bold valign-wrapper">
+                <span style="margin: auto">
+                    ${chartFunctions.getChartName(chart)}
+                </span>
+            </div>
         </div>
-    </@stepCollapsible>
+    </div>
 </#macro>
 
-<#macro stepTwo>
-    <@stepCollapsible step=locale.getString("chart.steps.second.step") stepName=locale.getString("chart.steps.second") isActive=false>
-                    <div class="input-field col s6 m6 l4 offset-l2">
-                        <#assign startDate = dateService.getLongDateString(chartSettings.getStartDate())/>
+<#macro dateSelect>
+    <div class="container">
+        <div class="row">
+            <div class="col s12">
+                <div class="card" id="chart-date-card">
+                    <div class="card-content">
+                        <div class="row">
+                            <div class="input-field col s6 m6 l4 offset-l2">
+                                <#assign startDate = dateService.getLongDateString(chartSettings.getStartDate())/>
+
+                                <input id="chart-datepicker" type="text" class="datepicker" name="startDate" value="${startDate}">
+                                <label for="chart-datepicker">${locale.getString("chart.steps.second.label.start")}</label>
+                            </div>
 
-                        <input id="chart-datepicker" type="text" class="datepicker" name="startDate" value="${startDate}">
-                        <label for="chart-datepicker">${locale.getString("chart.steps.second.label.start")}</label>
-                    </div>
+                            <div class="input-field col s6 m6 l4 ">
+                                <#assign endDate = dateService.getLongDateString(chartSettings.getEndDate())/>
 
-                    <div class="input-field col s6 m6 l4 ">
-                        <#assign endDate = dateService.getLongDateString(chartSettings.getEndDate())/>
+                                <input id="chart-datepicker-end" type="text" class="datepicker" name="endDate" value="${endDate}">
+                                <label for="chart-datepicker-end">${locale.getString("chart.steps.second.label.end")}</label>
+                            </div>
+                        </div>
+
+                        <@quickDateOptions/>
 
-                        <input id="chart-datepicker-end" type="text" class="datepicker" name="endDate" value="${endDate}">
-                        <label for="chart-datepicker-end">${locale.getString("chart.steps.second.label.end")}</label>
+                        <script>
+                            startDate = "${startDate}".split(".");
+                            startDate = new Date(startDate[2], startDate[1] - 1, startDate[0]);
+                            endDate = "${endDate}".split(".");
+                            endDate = new Date(endDate[2], endDate[1] - 1, endDate[0]);
+                        </script>
                     </div>
                 </div>
-                <div class="row no-margin-bottom">
-                    <div class="col s12 m12 l8 offset-l2 no-margin-top">
-                        <table class="no-border-table">
-                            <tr>
-                                <td class="quick-date" data-quick="0">${locale.getString("chart.quick.this.week")}</td>
-                                <td class="quick-date" data-quick="1">${locale.getString("chart.quick.this.month")}</td>
-                                <td class="quick-date" data-quick="2">${locale.getString("chart.quick.this.year")}</td>
-                                <td class="quick-date" data-quick="3">${locale.getString("chart.quick.all")}</td>
-                            </tr>
-                             <tr>
-                                <td class="quick-date" data-quick="4">${locale.getString("chart.quick.last.week")}</td>
-                                <td class="quick-date" data-quick="5">${locale.getString("chart.quick.last.month")}</td>
-                                <td class="quick-date" data-quick="6">${locale.getString("chart.quick.last.year")}</td>
-                                <td class="quick-date" data-quick="7">${locale.getString("chart.quick.until.endOfLastYear")}</td>
-                            </tr>
-                            <tr>
-                                <td class="quick-date" data-quick="8">${locale.getString("chart.quick.last.week.days")}</td>
-                                <td class="quick-date" data-quick="9">${locale.getString("chart.quick.last.month.days")}</td>
-                                <td class="quick-date" data-quick="10">${locale.getString("chart.quick.last.year.days")}</td>
-                                <td class="quick-date" data-quick="11">${locale.getString("chart.quick.until.today")}</td>
-                            </tr>
-                        </table>
-                    </div>
-                    <div class="col s12 m12 l8 offset-l2 no-margin-top quick-date-container">
-                    </div>
+            </div>
+        </div>
+    </div>
+</#macro>
 
-                <script>
-                    startDate = "${startDate}".split(".");
-                    startDate = new Date(startDate[2], startDate[1] - 1, startDate[0]);
-                    endDate = "${endDate}".split(".");
-                    endDate = new Date(endDate[2], endDate[1] - 1, endDate[0]);
-                </script>
-    </@stepCollapsible>
+<#macro quickDateOptions>
+    <div class="row no-margin-bottom">
+        <div class="col s12 m12 l8 offset-l2 no-margin-top">
+            <table class="no-border-table">
+                <tr>
+                    <@quickDateOption index="0" localizationKey="chart.quick.this.week"/>
+                    <@quickDateOption index="1" localizationKey="chart.quick.this.month"/>
+                    <@quickDateOption index="2" localizationKey="chart.quick.this.year"/>
+                    <@quickDateOption index="3" localizationKey="chart.quick.all"/>
+                </tr>
+                <tr>
+                    <@quickDateOption index="4" localizationKey="chart.quick.last.week"/>
+                    <@quickDateOption index="5" localizationKey="chart.quick.last.month"/>
+                    <@quickDateOption index="6" localizationKey="chart.quick.last.year"/>
+                    <@quickDateOption index="7" localizationKey="chart.quick.until.endOfLastYear"/>
+                </tr>
+                <tr>
+                    <@quickDateOption index="8" localizationKey="chart.quick.last.week.days"/>
+                    <@quickDateOption index="9" localizationKey="chart.quick.last.month.days"/>
+                    <@quickDateOption index="10" localizationKey="chart.quick.last.year.days"/>
+                    <@quickDateOption index="11" localizationKey="chart.quick.until.today"/>
+                </tr>
+            </table>
+        </div>
+    </div>
 </#macro>
 
-<#macro stepThree>
-    <@stepCollapsible step=locale.getString("chart.steps.third.step") stepName=locale.getString("chart.steps.third") isActive=false>
-        <div class="col s12 m12 l8 offset-l2 no-margin-top center-align">
-            <@transactionsMacros.buttonFilter chartSettings.getFilterConfiguration().isActive()/>
+<#macro quickDateOption index localizationKey>
+    <td class="quick-date" data-quick="${index}">${locale.getString(localizationKey)}</td>
+</#macro>
+
+<#macro filterOptions>
+    <div class="container" id="chart-filter-container">
+        <div class="row">
+            <div class="col s12 no-margin-top center-align">
+                <ul class="collapsible">
+                    <li>
+                        <div class="collapsible-header"><i class="fas fa-filter"></i>${locale.getString("title.filter")} <span class="badge background-red hidden text-white" id="filterActiveBadge">${locale.getString("filter.active.short")}</span></div>
+                        <div class="collapsible-body left-align">
+                            <@filterMacros.filterModalContent chartSettings.getFilterConfiguration() "filterConfiguration"/>
+                            <div class="center-align">
+                                <@filterMacros.buttonResetChart/>
+                            </div>
+                        </div>
+                    </li>
+                </ul>
+            </div>
         </div>
-    </@stepCollapsible>
-</#macro>
\ No newline at end of file
+    </div>
+</#macro>
diff --git a/src/main/resources/templates/charts/deleteChartModal.ftl b/src/main/resources/templates/charts/deleteChartModal.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..c104d879048b148c1c51d042c3cf0742bb601d69
--- /dev/null
+++ b/src/main/resources/templates/charts/deleteChartModal.ftl
@@ -0,0 +1,7 @@
+<#global locale = static["de.thecodelabs.utils.util.Localization"]>
+<#import "/spring.ftl" as s>
+<#import "../helpers/header.ftl" as header>
+
+<@header.modalConfirmDelete title=locale.getString("info.title.chart.delete") confirmUrl='/charts' itemId=chartToDelete.getID() confirmButtonTextKey='info.title.chart.delete'>
+    <p>${locale.getString("info.text.chart.delete", chartToDelete.getName())}</p>
+</@header.modalConfirmDelete>
\ No newline at end of file
diff --git a/src/main/resources/templates/charts/manage.ftl b/src/main/resources/templates/charts/manage.ftl
index e032e8cf5ff46fc1344461ca8bc17593a308ec12..85b4acac5b207821d841198d4a4f49950e875c0b 100644
--- a/src/main/resources/templates/charts/manage.ftl
+++ b/src/main/resources/templates/charts/manage.ftl
@@ -44,9 +44,11 @@
                                         </#if>
                                     </td>
                                     <td>
-                                        <@header.buttonFlat url='/charts/' + chart.ID?c + '/edit' icon='edit' localizationKey='' classes="no-padding text-default"/>
                                         <#if (chart.getType().name() == "CUSTOM")>
-                                            <@header.buttonFlat url='/charts/' + chart.ID?c + '/requestDelete' icon='delete' localizationKey='' classes="no-padding text-default"/>
+                                            <@header.buttonFlat url='/charts/' + chart.ID?c + '/edit' icon='edit' localizationKey='' classes="no-padding text-default"/>
+                                            <@header.buttonFlat url='/charts/' + chart.ID?c + '/requestDelete' icon='delete' localizationKey='' classes="no-padding text-default button-request-delete-chart" isDataUrl=true/>
+                                        <#else>
+                                            <@header.buttonFlat url='/charts/' + chart.ID?c + '/edit' icon='visibility' localizationKey='' classes="no-padding text-default"/>
                                         </#if>
                                     </td>
                                 </tr>
@@ -59,11 +61,7 @@
                 </@header.content>
             </div>
 
-            <#if currentChart??>
-                <@header.modalConfirmDelete title=locale.getString("info.title.chart.delete") confirmUrl='/charts' cancelUrlBase='/charts/manage' itemId=currentChart.getID() confirmButtonTextKey='info.title.chart.delete'>
-                    <p>${locale.getString("info.text.chart.delete", currentChart.getName())}</p>
-                </@header.modalConfirmDelete>
-            </#if>
+            <div id="deleteModalContainerOnDemand"></div>
         </main>
 
         <#import "../helpers/scripts.ftl" as scripts>
diff --git a/src/main/resources/templates/charts/newChart.ftl b/src/main/resources/templates/charts/newChart.ftl
index e8087410202d07e2c99626c5a63237607678c4d3..ca039397e02061cd0d8d2ac2ce9347fcc36a316a 100644
--- a/src/main/resources/templates/charts/newChart.ftl
+++ b/src/main/resources/templates/charts/newChart.ftl
@@ -11,7 +11,7 @@
 
         <@header.header "BudgetMaster - ${title}"/>
         <#import "/spring.ftl" as s>
-        <link rel="stylesheet" href="<@s.url "/webjars/codemirror/5.50.0/lib/codemirror.css"/>">
+        <link rel="stylesheet" href="<@s.url "/webjars/codemirror/5.62.0/lib/codemirror.css"/>">
         <@header.style "charts"/>
     </head>
     <@header.body>
@@ -47,7 +47,7 @@
                                     </#if>
                                 </#if>
                                 <i class="material-icons prefix">edit</i>
-                                <input id="chart-name" type="text" name="name" <@validation.validation "name"/> value="${chartName}">
+                                <input id="chart-name" type="text" name="name" <@validation.validation "name"/> value="${chartName}" <#if chart.getType().name() == "DEFAULT">disabled</#if>>
                                 <label for="chart-name">${locale.getString("chart.new.label.name")}</label>
                             </div>
                         </div>
@@ -102,8 +102,8 @@
         <!-- Scripts-->
         <#import "../helpers/scripts.ftl" as scripts>
         <@scripts.scripts/>
-        <script src="<@s.url '/webjars/codemirror/5.50.0/lib/codemirror.js'/>"></script>
-        <script src="<@s.url '/webjars/codemirror/5.50.0/mode/javascript/javascript.js'/>"></script>
+        <script src="<@s.url '/webjars/codemirror/5.62.0/lib/codemirror.js'/>"></script>
+        <script src="<@s.url '/webjars/codemirror/5.62.0/mode/javascript/javascript.js'/>"></script>
         <script src="<@s.url '/js/charts.js'/>"></script>
     </@header.body>
 </html>
\ No newline at end of file
diff --git a/src/main/resources/templates/filter/filterMacros.ftl b/src/main/resources/templates/filter/filterMacros.ftl
index 35f871588114d8c8299df0967bb8bc26d4f7200d..09a7f08bb252a365e4ee6db8561702ff72af7f44 100644
--- a/src/main/resources/templates/filter/filterMacros.ftl
+++ b/src/main/resources/templates/filter/filterMacros.ftl
@@ -1,50 +1,28 @@
 <#import "/spring.ftl" as s>
 
 <#macro buttons>
-    <div class="row hide-on-small-only valign-wrapper">
-        <div class="col s6 right-align">
+    <div class="row hide-on-small-only no-margin-bottom">
+        <div class="col s12 right-align">
+            <@buttonCloseModal/>
             <@buttonReset/>
-        </div>
-
-        <div class="col s6 left-align">
             <@buttonApply/>
         </div>
     </div>
 
-    <div class="hide-on-med-and-up valign-wrapper">
+    <div class="hide-on-med-and-up valign-wrapper no-margin-bottom">
         <div class="row center-align">
             <div class="col s12">
-                <@buttonReset/>
+                <@buttonCloseModal/>
             </div>
         </div>
         <div class="row center-align">
             <div class="col s12">
-                <@buttonApply/>
-            </div>
-        </div>
-    </div>
-</#macro>
-
-<#macro buttonsCharts>
-    <div class="row hide-on-small-only valign-wrapper">
-        <div class="col s6 right-align">
-            <@buttonResetChart/>
-        </div>
-
-        <div class="col s6 left-align">
-            <@buttonClose/>
-        </div>
-    </div>
-
-    <div class="hide-on-med-and-up valign-wrapper">
-        <div class="row center-align">
-            <div class="col s12">
-                <@buttonResetChart/>
+                <@buttonReset/>
             </div>
         </div>
         <div class="row center-align">
             <div class="col s12">
-                <@buttonClose/>
+                <@buttonApply/>
             </div>
         </div>
     </div>
@@ -55,7 +33,7 @@
 </#macro>
 
 <#macro buttonApply>
-    <button class="btn waves-effect waves-light background-blue" type="submit" name="buttonSave">
+    <button class="btn waves-effect waves-light background-green" type="submit" id="buttonApplyFilter">
         <i class="fas fa-filter left"></i>${locale.getString("filter.apply")}
     </button>
 </#macro>
@@ -68,6 +46,10 @@
     <a class="filter-button-close waves-effect waves-light background-blue btn white-text"><i class="fas fa-filter left"></i>${locale.getString("filter.apply")}</a>
 </#macro>
 
+<#macro buttonCloseModal>
+    <@header.buttonLink url='' icon='clear' localizationKey='cancel' color='red' classes='modal-action modal-close text-white'/>
+</#macro>
+
 <#macro buttonsAllOrNone>
     <div class="row no-margin">
         <div class="col s6 right-align">
@@ -80,30 +62,16 @@
 </#macro>
 
 <#macro filterModal filterConfiguration>
-    <div id="modalFilter" class="modal background-color">
+    <div id="modalFilter" class="modal modal-fixed-footer background-color">
         <div class="modal-content">
             <h4>${locale.getString("title.filter")}</h4>
             <form name="NewFilterConfiguration" action="<@s.url '/filter/apply'/>" method="post">
                 <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
                 <@filterModalContent filterConfiguration/>
-                <@buttons/>
             </form>
         </div>
         <div class="modal-footer background-color">
-            <@header.buttonLink url='' icon='clear' localizationKey='cancel' color='red' classes='modal-action modal-close text-white'/>
-        </div>
-    </div>
-</#macro>
-
-<#macro filterModalCharts filterConfiguration>
-    <div id="modalFilter" class="modal background-color">
-        <div class="modal-content">
-            <h4>${locale.getString("title.filter")}</h4>
-            <@filterModalContent filterConfiguration "filterConfiguration"/>
-            <@buttonsCharts/>
-        </div>
-        <div class="modal-footer background-color">
-            <@header.buttonLink url='' icon='clear' localizationKey='cancel' color='red' classes='modal-action modal-close text-white'/>
+            <@buttons/>
         </div>
     </div>
 </#macro>
diff --git a/src/main/resources/templates/helpers/availableImages.ftl b/src/main/resources/templates/helpers/availableImages.ftl
index 6eba2e39a997531eb3325a4f7df61049020b4ef3..f6eab8dc8ee6bf866dabdb4b339ad7e17021b095 100644
--- a/src/main/resources/templates/helpers/availableImages.ftl
+++ b/src/main/resources/templates/helpers/availableImages.ftl
@@ -4,12 +4,12 @@
 <@header.globals/>
 
 <#list availableImages as image>
-    <@imageOption image 'item-icon'/>
+    <@imageOption image 'item-icon' selectedImageID/>
 </#list>
 
-<#macro imageOption image classPrefix>
+<#macro imageOption image classPrefix selectedImageID>
     <div class="col s4 m2 l2 ${classPrefix}-option-column">
-        <div class="${classPrefix}-option">
+        <div class="${classPrefix}-option <#if selectedImageID?? && selectedImageID==image.getID()>selected</#if>">
             <img src="${image.getBase64EncodedImage()}" class="${classPrefix}-preview" data-image-id="${image.getID()}"/>
         </div>
         <@header.buttonFlat url="/media/deleteImage/" + image.getID() icon='delete' localizationKey='delete.question' classes='no-padding text-default ' + classPrefix + '-option-delete' isDataUrl=true/>
diff --git a/src/main/resources/templates/helpers/customSelectMacros.ftl b/src/main/resources/templates/helpers/customSelectMacros.ftl
index 0c552da4a412c2d1f42ed2756ba2fc7da6640866..f3231f8fd3c8734259c4567d170b152f93d74d35 100644
--- a/src/main/resources/templates/helpers/customSelectMacros.ftl
+++ b/src/main/resources/templates/helpers/customSelectMacros.ftl
@@ -22,7 +22,7 @@
     <@customSelectStart "category-select-wrapper" categories inputClasses labelText "transaction-category" "label">
         <div class="custom-select-trigger" tabindex="0">
             <div class="custom-select-selected-item">
-                <#if selectedCategory??><@customSelectOptionCategoryContent selectedCategory "no-margin-left"/></#if>
+                <#if selectedCategory??><@customSelectOptionCategoryContent category=selectedCategory classes="no-margin-left" datasetValue=true/></#if>
             </div>
             <div class="custom-select-arrow"></div>
         </div>
@@ -140,8 +140,8 @@
     </div>
 </#macro>
 
-<#macro customSelectOptionCategoryContent category classes="" datasetValue="">
-    <@categoriesFunctions.categoryCircle category "category-circle-small ${classes}" datasetValue=""/>
+<#macro customSelectOptionCategoryContent category classes="" datasetValue=false>
+    <@categoriesFunctions.categoryCircle category=category classes="category-circle-small ${classes}" datasetValue=datasetValue/>
     <span class="custom-select-item-name">${categoriesFunctions.getCategoryName(category)}</span>
 </#macro>
 
@@ -163,9 +163,9 @@
 </#macro>
 
 <#macro accountIcon account accountName classes="" datasetValue="">
-    <div class="category-circle ${classes} category-square <#if account.getIcon()?? == false>account-square-border</#if>" <#if datasetValue?has_content>data-value="${account.getID()}"</#if>>
-        <#if account.getIcon()??>
-            <img src="${account.getIcon().getBase64EncodedImage()}" class="account-select-icon"/>
+    <div class="category-circle ${classes} category-square <#if account.getIconReference()?? == false>account-square-border</#if>" <#if datasetValue?has_content>data-value="${account.getID()}"</#if>>
+        <#if account.getIconReference()??>
+            <@header.entityIcon entity=account classes="account-select-icon text-blue"/>
         <#else>
             <span class="text-blue">
                 ${accountName?capitalize[0]}
diff --git a/src/main/resources/templates/helpers/globalDatePicker.ftl b/src/main/resources/templates/helpers/globalDatePicker.ftl
index e3d43bb23eb54da40c10325a2ee4384e2128b064..8afcd1e11c022ffd22d04eebe9b3cdea2b16b0a6 100644
--- a/src/main/resources/templates/helpers/globalDatePicker.ftl
+++ b/src/main/resources/templates/helpers/globalDatePicker.ftl
@@ -29,6 +29,9 @@
             <@header.buttonLink url='/setDate?target=' + target icon='done' localizationKey='ok' color='green' id='buttonChooseDate' classes='modal-action modal-close text-white'/>
         </div>
     </div>
+
+    <#assign hint=helpers.getHintByLocalizationKey("hint.globalDatePicker.hotkeys")/>
+    <@header.hint hint=hint actionUrl='/hotkeys'/>
 </#macro>
 
 <#macro datepickerGridYear startYear currentYear>
diff --git a/src/main/resources/templates/helpers/header.ftl b/src/main/resources/templates/helpers/header.ftl
index efd6955c392bf863886c427ffbd2e7829fd8c546..f29ce4c2b3c2c89c1a60715f89ec60fde76a268a 100644
--- a/src/main/resources/templates/helpers/header.ftl
+++ b/src/main/resources/templates/helpers/header.ftl
@@ -21,7 +21,7 @@
     <#import "/spring.ftl" as s>
     <title>${title}</title>
     <meta charset="UTF-8"/>
-    <link rel="stylesheet" href="<@s.url '/webjars/font-awesome/5.15.2/css/all.min.css'/>">
+    <link rel="stylesheet" href="<@s.url '/webjars/font-awesome/5.15.3/css/all.min.css'/>">
     <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
     <link rel="stylesheet" href="<@s.url "/webjars/materializecss/1.0.0/css/materialize.min.css"/>">
     <@style "colors"/>
@@ -45,7 +45,7 @@
     </#if>
 </#macro>
 
-<#macro modalConfirmDelete title confirmUrl cancelUrlBase itemId confirmButtonTextKey id="modalConfirmDelete" classes="">
+<#macro modalConfirmDelete title confirmUrl itemId confirmButtonTextKey id="modalConfirmDelete" classes="">
     <div id="${id}" class="modal background-color ${classes}">
         <div class="modal-content">
             <h4>${title}</h4>
@@ -53,7 +53,7 @@
             <#nested>
         </div>
         <div class="modal-footer background-color">
-            <@buttonLink url=cancelUrlBase icon='clear' localizationKey='cancel' color='red' classes='modal-action modal-close text-white'/>
+            <@buttonLink url='' icon='clear' localizationKey='cancel' color='red' classes='modal-action modal-close text-white' noUrl=true/>
             <@buttonLink url=confirmUrl + '/' + itemId?c + '/delete' icon='delete' localizationKey=confirmButtonTextKey color='green' classes='modal-action modal-close text-white'/>
         </div>
     </div>
@@ -79,12 +79,10 @@
             <div class="col s12 center-align">
                 <div class="notification-wrapper">
                     <div class="notification ${notification.getBackgroundColor()} ${notification.getTextColor()}">
-                        <div>
-                            <#if notification.getIcon()??>
-                                <i class="${notification.getIcon()} notification-item"></i>
-                            </#if>
-                            <span class="notification-item">${notification.getMessage()}</span>
-                        </div>
+                        <#if notification.getIcon()??>
+                            <i class="${notification.getIcon()} notification-item"></i>
+                        </#if>
+                        <span class="notification-item">${notification.getMessage()}</span>
                         <a class="notification-item notification-clear ${notification.getTextColor()}" data-id="notification-${notification?index}">
                             <i class="material-icons">clear</i>
                         </a>
@@ -95,6 +93,32 @@
     </#list>
 </#macro>
 
+<#macro hint hint icon="fas fa-info" actionUrl="">
+    <#if hint.isDismissed()>
+        <#return>
+    </#if>
+
+    <div class="row" id="hint-${hint.getID()}">
+        <div class="col s12 center-align">
+            <div class="notification-wrapper">
+                <div class="notification notification-border text-default">
+                    <i class="${icon} notification-item"></i>
+                    <#if actionUrl?has_content>
+                        <a href="<@s.url actionUrl/>" class="text-default">
+                    </#if>
+                        <span class="notification-item left-align">${locale.getString(hint.getLocalizationKey())}</span>
+                    <#if actionUrl?has_content>
+                        </a>
+                    </#if>
+                    <a class="notification-item hint-clear text-default" data-url="<@s.url "/hints/dismiss/" + hint.getID()/>" data-id="hint-${hint.getID()}">
+                        <i class="material-icons">clear</i>
+                    </a>
+                </div>
+            </div>
+        </div>
+    </div>
+</#macro>
+
 <#macro buttonLink url icon localizationKey id="" color="background-blue" classes="" isDataUrl=false noUrl=false disabled=false>
     <a <#if !isDataUrl && !noUrl>href="<@s.url url/>"</#if>
        id="${id}"
@@ -105,8 +129,8 @@
     </a>
 </#macro>
 
-<#macro buttonSubmit name icon localizationKey id="" color="background-blue" classes="" disabled=false>
-    <button id="${id}" class="btn waves-effect waves-light ${color} ${classes}" type="submit" name="${name}" <#if disabled>disabled</#if>>
+<#macro buttonSubmit name icon localizationKey id="" color="background-blue" classes="" disabled=false formaction="">
+    <button id="${id}" class="btn waves-effect waves-light ${color} ${classes}" type="submit" name="${name}" <#if disabled>disabled</#if> <#if formaction?has_content>formaction="<@s.url formaction/>"</#if>>
         <i class="material-icons left <#if !localizationKey?has_content>no-margin</#if>">${icon}</i><#if localizationKey?has_content>${locale.getString(localizationKey)}</#if>
     </button>
 </#macro>
@@ -118,4 +142,14 @@
             <#if isDataUrl>data-url="${url}"</#if>>
         <i class="material-icons left <#if !localizationKey?has_content>no-margin</#if> ${iconClasses}">${icon}</i><#if localizationKey?has_content><span>${locale.getString(localizationKey)}</span></#if>
     </a>
+</#macro>
+
+<#macro entityIcon entity classes="">
+    <#if entity.getIconReference()??>
+        <#if entity.getIconReference().isBuiltinIcon()>
+            <i class="${entity.getIconReference().getBuiltinIdentifier()} ${classes}"></i>
+        <#else>
+            <img src="${entity.getIconReference().getImage().getBase64EncodedImage()}" class="${classes}"/>
+        </#if>
+    </#if>
 </#macro>
\ No newline at end of file
diff --git a/src/main/resources/templates/helpers/iconSelect.ftl b/src/main/resources/templates/helpers/iconSelect.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..cf157c5418a7108de7c1988dd811af0d9e75898c
--- /dev/null
+++ b/src/main/resources/templates/helpers/iconSelect.ftl
@@ -0,0 +1,157 @@
+<#import "/spring.ftl" as s>
+<#import "../helpers/header.ftl" as header>
+
+<#macro iconSelect id item>
+    <div class="row">
+        <div class="input-field col s12 m12 l8 offset-l2">
+            <i class="fas fa-icons prefix"></i>
+            <label class="input-label" for="${id}">${locale.getString("account.new.label.icon")}</label>
+
+            <#assign hasImageIcon=item.getIconReference()?? && item.getIconReference().getImage()??/>
+            <#assign hasBuiltinIcon=item.getIconReference()?? && item.getIconReference().getBuiltinIdentifier()??/>
+
+            <div id="${id}" class="valign-wrapper item-icon">
+                <a id="item-icon-preview">
+                    <i id="builtin-icon-preview-icon" class="<#if hasBuiltinIcon>${item.getIconReference().getBuiltinIdentifier()}<#else>hidden</#if>"></i>
+                    <img id="item-icon-preview-icon" src="<#if hasImageIcon>${item.getIconReference().getImage().getBase64EncodedImage()}</#if>" class="item-icon-preview <#if hasImageIcon == false>hidden</#if>"/>
+                    <div id="item-icon-placeholder" class="<#if hasImageIcon || hasBuiltinIcon>hidden</#if>">${locale.getString("account.new.icon.placeholder")}</div>
+                </a>
+                <@header.buttonFlat url='' icon='delete' id='' localizationKey='' classes="no-padding text-default button-remove-icon-from-item" noUrl=true/>
+
+                <input id="hidden-input-icon-image-id" type="hidden" name="iconImageID" value="<#if hasImageIcon>${item.getIconReference().getImage().getID()?c}</#if>">
+                <input id="hidden-input-icon-builtin-identifier" type="hidden" name="builtinIconIdentifier" value="<#if hasBuiltinIcon>${item.getIconReference().getBuiltinIdentifier()}</#if>">
+            </div>
+        </div>
+    </div>
+</#macro>
+
+
+<#macro modalIconSelect idToFocusOnClose item>
+    <#assign hasImageIcon=item.getIconReference()?? && item.getIconReference().getImage()??/>
+
+    <div id="modalIconSelect" class="modal modal-fixed-footer background-color" data-focus-on-close="${idToFocusOnClose}">
+        <div class="modal-content center-align">
+            <div class="row">
+                <div class="col s12">
+                    <ul class="tabs" id="iconTabs">
+                        <li class="tab col s6"><a class="text-blue valign-wrapper <#if hasImageIcon == false>active</#if>" href="#tabBuiltinIcons" data-name="builtinIcons"><i class="fas fa-icons"></i> ${locale.getString(("icons.builtin"))}</a></li>
+                        <li class="tab col s6"><a class="text-blue valign-wrapper <#if hasImageIcon>active</#if>" href="#tabImages" data-name="images"><i class="fas fa-image"></i> ${locale.getString(("icons.images"))}</a></li>
+                    </ul>
+                </div>
+                <div id="tabBuiltinIcons" class="col s12"><@tabBuiltinIcons item/></div>
+                <div id="tabImages" class="col s12"><@tabImages item/></div>
+            </div>
+        </div>
+        <div class="modal-footer background-color">
+            <@header.buttonLink url='' icon='clear' localizationKey='cancel' color='red' classes='modal-action modal-close text-white' noUrl=true/>
+            <@header.buttonLink url='' icon='done' id='button-icon-confirm' localizationKey='ok' color='green' classes='modal-action modal-close text-white' noUrl=true disabled=true/>
+        </div>
+    </div>
+</#macro>
+
+<#macro tabImages item>
+     <div class="row">
+        <div class="col s12">
+            <div class="headline">${locale.getString('upload.image.headline')}</div>
+        </div>
+    </div>
+
+    <div class="row">
+        <@uploadImageForm/>
+    </div>
+
+    <hr>
+
+    <div class="row">
+        <div class="col s12">
+            <div class="headline">${locale.getString('available.images')}</div>
+        </div>
+    </div>
+
+    <#assign hasImageIcon=item.getIconReference()?? && item.getIconReference().getImage()??/>
+    <#if hasImageIcon>
+        <#assign selectedImageID=item.getIconReference().getImage().getID()?c/>
+    <#else>
+        <#assign selectedImageID=""/>
+    </#if>
+
+    <@progressIndicator/>
+
+    <div class="row" id="available-images" data-url="<@s.url '/media/getAvailableImages/' + selectedImageID/>">
+    </div>
+</#macro>
+
+<#macro tabBuiltinIcons item>
+    <div class="row no-margin-bottom">
+        <div class="input-field col s12 m12 l8 offset-l2">
+            <i class="material-icons prefix">search</i>
+            <input id="searchIcons" type="text" onchange="searchBuiltinIcons();" onkeypress="searchBuiltinIcons();" onpaste="searchBuiltinIcons()" oninput="searchBuiltinIcons();">
+            <label for="searchIcons">${locale.getString("search")}</label>
+        </div>
+    </div>
+    <div class="row">
+        <div class="col s12 center-align" id="numberOfIcons"><span id="numberOfMatchingIcons">${fontawesomeIcons?size?c}</span>/${fontawesomeIcons?size?c} ${locale.getString("icons.numberOf")}</div>
+    </div>
+
+    <hr>
+
+    <div class="row">
+        <#list fontawesomeIcons as icon>
+            <@builtinIconOption icon item/>
+        </#list>
+    </div>
+</#macro>
+
+<#macro builtinIconOption icon item>
+    <#assign hasBuiltinIcon=item.getIconReference()?? && item.getIconReference().getBuiltinIdentifier()??/>
+    <#if hasBuiltinIcon>
+        <#assign selectedIconName=item.getIconReference().getBuiltinIdentifier()/>
+    <#else>
+         <#assign selectedIconName=""/>
+    </#if>
+
+    <div class="col s4 m2 l2 builtin-icon-option-column">
+        <div class="builtin-icon-option <#if selectedIconName==icon>selected</#if>">
+            <i class="builtin-icon-option-icon ${icon}"></i>
+            <div class="builtin-icon-option-name truncate">${icon}</div>
+        </div>
+    </div>
+</#macro>
+
+<#macro uploadImageForm>
+    <form id="form-upload-image" method="post" action="<@s.url '/media/uploadImage'/>" enctype="multipart/form-data">
+        <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
+        <div class="file-field input-field col s12">
+            <div class="container">
+                <div class="btn background-blue">
+                    <i class="material-icons left">folder</i>
+                    ${locale.getString("account.new.icon.upload.choose.file")}
+                    <input id="inputUploadFile" type="file" accept="${helpers.getValidImageUploadTypes()}" name="file">
+                </div>
+                <div class="file-path-wrapper">
+                    <input class="file-path validate" type="text">
+                </div>
+                <@header.buttonLink url='' icon='upload' localizationKey='account.new.icon.upload' id='button-upload-new-image' classes='right' noUrl=true/>
+            </div>
+        </div>
+    </form>
+
+    <#assign hint=helpers.getHintByLocalizationKey("hint.icon.upload.image.size")/>
+    <@header.hint hint=hint/>
+</#macro>
+
+<#macro progressIndicator>
+    <div class="preloader-wrapper active margin" id="progressIndicator">
+        <div class="spinner-layer spinner-blue-only">
+            <div class="circle-clipper left">
+                <div class="circle"></div>
+            </div>
+            <div class="gap-patch">
+                <div class="circle"></div>
+            </div>
+            <div class="circle-clipper right">
+                <div class="circle"></div>
+            </div>
+        </div>
+    </div>
+</#macro>
\ No newline at end of file
diff --git a/src/main/resources/templates/helpers/imageSelect.ftl b/src/main/resources/templates/helpers/imageSelect.ftl
deleted file mode 100644
index 4bef6d187593be485faf1f908d97050d6e2eee98..0000000000000000000000000000000000000000
--- a/src/main/resources/templates/helpers/imageSelect.ftl
+++ /dev/null
@@ -1,72 +0,0 @@
-<#import "/spring.ftl" as s>
-<#import "../helpers/header.ftl" as header>
-
-<#macro imageSelect id item>
-    <div class="row">
-        <div class="input-field col s12 m12 l8 offset-l2">
-            <i class="fas fa-icons prefix"></i>
-            <label class="input-label" for="${id}">${locale.getString("account.new.label.icon")}</label>
-
-            <div id="${id}" class="valign-wrapper item-icon">
-                <a id="item-icon-preview" data-url="<@s.url '/media/getAvailableImages'/>">
-                    <img id="item-icon-preview-icon" src="<#if item.getIcon()??>${item.getIcon().getBase64EncodedImage()}</#if>" class="item-icon-preview <#if item.getIcon()?? == false>hidden</#if>"/>
-                    <div id="item-icon-placeholder" class="<#if item.getIcon()??>hidden</#if>">${locale.getString("account.new.icon.placeholder")}</div>
-                </a>
-                <@header.buttonFlat url='' icon='delete' id='' localizationKey='' classes="no-padding text-default button-remove-icon-from-item" noUrl=true/>
-
-                <input id="hidden-input-icon" type="hidden" name="icon" value="<#if item.getIcon()??>${item.getIcon().getID()?c}</#if>">
-            </div>
-        </div>
-    </div>
-</#macro>
-
-
-<#macro modalIconSelect idToFocusOnClose>
-    <div id="modalIconSelect" class="modal modal-fixed-footer background-color" data-focus-on-close="${idToFocusOnClose}">
-        <div class="modal-content center-align">
-            <div class="row">
-                <div class="col s12">
-                    <div class="headline">${locale.getString('upload.image.headline')}</div>
-                </div>
-            </div>
-
-            <div class="row">
-                <@uploadImageForm/>
-            </div>
-
-            <hr>
-
-            <div class="row">
-                <div class="col s12">
-                    <div class="headline">${locale.getString('available.images')}</div>
-                </div>
-            </div>
-
-            <div class="row" id="available-images">
-            </div>
-        </div>
-        <div class="modal-footer background-color">
-            <@header.buttonLink url='' icon='clear' localizationKey='cancel' color='red' classes='modal-action modal-close text-white' noUrl=true/>
-            <@header.buttonLink url='' icon='done' id='button-icon-confirm' localizationKey='ok' color='green' classes='modal-action modal-close text-white' noUrl=true disabled=true/>
-        </div>
-    </div>
-</#macro>
-
-<#macro uploadImageForm>
-    <form id="form-upload-image" method="post" action="<@s.url '/media/uploadImage'/>" enctype="multipart/form-data">
-        <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
-        <div class="file-field input-field col s12">
-            <div class="container">
-                <div class="btn background-blue">
-                    <i class="material-icons left">folder</i>
-                    ${locale.getString("account.new.icon.upload.choose.file")}
-                    <input id="inputUploadFile" type="file" accept="${helpers.getValidImageUploadTypes()}" name="file">
-                </div>
-                <div class="file-path-wrapper">
-                    <input class="file-path validate" type="text">
-                </div>
-                <@header.buttonLink url='' icon='upload' localizationKey='account.new.icon.upload' id='button-upload-new-image' classes='right' noUrl=true/>
-            </div>
-        </div>
-    </form>
-</#macro>
\ No newline at end of file
diff --git a/src/main/resources/templates/helpers/navbar.ftl b/src/main/resources/templates/helpers/navbar.ftl
index 46562f0e39280ec17c9bc99f2327bf5a20672fbe..8a70e510679337f6f0e1a715611372c9a89c1452 100644
--- a/src/main/resources/templates/helpers/navbar.ftl
+++ b/src/main/resources/templates/helpers/navbar.ftl
@@ -15,6 +15,7 @@
         <@itemWithIcon "charts" "/charts" locale.getString("menu.charts"), entityType.CHART.getIcon(), entityType.CHART.getColor(), activeID/>
         <@itemWithIcon "reports", "/reports", locale.getString("menu.reports"), entityType.REPORT.getIcon(), entityType.REPORT.getColor(), activeID/>
         <@itemWithIcon "categories", "/categories", locale.getString("menu.categories"), entityType.CATEGORY.getIcon(), entityType.CATEGORY.getColor(), activeID/>
+        <@itemWithIcon "tags", "/tags", locale.getString("menu.tags"), entityType.TAGS.getIcon(), entityType.TAGS.getColor(), activeID/>
         <@itemWithIcon "statistics", "/statistics", locale.getString("menu.statistics"), entityType.STATISTICS.getIcon(), entityType.STATISTICS.getColor(), activeID/>
         <@itemWithIcon "settings", "/settings", locale.getString("menu.settings"), entityType.SETTINGS.getIcon(), entityType.SETTINGS.getColor(), activeID/>
 
diff --git a/src/main/resources/templates/helpers/scripts.ftl b/src/main/resources/templates/helpers/scripts.ftl
index 0bd7d3eb61b91e57f18c5a346dc9e4969830a68e..cf6778142b510b7f9257ff6dee62459bfc443f8a 100644
--- a/src/main/resources/templates/helpers/scripts.ftl
+++ b/src/main/resources/templates/helpers/scripts.ftl
@@ -9,6 +9,8 @@
     <script src="<@s.url '/js/hotkeys.js'/>"></script>
     <script src="<@s.url '/js/main.js'/>"></script>
     <script src="<@s.url '/js/customSelect.js'/>"></script>
+    <script src="<@s.url '/js/fetchModalContent.js'/>"></script>
+
     <script>
         accountPlaceholderName = "${locale.getString("account.all")}";
     </script>
diff --git a/src/main/resources/templates/index.ftl b/src/main/resources/templates/index.ftl
index 89a7808bf612ccc9873051ccc0b3856cdcdd6b81..4c0d085a44b32dd64db744b499b372a8bdd32fa1 100644
--- a/src/main/resources/templates/index.ftl
+++ b/src/main/resources/templates/index.ftl
@@ -24,9 +24,8 @@
                     </div>
 
                     <@header.content>
-                        <#if settings.getShowFirstUseBanner()>
-                            <@indexFunctions.firstUseBanner/>
-                        </#if>
+                        <#assign hint=helpers.getHintByLocalizationKey("hint.first.use.teaser")/>
+                        <@header.hint hint=hint icon="fas fa-graduation-cap" actionUrl="/firstUse"/>
 
                         <div class="hide-on-small-only"><br></div>
 
diff --git a/src/main/resources/templates/indexFunctions.ftl b/src/main/resources/templates/indexFunctions.ftl
index e168ea6a281a80cdceebaf7bcf632fd2fd258ddf..807d0b3ad58083be89018247a8e111589b5c3890 100644
--- a/src/main/resources/templates/indexFunctions.ftl
+++ b/src/main/resources/templates/indexFunctions.ftl
@@ -28,21 +28,3 @@
         </#if>
     </p>
 </#macro>
-
-<#macro firstUseBanner>
-    <div class="row" id="firstUseBanner">
-        <div class="col s12 center-align">
-            <div class="notification-wrapper">
-                <div class="notification notification-border text-default">
-                    <a href="<@s.url "/firstUse"/>" class="text-default">
-                        <i class="fas fa-graduation-cap notification-item"></i>
-                        <span class="notification-item">${locale.getString("home.first.use.teaser")}</span>
-                    </a>
-                    <a href="<@s.url "/settings/hideFirstUseBanner"/>" class="text-default notification-item notification-clear">
-                        <i class="material-icons">clear</i>
-                    </a>
-                </div>
-            </div>
-        </div>
-    </div>
-</#macro>
\ No newline at end of file
diff --git a/src/main/resources/templates/reports/reports.ftl b/src/main/resources/templates/reports/reports.ftl
index 19a42f6a3f42741b0f4c732e8f7668d7cee13c6a..b5fd9e2483f41a3289071023b068af93c11175b1 100644
--- a/src/main/resources/templates/reports/reports.ftl
+++ b/src/main/resources/templates/reports/reports.ftl
@@ -69,12 +69,9 @@
                         <div class="row no-margin">
                             <div class="col s12 center-align">
                                 <div class="headline-small text-default">${locale.getString("report.columns")}</div>
-                                <table class="no-border-table table-advice">
-                                    <tr>
-                                        <td><i class="material-icons">info_outline</i></td>
-                                        <td>${locale.getString("report.columns.advice")}</td>
-                                    </tr>
-                                </table>
+                                <br>
+                                <#assign hint=helpers.getHintByLocalizationKey("hint.report.columns")/>
+                                <@header.hint hint=hint/>
                             </div>
                         </div>
                         <div class="row">
diff --git a/src/main/resources/templates/search/search.ftl b/src/main/resources/templates/search/search.ftl
index 37845577e9a3b10e999b4218aacb8bb71b31e6d8..f962e9df4e2441328d5c32a0cf2ea07207b02914 100644
--- a/src/main/resources/templates/search/search.ftl
+++ b/src/main/resources/templates/search/search.ftl
@@ -29,7 +29,7 @@
                         <input type="hidden" name="page" id="inputPageNumber" value="${page.getNumber()}"/>
                     </form>
 
-                    <@searchMacros.pagination page/>
+                    <@searchMacros.pagination page "top"/>
 
                     <div class="row search-container">
                         <div class="col s12">
@@ -40,8 +40,8 @@
                                             <div class="col s3 center-align bold transaction-text">
                                                 ${dateService.getDateStringNormal(transaction.date)}
                                             </div>
-                                            <@transactionsMacros.transactionType transaction/>
                                             <@transactionsMacros.transactionAccountIcon transaction/>
+                                            <@transactionsMacros.transactionType transaction/>
                                             <@transactionsMacros.transactionLinks transaction/>
                                         </div>
                                         <div class="row valign-wrapper no-margin-bottom">
@@ -56,8 +56,8 @@
                                                 ${dateService.getDateStringNormal(transaction.date)}
                                             </div>
                                             <@transactionsMacros.transactionCategory transaction "left-align"/>
-                                            <@transactionsMacros.transactionType transaction/>
                                             <@transactionsMacros.transactionAccountIcon transaction/>
+                                            <@transactionsMacros.transactionType transaction/>
                                             <@transactionsMacros.transactionNameAndDescription transaction "l3 xl4"/>
                                             <@transactionsMacros.transactionAmount transaction transaction.getAccount() "l2 xl2"/>
                                             <@transactionsMacros.transactionLinks transaction/>
@@ -77,6 +77,8 @@
                             </#if>
                         </div>
                     </div>
+
+                    <@searchMacros.pagination page "bottom"/>
                 </@header.content>
             </div>
         </main>
diff --git a/src/main/resources/templates/search/searchMacros.ftl b/src/main/resources/templates/search/searchMacros.ftl
index e3ae3030d665e09af620a3fb0e43d8dfff712c7e..86378617149e0dff70980979f4541034b2c271b9 100644
--- a/src/main/resources/templates/search/searchMacros.ftl
+++ b/src/main/resources/templates/search/searchMacros.ftl
@@ -58,8 +58,8 @@
     </div>
 </#macro>
 
-<#macro pagination page>
-    <div class="row">
+<#macro pagination page position>
+    <div class="row pagination-position-${position}">
         <div class="col s12 center-align">
             <#if page.getTotalPages() gt 0>
                 <ul class="pagination">
diff --git a/src/main/resources/templates/settings/importStepTwo.ftl b/src/main/resources/templates/settings/importStepTwo.ftl
index 67886d4a66948283c758fa0a716b8115d7074ce4..ff3656b3900b48a40234aa6a34a27d6abded12ed 100644
--- a/src/main/resources/templates/settings/importStepTwo.ftl
+++ b/src/main/resources/templates/settings/importStepTwo.ftl
@@ -25,11 +25,21 @@
 
                 <div class="container">
                     <#import "../helpers/validation.ftl" as validation>
-                    <form name="Import" action="<@s.url '/settings/database/import/step3'/>" method="post" onsubmit="return validateForm()">
+                    <form name="Import" method="post" onsubmit="return validateForm()">
                         <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
 
+                        <div class="section center-align">
+                            <@header.buttonSubmit name='action' icon='add' localizationKey='title.account.new' id='buttonImportCreateAccount' classes='button-new-account' formaction='/settings/database/import/step2/createAccount'/>
+                        </div>
+
                         <table class="bordered">
-                            <#list helpers.getAccountMatches(database.getAccounts()) as accountMatch>
+                            <#if accountMatchList??>
+                                <#assign accountMatches=accountMatchList.getAccountMatches()>
+                            <#else>
+                                <#assign accountMatches=helpers.getAccountMatches(database.getAccounts())>
+                            </#if>
+
+                            <#list accountMatches as accountMatch>
                                 <tr>
                                     <td class="import-text">${locale.getString("info.database.import.source")}</td>
                                     <td class="account-source-id hidden"><#if accountMatch.getAccountSource().getID()??>${accountMatch.getAccountSource().getID()?c}<#else>-1</#if> </td>
@@ -38,18 +48,14 @@
                                     <td>
                                         <div class="input-field no-margin">
                                             <select class="account-destination">
-                                                <#list availableAccounts as account>
-                                                    <#if (account.getType().name() == "CUSTOM")>
-                                                        <option value="${account.getID()?c}">${account.getName()}</option>
-                                                    </#if>
-                                                </#list>
+                                                <#if accountMatch.getAccountDestination()??>
+                                                    <@accountSelect selectedAccountID=accountMatch.getAccountDestination().getID()/>
+                                                <#else>
+                                                    <@accountSelect/>
+                                                </#if>
                                             </select>
                                         </div>
                                     </td>
-                                    <td class="import-text">${locale.getString("info.database.import.or")}</td>
-                                    <td>
-                                        <@header.buttonLink url='/accounts/newAccount' icon='add' localizationKey='title.account.new' classes='button-new-account'/>
-                                    </td>
                                 </tr>
                             </#list>
                         </table>
@@ -68,7 +74,7 @@
                             </div>
 
                             <div class="col m6 l4 left-align">
-                                <@header.buttonSubmit name='action' icon='unarchive' localizationKey='settings.database.import' id='buttonImport'/>
+                                <@header.buttonSubmit name='action' icon='unarchive' localizationKey='settings.database.import' id='buttonImport' formaction='/settings/database/import/step3'/>
                             </div>
                         </div>
                     </form>
@@ -81,4 +87,12 @@
         <@scripts.scripts/>
         <script src="<@s.url '/js/import.js'/>"></script>
     </@header.body>
-</html>
\ No newline at end of file
+</html>
+
+<#macro accountSelect selectedAccountID=-1>
+    <#list availableAccounts as account>
+        <#if (account.getType().name() == "CUSTOM")>
+            <option value="${account.getID()?c}" <#if account.getID() == selectedAccountID>selected</#if>>${account.getName()}</option>
+        </#if>
+    </#list>
+</#macro>
\ No newline at end of file
diff --git a/src/main/resources/templates/settings/settings.ftl b/src/main/resources/templates/settings/settings.ftl
index 96600407c6b3dda77401325e1eb9cb080cfe8432..b50c4d1b3db51f5d7c000f70af9afc7c13259943 100644
--- a/src/main/resources/templates/settings/settings.ftl
+++ b/src/main/resources/templates/settings/settings.ftl
@@ -29,7 +29,6 @@
                             <input type="hidden" name="lastBackupReminderDate" value="${dateService.getLongDateString(settings.getLastBackupReminderDate())}">
                             <input type="hidden" name="installedVersionCode" value="${settings.getInstalledVersionCode()}">
                             <input type="hidden" name="whatsNewShownForCurrentVersion" value="${settings.getWhatsNewShownForCurrentVersion()?c}">
-                            <input type="hidden" name="showFirstUseBanner" value="${settings.getShowFirstUseBanner()?c}">
 
                             <#-- password -->
                             <div class="row">
@@ -226,6 +225,19 @@
                         </div>
                     </div>
 
+                    <hr>
+                    <#-- hints -->
+                    <div class="container">
+                        <div class="section center-align">
+                            <div class="headline">${locale.getString("headline.hints")}</div>
+                        </div>
+                    </div>
+                    <div class="row">
+                        <div class="col s12 center-align">
+                            <@header.buttonLink url='/hints/resetAll' icon='restore' localizationKey='button.hints.reset'/>
+                        </div>
+                    </div>
+
                     <hr>
                     <#-- database -->
                     <div class="container">
@@ -255,6 +267,10 @@
             <@settingsMacros.update/>
         </#if>
 
+        <script>
+            copiedToClipboard = '${locale.getString("copied")}';
+        </script>
+
         <!-- Scripts-->
         <#import "../helpers/scripts.ftl" as scripts>
         <@scripts.scripts/>
diff --git a/src/main/resources/templates/settings/settingsMacros.ftl b/src/main/resources/templates/settings/settingsMacros.ftl
index ce37a7d087eec9f0b6d648ef908dc85dd4c9e1cd..8ed321ea2ce00ed35ce5e70ba2905aac594c14aa 100644
--- a/src/main/resources/templates/settings/settingsMacros.ftl
+++ b/src/main/resources/templates/settings/settingsMacros.ftl
@@ -86,7 +86,7 @@
         <div class="modal-content">
             <h4>${locale.getString("info.title.database.delete")}</h4>
             <p>${locale.getString("info.header.text.database.delete")}</p>
-            <p>${locale.getString("info.text.database.delete", verificationCode)}</p>
+            <p class="valign-wrapper">${locale.getString("info.text.database.delete")} <span id="verificationCode">${verificationCode}</span></p>
 
             <form id="form-confirm-database-delete" action="<@s.url '/settings/database/delete'/>" method="post">
                 <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
diff --git a/src/main/resources/templates/tags/tags.ftl b/src/main/resources/templates/tags/tags.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..68f56c669c72b574757cb1107e7b614e5de0dc50
--- /dev/null
+++ b/src/main/resources/templates/tags/tags.ftl
@@ -0,0 +1,55 @@
+<html>
+    <head>
+        <#import "../helpers/header.ftl" as header>
+        <@header.globals/>
+        <@header.header "BudgetMaster - ${locale.getString('menu.tags')}"/>
+        <#import "/spring.ftl" as s>
+    </head>
+    <@header.body>
+        <#import "../helpers/navbar.ftl" as navbar>
+        <@navbar.navbar "tags" settings/>
+
+        <main>
+            <div class="card main-card background-color">
+                <div class="container">
+                    <div class="section center-align">
+                        <div class="headline"><i class="material-icons">local_offer</i> ${locale.getString("menu.tags")}</div>
+                    </div>
+                </div>
+
+                <@header.content>
+                    <div class="container">
+                        <#if tagUsages?keys?size == 0>
+                            <div class="headline center-align">${locale.getString("placeholder")}</div>
+                        <#else>
+                            <table class="bordered">
+                                <thead>
+                                    <tr>
+                                        <th>${locale.getString("category.new.label.name")}</th>
+                                        <th>${locale.getString("categories.usages")}</th>
+                                        <th>${locale.getString("categories.actions")}</th>
+                                    </tr>
+                                </thead>
+                                <#list tagUsages as tagName, usageCount>
+                                    <tr>
+                                        <td>${tagName} </td>
+                                        <td>
+                                            <a href="<@s.url '/search?searchTags=true&searchText=' + tagName/>" class="waves-effect waves-light text-default">${usageCount}</a>
+                                        </td>
+                                        <td>
+                                            <@header.buttonFlat url='/search?searchTags=true&searchText=' + tagName icon='search' localizationKey='' classes="no-padding text-default"/>
+                                        </td>
+                                    </tr>
+                                </#list>
+                            </table>
+                        </#if>
+                    </div>
+                </@header.content>
+            </div>
+        </main>
+
+        <!--  Scripts-->
+        <#import "../helpers/scripts.ftl" as scripts>
+        <@scripts.scripts/>
+    </@header.body>
+</html>
diff --git a/src/main/resources/templates/templates/deleteTemplateModal.ftl b/src/main/resources/templates/templates/deleteTemplateModal.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..868f349b3ed13bb8b1e82911a8e8e1b192b1c397
--- /dev/null
+++ b/src/main/resources/templates/templates/deleteTemplateModal.ftl
@@ -0,0 +1,7 @@
+<#global locale = static["de.thecodelabs.utils.util.Localization"]>
+<#import "/spring.ftl" as s>
+<#import "../helpers/header.ftl" as header>
+
+<@header.modalConfirmDelete title=locale.getString("info.title.template.delete") confirmUrl='/templates' itemId=templateToDelete.getID() confirmButtonTextKey='info.title.template.delete'>
+    <p>${locale.getString("info.text.template.delete", templateToDelete.getTemplateName())}</p>
+</@header.modalConfirmDelete>
\ No newline at end of file
diff --git a/src/main/resources/templates/templates/newTemplate.ftl b/src/main/resources/templates/templates/newTemplate.ftl
index 9693848c25e82def2046ef150694a80a76028ca5..96d29e2acdcca858d0bb217866a211093d7ed8d7 100644
--- a/src/main/resources/templates/templates/newTemplate.ftl
+++ b/src/main/resources/templates/templates/newTemplate.ftl
@@ -12,7 +12,7 @@
         <@header.style "transactions"/>
         <@header.style "datepicker"/>
         <@header.style "collapsible"/>
-        <@header.style "imageSelect"/>
+        <@header.style "iconSelect"/>
         <#import "/spring.ftl" as s>
     </head>
     <@header.body>
@@ -22,7 +22,7 @@
         <#import "../transactions/newTransactionMacros.ftl" as newTransactionMacros>
         <#import "templateFunctions.ftl" as templateFunctions>
         <#import "../helpers/customSelectMacros.ftl" as customSelectMacros>
-        <#import "../helpers/imageSelect.ftl" as imageSelectMacros>
+        <#import "../helpers/iconSelect.ftl" as iconSelectMacros>
 
         <main>
             <div class="card main-card background-color">
@@ -79,7 +79,7 @@
                         </#if>
 
                         <#-- icon -->
-                        <@imageSelectMacros.imageSelect id="template-icon" item=template/>
+                        <@iconSelectMacros.iconSelect id="template-icon" item=template/>
 
                         <br>
                         <#-- buttons -->
@@ -90,7 +90,7 @@
             </div>
         </main>
 
-        <@imageSelectMacros.modalIconSelect idToFocusOnClose="template-name"/>
+        <@iconSelectMacros.modalIconSelect idToFocusOnClose="template-name" item=template/>
 
         <!-- Pass localization to JS -->
         <#import "../helpers/globalDatePicker.ftl" as datePicker>
@@ -103,6 +103,6 @@
         <script src="<@s.url '/js/helpers.js'/>"></script>
         <script src="<@s.url '/js/transactions.js'/>"></script>
         <script src="<@s.url '/js/templates.js'/>"></script>
-        <script src="<@s.url '/js/imageSelect.js'/>"></script>
+        <script src="<@s.url '/js/iconSelect.js'/>"></script>
     </@header.body>
 </html>
diff --git a/src/main/resources/templates/templates/templateFunctions.ftl b/src/main/resources/templates/templates/templateFunctions.ftl
index 90928593cd4b9a5f5bc3e2a2b6baeb3cc6985118..b12f22a1461b9d7444ba80d214086e57c220a925 100644
--- a/src/main/resources/templates/templates/templateFunctions.ftl
+++ b/src/main/resources/templates/templates/templateFunctions.ftl
@@ -26,7 +26,7 @@
                                 <@templateHeader template/>
                                 <div class="collapsible-header-button">
                                     <@header.buttonFlat url='/templates/' + template.ID?c + '/edit' icon='edit' localizationKey='' classes="no-padding text-default"/>
-                                    <@header.buttonFlat url='/templates/' + template.ID?c + '/requestDelete' icon='delete' localizationKey='' classes="no-padding text-default"/>
+                                    <@header.buttonFlat url='/templates/' + template.ID?c + '/requestDelete' icon='delete' localizationKey='' classes="no-padding text-default button-request-delete-template" isDataUrl=true/>
                                     <@header.buttonLink url='/templates/' + template.ID?c + '/select' icon='note_add' localizationKey='' classes='button-select-template'/>
                                 </div>
                             </div>
@@ -52,8 +52,8 @@
 </#macro>
 
 <#macro templateHeader template>
-    <#if template.getIcon()??>
-       <img src="${template.getIcon().getBase64EncodedImage()}" class="template-icon"/>
+    <#if template.getIconReference()??>
+        <@header.entityIcon entity=template classes="template-icon text-default"/>
     <#elseif template.getTransferAccount()??>
         <i class="material-icons">swap_horiz</i>
     <#else>
diff --git a/src/main/resources/templates/templates/templates.ftl b/src/main/resources/templates/templates/templates.ftl
index 1325cfae2ab20e29bf79fa8ead10c945c8bba04c..29b6eed010090b38cf2fb0fd251d2986800f29b0 100644
--- a/src/main/resources/templates/templates/templates.ftl
+++ b/src/main/resources/templates/templates/templates.ftl
@@ -33,6 +33,9 @@
                     <br>
                     <@templateFunctions.buttons/>
                     <br>
+                    <#assign hint=helpers.getHintByLocalizationKey("hint.template.arrow.keys")/>
+                    <@header.hint hint=hint/>
+                    <br>
                     <#if templates?size == 0>
                         <div class="container">
                             <div class="headline center-align">${locale.getString("placeholder")}</div>
@@ -43,11 +46,7 @@
                 </div>
             </@header.content>
 
-            <#if currentTemplate??>
-                <@header.modalConfirmDelete title=locale.getString("info.title.template.delete") confirmUrl='/templates' cancelUrlBase='/templates' itemId=currentTemplate.getID() confirmButtonTextKey='info.title.template.delete'>
-                    <p>${locale.getString("info.text.template.delete", currentTemplate.getTemplateName())}</p>
-                </@header.modalConfirmDelete>
-            </#if>
+            <div id="deleteModalContainerOnDemand"></div>
         </main>
 
         <#import "../helpers/scripts.ftl" as scripts>
diff --git a/src/main/resources/templates/transactions/deleteTransactionModal.ftl b/src/main/resources/templates/transactions/deleteTransactionModal.ftl
new file mode 100644
index 0000000000000000000000000000000000000000..847e92f2eff19c92012b9058bd47abfe1e3280c0
--- /dev/null
+++ b/src/main/resources/templates/transactions/deleteTransactionModal.ftl
@@ -0,0 +1,11 @@
+<#global locale = static["de.thecodelabs.utils.util.Localization"]>
+<#import "/spring.ftl" as s>
+<#import "../helpers/header.ftl" as header>
+
+<@header.modalConfirmDelete title=locale.getString("info.title.transaction.delete") confirmUrl='/transactions' itemId=transactionToDelete.getID() confirmButtonTextKey='delete'>
+    <#if transactionToDelete.isRepeating()>
+        <p>${locale.getString("info.text.transaction.repeating.delete", transactionToDelete.name)}</p>
+    <#else>
+        <p>${locale.getString("info.text.transaction.delete", transactionToDelete.name)}</p>
+    </#if>
+</@header.modalConfirmDelete>
\ No newline at end of file
diff --git a/src/main/resources/templates/transactions/newTransactionNormal.ftl b/src/main/resources/templates/transactions/newTransactionNormal.ftl
index aa8a182ee21be50eb6cff25d0001f38df528b659..82b800818421efb6acb1c75ac24273798dc98a39 100644
--- a/src/main/resources/templates/transactions/newTransactionNormal.ftl
+++ b/src/main/resources/templates/transactions/newTransactionNormal.ftl
@@ -43,6 +43,9 @@
                             <#-- isPayment switch -->
                             <@newTransactionMacros.isExpenditureSwitch transaction/>
 
+                            <#assign hint=helpers.getHintByLocalizationKey("hint.transaction.save")/>
+                            <@header.hint hint=hint/>
+
                             <#-- name -->
                             <@newTransactionMacros.transactionName transaction suggestionsJSON/>
 
diff --git a/src/main/resources/templates/transactions/newTransactionRepeating.ftl b/src/main/resources/templates/transactions/newTransactionRepeating.ftl
index 1756b0f9f007aae6e76a556f2f8f2f53712bd2de..5c9d47f7b3a9265a298045676131f05d58a54eb4 100644
--- a/src/main/resources/templates/transactions/newTransactionRepeating.ftl
+++ b/src/main/resources/templates/transactions/newTransactionRepeating.ftl
@@ -41,6 +41,9 @@
                             <#-- isPayment switch -->
                             <@newTransactionMacros.isExpenditureSwitch transaction/>
 
+                            <#assign hint=helpers.getHintByLocalizationKey("hint.transaction.save")/>
+                            <@header.hint hint=hint/>
+
                             <#-- name -->
                             <@newTransactionMacros.transactionName transaction suggestionsJSON/>
 
diff --git a/src/main/resources/templates/transactions/newTransactionTransfer.ftl b/src/main/resources/templates/transactions/newTransactionTransfer.ftl
index 4055fb273794efa1f36099ab92db54cc8fdf0c3f..96c3c21e669ea142fc29315ef2b3ed87564560b1 100644
--- a/src/main/resources/templates/transactions/newTransactionTransfer.ftl
+++ b/src/main/resources/templates/transactions/newTransactionTransfer.ftl
@@ -41,6 +41,9 @@
                             <input type="hidden" name="isExpenditure" value="true">
                             <input type="hidden" name="previousType" value="<#if previousType??>${previousType.name()}</#if>">
 
+                            <#assign hint=helpers.getHintByLocalizationKey("hint.transaction.save")/>
+                            <@header.hint hint=hint/>
+
                             <#-- name -->
                             <@newTransactionMacros.transactionName transaction suggestionsJSON/>
 
diff --git a/src/main/resources/templates/transactions/transactions.ftl b/src/main/resources/templates/transactions/transactions.ftl
index 75eaec1aad13c6938bb96f34c0d6bac710ff14a6..28a841526993ddb3e77934d81f6abccf3425a31f 100644
--- a/src/main/resources/templates/transactions/transactions.ftl
+++ b/src/main/resources/templates/transactions/transactions.ftl
@@ -91,15 +91,7 @@
                 </@header.content>
             </div>
 
-            <#if currentTransaction??>
-                <@header.modalConfirmDelete title=locale.getString("info.title.transaction.delete") confirmUrl='/transactions' cancelUrlBase='/transactions' itemId=currentTransaction.getID() confirmButtonTextKey='delete'>
-                    <#if currentTransaction.isRepeating()>
-                        <p>${locale.getString("info.text.transaction.repeating.delete", currentTransaction.name)}</p>
-                    <#else>
-                        <p>${locale.getString("info.text.transaction.delete", currentTransaction.name)}</p>
-                    </#if>
-                </@header.modalConfirmDelete>
-            </#if>
+            <div id="deleteModalContainerOnDemand"></div>
 
             <@filterMacros.filterModal filterConfiguration/>
         </main>
diff --git a/src/main/resources/templates/transactions/transactionsMacros.ftl b/src/main/resources/templates/transactions/transactionsMacros.ftl
index 8fdaf57b20d71477352927cf8edc9b3b57752276..70c6acb1e0f9fb1ba5c288b6ea5c6ec92cfd54ee 100644
--- a/src/main/resources/templates/transactions/transactionsMacros.ftl
+++ b/src/main/resources/templates/transactions/transactionsMacros.ftl
@@ -17,10 +17,10 @@
     <#import "../categories/categoriesFunctions.ftl" as categoriesFunctions>
     <div class="col s2 l1 xl1 ${alignment}">
         <div class="hide-on-med-and-down">
-            <@categoriesFunctions.categoryCircle transaction.category/>
+            <@categoriesFunctions.categoryCircle category=transaction.category enableSearchWrapper=true/>
         </div>
         <div class="hide-on-large-only">
-            <@categoriesFunctions.categoryCircle transaction.category "category-circle-small"/>
+            <@categoriesFunctions.categoryCircle category=transaction.category classes="category-circle-small" enableSearchWrapper=true/>
         </div>
     </div>
 </#macro>
@@ -47,9 +47,9 @@
 
 <#macro transactionButtons transaction>
         <div class="col s8 l2 xl1 right-align transaction-buttons no-wrap">
-            <#if (transaction.category.type.name() != "REST") && transaction.getAccount().getAccountState().name() == "FULL_ACCESS">
+            <#if transaction.isEditable()>
                 <@header.buttonFlat url='/transactions/' + transaction.ID?c + '/edit' icon='edit' localizationKey='' classes="no-padding text-default"/>
-                <@header.buttonFlat url='/transactions/' + transaction.ID?c + '/requestDelete' icon='delete' localizationKey='' classes="no-padding text-default"/>
+                <@header.buttonFlat url='/transactions/' + transaction.ID?c + '/requestDelete' icon='delete' localizationKey='' classes="no-padding text-default button-request-delete-transaction" isDataUrl=true/>
             </#if>
         </div>
 </#macro>
@@ -57,14 +57,16 @@
 <#macro transactionAccountIcon transaction>
     <#if helpers.getCurrentAccount().getType().name() == "ALL" && transaction.getAccount()??>
         <#import "../helpers/customSelectMacros.ftl" as customSelectMacros>
-        <div class="col s2 l1 xl1 tooltipped no-padding" data-position="bottom" data-tooltip="${transaction.getAccount().getName()}">
-            <div class="hide-on-med-and-down">
-                <@customSelectMacros.accountIcon transaction.getAccount() transaction.getAccount().getName()/>
-            </div>
-            <div class="hide-on-large-only">
-                <@customSelectMacros.accountIcon transaction.getAccount() transaction.getAccount().getName() "category-circle-small"/>
+        <a href="<@s.url '/accounts/' + transaction.getAccount().getID() + '/select'/>">
+            <div class="col s2 l1 xl1 tooltipped no-padding" data-position="bottom" data-tooltip="${transaction.getAccount().getName()}">
+                <div class="hide-on-med-and-down">
+                    <@customSelectMacros.accountIcon transaction.getAccount() transaction.getAccount().getName()/>
+                </div>
+                <div class="hide-on-large-only">
+                    <@customSelectMacros.accountIcon transaction.getAccount() transaction.getAccount().getName() "category-circle-small"/>
+                </div>
             </div>
-        </div>
+        </a>
     </#if>
 
 </#macro>
diff --git a/src/main/resources/templates/whatsNewModal.ftl b/src/main/resources/templates/whatsNewModal.ftl
index 1619f3297320cb775d2cfe637942de60658661e8..75c2e1522333956bc41c5d21fb80e2982499c42a 100644
--- a/src/main/resources/templates/whatsNewModal.ftl
+++ b/src/main/resources/templates/whatsNewModal.ftl
@@ -26,10 +26,10 @@
                     ${locale.getString("about.date")} ${build.getVersionDate()}
                 </div>
                 <div>
-                    ${locale.getString("news.all.releases")} <a href="${locale.getString("roadmap.url")}">${locale.getString("about.roadmap.link")}</a>
+                    ${locale.getString("news.all.releases")} <a target="_blank" href="${locale.getString("roadmap.url")}">${locale.getString("about.roadmap.link")}</a>
                 </div>
                 <div>
-                    ${locale.getString("news.detailed")} <a href="https://github.com/deadlocker8/BudgetMaster/releases/tag/v${build.getVersionName()}">GitHub</a>
+                    ${locale.getString("news.detailed")} <a target="_blank" href="https://github.com/deadlocker8/BudgetMaster/releases/tag/v${build.getVersionName()}">GitHub</a>
                 </div>
             </div>
         </div>
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/DateRepairTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/DateRepairTest.java
index b665d072c97fa9092d98c3c33726d19a631238b5..81b76d44ab67909abb7040475e2f02c359929bcf 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/DateRepairTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/DateRepairTest.java
@@ -5,8 +5,7 @@ import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
 import de.deadlocker8.budgetmaster.tags.Tag;
 import de.deadlocker8.budgetmaster.transactions.Transaction;
 import de.deadlocker8.budgetmaster.transactions.TransactionRepository;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.jdbc.DataSourceBuilder;
@@ -22,19 +21,17 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.sql.DataSource;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringRunner.class)
 @SpringBootTest(classes = Main.class)
 @Import(DateRepairTest.TestDatabaseConfiguration.class)
 @ActiveProfiles("test")
 @SeleniumTest
 @Transactional
-public class DateRepairTest
+class DateRepairTest
 {
 	@TestConfiguration
 	static class TestDatabaseConfiguration
@@ -56,7 +53,7 @@ public class DateRepairTest
 	private TransactionRepository transactionRepository;
 
 	@Test
-	public void test_Repeating_WithTags()
+	void test_Repeating_WithTags()
 	{
 		final List<Transaction> transactions = transactionRepository.findAll();
 		assertThat(transactions).hasSize(8);
@@ -69,7 +66,7 @@ public class DateRepairTest
 	}
 
 	@Test
-	public void test_Repeating()
+	void test_Repeating()
 	{
 		final List<Transaction> transactions = transactionRepository.findAll();
 		assertThat(transactions).hasSize(8);
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/helpers/IntegrationTestHelper.java b/src/test/java/de/deadlocker8/budgetmaster/integration/helpers/IntegrationTestHelper.java
index ce3926a2550c2c574c1681e45334879f8893a563..13c628764ebc7e39a6f6ee0b63c7e3bb7e235065 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/helpers/IntegrationTestHelper.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/helpers/IntegrationTestHelper.java
@@ -3,7 +3,6 @@ package de.deadlocker8.budgetmaster.integration.helpers;
 import de.deadlocker8.budgetmaster.accounts.Account;
 import de.deadlocker8.budgetmaster.accounts.AccountState;
 import de.thecodelabs.utils.util.Localization;
-import org.junit.rules.TestName;
 import org.openqa.selenium.*;
 import org.openqa.selenium.support.ui.ExpectedConditions;
 import org.openqa.selenium.support.ui.WebDriverWait;
@@ -18,7 +17,7 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.List;
 
-import static org.junit.Assert.assertEquals;
+import static org.assertj.core.api.Assertions.assertThat;
 
 public class IntegrationTestHelper
 {
@@ -140,7 +139,8 @@ public class IntegrationTestHelper
 
 		// close result page
 		driver.findElement(By.id("button-finish-import")).click();
-		assertEquals(Localization.getString("menu.settings"), IntegrationTestHelper.getTextNode(driver.findElement(By.className("headline"))));
+		assertThat(IntegrationTestHelper.getTextNode(driver.findElement(By.className("headline"))))
+				.isEqualTo(Localization.getString("menu.settings"));
 
 		start();
 	}
@@ -172,10 +172,11 @@ public class IntegrationTestHelper
 	private void matchAccounts(List<String> sourceAccounts, List<Account> destinationAccounts)
 	{
 		WebElement headlineImport = driver.findElement(By.className("headline"));
-		assertEquals(Localization.getString("info.title.database.import.dialog"), IntegrationTestHelper.getTextNode(headlineImport));
+		assertThat(IntegrationTestHelper.getTextNode(headlineImport))
+				.isEqualTo(Localization.getString("info.title.database.import.dialog"));
 
 		List<WebElement> tableRows = driver.findElements(By.cssSelector(".container form table tr"));
-		assertEquals(destinationAccounts.size(), tableRows.size());
+		assertThat(tableRows.size()).isEqualTo(destinationAccounts.size());
 
 		for(int i = 0; i < destinationAccounts.size(); i++)
 		{
@@ -183,7 +184,7 @@ public class IntegrationTestHelper
 
 			WebElement row = tableRows.get(i);
 			WebElement sourceAccount = row.findElement(By.className("account-source"));
-			assertEquals(sourceAccounts.get(i), IntegrationTestHelper.getTextNode(sourceAccount));
+			assertThat(IntegrationTestHelper.getTextNode(sourceAccount)).isEqualTo(sourceAccounts.get(i));
 
 			WebDriverWait wait = new WebDriverWait(driver, 5);
 			wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("select-dropdown")));
@@ -194,12 +195,10 @@ public class IntegrationTestHelper
 		}
 	}
 
-	public static void saveScreenshots(WebDriver webDriver, TestName testName, Class testClass)
+	public static void saveScreenshots(WebDriver webDriver, String methodName, String className)
 	{
 		File screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
 
-		String className = testClass.getSimpleName();
-		String methodName = testName.getMethodName();
 		final Path destination = Paths.get("screenshots", className + "_" + methodName + "_" + screenshot.getName());
 
 		try
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/helpers/SeleniumTestBase.java b/src/test/java/de/deadlocker8/budgetmaster/integration/helpers/SeleniumTestBase.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c3a9432f6591e7b5d7aaf9ed0ce09d977afa010
--- /dev/null
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/helpers/SeleniumTestBase.java
@@ -0,0 +1,30 @@
+package de.deadlocker8.budgetmaster.integration.helpers;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.firefox.FirefoxDriver;
+import org.openqa.selenium.firefox.FirefoxOptions;
+import org.springframework.boot.web.server.LocalServerPort;
+
+public class SeleniumTestBase
+{
+	protected WebDriver driver;
+
+	@LocalServerPort
+	protected int port;
+
+	@BeforeEach
+	public final void init()
+	{
+		FirefoxOptions options = new FirefoxOptions();
+		options.setHeadless(false);
+		options.addPreference("devtools.console.stdout.content", true);
+		driver = new FirefoxDriver(options);
+		driver.manage().window().maximize();
+	}
+
+	public WebDriver getDriver()
+	{
+		return driver;
+	}
+}
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/helpers/SeleniumTestWatcher.java b/src/test/java/de/deadlocker8/budgetmaster/integration/helpers/SeleniumTestWatcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..f802c3c9deb5d3810011f9d0a02e80cbb99e1258
--- /dev/null
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/helpers/SeleniumTestWatcher.java
@@ -0,0 +1,36 @@
+package de.deadlocker8.budgetmaster.integration.helpers;
+
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.TestWatcher;
+import org.openqa.selenium.WebDriver;
+
+public class SeleniumTestWatcher implements TestWatcher
+{
+	@Override
+	public void testSuccessful(ExtensionContext context)
+	{
+		final WebDriver driver = getDriver(context);
+		driver.quit();
+	}
+
+	@Override
+	public void testAborted(ExtensionContext context, Throwable cause)
+	{
+		final WebDriver driver = getDriver(context);
+		driver.quit();
+	}
+
+	@Override
+	public void testFailed(ExtensionContext context, Throwable cause)
+	{
+		final WebDriver driver = getDriver(context);
+		IntegrationTestHelper.saveScreenshots(driver, context.getRequiredTestMethod().getName(), context.getRequiredTestClass().getSimpleName());
+		driver.quit();
+	}
+
+	private WebDriver getDriver(ExtensionContext context)
+	{
+		final SeleniumTestBase testInstance = (SeleniumTestBase) context.getRequiredTestInstance();
+		return testInstance.getDriver();
+	}
+}
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/AccountTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/AccountTest.java
index 0c2823b26545ed2ca28915d40b314b2eb7a9c9cd..679e1d32160bac1933771ce4f18e29a8de4d463d 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/AccountTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/AccountTest.java
@@ -5,16 +5,13 @@ import de.deadlocker8.budgetmaster.accounts.Account;
 import de.deadlocker8.budgetmaster.accounts.AccountState;
 import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.authentication.UserService;
-import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
-import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
-import de.deadlocker8.budgetmaster.integration.helpers.TransactionTestHelper;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
+import de.deadlocker8.budgetmaster.integration.helpers.*;
+import de.deadlocker8.budgetmaster.search.Search;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.TestWatcher;
 import org.openqa.selenium.By;
 import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.WebDriver;
@@ -26,7 +23,6 @@ import org.openqa.selenium.support.ui.WebDriverWait;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
 
 import java.io.File;
 import java.util.Arrays;
@@ -35,46 +31,17 @@ import java.util.stream.Collectors;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringRunner.class)
+@ExtendWith(SeleniumTestWatcher.class)
 @SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
 @SeleniumTest
-public class AccountTest
+class AccountTest extends SeleniumTestBase
 {
 	private IntegrationTestHelper helper;
-	private WebDriver driver;
 
-	@LocalServerPort
-	int port;
-
-	@Rule
-	public TestName name = new TestName();
-
-	@Rule
-	public TestWatcher testWatcher = new TestWatcher()
-	{
-		@Override
-		protected void finished(Description description)
-		{
-			driver.quit();
-		}
-
-		@Override
-		protected void failed(Throwable e, Description description)
-		{
-			IntegrationTestHelper.saveScreenshots(driver, name, AccountTest.class);
-		}
-	};
-
-	@Before
+	@BeforeEach
 	public void prepare()
 	{
-		FirefoxOptions options = new FirefoxOptions();
-		options.setHeadless(false);
-		options.addPreference("devtools.console.stdout.content", true);
-		driver = new FirefoxDriver(options);
-
-		// prepare
 		helper = new IntegrationTestHelper(driver, port);
 		helper.start();
 		helper.login(UserService.DEFAULT_PASSWORD);
@@ -96,7 +63,7 @@ public class AccountTest
 	}
 
 	@Test
-	public void test_newAccount_cancel()
+	void test_newAccount_cancel()
 	{
 		driver.get(helper.getUrl() + "/accounts");
 		driver.findElement(By.id("button-new-account")).click();
@@ -117,7 +84,7 @@ public class AccountTest
 	}
 
 	@Test
-	public void test_newAccount()
+	void test_newAccount()
 	{
 		driver.get(helper.getUrl() + "/accounts");
 		driver.findElement(By.id("button-new-account")).click();
@@ -149,7 +116,7 @@ public class AccountTest
 	}
 
 	@Test
-	public void test_edit()
+	void test_edit()
 	{
 		driver.get(helper.getUrl() + "/accounts/2/edit");
 
@@ -158,7 +125,7 @@ public class AccountTest
 	}
 
 	@Test
-	public void test_readOnly_newTransaction_listOnlyReadableAccounts()
+	void test_readOnly_newTransaction_listOnlyReadableAccounts()
 	{
 		driver.get(helper.getUrl() + "/transactions");
 		driver.findElement(By.id("button-new-transaction")).click();
@@ -180,7 +147,7 @@ public class AccountTest
 	}
 
 	@Test
-	public void test_readOnly_preventTransactionDeleteAndEdit()
+	void test_readOnly_preventTransactionDeleteAndEdit()
 	{
 		// select "sfsdf"
 		TransactionTestHelper.selectGlobalAccountByName(driver, "sfsdf");
@@ -226,7 +193,7 @@ public class AccountTest
 	}
 
 	@Test
-	public void test_readOnly_preventNewTransaction()
+	void test_readOnly_preventNewTransaction()
 	{
 		TransactionTestHelper.selectGlobalAccountByName(driver, "read only account");
 
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/CategorySelectTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/CategorySelectTest.java
index 6d3c9eee3ee11cc6425bf3df43fa3d6d5ca00338..e1324c9a3dc05da67eb72e9dcfccd2c5f63d9be2 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/CategorySelectTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/CategorySelectTest.java
@@ -6,25 +6,16 @@ import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.authentication.UserService;
 import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
 import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestBase;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 import org.openqa.selenium.By;
 import org.openqa.selenium.Keys;
-import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
-import org.openqa.selenium.firefox.FirefoxDriver;
-import org.openqa.selenium.firefox.FirefoxOptions;
 import org.openqa.selenium.support.ui.ExpectedConditions;
 import org.openqa.selenium.support.ui.WebDriverWait;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
 
 import java.io.File;
 import java.util.Arrays;
@@ -32,46 +23,16 @@ import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringRunner.class)
 @SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
 @SeleniumTest
-public class CategorySelectTest
+class CategorySelectTest extends SeleniumTestBase
 {
 	private IntegrationTestHelper helper;
-	private WebDriver driver;
 
-	@LocalServerPort
-	int port;
-
-	@Rule
-	public TestName name = new TestName();
-
-	@Rule
-	public TestWatcher testWatcher = new TestWatcher()
-	{
-		@Override
-		protected void finished(Description description)
-		{
-			driver.quit();
-		}
-
-		@Override
-		protected void failed(Throwable e, Description description)
-		{
-			IntegrationTestHelper.saveScreenshots(driver, name, CategorySelectTest.class);
-		}
-	};
-
-	@Before
+	@BeforeEach
 	public void prepare()
 	{
-		FirefoxOptions options = new FirefoxOptions();
-		options.setHeadless(false);
-		options.addPreference("devtools.console.stdout.content", true);
-		driver = new FirefoxDriver(options);
-
-		// prepare
 		helper = new IntegrationTestHelper(driver, port);
 		helper.start();
 		helper.login(UserService.DEFAULT_PASSWORD);
@@ -99,7 +60,7 @@ public class CategorySelectTest
 	}
 
 	@Test
-	public void test_newTransaction_openWithEnter()
+	void test_newTransaction_openWithEnter()
 	{
 		// navigate to category select with tab traversal
 		driver.findElement(By.tagName("body")).sendKeys(Keys.TAB);
@@ -121,7 +82,7 @@ public class CategorySelectTest
 	}
 
 	@Test
-	public void test_newTransaction_goDownWithKey()
+	void test_newTransaction_goDownWithKey()
 	{
 		// open category select
 		driver.findElement(By.cssSelector(".category-select-wrapper .custom-select-trigger")).click();
@@ -150,7 +111,7 @@ public class CategorySelectTest
 	}
 
 	@Test
-	public void test_newTransaction_goUpWithKey()
+	void test_newTransaction_goUpWithKey()
 	{
 		// open category select
 		driver.findElement(By.cssSelector(".category-select-wrapper .custom-select-trigger")).click();
@@ -179,7 +140,7 @@ public class CategorySelectTest
 	}
 
 	@Test
-	public void test_newTransaction_confirmWithEnter()
+	void test_newTransaction_confirmWithEnter()
 	{
 		// open category select
 		driver.findElement(By.cssSelector(".category-select-wrapper .custom-select-trigger")).click();
@@ -199,7 +160,7 @@ public class CategorySelectTest
 	}
 
 	@Test
-	public void test_newTransaction_jumpToCategoryByFirstLetter()
+	void test_newTransaction_jumpToCategoryByFirstLetter()
 	{
 		// open category select
 		driver.findElement(By.cssSelector(".category-select-wrapper .custom-select-trigger")).click();
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/ChangeTransactionTypeTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/ChangeTransactionTypeTest.java
index c1c1781a0c8138d60cb32cc7c89e9840cd657281..b8e5c4721177e137bffc0eef746c36a7ff6af137 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/ChangeTransactionTypeTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/ChangeTransactionTypeTest.java
@@ -4,29 +4,18 @@ import de.deadlocker8.budgetmaster.Main;
 import de.deadlocker8.budgetmaster.accounts.Account;
 import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.authentication.UserService;
-import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
-import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
-import de.deadlocker8.budgetmaster.integration.helpers.TransactionTestHelper;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
+import de.deadlocker8.budgetmaster.integration.helpers.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.openqa.selenium.By;
 import org.openqa.selenium.NoSuchElementException;
-import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
-import org.openqa.selenium.firefox.FirefoxDriver;
-import org.openqa.selenium.firefox.FirefoxOptions;
 import org.openqa.selenium.interactions.Actions;
 import org.openqa.selenium.support.ui.ExpectedConditions;
 import org.openqa.selenium.support.ui.WebDriverWait;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
 
 import java.io.File;
 import java.util.Arrays;
@@ -35,36 +24,13 @@ import java.util.List;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-@RunWith(SpringRunner.class)
+@ExtendWith(SeleniumTestWatcher.class)
 @SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
 @SeleniumTest
-public class ChangeTransactionTypeTest
+class ChangeTransactionTypeTest extends SeleniumTestBase
 {
 	private IntegrationTestHelper helper;
-	private WebDriver driver;
-
-	@LocalServerPort
-	int port;
-
-	@Rule
-	public TestName name = new TestName();
-
-	@Rule
-	public TestWatcher testWatcher = new TestWatcher()
-	{
-		@Override
-		protected void finished(Description description)
-		{
-			driver.quit();
-		}
-
-		@Override
-		protected void failed(Throwable e, Description description)
-		{
-			IntegrationTestHelper.saveScreenshots(driver, name, ChangeTransactionTypeTest.class);
-		}
-	};
 
 	private void openTransferTypeModal(int transactionID)
 	{
@@ -85,15 +51,9 @@ public class ChangeTransactionTypeTest
 		assertThat(driver.findElement(By.id("modalChangeTransactionType")).isDisplayed()).isTrue();
 	}
 
-	@Before
+	@BeforeEach
 	public void prepare()
 	{
-		FirefoxOptions options = new FirefoxOptions();
-		options.setHeadless(false);
-		options.addPreference("devtools.console.stdout.content", true);
-		driver = new FirefoxDriver(options);
-
-		// prepare
 		helper = new IntegrationTestHelper(driver, port);
 		helper.start();
 		helper.login(UserService.DEFAULT_PASSWORD);
@@ -108,7 +68,7 @@ public class ChangeTransactionTypeTest
 	}
 
 	@Test
-	public void test_availableOptions_normal()
+	void test_availableOptions_normal()
 	{
 		openTransferTypeModal(2);
 
@@ -119,7 +79,7 @@ public class ChangeTransactionTypeTest
 	}
 
 	@Test
-	public void test_availableOptions_recurring()
+	void test_availableOptions_recurring()
 	{
 		openTransferTypeModal(6);
 
@@ -130,7 +90,7 @@ public class ChangeTransactionTypeTest
 	}
 
 	@Test
-	public void test_availableOptions_transfer()
+	void test_availableOptions_transfer()
 	{
 		openTransferTypeModal(3);
 
@@ -141,7 +101,7 @@ public class ChangeTransactionTypeTest
 	}
 
 	@Test
-	public void test_normal_to_transfer()
+	void test_normal_to_transfer()
 	{
 		openTransferTypeModal(2);
 		TransactionTestHelper.selectOptionFromDropdown(driver, By.cssSelector("#modalChangeTransactionType .select-wrapper"), "Transfer");
@@ -167,7 +127,7 @@ public class ChangeTransactionTypeTest
 	}
 
 	@Test
-	public void test_recurring_to_normal()
+	void test_recurring_to_normal()
 	{
 		openTransferTypeModal(6);
 		TransactionTestHelper.selectOptionFromDropdown(driver, By.cssSelector("#modalChangeTransactionType .select-wrapper"), "Transaction");
@@ -191,7 +151,7 @@ public class ChangeTransactionTypeTest
 	}
 
 	@Test
-	public void test_transfer_to_recurring()
+	void test_transfer_to_recurring()
 	{
 		openTransferTypeModal(3);
 		TransactionTestHelper.selectOptionFromDropdown(driver, By.cssSelector("#modalChangeTransactionType .select-wrapper"), "Recurring");
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/ChartTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/ChartTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5208fbff0d0e38e6824b07d1931af09d89701b17
--- /dev/null
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/ChartTest.java
@@ -0,0 +1,352 @@
+package de.deadlocker8.budgetmaster.integration.selenium;
+
+import de.deadlocker8.budgetmaster.Main;
+import de.deadlocker8.budgetmaster.accounts.Account;
+import de.deadlocker8.budgetmaster.accounts.AccountType;
+import de.deadlocker8.budgetmaster.authentication.UserService;
+import de.deadlocker8.budgetmaster.charts.ChartDisplayType;
+import de.deadlocker8.budgetmaster.charts.ChartGroupType;
+import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestBase;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestWatcher;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.openqa.selenium.By;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.firefox.FirefoxDriver;
+import org.openqa.selenium.firefox.FirefoxOptions;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.test.annotation.DirtiesContext;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@ExtendWith(SeleniumTestWatcher.class)
+@SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
+@SeleniumTest
+class ChartTest extends SeleniumTestBase
+{
+	private final String SELECTOR_ACTIVE_DISPLAY_TYPE = ".button-display-type.active";
+	private final String SELECTOR_ACTIVE_GROUP_TYPE = ".button-group-type.active";
+	private final String SELECTOR_VISIBLE_CHART_PREVIEWS = ".chart-preview-column:not(.hidden)";
+	private final String SELECTOR_ACTIVE_CHART_PREVIEWS = ".chart-preview.active";
+
+	private IntegrationTestHelper helper;
+
+	@BeforeEach
+	public void prepare()
+	{
+		helper = new IntegrationTestHelper(driver, port);
+		helper.start();
+		helper.login(UserService.DEFAULT_PASSWORD);
+		helper.hideBackupReminder();
+		helper.hideWhatsNewDialog();
+
+		String path = getClass().getClassLoader().getResource("SearchDatabase.json").getFile().replace("/", File.separator);
+		final Account account1 = new Account("DefaultAccount0815", AccountType.CUSTOM);
+		final Account account2 = new Account("Account2", AccountType.CUSTOM);
+
+		helper.uploadDatabase(path, Arrays.asList("DefaultAccount0815", "sfsdf"), List.of(account1, account2));
+	}
+
+	@Test
+	void test_defaultSelection()
+	{
+		driver.get(helper.getUrl() + "/charts");
+
+		// check display type
+		assertThat(getSelectedType(SELECTOR_ACTIVE_DISPLAY_TYPE)).isEqualTo(ChartDisplayType.BAR.name());
+		assertThat(driver.findElement(By.id("buttonCustomCharts")).isDisplayed()).isFalse();
+
+		// check group type
+		assertThat(driver.findElement(By.id("chart-group-type-buttons")).isDisplayed()).isTrue();
+		assertThat(getSelectedType(SELECTOR_ACTIVE_GROUP_TYPE)).isEqualTo(ChartGroupType.MONTH.name());
+
+		// check displayed chart previews
+		final List<WebElement> displayedChartPreviews = driver.findElements(By.cssSelector(SELECTOR_VISIBLE_CHART_PREVIEWS));
+		assertThat(displayedChartPreviews)
+				.hasSize(3);
+		assertThat(displayedChartPreviews.get(0).findElement(By.cssSelector(".card-action span")).getText())
+				.isEqualTo("Incomes/Expenditures");
+
+		// filter
+		assertThat(driver.findElement(By.id("filterActiveBadge")).isDisplayed()).isFalse();
+
+		// button
+		assertThat(driver.findElement(By.name("buttonSave")).isEnabled()).isFalse();
+	}
+
+	@Test
+	void test_selectDisplayType()
+	{
+		driver.get(helper.getUrl() + "/charts");
+
+		final String buttonSelector = ".button-display-type[data-value='" + ChartDisplayType.LINE.name() + "']";
+		driver.findElement(By.cssSelector(buttonSelector)).click();
+
+		WebDriverWait wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.attributeContains(By.cssSelector(buttonSelector), "class", "active"));
+
+		// check display type
+		assertThat(getSelectedType(SELECTOR_ACTIVE_DISPLAY_TYPE)).isEqualTo(ChartDisplayType.LINE.name());
+		assertThat(driver.findElement(By.id("buttonCustomCharts")).isDisplayed()).isFalse();
+
+		// check group type
+		assertThat(driver.findElement(By.id("chart-group-type-buttons")).isDisplayed()).isTrue();
+		assertThat(getSelectedType(SELECTOR_ACTIVE_GROUP_TYPE)).isEqualTo(ChartGroupType.MONTH.name());
+
+		// check displayed chart previews
+		final List<WebElement> displayedChartPreviews = driver.findElements(By.cssSelector(SELECTOR_VISIBLE_CHART_PREVIEWS));
+		assertThat(displayedChartPreviews)
+				.hasSize(1);
+		assertThat(displayedChartPreviews.get(0).findElement(By.cssSelector(".card-action span")).getText())
+				.isEqualTo("Incomes/Expenditures");
+
+		// filter
+		assertThat(driver.findElement(By.id("filterActiveBadge")).isDisplayed()).isFalse();
+
+		// button
+		assertThat(driver.findElement(By.name("buttonSave")).isEnabled()).isFalse();
+	}
+
+	@Test
+	void test_hideGroupTypeIfOnlyOneDistinct()
+	{
+		driver.get(helper.getUrl() + "/charts");
+
+		final String buttonSelector = ".button-display-type[data-value='" + ChartDisplayType.PIE.name() + "']";
+		driver.findElement(By.cssSelector(buttonSelector)).click();
+
+		WebDriverWait wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.attributeContains(By.cssSelector(buttonSelector), "class", "active"));
+
+		// check display type
+		assertThat(getSelectedType(SELECTOR_ACTIVE_DISPLAY_TYPE)).isEqualTo(ChartDisplayType.PIE.name());
+
+		// check group type
+		assertThat(driver.findElement(By.id("chart-group-type-buttons")).isDisplayed()).isFalse();
+	}
+
+	@Test
+	void test_displayGroupTypeAfterHiding()
+	{
+		driver.get(helper.getUrl() + "/charts");
+
+		String buttonSelector = ".button-display-type[data-value='" + ChartDisplayType.PIE.name() + "']";
+		driver.findElement(By.cssSelector(buttonSelector)).click();
+
+		WebDriverWait wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.attributeContains(By.cssSelector(buttonSelector), "class", "active"));
+
+		// check display type
+		assertThat(getSelectedType(SELECTOR_ACTIVE_DISPLAY_TYPE)).isEqualTo(ChartDisplayType.PIE.name());
+
+		// check group type
+		assertThat(driver.findElement(By.id("chart-group-type-buttons")).isDisplayed()).isFalse();
+
+		buttonSelector = ".button-display-type[data-value='" + ChartDisplayType.BAR.name() + "']";
+		driver.findElement(By.cssSelector(buttonSelector)).click();
+
+		wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.attributeContains(By.cssSelector(buttonSelector), "class", "active"));
+
+		// check display type
+		assertThat(getSelectedType(SELECTOR_ACTIVE_DISPLAY_TYPE)).isEqualTo(ChartDisplayType.BAR.name());
+
+		// check group type
+		assertThat(driver.findElement(By.id("chart-group-type-buttons")).isDisplayed()).isTrue();
+	}
+
+	@Test
+	void test_selectGroupType()
+	{
+		driver.get(helper.getUrl() + "/charts");
+
+		final String buttonSelector = ".button-group-type[data-value='" + ChartGroupType.YEAR.name() + "']";
+		driver.findElement(By.cssSelector(buttonSelector)).click();
+
+		WebDriverWait wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.attributeContains(By.cssSelector(buttonSelector), "class", "active"));
+
+		// check group type
+		assertThat(driver.findElement(By.id("chart-group-type-buttons")).isDisplayed()).isTrue();
+		assertThat(getSelectedType(SELECTOR_ACTIVE_GROUP_TYPE)).isEqualTo(ChartGroupType.YEAR.name());
+
+		// check displayed chart previews
+		final List<WebElement> displayedChartPreviews = driver.findElements(By.cssSelector(SELECTOR_VISIBLE_CHART_PREVIEWS));
+		assertThat(displayedChartPreviews)
+				.hasSize(1);
+		assertThat(displayedChartPreviews.get(0).findElement(By.cssSelector(".card-action span")).getText())
+				.isEqualTo("Incomes/Expenditures");
+
+		// filter
+		assertThat(driver.findElement(By.id("filterActiveBadge")).isDisplayed()).isFalse();
+
+		// button
+		assertThat(driver.findElement(By.name("buttonSave")).isEnabled()).isFalse();
+	}
+
+	@Test
+	void test_selectChartEnabledButton()
+	{
+		driver.get(helper.getUrl() + "/charts");
+
+		final String chartPreviewSelector = ".chart-preview-column[data-id='6']";
+		driver.findElement(By.cssSelector(chartPreviewSelector)).click();
+
+		final WebDriverWait wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.attributeContains(By.cssSelector(chartPreviewSelector + " .chart-preview"), "class", "active"));
+
+		// check displayed chart previews
+		final List<WebElement> activeChartPreviews = driver.findElements(By.cssSelector(SELECTOR_ACTIVE_CHART_PREVIEWS));
+		assertThat(activeChartPreviews)
+				.hasSize(1);
+		assertThat(activeChartPreviews.get(0).findElement(By.cssSelector(".card-action span")).getText())
+				.isEqualTo("Incomes/Expenditures by categories");
+
+		// button
+		assertThat(driver.findElement(By.name("buttonSave")).isEnabled()).isTrue();
+	}
+
+	@Test
+	void test_selectDisplayTypeAfterSelectingChartDisablesButton()
+	{
+		driver.get(helper.getUrl() + "/charts");
+
+		final String chartPreviewSelector = ".chart-preview-column[data-id='6']";
+		driver.findElement(By.cssSelector(chartPreviewSelector)).click();
+
+		WebDriverWait wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.attributeContains(By.cssSelector(chartPreviewSelector + " .chart-preview"), "class", "active"));
+
+		final String buttonSelector = ".button-display-type[data-value='" + ChartDisplayType.LINE.name() + "']";
+		driver.findElement(By.cssSelector(buttonSelector)).click();
+
+		wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.attributeContains(By.cssSelector(buttonSelector), "class", "active"));
+
+		// check displayed chart previews
+		final List<WebElement> activeChartPreviews = driver.findElements(By.cssSelector(SELECTOR_ACTIVE_CHART_PREVIEWS));
+		assertThat(activeChartPreviews).isEmpty();
+
+		// button
+		assertThat(driver.findElement(By.name("buttonSave")).isEnabled()).isFalse();
+	}
+
+	@Test
+	void test_showFilterBadge()
+	{
+		driver.get(helper.getUrl() + "/charts");
+
+		assertThat(driver.findElement(By.id("filterActiveBadge")).isDisplayed()).isFalse();
+
+		driver.findElement(By.id("chart-filter-container")).click();
+		driver.findElement(By.id("section-type")).click();
+		final WebElement checkBox = driver.findElement(By.cssSelector("#section-type .text-default"));
+		((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", checkBox);
+		checkBox.click();
+
+		final WebDriverWait wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("filter-button-reset")));
+
+		assertThat(driver.findElement(By.id("filterActiveBadge")).isDisplayed()).isTrue();
+	}
+
+	@Test
+	void test_hideFilterBadgeOnReset()
+	{
+		driver.get(helper.getUrl() + "/charts");
+
+		driver.findElement(By.id("chart-filter-container")).click();
+		driver.findElement(By.id("section-type")).click();
+		final WebElement checkBox = driver.findElement(By.cssSelector("#section-type .text-default"));
+		((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", checkBox);
+		checkBox.click();
+
+		final WebDriverWait wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("filter-button-reset")));
+
+		driver.findElement(By.className("filter-button-reset")).click();
+		assertThat(driver.findElement(By.id("filterActiveBadge")).isDisplayed()).isFalse();
+	}
+
+	@Test
+	void test_showManageButtonForCustomCharts()
+	{
+		driver.get(helper.getUrl() + "/charts");
+
+		final String buttonSelector = ".button-display-type[data-value='" + ChartDisplayType.CUSTOM.name() + "']";
+		driver.findElement(By.cssSelector(buttonSelector)).click();
+
+		WebDriverWait wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.attributeContains(By.cssSelector(buttonSelector), "class", "active"));
+
+		// check display type
+		assertThat(getSelectedType(SELECTOR_ACTIVE_DISPLAY_TYPE)).isEqualTo(ChartDisplayType.CUSTOM.name());
+
+		assertThat(driver.findElement(By.id("buttonCustomCharts")).isDisplayed()).isTrue();
+	}
+
+	@Test
+	void test_showChart()
+	{
+		driver.get(helper.getUrl() + "/charts");
+
+		final String chartPreviewSelector = ".chart-preview-column[data-id='6']";
+		driver.findElement(By.cssSelector(chartPreviewSelector)).click();
+
+		WebDriverWait wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.attributeContains(By.cssSelector(chartPreviewSelector + " .chart-preview"), "class", "active"));
+
+		driver.findElement(By.name("buttonSave")).click();
+
+		wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("chart-canvas")));
+
+		assertThat(driver.findElements(By.cssSelector(".chart-canvas .plot-container"))).hasSize(1);
+	}
+
+	@Test
+	void test_EnabledButtonAfterShowChart()
+	{
+		driver.get(helper.getUrl() + "/charts");
+
+		final String chartPreviewSelector = ".chart-preview-column[data-id='6']";
+		driver.findElement(By.cssSelector(chartPreviewSelector)).click();
+
+		WebDriverWait wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.attributeContains(By.cssSelector(chartPreviewSelector + " .chart-preview"), "class", "active"));
+
+		driver.findElement(By.name("buttonSave")).click();
+
+		wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("chart-canvas")));
+
+		driver.findElement(By.id("buttonShowChartSettings")).click();
+
+		wait = new WebDriverWait(driver, 5);
+		wait.until(ExpectedConditions.attributeContains(By.cssSelector(chartPreviewSelector + " .chart-preview"), "class", "active"));
+
+		assertThat(driver.findElement(By.name("buttonSave")).isEnabled()).isTrue();
+	}
+
+	private String getSelectedType(String selector)
+	{
+		final List<WebElement> activeTypeButtons = driver.findElements(By.cssSelector(selector));
+		assertThat(activeTypeButtons)
+				.hasSize(1);
+
+		return activeTypeButtons.get(0).getAttribute("data-value");
+	}
+}
\ No newline at end of file
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/FirstUseTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/FirstUseTest.java
index 47e6a7a0539e22bc295efd8c0bec48d10ec7c275..7f3c6456807532d0729c9ebc42a64db95e0b9625 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/FirstUseTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/FirstUseTest.java
@@ -4,66 +4,30 @@ import de.deadlocker8.budgetmaster.Main;
 import de.deadlocker8.budgetmaster.authentication.UserService;
 import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
 import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestBase;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestWatcher;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.openqa.selenium.By;
-import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.firefox.FirefoxDriver;
-import org.openqa.selenium.firefox.FirefoxOptions;
 import org.openqa.selenium.support.ui.ExpectedConditions;
 import org.openqa.selenium.support.ui.WebDriverWait;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringRunner.class)
+@ExtendWith(SeleniumTestWatcher.class)
 @SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
 @SeleniumTest
-public class FirstUseTest
+class FirstUseTest extends SeleniumTestBase
 {
 	private IntegrationTestHelper helper;
-	private WebDriver driver;
 
-	@LocalServerPort
-	int port;
-
-	@Rule
-	public TestName name = new TestName();
-
-	@Rule
-	public TestWatcher testWatcher = new TestWatcher()
-	{
-		@Override
-		protected void finished(Description description)
-		{
-			driver.quit();
-		}
-
-		@Override
-		protected void failed(Throwable e, Description description)
-		{
-			IntegrationTestHelper.saveScreenshots(driver, name, FirstUseTest.class);
-		}
-	};
-
-	@Before
+	@BeforeEach
 	public void prepare()
 	{
-		FirefoxOptions options = new FirefoxOptions();
-		options.setHeadless(false);
-		options.addPreference("devtools.console.stdout.content", true);
-		driver = new FirefoxDriver(options);
-
-		// prepare
 		helper = new IntegrationTestHelper(driver, port);
 		helper.start();
 		helper.login(UserService.DEFAULT_PASSWORD);
@@ -72,30 +36,30 @@ public class FirstUseTest
 	}
 
 	@Test
-	public void test_firstUserBanner()
+	void test_firstUserBanner()
 	{
 		WebDriverWait wait = new WebDriverWait(driver, 5);
-		wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("firstUseBanner")));
-		assertThat(driver.findElement(By.id("firstUseBanner")).isDisplayed()).isTrue();
+		wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("hint-1")));
+		assertThat(driver.findElement(By.id("hint-1")).isDisplayed()).isTrue();
 	}
 
 	@Test
-	public void test_firstUserBanner_dismiss()
+	void test_firstUserBanner_dismiss()
 	{
 		WebDriverWait wait = new WebDriverWait(driver, 5);
-		wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("firstUseBanner")));
+		wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("hint-1")));
 
-		driver.findElements(By.className("notification-clear")).get(0).click();
+		driver.findElements(By.className("hint-clear")).get(0).click();
 
-		wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("firstUseBanner")));
-		assertThat(driver.findElements(By.id("firstUseBanner"))).isEmpty();
+		wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("hint-1")));
+		assertThat(driver.findElement(By.id("hint-1")).isDisplayed()).isFalse();
 	}
 
 	@Test
-	public void test_firstUserBanner_click()
+	void test_firstUserBanner_click()
 	{
 		WebDriverWait wait = new WebDriverWait(driver, 5);
-		wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("firstUseBanner")));
+		wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("hint-1")));
 
 		driver.findElements(By.className("notification")).get(0).click();
 
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/HotkeyTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/HotkeyTest.java
index 63051b0143b3e682c7fdf508b19ab9cf8e091511..dd5b33d5e0a04e737ffab1031ad0977828099ba0 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/HotkeyTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/HotkeyTest.java
@@ -4,79 +4,39 @@ import de.deadlocker8.budgetmaster.Main;
 import de.deadlocker8.budgetmaster.accounts.Account;
 import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.authentication.UserService;
-import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
-import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
-import de.deadlocker8.budgetmaster.integration.helpers.TransactionTestHelper;
+import de.deadlocker8.budgetmaster.integration.helpers.*;
 import de.thecodelabs.utils.util.OS;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.openqa.selenium.By;
 import org.openqa.selenium.Keys;
-import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
-import org.openqa.selenium.firefox.FirefoxDriver;
-import org.openqa.selenium.firefox.FirefoxOptions;
 import org.openqa.selenium.interactions.Action;
 import org.openqa.selenium.interactions.Actions;
 import org.openqa.selenium.support.ui.ExpectedConditions;
 import org.openqa.selenium.support.ui.WebDriverWait;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
 
 import java.io.File;
 import java.util.Arrays;
 import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assume.assumeTrue;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
-@RunWith(SpringRunner.class)
+@ExtendWith(SeleniumTestWatcher.class)
 @SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
 @SeleniumTest
-public class HotkeyTest
+class HotkeyTest extends SeleniumTestBase
 {
 	private IntegrationTestHelper helper;
-	private WebDriver driver;
 
-	@LocalServerPort
-	int port;
-
-	@Rule
-	public TestName name = new TestName();
-
-	@Rule
-	public TestWatcher testWatcher = new TestWatcher()
-	{
-		@Override
-		protected void finished(Description description)
-		{
-			driver.quit();
-		}
-
-		@Override
-		protected void failed(Throwable e, Description description)
-		{
-			IntegrationTestHelper.saveScreenshots(driver, name, HotkeyTest.class);
-		}
-	};
-
-	@Before
+	@BeforeEach
 	public void prepare()
 	{
-		FirefoxOptions options = new FirefoxOptions();
-		options.setHeadless(false);
-		options.addPreference("devtools.console.stdout.content", true);
-		driver = new FirefoxDriver(options);
-
-		// prepare
 		helper = new IntegrationTestHelper(driver, port);
 		helper.start();
 		helper.login(UserService.DEFAULT_PASSWORD);
@@ -87,10 +47,11 @@ public class HotkeyTest
 		final Account account1 = new Account("DefaultAccount0815", AccountType.CUSTOM);
 		final Account account2 = new Account("Account2", AccountType.CUSTOM);
 
-		helper.uploadDatabase(path, Arrays.asList("DefaultAccount0815", "sfsdf"), List.of(account1, account2));	}
+		helper.uploadDatabase(path, Arrays.asList("DefaultAccount0815", "sfsdf"), List.of(account1, account2));
+	}
 
 	@Test
-	public void hotkey_newTransaction_normal()
+	void hotkey_newTransaction_normal()
 	{
 		driver.findElement(By.tagName("body")).sendKeys("n");
 
@@ -101,7 +62,7 @@ public class HotkeyTest
 	}
 
 	@Test
-	public void hotkey_newTransaction_recurring()
+	void hotkey_newTransaction_recurring()
 	{
 		driver.findElement(By.tagName("body")).sendKeys("r");
 
@@ -123,7 +84,7 @@ public class HotkeyTest
 	}
 
 	@Test
-	public void hotkey_newTransaction_transactionFromTemplate()
+	void hotkey_newTransaction_transactionFromTemplate()
 	{
 		driver.findElement(By.tagName("body")).sendKeys("v");
 
@@ -134,7 +95,7 @@ public class HotkeyTest
 	}
 
 	@Test
-	public void hotkey_filter()
+	void hotkey_filter()
 	{
 		driver.findElement(By.tagName("body")).sendKeys("f");
 
@@ -146,7 +107,7 @@ public class HotkeyTest
 	}
 
 	@Test
-	public void hotkey_search()
+	void hotkey_search()
 	{
 		driver.findElement(By.tagName("body")).sendKeys("s");
 
@@ -154,7 +115,7 @@ public class HotkeyTest
 	}
 
 	@Test
-	public void hotkey_saveTransaction()
+	void hotkey_saveTransaction()
 	{
 		assumeTrue(OS.isWindows());
 
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/ImportTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/ImportTest.java
index ae4b6db07f5c39745c49398af2cfefb1e5b51575..b3eff6b6c0582c2d88c99fe626dec9de8d409efc 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/ImportTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/ImportTest.java
@@ -6,66 +6,25 @@ import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.authentication.UserService;
 import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
 import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
-import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.firefox.FirefoxDriver;
-import org.openqa.selenium.firefox.FirefoxOptions;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestBase;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestWatcher;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
 
 import java.io.File;
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(SpringRunner.class)
+@ExtendWith(SeleniumTestWatcher.class)
 @SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
 @SeleniumTest
-public class ImportTest
+class ImportTest extends SeleniumTestBase
 {
-	private WebDriver driver;
-
-	@LocalServerPort
-	int port;
-
-	@Rule
-	public TestName name = new TestName();
-
-	@Rule
-	public TestWatcher testWatcher = new TestWatcher()
-	{
-		@Override
-		protected void finished(Description description)
-		{
-			driver.quit();
-		}
-
-		@Override
-		protected void failed(Throwable e, Description description)
-		{
-			IntegrationTestHelper.saveScreenshots(driver, name, ImportTest.class);
-		}
-	};
-
-	@Before
-	public void prepare()
-	{
-		FirefoxOptions options = new FirefoxOptions();
-		options.setHeadless(false);
-		options.addPreference("devtools.console.stdout.content", true);
-		driver = new FirefoxDriver(options);
-	}
-
 	@Test
-	public void requestImport()
+	void requestImport()
 	{
 		IntegrationTestHelper helper = new IntegrationTestHelper(driver, port);
 		helper.start();
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/LoginControllerTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/LoginControllerTest.java
index e1ead30f7e0f7d9ac5bc121279749a90c27b8645..9708909b8d05efec2e0af05bc9f292e4fb037241 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/LoginControllerTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/LoginControllerTest.java
@@ -4,96 +4,54 @@ import de.deadlocker8.budgetmaster.Main;
 import de.deadlocker8.budgetmaster.authentication.UserService;
 import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
 import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestBase;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestWatcher;
 import de.thecodelabs.utils.util.Localization;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.openqa.selenium.By;
 import org.openqa.selenium.JavascriptExecutor;
-import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
-import org.openqa.selenium.firefox.FirefoxDriver;
-import org.openqa.selenium.firefox.FirefoxOptions;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringRunner.class)
+@ExtendWith(SeleniumTestWatcher.class)
 @SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
 @SeleniumTest
-public class LoginControllerTest
+class LoginControllerTest extends SeleniumTestBase
 {
-	private WebDriver driver;
-
-	@LocalServerPort
-	int port;
-
-	@Rule
-	public TestName name = new TestName();
-
-	@Rule
-	public TestWatcher testWatcher = new TestWatcher()
-	{
-		@Override
-		protected void finished(Description description)
-		{
-			driver.quit();
-		}
-
-		@Override
-		protected void failed(Throwable e, Description description)
-		{
-			IntegrationTestHelper.saveScreenshots(driver, name, LoginControllerTest.class);
-		}
-	};
-
-	@Before
-	public void prepare()
-	{
-		FirefoxOptions options = new FirefoxOptions();
-		options.setHeadless(false);
-		options.addPreference("devtools.console.stdout.content", true);
-		driver = new FirefoxDriver(options);
-	}
-
 	@Test
-	public void getLoginPage()
+	void getLoginPage()
 	{
 		IntegrationTestHelper helper = new IntegrationTestHelper(driver, port);
 		helper.start();
 
 		WebElement input = driver.findElement(By.id("login-password"));
-		assertNotNull(input);
+		assertThat(input).isNotNull();
 
 		WebElement label = driver.findElement(By.cssSelector(".input-field label"));
-		assertEquals(Localization.getString("login.password"), label.getText());
+		assertThat(label.getText()).isEqualTo(Localization.getString("login.password"));
 
 		WebElement button = driver.findElement(By.tagName("button"));
-		assertEquals(Localization.getString("login.button"), IntegrationTestHelper.getTextNode(button));
+		assertThat(IntegrationTestHelper.getTextNode(button)).isEqualTo(Localization.getString("login.button"));
 	}
 
 	@Test
-	public void wrongCredentials()
+	void wrongCredentials()
 	{
 		IntegrationTestHelper helper = new IntegrationTestHelper(driver, port);
 		helper.start();
 		helper.login("akhjfvbvahsdsa");
 
 		WebElement label = driver.findElement(By.id("loginMessage"));
-		assertEquals(Localization.getString("warning.wrong.password"), label.getText());
+		assertThat(label.getText()).isEqualTo(Localization.getString("warning.wrong.password"));
 	}
 
 	@Test
-	public void successLogin()
+	void successLogin()
 	{
 		IntegrationTestHelper helper = new IntegrationTestHelper(driver, port);
 		helper.start();
@@ -103,11 +61,11 @@ public class LoginControllerTest
 
 		WebElement label = driver.findElement(By.id("logo-home"));
 		String expected = helper.getUrl() + "/images/Logo_with_text_medium_res.png";
-		assertEquals(expected, label.getAttribute("src"));
+		assertThat(label.getAttribute("src")).isEqualTo(expected);
 	}
 
 	@Test
-	public void logout()
+	void logout()
 	{
 		IntegrationTestHelper helper = new IntegrationTestHelper(driver, port);
 		helper.start();
@@ -121,6 +79,6 @@ public class LoginControllerTest
 		buttonLogout.click();
 
 		WebElement label = driver.findElement(By.id("loginMessage"));
-		assertEquals(Localization.getString("logout.success"), label.getText());
+		assertThat(label.getText()).isEqualTo(Localization.getString("logout.success"));
 	}
 }
\ No newline at end of file
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionFromTemplateTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionFromTemplateTest.java
index 18a81336ea89d6f97de8a48f6d2d46aa76ec385c..86f50db823ed146ff57ce4ab2a84e0a75604962c 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionFromTemplateTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionFromTemplateTest.java
@@ -6,14 +6,14 @@ import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.authentication.UserService;
 import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
 import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestBase;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestWatcher;
 import de.thecodelabs.utils.util.Localization;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.TestWatcher;
 import org.openqa.selenium.By;
 import org.openqa.selenium.Keys;
 import org.openqa.selenium.WebDriver;
@@ -25,7 +25,6 @@ import org.openqa.selenium.support.ui.WebDriverWait;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
 
 import java.io.File;
 import java.util.Arrays;
@@ -33,46 +32,17 @@ import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringRunner.class)
+@ExtendWith(SeleniumTestWatcher.class)
 @SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
 @SeleniumTest
-public class NewTransactionFromTemplateTest
+class NewTransactionFromTemplateTest extends SeleniumTestBase
 {
 	private IntegrationTestHelper helper;
-	private WebDriver driver;
 
-	@LocalServerPort
-	int port;
-
-	@Rule
-	public TestName name = new TestName();
-
-	@Rule
-	public TestWatcher testWatcher = new TestWatcher()
-	{
-		@Override
-		protected void finished(Description description)
-		{
-			driver.quit();
-		}
-
-		@Override
-		protected void failed(Throwable e, Description description)
-		{
-			IntegrationTestHelper.saveScreenshots(driver, name, NewTransactionFromTemplateTest.class);
-		}
-	};
-
-	@Before
+	@BeforeEach
 	public void prepare()
 	{
-		FirefoxOptions options = new FirefoxOptions();
-		options.setHeadless(false);
-		options.addPreference("devtools.console.stdout.content", true);
-		driver = new FirefoxDriver(options);
-
-		// prepare
 		helper = new IntegrationTestHelper(driver, port);
 		helper.start();
 		helper.login(UserService.DEFAULT_PASSWORD);
@@ -90,7 +60,7 @@ public class NewTransactionFromTemplateTest
 	}
 
 	@Test
-	public void test_newTransactionFromTemplate_FullTemplate()
+	void test_newTransactionFromTemplate_FullTemplate()
 	{
 		WebDriverWait wait = new WebDriverWait(driver, 5);
 		final By locator = By.xpath("//div[contains(@class, 'new-transaction-button')]//a[contains(text(),'From template')]");
@@ -121,7 +91,7 @@ public class NewTransactionFromTemplateTest
 	}
 
 	@Test
-	public void test_newTransactionFromTemplate_OnlyIncome()
+	void test_newTransactionFromTemplate_OnlyIncome()
 	{
 		WebDriverWait wait = new WebDriverWait(driver, 5);
 		final By locator = By.xpath("//div[contains(@class, 'new-transaction-button')]//a[contains(text(),'From template')]");
@@ -142,7 +112,7 @@ public class NewTransactionFromTemplateTest
 	}
 
 	@Test
-	public void test_selectTemplateHotkeys_initialSelect()
+	void test_selectTemplateHotkeys_initialSelect()
 	{
 		driver.get(helper.getUrl() + "/templates");
 
@@ -158,7 +128,7 @@ public class NewTransactionFromTemplateTest
 	}
 
 	@Test
-	public void test_selectTemplateHotkeys_keyDown()
+	void test_selectTemplateHotkeys_keyDown()
 	{
 		driver.get(helper.getUrl() + "/templates");
 
@@ -177,7 +147,7 @@ public class NewTransactionFromTemplateTest
 	}
 
 	@Test
-	public void test_selectTemplateHotkeys_keyDown_goBackToTopFromLastItem()
+	void test_selectTemplateHotkeys_keyDown_goBackToTopFromLastItem()
 	{
 		driver.get(helper.getUrl() + "/templates");
 
@@ -197,7 +167,7 @@ public class NewTransactionFromTemplateTest
 	}
 
 	@Test
-	public void test_selectTemplateHotkeys_keyUp_goBackToBottomFromFirstItem()
+	void test_selectTemplateHotkeys_keyUp_goBackToBottomFromFirstItem()
 	{
 		driver.get(helper.getUrl() + "/templates");
 
@@ -216,7 +186,7 @@ public class NewTransactionFromTemplateTest
 	}
 
 	@Test
-	public void test_selectTemplateHotkeys_keyUp()
+	void test_selectTemplateHotkeys_keyUp()
 	{
 		driver.get(helper.getUrl() + "/templates");
 
@@ -236,7 +206,7 @@ public class NewTransactionFromTemplateTest
 	}
 
 	@Test
-	public void test_selectTemplateHotkeys_confirmSelection()
+	void test_selectTemplateHotkeys_confirmSelection()
 	{
 		driver.get(helper.getUrl() + "/templates");
 
@@ -255,7 +225,7 @@ public class NewTransactionFromTemplateTest
 	}
 
 	@Test
-	public void test_selectTemplateHotkeys_searchContainsSelection()
+	void test_selectTemplateHotkeys_searchContainsSelection()
 	{
 		driver.get(helper.getUrl() + "/templates");
 
@@ -278,7 +248,7 @@ public class NewTransactionFromTemplateTest
 	}
 
 	@Test
-	public void test_selectTemplateHotkeys_searchNotContainsSelection()
+	void test_selectTemplateHotkeys_searchNotContainsSelection()
 	{
 		driver.get(helper.getUrl() + "/templates");
 
@@ -300,7 +270,7 @@ public class NewTransactionFromTemplateTest
 	}
 
 	@Test
-	public void test_selectTemplateHotkeys_dontBlockEnterInGlobalSearch()
+	void test_selectTemplateHotkeys_dontBlockEnterInGlobalSearch()
 	{
 		driver.get(helper.getUrl() + "/templates");
 
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionNormalTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionNormalTest.java
index f33006b57631d9ebd0e2b3b5c417be28b2925b84..452e5c946628fd6839a543ebc108203fd85986ff 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionNormalTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionNormalTest.java
@@ -4,28 +4,17 @@ import de.deadlocker8.budgetmaster.Main;
 import de.deadlocker8.budgetmaster.accounts.Account;
 import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.authentication.UserService;
-import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
-import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
-import de.deadlocker8.budgetmaster.integration.helpers.TransactionTestHelper;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
+import de.deadlocker8.budgetmaster.integration.helpers.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.openqa.selenium.By;
 import org.openqa.selenium.JavascriptExecutor;
-import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
-import org.openqa.selenium.firefox.FirefoxDriver;
-import org.openqa.selenium.firefox.FirefoxOptions;
 import org.openqa.selenium.support.ui.ExpectedConditions;
 import org.openqa.selenium.support.ui.WebDriverWait;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
 
 import java.io.File;
 import java.text.SimpleDateFormat;
@@ -35,46 +24,17 @@ import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringRunner.class)
+@ExtendWith(SeleniumTestWatcher.class)
 @SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
 @SeleniumTest
-public class NewTransactionNormalTest
+class NewTransactionNormalTest extends SeleniumTestBase
 {
 	private IntegrationTestHelper helper;
-	private WebDriver driver;
 
-	@LocalServerPort
-	int port;
-
-	@Rule
-	public TestName name = new TestName();
-
-	@Rule
-	public TestWatcher testWatcher = new TestWatcher()
-	{
-		@Override
-		protected void finished(Description description)
-		{
-			driver.quit();
-		}
-
-		@Override
-		protected void failed(Throwable e, Description description)
-		{
-			IntegrationTestHelper.saveScreenshots(driver, name, NewTransactionNormalTest.class);
-		}
-	};
-
-	@Before
+	@BeforeEach
 	public void prepare()
 	{
-		FirefoxOptions options = new FirefoxOptions();
-		options.setHeadless(false);
-		options.addPreference("devtools.console.stdout.content", true);
-		driver = new FirefoxDriver(options);
-
-		// prepare
 		helper = new IntegrationTestHelper(driver, port);
 		helper.start();
 		helper.login(UserService.DEFAULT_PASSWORD);
@@ -100,7 +60,7 @@ public class NewTransactionNormalTest
 	}
 
 	@Test
-	public void test_newTransaction_cancel()
+	void test_newTransaction_cancel()
 	{
 		// click cancel button
 		WebElement cancelButton = driver.findElement(By.id("button-cancel-save-transaction"));
@@ -118,7 +78,7 @@ public class NewTransactionNormalTest
 	}
 
 	@Test
-	public void test_newTransaction_income()
+	void test_newTransaction_income()
 	{
 		String name = "My normal transaction";
 		String amount = "15.00";
@@ -154,7 +114,7 @@ public class NewTransactionNormalTest
 	}
 
 	@Test
-	public void test_newTransaction_expenditure()
+	void test_newTransaction_expenditure()
 	{
 		String name = "My normal transaction";
 		String amount = "15.00";
@@ -190,7 +150,7 @@ public class NewTransactionNormalTest
 	}
 
 	@Test
-	public void test_edit()
+	void test_edit()
 	{
 		driver.get(helper.getUrl() + "/transactions/2/edit");
 
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionRecurringTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionRecurringTest.java
index ceae4906c8751425cceb15153ec3e738bf41be8d..4e668a69f1a0c166e8b49d4ae2175ec1f7160d80 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionRecurringTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionRecurringTest.java
@@ -4,28 +4,17 @@ import de.deadlocker8.budgetmaster.Main;
 import de.deadlocker8.budgetmaster.accounts.Account;
 import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.authentication.UserService;
-import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
-import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
-import de.deadlocker8.budgetmaster.integration.helpers.TransactionTestHelper;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
+import de.deadlocker8.budgetmaster.integration.helpers.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.openqa.selenium.By;
 import org.openqa.selenium.JavascriptExecutor;
-import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
-import org.openqa.selenium.firefox.FirefoxDriver;
-import org.openqa.selenium.firefox.FirefoxOptions;
 import org.openqa.selenium.support.ui.ExpectedConditions;
 import org.openqa.selenium.support.ui.WebDriverWait;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
 
 import java.io.File;
 import java.text.SimpleDateFormat;
@@ -35,46 +24,17 @@ import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringRunner.class)
+@ExtendWith(SeleniumTestWatcher.class)
 @SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
 @SeleniumTest
-public class NewTransactionRecurringTest
+class NewTransactionRecurringTest extends SeleniumTestBase
 {
 	private IntegrationTestHelper helper;
-	private WebDriver driver;
 
-	@LocalServerPort
-	int port;
-
-	@Rule
-	public TestName name = new TestName();
-
-	@Rule
-	public TestWatcher testWatcher = new TestWatcher()
-	{
-		@Override
-		protected void finished(Description description)
-		{
-			driver.quit();
-		}
-
-		@Override
-		protected void failed(Throwable e, Description description)
-		{
-			IntegrationTestHelper.saveScreenshots(driver, name, NewTransactionRecurringTest.class);
-		}
-	};
-
-	@Before
+	@BeforeEach
 	public void prepare()
 	{
-		FirefoxOptions options = new FirefoxOptions();
-		options.setHeadless(false);
-		options.addPreference("devtools.console.stdout.content", true);
-		driver = new FirefoxDriver(options);
-
-		// prepare
 		helper = new IntegrationTestHelper(driver, port);
 		helper.start();
 		helper.login(UserService.DEFAULT_PASSWORD);
@@ -100,7 +60,7 @@ public class NewTransactionRecurringTest
 	}
 
 	@Test
-	public void test_newTransaction_cancel()
+	void test_newTransaction_cancel()
 	{
 		// click cancel button
 		WebElement cancelButton = driver.findElement(By.id("button-cancel-save-transaction"));
@@ -118,7 +78,7 @@ public class NewTransactionRecurringTest
 	}
 
 	@Test
-	public void test_newTransaction_income()
+	void test_newTransaction_income()
 	{
 		String name = "My recurring transaction";
 		String amount = "15.00";
@@ -182,7 +142,7 @@ public class NewTransactionRecurringTest
 	}
 
 	@Test
-	public void test_newTransaction_expenditure()
+	void test_newTransaction_expenditure()
 	{
 		String name = "My recurring transaction";
 		String amount = "15.00";
@@ -246,7 +206,7 @@ public class NewTransactionRecurringTest
 	}
 
 	@Test
-	public void test_edit()
+	void test_edit()
 	{
 		driver.get(helper.getUrl() + "/transactions/6/edit");
 
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionTransferTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionTransferTest.java
index 41502ef56953ffca750b1e3bf9cafaf2838bac05..141bad3f8ed1cedeb4f42aebf2b6642a763017d5 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionTransferTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/NewTransactionTransferTest.java
@@ -4,25 +4,18 @@ import de.deadlocker8.budgetmaster.Main;
 import de.deadlocker8.budgetmaster.accounts.Account;
 import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.authentication.UserService;
-import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
-import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
-import de.deadlocker8.budgetmaster.integration.helpers.TransactionTestHelper;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
-import org.openqa.selenium.*;
-import org.openqa.selenium.firefox.FirefoxDriver;
-import org.openqa.selenium.firefox.FirefoxOptions;
+import de.deadlocker8.budgetmaster.integration.helpers.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.openqa.selenium.By;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.ui.ExpectedConditions;
 import org.openqa.selenium.support.ui.WebDriverWait;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
 
 import java.io.File;
 import java.text.SimpleDateFormat;
@@ -33,46 +26,17 @@ import java.util.List;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-@RunWith(SpringRunner.class)
+@ExtendWith(SeleniumTestWatcher.class)
 @SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
 @SeleniumTest
-public class NewTransactionTransferTest
+class NewTransactionTransferTest extends SeleniumTestBase
 {
 	private IntegrationTestHelper helper;
-	private WebDriver driver;
 
-	@LocalServerPort
-	int port;
-
-	@Rule
-	public TestName name = new TestName();
-
-	@Rule
-	public TestWatcher testWatcher = new TestWatcher()
-	{
-		@Override
-		protected void finished(Description description)
-		{
-			driver.quit();
-		}
-
-		@Override
-		protected void failed(Throwable e, Description description)
-		{
-			IntegrationTestHelper.saveScreenshots(driver, name, NewTransactionTransferTest.class);
-		}
-	};
-
-	@Before
+	@BeforeEach
 	public void prepare()
 	{
-		FirefoxOptions options = new FirefoxOptions();
-		options.setHeadless(false);
-		options.addPreference("devtools.console.stdout.content", true);
-		driver = new FirefoxDriver(options);
-
-		// prepare
 		helper = new IntegrationTestHelper(driver, port);
 		helper.start();
 		helper.login(UserService.DEFAULT_PASSWORD);
@@ -98,7 +62,7 @@ public class NewTransactionTransferTest
 	}
 
 	@Test
-	public void test_newTransaction_cancel()
+	void test_newTransaction_cancel()
 	{
 		// click cancel button
 		WebElement cancelButton = driver.findElement(By.id("button-cancel-save-transaction"));
@@ -116,7 +80,7 @@ public class NewTransactionTransferTest
 	}
 
 	@Test
-	public void test_newTransaction_transfer()
+	void test_newTransaction_transfer()
 	{
 		String name = "My transfer transaction";
 		String amount = "15.00";
@@ -151,7 +115,7 @@ public class NewTransactionTransferTest
 	}
 
 	@Test
-	public void test_edit()
+	void test_edit()
 	{
 		driver.get(helper.getUrl() + "/transactions/3/edit");
 
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/SearchTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/SearchTest.java
index 56ebbc3420cb75251281a368d0a3116f46d7db54..17eb2e0514cbe48c96d05f2be007ce0af41fe0c5 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/SearchTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/SearchTest.java
@@ -6,14 +6,14 @@ import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.authentication.UserService;
 import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
 import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestBase;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestWatcher;
 import de.thecodelabs.utils.util.Localization;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.TestWatcher;
 import org.openqa.selenium.By;
 import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.WebDriver;
@@ -23,56 +23,23 @@ import org.openqa.selenium.firefox.FirefoxOptions;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
 
 import java.io.File;
 import java.util.Arrays;
 import java.util.List;
 
-import static junit.framework.TestCase.assertTrue;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
+import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringRunner.class)
+
+@ExtendWith(SeleniumTestWatcher.class)
 @SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
 @SeleniumTest
-public class SearchTest
+class SearchTest extends SeleniumTestBase
 {
-	private WebDriver driver;
-
-	@LocalServerPort
-	int port;
-
-	@Rule
-	public TestName name = new TestName();
-
-	@Rule
-	public TestWatcher testWatcher = new TestWatcher()
-	{
-		@Override
-		protected void finished(Description description)
-		{
-			driver.quit();
-		}
-
-		@Override
-		protected void failed(Throwable e, Description description)
-		{
-			IntegrationTestHelper.saveScreenshots(driver, name, SearchTest.class);
-		}
-	};
-
-	@Before
+	@BeforeEach
 	public void prepare()
 	{
-		FirefoxOptions options = new FirefoxOptions();
-		options.setHeadless(false);
-		options.addPreference("devtools.console.stdout.content", true);
-		driver = new FirefoxDriver(options);
-		driver.manage().window().maximize();
-
-		// prepare
 		IntegrationTestHelper helper = new IntegrationTestHelper(driver, port);
 		helper.start();
 		helper.login(UserService.DEFAULT_PASSWORD);
@@ -91,66 +58,66 @@ public class SearchTest
 	}
 
 	@Test
-	public void searchFromNavbar()
+	void searchFromNavbar()
 	{
 		// headline
 		WebElement headline = driver.findElement(By.className("headline"));
 		String expected = Localization.getString("menu.search.results", 24);
-		assertEquals(expected, headline.getText());
+		assertThat(headline.getText()).isEqualTo(expected);
 
 		// checkboxes
-		assertTrue(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchName\"]")).isSelected());
-		assertTrue(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchDescription\"]")).isSelected());
-		assertTrue(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchCategory\"]")).isSelected());
-		assertTrue(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchTags\"]")).isSelected());
+		assertThat(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchName\"]")).isSelected()).isTrue();
+		assertThat(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchDescription\"]")).isSelected()).isTrue();
+		assertThat(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchCategory\"]")).isSelected()).isTrue();
+		assertThat(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchTags\"]")).isSelected()).isTrue();
 
 		// results
 		List<WebElement> results = driver.findElements(By.cssSelector(".search-container .card-panel"));
-		assertEquals(10, results.size());
+		assertThat(results.size()).isEqualTo(10);
 	}
 
 	@Test
-	public void pagination()
+	void pagination()
 	{
 		// === PAGE 1 ===
-		List<WebElement> pages = driver.findElements(By.cssSelector(".pagination li"));
-		assertEquals(5, pages.size());
+		List<WebElement> pages = driver.findElements(By.cssSelector(".pagination-position-top .pagination li"));
+		assertThat(pages.size()).isEqualTo(5);
 
-		assertTrue(pages.get(0).getAttribute("class").contains("disabled"));
-		assertEquals("1", pages.get(1).findElement(By.className("page-link")).getText());
-		assertTrue(pages.get(1).getAttribute("class").contains("active"));
-		assertEquals("2", pages.get(2).findElement(By.className("page-link")).getText());
-		assertEquals("3", pages.get(3).findElement(By.className("page-link")).getText());
-		assertFalse(pages.get(4).getAttribute("class").contains("disabled"));
+		assertThat(pages.get(0).getAttribute("class")).contains("disabled");
+		assertThat(pages.get(1).findElement(By.className("page-link")).getText()).isEqualTo("1");
+		assertThat(pages.get(1).getAttribute("class")).contains("active");
+		assertThat(pages.get(2).findElement(By.className("page-link")).getText()).isEqualTo("2");
+		assertThat(pages.get(3).findElement(By.className("page-link")).getText()).isEqualTo("3");
+		assertThat(pages.get(4).getAttribute("class")).doesNotContain("disabled");
 
 		// validate results
 		List<WebElement> results = driver.findElements(By.cssSelector(".search-container .card-panel"));
-		assertEquals(10, results.size());
+		assertThat(results.size()).isEqualTo(10);
 
 		// === PAGE 1 ===
 		pages.get(3).click();
 
-		pages = driver.findElements(By.cssSelector(".pagination li"));
-		assertEquals(5, pages.size());
+		pages = driver.findElements(By.cssSelector(".pagination-position-top .pagination li"));
+		assertThat(pages.size()).isEqualTo(5);
 
 		// previous button should be enabled
-		assertFalse(pages.get(0).getAttribute("class").contains("disabled"));
+		assertThat(pages.get(0).getAttribute("class")).doesNotContain("disabled");
 
-		assertEquals("1", pages.get(1).findElement(By.className("page-link")).getText());
-		assertEquals("2", pages.get(2).findElement(By.className("page-link")).getText());
-		assertEquals("3", pages.get(3).findElement(By.className("page-link")).getText());
-		assertTrue(pages.get(3).getAttribute("class").contains("active"));
+		assertThat(pages.get(1).findElement(By.className("page-link")).getText()).isEqualTo("1");
+		assertThat(pages.get(2).findElement(By.className("page-link")).getText()).isEqualTo("2");
+		assertThat(pages.get(3).findElement(By.className("page-link")).getText()).isEqualTo("3");
+		assertThat(pages.get(3).getAttribute("class")).contains("active");
 
 		// next button should be disabled
-		assertTrue(pages.get(4).getAttribute("class").contains("disabled"));
+		assertThat(pages.get(4).getAttribute("class")).contains("disabled");
 
 		// validate
 		results = driver.findElements(By.cssSelector(".search-container .card-panel"));
-		assertEquals(4, results.size());
+		assertThat(results.size()).isEqualTo(4);
 	}
 
 	@Test
-	public void checkboxes()
+	void checkboxes()
 	{
 		// deselect some checkboxes (use JavascriptExecutor here as the checkbox is covered by a span)
 		JavascriptExecutor executor = (JavascriptExecutor) driver;
@@ -161,29 +128,29 @@ public class SearchTest
 		driver.findElement(By.cssSelector(".main-card #searchForm button[type=\"submit\"]")).click();
 
 		// validate
-		assertFalse(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchName\"]")).isSelected());
-		assertFalse(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchDescription\"]")).isSelected());
-		assertTrue(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchCategory\"]")).isSelected());
-		assertTrue(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchTags\"]")).isSelected());
+		assertThat(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchName\"]")).isSelected()).isFalse();
+		assertThat(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchDescription\"]")).isSelected()).isFalse();
+		assertThat(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchCategory\"]")).isSelected()).isTrue();
+		assertThat(driver.findElement(By.cssSelector(".main-card #searchForm input[name=\"searchTags\"]")).isSelected()).isTrue();
 
 		// results
 		List<WebElement> results = driver.findElements(By.cssSelector(".search-container .card-panel"));
-		assertEquals(2, results.size());
+		assertThat(results.size()).isEqualTo(2);
 	}
 
 	@Test
-	public void highlight()
+	void highlight()
 	{
 		driver.findElement(By.cssSelector(".main-card .search-result .hide-on-med-and-down .buttonHighlight")).click();
 
-		assertEquals("May 2019", driver.findElement(By.cssSelector(".headline-date")).getText());
+		assertThat(driver.findElement(By.cssSelector(".headline-date")).getText()).isEqualTo("May 2019");
 
 		List<WebElement> transactionsRows = driver.findElements(By.cssSelector(".transaction-container .hide-on-med-and-down.transaction-row-top"));
-		assertEquals(25, transactionsRows.size());
-		assertTrue(transactionsRows.get(0).getAttribute("class").contains("background-blue-light"));
+		assertThat(transactionsRows.size()).isEqualTo(25);
+		assertThat(transactionsRows.get(0).getAttribute("class")).contains("background-blue-light");
 		for(int i = 1; i < transactionsRows.size(); i++)
 		{
-			assertFalse(transactionsRows.get(i).getAttribute("class").contains("background-blue-light"));
+			assertThat(transactionsRows.get(i).getAttribute("class")).doesNotContain("background-blue-light");
 		}
 	}
 }
\ No newline at end of file
diff --git a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/WhatsNewTest.java b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/WhatsNewTest.java
index 9c5731e6d747abd04b6997e30c04056618d4c3b1..fc447467a636cddd6557c1880aa3abbe17974387 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/WhatsNewTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/integration/selenium/WhatsNewTest.java
@@ -4,66 +4,30 @@ import de.deadlocker8.budgetmaster.Main;
 import de.deadlocker8.budgetmaster.authentication.UserService;
 import de.deadlocker8.budgetmaster.integration.helpers.IntegrationTestHelper;
 import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTest;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.rules.TestWatcher;
-import org.junit.runner.Description;
-import org.junit.runner.RunWith;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestBase;
+import de.deadlocker8.budgetmaster.integration.helpers.SeleniumTestWatcher;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.openqa.selenium.By;
-import org.openqa.selenium.WebDriver;
-import org.openqa.selenium.firefox.FirefoxDriver;
-import org.openqa.selenium.firefox.FirefoxOptions;
 import org.openqa.selenium.support.ui.ExpectedConditions;
 import org.openqa.selenium.support.ui.WebDriverWait;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringRunner.class)
+@ExtendWith(SeleniumTestWatcher.class)
 @SpringBootTest(classes = Main.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
 @SeleniumTest
-public class WhatsNewTest
+class WhatsNewTest extends SeleniumTestBase
 {
 	private IntegrationTestHelper helper;
-	private WebDriver driver;
 
-	@LocalServerPort
-	int port;
-
-	@Rule
-	public TestName name = new TestName();
-
-	@Rule
-	public TestWatcher testWatcher = new TestWatcher()
-	{
-		@Override
-		protected void finished(Description description)
-		{
-			driver.quit();
-		}
-
-		@Override
-		protected void failed(Throwable e, Description description)
-		{
-			IntegrationTestHelper.saveScreenshots(driver, name, WhatsNewTest.class);
-		}
-	};
-
-	@Before
+	@BeforeEach
 	public void prepare()
 	{
-		FirefoxOptions options = new FirefoxOptions();
-		options.setHeadless(false);
-		options.addPreference("devtools.console.stdout.content", true);
-		driver = new FirefoxDriver(options);
-
-		// prepare
 		helper = new IntegrationTestHelper(driver, port);
 		helper.start();
 		helper.login(UserService.DEFAULT_PASSWORD);
@@ -71,7 +35,7 @@ public class WhatsNewTest
 	}
 
 	@Test
-	public void test_whats_new_dialog()
+	void test_whats_new_dialog()
 	{
 		WebDriverWait wait = new WebDriverWait(driver, 5);
 		wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("modalWhatsNew")));
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/CategoryServiceTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/CategoryServiceTest.java
index 25995796176a08af27d4d8e556f1c9f92b3c975e..566fbc0e7dbe049ff15f060455d1cd4089a4aa56 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/CategoryServiceTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/CategoryServiceTest.java
@@ -5,12 +5,12 @@ import de.deadlocker8.budgetmaster.categories.CategoryRepository;
 import de.deadlocker8.budgetmaster.categories.CategoryService;
 import de.deadlocker8.budgetmaster.categories.CategoryType;
 import de.deadlocker8.budgetmaster.unit.helpers.LocalizedTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -18,9 +18,9 @@ import java.util.Optional;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringJUnit4ClassRunner.class)
+@ExtendWith(SpringExtension.class)
 @LocalizedTest
-public class CategoryServiceTest
+class CategoryServiceTest
 {
 	private static final Category CATEGORY_NONE = new Category("No Category", "#FFFFFF", CategoryType.NONE);
 	private static final Category CATEGORY_REST = new Category("Rest", "#FFFF00", CategoryType.REST);
@@ -32,7 +32,7 @@ public class CategoryServiceTest
 	private CategoryService categoryService;
 
 	@Test
-	public void test_getAllCategories()
+	void test_getAllCategories()
 	{
 		List<Category> categories = new ArrayList<>();
 		categories.add(CATEGORY_NONE);
@@ -71,7 +71,7 @@ public class CategoryServiceTest
 	}
 
 	@Test
-	public void test_createDefaults()
+	void test_createDefaults()
 	{
 		categoryService.createDefaults();
 
@@ -81,7 +81,7 @@ public class CategoryServiceTest
 	}
 
 	@Test
-	public void test_isDeletable_default()
+	void test_isDeletable_default()
 	{
 		Mockito.when(categoryRepository.findById(1)).thenReturn(Optional.of(CATEGORY_NONE));
 
@@ -89,7 +89,7 @@ public class CategoryServiceTest
 	}
 
 	@Test
-	public void test_isDeletable_custom()
+	void test_isDeletable_custom()
 	{
 		Category customCategory = new Category("aa", "#ff0000", CategoryType.CUSTOM);
 
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/IconServiceTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/IconServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a4a00c1d4b6b4eaf4e586bd4f37949851e55095
--- /dev/null
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/IconServiceTest.java
@@ -0,0 +1,121 @@
+package de.deadlocker8.budgetmaster.unit;
+
+import de.deadlocker8.budgetmaster.accounts.Account;
+import de.deadlocker8.budgetmaster.accounts.AccountType;
+import de.deadlocker8.budgetmaster.categories.Category;
+import de.deadlocker8.budgetmaster.categories.CategoryType;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.IconRepository;
+import de.deadlocker8.budgetmaster.icon.IconService;
+import de.deadlocker8.budgetmaster.images.Image;
+import de.deadlocker8.budgetmaster.images.ImageFileExtension;
+import de.deadlocker8.budgetmaster.images.ImageRepository;
+import de.deadlocker8.budgetmaster.templates.Template;
+import de.deadlocker8.budgetmaster.unit.helpers.LocalizedTest;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.util.Optional;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@ExtendWith(SpringExtension.class)
+@LocalizedTest
+class IconServiceTest
+{
+	@Mock
+	private IconRepository iconRepository;
+
+	@Mock
+	private ImageRepository imageRepository;
+
+	@InjectMocks
+	private IconService iconService;
+
+	@Test
+	void test_deleteIcon_null()
+	{
+		iconService.deleteIcon(null);
+		Mockito.verify(iconRepository, Mockito.never()).delete(Mockito.any());
+	}
+
+	@Test
+	void test_deleteIcon_withReferringAccount()
+	{
+		final Icon icon = Mockito.spy(new Icon("fas fa-icons"));
+		final Account account = Mockito.spy(new Account("account with icon", AccountType.CUSTOM, icon));
+
+		Mockito.when(icon.getReferringAccount()).thenReturn(account);
+
+		iconService.deleteIcon(icon);
+		Mockito.verify(iconRepository, Mockito.times(1)).delete(icon);
+		Mockito.verify(account, Mockito.times(1)).setIconReference(null);
+	}
+
+	@Test
+	void test_deleteIcon_withReferringTemplate()
+	{
+		final Icon icon = Mockito.spy(new Icon("fas fa-icons"));
+
+		final Template template = new Template();
+		template.setTemplateName("template with icon");
+		template.setIconReference(icon);
+
+		final Template templateSpy = Mockito.spy(template);
+
+		Mockito.when(icon.getReferringTemplate()).thenReturn(templateSpy);
+
+		iconService.deleteIcon(icon);
+		Mockito.verify(iconRepository, Mockito.times(1)).delete(icon);
+		Mockito.verify(templateSpy, Mockito.times(1)).setIconReference(null);
+	}
+
+	@Test
+	void test_deleteIcon_withReferringCategory()
+	{
+		final Icon icon = Mockito.spy(new Icon("fas fa-icons"));
+
+		final Category category = Mockito.spy(new Category("category with icon", "#FFFFFF", CategoryType.CUSTOM, icon));
+
+		Mockito.when(icon.getReferringCategory()).thenReturn(category);
+
+		iconService.deleteIcon(icon);
+		Mockito.verify(iconRepository, Mockito.times(1)).delete(icon);
+		Mockito.verify(category, Mockito.times(1)).setIconReference(null);
+	}
+
+	@Test
+	void test_createIconReference_empty()
+	{
+		assertThat(iconService.createIconReference(null, null))
+				.isEmpty();
+	}
+
+	@Test
+	void test_createIconReference_builtinIcon()
+	{
+		final String builtinIdentifier = "fas fa-icons";
+		assertThat(iconService.createIconReference(null, builtinIdentifier))
+				.isPresent()
+				.get()
+				.isEqualTo(new Icon(builtinIdentifier));
+	}
+
+	@Test
+	void test_createIconReference_imageIcon()
+	{
+		final Image image = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
+		image.setID(12);
+
+		Mockito.when(imageRepository.findById(Mockito.any())).thenReturn(Optional.of(image));
+
+		assertThat(iconService.createIconReference(12, null))
+				.isPresent()
+				.get()
+				.isEqualTo(new Icon(image));
+	}
+}
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/IconizableTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/IconizableTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..64f8ec349e42909e6dbc285fa424e2d3d1f3c4f5
--- /dev/null
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/IconizableTest.java
@@ -0,0 +1,107 @@
+package de.deadlocker8.budgetmaster.unit;
+
+import de.deadlocker8.budgetmaster.accounts.Account;
+import de.deadlocker8.budgetmaster.accounts.AccountService;
+import de.deadlocker8.budgetmaster.accounts.AccountType;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.IconRepository;
+import de.deadlocker8.budgetmaster.icon.IconService;
+import de.deadlocker8.budgetmaster.unit.helpers.LocalizedTest;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import java.util.Optional;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@ExtendWith(SpringExtension.class)
+@LocalizedTest
+class IconizableTest
+{
+	@Mock
+	private IconRepository iconRepository;
+
+	@Mock
+	private AccountService accountService;
+
+	@Mock
+	private IconService iconService;
+
+	@Test
+	void test_updateIcon_noExistingItem_noNewIcon()
+	{
+		final Account account = Mockito.spy(new Account("account with icon", AccountType.CUSTOM));
+
+		Mockito.when(accountService.findById(Mockito.any())).thenReturn(Optional.empty());
+
+		account.updateIcon(iconService, null, null, accountService);
+
+		assertThat(account.getIconReference()).isNull();
+		Mockito.verify(iconService, Mockito.never()).deleteIcon(Mockito.any());
+		Mockito.verify(iconRepository, Mockito.never()).save(Mockito.any());
+	}
+
+	@Test
+	void test_updateIcon_noExistingItem_newBuiltinIcon()
+	{
+		final Account account = Mockito.spy(new Account("account with icon", AccountType.CUSTOM));
+
+		final String builtinIdentifier = "fas fa-icons";
+		final Icon icon = new Icon(builtinIdentifier);
+
+		Mockito.when(accountService.findById(Mockito.any())).thenReturn(Optional.empty());
+		Mockito.when(iconService.getRepository()).thenReturn(iconRepository);
+		Mockito.when(iconService.createIconReference(null, builtinIdentifier)).thenReturn(Optional.of(icon));
+
+		account.updateIcon(iconService, null, builtinIdentifier, accountService);
+
+		assertThat(account.getIconReference())
+				.isEqualTo(icon);
+		Mockito.verify(iconService, Mockito.never()).deleteIcon(Mockito.any());
+		Mockito.verify(iconRepository, Mockito.times(1)).save(icon);
+	}
+
+	@Test
+	void test_updateIcon_existingItem_newBuiltinIcon()
+	{
+		final String builtinIdentifier = "fas fa-icons";
+		final Icon icon = new Icon(builtinIdentifier);
+
+		final Account account = new Account("account with icon", AccountType.CUSTOM, icon);
+		account.setID(18);
+		final Account accountSpy = Mockito.spy(account);
+
+		Mockito.when(accountService.findById(Mockito.any())).thenReturn(Optional.of(accountSpy));
+		Mockito.when(iconService.getRepository()).thenReturn(iconRepository);
+		Mockito.when(iconService.createIconReference(null, builtinIdentifier)).thenReturn(Optional.of(icon));
+
+		accountSpy.updateIcon(iconService, null, builtinIdentifier, accountService);
+
+		assertThat(accountSpy.getIconReference())
+				.isEqualTo(icon);
+		Mockito.verify(iconService, Mockito.times(1)).deleteIcon(icon);
+		Mockito.verify(iconRepository, Mockito.times(1)).save(icon);
+	}
+
+	@Test
+	void test_updateIcon_existingItem_noNewIcon()
+	{
+		final Icon icon = new Icon("fas fa-icons");
+		final Account account = new Account("account with icon", AccountType.CUSTOM, icon);
+		account.setID(18);
+		final Account accountSpy = Mockito.spy(account);
+
+		Mockito.when(accountService.findById(Mockito.any())).thenReturn(Optional.of(accountSpy));
+		Mockito.when(iconService.getRepository()).thenReturn(iconRepository);
+		Mockito.when(iconService.createIconReference(null, null)).thenReturn(Optional.empty());
+
+		accountSpy.updateIcon(iconService, null, null, accountService);
+
+		assertThat(accountSpy.getIconReference()).isNull();
+		Mockito.verify(iconService, Mockito.times(1)).deleteIcon(icon);
+		Mockito.verify(iconRepository, Mockito.never()).save(Mockito.any());
+	}
+}
\ No newline at end of file
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/ImageServiceTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/ImageServiceTest.java
index 331b00f16a5bbcd0450e79890c5d1dd69987e3cf..32f891af48a01489d611ddcfc49297e9f7d739f0 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/ImageServiceTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/ImageServiceTest.java
@@ -1,17 +1,14 @@
 package de.deadlocker8.budgetmaster.unit;
 
 import de.deadlocker8.budgetmaster.images.*;
-import de.deadlocker8.budgetmaster.transactions.TransactionRepository;
-import de.deadlocker8.budgetmaster.transactions.TransactionService;
 import de.deadlocker8.budgetmaster.unit.helpers.LocalizedTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.verification.VerificationMode;
 import org.springframework.mock.web.MockMultipartFile;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.IOException;
@@ -19,9 +16,9 @@ import java.io.IOException;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
 
-@RunWith(SpringJUnit4ClassRunner.class)
+@ExtendWith(SpringExtension.class)
 @LocalizedTest
-public class ImageServiceTest
+class ImageServiceTest
 {
 	@Mock
 	private ImageRepository imageRepository;
@@ -30,34 +27,34 @@ public class ImageServiceTest
 	private ImageService imageService;
 
 	@Test
-	public void test_getFileExtension_valid()
+	void test_getFileExtension_valid()
 	{
 		assertThat(ImageService.getFileExtension("abc.png")).isNotEmpty()
 				.get().isEqualTo("png");
 	}
 
 	@Test
-	public void test_getFileExtension_validUppercase()
+	void test_getFileExtension_validUppercase()
 	{
 		assertThat(ImageService.getFileExtension("abc.PNG")).isNotEmpty()
 				.get().isEqualTo("png");
 	}
 
 	@Test
-	public void test_getFileExtension_validMultipleDots()
+	void test_getFileExtension_validMultipleDots()
 	{
 		assertThat(ImageService.getFileExtension("abc.jpeg.png")).isNotEmpty()
 				.get().isEqualTo("png");
 	}
 
 	@Test
-	public void test_getFileExtension_noDot()
+	void test_getFileExtension_noDot()
 	{
 		assertThat(ImageService.getFileExtension("abc")).isEmpty();
 	}
 
 	@Test
-	public void test_saveImageFile_noFileExtension()
+	void test_saveImageFile_noFileExtension()
 	{
 		final MultipartFile multipartFile = new MockMultipartFile("abc", "abc", "text/plain", new byte[0]);
 
@@ -66,7 +63,7 @@ public class ImageServiceTest
 	}
 
 	@Test
-	public void test_saveImageFile_invalidFileExtension()
+	void test_saveImageFile_invalidFileExtension()
 	{
 		final MultipartFile multipartFile = new MockMultipartFile("abc.pdf", "abc.pdf", "text/plain", new byte[0]);
 
@@ -75,7 +72,7 @@ public class ImageServiceTest
 	}
 
 	@Test
-	public void test_saveImageFile_valid() throws IOException, InvalidFileExtensionException
+	void test_saveImageFile_valid() throws IOException, InvalidFileExtensionException
 	{
 		final MultipartFile multipartFile = new MockMultipartFile("abc.png", "abc.png", "text/plain", new byte[0]);
 
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/TemplateServiceTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/TemplateServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f56442b3eb41674be158b8215dc134f8b4b5788
--- /dev/null
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/TemplateServiceTest.java
@@ -0,0 +1,169 @@
+package de.deadlocker8.budgetmaster.unit;
+
+import de.deadlocker8.budgetmaster.accounts.*;
+import de.deadlocker8.budgetmaster.categories.Category;
+import de.deadlocker8.budgetmaster.categories.CategoryService;
+import de.deadlocker8.budgetmaster.categories.CategoryType;
+import de.deadlocker8.budgetmaster.icon.IconService;
+import de.deadlocker8.budgetmaster.images.ImageService;
+import de.deadlocker8.budgetmaster.templates.Template;
+import de.deadlocker8.budgetmaster.templates.TemplateRepository;
+import de.deadlocker8.budgetmaster.templates.TemplateService;
+import de.deadlocker8.budgetmaster.unit.helpers.LocalizedTest;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@ExtendWith(SpringExtension.class)
+@LocalizedTest
+class TemplateServiceTest
+{
+	private static final Category CATEGORY_NONE = new Category("No category", "#FFFFFF", CategoryType.NONE);
+
+	private static final Account ACCOUNT_DEFAULT = new Account("Default Account", AccountType.CUSTOM);
+
+	@Mock
+	private TemplateRepository templateRepository;
+
+	@Mock
+	private AccountService accountService;
+
+	@Mock
+	private AccountRepository accountRepository;
+
+	@Mock
+	private CategoryService categoryService;
+
+	@Mock
+	private ImageService imageService;
+
+	@Mock
+	private IconService iconService;
+
+	@InjectMocks
+	private TemplateService templateService;
+
+	@Test
+	void test_prepareTemplateForNewTransaction_noCategory()
+	{
+		final Template template = new Template();
+
+		Mockito.when(categoryService.findByType(CategoryType.NONE)).thenReturn(CATEGORY_NONE);
+
+		final Template expectedTemplate = new Template();
+		expectedTemplate.setCategory(CATEGORY_NONE);
+
+		templateService.prepareTemplateForNewTransaction(template, false);
+		assertThat(template).isEqualTo(expectedTemplate);
+	}
+
+	@Test
+	void test_prepareTemplateForNewTransaction_accountIsFullAccess_noPreparation()
+	{
+		final Account account = new Account("Account", AccountType.CUSTOM);
+		account.setAccountState(AccountState.FULL_ACCESS);
+
+		final Template template = new Template();
+		template.setCategory(CATEGORY_NONE);
+		template.setAccount(account);
+
+		final Template expectedTemplate = new Template();
+		expectedTemplate.setCategory(CATEGORY_NONE);
+		expectedTemplate.setAccount(account);
+
+		templateService.prepareTemplateForNewTransaction(template, false);
+		assertThat(template).isEqualTo(expectedTemplate);
+	}
+
+	@Test
+	void test_prepareTemplateForNewTransaction_accountIsNotFullAccess_noPreparation()
+	{
+		final Account account = new Account("Account", AccountType.CUSTOM);
+		account.setAccountState(AccountState.READ_ONLY);
+
+		final Template template = new Template();
+		template.setCategory(CATEGORY_NONE);
+		template.setAccount(account);
+
+		Mockito.when(accountService.getRepository()).thenReturn(accountRepository);
+		Mockito.when(accountRepository.findByIsDefault(true)).thenReturn(ACCOUNT_DEFAULT);
+
+		final Template expectedTemplate = new Template();
+		expectedTemplate.setCategory(CATEGORY_NONE);
+		expectedTemplate.setAccount(ACCOUNT_DEFAULT);
+
+		templateService.prepareTemplateForNewTransaction(template, false);
+		assertThat(template).isEqualTo(expectedTemplate);
+	}
+
+	@Test
+	void test_prepareTemplateForNewTransaction_transferAccountIsFullAccess_noPreparation()
+	{
+		final Account account = new Account("Account", AccountType.CUSTOM);
+		account.setAccountState(AccountState.FULL_ACCESS);
+
+		final Account transferAccount = new Account("Transfer Account", AccountType.CUSTOM);
+		transferAccount.setAccountState(AccountState.FULL_ACCESS);
+
+		final Template template = new Template();
+		template.setCategory(CATEGORY_NONE);
+		template.setAccount(account);
+		template.setTransferAccount(transferAccount);
+
+		final Template expectedTemplate = new Template();
+		expectedTemplate.setCategory(CATEGORY_NONE);
+		expectedTemplate.setAccount(account);
+		expectedTemplate.setTransferAccount(transferAccount);
+
+		templateService.prepareTemplateForNewTransaction(template, false);
+		assertThat(template).isEqualTo(expectedTemplate);
+	}
+
+	@Test
+	void test_prepareTemplateForNewTransaction_transferAccountIsNotFullAccess_noPreparation()
+	{
+		final Account account = new Account("Account", AccountType.CUSTOM);
+		account.setAccountState(AccountState.FULL_ACCESS);
+
+		final Account transferAccount = new Account("Transfer Account", AccountType.CUSTOM);
+		transferAccount.setAccountState(AccountState.READ_ONLY);
+
+		final Template template = new Template();
+		template.setCategory(CATEGORY_NONE);
+		template.setAccount(account);
+		template.setTransferAccount(transferAccount);
+
+		Mockito.when(accountService.getRepository()).thenReturn(accountRepository);
+		Mockito.when(accountRepository.findByIsDefault(true)).thenReturn(ACCOUNT_DEFAULT);
+
+		final Template expectedTemplate = new Template();
+		expectedTemplate.setCategory(CATEGORY_NONE);
+		expectedTemplate.setAccount(account);
+		expectedTemplate.setTransferAccount(ACCOUNT_DEFAULT);
+
+		templateService.prepareTemplateForNewTransaction(template, false);
+		assertThat(template).isEqualTo(expectedTemplate);
+	}
+
+	@Test
+	void test_prepareTemplateForNewTransaction_noAccount_withPreparation()
+	{
+		final Template template = new Template();
+		template.setCategory(CATEGORY_NONE);
+
+		Mockito.when(accountService.getRepository()).thenReturn(accountRepository);
+		Mockito.when(accountRepository.findByIsDefault(true)).thenReturn(ACCOUNT_DEFAULT);
+
+		final Template expectedTemplate = new Template();
+		expectedTemplate.setCategory(CATEGORY_NONE);
+		expectedTemplate.setAccount(ACCOUNT_DEFAULT);
+
+		templateService.prepareTemplateForNewTransaction(template, true);
+		assertThat(template).isEqualTo(expectedTemplate);
+	}
+}
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionSearchSpecificationsTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionSearchSpecificationsTest.java
index 3443d602576d82a34a847c0a96ca6f46df50d89e..04045e2bbc78d6aaaf9c61cdd91bf808a19ce81c 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionSearchSpecificationsTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionSearchSpecificationsTest.java
@@ -19,22 +19,22 @@ import de.deadlocker8.budgetmaster.transactions.TransactionRepository;
 import de.deadlocker8.budgetmaster.transactions.TransactionSearchSpecifications;
 import org.joda.time.DateTime;
 import org.joda.time.format.DateTimeFormat;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
 import org.springframework.data.jpa.domain.Specification;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringJUnit4ClassRunner.class)
+@ExtendWith(SpringExtension.class)
 @DataJpaTest
-public class TransactionSearchSpecificationsTest
+class TransactionSearchSpecificationsTest
 {
 	@Autowired
 	private TransactionRepository transactionRepository;
@@ -64,7 +64,7 @@ public class TransactionSearchSpecificationsTest
 	private RepeatingOptionRepository repeatingOptionRepository;
 	private RepeatingOption repeatingOption;
 
-	@Before
+	@BeforeEach
 	public void init()
 	{
 		account = accountRepository.save(new Account("TestAccount", AccountType.CUSTOM));
@@ -137,7 +137,7 @@ public class TransactionSearchSpecificationsTest
 	}
 
 	@Test
-	public void getMatches_OnlyName()
+	void getMatches_OnlyName()
 	{
 		Search search = new Search("Test", true, false, false, false, 0);
 		Specification spec = TransactionSearchSpecifications.withDynamicQuery(search);
@@ -148,7 +148,7 @@ public class TransactionSearchSpecificationsTest
 	}
 
 	@Test
-	public void getMatches_PartialName()
+	void getMatches_PartialName()
 	{
 		Search search = new Search("es", true, false, false, false, 0);
 		Specification spec = TransactionSearchSpecifications.withDynamicQuery(search);
@@ -159,7 +159,7 @@ public class TransactionSearchSpecificationsTest
 	}
 
 	@Test
-	public void getMatches_IgnoreCase()
+	void getMatches_IgnoreCase()
 	{
 		Search search = new Search("tEST", true, true, true, true, 0);
 		Specification spec = TransactionSearchSpecifications.withDynamicQuery(search);
@@ -170,7 +170,7 @@ public class TransactionSearchSpecificationsTest
 	}
 
 	@Test
-	public void getMatches_OnlyDescription()
+	void getMatches_OnlyDescription()
 	{
 		Search search = new Search("What", true, true, true, true, 0);
 		Specification spec = TransactionSearchSpecifications.withDynamicQuery(search);
@@ -181,7 +181,7 @@ public class TransactionSearchSpecificationsTest
 	}
 
 	@Test
-	public void getMatches_OnlyCategory()
+	void getMatches_OnlyCategory()
 	{
 		Search search = new Search(category2.getName(), false, false, true, false, 0);
 		Specification spec = TransactionSearchSpecifications.withDynamicQuery(search);
@@ -193,7 +193,7 @@ public class TransactionSearchSpecificationsTest
 	}
 
 	@Test
-	public void getMatches_Order()
+	void getMatches_Order()
 	{
 		Search search = new Search("", true, true, true, true, 0);
 		Specification spec = TransactionSearchSpecifications.withDynamicQuery(search);
@@ -207,7 +207,7 @@ public class TransactionSearchSpecificationsTest
 	}
 
 	@Test
-	public void getMatches_Mixed()
+	void getMatches_Mixed()
 	{
 		Search search = new Search("e", true, true, true, true, 0);
 		Specification spec = TransactionSearchSpecifications.withDynamicQuery(search);
@@ -220,7 +220,7 @@ public class TransactionSearchSpecificationsTest
 	}
 
 	@Test
-	public void getMatches_NoMatches()
+	void getMatches_NoMatches()
 	{
 		Search search = new Search("asuzgdzasuiduzasds", true, true, true, true, 0);
 		Specification spec = TransactionSearchSpecifications.withDynamicQuery(search);
@@ -230,7 +230,7 @@ public class TransactionSearchSpecificationsTest
 	}
 
 	@Test
-	public void getMatches_SearchNothing()
+	void getMatches_SearchNothing()
 	{
 		Search search = new Search("egal", false, false, false, false, 0);
 		Specification spec = TransactionSearchSpecifications.withDynamicQuery(search);
@@ -240,7 +240,7 @@ public class TransactionSearchSpecificationsTest
 	}
 
 	@Test
-	public void getMatches_SearchTagsEquals()
+	void getMatches_SearchTagsEquals()
 	{
 		Search search = new Search("MyAwesomeTag", false, false, false, true, 0);
 		Specification spec = TransactionSearchSpecifications.withDynamicQuery(search);
@@ -251,7 +251,7 @@ public class TransactionSearchSpecificationsTest
 	}
 
 	@Test
-	public void getMatches_SearchTagsLike()
+	void getMatches_SearchTagsLike()
 	{
 		Search search = new Search("Awesome", false, false, false, true, 0);
 		Specification spec = TransactionSearchSpecifications.withDynamicQuery(search);
@@ -262,7 +262,7 @@ public class TransactionSearchSpecificationsTest
 	}
 
 	@Test
-	public void getMatches_IgnoreTransactionsFromHiddenAccounts()
+	void getMatches_IgnoreTransactionsFromHiddenAccounts()
 	{
 		Search search = new Search("hidden", true, false, false, false, 0);
 		Specification spec = TransactionSearchSpecifications.withDynamicQuery(search);
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionServiceDatabaseTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionServiceDatabaseTest.java
index 6bbc70088de6c1f125eca15ef1125129c95a8617..f70237e8ea8a05623bfd2419565ff23f7b8f1613 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionServiceDatabaseTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionServiceDatabaseTest.java
@@ -9,8 +9,7 @@ import de.deadlocker8.budgetmaster.transactions.Transaction;
 import de.deadlocker8.budgetmaster.transactions.TransactionService;
 import org.joda.time.DateTime;
 import org.joda.time.format.DateTimeFormat;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.jdbc.DataSourceBuilder;
@@ -21,7 +20,6 @@ import org.springframework.context.annotation.Import;
 import org.springframework.context.annotation.Primary;
 import org.springframework.core.io.Resource;
 import org.springframework.test.context.ActiveProfiles;
-import org.springframework.test.context.junit4.SpringRunner;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.sql.DataSource;
@@ -30,13 +28,12 @@ import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringRunner.class)
 @SpringBootTest(classes = Main.class)
 @Import(TransactionServiceDatabaseTest.TestDatabaseConfiguration.class)
 @ActiveProfiles("test")
 @SeleniumTest
 @Transactional
-public class TransactionServiceDatabaseTest
+class TransactionServiceDatabaseTest
 {
 	@TestConfiguration
 	static class TestDatabaseConfiguration
@@ -61,7 +58,7 @@ public class TransactionServiceDatabaseTest
 	private AccountService accountService;
 
 	@Test
-	public void test_deleteAll()
+	void test_deleteAll()
 	{
 		transactionService.deleteAll();
 
@@ -69,21 +66,20 @@ public class TransactionServiceDatabaseTest
 	}
 
 	@Test
-	public void test_getTransactionsForAccount_specificAccount()
+	void test_getTransactionsForAccount_specificAccount()
 	{
 		DateTime date1 = DateTime.parse("2020-04-30", DateTimeFormat.forPattern("yyyy-MM-dd"));
 		FilterConfiguration filterConfiguration = new FilterConfiguration(true, true, true, true, true, null, null, "");
 
-		Transaction transaction1 = transactionService.getRepository().getOne(37);  // normal transaction
-		Transaction transaction2 = transactionService.getRepository().getOne(9);  //transfer
-
 		List<Transaction> transactions = transactionService.getTransactionsForAccount(accountService.getRepository().findByName("Second Account"), date1, DateTime.now(), filterConfiguration);
-		assertThat(transactions).hasSize(2)
-				.containsExactlyInAnyOrder(transaction1, transaction2);
+		assertThat(transactions).hasSize(2);
+
+		assertThat(transactions.get(0)).hasFieldOrPropertyWithValue("ID", 9);  // transfer
+		assertThat(transactions.get(1)).hasFieldOrPropertyWithValue("ID", 37);  // normal transaction
 	}
 
 	@Test
-	public void test_getTransactionsForAccount_all()
+	void test_getTransactionsForAccount_all()
 	{
 		DateTime date1 = DateTime.parse("2020-04-30", DateTimeFormat.forPattern("yyyy-MM-dd"));
 		FilterConfiguration filterConfiguration = new FilterConfiguration(true, true, true, true, true, null, null, "");
@@ -93,7 +89,7 @@ public class TransactionServiceDatabaseTest
 	}
 
 	@Test
-	public void test_getTransactionsForAccountUntilDate()
+	void test_getTransactionsForAccountUntilDate()
 	{
 		DateTime date1 = DateTime.parse("2020-04-30", DateTimeFormat.forPattern("yyyy-MM-dd"));
 		DateTime date2 = DateTime.parse("2020-05-20", DateTimeFormat.forPattern("yyyy-MM-dd"));
@@ -104,7 +100,7 @@ public class TransactionServiceDatabaseTest
 	}
 
 	@Test
-	public void test_getTransactionsForMonthAndYear()
+	void test_getTransactionsForMonthAndYear()
 	{
 		FilterConfiguration filterConfiguration = new FilterConfiguration(true, true, true, true, true, null, null, "");
 
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionServiceTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionServiceTest.java
index f68e41f1f6498743de60492c0140f829ec404056..6c8c094771526d439833010d1b4b49ac6f7bf286 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionServiceTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionServiceTest.java
@@ -8,20 +8,20 @@ import de.deadlocker8.budgetmaster.transactions.Transaction;
 import de.deadlocker8.budgetmaster.transactions.TransactionRepository;
 import de.deadlocker8.budgetmaster.transactions.TransactionService;
 import de.deadlocker8.budgetmaster.unit.helpers.LocalizedTest;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.util.Optional;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringJUnit4ClassRunner.class)
+@ExtendWith(SpringExtension.class)
 @LocalizedTest
-public class TransactionServiceTest
+class TransactionServiceTest
 {
 	private static final Category CATEGORY_REST = new Category("Rest", "#FFFF00", CategoryType.REST);
 	private static final Category CATEGORY_CUSTOM = new Category("CustomCategory", "#0F0F0F", CategoryType.CUSTOM);
@@ -35,7 +35,7 @@ public class TransactionServiceTest
 	private TransactionService transactionService;
 
 	@Test
-	public void test_isDeletable_rest()
+	void test_isDeletable_rest()
 	{
 		Transaction transactionRest = new Transaction();
 		transactionRest.setID(1);
@@ -51,7 +51,7 @@ public class TransactionServiceTest
 	}
 
 	@Test
-	public void test_isDeletable_custom()
+	void test_isDeletable_custom()
 	{
 		Transaction transaction = new Transaction();
 		transaction.setID(1);
@@ -67,7 +67,7 @@ public class TransactionServiceTest
 	}
 
 	@Test
-	public void test_handleAmount_null()
+	void test_handleAmount_null()
 	{
 		Transaction transaction = new Transaction();
 		transaction.setAmount(null);
@@ -80,7 +80,7 @@ public class TransactionServiceTest
 	}
 
 	@Test
-	public void test_handleAmount_expenditure()
+	void test_handleAmount_expenditure()
 	{
 		Transaction transaction = new Transaction();
 		transaction.setAmount(500);
@@ -93,7 +93,7 @@ public class TransactionServiceTest
 	}
 
 	@Test
-	public void test_handleAmount_income()
+	void test_handleAmount_income()
 	{
 		Transaction transaction = new Transaction();
 		transaction.setAmount(-500);
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionSpecificationsTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionSpecificationsTest.java
index 1867c4d66808bbd7fcf627bbadc8c5fde6df7960..67d848d4a5b5cb4d162863156c3798e27e7db59e 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionSpecificationsTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/TransactionSpecificationsTest.java
@@ -18,22 +18,22 @@ import de.deadlocker8.budgetmaster.transactions.TransactionRepository;
 import de.deadlocker8.budgetmaster.transactions.TransactionSpecifications;
 import org.joda.time.DateTime;
 import org.joda.time.format.DateTimeFormat;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
 import org.springframework.data.jpa.domain.Specification;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringJUnit4ClassRunner.class)
+@ExtendWith(SpringExtension.class)
 @DataJpaTest
-public class TransactionSpecificationsTest
+class TransactionSpecificationsTest
 {
 	@Autowired
 	private TransactionRepository transactionRepository;
@@ -68,8 +68,7 @@ public class TransactionSpecificationsTest
 
 	private DateTime startDate = new DateTime(2018, 1, 1, 12, 0, 0, 0);
 
-
-	@Before
+	@BeforeEach
 	public void init()
 	{
 		account = accountRepository.save(new Account("TestAccount", AccountType.CUSTOM));
@@ -151,7 +150,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getIncomesAndExpendituresAndTransfers()
+	void getIncomesAndExpendituresAndTransfers()
 	{
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, true, null, List.of(), List.of(), null);
 
@@ -164,7 +163,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getIncomesAndExpenditures()
+	void getIncomesAndExpenditures()
 	{
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, false, null, List.of(), List.of(), null);
 
@@ -176,7 +175,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getIncomes()
+	void getIncomes()
 	{
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, false, false, null, List.of(), List.of(), null);
 
@@ -186,7 +185,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getExpenditures()
+	void getExpenditures()
 	{
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, false, true, false, null, List.of(), List.of(), null);
 
@@ -197,7 +196,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getTransfers()
+	void getTransfers()
 	{
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, false, false, true, null, List.of(), List.of(), null);
 
@@ -207,7 +206,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void incomesAndExpendituresFalse()
+	void incomesAndExpendituresFalse()
 	{
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, false, false, false, null, List.of(), List.of(), null);
 
@@ -219,7 +218,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getTransferBackReferences_NoReferences()
+	void getTransferBackReferences_NoReferences()
 	{
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, false, true, null, List.of(), List.of(), null);
 
@@ -229,7 +228,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getTransferBackReferences()
+	void getTransferBackReferences()
 	{
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account2, false, false, true, null, List.of(), List.of(), null);
 
@@ -240,7 +239,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getTransferBackReferences_WithStartDate()
+	void getTransferBackReferences_WithStartDate()
 	{
 		DateTime startDate2019 = new DateTime(2019, 1, 1, 12, 0, 0, 0);
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate2019, DateTime.now(), account2, false, false, true, null, List.of(), List.of(), null);
@@ -250,7 +249,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getRepeating()
+	void getRepeating()
 	{
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, false, true, List.of(), List.of(), null);
 
@@ -260,7 +259,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void noRepeating()
+	void noRepeating()
 	{
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, true, false, List.of(), List.of(), null);
 
@@ -272,7 +271,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void noMatchingCategory()
+	void noMatchingCategory()
 	{
 		List<Integer> categoryIDs = new ArrayList<>();
 		categoryIDs.add(categoryUnused.getID());
@@ -283,7 +282,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getByCategory()
+	void getByCategory()
 	{
 		List<Integer> categoryIDs = new ArrayList<>();
 		categoryIDs.add(category1.getID());
@@ -296,7 +295,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getByFullName()
+	void getByFullName()
 	{
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, true, null, List.of(), List.of(), "Repeating");
 
@@ -306,7 +305,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getByPartialName()
+	void getByPartialName()
 	{
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, true, null, List.of(), List.of(), "tin");
 
@@ -316,17 +315,17 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getByPartialName_ExcludeTransfersWithWrongAccount()
+	void getByPartialName_ExcludeTransfersWithWrongAccount()
 	{
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account2, true, true, true, null, List.of(), List.of(), "tion");
 
 		List<Transaction> results = transactionRepository.findAll(spec);
 		assertThat(results).hasSize(1)
-			.contains(transferTransaction);
+				.contains(transferTransaction);
 	}
 
 	@Test
-	public void getByTags()
+	void getByTags()
 	{
 		List<Integer> tagIDs = new ArrayList<>();
 		tagIDs.add(tag1.getID());
@@ -339,13 +338,13 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getByMultipleTags()
+	void getByMultipleTags()
 	{
 		List<Integer> tagIDs = new ArrayList<>();
 		tagIDs.add(tag1.getID());
 		tagIDs.add(tag2.getID());
 
-		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, true,null, List.of(), tagIDs, null);
+		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, DateTime.now(), account, true, true, true, null, List.of(), tagIDs, null);
 
 		List<Transaction> results = transactionRepository.findAll(spec);
 		assertThat(results).hasSize(2)
@@ -355,7 +354,7 @@ public class TransactionSpecificationsTest
 
 
 	@Test
-	public void getByUnusedTags()
+	void getByUnusedTags()
 	{
 		List<Integer> tagIDs = new ArrayList<>();
 		tagIDs.add(tagUnused.getID());
@@ -367,7 +366,7 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getRepeatingExpenditureByCategoryAndTagsAndName()
+	void getRepeatingExpenditureByCategoryAndTagsAndName()
 	{
 		List<Integer> categoryIDs = new ArrayList<>();
 		categoryIDs.add(category1.getID());
@@ -384,14 +383,15 @@ public class TransactionSpecificationsTest
 	}
 
 	@Test
-	public void getFromAllAccountsExceptTransfersWithSpecificEndDateOrWithHiddenAccount()
+	void getFromAllAccountsExceptTransfersWithSpecificEndDate()
 	{
 		DateTime endDate = new DateTime(2018, 11, 30, 12, 0, 0, 0);
 		Specification spec = TransactionSpecifications.withDynamicQuery(startDate, endDate, null, true, true, false, null, List.of(), List.of(), null);
 
 		List<Transaction> results = transactionRepository.findAll(spec);
-		assertThat(results).hasSize(2)
+		assertThat(results).hasSize(3)
 				.contains(transaction1)
-				.contains(repeatingTransaction);
+				.contains(repeatingTransaction)
+				.contains(transactionInHiddenAccount);
 	}
 }
\ No newline at end of file
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/backup/LocalGitBackupTaskTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/backup/LocalGitBackupTaskTest.java
index 8699ea20c9fcb334f305195a569fd86295fda097..235e73b6111f2c1a30659d10af03c87cfd70883f 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/backup/LocalGitBackupTaskTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/backup/LocalGitBackupTaskTest.java
@@ -6,22 +6,21 @@ import de.deadlocker8.budgetmaster.backup.BackupTask;
 import de.deadlocker8.budgetmaster.backup.LocalGitBackupTask;
 import de.deadlocker8.budgetmaster.categories.CategoryType;
 import de.deadlocker8.budgetmaster.database.DatabaseService;
-import de.deadlocker8.budgetmaster.database.model.v5.BackupCategory_v5;
-import de.deadlocker8.budgetmaster.database.model.v6.BackupDatabase_v6;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupCategory_v7;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupDatabase_v7;
 import de.deadlocker8.budgetmaster.settings.Settings;
 import de.deadlocker8.budgetmaster.settings.SettingsService;
 import de.deadlocker8.budgetmaster.unit.helpers.Helpers;
 import de.thecodelabs.utils.util.OS;
 import org.joda.time.DateTimeUtils;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.io.IOException;
 import java.nio.file.Files;
@@ -31,8 +30,8 @@ import java.util.List;
 import static org.assertj.core.api.Assertions.assertThat;
 
 
-@RunWith(SpringJUnit4ClassRunner.class)
-public class LocalGitBackupTaskTest
+@ExtendWith(SpringExtension.class)
+class LocalGitBackupTaskTest
 {
 	@Mock
 	private DatabaseService databaseService;
@@ -40,13 +39,13 @@ public class LocalGitBackupTaskTest
 	@Mock
 	private SettingsService settingsService;
 
-	@Rule
-	public final TemporaryFolder tempFolder = new TemporaryFolder();
+	@TempDir
+	public Path tempFolder;
 
 	private static String gitExecutable;
 
 
-	@BeforeClass
+	@BeforeAll
 	public static void setup()
 	{
 		if(OS.isWindows())
@@ -61,14 +60,14 @@ public class LocalGitBackupTaskTest
 		DateTimeUtils.setCurrentMillisFixed(1612004400000L);
 	}
 
-	@AfterClass
+	@AfterAll
 	public static void cleanup()
 	{
 		DateTimeUtils.setCurrentMillisSystem();
 	}
 
 	@Test
-	public void test_needsCleanup()
+	void test_needsCleanup()
 	{
 		final Settings previousSettings = Settings.getDefault();
 		previousSettings.setAutoBackupStrategy(AutoBackupStrategy.GIT_LOCAL);
@@ -79,12 +78,12 @@ public class LocalGitBackupTaskTest
 	}
 
 	@Test
-	public void test_runBackup_repositoryNotExisting() throws IOException
+	void test_runBackup_repositoryNotExisting()
 	{
 		final Settings previousSettings = Settings.getDefault();
 		previousSettings.setAutoBackupStrategy(AutoBackupStrategy.GIT_LOCAL);
 
-		final Path repositoryFolder = tempFolder.newFolder().toPath().resolve(".git");
+		final Path repositoryFolder = tempFolder.resolve(".git");
 
 		final LocalGitBackupTask localGitBackupTask = new LocalGitBackupTask(databaseService, settingsService);
 		localGitBackupTask.setGitFolder(repositoryFolder);
@@ -96,14 +95,14 @@ public class LocalGitBackupTaskTest
 	}
 
 	@Test
-	public void test_runBackup_firstCommit() throws IOException
+	void test_runBackup_firstCommit()
 	{
 		final Settings previousSettings = Settings.getDefault();
 		previousSettings.setAutoBackupStrategy(AutoBackupStrategy.GIT_LOCAL);
 
-		final Path repositoryFolder = tempFolder.newFolder().toPath().resolve(".git");
+		final Path repositoryFolder = tempFolder.resolve(".git");
 
-		final BackupDatabase_v6 database = new BackupDatabase_v6();
+		final BackupDatabase_v7 database = new BackupDatabase_v7();
 		Mockito.when(databaseService.getDatabaseForJsonSerialization()).thenReturn(database);
 		Mockito.doCallRealMethod().when(databaseService).exportDatabase(Mockito.any());
 
@@ -124,14 +123,14 @@ public class LocalGitBackupTaskTest
 	}
 
 	@Test
-	public void test_runBackup_fileNotChanged() throws IOException
+	void test_runBackup_fileNotChanged()
 	{
 		final Settings previousSettings = Settings.getDefault();
 		previousSettings.setAutoBackupStrategy(AutoBackupStrategy.GIT_LOCAL);
 
-		final Path repositoryFolder = tempFolder.newFolder().toPath().resolve(".git");
+		final Path repositoryFolder = tempFolder.resolve(".git");
 
-		final BackupDatabase_v6 database = new BackupDatabase_v6();
+		final BackupDatabase_v7 database = new BackupDatabase_v7();
 		Mockito.when(databaseService.getDatabaseForJsonSerialization()).thenReturn(database);
 		Mockito.doCallRealMethod().when(databaseService).exportDatabase(Mockito.any());
 
@@ -148,14 +147,14 @@ public class LocalGitBackupTaskTest
 	}
 
 	@Test
-	public void test_runBackup_fileChanged() throws IOException
+	void test_runBackup_fileChanged()
 	{
 		final Settings previousSettings = Settings.getDefault();
 		previousSettings.setAutoBackupStrategy(AutoBackupStrategy.GIT_LOCAL);
 
-		final Path repositoryFolder = tempFolder.newFolder().toPath().resolve(".git");
+		final Path repositoryFolder = tempFolder.resolve(".git");
 
-		final BackupDatabase_v6 database = new BackupDatabase_v6();
+		final BackupDatabase_v7 database = new BackupDatabase_v7();
 		Mockito.when(databaseService.getDatabaseForJsonSerialization()).thenReturn(database);
 		Mockito.doCallRealMethod().when(databaseService).exportDatabase(Mockito.any());
 
@@ -163,7 +162,7 @@ public class LocalGitBackupTaskTest
 		localGitBackupTask.setGitFolder(repositoryFolder);
 		localGitBackupTask.run();
 
-		final BackupDatabase_v6 databaseModified = new BackupDatabase_v6(List.of(new BackupCategory_v5(5, "myCategory", "#FF0000", CategoryType.CUSTOM, null)), List.of(), List.of(), List.of(), List.of(), List.of());
+		final BackupDatabase_v7 databaseModified = new BackupDatabase_v7(List.of(new BackupCategory_v7(5, "myCategory", "#FF0000", CategoryType.CUSTOM, null)), List.of(), List.of(), List.of(), List.of(), List.of(), List.of());
 		Mockito.when(databaseService.getDatabaseForJsonSerialization()).thenReturn(databaseModified);
 		localGitBackupTask.run();
 
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/backup/RemoteGitBackupTaskTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/backup/RemoteGitBackupTaskTest.java
index 5b7cdedf96ff5a6d58c551a0fc5082bbb9f03f2e..f9dd50270a3c4738f608337ec16c92bb952e471b 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/backup/RemoteGitBackupTaskTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/backup/RemoteGitBackupTaskTest.java
@@ -6,33 +6,31 @@ import de.deadlocker8.budgetmaster.backup.BackupTask;
 import de.deadlocker8.budgetmaster.backup.RemoteGitBackupTask;
 import de.deadlocker8.budgetmaster.categories.CategoryType;
 import de.deadlocker8.budgetmaster.database.DatabaseService;
-import de.deadlocker8.budgetmaster.database.model.v5.BackupCategory_v5;
-import de.deadlocker8.budgetmaster.database.model.v6.BackupDatabase_v6;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupCategory_v7;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupDatabase_v7;
 import de.deadlocker8.budgetmaster.settings.Settings;
 import de.deadlocker8.budgetmaster.settings.SettingsService;
 import de.deadlocker8.budgetmaster.unit.helpers.Helpers;
 import de.thecodelabs.utils.util.OS;
 import org.joda.time.DateTimeUtils;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.io.IOException;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 
-@RunWith(SpringJUnit4ClassRunner.class)
-public class RemoteGitBackupTaskTest
+@ExtendWith(SpringExtension.class)
+class RemoteGitBackupTaskTest
 {
 	@Mock
 	private DatabaseService databaseService;
@@ -40,13 +38,13 @@ public class RemoteGitBackupTaskTest
 	@Mock
 	private SettingsService settingsService;
 
-	@Rule
-	public final TemporaryFolder tempFolder = new TemporaryFolder();
+	@TempDir
+	public Path tempFolder;
 
 	private static String gitExecutable;
 
 
-	@BeforeClass
+	@BeforeAll
 	public static void setup()
 	{
 		if(OS.isWindows())
@@ -61,14 +59,14 @@ public class RemoteGitBackupTaskTest
 		DateTimeUtils.setCurrentMillisFixed(1612004400000L);
 	}
 
-	@AfterClass
+	@AfterAll
 	public static void cleanup()
 	{
 		DateTimeUtils.setCurrentMillisSystem();
 	}
 
 	@Test
-	public void test_needsCleanup_false_everythingEquals()
+	void test_needsCleanup_false_everythingEquals()
 	{
 		final Settings previousSettings = Settings.getDefault();
 		previousSettings.setAutoBackupStrategy(AutoBackupStrategy.GIT_REMOTE);
@@ -79,11 +77,12 @@ public class RemoteGitBackupTaskTest
 
 		final RemoteGitBackupTask remoteGitBackupTask = new RemoteGitBackupTask(databaseService, settingsService);
 
-		assertFalse(remoteGitBackupTask.needsCleanup(previousSettings, previousSettings));
+		assertThat(remoteGitBackupTask.needsCleanup(previousSettings, previousSettings))
+				.isFalse();
 	}
 
 	@Test
-	public void test_needsCleanup_false_onlyNameChanged()
+	void test_needsCleanup_false_onlyNameChanged()
 	{
 		final Settings previousSettings = Settings.getDefault();
 		previousSettings.setAutoBackupStrategy(AutoBackupStrategy.GIT_REMOTE);
@@ -101,11 +100,11 @@ public class RemoteGitBackupTaskTest
 
 		final RemoteGitBackupTask remoteGitBackupTask = new RemoteGitBackupTask(databaseService, settingsService);
 
-		assertFalse(remoteGitBackupTask.needsCleanup(previousSettings, newSettings));
+		assertThat(remoteGitBackupTask.needsCleanup(previousSettings, newSettings)).isFalse();
 	}
 
 	@Test
-	public void test_needsCleanup_true_urlChanged()
+	void test_needsCleanup_true_urlChanged()
 	{
 		final Settings previousSettings = Settings.getDefault();
 		previousSettings.setAutoBackupStrategy(AutoBackupStrategy.GIT_REMOTE);
@@ -123,11 +122,12 @@ public class RemoteGitBackupTaskTest
 
 		final RemoteGitBackupTask remoteGitBackupTask = new RemoteGitBackupTask(databaseService, settingsService);
 
-		assertTrue(remoteGitBackupTask.needsCleanup(previousSettings, newSettings));
+		assertThat(remoteGitBackupTask.needsCleanup(previousSettings, newSettings))
+				.isTrue();
 	}
 
 	@Test
-	public void test_needsCleanup_true_branchNameChanged()
+	void test_needsCleanup_true_branchNameChanged()
 	{
 		final Settings previousSettings = Settings.getDefault();
 		previousSettings.setAutoBackupStrategy(AutoBackupStrategy.GIT_REMOTE);
@@ -145,15 +145,16 @@ public class RemoteGitBackupTaskTest
 
 		final RemoteGitBackupTask remoteGitBackupTask = new RemoteGitBackupTask(databaseService, settingsService);
 
-		assertTrue(remoteGitBackupTask.needsCleanup(previousSettings, newSettings));
+		assertThat(remoteGitBackupTask.needsCleanup(previousSettings, newSettings))
+				.isTrue();
 	}
 
 	@Test
-	public void test_runBackup_firstCommit() throws IOException
+	void test_runBackup_firstCommit() throws IOException
 	{
 		// create fake server
-		final Path fakeServerFolder = tempFolder.newFolder("server").toPath();
-		final Path repositoryFolder = tempFolder.newFolder().toPath().resolve(".git");
+		final Path fakeServerFolder = Files.createDirectory(tempFolder.resolve("server"));
+		final Path repositoryFolder = Files.createDirectory(tempFolder.resolve("client")).resolve(".git");
 
 		final RemoteGitBackupTask remoteGitBackupTask = createBackupTask(repositoryFolder, fakeServerFolder);
 		remoteGitBackupTask.run();
@@ -184,11 +185,11 @@ public class RemoteGitBackupTaskTest
 	}
 
 	@Test
-	public void test_runBackup_fileNotChanged() throws IOException
+	void test_runBackup_fileNotChanged() throws IOException
 	{
 		// create fake server
-		final Path fakeServerFolder = tempFolder.newFolder("server").toPath();
-		final Path repositoryFolder = tempFolder.newFolder().toPath().resolve(".git");
+		final Path fakeServerFolder = Files.createDirectory(tempFolder.resolve("server"));
+		final Path repositoryFolder = Files.createDirectory(tempFolder.resolve("client")).resolve(".git");
 
 		final RemoteGitBackupTask remoteGitBackupTask = createBackupTask(repositoryFolder, fakeServerFolder);
 		remoteGitBackupTask.run();
@@ -208,16 +209,16 @@ public class RemoteGitBackupTaskTest
 	}
 
 	@Test
-	public void test_runBackup_fileChanged() throws IOException
+	void test_runBackup_fileChanged() throws IOException
 	{
 		// create fake server
-		final Path fakeServerFolder = tempFolder.newFolder("server").toPath();
-		final Path repositoryFolder = tempFolder.newFolder().toPath().resolve(".git");
+		final Path fakeServerFolder = Files.createDirectory(tempFolder.resolve("server"));
+		final Path repositoryFolder = Files.createDirectory(tempFolder.resolve("client")).resolve(".git");
 
 		final RemoteGitBackupTask remoteGitBackupTask = createBackupTask(repositoryFolder, fakeServerFolder);
 		remoteGitBackupTask.run();
 
-		final BackupDatabase_v6 databaseModified = new BackupDatabase_v6(List.of(new BackupCategory_v5(5, "myCategory", "#FF0000", CategoryType.CUSTOM, null)), List.of(), List.of(), List.of(), List.of(), List.of());
+		final BackupDatabase_v7 databaseModified = new BackupDatabase_v7(List.of(new BackupCategory_v7(5, "myCategory", "#FF0000", CategoryType.CUSTOM, null)), List.of(), List.of(), List.of(), List.of(), List.of(), List.of());
 		Mockito.when(databaseService.getDatabaseForJsonSerialization()).thenReturn(databaseModified);
 		remoteGitBackupTask.run();
 
@@ -257,7 +258,7 @@ public class RemoteGitBackupTaskTest
 		settings.setAutoBackupGitToken("0815");
 		Mockito.when(settingsService.getSettings()).thenReturn(settings);
 
-		final BackupDatabase_v6 database = new BackupDatabase_v6();
+		final BackupDatabase_v7 database = new BackupDatabase_v7();
 		Mockito.when(databaseService.getDatabaseForJsonSerialization()).thenReturn(database);
 		Mockito.doCallRealMethod().when(databaseService).exportDatabase(Mockito.any());
 
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseExportTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseExportTest.java
index 3e0648db995343192961f9b61bec836d66f14c23..6174a6655790f4e05ca3987f6fbf748720aa9a4d 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseExportTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseExportTest.java
@@ -9,14 +9,14 @@ import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.categories.Category;
 import de.deadlocker8.budgetmaster.categories.CategoryService;
 import de.deadlocker8.budgetmaster.categories.CategoryType;
-import de.deadlocker8.budgetmaster.charts.Chart;
-import de.deadlocker8.budgetmaster.charts.ChartRepository;
-import de.deadlocker8.budgetmaster.charts.ChartService;
-import de.deadlocker8.budgetmaster.charts.ChartType;
+import de.deadlocker8.budgetmaster.charts.*;
 import de.deadlocker8.budgetmaster.database.DatabaseParser;
 import de.deadlocker8.budgetmaster.database.DatabaseService;
 import de.deadlocker8.budgetmaster.database.InternalDatabase;
 import de.deadlocker8.budgetmaster.database.JSONIdentifier;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.IconRepository;
+import de.deadlocker8.budgetmaster.icon.IconService;
 import de.deadlocker8.budgetmaster.images.Image;
 import de.deadlocker8.budgetmaster.images.ImageFileExtension;
 import de.deadlocker8.budgetmaster.images.ImageRepository;
@@ -35,15 +35,14 @@ import de.deadlocker8.budgetmaster.transactions.TransactionRepository;
 import de.deadlocker8.budgetmaster.transactions.TransactionService;
 import de.thecodelabs.utils.util.Localization;
 import org.joda.time.DateTime;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
@@ -55,10 +54,10 @@ import java.util.Locale;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringJUnit4ClassRunner.class)
-public class DatabaseExportTest
+@ExtendWith(SpringExtension.class)
+class DatabaseExportTest
 {
-	@Before
+	@BeforeEach
 	public void before()
 	{
 		Localization.setDelegate(new Localization.LocalizationDelegate()
@@ -102,14 +101,17 @@ public class DatabaseExportTest
 	@Mock
 	private ImageService imageService;
 
+	@Mock
+	private IconService iconService;
+
 	@InjectMocks
 	private DatabaseService databaseService;
 
-	@Rule
-	public final TemporaryFolder tempFolder = new TemporaryFolder();
+	@TempDir
+	public Path tempFolder;
 
 	@Test
-	public void test_specialFields() throws IOException
+	void test_specialFields() throws IOException
 	{
 		// categories
 		Mockito.when(categoryService.getAllEntitiesAsc()).thenReturn(List.of());
@@ -139,9 +141,14 @@ public class DatabaseExportTest
 		Mockito.when(imageRepositoryMock.findAll()).thenReturn(List.of());
 		Mockito.when(imageService.getRepository()).thenReturn(imageRepositoryMock);
 
+		// icons
+		IconRepository iconRepositoryMock = Mockito.mock(IconRepository.class);
+		Mockito.when(iconRepositoryMock.findAll()).thenReturn(List.of());
+		Mockito.when(iconService.getRepository()).thenReturn(iconRepositoryMock);
+
 
 		// act
-		Path exportPath = tempFolder.newFile("exportTest.json").toPath();
+		Path exportPath = Files.createFile(tempFolder.resolve("exportTest.json"));
 		databaseService.exportDatabase(exportPath);
 
 
@@ -154,7 +161,7 @@ public class DatabaseExportTest
 	}
 
 	@Test
-	public void test_exportDatabase() throws IOException
+	void test_exportDatabase() throws IOException
 	{
 		// categories
 		Category categoryNone = new Category("NONE", "#000000", CategoryType.NONE);
@@ -234,6 +241,8 @@ public class DatabaseExportTest
 		chart.setType(ChartType.CUSTOM);
 		chart.setVersion(7);
 		chart.setScript("/* This list will be dynamically filled with all the transactions between\r\n* the start and and date you select on the \"Show Chart\" page\r\n* and filtered according to your specified filter.\r\n* An example entry for this list and tutorial about how to create custom charts ca be found in the BudgetMaster wiki:\r\n* https://github.com/deadlocker8/BudgetMaster/wiki/How-to-create-custom-charts\r\n*/\r\nvar transactionData \u003d [];\r\n\r\n// Prepare your chart settings here (mandatory)\r\nvar plotlyData \u003d [{\r\n    x: [],\r\n    y: [],\r\n    type: \u0027bar\u0027\r\n}];\r\n\r\n// Add your Plotly layout settings here (optional)\r\nvar plotlyLayout \u003d {};\r\n\r\n// Add your Plotly configuration settings here (optional)\r\nvar plotlyConfig \u003d {\r\n    showSendToCloud: false,\r\n    displaylogo: false,\r\n    showLink: false,\r\n    responsive: true\r\n};\r\n\r\n// Don\u0027t touch this line\r\nPlotly.newPlot(\"containerID\", plotlyData, plotlyLayout, plotlyConfig);\r\n");
+		chart.setDisplayType(ChartDisplayType.CUSTOM);
+		chart.setGroupType(ChartGroupType.NONE);
 
 		ChartRepository chartRepositoryMock = Mockito.mock(ChartRepository.class);
 		Mockito.when(chartRepositoryMock.findAllByType(Mockito.any())).thenReturn(List.of(chart));
@@ -247,9 +256,20 @@ public class DatabaseExportTest
 		Mockito.when(imageRepositoryMock.findAll()).thenReturn(List.of(image));
 		Mockito.when(imageService.getRepository()).thenReturn(imageRepositoryMock);
 
+		// icons
+		final Icon iconImage = new Icon(image);
+		iconImage.setID(38);
+
+		final Icon iconBuiltin = new Icon("fas fa-icons");
+		iconBuiltin.setID(39);
+
+		IconRepository iconRepositoryMock = Mockito.mock(IconRepository.class);
+		Mockito.when(iconRepositoryMock.findAll()).thenReturn(List.of(iconImage, iconBuiltin));
+		Mockito.when(iconService.getRepository()).thenReturn(iconRepositoryMock);
+
 
 		// act
-		Path exportPath = tempFolder.newFile("exportTest.json").toPath();
+		Path exportPath = Files.createFile(tempFolder.resolve("exportTest.json"));
 		databaseService.exportDatabase(exportPath);
 
 		// assert
@@ -263,5 +283,6 @@ public class DatabaseExportTest
 		assertThat(importedDatabase.getTemplates()).containsExactly(template1, template2);
 		assertThat(importedDatabase.getCharts()).containsExactly(chart);
 		assertThat(importedDatabase.getImages()).containsExactly(image);
+		assertThat(importedDatabase.getIcons()).containsExactly(iconImage, iconBuiltin);
 	}
 }
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParserTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParserTest.java
index d514bd46eecff44c4a4cdf7d235f0f4c9c79a340..57b0debb6dc17a6ceb5c707e75507e60e8cf277f 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParserTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParserTest.java
@@ -1,13 +1,13 @@
 package de.deadlocker8.budgetmaster.unit.database;
 
-import de.deadlocker8.budgetmaster.database.InternalDatabase;
 import de.deadlocker8.budgetmaster.database.DatabaseParser;
+import de.deadlocker8.budgetmaster.database.InternalDatabase;
 import de.thecodelabs.utils.util.Localization;
 import de.thecodelabs.utils.util.Localization.LocalizationDelegate;
 import de.thecodelabs.utils.util.localization.LocalizationMessageFormatter;
 import de.thecodelabs.utils.util.localization.formatter.JavaMessageFormatter;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
@@ -19,9 +19,9 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 
-public class DatabaseParserTest
+class DatabaseParserTest
 {
-	@Before
+	@BeforeEach
 	public void before()
 	{
 		Localization.setDelegate(new LocalizationDelegate()
@@ -48,7 +48,7 @@ public class DatabaseParserTest
 	}
 
 	@Test
-	public void test_v6() throws URISyntaxException, IOException
+	void test_v6() throws URISyntaxException, IOException
 	{
 		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
 		DatabaseParser importer = new DatabaseParser(json);
@@ -58,7 +58,7 @@ public class DatabaseParserTest
 	}
 
 	@Test
-	public void test_v5() throws URISyntaxException, IOException
+	void test_v5() throws URISyntaxException, IOException
 	{
 		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v5Test.json").toURI())));
 		DatabaseParser importer = new DatabaseParser(json);
@@ -68,7 +68,7 @@ public class DatabaseParserTest
 	}
 
 	@Test
-	public void test_v4() throws URISyntaxException, IOException
+	void test_v4() throws URISyntaxException, IOException
 	{
 		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v4Test.json").toURI())));
 		DatabaseParser importer = new DatabaseParser(json);
@@ -78,7 +78,7 @@ public class DatabaseParserTest
 	}
 
 	@Test
-	public void test_v3() throws URISyntaxException, IOException
+	void test_v3() throws URISyntaxException, IOException
 	{
 		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v3Test.json").toURI())));
 		DatabaseParser importer = new DatabaseParser(json);
@@ -88,7 +88,7 @@ public class DatabaseParserTest
 	}
 
 	@Test
-	public void test_v2() throws URISyntaxException, IOException
+	void test_v2() throws URISyntaxException, IOException
 	{
 		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("LegacyParserTest.json").toURI())));
 		DatabaseParser importer = new DatabaseParser(json);
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v4Test.java b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v4Test.java
index bd0b3a64fa42906942fb1ece72d06cca846729de..1bbbac3df1bc6d8ca11add71e43c7f0756e1c46c 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v4Test.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v4Test.java
@@ -6,11 +6,10 @@ import de.deadlocker8.budgetmaster.database.DatabaseParser_v4;
 import de.deadlocker8.budgetmaster.database.model.v4.*;
 import de.deadlocker8.budgetmaster.repeating.endoption.RepeatingEndAfterXTimes;
 import de.deadlocker8.budgetmaster.repeating.modifier.RepeatingModifierDays;
-import de.deadlocker8.budgetmaster.tags.Tag;
 import de.thecodelabs.utils.util.Localization;
 import de.thecodelabs.utils.util.Localization.LocalizationDelegate;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
@@ -20,12 +19,13 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
-import static org.assertj.core.api.Assertions.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 
-public class DatabaseParser_v4Test
+class DatabaseParser_v4Test
 {
-	@Before
+	@BeforeEach
 	public void before()
 	{
 		Localization.setDelegate(new LocalizationDelegate()
@@ -46,7 +46,7 @@ public class DatabaseParser_v4Test
 	}
 
 	@Test
-	public void test_Categories()
+	void test_Categories()
 	{
 		try
 		{
@@ -68,7 +68,7 @@ public class DatabaseParser_v4Test
 	}
 
 	@Test
-	public void test_Accounts()
+	void test_Accounts()
 	{
 		try
 		{
@@ -88,7 +88,7 @@ public class DatabaseParser_v4Test
 	}
 
 	@Test
-	public void test_Transactions()
+	void test_Transactions()
 	{
 		try
 		{
@@ -170,7 +170,7 @@ public class DatabaseParser_v4Test
 	}
 
 	@Test
-	public void test_Templates()
+	void test_Templates()
 	{
 		try
 		{
@@ -225,7 +225,7 @@ public class DatabaseParser_v4Test
 	}
 
 	@Test
-	public void test_convertToInternalShouldFail() throws URISyntaxException, IOException
+	void test_convertToInternalShouldFail() throws URISyntaxException, IOException
 	{
 		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v4Test.json").toURI())));
 		DatabaseParser_v4 parser = new DatabaseParser_v4(json);
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v5Test.java b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v5Test.java
index 962e4f50f94768a3a673495d362b1d4fad10f585..be2ff915b268f895b97777d844313cc88aeaadaa 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v5Test.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v5Test.java
@@ -4,17 +4,19 @@ import de.deadlocker8.budgetmaster.accounts.AccountState;
 import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.categories.CategoryType;
 import de.deadlocker8.budgetmaster.charts.ChartType;
-import de.deadlocker8.budgetmaster.database.DatabaseParser_v4;
 import de.deadlocker8.budgetmaster.database.DatabaseParser_v5;
-import de.deadlocker8.budgetmaster.database.model.v4.*;
+import de.deadlocker8.budgetmaster.database.model.v4.BackupRepeatingEndOption_v4;
+import de.deadlocker8.budgetmaster.database.model.v4.BackupRepeatingModifier_v4;
+import de.deadlocker8.budgetmaster.database.model.v4.BackupRepeatingOption_v4;
+import de.deadlocker8.budgetmaster.database.model.v4.BackupTag_v4;
 import de.deadlocker8.budgetmaster.database.model.v5.*;
 import de.deadlocker8.budgetmaster.images.ImageFileExtension;
 import de.deadlocker8.budgetmaster.repeating.endoption.RepeatingEndAfterXTimes;
 import de.deadlocker8.budgetmaster.repeating.modifier.RepeatingModifierDays;
 import de.thecodelabs.utils.util.Localization;
 import de.thecodelabs.utils.util.Localization.LocalizationDelegate;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
@@ -28,9 +30,9 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 
-public class DatabaseParser_v5Test
+class DatabaseParser_v5Test
 {
-	@Before
+	@BeforeEach
 	public void before()
 	{
 		Localization.setDelegate(new LocalizationDelegate()
@@ -51,7 +53,7 @@ public class DatabaseParser_v5Test
 	}
 
 	@Test
-	public void test_Charts()
+	void test_Charts()
 	{
 		try
 		{
@@ -71,7 +73,7 @@ public class DatabaseParser_v5Test
 	}
 
 	@Test
-	public void test_Categories()
+	void test_Categories()
 	{
 		try
 		{
@@ -91,7 +93,7 @@ public class DatabaseParser_v5Test
 	}
 
 	@Test
-	public void test_Accounts()
+	void test_Accounts()
 	{
 		try
 		{
@@ -115,7 +117,7 @@ public class DatabaseParser_v5Test
 	}
 
 	@Test
-	public void test_Images()
+	void test_Images()
 	{
 		try
 		{
@@ -136,7 +138,7 @@ public class DatabaseParser_v5Test
 	}
 
 	@Test
-	public void test_Templates()
+	void test_Templates()
 	{
 		try
 		{
@@ -165,7 +167,7 @@ public class DatabaseParser_v5Test
 	}
 
 	@Test
-	public void test_Transactions()
+	void test_Transactions()
 	{
 		try
 		{
@@ -250,7 +252,7 @@ public class DatabaseParser_v5Test
 		}
 	}
 	@Test
-	public void test_convertToInternalShouldFail() throws URISyntaxException, IOException
+	void test_convertToInternalShouldFail() throws URISyntaxException, IOException
 	{
 		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v5Test.json").toURI())));
 		DatabaseParser_v5 parser = new DatabaseParser_v5(json);
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v6Test.java b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v6Test.java
index 22cfef0df591dc2b13da0cb6787b21d7a70e5e47..c90e64c931661347c0309fd439aff6bae55e6989 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v6Test.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v6Test.java
@@ -15,13 +15,17 @@ import de.deadlocker8.budgetmaster.database.model.v6.BackupAccount_v6;
 import de.deadlocker8.budgetmaster.database.model.v6.BackupDatabase_v6;
 import de.deadlocker8.budgetmaster.database.model.v6.BackupTemplate_v6;
 import de.deadlocker8.budgetmaster.database.model.v6.BackupTransaction_v6;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupAccount_v7;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupCategory_v7;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupDatabase_v7;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupTemplate_v7;
 import de.deadlocker8.budgetmaster.images.ImageFileExtension;
 import de.deadlocker8.budgetmaster.repeating.endoption.RepeatingEndAfterXTimes;
 import de.deadlocker8.budgetmaster.repeating.modifier.RepeatingModifierDays;
 import de.thecodelabs.utils.util.Localization;
 import de.thecodelabs.utils.util.Localization.LocalizationDelegate;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
@@ -34,9 +38,9 @@ import java.util.Locale;
 import static org.assertj.core.api.Assertions.assertThat;
 
 
-public class DatabaseParser_v6Test
+class DatabaseParser_v6Test
 {
-	@Before
+	@BeforeEach
 	public void before()
 	{
 		Localization.setDelegate(new LocalizationDelegate()
@@ -57,7 +61,7 @@ public class DatabaseParser_v6Test
 	}
 
 	@Test
-	public void test_Charts() throws URISyntaxException, IOException
+	void test_Charts() throws URISyntaxException, IOException
 	{
 		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
 		DatabaseParser_v6 parser = new DatabaseParser_v6(json);
@@ -70,7 +74,7 @@ public class DatabaseParser_v6Test
 	}
 
 	@Test
-	public void test_Categories() throws URISyntaxException, IOException
+	void test_Categories() throws URISyntaxException, IOException
 	{
 		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
 		DatabaseParser_v6 parser = new DatabaseParser_v6(json);
@@ -83,7 +87,7 @@ public class DatabaseParser_v6Test
 	}
 
 	@Test
-	public void test_Accounts() throws URISyntaxException, IOException
+	void test_Accounts() throws URISyntaxException, IOException
 	{
 		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
 		DatabaseParser_v6 parser = new DatabaseParser_v6(json);
@@ -91,14 +95,14 @@ public class DatabaseParser_v6Test
 
 		final BackupAccount_v6 account = new BackupAccount_v6(3, "Second Account", AccountState.FULL_ACCESS, AccountType.CUSTOM, 1);
 
-		assertThat(database.getAccounts()).hasSize(3)
+		assertThat(database.getAccounts()).hasSize(4)
 				.contains(account);
 		assertThat(database.getAccounts().get(2).getIconID())
 				.isOne();
 	}
 
 	@Test
-	public void test_Images() throws URISyntaxException, IOException
+	void test_Images() throws URISyntaxException, IOException
 	{
 		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
 		DatabaseParser_v6 parser = new DatabaseParser_v6(json);
@@ -112,7 +116,7 @@ public class DatabaseParser_v6Test
 	}
 
 	@Test
-	public void test_Templates() throws URISyntaxException, IOException
+	void test_Templates() throws URISyntaxException, IOException
 	{
 		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
 		DatabaseParser_v6 parser = new DatabaseParser_v6(json);
@@ -131,7 +135,7 @@ public class DatabaseParser_v6Test
 	}
 
 	@Test
-	public void test_Transactions() throws URISyntaxException, IOException
+	void test_Transactions() throws URISyntaxException, IOException
 	{
 		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
 		DatabaseParser_v6 parser = new DatabaseParser_v6(json);
@@ -197,4 +201,56 @@ public class DatabaseParser_v6Test
 						repeatingTransaction_1,
 						transferTransaction);
 	}
+
+	@Test
+	void test_Upgrade_Accounts() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
+		DatabaseParser_v6 parser = new DatabaseParser_v6(json);
+		BackupDatabase_v6 database = parser.parseDatabaseFromJSON();
+
+		final BackupDatabase_v7 upgradedDatabase = (BackupDatabase_v7) database.upgrade();
+
+		final BackupAccount_v7 upgradedAccount1 = new BackupAccount_v7(1, "Placeholder", AccountState.FULL_ACCESS, AccountType.ALL, null);
+		final BackupAccount_v7 upgradedAccount2 = new BackupAccount_v7(2, "Default", AccountState.FULL_ACCESS, AccountType.CUSTOM, null);
+		final BackupAccount_v7 upgradedAccount3 = new BackupAccount_v7(3, "Second Account", AccountState.FULL_ACCESS, AccountType.CUSTOM, 1);
+		final BackupAccount_v7 upgradedAccount4 = new BackupAccount_v7(4, "Third Account", AccountState.FULL_ACCESS, AccountType.CUSTOM, 2);
+
+		assertThat(upgradedDatabase.getAccounts()).hasSize(4)
+				.containsExactly(upgradedAccount1, upgradedAccount2, upgradedAccount3, upgradedAccount4);
+	}
+
+	@Test
+	void test_Upgrade_Templates() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
+		DatabaseParser_v6 parser = new DatabaseParser_v6(json);
+		BackupDatabase_v6 database = parser.parseDatabaseFromJSON();
+
+		final BackupDatabase_v7 upgradedDatabase = (BackupDatabase_v7) database.upgrade();
+
+		final BackupTemplate_v7 upgradedTemplate = new BackupTemplate_v7("Template with icon", null, true, null, null, null, null, 3, List.of(), null);
+
+		assertThat(upgradedDatabase.getTemplates()).hasSize(4)
+				.contains(upgradedTemplate);
+		assertThat(upgradedDatabase.getIcons().get(2).getImageID())
+				.isOne();
+	}
+
+	@Test
+	void test_Upgrade_Categories() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
+		DatabaseParser_v6 parser = new DatabaseParser_v6(json);
+		BackupDatabase_v6 database = parser.parseDatabaseFromJSON();
+
+		final BackupDatabase_v7 upgradedDatabase = (BackupDatabase_v7) database.upgrade();
+
+		final BackupCategory_v7 upgradedCategory = new BackupCategory_v7(3, "0815", "#ffcc00", CategoryType.CUSTOM, 0);
+
+		assertThat(upgradedDatabase.getCategories()).hasSize(3)
+				.contains(upgradedCategory);
+		assertThat(upgradedDatabase.getIcons().get(0).getBuiltinIdentifier())
+				.isEqualTo("fas fa-icons");
+	}
 }
\ No newline at end of file
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v7Test.java b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v7Test.java
new file mode 100644
index 0000000000000000000000000000000000000000..d238edb7e957a3ca81537d365c4b588d78cb21e5
--- /dev/null
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v7Test.java
@@ -0,0 +1,214 @@
+package de.deadlocker8.budgetmaster.unit.database;
+
+import de.deadlocker8.budgetmaster.accounts.AccountState;
+import de.deadlocker8.budgetmaster.accounts.AccountType;
+import de.deadlocker8.budgetmaster.categories.CategoryType;
+import de.deadlocker8.budgetmaster.charts.ChartType;
+import de.deadlocker8.budgetmaster.database.DatabaseParser_v7;
+import de.deadlocker8.budgetmaster.database.model.v4.BackupRepeatingEndOption_v4;
+import de.deadlocker8.budgetmaster.database.model.v4.BackupRepeatingModifier_v4;
+import de.deadlocker8.budgetmaster.database.model.v4.BackupRepeatingOption_v4;
+import de.deadlocker8.budgetmaster.database.model.v4.BackupTag_v4;
+import de.deadlocker8.budgetmaster.database.model.v5.BackupChart_v5;
+import de.deadlocker8.budgetmaster.database.model.v6.BackupTransaction_v6;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupAccount_v7;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupCategory_v7;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupDatabase_v7;
+import de.deadlocker8.budgetmaster.database.model.v7.BackupTemplate_v7;
+import de.deadlocker8.budgetmaster.images.ImageFileExtension;
+import de.deadlocker8.budgetmaster.repeating.endoption.RepeatingEndAfterXTimes;
+import de.deadlocker8.budgetmaster.repeating.modifier.RepeatingModifierDays;
+import de.thecodelabs.utils.util.Localization;
+import de.thecodelabs.utils.util.Localization.LocalizationDelegate;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+
+class DatabaseParser_v7Test
+{
+	@BeforeEach
+	public void before()
+	{
+		Localization.setDelegate(new LocalizationDelegate()
+		{
+			@Override
+			public Locale getLocale()
+			{
+				return Locale.ENGLISH;
+			}
+
+			@Override
+			public String getBaseResource()
+			{
+				return "languages/base";
+			}
+		});
+		Localization.load();
+	}
+
+	@Test
+	void test_Charts() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+		DatabaseParser_v7 parser = new DatabaseParser_v7(json);
+		BackupDatabase_v7 database = parser.parseDatabaseFromJSON();
+
+		final BackupChart_v5 chart = new BackupChart_v5(9, "The best chart", "/* This list will be dynamically filled with all the transactions between\r\n* the start and and date you select on the \"Show Chart\" page\r\n* and filtered according to your specified filter.\r\n* An example entry for this list and tutorial about how to create custom charts ca be found in the BudgetMaster wiki:\r\n* https://github.com/deadlocker8/BudgetMaster/wiki/How-to-create-custom-charts\r\n*/\r\nvar transactionData \u003d [];\r\n\r\n// Prepare your chart settings here (mandatory)\r\nvar plotlyData \u003d [{\r\n    x: [],\r\n    y: [],\r\n    type: \u0027bar\u0027\r\n}];\r\n\r\n// Add your Plotly layout settings here (optional)\r\nvar plotlyLayout \u003d {};\r\n\r\n// Add your Plotly configuration settings here (optional)\r\nvar plotlyConfig \u003d {\r\n    showSendToCloud: false,\r\n    displaylogo: false,\r\n    showLink: false,\r\n    responsive: true\r\n};\r\n\r\n// Don\u0027t touch this line\r\nPlotly.newPlot(\"containerID\", plotlyData, plotlyLayout, plotlyConfig);\r\n", ChartType.CUSTOM, 7);
+
+		assertThat(database.getCharts()).hasSize(1)
+				.contains(chart);
+	}
+
+	@Test
+	void test_Categories() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+		DatabaseParser_v7 parser = new DatabaseParser_v7(json);
+		BackupDatabase_v7 database = parser.parseDatabaseFromJSON();
+
+		final BackupCategory_v7 category = new BackupCategory_v7(3, "0815", "#ffcc00", CategoryType.CUSTOM, 2);
+
+		assertThat(database.getCategories()).hasSize(3)
+				.contains(category);
+	}
+
+	@Test
+	void test_Accounts() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+		DatabaseParser_v7 parser = new DatabaseParser_v7(json);
+		BackupDatabase_v7 database = parser.parseDatabaseFromJSON();
+
+		final BackupAccount_v7 account = new BackupAccount_v7(3, "Second Account", AccountState.FULL_ACCESS, AccountType.CUSTOM, 1);
+
+		assertThat(database.getAccounts()).hasSize(3)
+				.contains(account);
+		assertThat(database.getAccounts().get(2).getIconReferenceID())
+				.isOne();
+	}
+
+	@Test
+	void test_Images() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+		DatabaseParser_v7 parser = new DatabaseParser_v7(json);
+		BackupDatabase_v7 database = parser.parseDatabaseFromJSON();
+
+		assertThat(database.getImages()).hasSize(1);
+		assertThat(database.getImages().get(0)).hasFieldOrPropertyWithValue("fileExtension", ImageFileExtension.PNG);
+		assertThat(database.getImages().get(0).getImage())
+				.isNotNull()
+				.hasSizeGreaterThan(1);
+	}
+
+	@Test
+	void test_Templates() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+		DatabaseParser_v7 parser = new DatabaseParser_v7(json);
+		BackupDatabase_v7 database = parser.parseDatabaseFromJSON();
+
+		BackupTemplate_v7 template = new BackupTemplate_v7();
+		template.setTemplateName("Template with icon");
+		template.setExpenditure(true);
+		template.setIconReferenceID(1);
+		template.setTags(List.of());
+
+		assertThat(database.getTemplates()).hasSize(4)
+				.contains(template);
+		assertThat(database.getTemplates().get(3).getIconReferenceID())
+				.isOne();
+	}
+
+	@Test
+	void test_Transactions() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+		DatabaseParser_v7 parser = new DatabaseParser_v7(json);
+		BackupDatabase_v7 database = parser.parseDatabaseFromJSON();
+
+		BackupTransaction_v6 normalTransaction_1 = new BackupTransaction_v6();
+		normalTransaction_1.setAmount(35000);
+		normalTransaction_1.setDate("2018-03-13");
+		normalTransaction_1.setCategoryID(1);
+		normalTransaction_1.setName("Income");
+		normalTransaction_1.setDescription("Lorem Ipsum");
+		normalTransaction_1.setTags(new ArrayList<>());
+		normalTransaction_1.setAccountID(2);
+		normalTransaction_1.setExpenditure(false);
+
+		BackupTransaction_v6 normalTransaction_2 = new BackupTransaction_v6();
+		normalTransaction_2.setAmount(-2000);
+		normalTransaction_2.setDate("2018-06-15");
+		normalTransaction_2.setName("Simple");
+		normalTransaction_2.setDescription("");
+		normalTransaction_2.setAccountID(3);
+		normalTransaction_2.setCategoryID(3);
+		normalTransaction_2.setExpenditure(true);
+
+		List<BackupTag_v4> tags = new ArrayList<>();
+		BackupTag_v4 tag = new BackupTag_v4("0815");
+		tags.add(tag);
+		normalTransaction_2.setTags(tags);
+
+		BackupTransaction_v6 repeatingTransaction_1 = new BackupTransaction_v6();
+		repeatingTransaction_1.setAmount(-12300);
+		String repeatingTransaction_1Date = "2018-03-13";
+		repeatingTransaction_1.setDate(repeatingTransaction_1Date);
+		repeatingTransaction_1.setCategoryID(1);
+		repeatingTransaction_1.setName("Test");
+		repeatingTransaction_1.setDescription("");
+		repeatingTransaction_1.setAccountID(2);
+		BackupRepeatingOption_v4 repeatingOption_1 = new BackupRepeatingOption_v4();
+		repeatingOption_1.setModifier(new BackupRepeatingModifier_v4(10, new RepeatingModifierDays(10).getLocalizationKey()));
+		repeatingOption_1.setStartDate(repeatingTransaction_1Date);
+		BackupRepeatingEndOption_v4 endOption = new BackupRepeatingEndOption_v4();
+		endOption.setTimes(2);
+		endOption.setLocalizationKey(new RepeatingEndAfterXTimes(2).getLocalizationKey());
+		repeatingOption_1.setEndOption(endOption);
+		repeatingTransaction_1.setRepeatingOption(repeatingOption_1);
+		repeatingTransaction_1.setTags(new ArrayList<>());
+		repeatingTransaction_1.setExpenditure(true);
+
+		BackupTransaction_v6 transferTransaction = new BackupTransaction_v6();
+		transferTransaction.setAmount(-250);
+		transferTransaction.setDate("2018-06-15");
+		transferTransaction.setName("Transfer");
+		transferTransaction.setDescription("");
+		transferTransaction.setAccountID(3);
+		transferTransaction.setTransferAccountID(2);
+		transferTransaction.setCategoryID(3);
+		transferTransaction.setTags(new ArrayList<>());
+		transferTransaction.setExpenditure(true);
+
+		assertThat(database.getTransactions()).hasSize(4)
+				.contains(normalTransaction_1,
+						normalTransaction_2,
+						repeatingTransaction_1,
+						transferTransaction);
+	}
+
+	@Test
+	void test_Icons() throws URISyntaxException, IOException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+		DatabaseParser_v7 parser = new DatabaseParser_v7(json);
+		BackupDatabase_v7 database = parser.parseDatabaseFromJSON();
+
+		assertThat(database.getIcons()).hasSize(2);
+		assertThat(database.getIcons().get(0).getImageID())
+				.isOne();
+		assertThat(database.getIcons().get(1).getBuiltinIdentifier())
+				.isEqualTo("fas fa-icons");
+	}
+}
\ No newline at end of file
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v6_convertToInternalTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v7_convertToInternalTest.java
similarity index 75%
rename from src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v6_convertToInternalTest.java
rename to src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v7_convertToInternalTest.java
index 4328d68b7f38408ffe39f66f06f41ef63d4d977e..f322b7938fa7e90e6bfe4bb19629578cdec9daed 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v6_convertToInternalTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseParser_v7_convertToInternalTest.java
@@ -5,9 +5,12 @@ import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.categories.Category;
 import de.deadlocker8.budgetmaster.categories.CategoryType;
 import de.deadlocker8.budgetmaster.charts.Chart;
+import de.deadlocker8.budgetmaster.charts.ChartDisplayType;
+import de.deadlocker8.budgetmaster.charts.ChartGroupType;
 import de.deadlocker8.budgetmaster.charts.ChartType;
-import de.deadlocker8.budgetmaster.database.DatabaseParser_v6;
+import de.deadlocker8.budgetmaster.database.DatabaseParser_v7;
 import de.deadlocker8.budgetmaster.database.InternalDatabase;
+import de.deadlocker8.budgetmaster.icon.Icon;
 import de.deadlocker8.budgetmaster.images.Image;
 import de.deadlocker8.budgetmaster.images.ImageFileExtension;
 import de.deadlocker8.budgetmaster.repeating.RepeatingOption;
@@ -20,8 +23,8 @@ import de.thecodelabs.utils.util.Localization;
 import de.thecodelabs.utils.util.Localization.LocalizationDelegate;
 import org.joda.time.DateTime;
 import org.joda.time.format.DateTimeFormat;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
@@ -34,9 +37,9 @@ import java.util.Locale;
 import static org.assertj.core.api.Assertions.assertThat;
 
 
-public class DatabaseParser_v6_convertToInternalTest
+class DatabaseParser_v7_convertToInternalTest
 {
-	@Before
+	@BeforeEach
 	public void before()
 	{
 		Localization.setDelegate(new LocalizationDelegate()
@@ -57,15 +60,15 @@ public class DatabaseParser_v6_convertToInternalTest
 	}
 
 	@Test
-	public void test_Charts()
+	void test_Charts()
 	{
 		try
 		{
-			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
-			DatabaseParser_v6 importer = new DatabaseParser_v6(json);
+			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+			DatabaseParser_v7 importer = new DatabaseParser_v7(json);
 			InternalDatabase database = importer.parseDatabaseFromJSON().convertToInternal();
 
-			final Chart chart = new Chart("The best chart", "/* This list will be dynamically filled with all the transactions between\r\n* the start and and date you select on the \"Show Chart\" page\r\n* and filtered according to your specified filter.\r\n* An example entry for this list and tutorial about how to create custom charts ca be found in the BudgetMaster wiki:\r\n* https://github.com/deadlocker8/BudgetMaster/wiki/How-to-create-custom-charts\r\n*/\r\nvar transactionData \u003d [];\r\n\r\n// Prepare your chart settings here (mandatory)\r\nvar plotlyData \u003d [{\r\n    x: [],\r\n    y: [],\r\n    type: \u0027bar\u0027\r\n}];\r\n\r\n// Add your Plotly layout settings here (optional)\r\nvar plotlyLayout \u003d {};\r\n\r\n// Add your Plotly configuration settings here (optional)\r\nvar plotlyConfig \u003d {\r\n    showSendToCloud: false,\r\n    displaylogo: false,\r\n    showLink: false,\r\n    responsive: true\r\n};\r\n\r\n// Don\u0027t touch this line\r\nPlotly.newPlot(\"containerID\", plotlyData, plotlyLayout, plotlyConfig);\r\n", ChartType.CUSTOM, 7);
+			final Chart chart = new Chart("The best chart", "/* This list will be dynamically filled with all the transactions between\r\n* the start and and date you select on the \"Show Chart\" page\r\n* and filtered according to your specified filter.\r\n* An example entry for this list and tutorial about how to create custom charts ca be found in the BudgetMaster wiki:\r\n* https://github.com/deadlocker8/BudgetMaster/wiki/How-to-create-custom-charts\r\n*/\r\nvar transactionData \u003d [];\r\n\r\n// Prepare your chart settings here (mandatory)\r\nvar plotlyData \u003d [{\r\n    x: [],\r\n    y: [],\r\n    type: \u0027bar\u0027\r\n}];\r\n\r\n// Add your Plotly layout settings here (optional)\r\nvar plotlyLayout \u003d {};\r\n\r\n// Add your Plotly configuration settings here (optional)\r\nvar plotlyConfig \u003d {\r\n    showSendToCloud: false,\r\n    displaylogo: false,\r\n    showLink: false,\r\n    responsive: true\r\n};\r\n\r\n// Don\u0027t touch this line\r\nPlotly.newPlot(\"containerID\", plotlyData, plotlyLayout, plotlyConfig);\r\n", ChartType.CUSTOM, 7, ChartDisplayType.CUSTOM, ChartGroupType.NONE, null);
 			chart.setID(9);
 
 			assertThat(database.getCharts()).hasSize(1)
@@ -78,15 +81,18 @@ public class DatabaseParser_v6_convertToInternalTest
 	}
 
 	@Test
-	public void test_Categories()
+	void test_Categories()
 	{
 		try
 		{
-			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
-			DatabaseParser_v6 importer = new DatabaseParser_v6(json);
+			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+			DatabaseParser_v7 importer = new DatabaseParser_v7(json);
 			InternalDatabase database = importer.parseDatabaseFromJSON().convertToInternal();
 
-			final Category category = new Category("0815", "#ffcc00", CategoryType.CUSTOM, "fas fa-icons");
+			final Icon icon = new Icon("fas fa-icons");
+			icon.setID(2);
+
+			final Category category = new Category("0815", "#ffcc00", CategoryType.CUSTOM, icon);
 			category.setID(3);
 
 			assertThat(database.getCategories()).hasSize(3)
@@ -99,22 +105,28 @@ public class DatabaseParser_v6_convertToInternalTest
 	}
 
 	@Test
-	public void test_Accounts()
+	void test_Accounts()
 	{
 		try
 		{
-			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
-			DatabaseParser_v6 importer = new DatabaseParser_v6(json);
+			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+			DatabaseParser_v7 importer = new DatabaseParser_v7(json);
 			InternalDatabase database = importer.parseDatabaseFromJSON().convertToInternal();
 
 			final Image accountImage = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
 			accountImage.setID(1);
-			final Account account = new Account("Second Account", AccountType.CUSTOM, accountImage);
+
+			final Icon icon = new Icon(accountImage);
+			icon.setID(1);
+
+			final Account account = new Account("Second Account", AccountType.CUSTOM, icon);
 			account.setID(3);
 
 			assertThat(database.getAccounts()).hasSize(3)
 					.contains(account);
-			assertThat(database.getAccounts().get(2).getIcon().getImage())
+			assertThat(database.getAccounts().get(2).getIconReference())
+					.isEqualTo(icon);
+			assertThat(database.getAccounts().get(2).getIconReference().getImage().getImage())
 					.isNotNull()
 					.hasSizeGreaterThan(1);
 		}
@@ -125,12 +137,12 @@ public class DatabaseParser_v6_convertToInternalTest
 	}
 
 	@Test
-	public void test_Images()
+	void test_Images()
 	{
 		try
 		{
-			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
-			DatabaseParser_v6 importer = new DatabaseParser_v6(json);
+			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+			DatabaseParser_v7 importer = new DatabaseParser_v7(json);
 			InternalDatabase database = importer.parseDatabaseFromJSON().convertToInternal();
 
 			final Image image = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
@@ -149,25 +161,31 @@ public class DatabaseParser_v6_convertToInternalTest
 	}
 
 	@Test
-	public void test_Templates()
+	void test_Templates()
 	{
 		try
 		{
-			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
-			DatabaseParser_v6 importer = new DatabaseParser_v6(json);
+			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+			DatabaseParser_v7 importer = new DatabaseParser_v7(json);
 			InternalDatabase database = importer.parseDatabaseFromJSON().convertToInternal();
 
 			final Image templateImage = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
 			templateImage.setID(1);
+
+			final Icon icon = new Icon(templateImage);
+			icon.setID(1);
+
 			final Template template = new Template();
 			template.setTemplateName("Template with icon");
 			template.setIsExpenditure(true);
-			template.setIcon(templateImage);
+			template.setIconReference(icon);
 			template.setTags(List.of());
 
 			assertThat(database.getTemplates()).hasSize(4)
 					.contains(template);
-			assertThat(database.getTemplates().get(3).getIcon().getImage())
+			assertThat(database.getTemplates().get(3).getIconReference())
+					.isEqualTo(icon);
+			assertThat(database.getTemplates().get(3).getIconReference().getImage().getImage())
 					.isNotNull()
 					.hasSizeGreaterThan(1);
 		}
@@ -178,12 +196,12 @@ public class DatabaseParser_v6_convertToInternalTest
 	}
 
 	@Test
-	public void test_Transactions()
+	void test_Transactions()
 	{
 		try
 		{
-			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v6Test.json").toURI())));
-			DatabaseParser_v6 importer = new DatabaseParser_v6(json);
+			String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+			DatabaseParser_v7 importer = new DatabaseParser_v7(json);
 			InternalDatabase database = importer.parseDatabaseFromJSON().convertToInternal();
 
 			Account account1 = new Account("Default", AccountType.CUSTOM);
@@ -192,15 +210,21 @@ public class DatabaseParser_v6_convertToInternalTest
 			Image image = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
 			image.setID(1);
 
+			Icon accountIcon = new Icon(image);
+			accountIcon.setID(1);
+
 			Account account2 = new Account("Second Account", AccountType.CUSTOM);
-			account2.setIcon(image);
+			account2.setIconReference(accountIcon);
 			account2.setID(3);
 
 			Category categoryNone = new Category("Keine Kategorie", "#FFFFFF", CategoryType.NONE);
 			categoryNone.setID(1);
 
+			Icon categoryIcon = new Icon("fas fa-icons");
+			categoryIcon.setID(2);
+
 			Category category3 = new Category("0815", "#ffcc00", CategoryType.CUSTOM);
-			category3.setIcon("fas fa-icons");
+			category3.setIconReference(categoryIcon);
 			category3.setID(3);
 
 			Transaction normalTransaction_1 = new Transaction();
@@ -248,7 +272,7 @@ public class DatabaseParser_v6_convertToInternalTest
 			repeatingTransaction_1.setTags(new ArrayList<>());
 			repeatingTransaction_1.setIsExpenditure(true);
 
-		    Transaction transferTransaction = new Transaction();
+			Transaction transferTransaction = new Transaction();
 			transferTransaction.setAmount(-250);
 			DateTime transferTransactionDate = DateTime.parse("2018-06-15", DateTimeFormat.forPattern("yyyy-MM-dd"));
 			transferTransactionDate = transferTransactionDate.withHourOfDay(12).withMinuteOfHour(0).withSecondOfMinute(0);
@@ -273,4 +297,27 @@ public class DatabaseParser_v6_convertToInternalTest
 			e.printStackTrace();
 		}
 	}
+
+	@Test
+	void test_Icons() throws IOException, URISyntaxException
+	{
+		String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("DatabaseParser_v7Test.json").toURI())));
+		DatabaseParser_v7 importer = new DatabaseParser_v7(json);
+		InternalDatabase database = importer.parseDatabaseFromJSON().convertToInternal();
+
+		final Image image = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
+		image.setID(1);
+
+		final Icon icon1 = new Icon(image);
+		icon1.setID(1);
+
+		final Icon icon2 = new Icon("fas fa-icons");
+		icon2.setID(2);
+
+		assertThat(database.getIcons()).hasSize(2)
+				.containsExactly(icon1, icon2);
+		assertThat(database.getImages().get(0).getImage())
+				.isNotNull()
+				.hasSizeGreaterThan(1);
+	}
 }
\ No newline at end of file
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseServiceTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseServiceTest.java
index 869248796ebd33a021709ba7227ee89e219b6a7d..9a6b6bf620a9730a38224b1cca96b1e8bccfe78f 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseServiceTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/database/DatabaseServiceTest.java
@@ -12,11 +12,11 @@ import de.deadlocker8.budgetmaster.tags.TagService;
 import de.deadlocker8.budgetmaster.transactions.TransactionService;
 import de.deadlocker8.budgetmaster.unit.helpers.LoggerTestUtil;
 import org.assertj.core.groups.Tuple;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.net.URISyntaxException;
 import java.nio.file.Path;
@@ -27,8 +27,8 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.when;
 
 
-@RunWith(SpringJUnit4ClassRunner.class)
-public class DatabaseServiceTest
+@ExtendWith(SpringExtension.class)
+class DatabaseServiceTest
 {
 	@Mock
 	private AccountService accountService;
@@ -49,7 +49,7 @@ public class DatabaseServiceTest
 	private DatabaseService databaseService;
 
 	@Test
-	public void test_determineFilesToDelete_unlimited() throws URISyntaxException
+	void test_determineFilesToDelete_unlimited() throws URISyntaxException
 	{
 		ListAppender<ILoggingEvent> loggingAppender = LoggerTestUtil.getListAppenderForClass(DatabaseService.class);
 
@@ -68,7 +68,7 @@ public class DatabaseServiceTest
 	}
 
 	@Test
-	public void test_determineFilesToDelete_limitNotReached() throws URISyntaxException
+	void test_determineFilesToDelete_limitNotReached() throws URISyntaxException
 	{
 		ListAppender<ILoggingEvent> loggingAppender = LoggerTestUtil.getListAppenderForClass(DatabaseService.class);
 
@@ -87,7 +87,7 @@ public class DatabaseServiceTest
 	}
 
 	@Test
-	public void test_determineFilesToDelete_limitReachedExactly() throws URISyntaxException
+	void test_determineFilesToDelete_limitReachedExactly() throws URISyntaxException
 	{
 		ListAppender<ILoggingEvent> loggingAppender = LoggerTestUtil.getListAppenderForClass(DatabaseService.class);
 
@@ -109,7 +109,7 @@ public class DatabaseServiceTest
 	}
 
 	@Test
-	public void test_determineFilesToDelete_limitReached() throws URISyntaxException
+	void test_determineFilesToDelete_limitReached() throws URISyntaxException
 	{
 		ListAppender<ILoggingEvent> loggingAppender = LoggerTestUtil.getListAppenderForClass(DatabaseService.class);
 
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/database/ImportServiceTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/database/ImportServiceTest.java
index 287d7d00561f36a8f1b8458ac7068fe3b05bbcbb..769a074037758e7f6987fd37c8b5f04381f6b82e 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/database/ImportServiceTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/database/ImportServiceTest.java
@@ -1,6 +1,7 @@
 package de.deadlocker8.budgetmaster.unit.database;
 
 import de.deadlocker8.budgetmaster.accounts.Account;
+import de.deadlocker8.budgetmaster.accounts.AccountRepository;
 import de.deadlocker8.budgetmaster.accounts.AccountType;
 import de.deadlocker8.budgetmaster.categories.Category;
 import de.deadlocker8.budgetmaster.categories.CategoryRepository;
@@ -12,6 +13,10 @@ import de.deadlocker8.budgetmaster.charts.ChartType;
 import de.deadlocker8.budgetmaster.database.InternalDatabase;
 import de.deadlocker8.budgetmaster.database.accountmatches.AccountMatch;
 import de.deadlocker8.budgetmaster.database.accountmatches.AccountMatchList;
+import de.deadlocker8.budgetmaster.icon.Icon;
+import de.deadlocker8.budgetmaster.icon.IconRepository;
+import de.deadlocker8.budgetmaster.icon.IconService;
+import de.deadlocker8.budgetmaster.icon.Iconizable;
 import de.deadlocker8.budgetmaster.images.Image;
 import de.deadlocker8.budgetmaster.images.ImageFileExtension;
 import de.deadlocker8.budgetmaster.images.ImageRepository;
@@ -28,20 +33,21 @@ import de.deadlocker8.budgetmaster.transactions.Transaction;
 import de.deadlocker8.budgetmaster.transactions.TransactionBase;
 import de.deadlocker8.budgetmaster.transactions.TransactionRepository;
 import org.joda.time.DateTime;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-@RunWith(SpringJUnit4ClassRunner.class)
-public class ImportServiceTest
+@ExtendWith(SpringExtension.class)
+class ImportServiceTest
 {
 	@Mock
 	private CategoryRepository categoryRepository;
@@ -64,11 +70,17 @@ public class ImportServiceTest
 	@Mock
 	private RepeatingTransactionUpdater repeatingTransactionUpdater;
 
+	@Mock
+	private AccountRepository accountRepository;
+
+	@Mock
+	private IconService iconService;
+
 	@InjectMocks
 	private ImportService importService;
 
 	@Test
-	public void test_updateCategoriesForTransactions()
+	void test_updateCategoriesForTransactions()
 	{
 		Category category1 = new Category("Category1", "#ff0000", CategoryType.CUSTOM);
 		category1.setID(3);
@@ -97,7 +109,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_updateCategoriesForTemplates()
+	void test_updateCategoriesForTemplates()
 	{
 		Category category1 = new Category("Category1", "#ff0000", CategoryType.CUSTOM);
 		category1.setID(3);
@@ -129,7 +141,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_removeAlreadyUpdatedTransactions()
+	void test_removeAlreadyUpdatedTransactions()
 	{
 		Category category1 = new Category("Category1", "#ff0000", CategoryType.CUSTOM);
 		category1.setID(3);
@@ -165,7 +177,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_updateAccountsForTransactions()
+	void test_updateAccountsForTransactions()
 	{
 		Account account1 = new Account("Account_1", AccountType.CUSTOM);
 		account1.setID(2);
@@ -196,7 +208,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_updateTransferAccountsForTransactions()
+	void test_updateTransferAccountsForTransactions()
 	{
 		Account account1 = new Account("Account_1", AccountType.CUSTOM);
 		account1.setID(2);
@@ -229,7 +241,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_updateAccountsForTemplates()
+	void test_updateAccountsForTemplates()
 	{
 		Account account1 = new Account("Account_1", AccountType.CUSTOM);
 		account1.setID(2);
@@ -263,7 +275,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_updateTransferAccountsForTemplates()
+	void test_updateTransferAccountsForTemplates()
 	{
 		Account account1 = new Account("Account_1", AccountType.CUSTOM);
 		account1.setID(2);
@@ -298,7 +310,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_updateTagsForItem_ExistingTag()
+	void test_updateTagsForItem_ExistingTag()
 	{
 		Account account1 = new Account("Account_1", AccountType.CUSTOM);
 		account1.setID(2);
@@ -325,7 +337,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_updateTagsForItem_NewTag()
+	void test_updateTagsForItem_NewTag()
 	{
 		Account account1 = new Account("Account_1", AccountType.CUSTOM);
 		account1.setID(2);
@@ -355,7 +367,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_importFullDatabase()
+	void test_importFullDatabase()
 	{
 		// source accounts
 		Account sourceAccount1 = new Account("Source_Account_1", AccountType.CUSTOM);
@@ -406,6 +418,10 @@ public class ImportServiceTest
 		tags2.add(tag1);
 		template1.setTags(tags2);
 
+		Icon icon1 = new Icon("fas fa-icons");
+		icon1.setID(12);
+		template1.setIconReference(icon1);
+
 		Template template2 = new Template();
 		template2.setTemplateName("MyTemplate2");
 		template2.setTransferAccount(sourceAccount2);
@@ -424,7 +440,7 @@ public class ImportServiceTest
 		chart.setScript("/* This list will be dynamically filled with all the transactions between\r\n* the start and and date you select on the \"Show Chart\" page\r\n* and filtered according to your specified filter.\r\n* An example entry for this list and tutorial about how to create custom charts ca be found in the BudgetMaster wiki:\r\n* https://github.com/deadlocker8/BudgetMaster/wiki/How-to-create-custom-charts\r\n*/\r\nvar transactionData \u003d [];\r\n\r\n// Prepare your chart settings here (mandatory)\r\nvar plotlyData \u003d [{\r\n    x: [],\r\n    y: [],\r\n    type: \u0027bar\u0027\r\n}];\r\n\r\n// Add your Plotly layout settings here (optional)\r\nvar plotlyLayout \u003d {};\r\n\r\n// Add your Plotly configuration settings here (optional)\r\nvar plotlyConfig \u003d {\r\n    showSendToCloud: false,\r\n    displaylogo: false,\r\n    showLink: false,\r\n    responsive: true\r\n};\r\n\r\n// Don\u0027t touch this line\r\nPlotly.newPlot(\"containerID\", plotlyData, plotlyLayout, plotlyConfig);\r\n");
 
 		// database
-		InternalDatabase database = new InternalDatabase(new ArrayList<>(), accounts, transactions, templates, List.of(chart), List.of());
+		InternalDatabase database = new InternalDatabase(new ArrayList<>(), accounts, transactions, templates, List.of(chart), List.of(), List.of(icon1));
 
 		// account matches
 		AccountMatch match1 = new AccountMatch(sourceAccount1);
@@ -463,6 +479,10 @@ public class ImportServiceTest
 		expectedTemplateTags.add(tag1);
 		expectedTemplate1.setTags(expectedTemplateTags);
 
+		Icon expectedIcon = new Icon("fas fa-icons");
+		expectedIcon.setID(28);
+		expectedTemplate1.setIconReference(expectedIcon);
+
 		Template expectedTemplate2 = new Template();
 		expectedTemplate2.setTemplateName("MyTemplate2");
 		expectedTemplate2.setTransferAccount(destAccount2);
@@ -475,6 +495,13 @@ public class ImportServiceTest
 		final ChartRepository chartRepositoryMock = Mockito.mock(ChartRepository.class);
 		Mockito.when(chartService.getRepository()).thenReturn(chartRepositoryMock);
 
+		Mockito.when(accountRepository.findById(5)).thenReturn(Optional.of(destAccount1));
+		Mockito.when(accountRepository.findById(2)).thenReturn(Optional.of(destAccount2));
+
+		IconRepository iconRepositoryMock = Mockito.mock(IconRepository.class);
+		Mockito.when(iconService.getRepository()).thenReturn(iconRepositoryMock);
+		Mockito.when(iconRepositoryMock.save(Mockito.any())).thenReturn(expectedIcon);
+
 		importService.importDatabase(database, accountMatchList, true, true);
 		InternalDatabase databaseResult = importService.getDatabase();
 
@@ -492,7 +519,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_chartId()
+	void test_chartId()
 	{
 		Chart chart = new Chart();
 		chart.setID(9);
@@ -502,7 +529,7 @@ public class ImportServiceTest
 		chart.setScript("/* This list will be dynamically filled with all the transactions between\r\n* the start and and date you select on the \"Show Chart\" page\r\n* and filtered according to your specified filter.\r\n* An example entry for this list and tutorial about how to create custom charts ca be found in the BudgetMaster wiki:\r\n* https://github.com/deadlocker8/BudgetMaster/wiki/How-to-create-custom-charts\r\n*/\r\nvar transactionData \u003d [];\r\n\r\n// Prepare your chart settings here (mandatory)\r\nvar plotlyData \u003d [{\r\n    x: [],\r\n    y: [],\r\n    type: \u0027bar\u0027\r\n}];\r\n\r\n// Add your Plotly layout settings here (optional)\r\nvar plotlyLayout \u003d {};\r\n\r\n// Add your Plotly configuration settings here (optional)\r\nvar plotlyConfig \u003d {\r\n    showSendToCloud: false,\r\n    displaylogo: false,\r\n    showLink: false,\r\n    responsive: true\r\n};\r\n\r\n// Don\u0027t touch this line\r\nPlotly.newPlot(\"containerID\", plotlyData, plotlyLayout, plotlyConfig);\r\n");
 
 		// database
-		InternalDatabase database = new InternalDatabase(List.of(), List.of(), List.of(), List.of(), List.of(chart), List.of());
+		InternalDatabase database = new InternalDatabase(List.of(), List.of(), List.of(), List.of(), List.of(chart), List.of(), List.of());
 
 		// act
 		int highestUsedID = 22;
@@ -519,7 +546,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_updateImagesForAccounts()
+	void test_updateImagesForIcons()
 	{
 		Image image1 = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
 		image1.setID(3);
@@ -527,20 +554,20 @@ public class ImportServiceTest
 		Image image2 = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.JPG);
 		image2.setID(4);
 
-		Account account1 = new Account("Account_1", AccountType.CUSTOM, image1);
-		Account account2 = new Account("Account_2", AccountType.CUSTOM, image2);
+		Icon icon1 = new Icon(image1);
+		Icon icon2 = new Icon(image2);
 
-		final List<Account> accountList = List.of(account1, account2);
+		final List<Icon> iconList = List.of(icon1, icon2);
 
-		List<Account> updatedAccounts = importService.updateImagesForAccounts(accountList, 3, 5);
-		assertThat(updatedAccounts).hasSize(1);
-		final Image icon = updatedAccounts.get(0).getIcon();
+		List<Icon> updatedIcons = importService.updateImagesForIcons(iconList, 3, 5);
+		assertThat(updatedIcons).hasSize(1);
+		final Image icon = updatedIcons.get(0).getImage();
 		assertThat(icon.getBase64EncodedImage()).isEqualTo("data:image/png;base64,");
 		assertThat(icon.getID()).isEqualTo(5);
 	}
 
 	@Test
-	public void test_importImages_notExisting()
+	void test_importImages_notExisting()
 	{
 		Image image = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
 		image.setID(3);
@@ -552,7 +579,7 @@ public class ImportServiceTest
 		Mockito.when(imageService.getRepository()).thenReturn(imageRepositoryMock);
 		Mockito.when(imageRepositoryMock.save(Mockito.any())).thenReturn(newImage);
 
-		InternalDatabase database = new InternalDatabase(List.of(), List.of(), List.of(), List.of(), List.of(), List.of(image));
+		InternalDatabase database = new InternalDatabase(List.of(), List.of(), List.of(), List.of(), List.of(), List.of(image), List.of());
 		importService.importDatabase(database, new AccountMatchList(List.of()), true, true);
 
 		Image expectedImage = new Image(image.getImage(), image.getFileName(), image.getFileExtension());
@@ -560,7 +587,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_importImages_alreadyExisting()
+	void test_importImages_alreadyExisting()
 	{
 		Image image = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
 		image.setID(3);
@@ -572,7 +599,7 @@ public class ImportServiceTest
 		Mockito.when(imageService.getRepository()).thenReturn(imageRepositoryMock);
 		Mockito.when(imageRepositoryMock.save(Mockito.any())).thenReturn(newImage);
 
-		InternalDatabase database = new InternalDatabase(List.of(), List.of(), List.of(), List.of(), List.of(), List.of(image));
+		InternalDatabase database = new InternalDatabase(List.of(), List.of(), List.of(), List.of(), List.of(), List.of(image), List.of());
 		importService.importDatabase(database, new AccountMatchList(List.of()), true, true);
 
 		Image expectedImage = new Image(image.getImage(), image.getFileName(), image.getFileExtension());
@@ -580,37 +607,45 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_updateImagesForTemplates()
+	void test_importAccounts_icon()
 	{
-		Image image1 = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
-		image1.setID(3);
+		Image image = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
+		image.setID(3);
+		Icon icon = new Icon(image);
+		icon.setID(15);
 
-		Image image2 = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.JPG);
-		image2.setID(4);
+		Account accountSource = new Account("my account with icon", AccountType.CUSTOM, icon);
+		accountSource.setID(1);
+		Account accountDestination = new Account("destination", AccountType.CUSTOM);
+		accountDestination.setID(15);
 
-		Template template1 = new Template();
-		template1.setTemplateName("Template with icon 1");
-		template1.setIsExpenditure(true);
-		template1.setIcon(image1);
-		template1.setTags(List.of());
+		InternalDatabase database = new InternalDatabase(List.of(), List.of(accountSource), List.of(), List.of(), List.of(), List.of(image), List.of(icon));
+		AccountMatch accountMatch = new AccountMatch(accountSource);
+		accountMatch.setAccountDestination(accountDestination);
 
-		Template template2 = new Template();
-		template2.setTemplateName("Template with icon 2");
-		template2.setIsExpenditure(true);
-		template2.setIcon(image2);
-		template2.setTags(List.of());
+		Icon expectedIcon = new Icon(image);
+		expectedIcon.setID(1);
 
-		final List<Template> templateList = List.of(template1, template2);
+		Account expectedAccount = new Account("destination", AccountType.CUSTOM, expectedIcon);
+		expectedAccount.setID(15);
+		Mockito.when(accountRepository.save(Mockito.any())).thenReturn(expectedAccount);
+		Mockito.when(accountRepository.findById(15)).thenReturn(Optional.of(accountDestination));
 
-		List<Template> updatedTemplates = importService.updateImagesForTemplates(templateList, 3, 5);
-		assertThat(updatedTemplates).hasSize(1);
-		final Image icon = updatedTemplates.get(0).getIcon();
-		assertThat(icon.getBase64EncodedImage()).isEqualTo("data:image/png;base64,");
-		assertThat(icon.getID()).isEqualTo(5);
+		ImageRepository imageRepositoryMock = Mockito.mock(ImageRepository.class);
+		Mockito.when(imageService.getRepository()).thenReturn(imageRepositoryMock);
+		Mockito.when(imageRepositoryMock.save(Mockito.any())).thenReturn(image);
+
+		IconRepository iconRepositoryMock = Mockito.mock(IconRepository.class);
+		Mockito.when(iconService.getRepository()).thenReturn(iconRepositoryMock);
+		Mockito.when(iconRepositoryMock.save(Mockito.any())).thenReturn(expectedIcon);
+
+		importService.importDatabase(database, new AccountMatchList(List.of(accountMatch)), true, true);
+
+		Mockito.verify(accountRepository, Mockito.atLeast(1)).save(expectedAccount);
 	}
 
 	@Test
-	public void test_skipTemplates()
+	void test_skipTemplates()
 	{
 		Template template = new Template();
 		template.setTemplateName("myTemplate");
@@ -619,7 +654,7 @@ public class ImportServiceTest
 		template.setTags(new ArrayList<>());
 
 		// database
-		InternalDatabase database = new InternalDatabase(List.of(), List.of(), List.of(), List.of(template), List.of(), List.of());
+		InternalDatabase database = new InternalDatabase(List.of(), List.of(), List.of(), List.of(template), List.of(), List.of(), List.of());
 
 		// act
 		importService.importDatabase(database, new AccountMatchList(List.of()), false, true);
@@ -629,7 +664,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_skipCarts()
+	void test_skipCarts()
 	{
 		Chart chart = new Chart();
 		chart.setID(9);
@@ -638,7 +673,7 @@ public class ImportServiceTest
 		chart.setVersion(7);
 
 		// database
-		InternalDatabase database = new InternalDatabase(List.of(), List.of(), List.of(), List.of(), List.of(chart), List.of());
+		InternalDatabase database = new InternalDatabase(List.of(), List.of(), List.of(), List.of(), List.of(chart), List.of(), List.of());
 
 		Mockito.when(chartService.getHighestUsedID()).thenReturn(8);
 		final ChartRepository chartRepositoryMock = Mockito.mock(ChartRepository.class);
@@ -652,7 +687,7 @@ public class ImportServiceTest
 	}
 
 	@Test
-	public void test_errorWhileImportingCategory_shouldBeCollected()
+	void test_errorWhileImportingCategory_shouldBeCollected()
 	{
 		Category category1 = new Category("Category1", "#ff0000", CategoryType.CUSTOM);
 		category1.setID(3);
@@ -664,7 +699,7 @@ public class ImportServiceTest
 		Mockito.when(categoryRepository.findByNameAndColorAndType(Mockito.eq("Category1"), Mockito.any(), Mockito.any())).thenThrow(new NullPointerException());
 		Mockito.when(categoryRepository.findByNameAndColorAndType(Mockito.eq("Category2"), Mockito.any(), Mockito.any())).thenReturn(category2);
 
-		InternalDatabase database = new InternalDatabase(List.of(category1, category2), List.of(), List.of(), List.of(), List.of(), List.of());
+		InternalDatabase database = new InternalDatabase(List.of(category1, category2), List.of(), List.of(), List.of(), List.of(), List.of(), List.of());
 		final List<ImportResultItem> importResultItems = importService.importDatabase(database, new AccountMatchList(List.of()), false, false);
 
 		assertThat(importResultItems).hasSize(6)
@@ -672,4 +707,35 @@ public class ImportServiceTest
 		assertThat(importService.getCollectedErrorMessages()).hasSize(1)
 				.contains("Error while importing category with name \"Category1\": java.lang.NullPointerException (null)");
 	}
+
+	@Test
+	void test_updateIconsForAccounts()
+	{
+		Image image1 = new Image(new Byte[0], "awesomeIcon.png", ImageFileExtension.PNG);
+		image1.setID(3);
+
+		Icon icon1 = new Icon(image1);
+		icon1.setID(3);
+
+		Icon icon2 = new Icon("fas fa-icons");
+		icon2.setID(4);
+
+		Account account1 = new Account("account with image icon", AccountType.CUSTOM, icon1);
+		Account account2 = new Account("account with built-in icon", AccountType.CUSTOM, icon2);
+		List<Account> accounts = List.of(account1, account2);
+
+		List<Iconizable> updatedAccounts = importService.updateIconsForItems(accounts, 3, 5);
+		assertThat(updatedAccounts).hasSize(1);
+		assertThat(updatedAccounts.get(0).getIconReference())
+				.hasFieldOrPropertyWithValue("ID", 5)
+				.hasFieldOrPropertyWithValue("image", image1)
+				.hasFieldOrPropertyWithValue("builtinIdentifier", null);
+
+		updatedAccounts = importService.updateIconsForItems(accounts, 4, 6);
+		assertThat(updatedAccounts).hasSize(1);
+		assertThat(updatedAccounts.get(0).getIconReference())
+				.hasFieldOrPropertyWithValue("ID", 6)
+				.hasFieldOrPropertyWithValue("image", null)
+				.hasFieldOrPropertyWithValue("builtinIdentifier", "fas fa-icons");
+	}
 }
\ No newline at end of file
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/helpers/LocalizationHelpers.java b/src/test/java/de/deadlocker8/budgetmaster/unit/helpers/LocalizationHelpers.java
index a78dbae012c00befff7a45a74ec0dcf2527ac595..8a6e46f5130d81785541f2697046c76c6b2652e7 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/helpers/LocalizationHelpers.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/helpers/LocalizationHelpers.java
@@ -24,7 +24,7 @@ public class LocalizationHelpers extends AbstractTestExecutionListener
 			@Override
 			public String[] getBaseResources()
 			{
-				return new String[]{"languages/base", "languages/news"};
+				return new String[]{"languages/base", "languages/news", "languages/hints"};
 			}
 
 			@Override
diff --git a/src/test/java/de/deadlocker8/budgetmaster/unit/repeating/RepeatingOptionTest.java b/src/test/java/de/deadlocker8/budgetmaster/unit/repeating/RepeatingOptionTest.java
index 5513c067b71363c6449977956d7e8e52a31cf95f..f44b7e850eed3f2087f2b9aaf5f0161b672058e3 100644
--- a/src/test/java/de/deadlocker8/budgetmaster/unit/repeating/RepeatingOptionTest.java
+++ b/src/test/java/de/deadlocker8/budgetmaster/unit/repeating/RepeatingOptionTest.java
@@ -8,19 +8,20 @@ import de.deadlocker8.budgetmaster.repeating.modifier.RepeatingModifierDays;
 import de.deadlocker8.budgetmaster.repeating.modifier.RepeatingModifierMonths;
 import de.deadlocker8.budgetmaster.repeating.modifier.RepeatingModifierYears;
 import org.joda.time.DateTime;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import static org.junit.Assert.*;
+import static org.assertj.core.api.Assertions.assertThat;
 
-public class RepeatingOptionTest
+
+class RepeatingOptionTest
 {
 	// test repeating every X days
 
 	@Test
-	public void test_GetRepeatingDates_Every3Days_EndAfter3Times()
+	void test_GetRepeatingDates_Every3Days_EndAfter3Times()
 	{
 		DateTime startDate = new DateTime(2018, 4, 22, 12, 0);
 		RepeatingOption repeatingOption = new RepeatingOption(startDate,
@@ -35,11 +36,12 @@ public class RepeatingOptionTest
 		expected.add(new DateTime(2018, 4, 28, 12, 0));
 		expected.add(new DateTime(2018, 5, 1, 12, 0));
 
-		assertEquals(expected, repeatingOption.getRepeatingDates(dateFetchLimit));
+		assertThat(repeatingOption.getRepeatingDates(dateFetchLimit))
+				.isEqualTo(expected);
 	}
 
 	@Test
-	public void test_GetRepeatingDates_Every3Days_EndAfterDate()
+	void test_GetRepeatingDates_Every3Days_EndAfterDate()
 	{
 		DateTime startDate = new DateTime(2018, 4, 22, 12, 0);
 		DateTime endDate = new DateTime(2018, 4, 28, 12, 0);
@@ -54,11 +56,12 @@ public class RepeatingOptionTest
 		expected.add(new DateTime(2018, 4, 25, 12, 0));
 		expected.add(new DateTime(2018, 4, 28, 12, 0));
 
-		assertEquals(expected, repeatingOption.getRepeatingDates(dateFetchLimit));
+		assertThat(repeatingOption.getRepeatingDates(dateFetchLimit))
+				.isEqualTo(expected);
 	}
 
 	@Test
-	public void test_GetRepeatingDates_Every3Days_EndNever()
+	void test_GetRepeatingDates_Every3Days_EndNever()
 	{
 		DateTime startDate = new DateTime(2018, 4, 22, 12, 0);
 		RepeatingOption repeatingOption = new RepeatingOption(startDate,
@@ -73,13 +76,14 @@ public class RepeatingOptionTest
 		expected.add(new DateTime(2018, 4, 28, 12, 0));
 		expected.add(new DateTime(2018, 5, 1, 12, 0));
 
-		assertEquals(expected, repeatingOption.getRepeatingDates(dateFetchLimit));
+		assertThat(repeatingOption.getRepeatingDates(dateFetchLimit))
+				.isEqualTo(expected);
 	}
 
 	// test repeating every X months
 
 	@Test
-	public void test_GetRepeatingDates_Every2Month_EndAfter5Times()
+	void test_GetRepeatingDates_Every2Month_EndAfter5Times()
 	{
 		DateTime startDate = new DateTime(2018, 4, 30, 12, 0);
 		RepeatingOption repeatingOption = new RepeatingOption(startDate,
@@ -96,11 +100,12 @@ public class RepeatingOptionTest
 		expected.add(new DateTime(2018, 12, 30, 12, 0));
 		expected.add(new DateTime(2019, 2, 28, 12, 0));
 
-		assertEquals(expected, repeatingOption.getRepeatingDates(dateFetchLimit));
+		assertThat(repeatingOption.getRepeatingDates(dateFetchLimit))
+				.isEqualTo(expected);
 	}
 
 	@Test
-	public void test_GetRepeatingDates_Every2Month_EndAfterDate()
+	void test_GetRepeatingDates_Every2Month_EndAfterDate()
 	{
 		DateTime startDate = new DateTime(2018, 4, 30, 12, 0);
 		DateTime endDate = new DateTime(2018, 9, 28, 12, 0);
@@ -115,11 +120,12 @@ public class RepeatingOptionTest
 		expected.add(new DateTime(2018, 6, 30, 12, 0));
 		expected.add(new DateTime(2018, 8, 30, 12, 0));
 
-		assertEquals(expected, repeatingOption.getRepeatingDates(dateFetchLimit));
+		assertThat(repeatingOption.getRepeatingDates(dateFetchLimit))
+				.isEqualTo(expected);
 	}
 
 	@Test
-	public void test_GetRepeatingDates_Every2Month_EndNever()
+	void test_GetRepeatingDates_Every2Month_EndNever()
 	{
 		DateTime startDate = new DateTime(2018, 4, 30, 12, 0);
 		RepeatingOption repeatingOption = new RepeatingOption(startDate,
@@ -133,13 +139,14 @@ public class RepeatingOptionTest
 		expected.add(new DateTime(2018, 6, 30, 12, 0));
 		expected.add(new DateTime(2018, 8, 30, 12, 0));
 
-		assertEquals(expected, repeatingOption.getRepeatingDates(dateFetchLimit));
+		assertThat(repeatingOption.getRepeatingDates(dateFetchLimit))
+				.isEqualTo(expected);
 	}
 
 	// test repeating every X years
 
 	@Test
-	public void test_GetRepeatingDates_EveryYear_EndAfter2Times()
+	void test_GetRepeatingDates_EveryYear_EndAfter2Times()
 	{
 		DateTime startDate = new DateTime(2018, 4, 30, 12, 0);
 		RepeatingOption repeatingOption = new RepeatingOption(startDate,
@@ -153,11 +160,12 @@ public class RepeatingOptionTest
 		expected.add(new DateTime(2019, 4, 30, 12, 0));
 		expected.add(new DateTime(2020, 4, 30, 12, 0));
 
-		assertEquals(expected, repeatingOption.getRepeatingDates(dateFetchLimit));
+		assertThat(repeatingOption.getRepeatingDates(dateFetchLimit))
+				.isEqualTo(expected);
 	}
 
 	@Test
-	public void test_GetRepeatingDates_EveryYear_EndAfterDate()
+	void test_GetRepeatingDates_EveryYear_EndAfterDate()
 	{
 		DateTime startDate = new DateTime(2018, 4, 30, 12, 0);
 		DateTime endDate = new DateTime(2019, 9, 28, 12, 0);
@@ -171,11 +179,12 @@ public class RepeatingOptionTest
 		expected.add(startDate);
 		expected.add(new DateTime(2019, 4, 30, 12, 0));
 
-		assertEquals(expected, repeatingOption.getRepeatingDates(dateFetchLimit));
+		assertThat(repeatingOption.getRepeatingDates(dateFetchLimit))
+				.isEqualTo(expected);
 	}
 
 	@Test
-	public void test_GetRepeatingDates_EveryYear_EndNever()
+	void test_GetRepeatingDates_EveryYear_EndNever()
 	{
 		DateTime startDate = new DateTime(2018, 4, 30, 12, 0);
 		RepeatingOption repeatingOption = new RepeatingOption(startDate,
@@ -188,6 +197,7 @@ public class RepeatingOptionTest
 		expected.add(startDate);
 		expected.add(new DateTime(2019, 4, 30, 12, 0));
 
-		assertEquals(expected, repeatingOption.getRepeatingDates(dateFetchLimit));
+		assertThat(repeatingOption.getRepeatingDates(dateFetchLimit))
+				.isEqualTo(expected);
 	}
 }
\ No newline at end of file
diff --git a/src/test/resources/DatabaseParser_v6Test.json b/src/test/resources/DatabaseParser_v6Test.json
index fe9c3bae8ddc33de4e583074b57509147a4da2d1..5a60e183bb7b3bf9dad5bbd2f768feb63f6ae132 100644
--- a/src/test/resources/DatabaseParser_v6Test.json
+++ b/src/test/resources/DatabaseParser_v6Test.json
@@ -41,6 +41,13 @@
             "accountState": "FULL_ACCESS",
             "type": "CUSTOM",
             "iconID": 1
+        },
+        {
+            "ID": 4,
+            "name": "Third Account",
+            "accountState": "FULL_ACCESS",
+            "type": "CUSTOM",
+            "iconID": 1
         }
     ],
     "transactions": [
diff --git a/src/test/resources/DatabaseParser_v7Test.json b/src/test/resources/DatabaseParser_v7Test.json
new file mode 100644
index 0000000000000000000000000000000000000000..679008d018df744a36497bd7b512ee945a2f3718
--- /dev/null
+++ b/src/test/resources/DatabaseParser_v7Test.json
@@ -0,0 +1,3298 @@
+{
+    "TYPE": "BUDGETMASTER_DATABASE",
+    "VERSION": 6,
+    "categories": [
+        {
+            "ID": 1,
+            "name": "Keine Kategorie",
+            "color": "#FFFFFF",
+            "type": "NONE"
+        },
+        {
+            "ID": 2,
+            "name": "Übertrag",
+            "color": "#FFFF00",
+            "type": "REST"
+        },
+        {
+            "ID": 3,
+            "name": "0815",
+            "color": "#ffcc00",
+            "type": "CUSTOM",
+            "iconReferenceID": 2
+        }
+    ],
+    "accounts": [
+        {
+            "ID": 1,
+            "name": "Placeholder",
+            "accountState": "FULL_ACCESS",
+            "type": "ALL"
+        },
+        {
+            "ID": 2,
+            "name": "Default",
+            "accountState": "FULL_ACCESS",
+            "type": "CUSTOM"
+        },
+        {
+            "ID": 3,
+            "name": "Second Account",
+            "accountState": "FULL_ACCESS",
+            "type": "CUSTOM",
+            "iconReferenceID": 1
+        }
+    ],
+    "transactions": [
+        {
+            "ID": 5,
+            "amount": 35000,
+            "isExpenditure": false,
+            "date": "2018-03-13",
+            "accountID": 2,
+            "categoryID": 1,
+            "name": "Income",
+            "description": "Lorem Ipsum",
+            "tags": []
+        },
+        {
+            "ID": 12,
+            "amount": -2000,
+            "isExpenditure": true,
+            "date": "2018-06-15",
+            "accountID": 3,
+            "categoryID": 3,
+            "name": "Simple",
+            "description": "",
+            "tags": [
+                {
+                    "ID": 1,
+                    "name": "0815"
+                }
+            ]
+        },
+        {
+            "ID": 13,
+            "amount": -12300,
+            "isExpenditure": true,
+            "date": "2018-03-13",
+            "accountID": 2,
+            "categoryID": 1,
+            "name": "Test",
+            "description": "",
+            "tags": [],
+            "repeatingOption": {
+                "ID": 2,
+                "startDate": "2018-03-13",
+                "modifier": {
+                    "ID": 3,
+                    "quantity": 10,
+                    "localizationKey": "repeating.modifier.days"
+                },
+                "endOption": {
+                    "times": 2,
+                    "ID": 3,
+                    "localizationKey": "repeating.end.key.afterXTimes"
+                }
+            }
+        },
+        {
+            "ID": 16,
+            "amount": -250,
+            "isExpenditure": true,
+            "date": "2018-06-15",
+            "accountID": 3,
+            "categoryID": 3,
+            "name": "Transfer",
+            "description": "",
+            "tags": [],
+            "transferAccountID": 2
+        }
+    ],
+    "templates": [
+        {
+            "ID": 5,
+            "amount": 1500,
+            "accountID": 2,
+            "categoryID": 1,
+            "name": "Income",
+            "templateName": "My Simple Template",
+            "description": "Lorem Ipsum",
+            "tags": [
+                {
+                    "name": "0815"
+                }
+            ]
+        },
+        {
+            "ID": 6,
+            "templateName": "My Minimal Template",
+            "tags": []
+        },
+        {
+            "ID": 7,
+            "amount": -35000,
+            "accountID": 3,
+            "categoryID": 3,
+            "name": "Income",
+            "templateName": "My Transfer Template",
+            "description": "Lorem Ipsum",
+            "tags": [
+                {
+                    "name": "0815"
+                }
+            ],
+            "transferAccountID": 2
+        },
+        {
+            "ID": 8,
+            "templateName": "Template with icon",
+            "isExpenditure": true,
+            "tags": [],
+            "iconReferenceID": 1
+        }
+    ],
+    "charts": [
+        {
+            "ID": 9,
+            "name": "The best chart",
+            "script": "/* This list will be dynamically filled with all the transactions between\r\n* the start and and date you select on the \"Show Chart\" page\r\n* and filtered according to your specified filter.\r\n* An example entry for this list and tutorial about how to create custom charts ca be found in the BudgetMaster wiki:\r\n* https://github.com/deadlocker8/BudgetMaster/wiki/How-to-create-custom-charts\r\n*/\r\nvar transactionData \u003d [];\r\n\r\n// Prepare your chart settings here (mandatory)\r\nvar plotlyData \u003d [{\r\n    x: [],\r\n    y: [],\r\n    type: \u0027bar\u0027\r\n}];\r\n\r\n// Add your Plotly layout settings here (optional)\r\nvar plotlyLayout \u003d {};\r\n\r\n// Add your Plotly configuration settings here (optional)\r\nvar plotlyConfig \u003d {\r\n    showSendToCloud: false,\r\n    displaylogo: false,\r\n    showLink: false,\r\n    responsive: true\r\n};\r\n\r\n// Don\u0027t touch this line\r\nPlotly.newPlot(\"containerID\", plotlyData, plotlyLayout, plotlyConfig);\r\n",
+            "type": "CUSTOM",
+            "version": 7
+        }
+    ],
+    "images": [
+        {
+            "ID": 1,
+            "image": [
+                -119,
+                80,
+                78,
+                71,
+                13,
+                10,
+                26,
+                10,
+                0,
+                0,
+                0,
+                13,
+                73,
+                72,
+                68,
+                82,
+                0,
+                0,
+                0,
+                -76,
+                0,
+                0,
+                0,
+                -76,
+                8,
+                6,
+                0,
+                0,
+                0,
+                61,
+                -51,
+                6,
+                50,
+                0,
+                0,
+                11,
+                -14,
+                73,
+                68,
+                65,
+                84,
+                120,
+                -100,
+                -19,
+                -35,
+                79,
+                108,
+                84,
+                -41,
+                21,
+                -57,
+                113,
+                -85,
+                21,
+                -91,
+                73,
+                85,
+                117,
+                31,
+                -87,
+                93,
+                84,
+                -35,
+                53,
+                -72,
+                106,
+                -73,
+                93,
+                -92,
+                -35,
+                -107,
+                101,
+                -108,
+                -126,
+                -64,
+                6,
+                20,
+                112,
+                -30,
+                -40,
+                -109,
+                -72,
+                -31,
+                -97,
+                -120,
+                -99,
+                -80,
+                -120,
+                42,
+                85,
+                -79,
+                -33,
+                -104,
+                58,
+                -111,
+                72,
+                -112,
+                -6,
+                7,
+                37,
+                -87,
+                -102,
+                98,
+                4,
+                111,
+                -58,
+                99,
+                -20,
+                98,
+                76,
+                -109,
+                66,
+                -101,
+                82,
+                -64,
+                48,
+                80,
+                100,
+                91,
+                14,
+                -123,
+                96,
+                -89,
+                82,
+                9,
+                18,
+                -119,
+                106,
+                53,
+                -76,
+                -58,
+                -40,
+                -89,
+                -117,
+                -26,
+                -103,
+                97,
+                124,
+                103,
+                124,
+                -17,
+                123,
+                -9,
+                -34,
+                115,
+                -17,
+                123,
+                -65,
+                -81,
+                116,
+                -106,
+                -58,
+                -29,
+                59,
+                31,
+                14,
+                -113,
+                -7,
+                -25,
+                -122,
+                6,
+                -124,
+                16,
+                -110,
+                41,
+                -105,
+                -53,
+                125,
+                -46,
+                -34,
+                -34,
+                78,
+                -43,
+                -61,
+                125,
+                -69,
+                16,
+                82,
+                -86,
+                -75,
+                -75,
+                117,
+                -107,
+                8,
+                50,
+                96,
+                35,
+                -17,
+                -54,
+                -27,
+                114,
+                45,
+                50,
+                -104,
+                -127,
+                26,
+                121,
+                -111,
+                10,
+                102,
+                -96,
+                70,
+                78,
+                23,
+                7,
+                51,
+                64,
+                35,
+                103,
+                -117,
+                11,
+                26,
+                -88,
+                -111,
+                -109,
+                1,
+                52,
+                -14,
+                62,
+                -39,
+                71,
+                52,
+                100,
+                38,
+                -105,
+                -53,
+                -123,
+                -36,
+                63,
+                15,
+                -54,
+                88,
+                -71,
+                92,
+                -18,
+                51,
+                93,
+                -128,
+                -79,
+                -71,
+                17,
+                75,
+                -19,
+                -19,
+                -19,
+                115,
+                54,
+                17,
+                3,
+                55,
+                -46,
+                -34,
+                -38,
+                -75,
+                107,
+                87,
+                115,
+                3,
+                6,
+                110,
+                79,
+                107,
+                -20,
+                26,
+                33,
+                87,
+                -26,
+                -47,
+                -82,
+                17,
+                118,
+                -84,
+                -14,
+                -45,
+                -58,
+                126,
+                94,
+                -107,
+                -13,
+                -19,
+                -82,
+                19,
+                -33,
+                -25,
+                -74,
+                -60,
+                30,
+                -9,
+                -99,
+                -32,
+                26,
+                -28,
+                -25,
+                95,
+                120,
+                -122,
+                94,
+                -23,
+                111,
+                -10,
+                26,
+                54,
+                -73,
+                41,
+                -74,
+                -72,
+                15,
+                62,
+                26,
+                110,
+                -60,
+                -47,
+                -28,
+                11,
+                77,
+                75,
+                19,
+                -25,
+                -21,
+                -71,
+                -49,
+                -79,
+                98,
+                -58,
+                -72,
+                109,
+                89,
+                -49,
+                -127,
+                67,
+                119,
+                6,
+                -13,
+                75,
+                -81,
+                109,
+                125,
+                0,
+                115,
+                18,
+                -44,
+                79,
+                -25,
+                -74,
+                -77,
+                -97,
+                105,
+                99,
+                87,
+                6,
+                -73,
+                52,
+                -9,
+                -127,
+                127,
+                -73,
+                115,
+                -104,
+                29,
+                114,
+                -11,
+                86,
+                -82,
+                -98,
+                -82,
+                -34,
+                109,
+                -79,
+                -1,
+                92,
+                -18,
+                -13,
+                109,
+                124,
+                -15,
+                -60,
+                21,
+                110,
+                99,
+                86,
+                -29,
+                60,
+                -20,
+                31,
+                -19,
+                -6,
+                53,
+                59,
+                -28,
+                -18,
+                -61,
+                -51,
+                117,
+                49,
+                39,
+                -39,
+                -46,
+                -82,
+                -96,
+                -26,
+                54,
+                102,
+                -83,
+                -58,
+                -50,
+                -29,
+                -9,
+                56,
+                15,
+                -102,
+                27,
+                -77,
+                12,
+                -28,
+                52,
+                -96,
+                -26,
+                118,
+                102,
+                -83,
+                -84,
+                98,
+                14,
+                20,
+                33,
+                71,
+                -45,
+                -79,
+                -93,
+                -51,
+                75,
+                -44,
+                -36,
+                -50,
+                -84,
+                -107,
+                69,
+                -52,
+                113,
+                32,
+                -21,
+                -38,
+                -46,
+                45,
+                -49,
+                -18,
+                1,
+                104,
+                -109,
+                -15,
+                96,
+                78,
+                -74,
+                -27,
+                -72,
+                32,
+                -5,
+                124,
+                -23,
+                -63,
+                -19,
+                -52,
+                90,
+                -103,
+                -40,
+                -50,
+                109,
+                122,
+                49,
+                -25,
+                11,
+                77,
+                -44,
+                -42,
+                -106,
+                -28,
+                54,
+                -27,
+                0,
+                -38,
+                84,
+                -74,
+                15,
+                -74,
+                -83,
+                61,
+                -25,
+                -19,
+                86,
+                -10,
+                121,
+                75,
+                115,
+                59,
+                -77,
+                86,
+                90,
+                -73,
+                115,
+                -101,
+                -127,
+                -83,
+                -84,
+                19,
+                -11,
+                51,
+                -19,
+                29,
+                0,
+                109,
+                34,
+                -107,
+                67,
+                -47,
+                -111,
+                -17,
+                91,
+                121,
+                25,
+                -24,
+                4,
+                -105,
+                30,
+                73,
+                3,
+                104,
+                65,
+                54,
+                65,
+                47,
+                44,
+                44,
+                -104,
+                -59,
+                -100,
+                -77,
+                -117,
+                57,
+                -23,
+                -106,
+                6,
+                104,
+                3,
+                -39,
+                4,
+                -35,
+                -46,
+                -46,
+                -30,
+                -51,
+                86,
+                -18,
+                27,
+                -38,
+                68,
+                65,
+                -72,
+                -47,
+                40,
+                106,
+                -128,
+                54,
+                -112,
+                77,
+                -48,
+                38,
+                32,
+                -17,
+                -2,
+                -23,
+                83,
+                -38,
+                49,
+                15,
+                -50,
+                -20,
+                94,
+                26,
+                -128,
+                -10,
+                44,
+                -37,
+                -41,
+                -48,
+                58,
+                -45,
+                13,
+                -7,
+                -32,
+                -103,
+                -42,
+                7,
+                48,
+                -85,
+                -94,
+                -74,
+                29,
+                64,
+                11,
+                -14,
+                17,
+                -12,
+                -47,
+                63,
+                -65,
+                106,
+                116,
+                43,
+                87,
+                -113,
+                -20,
+                -45,
+                -28,
+                61,
+                -31,
+                122,
+                -85,
+                -25,
+                0,
+                -48,
+                -126,
+                124,
+                3,
+                -83,
+                27,
+                -14,
+                -47,
+                -85,
+                -37,
+                -21,
+                98,
+                118,
+                121,
+                75,
+                3,
+                -76,
+                32,
+                95,
+                64,
+                -9,
+                -124,
+                -21,
+                -83,
+                110,
+                101,
+                31,
+                80,
+                3,
+                -76,
+                32,
+                31,
+                64,
+                -21,
+                -122,
+                92,
+                -102,
+                -34,
+                -91,
+                -116,
+                89,
+                5,
+                116,
+                80,
+                -40,
+                104,
+                -27,
+                92,
+                0,
+                90,
+                -112,
+                -53,
+                -96,
+                -69,
+                29,
+                -40,
+                -54,
+                46,
+                111,
+                105,
+                -128,
+                22,
+                -28,
+                42,
+                104,
+                -41,
+                32,
+                -69,
+                -120,
+                26,
+                -96,
+                5,
+                -71,
+                6,
+                90,
+                -27,
+                -55,
+                12,
+                14,
+                -52,
+                42,
+                -96,
+                -5,
+                79,
+                -25,
+                -115,
+                -98,
+                21,
+                64,
+                11,
+                114,
+                9,
+                -76,
+                -21,
+                -112,
+                93,
+                -37,
+                -46,
+                0,
+                45,
+                -56,
+                5,
+                -48,
+                -70,
+                33,
+                7,
+                -122,
+                49,
+                15,
+                -50,
+                -20,
+                -90,
+                -30,
+                -11,
+                -99,
+                -20,
+                -88,
+                1,
+                90,
+                16,
+                55,
+                104,
+                -97,
+                -74,
+                114,
+                -36,
+                45,
+                61,
+                -3,
+                -15,
+                -108,
+                -111,
+                -77,
+                3,
+                104,
+                65,
+                92,
+                -96,
+                117,
+                67,
+                -18,
+                45,
+                53,
+                91,
+                -59,
+                -20,
+                -62,
+                -91,
+                7,
+                64,
+                11,
+                -78,
+                13,
+                122,
+                -18,
+                -18,
+                127,
+                -68,
+                -34,
+                -54,
+                -43,
+                -13,
+                -42,
+                -7,
+                54,
+                54,
+                -44,
+                0,
+                45,
+                -56,
+                38,
+                104,
+                -35,
+                -112,
+                -33,
+                -8,
+                -61,
+                86,
+                86,
+                -52,
+                -86,
+                91,
+                -6,
+                -18,
+                -4,
+                -100,
+                6,
+                -58,
+                -9,
+                3,
+                104,
+                65,
+                54,
+                64,
+                -113,
+                125,
+                48,
+                -102,
+                -86,
+                -83,
+                -20,
+                -54,
+                -91,
+                7,
+                64,
+                11,
+                50,
+                13,
+                90,
+                55,
+                -28,
+                119,
+                -2,
+                -10,
+                28,
+                59,
+                94,
+                -47,
+                -12,
+                13,
+                109,
+                -74,
+                -114,
+                26,
+                -96,
+                5,
+                -103,
+                4,
+                -99,
+                -10,
+                -83,
+                -52,
+                -67,
+                -91,
+                1,
+                90,
+                -112,
+                15,
+                -96,
+                -117,
+                31,
+                -18,
+                100,
+                -57,
+                -22,
+                34,
+                106,
+                -128,
+                22,
+                -28,
+                -6,
+                37,
+                7,
+                55,
+                80,
+                -43,
+                -23,
+                81,
+                120,
+                -22,
+                30,
+                -96,
+                13,
+                100,
+                26,
+                -12,
+                127,
+                99,
+                62,
+                76,
+                87,
+                -102,
+                -26,
+                -57,
+                -23,
+                -6,
+                -106,
+                6,
+                104,
+                65,
+                -90,
+                65,
+                19,
+                -87,
+                111,
+                105,
+                110,
+                -112,
+                -66,
+                -96,
+                6,
+                104,
+                65,
+                54,
+                64,
+                -85,
+                -96,
+                -26,
+                -122,
+                -88,
+                107,
+                100,
+                95,
+                53,
+                24,
+                -124,
+                27,
+                0,
+                90,
+                103,
+                -74,
+                64,
+                79,
+                -50,
+                -116,
+                101,
+                14,
+                -75,
+                -23,
+                45,
+                13,
+                -48,
+                -126,
+                108,
+                -127,
+                38,
+                -110,
+                -33,
+                -46,
+                -59,
+                -21,
+                -2,
+                60,
+                -86,
+                -63,
+                -119,
+                26,
+                -96,
+                5,
+                -39,
+                4,
+                -83,
+                -126,
+                -102,
+                27,
+                -94,
+                -82,
+                9,
+                66,
+                -71,
+                -97,
+                -73,
+                59,
+                -4,
+                49,
+                64,
+                -21,
+                -56,
+                54,
+                -24,
+                -73,
+                -33,
+                125,
+                57,
+                115,
+                -88,
+                77,
+                109,
+                105,
+                -128,
+                22,
+                100,
+                27,
+                52,
+                81,
+                -10,
+                -74,
+                -76,
+                41,
+                -44,
+                0,
+                45,
+                -120,
+                3,
+                116,
+                22,
+                81,
+                -53,
+                -2,
+                -68,
+                7,
+                -122,
+                119,
+                0,
+                116,
+                -110,
+                -72,
+                64,
+                -65,
+                114,
+                -28,
+                113,
+                -96,
+                -82,
+                -102,
+                114,
+                -71,
+                76,
+                -27,
+                114,
+                -103,
+                46,
+                94,
+                -68,
+                8,
+                -48,
+                113,
+                -29,
+                2,
+                77,
+                -108,
+                -67,
+                45,
+                61,
+                56,
+                45,
+                70,
+                -3,
+                -50,
+                -24,
+                -66,
+                37,
+                -52,
+                -47,
+                0,
+                116,
+                -52,
+                56,
+                65,
+                103,
+                17,
+                117,
+                -83,
+                -83,
+                44,
+                26,
+                -128,
+                -114,
+                17,
+                55,
+                104,
+                -39,
+                -49,
+                -84,
+                11,
+                -62,
+                -115,
+                -20,
+                24,
+                117,
+                -94,
+                62,
+                125,
+                -10,
+                100,
+                93,
+                -52,
+                50,
+                -105,
+                30,
+                0,
+                45,
+                -120,
+                27,
+                52,
+                81,
+                -10,
+                -74,
+                -12,
+                74,
+                -112,
+                101,
+                -73,
+                52,
+                64,
+                11,
+                114,
+                1,
+                -76,
+                -53,
+                -88,
+                117,
+                126,
+                127,
+                21,
+                -56,
+                50,
+                -88,
+                1,
+                90,
+                -112,
+                43,
+                -96,
+                -125,
+                -126,
+                -20,
+                -117,
+                121,
+                -52,
+                95,
+                122,
+                28,
+                120,
+                111,
+                -101,
+                -10,
+                -65,
+                92,
+                113,
+                49,
+                -105,
+                -53,
+                101,
+                -102,
+                -100,
+                -100,
+                4,
+                104,
+                -39,
+                92,
+                1,
+                77,
+                -28,
+                -58,
+                -106,
+                -34,
+                63,
+                -6,
+                -92,
+                -12,
+                -19,
+                -112,
+                -71,
+                61,
+                73,
+                32,
+                -81,
+                -76,
+                -91,
+                1,
+                90,
+                -112,
+                75,
+                -96,
+                93,
+                64,
+                -83,
+                -118,
+                -71,
+                -10,
+                109,
+                -38,
+                -91,
+                13,
+                115,
+                45,
+                -44,
+                0,
+                45,
+                -56,
+                87,
+                -48,
+                -7,
+                34,
+                -33,
+                -89,
+                -118,
+                -42,
+                -101,
+                35,
+                83,
+                -37,
+                -75,
+                67,
+                -114,
+                -26,
+                -42,
+                -83,
+                91,
+                0,
+                -67,
+                82,
+                -82,
+                -127,
+                86,
+                65,
+                -19,
+                26,
+                -24,
+                32,
+                -36,
+                96,
+                12,
+                -77,
+                104,
+                75,
+                3,
+                -76,
+                32,
+                23,
+                65,
+                115,
+                -96,
+                78,
+                -118,
+                -39,
+                52,
+                100,
+                17,
+                106,
+                -128,
+                22,
+                -28,
+                59,
+                -24,
+                -41,
+                53,
+                125,
+                28,
+                88,
+                92,
+                -56,
+                61,
+                -31,
+                122,
+                -85,
+                -104,
+                -53,
+                -27,
+                50,
+                -51,
+                -49,
+                -49,
+                3,
+                116,
+                -83,
+                92,
+                5,
+                -83,
+                -126,
+                -102,
+                11,
+                -76,
+                109,
+                -56,
+                -43,
+                91,
+                26,
+                -96,
+                5,
+                -71,
+                12,
+                122,
+                -10,
+                -50,
+                -89,
+                -42,
+                80,
+                -85,
+                64,
+                126,
+                125,
+                -16,
+                39,
+                -84,
+                -104,
+                -93,
+                1,
+                104,
+                65,
+                46,
+                -125,
+                38,
+                -110,
+                -33,
+                -46,
+                -3,
+                -29,
+                29,
+                86,
+                64,
+                115,
+                35,
+                -82,
+                -100,
+                111,
+                -18,
+                57,
+                14,
+                -48,
+                -43,
+                -71,
+                14,
+                90,
+                5,
+                -75,
+                73,
+                -48,
+                -91,
+                83,
+                111,
+                -79,
+                3,
+                78,
+                -78,
+                -91,
+                -71,
+                -99,
+                89,
+                -53,
+                7,
+                -48,
+                -89,
+                -82,
+                28,
+                49,
+                -114,
+                -38,
+                -105,
+                -83,
+                28,
+                23,
+                53,
+                -73,
+                51,
+                107,
+                -7,
+                0,
+                -102,
+                72,
+                126,
+                75,
+                -105,
+                110,
+                -24,
+                -5,
+                45,
+                -79,
+                127,
+                29,
+                123,
+                -97,
+                29,
+                -85,
+                -52,
+                -84,
+                1,
+                -24,
+                -5,
+                -7,
+                2,
+                90,
+                5,
+                -75,
+                14,
+                -48,
+                -36,
+                72,
+                117,
+                111,
+                105,
+                110,
+                103,
+                -42,
+                -14,
+                9,
+                -12,
+                -2,
+                33,
+                -7,
+                -33,
+                103,
+                18,
+                23,
+                -12,
+                -91,
+                -14,
+                37,
+                118,
+                -100,
+                38,
+                80,
+                115,
+                59,
+                -77,
+                -106,
+                79,
+                -96,
+                -119,
+                -52,
+                109,
+                -23,
+                -46,
+                -76,
+                -2,
+                23,
+                19,
+                1,
+                52,
+                67,
+                -66,
+                -127,
+                38,
+                -46,
+                -113,
+                -102,
+                27,
+                -94,
+                13,
+                -44,
+                -36,
+                -50,
+                -84,
+                -27,
+                35,
+                -24,
+                -18,
+                -93,
+                -21,
+                -76,
+                -96,
+                46,
+                25,
+                120,
+                -119,
+                -89,
+                11,
+                3,
+                -48,
+                -98,
+                -127,
+                38,
+                74,
+                -66,
+                -91,
+                -71,
+                -47,
+                1,
+                -76,
+                -95,
+                124,
+                5,
+                77,
+                20,
+                15,
+                117,
+                105,
+                102,
+                39,
+                59,
+                56,
+                14,
+                -44,
+                -36,
+                -50,
+                -84,
+                -27,
+                51,
+                -24,
+                32,
+                -36,
+                32,
+                5,
+                58,
+                122,
+                31,
+                34,
+                55,
+                50,
+                -101,
+                115,
+                -31,
+                66,
+                25,
+                -96,
+                125,
+                3,
+                77,
+                36,
+                -73,
+                -91,
+                3,
+                15,
+                31,
+                87,
+                -42,
+                -67,
+                -91,
+                -71,
+                -99,
+                89,
+                -53,
+                119,
+                -48,
+                68,
+                -11,
+                81,
+                115,
+                -93,
+                -30,
+                -100,
+                -30,
+                -24,
+                89,
+                -128,
+                -10,
+                17,
+                -76,
+                -24,
+                35,
+                16,
+                126,
+                53,
+                -68,
+                -105,
+                29,
+                20,
+                -25,
+                68,
+                -25,
+                0,
+                -48,
+                30,
+                -126,
+                38,
+                34,
+                108,
+                -27,
+                -49,
+                -25,
+                -19,
+                -111,
+                -97,
+                45,
+                -5,
+                -53,
+                13,
+                -48,
+                30,
+                -126,
+                38,
+                34,
+                58,
+                -7,
+                -105,
+                65,
+                118,
+                80,
+                46,
+                108,
+                -27,
+                -22,
+                89,
+                -45,
+                9,
+                -48,
+                94,
+                -126,
+                -26,
+                6,
+                -59,
+                53,
+                -67,
+                -123,
+                45,
+                43,
+                -2,
+                -57,
+                -104,
+                -37,
+                -103,
+                -75,
+                -46,
+                4,
+                -6,
+                -26,
+                -51,
+                -101,
+                -20,
+                -72,
+                108,
+                79,
+                32,
+                -7,
+                88,
+                124,
+                102,
+                80,
+                -89,
+                9,
+                52,
+                81,
+                118,
+                -74,
+                116,
+                105,
+                -26,
+                -2,
+                -21,
+                -66,
+                1,
+                -70,
+                -94,
+                -76,
+                -127,
+                38,
+                74,
+                63,
+                -22,
+                36,
+                -17,
+                -119,
+                -28,
+                -10,
+                102,
+                -68,
+                52,
+                -126,
+                30,
+                31,
+                31,
+                103,
+                71,
+                103,
+                6,
+                114,
+                -19,
+                119,
+                -29,
+                -32,
+                -46,
+                -29,
+                -13,
+                -46,
+                8,
+                -102,
+                40,
+                125,
+                91,
+                90,
+                -25,
+                59,
+                -41,
+                -71,
+                -51,
+                25,
+                45,
+                -83,
+                -96,
+                -119,
+                -46,
+                -127,
+                90,
+                -9,
+                -69,
+                -41,
+                83,
+                -113,
+                26,
+                -96,
+                93,
+                -99,
+                75,
+                -44,
+                115,
+                84,
+                -3,
+                -61,
+                -35,
+                101,
+                65,
+                -25,
+                11,
+                77,
+                11,
+                -36,
+                -10,
+                -116,
+                -92,
+                5,
+                -12,
+                -28,
+                87,
+                106,
+                -49,
+                -62,
+                93,
+                123,
+                -126,
+                5,
+                -15,
+                -61,
+                84,
+                -97,
+                90,
+                47,
+                125,
+                -59,
+                -106,
+                -106,
+                40,
+                54,
+                -24,
+                122,
+                -120,
+                107,
+                13,
+                83,
+                -36,
+                64,
+                101,
+                103,
+                -20,
+                -62,
+                -7,
+                101,
+                -24,
+                -30,
+                -128,
+                -50,
+                52,
+                106,
+                101,
+                -48,
+                19,
+                95,
+                -117,
+                -121,
+                -103,
+                17,
+                54,
+                55,
+                84,
+                -43,
+                -83,
+                108,
+                19,
+                116,
+                111,
+                -79,
+                -7,
+                -97,
+                -36,
+                6,
+                -75,
+                -90,
+                4,
+                58,
+                41,
+                100,
+                -96,
+                94,
+                54,
+                -57,
+                78,
+                -1,
+                -74,
+                46,
+                -72,
+                -72,
+                -96,
+                51,
+                -69,
+                -91,
+                89,
+                48,
+                71,
+                -13,
+                -39,
+                7,
+                -103,
+                70,
+                45,
+                -125,
+                45,
+                9,
+                -24,
+                -46,
+                -12,
+                -82,
+                -20,
+                -95,
+                102,
+                -61,
+                -52,
+                -80,
+                -87,
+                -71,
+                1,
+                71,
+                115,
+                -32,
+                -40,
+                78,
+                105,
+                104,
+                73,
+                64,
+                -85,
+                93,
+                122,
+                52,
+                -3,
+                -110,
+                -37,
+                -94,
+                -106,
+                88,
+                49,
+                103,
+                16,
+                -75,
+                -62,
+                -61,
+                106,
+                90,
+                64,
+                103,
+                -18,
+                -46,
+                -93,
+                30,
+                -26,
+                71,
+                -10,
+                -100,
+                -80,
+                3,
+                58,
+                3,
+                -88,
+                -69,
+                67,
+                -7,
+                -49,
+                18,
+                -47,
+                13,
+                -6,
+                -56,
+                -44,
+                -13,
+                -39,
+                65,
+                -51,
+                -66,
+                -99,
+                51,
+                0,
+                58,
+                14,
+                -28,
+                124,
+                -95,
+                -119,
+                -6,
+                -122,
+                54,
+                107,
+                1,
+                -83,
+                -78,
+                -91,
+                -13,
+                3,
+                91,
+                26,
+                -71,
+                77,
+                38,
+                -86,
+                22,
+                -26,
+                117,
+                -35,
+                -121,
+                -20,
+                -126,
+                78,
+                33,
+                -22,
+                -96,
+                32,
+                -9,
+                49,
+                11,
+                38,
+                -73,
+                115,
+                -26,
+                46,
+                61,
+                -100,
+                -40,
+                -50,
+                12,
+                -96,
+                23,
+                22,
+                22,
+                -100,
+                -36,
+                -54,
+                -47,
+                4,
+                6,
+                64,
+                -1,
+                -30,
+                79,
+                79,
+                -91,
+                31,
+                117,
+                86,
+                65,
+                19,
+                -103,
+                -39,
+                -46,
+                -79,
+                -2,
+                -103,
+                -73,
+                -80,
+                -99,
+                85,
+                111,
+                -45,
+                -31,
+                -61,
+                -21,
+                -66,
+                -56,
+                109,
+                51,
+                86,
+                78,
+                -127,
+                -10,
+                28,
+                117,
+                -30,
+                -21,
+                87,
+                -61,
+                -104,
+                51,
+                113,
+                -23,
+                33,
+                -62,
+                -4,
+                -40,
+                -34,
+                -31,
+                -52,
+                -128,
+                -98,
+                -99,
+                -99,
+                53,
+                6,
+                -71,
+                122,
+                -126,
+                112,
+                -7,
+                -25,
+                -121,
+                -40,
+                -58,
+                60,
+                56,
+                -77,
+                -101,
+                126,
+                62,
+                -40,
+                -100,
+                94,
+                -44,
+                34,
+                -48,
+                31,
+                -99,
+                -7,
+                65,
+                102,
+                64,
+                19,
+                37,
+                -39,
+                -46,
+                -105,
+                18,
+                -63,
+                26,
+                -120,
+                -7,
+                -5,
+                96,
+                -80,
+                -91,
+                -21,
+                36,
+                -66,
+                -36,
+                88,
+                -107,
+                41,
+                -48,
+                113,
+                80,
+                115,
+                65,
+                4,
+                -22,
+                21,
+                18,
+                -127,
+                126,
+                -13,
+                -48,
+                -34,
+                -52,
+                -127,
+                -66,
+                118,
+                -19,
+                -102,
+                20,
+                -28,
+                51,
+                -25,
+                79,
+                -77,
+                67,
+                -44,
+                53,
+                50,
+                -105,
+                64,
+                -34,
+                -95,
+                22,
+                -127,
+                -2,
+                -58,
+                11,
+                22,
+                -97,
+                33,
+                116,
+                4,
+                52,
+                -47,
+                -54,
+                91,
+                -38,
+                -10,
+                -75,
+                46,
+                -74,
+                116,
+                -116,
+                -100,
+                122,
+                -108,
+                99,
+                98,
+                21,
+                43,
+                -24,
+                90,
+                -88,
+                15,
+                -99,
+                -20,
+                91,
+                118,
+                7,
+                -1,
+                -18,
+                -54,
+                115,
+                -20,
+                24,
+                -127,
+                90,
+                -112,
+                83,
+                -96,
+                29,
+                -24,
+                -14,
+                -27,
+                -53,
+                -46,
+                79,
+                -112,
+                112,
+                67,
+                -44,
+                53,
+                -87,
+                -6,
+                8,
+                4,
+                -128,
+                94,
+                94,
+                -71,
+                92,
+                -90,
+                -66,
+                -127,
+                22,
+                39,
+                30,
+                51,
+                -58,
+                -106,
+                86,
+                -52,
+                -103,
+                23,
+                39,
+                -115,
+                127,
+                -127,
+                -37,
+                -15,
+                3,
+                -55,
+                -34,
+                -63,
+                3,
+                31,
+                -14,
+                61,
+                -12,
+                6,
+                -44,
+                -126,
+                -100,
+                1,
+                -19,
+                96,
+                -78,
+                119,
+                48,
+                55,
+                68,
+                -37,
+                -96,
+                -13,
+                -59,
+                -90,
+                57,
+                110,
+                -73,
+                53,
+                115,
+                -30,
+                5,
+                -2,
+                -41,
+                -73,
+                113,
+                -37,
+                21,
+                118,
+                112,
+                -76,
+                11,
+                -88,
+                125,
+                -37,
+                -46,
+                43,
+                -127,
+                126,
+                -94,
+                -89,
+                63,
+                -109,
+                -37,
+                57,
+                42,
+                107,
+                -96,
+                75,
+                -66,
+                -93,
+                -106,
+                123,
+                79,
+                -31,
+                -105,
+                -36,
+                -57,
+                60,
+                123,
+                78,
+                -4,
+                -25,
+                79,
+                36,
+                -1,
+                30,
+                89,
+                67,
+                45,
+                -5,
+                -13,
+                -10,
+                14,
+                52,
+                -97,
+                -29,
+                -10,
+                -69,
+                44,
+                25,
+                -48,
+                -58,
+                80,
+                39,
+                -19,
+                31,
+                61,
+                -118,
+                -33,
+                -13,
+                -31,
+                88,
+                -33,
+                70,
+                -12,
+                75,
+                -119,
+                -128,
+                -38,
+                -47,
+                45,
+                45,
+                11,
+                -70,
+                -79,
+                107,
+                -124,
+                104,
+                126,
+                -42,
+                13,
+                -52,
+                -13,
+                -1,
+                78,
+                -10,
+                -67,
+                99,
+                60,
+                -127,
+                3,
+                -48,
+                -98,
+                -96,
+                86,
+                2,
+                29,
+                -59,
+                -71,
+                -107,
+                25,
+                -1,
+                -123,
+                -56,
+                10,
+                106,
+                21,
+                -52,
+                -7,
+                66,
+                19,
+                -19,
+                43,
+                110,
+                -38,
+                -62,
+                -19,
+                120,
+                -87,
+                88,
+                -96,
+                -105,
+                112,
+                -83,
+                -106,
+                -57,
+                -77,
+                -72,
+                -24,
+                22,
+                -26,
+                24,
+                -88,
+                101,
+                47,
+                61,
+                -126,
+                -48,
+                79,
+                -44,
+                -86,
+                -112,
+                -99,
+                -36,
+                -46,
+                -119,
+                64,
+                87,
+                55,
+                119,
+                -101,
+                104,
+                -22,
+                59,
+                68,
+                -73,
+                -113,
+                -59,
+                20,
+                91,
+                39,
+                19,
+                -104,
+                99,
+                -96,
+                78,
+                -29,
+                -106,
+                30,
+                -72,
+                33,
+                -1,
+                9,
+                75,
+                -50,
+                -93,
+                -42,
+                10,
+                -38,
+                84,
+                38,
+                49,
+                103,
+                28,
+                -75,
+                14,
+                -56,
+                -47,
+                -68,
+                -4,
+                -34,
+                -109,
+                95,
+                -26,
+                -10,
+                12,
+                -48,
+                -47,
+                76,
+                60,
+                36,
+                125,
+                115,
+                100,
+                -17,
+                96,
+                19,
+                -17,
+                -36,
+                -42,
+                53,
+                -3,
+                19,
+                29,
+                90,
+                49,
+                99,
+                67,
+                -53,
+                102,
+                3,
+                115,
+                -58,
+                -74,
+                -76,
+                110,
+                -56,
+                -67,
+                -59,
+                -26,
+                78,
+                110,
+                -57,
+                75,
+                57,
+                13,
+                122,
+                -15,
+                -98,
+                93,
+                -48,
+                41,
+                71,
+                -3,
+                -58,
+                -69,
+                91,
+                -45,
+                -71,
+                -107,
+                43,
+                115,
+                26,
+                -76,
+                109,
+                -52,
+                -122,
+                64,
+                -65,
+                -6,
+                123,
+                125,
+                31,
+                -23,
+                -27,
+                -54,
+                86,
+                -34,
+                87,
+                -36,
+                -16,
+                117,
+                110,
+                -69,
+                -62,
+                0,
+                58,
+                62,
+                104,
+                34,
+                -9,
+                -73,
+                116,
+                111,
+                81,
+                -2,
+                35,
+                11,
+                -68,
+                -35,
+                -54,
+                -107,
+                1,
+                116,
+                50,
+                -44,
+                -13,
+                -9,
+                -26,
+                -99,
+                69,
+                -99,
+                41,
+                -56,
+                81,
+                -50,
+                -126,
+                -42,
+                -7,
+                52,
+                -69,
+                35,
+                91,
+                -6,
+                -32,
+                -103,
+                86,
+                43,
+                -112,
+                -125,
+                80,
+                47,
+                100,
+                111,
+                48,
+                55,
+                52,
+                56,
+                12,
+                -6,
+                -22,
+                15,
+                -67,
+                1,
+                77,
+                -28,
+                -50,
+                -91,
+                71,
+                102,
+                33,
+                71,
+                57,
+                11,
+                -102,
+                11,
+                115,
+                76,
+                -48,
+                55,
+                63,
+                -7,
+                -120,
+                21,
+                -75,
+                110,
+                -56,
+                94,
+                98,
+                110,
+                104,
+                112,
+                24,
+                -12,
+                -11,
+                -57,
+                -67,
+                2,
+                77,
+                36,
+                -65,
+                -91,
+                11,
+                127,
+                -33,
+                -31,
+                52,
+                102,
+                110,
+                -109,
+                -119,
+                114,
+                22,
+                -12,
+                -62,
+                93,
+                -17,
+                64,
+                19,
+                -39,
+                -67,
+                -12,
+                -48,
+                -66,
+                -107,
+                -117,
+                -98,
+                99,
+                110,
+                104,
+                112,
+                24,
+                52,
+                17,
+                15,
+                -26,
+                -124,
+                31,
+                118,
+                115,
+                124,
+                -20,
+                55,
+                86,
+                80,
+                99,
+                43,
+                -41,
+                8,
+                -96,
+                -11,
+                109,
+                -25,
+                40,
+                -109,
+                -96,
+                117,
+                67,
+                -18,
+                45,
+                54,
+                -35,
+                -31,
+                54,
+                -88,
+                53,
+                -128,
+                -42,
+                15,
+                -102,
+                72,
+                63,
+                -22,
+                -16,
+                -22,
+                14,
+                108,
+                101,
+                -103,
+                -100,
+                6,
+                77,
+                100,
+                25,
+                116,
+                -68,
+                -9,
+                28,
+                -118,
+                122,
+                109,
+                -16,
+                105,
+                109,
+                -88,
+                13,
+                92,
+                43,
+                -97,
+                -30,
+                118,
+                103,
+                44,
+                -128,
+                -42,
+                -65,
+                -99,
+                -93,
+                -110,
+                -126,
+                126,
+                -13,
+                92,
+                27,
+                -74,
+                -78,
+                106,
+                -50,
+                -125,
+                38,
+                -78,
+                -125,
+                121,
+                -30,
+                -85,
+                70,
+                110,
+                122,
+                92,
+                -44,
+                -70,
+                33,
+                7,
+                -123,
+                77,
+                79,
+                112,
+                91,
+                -77,
+                -110,
+                23,
+                -96,
+                39,
+                30,
+                -10,
+                110,
+                59,
+                71,
+                5,
+                -95,
+                -4,
+                -17,
+                42,
+                28,
+                -100,
+                -39,
+                77,
+                125,
+                67,
+                -101,
+                -75,
+                99,
+                110,
+                -20,
+                26,
+                73,
+                -1,
+                102,
+                -114,
+                -14,
+                2,
+                52,
+                -111,
+                -105,
+                -104,
+                -93,
+                -76,
+                95,
+                3,
+                75,
+                -50,
+                -9,
+                94,
+                26,
+                90,
+                -70,
+                -17,
+                -72,
+                -99,
+                89,
+                -53,
+                27,
+                -48,
+                68,
+                94,
+                98,
+                -114,
+                -78,
+                -115,
+                -71,
+                -6,
+                -66,
+                -29,
+                118,
+                102,
+                45,
+                -81,
+                64,
+                19,
+                -3,
+                -1,
+                -67,
+                127,
+                -98,
+                97,
+                38,
+                82,
+                -5,
+                -12,
+                -91,
+                36,
+                -13,
+                104,
+                -89,
+                -8,
+                -66,
+                -29,
+                118,
+                102,
+                45,
+                -17,
+                64,
+                71,
+                37,
+                -127,
+                -4,
+                -81,
+                -9,
+                89,
+                110,
+                -78,
+                -19,
+                -83,
+                12,
+                -48,
+                62,
+                -127,
+                -114,
+                82,
+                -127,
+                124,
+                -11,
+                49,
+                -18,
+                91,
+                107,
+                4,
+                -14,
+                26,
+                -119,
+                -5,
+                -114,
+                -37,
+                -103,
+                -75,
+                -68,
+                7,
+                93,
+                -39,
+                -115,
+                61,
+                -9,
+                47,
+                73,
+                38,
+                30,
+                34,
+                -102,
+                122,
+                -124,
+                -5,
+                22,
+                45,
+                75,
+                47,
+                -26,
+                -115,
+                -46,
+                -9,
+                29,
+                -73,
+                51,
+                107,
+                -91,
+                10,
+                -76,
+                39,
+                -23,
+                -64,
+                76,
+                68,
+                -46,
+                -9,
+                27,
+                64,
+                3,
+                -76,
+                -47,
+                22,
+                23,
+                23,
+                99,
+                67,
+                -18,
+                9,
+                -41,
+                47,
+                -3,
+                57,
+                0,
+                45,
+                8,
+                -96,
+                121,
+                -118,
+                -69,
+                -107,
+                43,
+                3,
+                104,
+                65,
+                0,
+                -51,
+                -105,
+                44,
+                -28,
+                -3,
+                67,
+                -49,
+                10,
+                -65,
+                30,
+                -96,
+                5,
+                1,
+                52,
+                95,
+                -77,
+                119,
+                62,
+                85,
+                -34,
+                -54,
+                -107,
+                1,
+                -76,
+                32,
+                -128,
+                -26,
+                -83,
+                22,
+                -28,
+                63,
+                94,
+                14,
+                87,
+                -4,
+                90,
+                -128,
+                22,
+                4,
+                -48,
+                -4,
+                -87,
+                108,
+                -27,
+                -54,
+                0,
+                90,
+                16,
+                64,
+                -13,
+                55,
+                126,
+                -29,
+                44,
+                -27,
+                11,
+                77,
+                116,
+                123,
+                -10,
+                99,
+                -91,
+                -81,
+                3,
+                104,
+                65,
+                0,
+                -19,
+                111,
+                0,
+                45,
+                8,
+                -96,
+                -3,
+                13,
+                -96,
+                5,
+                1,
+                -76,
+                -65,
+                1,
+                -76,
+                32,
+                -128,
+                -10,
+                55,
+                -128,
+                22,
+                4,
+                -48,
+                -2,
+                6,
+                -48,
+                -126,
+                84,
+                14,
+                5,
+                -29,
+                -17,
+                112,
+                59,
+                -77,
+                22,
+                -9,
+                65,
+                99,
+                0,
+                90,
+                107,
+                -36,
+                7,
+                -115,
+                1,
+                104,
+                -83,
+                113,
+                31,
+                52,
+                6,
+                -96,
+                -75,
+                -58,
+                125,
+                -48,
+                24,
+                -128,
+                -42,
+                26,
+                -9,
+                65,
+                99,
+                0,
+                90,
+                107,
+                -115,
+                47,
+                -98,
+                96,
+                63,
+                108,
+                12,
+                64,
+                107,
+                -115,
+                -5,
+                -80,
+                49,
+                0,
+                -83,
+                53,
+                -18,
+                -61,
+                -58,
+                0,
+                -76,
+                -42,
+                -72,
+                15,
+                27,
+                3,
+                -52,
+                -38,
+                -29,
+                62,
+                116,
+                12,
+                64,
+                107,
+                -19,
+                91,
+                29,
+                -61,
+                -85,
+                -71,
+                15,
+                30,
+                3,
+                -52,
+                -38,
+                -29,
+                -66,
+                3,
+                48,
+                -64,
+                -116,
+                -112,
+                -109,
+                -3,
+                15,
+                62,
+                -114,
+                31,
+                -125,
+                -73,
+                -124,
+                107,
+                78,
+                0,
+                0,
+                0,
+                0,
+                73,
+                69,
+                78,
+                68,
+                -82,
+                66,
+                96,
+                -126
+            ],
+            "fileName": "awesomeIcon.png",
+            "fileExtension": "PNG"
+        }
+    ],
+    "icons": [
+        {
+            "ID": 1,
+            "imageID": 1
+        },
+        {
+            "ID": 2,
+            "builtinIdentifier": "fas fa-icons"
+        }
+    ]
+}
\ No newline at end of file