feat: add leave submission withdrawal and audit trail
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
package com.all8ai.aioa.audit.application
|
||||
|
||||
import com.all8ai.aioa.audit.domain.AuditEvent
|
||||
import com.all8ai.aioa.audit.domain.AuditEventRepository
|
||||
import com.all8ai.aioa.identity.domain.CurrentUser
|
||||
import com.all8ai.aioa.shared.id.UuidV7
|
||||
import com.all8ai.aioa.shared.web.TraceIdFilter
|
||||
import org.slf4j.MDC
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class AuditService(
|
||||
private val repository: AuditEventRepository,
|
||||
) {
|
||||
fun recordSuccess(
|
||||
actor: CurrentUser,
|
||||
action: String,
|
||||
resourceType: String,
|
||||
resourceId: String,
|
||||
idempotencyKey: String?,
|
||||
details: Map<String, Any?>,
|
||||
) {
|
||||
repository.append(
|
||||
AuditEvent(
|
||||
id = UuidV7.generate(),
|
||||
tenantId = actor.tenantId,
|
||||
actorId = actor.id,
|
||||
action = action,
|
||||
resourceType = resourceType,
|
||||
resourceId = resourceId,
|
||||
traceId = MDC.get(TraceIdFilter.MDC_TRACE_ID) ?: "unknown",
|
||||
idempotencyKey = idempotencyKey,
|
||||
result = "SUCCESS",
|
||||
details = details,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.all8ai.aioa.audit.domain
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
data class AuditEvent(
|
||||
val id: UUID,
|
||||
val tenantId: UUID,
|
||||
val actorId: UUID,
|
||||
val action: String,
|
||||
val resourceType: String,
|
||||
val resourceId: String,
|
||||
val traceId: String,
|
||||
val idempotencyKey: String?,
|
||||
val result: String,
|
||||
val details: Map<String, Any?>,
|
||||
)
|
||||
|
||||
fun interface AuditEventRepository {
|
||||
fun append(event: AuditEvent)
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.all8ai.aioa.audit.infrastructure
|
||||
|
||||
import com.all8ai.aioa.audit.domain.AuditEvent
|
||||
import com.all8ai.aioa.audit.domain.AuditEventRepository
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import org.jooq.DSLContext
|
||||
import org.springframework.stereotype.Repository
|
||||
|
||||
@Repository
|
||||
class JooqAuditEventRepository(
|
||||
private val dsl: DSLContext,
|
||||
private val objectMapper: ObjectMapper,
|
||||
) : AuditEventRepository {
|
||||
override fun append(event: AuditEvent) {
|
||||
dsl.execute(
|
||||
"""
|
||||
INSERT INTO audit.event (
|
||||
id, tenant_id, actor_id, action, resource_type, resource_id,
|
||||
trace_id, idempotency_key, result, details
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, CAST(? AS JSONB))
|
||||
""".trimIndent(),
|
||||
event.id,
|
||||
event.tenantId,
|
||||
event.actorId,
|
||||
event.action,
|
||||
event.resourceType,
|
||||
event.resourceId,
|
||||
event.traceId,
|
||||
event.idempotencyKey,
|
||||
event.result,
|
||||
objectMapper.writeValueAsString(event.details),
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user