feat(wallet): add runtime auto-withdrawal thresholds - #45
feat(wallet): add runtime auto-withdrawal thresholds#45marek-chmielowski-blurify wants to merge 1 commit into
Conversation
| @@ -1047,14 +1062,54 @@ export class WalletService { | |||
| if (rule) { | |||
| return { value: rule.threshold, source: 'per-player' }; | |||
There was a problem hiding this comment.
Blocking: when the singleton row is missing, this early return skips getAutoWithdrawalConfig(). A player with an override can still have a withdrawal auto-approved, so an unseeded install is not fail-closed. Check that the global row exists before accepting the per-player threshold.
There was a problem hiding this comment.
I know this return already existed, but this PR adds the new fail-closed requirement based on the DB singleton. Because getAutoWithdrawalConfig() is called only after the early return, that requirement is skipped for players with a per-player rule.
| // install, and `set` below self-heals it via upsert - a missing `before` | ||
| // must not block that self-heal. | ||
| const before = await wallet.getAutoWithdrawalConfigOrNull(); | ||
| const config = await wallet.setAutoWithdrawalConfig(adminId, input); |
There was a problem hiding this comment.
Blocking: this commits the threshold update before the audit write. If audit.record() fails, the API returns an error but the threshold remains changed without the required audit entry. Make the update and audit record atomic, or roll the update back when auditing fails.
| export type WalletAutoWithdrawalConfig = z.infer<typeof WalletAutoWithdrawalConfigSchema>; | ||
|
|
||
| export const SetWalletAutoWithdrawalConfigInputSchema = z.object({ | ||
| fiatThreshold: MoneyAmountSchema, |
There was a problem hiding this comment.
This accepts unlimited integer digits, but the database column is numeric(18,8) and only allows 10 digits before the decimal. For example, 10000000000 passes this schema and then causes a database 500. Limit the input precision so invalid values return a 4xx response.
Summary
Moves global fiat and crypto auto-withdrawal thresholds from static platform configuration into a DB-backed wallet singleton. Adds Super Admin read/update routes, audit recording, safe seed defaults, migration coverage, and unit/e2e tests.
Why
Introduced these changes so operators can update auto-withdrawal thresholds at runtime without a redeploy while preserving fail-closed payout behavior and a complete audit trail.
Worth knowing
The new
wallet_auto_withdrawal_configrow is a global singleton for the current single-tenant runtime, so it intentionally has notenantIdor RLS policy. Both seeded thresholds default to zero, preventing an upgrade from silently enabling auto-approval; missing config also fails closed.pnpm verifyis green (typecheck + lint + boundaries + module-shape + tests)pnpm check:driftis green (catalog / OpenAPI not stale) - runpnpm regenif not/schemasubpath (no direct module imports)tenantIdand are RLS-covered (pnpm regenrunsgen:rls)Closes BF-211