DFE-Digital / DFE-Digital/check-performance-data

Track when users search for a pupil by CYPMD ID or UPN instead of by name

Open
#419 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
C#
Stars
0
Forks
1
Avg merge
19h 21m
Merged PRs (30d)
54

Description

Why

Julia asked whether we can tell when a user searches for a pupil by CYPMD ID or UPN instead of by name, in the change journeys. Two requirements:

  • detect numeric-only and UPN-shaped input and record it as a possible ID/UPN search attempt
  • record it once per search interaction, not once per character typed into the autocomplete

Feasibility has been checked. Both parts are possible and most of the plumbing already exists. Estimate ~0.5 day, no architectural change.

What we already have

  • A client-side beacon built for exactly this. wwwroot/js/analytics-events.js posts to /client-events, and ClientEventsController builds the typed event server-side from an allowlist of event names, so the client cannot inject arbitrary fields. Three events already use it (help_details_expanded, external_link_clicked, evidence_file_selected). The script loads on every page from _Layout.cshtml:275 and the antiforgery token is already exposed there.
  • Identifier search already works. PupilSuggestionFormat.Matches does a StartsWith against UPN/ULN and against the CYPMD ID, plus date of birth on 16-19. A user who types a CYPMD ID does get a hit today. This is a measure of how people search, not a broken path.
  • The suggestions endpoint fires on every keystroke. The autocomplete calls /pupils/suggestions on each character from two upwards, with no debounce (Views/Journey/PupilSearch.cshtml:129). Counting server-side gives one row per character, which is the noise the second requirement is about. De-duplication has to happen in the browser.

Detecting the input shape

Classify in the browser and send a token only, never the typed text:

Token Rule Catches
upn ^[A-Za-z]\d{11}[0-9A-Za-z]$ 13-character UPN: check letter, serial, optional trailing letter
numeric ^\d{4,}$ CYPMD ID and ULN, without depending on either exact length
date ^\d{1,2}[/\-.]\d{1,2} Date-of-birth attempts, kept apart from ID attempts
name everything else The baseline to measure the others against

Sending the token alone keeps the rule already written into docs/bigquery-analytics.md: no free text and no pupil identifiers as plain fields. Sending the raw query would mean marking it Hidden, and putting a UPN into hidden_data is a DPO decision, not a delivery-team one. Recommend the token only.

Once per search interaction

In the page script:

  • debounce ~800 ms after typing stops, then classify the current input value
  • hold a set of classifications already sent for this page view, so each fires at most once. Typing a CYPMD ID, deleting it and typing a name produces two events, not forty
  • also fire on onConfirm and on form submit, so an abandoned search is still counted

Tasks

  • Add a PupilSearchInputTypeEvent record in Application/Analytics/, carrying input_type, page_path and the checking window type
  • Add one arm to the ClientEventsController allowlist, re-validating the token against the four permitted values so a forged post cannot widen the field
  • Add the classifier and debounce to analytics-events.js, gated on #pupil-search so _Autocomplete.cshtml and _PupilSearch.cshtml pick it up too, rather than inline in one view
  • Unit tests beside ClientEventsControllerTests and ClientEventsTests
  • Add a row to the event catalogue in docs/bigquery-analytics.md

To settle before the work starts

  • The metric on its own is not actionable. Because identifier search already works, input_type answers "how often do users reach for an ID?" and not "where does it fail?". To make it useful, pair the token with whether the search found anything, so ID searches that returned nothing are visible. Doing that server-side returns us to one row per keystroke; the clean compromise is to attach the result count of the last suggestions response to the same client beacon.
  • The real CYPMD ID format is unconfirmed. The dev seed uses six digits (SeedPupilData.cs:108,178), which is a local convenience and not the supplier's contract. The numeric catch-all avoids depending on it, but we should not claim the metric separates a CYPMD ID from a ULN until the supplier's shape is confirmed.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with wwwroot/js/analytics-events.js and the ClientEventsController allowlist, then inspect the existing ClientEventsControllerTests and ClientEventsTests. Check the pupil search wiring in Views/Journey/PupilSearch.cshtml and the shared autocomplete views before deciding how the page-view de-duplication works. Done means the permitted input tokens are recorded once per interaction, tests cover the classifier and endpoint, and docs/bigquery-analytics.md lists the event.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, javascript
Domain
analytics, full-stack
Issue type
Feature
Difficulty
3/5
Estimated time
Half a day
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.