diff --git a/service-chats/.dockerignore b/service-chats/.dockerignore
new file mode 100644
index 0000000..94810d0
--- /dev/null
+++ b/service-chats/.dockerignore
@@ -0,0 +1,5 @@
+*
+!target/*-runner
+!target/*-runner.jar
+!target/lib/*
+!target/quarkus-app/*
\ No newline at end of file
diff --git a/service-chats/.gitignore b/service-chats/.gitignore
new file mode 100644
index 0000000..bdf57ce
--- /dev/null
+++ b/service-chats/.gitignore
@@ -0,0 +1,39 @@
+#Maven
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+release.properties
+
+# Eclipse
+.project
+.classpath
+.settings/
+bin/
+
+# IntelliJ
+.idea
+*.ipr
+*.iml
+*.iws
+
+# NetBeans
+nb-configuration.xml
+
+# Visual Studio Code
+.vscode
+.factorypath
+
+# OSX
+.DS_Store
+
+# Vim
+*.swp
+*.swo
+
+# patch
+*.orig
+*.rej
+
+# Local environment
+.env
diff --git a/service-chats/README.md b/service-chats/README.md
new file mode 100644
index 0000000..2a23a0f
--- /dev/null
+++ b/service-chats/README.md
@@ -0,0 +1,59 @@
+# service-chats Project
+
+This project uses Quarkus, the Supersonic Subatomic Java Framework.
+
+If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ .
+
+## Running the application in dev mode
+
+You can run your application in dev mode that enables live coding using:
+```shell script
+./mvnw compile quarkus:dev
+```
+
+> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at http://localhost:8080/q/dev/.
+
+## Packaging and running the application
+
+The application can be packaged using:
+```shell script
+./mvnw package
+```
+It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory.
+Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory.
+
+The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`.
+
+If you want to build an _über-jar_, execute the following command:
+```shell script
+./mvnw package -Dquarkus.package.type=uber-jar
+```
+
+The application, packaged as an _über-jar_, is now runnable using `java -jar target/*-runner.jar`.
+
+## Creating a native executable
+
+You can create a native executable using:
+```shell script
+./mvnw package -Pnative
+```
+
+Or, if you don't have GraalVM installed, you can run the native executable build in a container using:
+```shell script
+./mvnw package -Pnative -Dquarkus.native.container-build=true
+```
+
+You can then execute your native executable with: `./target/service-chats-1.0.0-SNAPSHOT-runner`
+
+If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.html.
+
+## Related Guides
+
+
+## Provided Code
+
+### RESTEasy Reactive
+
+Easily start your Reactive RESTful Web Services
+
+[Related guide section...](https://quarkus.io/guides/getting-started-reactive#reactive-jax-rs-resources)
diff --git a/service-chats/pom.xml b/service-chats/pom.xml
new file mode 100644
index 0000000..9ecd039
--- /dev/null
+++ b/service-chats/pom.xml
@@ -0,0 +1,176 @@
+
+
+ 4.0.0
+ it.volvox.service-chats
+ service-chats
+ 1.0.0-SNAPSHOT
+
+ 3.8.1
+ true
+ 17
+ 17
+ UTF-8
+ UTF-8
+ quarkus-bom
+ io.quarkus.platform
+ 2.4.1.Final
+ 3.0.0-M5
+ 2.7.9.2
+ 4.0.183
+
+
+
+ mchv
+ MCHV Apache Maven Packages
+ https://mvn.mchv.eu/repository/mchv/
+
+
+
+
+
+ ${quarkus.platform.group-id}
+ ${quarkus.platform.artifact-id}
+ ${quarkus.platform.version}
+ pom
+ import
+
+
+ it.tdlight
+ tdlight-java
+ ${volvox.tdlight.version}
+
+
+ it.tdlight
+ tdlight-natives-linux-amd64
+ ${volvox.tdlight.natives.version}
+
+
+
+
+
+ io.quarkus
+ quarkus-reactive-pg-client
+
+
+ io.quarkus
+ quarkus-smallrye-openapi
+
+
+ io.quarkus
+ quarkus-resteasy-reactive-jackson
+
+
+ io.quarkus
+ quarkus-hibernate-reactive-panache
+
+
+ io.quarkus
+ quarkus-hibernate-validator
+
+
+ io.quarkus
+ quarkus-arc
+
+
+ io.quarkus
+ quarkus-resteasy-reactive
+
+
+
+ io.quarkus
+ quarkus-junit5
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+
+ it.tdlight
+ tdlight-java
+
+
+ it.tdlight
+ tdlight-natives-linux-amd64
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+
+
+ ${quarkus.platform.group-id}
+ quarkus-maven-plugin
+ ${quarkus.platform.version}
+ true
+
+
+
+ build
+ generate-code
+ generate-code-tests
+
+
+
+
+
+ maven-compiler-plugin
+ ${compiler-plugin.version}
+
+ ${maven.compiler.parameters}
+
+
+
+ maven-surefire-plugin
+ ${surefire-plugin.version}
+
+
+ org.jboss.logmanager.LogManager
+ ${maven.home}
+
+
+
+
+
+
+
+ native
+
+
+ native
+
+
+
+
+
+ maven-failsafe-plugin
+ ${surefire-plugin.version}
+
+
+
+ integration-test
+ verify
+
+
+
+ ${project.build.directory}/${project.build.finalName}-runner
+ org.jboss.logmanager.LogManager
+ ${maven.home}
+
+
+
+
+
+
+
+
+ native
+
+
+
+
diff --git a/service-chats/src/main/docker/Dockerfile.jvm b/service-chats/src/main/docker/Dockerfile.jvm
new file mode 100644
index 0000000..404ec8e
--- /dev/null
+++ b/service-chats/src/main/docker/Dockerfile.jvm
@@ -0,0 +1,55 @@
+####
+# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
+#
+# Before building the container image run:
+#
+# ./mvnw package
+#
+# Then, build the image with:
+#
+# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/service-chats-jvm .
+#
+# Then run the container using:
+#
+# docker run -i --rm -p 8080:8080 quarkus/service-chats-jvm
+#
+# If you want to include the debug port into your docker image
+# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005
+#
+# Then run the container using :
+#
+# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/service-chats-jvm
+#
+###
+FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4
+
+ARG JAVA_PACKAGE=java-11-openjdk-headless
+ARG RUN_JAVA_VERSION=1.3.8
+ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
+# Install java and the run-java script
+# Also set up permissions for user `1001`
+RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
+ && microdnf update \
+ && microdnf clean all \
+ && mkdir /deployments \
+ && chown 1001 /deployments \
+ && chmod "g+rwX" /deployments \
+ && chown 1001:root /deployments \
+ && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
+ && chown 1001 /deployments/run-java.sh \
+ && chmod 540 /deployments/run-java.sh \
+ && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/conf/security/java.security
+
+# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
+ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
+# We make four distinct layers so if there are application changes the library layers can be re-used
+COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/
+COPY --chown=1001 target/quarkus-app/*.jar /deployments/
+COPY --chown=1001 target/quarkus-app/app/ /deployments/app/
+COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/
+
+EXPOSE 8080
+USER 1001
+
+ENTRYPOINT [ "/deployments/run-java.sh" ]
+
diff --git a/service-chats/src/main/docker/Dockerfile.legacy-jar b/service-chats/src/main/docker/Dockerfile.legacy-jar
new file mode 100644
index 0000000..f8da1f8
--- /dev/null
+++ b/service-chats/src/main/docker/Dockerfile.legacy-jar
@@ -0,0 +1,51 @@
+####
+# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
+#
+# Before building the container image run:
+#
+# ./mvnw package -Dquarkus.package.type=legacy-jar
+#
+# Then, build the image with:
+#
+# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/service-chats-legacy-jar .
+#
+# Then run the container using:
+#
+# docker run -i --rm -p 8080:8080 quarkus/service-chats-legacy-jar
+#
+# If you want to include the debug port into your docker image
+# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5005
+#
+# Then run the container using :
+#
+# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/service-chats-legacy-jar
+#
+###
+FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4
+
+ARG JAVA_PACKAGE=java-11-openjdk-headless
+ARG RUN_JAVA_VERSION=1.3.8
+ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
+# Install java and the run-java script
+# Also set up permissions for user `1001`
+RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
+ && microdnf update \
+ && microdnf clean all \
+ && mkdir /deployments \
+ && chown 1001 /deployments \
+ && chmod "g+rwX" /deployments \
+ && chown 1001:root /deployments \
+ && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
+ && chown 1001 /deployments/run-java.sh \
+ && chmod 540 /deployments/run-java.sh \
+ && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/conf/security/java.security
+
+# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
+ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
+COPY target/lib/* /deployments/lib/
+COPY target/*-runner.jar /deployments/app.jar
+
+EXPOSE 8080
+USER 1001
+
+ENTRYPOINT [ "/deployments/run-java.sh" ]
diff --git a/service-chats/src/main/docker/Dockerfile.native b/service-chats/src/main/docker/Dockerfile.native
new file mode 100644
index 0000000..e17ee54
--- /dev/null
+++ b/service-chats/src/main/docker/Dockerfile.native
@@ -0,0 +1,27 @@
+####
+# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode
+#
+# Before building the container image run:
+#
+# ./mvnw package -Pnative
+#
+# Then, build the image with:
+#
+# docker build -f src/main/docker/Dockerfile.native -t quarkus/service-chats .
+#
+# Then run the container using:
+#
+# docker run -i --rm -p 8080:8080 quarkus/service-chats
+#
+###
+FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4
+WORKDIR /work/
+RUN chown 1001 /work \
+ && chmod "g+rwX" /work \
+ && chown 1001:root /work
+COPY --chown=1001:root target/*-runner /work/application
+
+EXPOSE 8080
+USER 1001
+
+CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
diff --git a/service-chats/src/main/docker/Dockerfile.native-distroless b/service-chats/src/main/docker/Dockerfile.native-distroless
new file mode 100644
index 0000000..b4b246c
--- /dev/null
+++ b/service-chats/src/main/docker/Dockerfile.native-distroless
@@ -0,0 +1,23 @@
+####
+# This Dockerfile is used in order to build a distroless container that runs the Quarkus application in native (no JVM) mode
+#
+# Before building the container image run:
+#
+# ./mvnw package -Pnative
+#
+# Then, build the image with:
+#
+# docker build -f src/main/docker/Dockerfile.native-distroless -t quarkus/service-chats .
+#
+# Then run the container using:
+#
+# docker run -i --rm -p 8080:8080 quarkus/service-chats
+#
+###
+FROM quay.io/quarkus/quarkus-distroless-image:1.0
+COPY target/*-runner /application
+
+EXPOSE 8080
+USER nonroot
+
+CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
diff --git a/service-chats/src/main/java/io/volvox/chats/Chat.java b/service-chats/src/main/java/io/volvox/chats/Chat.java
new file mode 100644
index 0000000..650fe51
--- /dev/null
+++ b/service-chats/src/main/java/io/volvox/chats/Chat.java
@@ -0,0 +1,23 @@
+package io.volvox.chats;
+
+import io.quarkus.hibernate.reactive.panache.PanacheEntityBase;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+@Entity
+public class Chat extends PanacheEntityBase {
+ @Id
+ public String id;
+
+ public String name;
+ public String username;
+ public Status status;
+
+ public ChatId getChatId() {
+ return new ChatId(id);
+ }
+
+ public void setChatId(ChatId id) {
+ this.id = id.toString();
+ }
+}
diff --git a/service-chats/src/main/java/io/volvox/chats/ChatId.java b/service-chats/src/main/java/io/volvox/chats/ChatId.java
new file mode 100644
index 0000000..9141d4d
--- /dev/null
+++ b/service-chats/src/main/java/io/volvox/chats/ChatId.java
@@ -0,0 +1,35 @@
+package io.volvox.chats;
+
+public record ChatId(Type type, long id) {
+ ChatId(String id) {
+ this(getType(id), getIdLong(id));
+ }
+
+ private static Type getType(String id) {
+ return switch (id.charAt(0)) {
+ case 's' -> Type.SUPER;
+ case 'b' -> Type.BASIC;
+ case 'u' -> Type.PRIVATE;
+ default -> throw new IllegalArgumentException();
+ };
+ }
+
+ private static long getIdLong(String id) {
+ return Long.parseUnsignedLong(id.substring(1));
+ }
+
+ public enum Type {
+ BASIC,
+ SUPER,
+ PRIVATE
+ }
+
+ @Override
+ public String toString() {
+ return switch (type) {
+ case SUPER -> 's';
+ case BASIC -> 'b';
+ case PRIVATE -> 'u';
+ } + Long.toUnsignedString(id);
+ }
+}
diff --git a/service-chats/src/main/java/io/volvox/chats/ChatRepository.java b/service-chats/src/main/java/io/volvox/chats/ChatRepository.java
new file mode 100644
index 0000000..69d6f33
--- /dev/null
+++ b/service-chats/src/main/java/io/volvox/chats/ChatRepository.java
@@ -0,0 +1,22 @@
+package io.volvox.chats;
+
+import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
+import io.smallrye.mutiny.Uni;
+import javax.enterprise.context.ApplicationScoped;
+import org.hibernate.annotations.NamedQueries;
+import org.hibernate.annotations.NamedQuery;
+
+@ApplicationScoped
+@NamedQueries({
+ @NamedQuery(name = "Chat.getByName", query = "from Chat where name = ?1"),
+ @NamedQuery(name = "Chat.getByUsername", query = "from Chat where username = ?1"),
+ @NamedQuery(name = "Chat.countByStatus", query = "select count(*) from Chat p where p.status = :status"),
+ @NamedQuery(name = "Chat.updateStatusById", query = "update Chat p set p.status = :status where p.id = :id"),
+ @NamedQuery(name = "Chat.deleteById", query = "delete from Chat p where p.id = ?1")
+})
+public class ChatRepository implements PanacheRepositoryBase {
+
+ public Uni findByUsername(String username) {
+ return find("#Chat.getByUsername", username).firstResult();
+ }
+}
diff --git a/service-chats/src/main/java/io/volvox/chats/ChatResource.java b/service-chats/src/main/java/io/volvox/chats/ChatResource.java
new file mode 100644
index 0000000..6871cfe
--- /dev/null
+++ b/service-chats/src/main/java/io/volvox/chats/ChatResource.java
@@ -0,0 +1,87 @@
+package io.volvox.chats;
+
+import io.quarkus.hibernate.reactive.panache.PanacheEntityBase;
+import io.smallrye.mutiny.Multi;
+import io.smallrye.mutiny.Uni;
+import java.net.URI;
+import javax.inject.Inject;
+import javax.transaction.Transactional;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("/api/chats")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class ChatResource {
+
+ @Inject
+ ChatRepository chatRepository;
+
+ @GET
+ public Multi listSessions() {
+ return Chat.streamAll();
+ }
+
+ @GET
+ @Path("/{id}")
+ public Uni get(@PathParam("id") String id) {
+ return Chat.findById(id);
+ }
+
+ @POST
+ @Transactional
+ public Uni create(Chat chat) {
+ return chat.persist()
+ // Return success
+ .replaceWith(() -> Response.created(URI.create("/api/" + chat.id)).build());
+ }
+
+ @PUT
+ @Path("/{id}")
+ @Transactional
+ public Uni update(@PathParam("id") String id, Chat chat) {
+ // Find chat by id
+ return Chat.findById(id)
+ .flatMap(entity -> {
+ if (entity == null) {
+ // Persist the chat if not found
+ return chat.persist();
+ } else {
+ // Update all fields
+ entity.name = chat.name;
+ // Return the updated item
+ return Uni.createFrom().item(entity);
+ }
+ });
+ }
+
+ @DELETE
+ @Path("/{id}")
+ @Transactional
+ public Uni delete(@PathParam("id") String id) {
+ return Chat.findById(id)
+ .onItem().ifNull().failWith(NotFoundException::new)
+ .flatMap(PanacheEntityBase::delete);
+ }
+
+ @GET
+ @Path("/search/{username}")
+ public Uni search(@PathParam("username") String username) {
+ return chatRepository.findByUsername(username);
+ }
+
+ @GET
+ @Path("/count")
+ public Uni count() {
+ return Chat.count();
+ }
+}
diff --git a/service-chats/src/main/java/io/volvox/chats/ChatsService.java b/service-chats/src/main/java/io/volvox/chats/ChatsService.java
new file mode 100644
index 0000000..a00875d
--- /dev/null
+++ b/service-chats/src/main/java/io/volvox/chats/ChatsService.java
@@ -0,0 +1,32 @@
+package io.volvox.chats;
+
+import io.quarkus.vertx.ConsumeEvent;
+import io.vertx.mutiny.core.eventbus.EventBus;
+import io.vertx.mutiny.core.eventbus.Message;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+@ApplicationScoped
+public class ChatsService {
+
+ @Inject
+ EventBus bus;
+
+ @Inject
+ ChatResource chatResource;
+
+ @ConsumeEvent(value = "chats.list")
+ public void listChats(Message msg) {
+ chatResource.listSessions().collect().asList().subscribe().with(msg::reply);
+ }
+
+ @ConsumeEvent(value = "chats.get")
+ public void get(Message msg) {
+ chatResource.get(msg.body()).subscribe().with(msg::reply);
+ }
+
+ @ConsumeEvent(value = "chats.update")
+ public void update(Message msg) {
+ chatResource.update(msg.body().id, msg.body()).subscribe().with(msg::reply);
+ }
+}
\ No newline at end of file
diff --git a/service-chats/src/main/java/io/volvox/chats/Status.java b/service-chats/src/main/java/io/volvox/chats/Status.java
new file mode 100644
index 0000000..b95809e
--- /dev/null
+++ b/service-chats/src/main/java/io/volvox/chats/Status.java
@@ -0,0 +1,7 @@
+package io.volvox.chats;
+
+public enum Status {
+ ALIVE,
+ DELETED,
+ UNKNOWN
+}
diff --git a/service-chats/src/main/resources/application.properties b/service-chats/src/main/resources/application.properties
new file mode 100644
index 0000000..e69de29