Establish secure account and managed AI backend

Provide the production foundation for Apple identity, immutable credits, referrals, integrity checks, managed providers, and hardened Docker deployment.
This commit is contained in:
Rocky
2026-08-16 14:46:23 +08:00
commit 0af35d44f4
124 changed files with 21052 additions and 0 deletions
@@ -0,0 +1,576 @@
package com.osglab.account.features.credits
import com.osglab.account.features.credits.domain.CreditCostCalculator
import com.osglab.account.features.credits.domain.CreditConflict
import com.osglab.account.features.credits.domain.CreditRateVersion
import com.osglab.account.features.credits.domain.InsufficientCredits
import com.osglab.account.features.credits.domain.InvalidCreditRequest
import com.osglab.account.features.credits.domain.LedgerEntryType
import com.osglab.account.features.credits.domain.ReservationStatus
import com.osglab.account.features.credits.domain.ReservationStateRules
import com.osglab.account.features.credits.domain.UsageKind
import com.osglab.account.features.credits.domain.UsageMeasurement
import com.osglab.account.features.credits.domain.externalIdempotencyKey
import com.osglab.account.features.credits.services.CreditService
import com.osglab.account.features.credits.services.ReferralRewardConfig
import com.osglab.account.features.referrals.domain.ReferralBinding
import com.osglab.account.features.referrals.domain.ReferralCampaign
import com.osglab.account.features.referrals.domain.ReferralCampaignBudget
import com.osglab.account.features.referrals.domain.ReferralRewardStatus
import io.kotest.core.spec.style.FunSpec
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.longs.shouldBeExactly
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.types.shouldBeInstanceOf
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import java.time.Clock
import java.time.Instant
import java.time.ZoneOffset
import java.util.UUID
import kotlin.random.Random
class CreditServiceTest : FunSpec({
val now = Instant.parse("2026-08-15T00:00:00Z")
test("ASR and LLM rates round each billed dimension upward") {
CreditCostCalculator.calculate(
asrRate(now),
UsageMeasurement.Asr(durationMillis = 101),
) shouldBeExactly 2
CreditCostCalculator.calculate(
llmRate(now),
UsageMeasurement.Llm(inputTokens = 1001, outputTokens = 1),
) shouldBeExactly 4
}
test("cost calculation avoids intermediate overflow and rejects an unrepresentable result") {
CreditCostCalculator.calculate(
asrRate(now).copy(
asrCreditsNumerator = 2,
asrMillisDenominator = 2,
),
UsageMeasurement.Asr(Long.MAX_VALUE),
) shouldBeExactly Long.MAX_VALUE
shouldThrow<InvalidCreditRequest> {
CreditCostCalculator.calculate(
asrRate(now).copy(
asrCreditsNumerator = 2,
asrMillisDenominator = 1,
),
UsageMeasurement.Asr(Long.MAX_VALUE),
)
}
}
test("signup grant is idempotent") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.grantSignupTrial(userId, 100, "signup-key-001")
service.grantSignupTrial(userId, 100, "signup-key-001")
store.balance(userId) shouldBeExactly 100
store.ledger.filter { it.type == LedgerEntryType.SIGNUP_TRIAL } shouldHaveSize 1
}
test("balance overflow rolls back without appending a ledger entry") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.grantSignupTrial(userId, Long.MAX_VALUE, "signup-max-key")
shouldThrow<InvalidCreditRequest> {
service.grantSignupTrial(userId, 1, "signup-overflow-key")
}
store.balance(userId) shouldBeExactly Long.MAX_VALUE
store.ledger.filter { it.userId == userId } shouldHaveSize 1
}
test("concurrent reservations cannot make the account negative") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.grantSignupTrial(userId, 100, "signup-key-002")
val results = coroutineScope {
listOf("reserve-key-001", "reserve-key-002").map { key ->
async(Dispatchers.Default) {
runCatching {
service.reserve(
userId = userId,
provider = "asr-provider",
model = "asr-model",
estimatedUsage = UsageMeasurement.Asr(6_000),
managedCall = true,
idempotencyKey = key,
)
}
}
}.awaitAll()
}
results.count(Result<*>::isSuccess) shouldBe 1
results.single(Result<*>::isFailure).exceptionOrNull()
.shouldBeInstanceOf<InsufficientCredits>()
store.balance(userId) shouldBeExactly 40
}
test("first positive managed settlement rewards both users exactly once") {
val store = storeWithRates(now)
val service = service(store, now)
val inviter = UUID.randomUUID()
val invitee = UUID.randomUUID()
val binding = ReferralBinding(
id = UUID.randomUUID(),
inviterUserId = inviter,
inviteeUserId = invitee,
codeId = UUID.randomUUID(),
boundAt = now,
rewardedAt = null,
rewardSettlementId = null,
)
store.inTransaction { it.referrals.insertBindingIfAbsent(binding) }
service.grantSignupTrial(invitee, 100, "signup-key-003")
val reservation = service.reserve(
userId = invitee,
provider = "asr-provider",
model = "asr-model",
estimatedUsage = UsageMeasurement.Asr(1_000),
managedCall = true,
idempotencyKey = "reserve-key-003",
)
val first = service.settle(
invitee,
reservation.id,
UsageMeasurement.Asr(500),
"settle-key-003",
)
val retried = service.settle(
invitee,
reservation.id,
UsageMeasurement.Asr(500),
"settle-key-003",
)
first.status shouldBe ReservationStatus.SETTLED
retried shouldBe first
store.balance(invitee) shouldBeExactly 125
store.balance(inviter) shouldBeExactly 30
store.ledger.filter {
it.type == LedgerEntryType.REFERRAL_INVITEE ||
it.type == LedgerEntryType.REFERRAL_INVITER
} shouldHaveSize 2
store.usageRecords shouldHaveSize 1
store.usageRecords.single().rateVersionId shouldBe reservation.rateVersionId
store.bindings.getValue(invitee).rewardSettlementId shouldBe reservation.id
}
test("zero-cost managed settlement does not consume first valid referral reward") {
val store = storeWithRates(now)
val service = service(store, now)
val inviter = UUID.randomUUID()
val invitee = UUID.randomUUID()
store.inTransaction {
it.referrals.insertBindingIfAbsent(
ReferralBinding(
id = UUID.randomUUID(),
inviterUserId = inviter,
inviteeUserId = invitee,
codeId = UUID.randomUUID(),
boundAt = now,
rewardedAt = null,
rewardSettlementId = null,
),
)
}
service.grantSignupTrial(invitee, 100, "zero-signup-key")
val zeroCost = service.reserve(
invitee,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = true,
idempotencyKey = "zero-reserve-key",
)
service.settle(
invitee,
zeroCost.id,
UsageMeasurement.Asr(0),
"zero-settle-key",
)
store.bindings.getValue(invitee).rewardStatus shouldBe ReferralRewardStatus.PENDING
val qualifying = service.reserve(
invitee,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = true,
idempotencyKey = "valid-reserve-key",
)
service.settle(
invitee,
qualifying.id,
UsageMeasurement.Asr(1),
"valid-settle-key",
)
store.bindings.getValue(invitee).rewardSettlementId shouldBe qualifying.id
store.ledger.count {
it.type == LedgerEntryType.REFERRAL_INVITER ||
it.type == LedgerEntryType.REFERRAL_INVITEE
} shouldBe 2
}
test("concurrent settlement replay grants both referral sides only once") {
val store = storeWithRates(now)
val service = service(store, now)
val inviter = UUID.randomUUID()
val invitee = UUID.randomUUID()
store.inTransaction {
it.referrals.insertBindingIfAbsent(
ReferralBinding(
id = UUID.randomUUID(),
inviterUserId = inviter,
inviteeUserId = invitee,
codeId = UUID.randomUUID(),
boundAt = now,
rewardedAt = null,
rewardSettlementId = null,
),
)
}
service.grantSignupTrial(invitee, 100, "concurrent-signup-key")
val reservation = service.reserve(
userId = invitee,
provider = "asr-provider",
model = "asr-model",
estimatedUsage = UsageMeasurement.Asr(1_000),
managedCall = true,
idempotencyKey = "concurrent-reserve-key",
)
val results = coroutineScope {
List(8) {
async(Dispatchers.Default) {
service.settle(
userId = invitee,
reservationId = reservation.id,
actualUsage = UsageMeasurement.Asr(500),
idempotencyKey = "concurrent-settle-key",
)
}
}.awaitAll()
}
results.distinct() shouldHaveSize 1
store.usageRecords shouldHaveSize 1
store.ledger.count {
it.type == LedgerEntryType.REFERRAL_INVITEE ||
it.type == LedgerEntryType.REFERRAL_INVITER
} shouldBe 2
store.balance(inviter) shouldBeExactly 30
store.balance(invitee) shouldBeExactly 125
}
test("ledger projection remains non-negative across randomized terminal operations") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.grantSignupTrial(userId, 20_000, "property-signup-key")
val random = Random(42)
repeat(100) { index ->
val estimate = random.nextLong(1, 5_000)
val reservation = service.reserve(
userId,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(estimate),
managedCall = false,
idempotencyKey = "property-reserve-$index",
)
if (index % 3 == 0) {
service.release(userId, reservation.id, "property-release-$index")
} else {
val actual = random.nextLong(0, estimate + 1)
service.settle(
userId,
reservation.id,
UsageMeasurement.Asr(actual),
"property-settle-$index",
)
if (index % 5 == 0) {
service.refund(userId, reservation.id, "property-refund-$index")
}
}
}
var projection = 0L
store.ledger.filter { it.userId == userId }.forEach { entry ->
projection = Math.addExact(projection, entry.amountDelta)
entry.balanceAfter shouldBeExactly projection
(projection >= 0) shouldBe true
}
store.balance(userId) shouldBeExactly projection
}
test("campaign cap is consumed once and later qualification is not rewarded") {
val store = storeWithRates(now)
val service = service(store, now)
val campaignId = UUID.randomUUID()
store.campaigns[campaignId] = ReferralCampaign(
id = campaignId,
name = "One reward",
startsAt = now.minusSeconds(60),
endsAt = null,
bindingWindowSeconds = 604_800,
inviterRewardCredits = 7,
inviteeRewardCredits = 5,
maxRewardedBindings = 1,
budgetCredits = 12,
enabled = true,
)
store.campaignBudgets[campaignId] = ReferralCampaignBudget(campaignId, 0, 0, now)
val inviter = UUID.randomUUID()
val invitees = List(2) { UUID.randomUUID() }
invitees.forEach { invitee ->
store.inTransaction {
it.referrals.insertBindingIfAbsent(
ReferralBinding(
id = UUID.randomUUID(),
inviterUserId = inviter,
inviteeUserId = invitee,
codeId = UUID.randomUUID(),
boundAt = now,
rewardedAt = null,
rewardSettlementId = null,
campaignId = campaignId,
),
)
}
service.grantSignupTrial(invitee, 100, "campaign-signup-$invitee")
val reservation = service.reserve(
invitee,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = true,
idempotencyKey = "campaign-reserve-$invitee",
)
service.settle(
invitee,
reservation.id,
UsageMeasurement.Asr(500),
"campaign-settle-$invitee",
)
}
store.ledger.count {
it.type == LedgerEntryType.REFERRAL_INVITER ||
it.type == LedgerEntryType.REFERRAL_INVITEE
} shouldBe 2
store.campaignBudgets.getValue(campaignId).rewardedBindings shouldBeExactly 1
store.bindings.getValue(invitees[1]).rewardStatus shouldBe
ReferralRewardStatus.INELIGIBLE_BUDGET
}
test("exhausted campaign counters fail closed without partial rewards") {
val store = storeWithRates(now)
val service = service(store, now)
val campaignId = UUID.randomUUID()
store.campaigns[campaignId] = ReferralCampaign(
id = campaignId,
name = "Exhausted",
startsAt = now.minusSeconds(60),
endsAt = null,
bindingWindowSeconds = 604_800,
inviterRewardCredits = 7,
inviteeRewardCredits = 5,
maxRewardedBindings = null,
budgetCredits = null,
enabled = true,
)
store.campaignBudgets[campaignId] = ReferralCampaignBudget(
campaignId,
Long.MAX_VALUE,
Long.MAX_VALUE,
now,
)
val inviter = UUID.randomUUID()
val invitee = UUID.randomUUID()
store.inTransaction {
it.referrals.insertBindingIfAbsent(
ReferralBinding(
id = UUID.randomUUID(),
inviterUserId = inviter,
inviteeUserId = invitee,
codeId = UUID.randomUUID(),
boundAt = now,
rewardedAt = null,
rewardSettlementId = null,
campaignId = campaignId,
),
)
}
service.grantSignupTrial(invitee, 100, "exhausted-signup-key")
val reservation = service.reserve(
invitee,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = true,
idempotencyKey = "exhausted-reserve-key",
)
service.settle(
invitee,
reservation.id,
UsageMeasurement.Asr(500),
"exhausted-settle-key",
)
store.bindings.getValue(invitee).rewardStatus shouldBe
ReferralRewardStatus.INELIGIBLE_BUDGET
store.ledger.none {
it.type == LedgerEntryType.REFERRAL_INVITER ||
it.type == LedgerEntryType.REFERRAL_INVITEE
} shouldBe true
}
test("release and refund restore only the corresponding debit") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.grantSignupTrial(userId, 100, "signup-key-004")
val released = service.reserve(
userId,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = false,
idempotencyKey = "reserve-key-004",
)
service.release(userId, released.id, "release-key-004")
service.release(userId, released.id, "release-key-004")
val settled = service.reserve(
userId,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = false,
idempotencyKey = "reserve-key-005",
)
service.settle(userId, settled.id, UsageMeasurement.Asr(500), "settle-key-005")
service.refund(userId, settled.id, "refund-key-005")
service.refund(userId, settled.id, "refund-key-005")
store.balance(userId) shouldBeExactly 100
store.ledger.filter { it.type == LedgerEntryType.USAGE_RELEASE } shouldHaveSize 1
store.ledger.filter { it.type == LedgerEntryType.USAGE_REFUND } shouldHaveSize 1
}
test("settlement replay rejects different actual usage") {
val store = storeWithRates(now)
val service = service(store, now)
val userId = UUID.randomUUID()
service.grantSignupTrial(userId, 100, "signup-key-006")
val reservation = service.reserve(
userId,
"asr-provider",
"asr-model",
UsageMeasurement.Asr(1_000),
managedCall = false,
idempotencyKey = "reserve-key-006",
)
service.settle(userId, reservation.id, UsageMeasurement.Asr(500), "settle-key-006")
shouldThrow<CreditConflict> {
service.settle(userId, reservation.id, UsageMeasurement.Asr(600), "settle-key-006")
}
}
test("public idempotency values cannot occupy the internal reward namespace") {
externalIdempotencyKey("internal:referral:known-binding:invitee") shouldNotBe
"internal:referral:known-binding:invitee"
}
test("reservation state rules allow only settle release and refund transitions") {
ReservationStateRules.canTransition(
ReservationStatus.RESERVED,
ReservationStatus.SETTLED,
) shouldBe true
ReservationStateRules.canTransition(
ReservationStatus.RESERVED,
ReservationStatus.RELEASED,
) shouldBe true
ReservationStateRules.canTransition(
ReservationStatus.SETTLED,
ReservationStatus.REFUNDED,
) shouldBe true
ReservationStatus.entries.forEach { target ->
ReservationStateRules.canTransition(
ReservationStatus.REFUNDED,
target,
) shouldBe false
}
ReservationStateRules.canTransition(
ReservationStatus.RELEASED,
ReservationStatus.SETTLED,
) shouldBe false
}
})
private fun service(store: TestBillingStore, now: Instant) = CreditService(
transactions = store,
referralRewards = ReferralRewardConfig(inviterCredits = 30, inviteeCredits = 30),
clock = Clock.fixed(now, ZoneOffset.UTC),
)
private fun storeWithRates(now: Instant) = TestBillingStore().also {
val asr = asrRate(now)
val llm = llmRate(now)
it.rates[asr.id] = asr
it.rates[llm.id] = llm
}
private fun asrRate(now: Instant) = CreditRateVersion(
id = UUID.nameUUIDFromBytes("asr-rate".toByteArray()),
kind = UsageKind.ASR,
provider = "asr-provider",
model = "asr-model",
effectiveFrom = now.minusSeconds(60),
effectiveUntil = null,
asrCreditsNumerator = 1,
asrMillisDenominator = 100,
inputCreditsNumerator = null,
inputTokensDenominator = null,
outputCreditsNumerator = null,
outputTokensDenominator = null,
)
private fun llmRate(now: Instant) = CreditRateVersion(
id = UUID.nameUUIDFromBytes("llm-rate".toByteArray()),
kind = UsageKind.LLM,
provider = "llm-provider",
model = "llm-model",
effectiveFrom = now.minusSeconds(60),
effectiveUntil = null,
asrCreditsNumerator = null,
asrMillisDenominator = null,
inputCreditsNumerator = 2,
inputTokensDenominator = 1_000,
outputCreditsNumerator = 3,
outputTokensDenominator = 1_000,
)