Add secure administrator operations console
Provide TOTP-authenticated, role-controlled user and credit workflows with paginated audit data and SQL-backed statistics so operations can manage growth safely.
This commit is contained in:
@@ -80,6 +80,161 @@ class CreditServiceTest : FunSpec({
|
||||
store.ledger.filter { it.type == LedgerEntryType.SIGNUP_TRIAL } shouldHaveSize 1
|
||||
}
|
||||
|
||||
test("manual grant appends one linked audit and ledger entry") {
|
||||
val store = storeWithRates(now)
|
||||
val service = service(store, now)
|
||||
val userId = UUID.randomUUID()
|
||||
store.registeredUsers += userId
|
||||
|
||||
val result = service.grantManual(
|
||||
operatorId = TEST_OPERATOR_ID,
|
||||
userId = userId,
|
||||
credits = 250,
|
||||
reason = "Customer support adjustment",
|
||||
requestId = "support-ticket-1042",
|
||||
idempotencyKey = "manual-grant-key-001",
|
||||
)
|
||||
|
||||
result.replayed shouldBe false
|
||||
result.balanceAfter shouldBeExactly 250
|
||||
store.balance(userId) shouldBeExactly 250
|
||||
store.manualGrants.single() shouldBe result.grant
|
||||
store.adminAudits.single().id shouldBe result.grant.auditLogId
|
||||
store.ledger.single { it.type == LedgerEntryType.MANUAL_GRANT }.let { ledger ->
|
||||
ledger.referenceId shouldBe result.grant.id
|
||||
ledger.id shouldBe result.grant.ledgerEntryId
|
||||
}
|
||||
}
|
||||
|
||||
test("manual grant replay is stable and rejects changed parameters") {
|
||||
val store = storeWithRates(now)
|
||||
val service = service(store, now)
|
||||
val userId = UUID.randomUUID()
|
||||
store.registeredUsers += userId
|
||||
val first = service.grantManual(
|
||||
TEST_OPERATOR_ID,
|
||||
userId,
|
||||
100,
|
||||
"Retention credit",
|
||||
"support-ticket-1043",
|
||||
"manual-grant-key-002",
|
||||
)
|
||||
val replay = service.grantManual(
|
||||
TEST_OPERATOR_ID,
|
||||
userId,
|
||||
100,
|
||||
"Retention credit",
|
||||
"support-ticket-1043",
|
||||
"manual-grant-key-002",
|
||||
)
|
||||
|
||||
replay.grant shouldBe first.grant
|
||||
replay.replayed shouldBe true
|
||||
shouldThrow<CreditConflict> {
|
||||
service.grantManual(
|
||||
TEST_OPERATOR_ID,
|
||||
userId,
|
||||
101,
|
||||
"Retention credit",
|
||||
"support-ticket-1043",
|
||||
"manual-grant-key-002",
|
||||
)
|
||||
}
|
||||
store.balance(userId) shouldBeExactly 100
|
||||
store.manualGrants shouldHaveSize 1
|
||||
store.ledger.filter { it.type == LedgerEntryType.MANUAL_GRANT } shouldHaveSize 1
|
||||
}
|
||||
|
||||
test("manual grant validates positive amount and rolls back an audit failure") {
|
||||
val store = storeWithRates(now)
|
||||
val service = service(store, now)
|
||||
val userId = UUID.randomUUID()
|
||||
store.registeredUsers += userId
|
||||
|
||||
shouldThrow<InvalidCreditRequest> {
|
||||
service.grantManual(
|
||||
TEST_OPERATOR_ID,
|
||||
userId,
|
||||
0,
|
||||
"Invalid adjustment",
|
||||
"support-ticket-1044",
|
||||
"manual-grant-key-003",
|
||||
)
|
||||
}
|
||||
store.failNextManualGrantInsert = true
|
||||
shouldThrow<IllegalStateException> {
|
||||
service.grantManual(
|
||||
TEST_OPERATOR_ID,
|
||||
userId,
|
||||
50,
|
||||
"Rollback adjustment",
|
||||
"support-ticket-1045",
|
||||
"manual-grant-key-004",
|
||||
)
|
||||
}
|
||||
|
||||
store.balance(userId) shouldBeExactly 0
|
||||
store.manualGrants shouldHaveSize 0
|
||||
store.adminAudits shouldHaveSize 0
|
||||
store.ledger.filter { it.type == LedgerEntryType.MANUAL_GRANT } shouldHaveSize 0
|
||||
}
|
||||
|
||||
test("concurrent manual grant replay credits exactly once") {
|
||||
val store = storeWithRates(now)
|
||||
val service = service(store, now)
|
||||
val userId = UUID.randomUUID()
|
||||
store.registeredUsers += userId
|
||||
|
||||
val results = coroutineScope {
|
||||
List(8) {
|
||||
async(Dispatchers.Default) {
|
||||
service.grantManual(
|
||||
TEST_OPERATOR_ID,
|
||||
userId,
|
||||
75,
|
||||
"Concurrent adjustment",
|
||||
"support-ticket-1046",
|
||||
"manual-grant-key-005",
|
||||
)
|
||||
}
|
||||
}.awaitAll()
|
||||
}
|
||||
|
||||
results.map { it.grant.id }.distinct() shouldHaveSize 1
|
||||
store.balance(userId) shouldBeExactly 75
|
||||
store.manualGrants shouldHaveSize 1
|
||||
store.ledger.filter { it.type == LedgerEntryType.MANUAL_GRANT } shouldHaveSize 1
|
||||
}
|
||||
|
||||
test("manual grant supports the maximum balance and rejects overflow") {
|
||||
val store = storeWithRates(now)
|
||||
val service = service(store, now)
|
||||
val userId = UUID.randomUUID()
|
||||
store.registeredUsers += userId
|
||||
service.grantManual(
|
||||
TEST_OPERATOR_ID,
|
||||
userId,
|
||||
Long.MAX_VALUE,
|
||||
"Maximum supported adjustment",
|
||||
"support-ticket-1047",
|
||||
"manual-grant-key-006",
|
||||
)
|
||||
|
||||
shouldThrow<InvalidCreditRequest> {
|
||||
service.grantManual(
|
||||
TEST_OPERATOR_ID,
|
||||
userId,
|
||||
1,
|
||||
"Overflow adjustment",
|
||||
"support-ticket-1048",
|
||||
"manual-grant-key-007",
|
||||
)
|
||||
}
|
||||
|
||||
store.balance(userId) shouldBeExactly Long.MAX_VALUE
|
||||
store.manualGrants shouldHaveSize 1
|
||||
}
|
||||
|
||||
test("balance overflow rolls back without appending a ledger entry") {
|
||||
val store = storeWithRates(now)
|
||||
val service = service(store, now)
|
||||
@@ -574,3 +729,5 @@ private fun llmRate(now: Instant) = CreditRateVersion(
|
||||
outputCreditsNumerator = 3,
|
||||
outputTokensDenominator = 1_000,
|
||||
)
|
||||
|
||||
private val TEST_OPERATOR_ID = UUID.fromString("11111111-1111-1111-1111-111111111111")
|
||||
|
||||
Reference in New Issue
Block a user