feat(onboarding): Explicit Device Enrollment für Master-Geräte hinzugefügt

- Master-Geräte können erwartete Clients inkl. Name & Rolle definieren.
- Neue Rollen (`RICHTER`, `ZEITNEHMER` etc.) integriert.
- Backend- und Frontend-Validierung erweitert, UI-Komponente für Client-Verwaltung.

Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
This commit is contained in:
2026-04-16 10:24:49 +02:00
parent f98a9075ae
commit 82a4a13505
9 changed files with 201 additions and 7 deletions
@@ -10,13 +10,22 @@ import kotlin.time.Instant
data class Device(
val id: UUID = UUID.randomUUID(),
val name: String,
val expectedName: String? = null, // Falls vom Master vor-registriert
val securityKeyHash: String, // Gehasht für Sicherheit
val role: DeviceRole = DeviceRole.CLIENT,
val lastSyncAt: Instant? = null,
val isOnline: Boolean = false,
val isSynchronized: Boolean = true,
val createdAt: Instant,
val updatedAt: Instant = createdAt
)
enum class DeviceRole {
MASTER, CLIENT
MASTER,
CLIENT,
RICHTER,
ZEITNEHMER,
STALLMEISTER,
ANZEIGE,
PARCOURS_CHEF
}
@@ -13,10 +13,13 @@ object DeviceTable : Table("identity_devices") {
override val primaryKey = PrimaryKey(id)
val name = varchar("name", 100).uniqueIndex()
val expectedName = varchar("expected_name", 100).nullable()
val securityKeyHash = varchar("security_key_hash", 255)
val role = enumerationByName("role", 20, DeviceRole::class)
val lastSyncAt = timestamp("last_sync_at").nullable()
val isOnline = bool("is_online").default(false)
val isSynchronized = bool("is_synchronized").default(true)
val createdAt = timestamp("created_at")
val updatedAt = timestamp("updated_at")
}
@@ -33,18 +33,24 @@ class ExposedDeviceRepository : DeviceRepository {
if (existing != null) {
DeviceTable.update({ DeviceTable.id eq device.id }) {
it[name] = device.name
it[expectedName] = device.expectedName
it[securityKeyHash] = device.securityKeyHash
it[role] = device.role
it[lastSyncAt] = device.lastSyncAt
it[isOnline] = device.isOnline
it[isSynchronized] = device.isSynchronized
it[updatedAt] = now
}
} else {
DeviceTable.insert {
it[id] = device.id
it[name] = device.name
it[expectedName] = device.expectedName
it[securityKeyHash] = device.securityKeyHash
it[role] = device.role
it[lastSyncAt] = device.lastSyncAt
it[isOnline] = device.isOnline
it[isSynchronized] = device.isSynchronized
it[createdAt] = device.createdAt
it[updatedAt] = now
}
@@ -62,9 +68,12 @@ class ExposedDeviceRepository : DeviceRepository {
private fun rowToDevice(row: ResultRow): Device = Device(
id = row[DeviceTable.id],
name = row[DeviceTable.name],
expectedName = row[DeviceTable.expectedName],
securityKeyHash = row[DeviceTable.securityKeyHash],
role = row[DeviceTable.role],
lastSyncAt = row[DeviceTable.lastSyncAt],
isOnline = row[DeviceTable.isOnline],
isSynchronized = row[DeviceTable.isSynchronized],
createdAt = row[DeviceTable.createdAt],
updatedAt = row[DeviceTable.updatedAt]
)