diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000000000000000000000000000000000..3b41682ac579fafb665abb4dfcdaa6aaaa712184
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+/mvnw text eol=lf
+*.cmd text eol=crlf
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..5af444d3072d00e15aa7aed20b7c203b7b020c88
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,36 @@
+/logs/
+*.mv.db
+*.trace.db
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f0a86916aedd8d8ecdfa201aab18508d82c91d44
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>3.4.4</version>
+		<relativePath /> <!-- lookup parent from repository -->
+	</parent>
+	<groupId>cz.vsb.fei</groupId>
+	<artifactId>java2-lab08-v2</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+	<name>java2-lab08-v2</name>
+	<properties>
+		<java.version>21</java.version>
+	</properties>
+	<dependencies>
+
+		<dependency>
+			<groupId>org.springdoc</groupId>
+			<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+			<version>2.8.6</version>
+		</dependency>
+		<dependency>
+			<groupId>org.hibernate</groupId>
+			<artifactId>hibernate-jpamodelgen</artifactId>
+			<scope>provided</scope>
+			<version>6.6.11.Final</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-data-jpa</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-thymeleaf</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>com.h2database</groupId>
+			<artifactId>h2</artifactId>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.projectlombok</groupId>
+			<artifactId>lombok</artifactId>
+			<optional>true</optional>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-test</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>cz.vsb.fei</groupId>
+			<artifactId>kelvin-java-unittest-support</artifactId>
+			<version>[0.1.4,)</version>
+			<scope>test</scope>
+		</dependency>
+
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<annotationProcessorPaths>
+						<path>
+							<groupId>org.projectlombok</groupId>
+							<artifactId>lombok</artifactId>
+						</path>
+						<path>
+							<groupId>org.hibernate</groupId>
+							<artifactId>hibernate-jpamodelgen</artifactId>
+							<version>6.6.11.Final</version>
+						</path>
+					</annotationProcessorPaths>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+				<configuration>
+					<excludes>
+						<exclude>
+							<groupId>org.projectlombok</groupId>
+							<artifactId>lombok</artifactId>
+						</exclude>
+					</excludes>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>build-helper-maven-plugin</artifactId>
+				<configuration>
+					<sources>
+						<source>target/generated-sources/annotations</source>
+					</sources>
+				</configuration>
+				<executions>
+					<execution>
+						<id>add-source</id>
+						<phase>process-resources</phase>
+						<goals>
+							<goal>add-source</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+	<repositories>
+		<repository>
+			<id>vsb-education-release</id>
+			<url>https://artifactory.cs.vsb.cz/repository/education-releases/</url>
+		</repository>
+		<repository>
+			<id>vsb-education-snapshot</id>
+			<url>https://artifactory.cs.vsb.cz/repository/education-snapshot/</url>
+		</repository>
+	</repositories>
+
+</project>
diff --git a/src/main/java/cz/vsb/fei/java2/lab08/Java2RestServerApplication.java b/src/main/java/cz/vsb/fei/java2/lab08/Java2RestServerApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..03e39f0f25bfbaeebb6224df8b6e91ed562bee39
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab08/Java2RestServerApplication.java
@@ -0,0 +1,13 @@
+package cz.vsb.fei.java2.lab08;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Java2RestServerApplication {
+
+	public static void main(String[] args) {
+		SpringApplication.run(Java2RestServerApplication.class, args);
+	}
+
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab08/Tools.java b/src/main/java/cz/vsb/fei/java2/lab08/Tools.java
new file mode 100644
index 0000000000000000000000000000000000000000..a18da4f5169d18595150b2be86cff9241e3d4c4c
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab08/Tools.java
@@ -0,0 +1,220 @@
+package cz.vsb.fei.java2.lab08;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+public class Tools {
+
+	public static final Random RANDOM = new Random();
+
+	public static final List<String> FIRST_NAMES = List.of("Petr", "Marie", "Jan", "Jana", "Tomáš", "Kateřina", "Lukáš",
+			"Tereza", "Martin", "Veronika", "David", "Eva", "Jakub", "Lucie", "Michal", "Anna", "Adam", "Monika", "Tom",
+			"Klára", "Robert", "Kristýna", "Marek", "Simona", "Filip", "Petra", "Ondřej", "Lenka", "Matěj", "Markéta",
+			"Pavel", "Hana", "Jakub", "Adéla", "Daniel", "Barbora", "Lukáš", "Eliška", "Josef");
+
+	public static final List<String> LAST_NAMES = List.of("Novák", "Svoboda", "Novotný", "Dvořák", "Černý",
+			"Procházková", "Kučera", "Veselý", "Horák", "Němec", "Pokorný", "Mareš", "Pospíšilová", "Hájek", "Jelínek",
+			"Král", "Růžička", "Beneš", "Fiala", "Sedláček", "Kříž", "Němcová", "Vlček", "Kolář", "Bartoš", "Bílý",
+			"Veselá", "Kovařík", "Havelka", "Malý", "Urban", "Kopecký", "Vlach", "Šimek", "Konečný", "Doležal",
+			"Šťastný", "Kopečná", "Holub", "Pospíchal");
+
+	public static final List<String> STREETS = List.of("Panská", "Hlavní", "Ulice Nová", "Náměstí Svobody", "Hřbitovní",
+			"Revoluční", "Sadová", "Jiráskova", "Školní", "Vinohradská", "Komenského", "Mírová", "Křížová",
+			"Masarykova", "Třída Svobody", "Karlova", "Dlouhá", "Žižkova", "Purkyňova", "Rybářská", "Sokolská",
+			"Rybníček", "Vrchlického", "Štefánikova", "Veselá", "Lipová", "Na Hrázi", "Výšinná", "Nová Cesta", "Česká");
+
+	public static final List<String> CITIES = Collections.unmodifiableList(
+			Arrays.asList("Praha", "Brno", "Ostrava", "Plzeň", "Liberec", "Olomouc", "České Budějovice",
+					"Hradec Králové", "Ústí nad Labem", "Pardubice", "Zlín", "Karlovy Vary", "Jihlava", "Tábor",
+					"Havířov", "Český Těšín", "Mladá Boleslav", "Trutnov", "Přerov", "Kladno", "Opava", "Frýdek-Místek",
+					"Děčín", "Karviná", "Jablonec nad Nisou", "Třebíč", "Žďár nad Sázavou", "Kolín", "Uherské Hradiště",
+					"Znojmo", "Prostějov", "Litoměřice", "Kroměříž", "Chomutov", "Příbram", "Příbram", "Cheb",
+					"Teplice", "Uherský Brod", "Sokolov", "Břeclav", "Litvínov", "Klatovy", "Vsetín", "Nový Jičín"));
+
+	public static final List<String> WORLD_CITIES = List.of("New York", "London", "Tokyo", "Paris", "Los Angeles",
+			"Shanghai", "Hong Kong", "Dubai", "Singapore", "Rome", "Berlin", "Sydney", "Barcelona", "Toronto",
+			"Chicago", "San Francisco", "Madrid", "Moscow", "Bangkok", "Beijing", "Seoul", "Istanbul", "Mumbai",
+			"Mexico City", "SĂŁo Paulo", "Buenos Aires", "Jakarta", "Lagos", "Cairo", "Rio de Janeiro", "Kuala Lumpur",
+			"Johannesburg", "Stockholm", "Helsinki", "Vienna", "Oslo", "Copenhagen", "Brussels", "Amsterdam", "Lisbon",
+			"Athens", "Dublin", "Warsaw", "Prague", "Budapest", "Zurich", "Geneva", "Munich", "Milan", "Venice",
+			"Seville", "Valencia", "Mexico City", "Havana", "Santiago", "Bogotá", "Lima", "Caracas", "Montevideo",
+			"Brasilia", "Manila", "Hanoi", "Taipei", "Kolkata", "Chennai", "Bangalore", "Karachi", "Riyadh", "Tehran",
+			"Baghdad", "Damascus", "Doha", "Kuwait City", "Muscat", "Ankara");
+
+	public static final List<String> BUILDINGS = List.of("Eiffel Tower", "Empire State Building", "Burj Khalifa",
+			"Big Ben", "Colosseum", "Sydney Opera House", "Statue of Liberty", "Leaning Tower of Pisa",
+			"Shanghai Tower", "One World Trade Center", "Willis Tower", "Taipei 101", "Louvre Museum",
+			"Chrysler Building", "Petronas Towers", "Shard London Bridge", "CN Tower", "Berlin TV Tower",
+			"Tokyo Skytree", "Guggenheim Museum", "Buckingham Palace", "Vatican City St. Peter's Basilica",
+			"Notre-Dame Cathedral", "Hagia Sophia", "Neuschwanstein Castle", "Forbidden City", "Red Square Kremlin",
+			"Christ the Redeemer", "Pantheon Rome", "Alhambra Spain", "Sagrada Familia", "Westminster Abbey",
+			"White House", "Lincoln Memorial", "Golden Gate Bridge", "Hollywood Sign", "Mount Rushmore",
+			"St. Basil's Cathedral", "Tower Bridge", "Edinburgh Castle", "Brandenburg Gate", "Palace of Versailles",
+			"Angkor Wat", "Great Wall of China", "Taj Mahal", "Machu Picchu", "Pyramids of Giza", "Stonehenge",
+			"Parthenon Athens", "Petra Jordan");
+
+	public static final List<String> NATO_COUNTRIES = List.of("United States", "Canada", "United Kingdom", "France",
+			"Germany", "Italy", "Spain", "Turkey", "Poland", "Netherlands", "Belgium", "Norway", "Denmark", "Portugal",
+			"Greece", "Czech Republic", "Hungary", "Slovakia", "Romania", "Bulgaria", "Estonia", "Latvia", "Lithuania",
+			"Slovenia", "Croatia", "Albania", "Montenegro", "North Macedonia");
+	
+	public static final List<String> POST_NUMBER = List.of("10000", "11000", "12000", "13000", "14000", "15000",
+			"16000", "17000", "18000", "19000", "20000", "21000", "22000", "23000", "24000", "25000", "26000", "27000",
+			"28000", "29000", "30000", "31000", "32000", "33000", "34000", "35000", "36000", "37000", "38000", "39000");
+
+	public static final List<String> COMPANY_NAMES = List.of("Inova", "Sprint", "Polaris", "Forte", "Nexus", "Vertex",
+			"Synergie", "Horizon", "Astra", "Axiom", "Optima", "Integra", "Evolve", "Apex", "Dynasty", "Eclipse",
+			"Paragon", "Fusion", "Oasis", "Equinox", "Voyage", "Genesis", "Zenith", "Elite", "Harmony", "Stratos",
+			"Aurora", "Quantum", "Spectrum");
+
+	public static final List<String> BIRD_NAMES = List.of("Vlaštovka", "Sýkorka", "Krkavec", "Sokol", "Káně",
+			"Střízlík", "Sojka", "Datel", "Drozd", "Rorýs", "Husa", "Labuť", "Krahujec", "Sova", "Výr", "Husice",
+			"Havran", "Špaček", "Ledňáček", "Sup");
+
+	public static final List<String> NICKNAMES = List.of("CyberSurfer", "PixelPioneer", "SocialSavvy", "DigitalDynamo",
+			"ByteBuddy", "InstaGuru", "TikTokTornado", "SnapMaster", "TweetTrendsetter", "ChatChampion", "HashtagHero",
+			"EmojiEnthusiast", "StoryStylist", "SelfieStar", "FilterFanatic", "VlogVirtuoso", "Memelord",
+			"InfluencerInsider", "StreamSupreme", "GeekyGizmo", "CodeCommander", "JavaJuggernaut", "ByteNinja",
+			"SyntaxSamurai", "ClassyCoder", "ObjectOmnipotent", "LoopLegend", "VariableVirtuoso", "DebugDemon",
+			"CompilerCrusader", "PixelProdigy", "VirtualVoyager", "AlgorithmAce", "DataDynamo", "ExceptionExpert",
+			"BugBuster", "SyntaxSorcerer", "CodeCrusader", "JavaJester");
+
+	public static final List<String> PLAYER_NICKS = List.of("CyberSurfer", "PixelPioneer", "SocialSavvy",
+			"DigitalDynamo", "ByteBuddy", "InstaGuru", "TikTokTornado", "SnapMaster", "TweetTrendsetter",
+			"ChatChampion", "HashtagHero", "EmojiEnthusiast", "StoryStylist", "SelfieStar", "FilterFanatic",
+			"VlogVirtuoso", "Memelord", "InfluencerInsider", "StreamSupreme", "GeekyGizmo", "CodeCommander",
+			"JavaJuggernaut", "ByteNinja", "SyntaxSamurai", "ClassyCoder", "ObjectOmnipotent", "LoopLegend",
+			"VariableVirtuoso", "DebugDemon", "CompilerCrusader", "PixelProdigy", "VirtualVoyager", "AlgorithmAce",
+			"DataDynamo", "ExceptionExpert", "BugBuster", "SyntaxSorcerer", "CodeCrusader", "JavaJester",
+			"NerdyNavigator", "CryptoCaptain", "SocialButterfly", "AppArchitect", "WebWizard", "FunctionFreak",
+			"PixelArtist", "CyberPhantom", "HackHero", "CacheChampion", "ScreenSage", "WebWeaver", "LogicLover",
+			"BitBlazer", "NetworkNomad", "ProtocolPioneer", "BinaryBoss", "StackSultan", "SocialScribe", "RenderRuler",
+			"ScriptSorcerer", "HTMLHero", "PixelProwler", "FrameFreak", "DataDreamer", "BotBuilder", "ByteBishop",
+			"KeyboardKnight", "DesignDaredevil", "JavaJuggler", "SyntaxStrategist", "TechTactician", "ProgramProdigy",
+			"BinaryBard", "PixelPoet", "GigabyteGuru", "TechTrekker", "NetworkNinja", "DataDetective", "MatrixMaster",
+			"CodeConductor", "AppAlchemist", "ServerSage", "ClusterChampion", "ScriptSensei", "KeyboardKicker",
+			"CacheCrafter", "SocialSpark", "BinaryBeast", "CodeConnoisseur", "BitBrain", "VirtualVanguard",
+			"SystemSculptor", "RenderRogue", "CryptoConqueror", "MachineMonarch", "PixelPal", "CompilerCaptain",
+			"BitBuilder", "TechTitan", "CloudConqueror", "EchoExplorer", "FunctionFanatic", "RobotRanger");
+
+	public static final List<String> NAME_OF_GAMES = List.of("Call of Duty: Warzone", "Counter-Strike 2",
+			"Battlefield 2042", "Overwatch 2", "Team Fortress 2", "Halo Infinite", "Apex Legends", "Rainbow Six Siege",
+			"Valorant", "Fortnite", "PUBG: Battlegrounds", "Destiny 2", "Titanfall 2", "Splatoon 3", "Gears of War 5",
+			"Left 4 Dead 2", "Dota 2", "League of Legends", "Minecraft (Bedrock/Java - multiplayer)", "Rust",
+			"Escape from Tarkov", "DayZ", "Hell Let Loose", "Hunt: Showdown", "Chivalry 2", "Payday 3", "War Thunder",
+			"Enlisted", "World of Tanks", "Sea of Thieves");
+
+	public static final List<String> EMAIL_PREFIX = List.of("cool.guy", "sunny.day", "dark.knight", "happy.cat",
+			"speed.runner", "storm.rider", "night.owl", "fire.fox", "ice.queen", "shadow.fox", "blue.sky", "lucky.star",
+			"red.dragon", "silver.wolf", "golden.eagle", "mystic.raven", "thunder.bolt", "frost.bite", "cosmic.wave",
+			"silent.ninja", "hidden.tiger", "burning.phoenix", "wild.hawk", "deep.ocean", "swift.fox", "brave.lion",
+			"electric.zebra", "rapid.cobra", "gentle.giant", "crazy.horse");
+
+	public static final List<String> PASSWORDS = List.of("Dr@g0n123!", "Thund3r#456", "Sh@d0w789$", "E@gl3!234",
+			"St0rm#567", "T1g3r$890", "Ph03n1x@123", "R@v3n#456", "Kn1ght!789", "0c3an@234", "F1r3#567", "Fr0st$890",
+			"L1ghtn!ng@123", "C0br@#456", "H@wk!789", "F0x$234", "W0lf#567", "L10n!890", "B!zzard@123", "D3str0y3r#456",
+			"R3ck0n!789", "Gh0st$234", "D@rkN!ght#567", "L3gend!890", "M@st3r@123", "N1ghtm@r3#456", "S@v@g3!789",
+			"T3rm!n@t0r$234", "Fur10us#567", "B@ttleL!on!890");
+
+	public static final List<String> EMAIL_DOMAIN = List.of("gmail.com", "seznam.cz", "hotmail.com", "outlook.com");
+
+	public static final List<String> COURSE_NAMES = List.of("Java 1", "Java 2", "C# 1", "C# 2", "Python", "Databáze I",
+			"Databáze II", "Funkcionální programování", "OOP", "PS", "APPS", "SWI");
+
+	public static String randomPassword() {
+		return randomElementFrom(PASSWORDS);
+	}
+
+	public static String randomGameName() {
+		return randomElementFrom(NAME_OF_GAMES);
+	}
+
+	public static String randomNick() {
+		return randomElementFrom(PLAYER_NICKS);
+	}
+
+	public static String randomFistName() {
+		return randomElementFrom(FIRST_NAMES);
+	}
+
+	public static String randomFullName() {
+		return String.format("%s %s", randomElementFrom(FIRST_NAMES), randomElementFrom(LAST_NAMES));
+	}
+
+	public static String randomEmail() {
+		return String.format("%s@%s", randomElementFrom(EMAIL_PREFIX), randomElementFrom(EMAIL_DOMAIN));
+	}
+
+	public static String randomLastName() {
+		return randomElementFrom(LAST_NAMES);
+	}
+
+	public static String randomCountry() {
+		return randomElementFrom(NATO_COUNTRIES);
+	}
+
+	public static String randomCity() {
+		return randomElementFrom(CITIES);
+	}
+
+	public static String randomBuilding() {
+		return randomElementFrom(BUILDINGS);
+	}
+
+	public static String randomCompanyName() {
+		StringBuilder name = new StringBuilder();
+		int numberOfWords = RANDOM.nextInt(2) + 1;
+		for (int j = 0; j < numberOfWords; j++) {
+			name.append(randomElementFrom(COMPANY_NAMES));
+			if (j < numberOfWords - 1) {
+				name.append(" ");
+			}
+		}
+		return name.toString();
+	}
+
+	public static String randomAddress() {
+		return String.format("%s %d, %s, %s", randomElementFrom(STREETS), RANDOM.nextInt(99) + 1,
+				randomElementFrom(CITIES), randomElementFrom(POST_NUMBER));
+	}
+
+	public static <T> T randomElementFrom(List<T> list) {
+		return randomElementFrom(list, RANDOM);
+	}
+
+	public static <T> T randomElement(T[] array) {
+		return array[RANDOM.nextInt(array.length)];
+	}
+
+	public static <T> T randomElementFrom(List<T> list, Random r) {
+		if (list.isEmpty()) {
+			return null;
+		}
+		return list.get(r.nextInt(list.size()));
+	}
+
+	public static LocalDate randomPreviousDate() {
+		return LocalDate.of(LocalDate.now().getYear() - RANDOM.nextInt(80), RANDOM.nextInt(12) + 1, 1)
+				.plusDays(RANDOM.nextInt(31));
+	}
+
+	public static LocalDate randomDateInFuture() {
+		return LocalDate.now().plusDays(RANDOM.nextInt(400));
+	}
+
+	public static LocalDateTime randomPreviousDateTime() {
+		return LocalDateTime.now().minusMinutes(RANDOM.nextInt(100000));
+	}
+
+	public static LocalDateTime randomDateTimeInFuture() {
+		return LocalDateTime.now().plusMinutes(RANDOM.nextInt(100000));
+	}
+
+	private Tools() {
+		/* hide public one - nothing to do */
+	}
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab08/controllers/HelloController.java b/src/main/java/cz/vsb/fei/java2/lab08/controllers/HelloController.java
new file mode 100644
index 0000000000000000000000000000000000000000..d20108f0ca5606d8ba123879a914018f3316b8c9
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab08/controllers/HelloController.java
@@ -0,0 +1,74 @@
+package cz.vsb.fei.java2.lab08.controllers;
+
+import cz.vsb.fei.java2.lab08.entities.Player;
+import cz.vsb.fei.java2.lab08.entities.Score;
+import cz.vsb.fei.java2.lab08.repositories.PlayerRepository;
+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 cz.vsb.fei.java2.lab08.repositories.ScoreRepository;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.List;
+import java.util.Optional;
+
+@Controller
+public class HelloController {
+
+  @Autowired
+  private ScoreRepository scoreRepository;
+
+  @Autowired
+  private PlayerRepository playerRepository;
+
+  @GetMapping("/")
+  public String hello() {
+    return "index";
+  }
+
+  @GetMapping("/playersTable")
+  public String listOfPersons(@RequestParam("tenYoungest") Optional<Boolean> tenYoungest,
+                              @RequestParam("tenOldest") Optional<Boolean> tenOldest,
+                              @RequestParam("firstName") Optional<String> firstName, Model model) {
+    List<Player> players;
+    if (tenYoungest.orElse(false)) {
+      players = playerRepository.getTenYoungest();
+    } else if (tenOldest.orElse(false)) {
+      players = playerRepository.getTenOldest();
+    } else if (firstName.isPresent()) {
+      players = playerRepository.findByFirstNameContaining(firstName.get());
+      model.addAttribute("firstName", firstName.get());
+    } else {
+      players = playerRepository.findAll();
+    }
+    model.addAttribute("players", players);
+    return "players";
+  }
+
+
+  @GetMapping("/scoresTable")
+  public String getAll(@RequestParam Optional<Boolean> lastTen, @RequestParam Optional<Boolean> topTen,
+                       @RequestParam Optional<String> name, Model model) {
+    List<Score> scores;
+    if (lastTen.orElse(false)) {
+      scores = scoreRepository.getLastTen();
+    } else if (topTen.orElse(false)) {
+      scores = scoreRepository.getTopTen();
+    } else if (name.isPresent()) {
+      scores = scoreRepository.findByNameContaining(name.get());
+      model.addAttribute("name", name.get());
+    } else {
+      scores = scoreRepository.findAll();
+    }
+    model.addAttribute("scores", scores);
+    return "scores";
+  }
+
+  @GetMapping("/raw-rest")
+  public String rawRest() {
+    return "raw-rest";
+  }
+
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab08/controllers/PlayerRestController.java b/src/main/java/cz/vsb/fei/java2/lab08/controllers/PlayerRestController.java
new file mode 100644
index 0000000000000000000000000000000000000000..1b3bf564c4a5ed4466fd0f33867f82d91bc9f44b
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab08/controllers/PlayerRestController.java
@@ -0,0 +1,92 @@
+package cz.vsb.fei.java2.lab08.controllers;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import cz.vsb.fei.java2.lab08.entities.Player;
+import cz.vsb.fei.java2.lab08.repositories.PlayerRepository;
+import jakarta.annotation.PostConstruct;
+
+@RestController
+@RequestMapping("players")
+public class PlayerRestController {
+
+	@Autowired
+	private PlayerRepository playerRepository;
+
+	@GetMapping(path = { "", "/" })
+	public List<Player> getAll(@RequestParam Optional<Boolean> tenYoungest, @RequestParam Optional<Boolean> tenOldest,
+			@RequestParam Optional<String> firstName) {
+		if(tenYoungest.orElse(false)) {
+			return playerRepository.getTenYoungest();
+		}
+		if(tenOldest.orElse(false)) {
+			return playerRepository.getTenOldest();
+		}
+		if(firstName.isPresent()) {
+			return playerRepository.findByFirstNameContaining(firstName.get());
+		}
+		return playerRepository.findAll();
+	}
+
+	@PostConstruct
+	private void init() {
+		if (playerRepository.findAll().isEmpty()) {
+			generate();
+		}
+	}
+
+	@GetMapping("/generate")
+	public ResponseEntity<Player> generate() {
+		Stream.generate(Player::generate).limit(10).forEach(playerRepository::save);
+		return new ResponseEntity<>(HttpStatus.OK);
+	}
+
+	@GetMapping("/{id}")
+	public Player getById(@PathVariable("id") long id) {
+		return playerRepository.findById(id).get();
+	}
+
+	@DeleteMapping("/{id}")
+	public ResponseEntity<Player> delete(@PathVariable("id") long id) {
+		playerRepository.deleteById(id);
+		return new ResponseEntity<>(HttpStatus.OK);
+	}
+
+	@DeleteMapping(path = { "", "/" })
+	public ResponseEntity<String> delete(@RequestParam Optional<Boolean> tenOldest) {
+		if (!tenOldest.isPresent() || !tenOldest.get().booleanValue()) {
+			return new ResponseEntity<>("Cannot delete all players.", HttpStatus.FORBIDDEN);
+		}
+		playerRepository.deleteTenOldest();
+		return new ResponseEntity<>("Successfuly deleted 10 oldest players.", HttpStatus.OK);
+	}
+
+	@PostMapping("/")
+	public ResponseEntity<Player> insertNew(@RequestBody Player player) {
+		player.setId(null);
+		player = playerRepository.save(player);
+		return new ResponseEntity<>(player, HttpStatus.CREATED);
+	}
+
+	@PutMapping("/{id}")
+	public ResponseEntity<Player> update(@PathVariable("id") long id, @RequestBody Player player) {
+		player.setId(id);
+		playerRepository.save(player);
+		return new ResponseEntity<>(HttpStatus.OK);
+	}
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab08/controllers/ScoreRestController.java b/src/main/java/cz/vsb/fei/java2/lab08/controllers/ScoreRestController.java
new file mode 100644
index 0000000000000000000000000000000000000000..b393f15db0a710ecf4ee14c54315d7ea2fe37b1c
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab08/controllers/ScoreRestController.java
@@ -0,0 +1,93 @@
+package cz.vsb.fei.java2.lab08.controllers;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import cz.vsb.fei.java2.lab08.entities.Score;
+import cz.vsb.fei.java2.lab08.repositories.ScoreRepository;
+import jakarta.annotation.PostConstruct;
+
+@RestController
+@RequestMapping("scores")
+public class ScoreRestController {
+
+	@Autowired
+	private ScoreRepository scoreRepository;
+
+	@PostConstruct
+	private void init() {
+		if (scoreRepository.findAll().isEmpty()) {
+			generate();
+		}
+	}
+
+	@GetMapping(path = { "", "/" })
+	public List<Score> getAll(@RequestParam Optional<Boolean> lastTen, @RequestParam Optional<Boolean> topTen,
+			@RequestParam Optional<String> name) {
+		if (lastTen.orElse(false)) {
+			return scoreRepository.getLastTen();
+		}
+		if (topTen.orElse(false)) {
+			return scoreRepository.getTopTen();
+		}
+		if (name.isPresent()) {
+			return scoreRepository.findByNameContaining(name.get());
+		}
+		return scoreRepository.findAll();
+	}
+
+	@GetMapping("/generate")
+	public ResponseEntity<Score> generate() {
+		Stream.generate(Score::generate).limit(10).forEach(scoreRepository::save);
+		return new ResponseEntity<>(HttpStatus.OK);
+	}
+
+	@GetMapping("/{id}")
+	public Score getById(@PathVariable("id") long id) {
+		return scoreRepository.findById(id).get();
+	}
+
+	@DeleteMapping("/{id}")
+	public ResponseEntity<Score> delete(@PathVariable("id") long id) {
+		scoreRepository.deleteById(id);
+		return new ResponseEntity<>(HttpStatus.OK);
+	}
+
+	@DeleteMapping(path = { "", "/" })
+	public ResponseEntity<String> delete(@RequestParam Optional<Boolean> lastTen) {
+		if (!lastTen.isPresent() || !lastTen.get().booleanValue()) {
+			return new ResponseEntity<>("Cannot delete all scores.", HttpStatus.FORBIDDEN);
+		}
+		scoreRepository.deleteLastTen();
+		return new ResponseEntity<>("Successfuly deleted last ten scores.", HttpStatus.OK);
+	}
+
+	@PostMapping(path = { "", "/" })
+	public ResponseEntity<Score> insertNew(@RequestBody Score score) {
+		score.setId(null);
+		score = scoreRepository.save(score);
+		return new ResponseEntity<>(score, HttpStatus.CREATED);
+	}
+
+	@PutMapping("/{id}")
+	public ResponseEntity<Score> update(@PathVariable("id") long id, @RequestBody Score score) {
+		score.setId(id);
+		scoreRepository.save(score);
+		return new ResponseEntity<>(HttpStatus.OK);
+	}
+
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab08/entities/Player.java b/src/main/java/cz/vsb/fei/java2/lab08/entities/Player.java
new file mode 100644
index 0000000000000000000000000000000000000000..8373d37bd1d801c61908765ba7aa4273ca96e41f
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab08/entities/Player.java
@@ -0,0 +1,41 @@
+package cz.vsb.fei.java2.lab08.entities;
+
+import java.time.LocalDate;
+
+import cz.vsb.fei.java2.lab08.Tools;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@Entity
+@NoArgsConstructor
+public class Player {
+	
+	@Id
+	@GeneratedValue(strategy = GenerationType.AUTO)
+	private Long id;
+	
+	private String firstName;
+	private String lastName;
+	private LocalDate dayOfBirth;
+
+	public Player(String firstName, String lastName, LocalDate dayOfBirth) {
+		this.firstName = firstName;
+		this.lastName = lastName;
+		this.dayOfBirth = dayOfBirth;
+	}
+	
+	public static Player generate() {
+		return new Player(
+				Tools.randomFistName(),
+				Tools.randomLastName(),
+				Tools.randomPreviousDate());
+	}
+
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab08/entities/Score.java b/src/main/java/cz/vsb/fei/java2/lab08/entities/Score.java
new file mode 100644
index 0000000000000000000000000000000000000000..e1a80e2a5027fe6e039057e1e195839600bb308d
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab08/entities/Score.java
@@ -0,0 +1,44 @@
+package cz.vsb.fei.java2.lab08.entities;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonBackReference;
+import com.fasterxml.jackson.annotation.JsonIdentityInfo;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonManagedReference;
+import com.fasterxml.jackson.annotation.ObjectIdGenerators;
+
+import cz.vsb.fei.java2.lab08.Tools;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.ManyToOne;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@Entity
+@NoArgsConstructor
+public class Score {
+	
+	@Id
+	@GeneratedValue(strategy = GenerationType.AUTO)
+	private Long id;
+	private String name;
+	private int points;
+
+	public Score(String name, int points) {
+		super();
+		this.name = name;
+		this.points = points;
+	}
+
+	public static Score generate() {
+		return new Score(Tools.randomNick() ,Tools.RANDOM.nextInt(100, 800));
+	}
+
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab08/repositories/PlayerCustomRepository.java b/src/main/java/cz/vsb/fei/java2/lab08/repositories/PlayerCustomRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..a61863e3f6a885416f729a2edf8f4883da32fb50
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab08/repositories/PlayerCustomRepository.java
@@ -0,0 +1,12 @@
+package cz.vsb.fei.java2.lab08.repositories;
+
+import java.util.List;
+
+import cz.vsb.fei.java2.lab08.entities.Player;
+
+public interface PlayerCustomRepository {
+	
+	public List<Player> getTenOldest();
+	public void deleteTenOldest();
+
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab08/repositories/PlayerCustomRepositoryImpl.java b/src/main/java/cz/vsb/fei/java2/lab08/repositories/PlayerCustomRepositoryImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..db9fb1c88bcf21c1b50c329687ec16fd2d7d5933
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab08/repositories/PlayerCustomRepositoryImpl.java
@@ -0,0 +1,37 @@
+package cz.vsb.fei.java2.lab08.repositories;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+import cz.vsb.fei.java2.lab08.entities.Player;
+import cz.vsb.fei.java2.lab08.entities.Player_;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.criteria.CriteriaBuilder;
+import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.Root;
+import jakarta.transaction.Transactional;
+
+public class PlayerCustomRepositoryImpl implements PlayerCustomRepository {
+
+	@Autowired
+	private EntityManager em;
+
+	@Override
+	public List<Player> getTenOldest() {
+		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
+		CriteriaQuery<Player> query = criteriaBuilder.createQuery(Player.class);
+		Root<Player> root = query.from(Player.class);
+		query.orderBy(criteriaBuilder.asc(root.get(Player_.dayOfBirth)));
+		return em.createQuery(query).setMaxResults(10).getResultList();
+	}
+
+	@Override
+	@Transactional
+	public void deleteTenOldest() {
+		List<Player> scores = em.createQuery("select p from Player p order by p.dayOfBirth asc", Player.class)
+				.setMaxResults(10).getResultList();
+		scores.forEach(em::remove);
+	}
+
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab08/repositories/PlayerRepository.java b/src/main/java/cz/vsb/fei/java2/lab08/repositories/PlayerRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..d00be1974607143d7d503b460765484edb5758a7
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab08/repositories/PlayerRepository.java
@@ -0,0 +1,18 @@
+package cz.vsb.fei.java2.lab08.repositories;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import cz.vsb.fei.java2.lab08.entities.Player;
+
+@Repository
+public interface PlayerRepository extends JpaRepository<Player, Long>, PlayerCustomRepository {
+
+	@Query("select p from Player p order by p.dayOfBirth desc limit 10")
+	public List<Player> getTenYoungest();
+	
+	public List<Player> findByFirstNameContaining(String firstName);
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab08/repositories/ScoreCustomRepository.java b/src/main/java/cz/vsb/fei/java2/lab08/repositories/ScoreCustomRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..af57d628b2561b1c549557aa30e3f99aa4b359d8
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab08/repositories/ScoreCustomRepository.java
@@ -0,0 +1,12 @@
+package cz.vsb.fei.java2.lab08.repositories;
+
+import java.util.List;
+
+import cz.vsb.fei.java2.lab08.entities.Score;
+
+public interface ScoreCustomRepository {
+	
+	public List<Score> getTopTen();
+	public void deleteLastTen();
+
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab08/repositories/ScoreCustomRepositoryImpl.java b/src/main/java/cz/vsb/fei/java2/lab08/repositories/ScoreCustomRepositoryImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..40584ddd785a8c3b20da5f7e125dd03d07a12e93
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab08/repositories/ScoreCustomRepositoryImpl.java
@@ -0,0 +1,38 @@
+package cz.vsb.fei.java2.lab08.repositories;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+import cz.vsb.fei.java2.lab08.entities.Score;
+import cz.vsb.fei.java2.lab08.entities.Score_;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.criteria.CriteriaBuilder;
+import jakarta.persistence.criteria.CriteriaDelete;
+import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.Root;
+import jakarta.transaction.Transactional;
+
+public class ScoreCustomRepositoryImpl implements ScoreCustomRepository {
+
+	@Autowired
+	private EntityManager em;
+
+	@Override
+	public List<Score> getTopTen() {
+		CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
+		CriteriaQuery<Score> query = criteriaBuilder.createQuery(Score.class);
+		Root<Score> root = query.from(Score.class);
+		query.orderBy(criteriaBuilder.desc(root.get(Score_.points)));
+		return em.createQuery(query).setMaxResults(10).getResultList();
+	}
+
+	@Override
+	@Transactional
+	public void deleteLastTen() {
+		List<Score> scores = em.createQuery("select s from Score s order by s.points asc", Score.class)
+				.setMaxResults(10).getResultList();
+		scores.forEach(em::remove);
+	}
+
+}
diff --git a/src/main/java/cz/vsb/fei/java2/lab08/repositories/ScoreRepository.java b/src/main/java/cz/vsb/fei/java2/lab08/repositories/ScoreRepository.java
new file mode 100644
index 0000000000000000000000000000000000000000..18f3a50be9b753657416add528b5a2f430cf24c5
--- /dev/null
+++ b/src/main/java/cz/vsb/fei/java2/lab08/repositories/ScoreRepository.java
@@ -0,0 +1,19 @@
+package cz.vsb.fei.java2.lab08.repositories;
+
+import java.util.List;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import cz.vsb.fei.java2.lab08.entities.Score;
+
+@Repository
+public interface ScoreRepository extends JpaRepository<Score, Long>, ScoreCustomRepository {
+
+	@Query("select s from Score s order by s.points asc limit 10")
+	public List<Score> getLastTen();
+	
+	public List<Score> findByNameContaining(String name);
+	
+}
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c115ad44bf374ef6c29e69eb9f826532b88508fe
--- /dev/null
+++ b/src/main/resources/application.yaml
@@ -0,0 +1,5 @@
+spring:
+  thymeleaf:
+    cache: false
+  application:
+    name: "java2-rest-server"
diff --git a/src/main/resources/static/JavaDukeWaving.svg b/src/main/resources/static/JavaDukeWaving.svg
new file mode 100644
index 0000000000000000000000000000000000000000..88133dccf0ae925c765795cde2763531305b8e46
--- /dev/null
+++ b/src/main/resources/static/JavaDukeWaving.svg
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 14948)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="225.938px" height="407.407px" viewBox="0 0 225.938 407.407" enable-background="new 0 0 225.938 407.407"
+	 xml:space="preserve">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M48.859,43.518c8.424,17.64,2.736,140.832-7.128,184.032
+	c-9.864,43.272-19.728,98.28-22.032,144.576c-1.008,19.728,2.016,27.504,14.904,27.504c22.752,0,51.624-47.952,87.84-46.872
+	c36.288,1.08,47.808,55.008,64.8,54.648c16.992-0.36,30.672-6.264,30.816-58.752C218.563,191.981,87.235,64.973,48.859,43.518
+	L48.859,43.518L48.859,43.518L48.859,43.518z"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M162.763,168.726c7.992,13.464,28.368,3.096,29.232-12.096
+	c0.864-15.192-1.368-34.344-11.232-35.064c-9.864-0.72-16.92-10.584-26.784-11.304c-9.864-0.72-20.448,9.144-25.056-3.96
+	s12.384-18.648,25.056-20.736c-11.304-11.304-17.928-23.832-22.896-36.864c-4.968-13.032-8.64-24.984,5.256-30.096
+	c13.896-5.112,12.744,21.168,28.656,33.192c-4.68-17.712-6.408-25.056-6.048-35.352s-0.36-18.144,14.256-16.128
+	c14.616,2.016,8.28,32.4,19.656,44.784c3.456-11.736,5.544-26.64,13.896-32.76s27.36-6.264,15.264,18.864
+	c-12.096,25.128,3.528,38.736-0.144,58.536c-3.672,19.8-15.048,16.2-19.944,28.944c-4.896,12.744,2.88,41.76-6.336,54.792
+	c-9.216,13.032-10.872,33.048-4.896,49.032C172.339,205.374,162.763,168.726,162.763,168.726L162.763,168.726L162.763,168.726
+	L162.763,168.726z"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M48.355,185.646c-7.416,50.832-33.192,56.88-34.488,77.976
+	c-1.296,21.096,6.84,23.112,6.336,42.624c-0.504,19.512-17.856,27.432-19.944,38.016s8.928,13.968,15.336,13.968
+	c6.408,0,12.816-28.08,15.408-45.936s-8.496-28.368-8.496-40.608c0-12.24,16.056-34.632,13.104-14.976
+	C48.931,235.686,55.268,208.901,48.355,185.646L48.355,185.646L48.355,185.646L48.355,185.646z"/>
+<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M58.292,205.013c-5.616,27.504-40.68,181.08-22.824,183.024
+	c17.856,1.944,43.272-47.52,84.888-47.16c41.688,0.36,58.104,55.44,68.256,55.08c10.152-0.36,16.848,3.6,17.928-58.464
+	c1.08-62.064-36.792-141.336-59.184-176.256C116.971,163.181,84.283,187.518,58.292,205.013L58.292,205.013L58.292,205.013
+	L58.292,205.013z"/>
+<g>
+	<path fill="none" d="M139.162,172.181c-1.95-18.251-19.12-25.421-35.661-23.168c-13.889,1.893-32.403,13.613-34.107,28.64
+		c-1.921,16.937,11.402,32.522,28.361,33.203c15.03,0.604,31.176-6.668,37.93-20.79
+		C138.415,184.362,139.482,178.488,139.162,172.181"/>
+	<path d="M147.082,171.533c-1.662-17.195-14.407-27.988-30.895-30.627c-15.924-2.549-33.26,4.998-44.408,16.146
+		c-12.538,12.538-13.039,29.978-4.26,44.833c8.661,14.657,27.847,19.501,43.563,15.835
+		C132.588,212.705,148.48,193.896,147.082,171.533"/>
+	<radialGradient id="SVGID_1_" cx="86.6299" cy="167.0693" r="54.7155" gradientUnits="userSpaceOnUse">
+		<stop  offset="0" style="stop-color:#FFFFFF"/>
+		<stop  offset="0.0604" style="stop-color:#FBC8B4"/>
+		<stop  offset="0.0712" style="stop-color:#FBC3B0"/>
+		<stop  offset="0.1829" style="stop-color:#F7978B"/>
+		<stop  offset="0.2995" style="stop-color:#F4716B"/>
+		<stop  offset="0.4199" style="stop-color:#F15251"/>
+		<stop  offset="0.5453" style="stop-color:#EF3A3D"/>
+		<stop  offset="0.6778" style="stop-color:#EE292F"/>
+		<stop  offset="0.822" style="stop-color:#ED1F27"/>
+		<stop  offset="1" style="stop-color:#ED1C24"/>
+	</radialGradient>
+	<path fill="url(#SVGID_1_)" stroke="#000000" d="M139.162,177.941c-1.493,15.627-13.947,28.182-28.944,31.824
+		c-15.87,3.854-33.393-2.257-39.096-18.576c-2.912-8.332-2.37-16.879,2.637-24.198c4.223-6.171,11.033-11,17.779-14.066
+		c13.924-6.326,33.832-7.029,43.531,7.077C138.744,165.348,139.387,171.641,139.162,177.941"/>
+</g>
+</svg>
diff --git a/src/main/resources/static/favicon.ico b/src/main/resources/static/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..cafa0a85d2544375e95df2e3d24303494cdae7a9
Binary files /dev/null and b/src/main/resources/static/favicon.ico differ
diff --git a/src/main/resources/templates/common.html b/src/main/resources/templates/common.html
new file mode 100644
index 0000000000000000000000000000000000000000..8a33302cc10dcbec53e135c362d79383e8bebef6
--- /dev/null
+++ b/src/main/resources/templates/common.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+
+<html xmlns:th="http://www.thymeleaf.org">
+<head>
+	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
+	<title>Person - Score Demo</title>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+</head>
+
+  <body>
+  
+	<div th:fragment="menu">
+		<nav class="navbar navbar-dark bg-primary navbar-expand-lg">
+			<div class="container-fluid">
+				<a class="navbar-brand" href="#"><img src="JavaDukeWaving.svg" alt="Java"  class="d-inline-block align-text-top" style="height: 1em;margin: 5px">
+					Demo</a>
+				<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
+					<span class="navbar-toggler-icon"></span>
+				</button>
+				<div class="collapse navbar-collapse" id="navbarSupportedContent">
+					<ul class="navbar-nav me-auto mb-2 mb-lg-0">
+						<li class="nav-item active">
+							<a class="nav-link" href="playersTable">Persons<span class="sr-only">(current)</span></a>
+						</li>
+						<li class="nav-item">
+							<a class="nav-link" href="scoresTable">Scores</a>
+						</li>
+						<li class="nav-item">
+							<a class="nav-link" href="raw-rest">RAW REST</a>
+						</li>
+						<li class="nav-item">
+							<a class="nav-link" href="/swagger-ui/index.html">Swagger UI</a>
+						</li>
+					</ul>
+				</div>
+			</div>
+		</nav>
+	</div>
+
+	</body>
+
+</html>
\ No newline at end of file
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..8b6329bf0490606bfb09d7fbb781456570976cc5
--- /dev/null
+++ b/src/main/resources/templates/index.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+
+<html xmlns:th="http://www.thymeleaf.org">
+
+  <head>
+	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
+    <title>Person Score Demo</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+  </head>
+
+  <body>
+    <div th:include="common :: menu">
+    </div>
+    <p th:text="#{home.welcome}">Welcome to our grocery store!</p>
+	<i class="fa-solid fa-thumbs-up fa-5x"></i>
+	<script src="https://kit.fontawesome.com/8c1b7edae9.js" crossorigin="anonymous"></script>
+	<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
+
+  </body>
+
+</html>
\ No newline at end of file
diff --git a/src/main/resources/templates/players.html b/src/main/resources/templates/players.html
new file mode 100644
index 0000000000000000000000000000000000000000..dbc755c737137e54bb33a3c1d7b3f1bebbcab9fa
--- /dev/null
+++ b/src/main/resources/templates/players.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+
+<html xmlns:th="http://www.thymeleaf.org">
+
+<head>
+  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
+        integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
+  <title>List of Persosn</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+
+<body>
+<div th:include="common :: menu">
+</div>
+
+<h2>List of Players</h2>
+<a class="btn btn-primary m-1" onclick="fetch('/players/generate').then((res) => window.location.reload(true))">
+  <i class="fa-solid fa-users-gear"></i> Generate next 10
+</a>
+<a class="btn btn-primary m-1" href="/playersTable?tenYoungest=true">
+  <i class="fa-solid fa-seedling"></i> Ten Youngest
+</a>
+<a class="btn btn-primary m-1" href="/playersTable?tenOldest=true">  <i class="fa-solid fa-tree"></i> Ten Oldest
+</a>
+<a class="btn btn-primary m-1" href="/playersTable">
+  <i class="fa-solid fa-person-dots-from-line"></i> All
+</a>
+<br/>
+<form method="get" target="scoresTable" class="row g-3">
+  <div class="col-auto">
+    <label for="firstName" class="col-sm-2 col-form-label m-1 text-nowrap">First Name</label>
+  </div>
+  <div class="col-auto">
+    <input type="text" class="form-control m-1" id="firstName" name="firstName" placeholder="partial name" th:value="${firstName}"/>
+  </div>
+  <div class="col-auto">
+    <button type="submit" class="btn btn-primary m-1"><i class="fa-solid fa-magnifying-glass"></i> Search</button>
+  </div>
+</form>
+
+<table class="table table-striped table-bordered">
+  <thead>
+  <tr class="table-primary">
+    <th>ID</th>
+    <th>First Name</th>
+    <th>Last Name</th>
+  </tr>
+  </thead>
+  <tbody>
+  <tr th:each="player : ${players}">
+    <td th:text="${player.id}"></td>
+    <td th:text="${player.firstName}"></td>
+    <td th:text="${player.lastName}"></td>
+    <td th:text="${player.dayOfBirth}"></td>
+  </tr>
+  </tbody>
+</table>
+<script src="https://kit.fontawesome.com/8c1b7edae9.js" crossorigin="anonymous"></script>
+<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
+        integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
+        crossorigin="anonymous"></script>
+
+</body>
+
+</html>
\ No newline at end of file
diff --git a/src/main/resources/templates/raw-rest.html b/src/main/resources/templates/raw-rest.html
new file mode 100644
index 0000000000000000000000000000000000000000..827c3cdc6b88523172719021aba6f8251679fb1d
--- /dev/null
+++ b/src/main/resources/templates/raw-rest.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+
+<html xmlns:th="http://www.thymeleaf.org">
+
+<head>
+  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
+        integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
+  <title>raw REST api</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+
+<body>
+<div th:include="common :: menu">
+</div>
+
+<h2>RAW REST API</h2>
+<a href="/players">/players</a><br/>
+<a href="/players/1">/players/1</a><br/>
+<a href="/players?tenYoungest=true">/players?tenYoungest=true</a><br/>
+<a href="/players?tenOldest=true">/players?tenOldest=true</a><br/>
+<a href="/players?firstName=v">/players?firstName=v</a><br/>
+<a href="/players/generate">/players/generate</a><br/>
+<br/>
+<a href="/scores">/scores</a><br/>
+<a href="/scores/1">/scores/1</a><br/>
+<a href="/scores?lastTen=true">/scores?lastTen=true</a><br/>
+<a href="/scores?topTen=true">/scores?topTen=true</a><br/>
+<a href="/scores?name=v">/scores?name=v</a><br/>
+<a href="/scores/generate">/players/generate</a><br/>
+
+<script src="https://kit.fontawesome.com/8c1b7edae9.js" crossorigin="anonymous"></script>
+<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
+        integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
+        crossorigin="anonymous"></script>
+
+</body>
+
+</html>
\ No newline at end of file
diff --git a/src/main/resources/templates/scores.html b/src/main/resources/templates/scores.html
new file mode 100644
index 0000000000000000000000000000000000000000..3c65da5474ebbb4047d3680be105da46ae47fd40
--- /dev/null
+++ b/src/main/resources/templates/scores.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+
+<html xmlns:th="http://www.thymeleaf.org">
+
+<head>
+  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
+        integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
+  <title>List of Persosn</title>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+</head>
+
+<body>
+<div th:include="common :: menu">
+</div>
+
+<h2>List of Scores</h2>
+<a class="btn btn-primary m-1" onclick="fetch('/scores/generate').then((res) => window.location.reload(true))">
+  <i class="fa-solid fa-users-gear"></i> Generate next 10
+</a>
+<a class="btn btn-primary m-1" href="/scoresTable?topTen=true">
+  <i class="fa-solid fa-trophy"></i> Ten Higest
+</a>
+<a class="btn btn-primary m-1" href="/scoresTable?lastTen=true"> <i class="fa-solid fa-thumbs-down"></i> Ten Smallest
+</a>
+<a class="btn btn-primary m-1" href="/scoresTable">
+  <i class="fa-solid fa-person-dots-from-line"></i> All
+</a>
+<br/>
+<form method="get" target="scoresTable" class="row g-3">
+  <div class="col-auto">
+    <label for="name" class="col-sm-2 col-form-label m-1">Name</label>
+  </div>
+  <div class="col-auto">
+    <input type="text" class="form-control m-1" id="name" name="name" placeholder="partial name" th:value="${name}"/>
+  </div>
+  <div class="col-auto">
+    <button type="submit" class="btn btn-primary m-1"><i class="fa-solid fa-magnifying-glass"></i> Search</button>
+  </div>
+</form>
+<table class="table table-striped table-bordered">
+  <thead>
+  <tr class="table-primary">
+    <th>ID</th>
+    <th>First Name</th>
+    <th>Last Name</th>
+  </tr>
+  </thead>
+  <tbody>
+  <tr th:each="score : ${scores}">
+    <td th:text="${score.id}"></td>
+    <td th:text="${score.name}"></td>
+    <td th:text="${score.points}"></td>
+  </tr>
+  </tbody>
+</table>
+<script src="https://kit.fontawesome.com/8c1b7edae9.js" crossorigin="anonymous"></script>
+<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
+        integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
+        crossorigin="anonymous"></script>
+
+</body>
+
+</html>
\ No newline at end of file
diff --git a/src/test/java/jez04/structure/test/ClassStructureTest.java b/src/test/java/jez04/structure/test/ClassStructureTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e31655678705c92601647e148c4088bb9bc670a2
--- /dev/null
+++ b/src/test/java/jez04/structure/test/ClassStructureTest.java
@@ -0,0 +1,47 @@
+package jez04.structure.test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.net.URISyntaxException;
+
+import org.hamcrest.Matchers;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+import cz.vsb.fei.kelvin.unittest.TextFileContains;
+
+class ClassStructureTest {
+
+	// @formatter:off
+	@ParameterizedTest
+	@CsvSource({
+		".*\\.java,@RestController,2",
+		".*\\.java,@GetMapping,4",
+		".*\\.java,@PostMapping,2",
+		".*\\.java,@PutMapping,2",
+		".*\\.java,@DeleteMapping,2",
+		".*\\.java,@Autowire,2",
+		".*\\.java,@PathVariable,4",
+		".*\\.java,@Repository,2",
+		".*\\.java,@Entity,2",
+		".*\\.java,@OneToMany\\(mappedBy,1",
+		".*\\.java,@ManyToOne,1",
+		".*\\.java,JpaRepository,2",
+		".*\\.java,@SpringBootApplication,1"
+	})
+	// @formatter:on
+	void anotaceTest(String file, String annotation, int count) throws URISyntaxException {
+		assertThat(TextFileContains.getProjectRoot(getClass()), new TextFileContains(file, annotation).useRegExpForName(true).count(count));
+	}
+
+	// @formatter:off
+	@ParameterizedTest
+	@CsvSource({
+		"spring-boot-starter-parent",
+	})
+	// @formatter:on
+	void pomXmlTest(String text) throws URISyntaxException {
+		assertThat(TextFileContains.getProjectRoot(getClass()), new TextFileContains("pom.xml", text));
+	}
+	
+}