Add repository overview endpoint

This commit is contained in:
Fabian Wolter
2026-06-14 07:04:08 +00:00
parent 74ddd8eed7
commit ac9523c73c
9 changed files with 117 additions and 0 deletions
@@ -1,6 +1,7 @@
package de.ruvnox.tactical package de.ruvnox.tactical
import de.ruvnox.tactical.api.statusRoutes import de.ruvnox.tactical.api.statusRoutes
import de.ruvnox.tactical.api.systemRoutes
import io.ktor.server.application.Application import io.ktor.server.application.Application
import io.ktor.server.application.install import io.ktor.server.application.install
import io.ktor.server.engine.embeddedServer import io.ktor.server.engine.embeddedServer
@@ -35,5 +36,6 @@ fun Application.module() {
routing { routing {
statusRoutes() statusRoutes()
systemRoutes()
} }
} }
@@ -0,0 +1,20 @@
package de.ruvnox.tactical.api
import kotlinx.serialization.Serializable
@Serializable
data class CountSummaryResponse(
val total: Long,
val active: Long
)
@Serializable
data class SystemOverviewResponse(
val service: String,
val status: String,
val users: CountSummaryResponse,
val devices: CountSummaryResponse,
val operationRooms: CountSummaryResponse,
val messages: Long,
val auditEvents: Long
)
@@ -0,0 +1,35 @@
package de.ruvnox.tactical.api
import de.ruvnox.tactical.repository.AuditEventRepository
import de.ruvnox.tactical.repository.DeviceRepository
import de.ruvnox.tactical.repository.MessageRepository
import de.ruvnox.tactical.repository.OperationRoomRepository
import de.ruvnox.tactical.repository.UserRepository
import io.ktor.server.response.respond
import io.ktor.server.routing.Route
import io.ktor.server.routing.get
fun Route.systemRoutes() {
get("/api/v1/system/overview") {
call.respond(
SystemOverviewResponse(
service = "ruvnox-tactical-server",
status = "online",
users = CountSummaryResponse(
total = UserRepository.countTotal(),
active = UserRepository.countActive()
),
devices = CountSummaryResponse(
total = DeviceRepository.countTotal(),
active = DeviceRepository.countActive()
),
operationRooms = CountSummaryResponse(
total = OperationRoomRepository.countTotal(),
active = OperationRoomRepository.countActive()
),
messages = MessageRepository.countTotal(),
auditEvents = AuditEventRepository.countTotal()
)
)
}
}
@@ -0,0 +1,7 @@
package de.ruvnox.tactical.repository
object AuditEventRepository {
fun countTotal(): Long {
return queryLong("select count(*) from audit_events")
}
}
@@ -0,0 +1,11 @@
package de.ruvnox.tactical.repository
object DeviceRepository {
fun countTotal(): Long {
return queryLong("select count(*) from devices")
}
fun countActive(): Long {
return queryLong("select count(*) from devices where is_active = true")
}
}
@@ -0,0 +1,7 @@
package de.ruvnox.tactical.repository
object MessageRepository {
fun countTotal(): Long {
return queryLong("select count(*) from messages")
}
}
@@ -0,0 +1,11 @@
package de.ruvnox.tactical.repository
object OperationRoomRepository {
fun countTotal(): Long {
return queryLong("select count(*) from operation_rooms")
}
fun countActive(): Long {
return queryLong("select count(*) from operation_rooms where is_active = true")
}
}
@@ -0,0 +1,13 @@
package de.ruvnox.tactical.repository
import de.ruvnox.tactical.Database
internal fun queryLong(sql: String): Long {
return Database.connection().use { connection ->
connection.createStatement().use { statement ->
statement.executeQuery(sql).use { result ->
if (result.next()) result.getLong(1) else 0L
}
}
}
}
@@ -0,0 +1,11 @@
package de.ruvnox.tactical.repository
object UserRepository {
fun countTotal(): Long {
return queryLong("select count(*) from app_users")
}
fun countActive(): Long {
return queryLong("select count(*) from app_users where is_active = true")
}
}