feat(admin): move auto-ban config into DB admin settings (BUNYIP-351) #350

Merged
longjacksonle merged 1 commit from feat/BUNYIP-351-auto-ban-db-config into main 2026-07-08 19:41:17 +02:00

What

Phase 1 of BUNYIP-351: move the auto-ban thresholds out of env-only vars and into a DB-persisted, admin-editable singleton, following the established tier_config / stripe_config DB-overrides-env pattern.

AUTO_BAN_ENABLED, AUTO_BAN_THRESHOLD, AUTO_BAN_WINDOW_SECS, and AUTO_BAN_DURATION_SECS remain the bootstrap defaults. Once an admin edits the values in the new Auto-ban settings page, the auto_ban_config row overrides them and the change applies immediately with no restart. A wiped DB (all-NULL row) falls straight back to the env defaults, so a fresh deployment boots identically.

How

  • New singleton migration auto_ban_config (id CHECK=1, nullable columns, updated_at/updated_by), seeded id=1. Additive and immutable.
  • AutoBanConfigRow + AutoBanConfigResponse model; AutoBanConfig::from_db_row / has_db_overrides merge (mirrors TierConfig). AutoBanConfig now derives Copy.
  • AutoBanConfigRepository (get + COALESCE partial update).
  • AutoBanService holds its config behind a std::sync::RwLock and gains reload(). Values were already read per-request off a frozen copy, so this is the only refactor needed for live apply; a cheap Copy-out snapshot keeps the hot path lock-light.
  • Startup DB-override load in main.rs (env fallback).
  • GET/PUT /v1/admin/auto-ban-config handlers, routes, and an AdminAutoBanConfigUpdated audit action; the PUT hot-reloads the running service.
  • bunyip-web admin settings page + nav item at /admin/auto-ban-settings (api client, types DTO, page + save handler, shield-alert icon).
  • .env.example documents the vars as bootstrap defaults now overridable in the admin UI.

Tests

cargo fmt --check, cargo clippy --workspace --all-targets -D warnings, and cargo test --workspace --all-targets all green in the pinned rust-builder container. New unit tests cover from_db_row env-fallback, override, and out-of-range-clamp paths.

Scope

Stripe secrets and tier config were already DB-backed. Email/SMTP config (phase 2, includes an encrypted SMTP password reusing the Stripe encryption key set) and the leftover Stripe checkout knobs (phase 3) follow in later PRs. The revised ticket describes all three phases.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CTpxCd1SvpE8sk82aGikkz

## What Phase 1 of BUNYIP-351: move the auto-ban thresholds out of env-only vars and into a DB-persisted, admin-editable singleton, following the established `tier_config` / `stripe_config` DB-overrides-env pattern. `AUTO_BAN_ENABLED`, `AUTO_BAN_THRESHOLD`, `AUTO_BAN_WINDOW_SECS`, and `AUTO_BAN_DURATION_SECS` remain the bootstrap defaults. Once an admin edits the values in the new Auto-ban settings page, the `auto_ban_config` row overrides them and the change applies immediately with no restart. A wiped DB (all-NULL row) falls straight back to the env defaults, so a fresh deployment boots identically. ## How - New singleton migration `auto_ban_config` (id CHECK=1, nullable columns, updated_at/updated_by), seeded id=1. Additive and immutable. - `AutoBanConfigRow` + `AutoBanConfigResponse` model; `AutoBanConfig::from_db_row` / `has_db_overrides` merge (mirrors `TierConfig`). `AutoBanConfig` now derives `Copy`. - `AutoBanConfigRepository` (`get` + COALESCE partial `update`). - `AutoBanService` holds its config behind a `std::sync::RwLock` and gains `reload()`. Values were already read per-request off a frozen copy, so this is the only refactor needed for live apply; a cheap `Copy`-out snapshot keeps the hot path lock-light. - Startup DB-override load in `main.rs` (env fallback). - `GET`/`PUT /v1/admin/auto-ban-config` handlers, routes, and an `AdminAutoBanConfigUpdated` audit action; the PUT hot-reloads the running service. - bunyip-web admin settings page + nav item at `/admin/auto-ban-settings` (api client, types DTO, page + save handler, `shield-alert` icon). - `.env.example` documents the vars as bootstrap defaults now overridable in the admin UI. ## Tests `cargo fmt --check`, `cargo clippy --workspace --all-targets -D warnings`, and `cargo test --workspace --all-targets` all green in the pinned rust-builder container. New unit tests cover `from_db_row` env-fallback, override, and out-of-range-clamp paths. ## Scope Stripe secrets and tier config were already DB-backed. Email/SMTP config (phase 2, includes an encrypted SMTP password reusing the Stripe encryption key set) and the leftover Stripe checkout knobs (phase 3) follow in later PRs. The revised ticket describes all three phases. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01CTpxCd1SvpE8sk82aGikkz
feat(admin): move auto-ban config into DB admin settings (BUNYIP-351)
All checks were successful
E2E / Playwright against deployment (pull_request) Successful in 36s
Check / fmt + clippy + build + tests (pull_request) Successful in 30m46s
Create release / Create release from merged PR (pull_request) Has been skipped
d0ce0c2190
Auto-ban thresholds (AUTO_BAN_ENABLED / THRESHOLD / WINDOW_SECS / DURATION_SECS) were env-only and applied once at startup. This moves them into a DB-persisted, admin-editable singleton following the established tier_config / stripe_config DB-overrides-env pattern: a new auto_ban_config table whose NULL columns fall back to the env defaults at load time, so a wiped DB still boots identically and env stays the bootstrap default.

AutoBanService now holds its config behind a std::sync::RwLock and gains a reload() method, so an admin edit applies immediately without a restart (the values were already read per-request off a frozen copy). AutoBanConfig derives Copy for the cheap hot-path snapshot.

Adds the singleton migration, AutoBanConfigRow + AutoBanConfigResponse model, AutoBanConfigRepository (get + COALESCE partial update), AutoBanConfig::from_db_row / has_db_overrides, startup DB-override load in main.rs, GET/PUT /v1/admin/auto-ban-config handlers with an AdminAutoBanConfigUpdated audit action, and the bunyip-web admin settings page + nav item at /admin/auto-ban-settings. Unit tests cover the from_db_row env-fallback, override, and out-of-range-clamp paths.

This is phase 1 of BUNYIP-351. Email/SMTP config (phase 2) and the leftover Stripe checkout knobs (phase 3) follow in later PRs; Stripe secrets and tier config were already DB-backed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CTpxCd1SvpE8sk82aGikkz
longjacksonle scheduled this pull request to auto merge when all checks succeed 2026-07-08 19:11:09 +02:00
longjacksonle deleted branch feat/BUNYIP-351-auto-ban-db-config 2026-07-08 19:41:17 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/bunyip!350
No description provided.