Skip to content

[feature][admin-v2] Applicant blacklist scan#114

Open
jasperjjhe wants to merge 1 commit into
mainfrom
jasper/applicant-blacklist-scan
Open

[feature][admin-v2] Applicant blacklist scan#114
jasperjjhe wants to merge 1 commit into
mainfrom
jasper/applicant-blacklist-scan

Conversation

@jasperjjhe

Copy link
Copy Markdown

Summary

This PR adds a client-side blacklist auto-scan flow to Evaluator. Applicants are matched against a global Firestore blacklist in real time, surfaced in a dedicated sidebar section, and disabled in the main applicant list without mutating applicant records.

Scope Implemented

  • Added runtime blacklist matching by normalized email (toLowerCase().trim()).
  • Added a new Blacklisted accordion section at the top of the applicant sidebar.
  • Added disabled/greyed-out behavior for blacklisted applicants in the main list.
  • Wired blacklist subscription into evaluator state so updates react to both applicant and blacklist changes.
  • Added non-fatal error handling so blacklist read failures do not crash Evaluator.

Firestore Data Model

The implemented read path is:

  • Hackathons/blacklist/entries
    • Hackthons/blacklist is a document path shape so we must add a sub-collection

Each entry document supports:

  • email (required for matching)
  • firstName
  • lastName
  • notes (optional)

Note: Since Firestore is schemaless, we cannot inherently enforce fixed columns or required fields. We could add Firestore security rules for this. It's usually done on app-side but since this is expected to be a manual thing within Firestore we can consider adding a security rule.

Behaviour Details

  • Matching is exact after normalization and only uses email.
  • No applicant documents are modified; blacklist state is derived at runtime.
  • Blacklisted applicants:
    • appear in the Blacklisted sidebar section with count
    • are clickable there to focus the centre panel
    • remain visible but non-clickable in the main list
  • Blacklist section defaults open when matches exist (including async load case).
  • Blacklist accordion updates live if entries updated.
  • Not sure what spec intended with displaying banned hackathons. Will follow up.
  • Within entries the firstName and lastName are never used. Should this be intended?

Files Updated

  • types.ts
  • blacklist.ts
  • blacklist-section.tsx
  • applicant-entry.tsx
  • applicant-list.tsx
  • evaluator-provider.tsx
  • accordion.tsx
  • package.json
  • pnpm-lock.yaml

Firestore Rules / Environment Changes

  • Dev Firestore added document at Hackathons/blacklist then entries sub-collection; needs to be applied to Prod Firestore before rollout.
  • Dev Firestore rules were updated to allow reads for:
    • /Hackathons/blacklist/entries/{entryId}
  • This same rules update must be applied to Prod Firestore before rollout, or production Evaluator will fail to read blacklist entries with Missing or insufficient permissions.

Testing / Verification

  • Confirmed blacklist entries load in real time after dev rules update.
  • Confirmed matched applicants appear in Blacklisted section.
  • Confirmed matched rows are disabled in main applicant list.
  • Confirmed non-fatal behaviour when blacklist reads fail (warning logs, evaluator remains usable).

…pplicants

- add blacklist models and service for Firestore subscription + case-insensitive email matching
- render a collapsible Blacklisted section in Applicant List with count, details, and focus-on-click
- keep matched applicants visible in main list but greyed out and non-interactive
- wire blacklist subscription into evaluator provider and derive matches at runtime without mutating applicant docs
- handle blacklist fetch/subscription failures as non-fatal to keep evaluator usable
- add accordion UI dependency updates (radix-ui) and lockfile changes
@jasperjjhe jasperjjhe requested a review from geoff-jiang July 2, 2026 09:19
@jasperjjhe jasperjjhe added the enhancement New feature or request label Jul 2, 2026
@jasperjjhe

Copy link
Copy Markdown
Author

Checks seem to be failing benignly. Some naming normalization bug within the check itself.

? "bg-theme/10 hover:bg-theme/15 active:bg-theme/15"
: "hover:bg-theme/5 active:bg-theme/15",
"h-full w-full flex-row justify-between gap-0 rounded-none",
disabled

@geoff-jiang geoff-jiang Jul 6, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be slightly confusing for others seeing just a greyed-out row. Could you add a 'blacklist' chip to these entries as well so its clear?

eg. next to Applicant X label

@geoff-jiang

geoff-jiang commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@jasperjjhe looks great overall - love the clean design 🐐. Could you try running the biome scripts locally again (lint, format) because I'm seeing a few unordered CSS class and import warnings.

To address your questions in the ticket:

  1. Re: 'display banned hackathon' - the notion blacklist page also has a column for the hackathon that the incident occurred. No need to include it in the schema, apologies for the confusion.
  2. Circumventing w diff email is not a problem we've run into (afaik). Might have to leave this one for the future, unless you also want to add a 'potential matches' section with exact first + last name matches. I think name matching is inherently difficult though due to nicknames, legal names, diff people w the same name etc.
  3. Using the name from the applicant entry is fine.

Once this is merged, you can proceed with mirroring the dev firestore setup in prod. Please add the rule for admin-only reads and writes!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants