# User search

Administrative user selection uses `Mini\Model\UserSearch` on the user list, event enrollment, individual lesson, payment, rental, and skate-cover order screens. The model owns input validation, context eligibility, category filters, result counting, deterministic ordering, and pagination. Controllers select one supported context and views render the shared search components with context-specific actions.

## Search rules

- A query may contain up to 254 characters and 10 whitespace-separated terms. Every term must match, but terms may match different fields and may appear in any order.
- Search covers user ID, first name, last name, nickname, email, and mobile number. An active parent's email and mobile number also match the parent's children.
- Text comparison uses `utf8mb4_0900_ai_ci` only inside search expressions. Stored data and authentication comparisons retain their existing collation and behavior.
- `%` and `_` are escaped as literal characters. `*` is converted to the SQL wildcard `%`; a query containing only asterisks is rejected.
- Typo tolerance and similarity scoring are intentionally not implemented.
- Results are paginated at 50 records and ordered by last name, first name, and ID. The `new` category is ordered by creation date and ID descending.

## Categories and contexts

The administrative user list supports one category at a time: all active users, unconfirmed adult accounts, instructors including administrators, administrators, accounts created in the last 30 days, or suspicious names. A text query can narrow the currently selected category. Submitting keywords preserves the category, while selecting any category clears the current keywords and returns to its first page. Legacy category routes only select the initial category; subsequent forms post to the common user-list route.

The suspicious-name category excludes a record when either the first or last
name is exactly `Le`, `Vu`, or `Hu`. These short names are accepted even when
the other name would otherwise trigger a suspicious-name condition.

Suspicious names include a first or last name containing only one or two letters, an entire first or last name written in uppercase, a digit anywhere in the first or last name, or equal non-empty first and last names after whitespace normalization and accent/case-insensitive comparison. The UI does not expose the reason and never changes the record.

Event enrollment, individual lesson, and payment contexts exclude unconfirmed adults before counting and pagination while retaining child profiles. Rental and skate-cover selection includes every active user. These selection screens do not run a search until a non-empty query is submitted.

## Verification

Run `php tests/user_search_test.php` against an isolated database prepared with `scripts/prepare-rollpoints-tests.php`. The test fills the isolated database's `user` table inside a rolled-back transaction and verifies terms, Polish character matching, wildcards, literal SQL wildcard characters, parent contacts, categories, context eligibility, and pagination without changing application data.
