badges: per-tier search limits — result cap + min chars, config UI

Add anonymous/auth/trusted search constraints to BadgesRemoteCfg with
conservative defaults (anon: 15 results / 3 chars, auth: 25 / 2,
trusted+: 150 / 1). Configurable per event via mod_badges_json.

- BadgesRemoteCfg + BadgesLocState: 6 new fields with defaults
- sync_config__event_badges: mirrors new fields from mod_badges_json
- +page.svelte: effective_search_limits derived by tier using $ae_loc
  cumulative flags; enforces min_chars guard and result cap on both
  local IDB path and API call
- ae_comp__badge_search: effective_min_chars derived same way; blocks
  search trigger below threshold; shows dynamic hint text
- Fallback broad search (SCENARIO 2) suppressed for non-trusted users
  so no results show on page load without a query
- config/+page.svelte: Search Limits section with 3-column number
  inputs (Anonymous / Auth / Trusted+) for result limit and min chars

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-04-07 18:08:10 -04:00
parent be0b8baf62
commit ae9cdaf9f1
5 changed files with 198 additions and 12 deletions

View File

@@ -1095,6 +1095,14 @@ export function sync_config__event_badges({
loc.enable_search_qr = badges_cfg_remote?.enable_search_qr ?? true;
loc.qr_type = badges_cfg_remote?.qr_type ?? null;
// Per-tier search constraints
loc.anon_search_result_limit = badges_cfg_remote?.anon_search_result_limit ?? 15;
loc.anon_search_min_chars = badges_cfg_remote?.anon_search_min_chars ?? 3;
loc.auth_search_result_limit = badges_cfg_remote?.auth_search_result_limit ?? 25;
loc.auth_search_min_chars = badges_cfg_remote?.auth_search_min_chars ?? 2;
loc.trusted_search_result_limit = badges_cfg_remote?.trusted_search_result_limit ?? 150;
loc.trusted_search_min_chars = badges_cfg_remote?.trusted_search_min_chars ?? 1;
// Passcodes and permissions (may be null)
loc.trusted_passcode = badges_cfg_remote?.trusted_passcode ?? null;
loc.administrator_passcode = badges_cfg_remote?.administrator_passcode ?? null;

View File

@@ -19,6 +19,17 @@ export interface BadgesRemoteCfg {
enable_upload_badge_li_btn: boolean; // show the "Upload Badge List" button
enable_search_qr: boolean; // enable QR scan search
// Per-access-tier search limits.
// anonymous — not signed in at all
// auth — public passcode or identity-verified (Authenticated/Public)
// trusted — onsite staff (Trusted) and above; above-trusted inherits trusted limits
anon_search_result_limit: number;
anon_search_min_chars: number;
auth_search_result_limit: number;
auth_search_min_chars: number;
trusted_search_result_limit: number;
trusted_search_min_chars: number;
// QR code configuration
qr_type: string | null; // QR payload format (e.g. 'badge_id', 'url')
@@ -117,6 +128,13 @@ export interface BadgesLocState {
trusted?: { can_edit: string[] | '*' };
administrator?: { can_edit: string[] | '*' };
} | null;
// Per-tier search constraints (mirrored from mod_badges_json)
anon_search_result_limit: number;
anon_search_min_chars: number;
auth_search_result_limit: number;
auth_search_min_chars: number;
trusted_search_result_limit: number;
trusted_search_min_chars: number;
// Timestamp when the remote config was last mirrored locally
remote_cfg_last_synced_on: string | null;
}
@@ -177,6 +195,13 @@ export const badges_loc_defaults: BadgesLocState = {
trusted_passcode: null,
administrator_passcode: null,
edit_permissions: null,
// Per-tier search constraints — conservative defaults; overridden per event via mod_badges_json.
anon_search_result_limit: 15,
anon_search_min_chars: 3,
auth_search_result_limit: 25,
auth_search_min_chars: 2,
trusted_search_result_limit: 150,
trusted_search_min_chars: 1,
remote_cfg_last_synced_on: null
};