Skip to content

mlh's requested edits#469

Merged
Adr1an04 merged 9 commits into
mainfrom
mlhedits
Jun 18, 2026
Merged

mlh's requested edits#469
Adr1an04 merged 9 commits into
mainfrom
mlhedits

Conversation

@morallyearlgrey

@morallyearlgrey morallyearlgrey commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Why

MLH reached out requesting the following changes as a requirement for 2027 Season Launch certification:

  1. Phone number must be mandatory for hacker applications.
  2. School selection must reflect the updated MLH schools list (https://github.com/MLH/mlh-policies/blob/master/schools.csv).
  3. MLH consent checkboxes must reflect new changes.

What

School list: Updated FORMS.SCHOOLS to match the latest CSV (let me know if we want to prioritize the Florida schools at the top).
MLH checkboxes: Updated checkbox copy to reflect current MLH + DEV language. The "agree to receive emails" checkbox is now optional per MLH guidance, while the Code of Conduct and data sharing checkboxes remain required.
Phone number (form): Added min(1, "Required") validation to the hacker application form Zod schema. The member profile form is unaffected (phone number is still optional here).
Phone number (db): Updated the knight_hacks_hacker table to set phone_number as NOT NULL. Updated createHacker and updateHacker mutations.
Migration files: Schema change was generated via pnpm db:generate.

Test Plan

Verified locally against a test hackathon by submitting applications under the following conditions:

  • Submitting with no phone number → blocked with is required error
  • Submitting with a blank phone number → blocked with invalid number error
  • Submitting with a valid phone number → passes
  • Submitting without checking one or both required MLH checkboxes → blocked
  • Submitting with both required MLH checkboxes checked → passes
  • Submitting with and without the optional MLH email checkbox → both pass

Confirmed local DB changed. Frontend also displayed correct error/pass feedback. Migration files showed changes to schema.

Loink to testing vid: https://youtu.be/Nyqvqi-Al5M

Checklist

  • pnpm db:generate run and migration files committed
  • No environment variable changes

Summary by CodeRabbit

  • New Features

    • Improved combo box mobile/desktop search with relevance ranking and smarter filtering.
  • Bug Fixes

    • Updated hacker application form phone number rules and prefill behavior.
    • Adjusted hydration-aware navigation and button enable/disable states.
    • Simplified MLH/DEV email consent agreement UI and updated consent text.
  • Improvements

    • Enforced non-null phone numbers and updated related database/schema behavior.
    • Refreshed the schools list ordering and entries.

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 29855a24-315b-4349-a965-9b747927cd03

📥 Commits

Reviewing files that changed from the base of the PR and between 60b3851 and d989a1f.

📒 Files selected for processing (1)
  • apps/blade/src/app/_components/dashboard/hacker/hacker-application-form.tsx

📝 Walkthrough

Walkthrough

Makes phoneNumber required (NOT NULL) across the DB schema, SQL migration, and API mutations (writing "" instead of null). The hacker application form tightens phone validation, introduces hydration tracking to gate navigation, and relaxes the MLH email consent checkbox to optional with updated label text referencing DEV. The profile form fallback behavior is updated to use logical-or instead of nullish coalescing. The SCHOOLS constant is reordered and expanded with new entries. The responsive combo box gains fuzzy-search scoring utilities for better item filtering.

Changes

Phone Number Required & MLH/DEV Consent Changes

Layer / File(s) Summary
DB schema: phoneNumber NOT NULL constraint and migration
packages/db/src/schemas/knight-hacks.ts, packages/db/drizzle/0009_smooth_forgotten_one.sql, packages/db/drizzle/meta/_journal.json, packages/db/drizzle/meta/0009_snapshot.json
Adds .notNull() to Hacker.phoneNumber, generates the SQL migration to backfill NULL to '' and enforce the constraint, and registers the migration in Drizzle journal and snapshot.
API mutations: empty string instead of null
packages/api/src/routers/hackers/mutations.ts
createHacker and updateHacker now persist "" instead of null when input phone number is empty; change-logging comparison updated to work directly with normalized values.
Form: phone validation, hydration gating, and navigation control wiring
apps/blade/src/app/_components/dashboard/hacker/hacker-application-form.tsx, apps/blade/src/app/_components/settings/hacker-profile-form.tsx
Tightens Zod regex to accept only 10 digits or XXX-XXX-XXXX; introduces hasHydrated state to gate navigation button disabled states and prevent navigation before hydration; updates profile form phoneNumber fallback from nullish coalescing (??) to logical-or (||); wires Back, Next, and Submit button disabled props to hydration-aware computed state.
Form: MLH/DEV consent relaxed and relabeled
apps/blade/src/app/_components/dashboard/hacker/hacker-application-form.tsx
Removes must-be-true refinement from agreesToReceiveEmailsFromMLH, strips error styling and required marker, updates checkbox label to "MLH + DEV" for occasional emails, and rewrites data-sharing agreement links to reference DEV.

SCHOOLS Constant Updates

Layer / File(s) Summary
SCHOOLS array: reordered and new entries
packages/consts/src/forms/schools.ts
Removes Florida institutions from leading position and reinserts them alphabetically; adds new entries including Asansol Engineering College, California Institute of Technology, Abbey Park High School, Dwight School London, Geeta University, and others.

Responsive Combo Box Search Scoring

Layer / File(s) Summary
Search: scoring functions and ItemList integration
packages/ui/src/responsive-combo-box.tsx
Introduces fuzzy-search scoring helpers (normalization, acronym derivation, stop-word filtering, multi-heuristic relevance scoring); refactors ItemList to memoize scored results, sort by relevance, and limit output; disables Command's built-in filtering in favor of precomputed scored list with index-aware keying.

Sequence Diagram

sequenceDiagram
  participant User
  participant HackerForm as HackerFormPage
  participant Hydration
  participant API
  participant DB
  User->>HackerForm: load application form
  HackerForm->>Hydration: mount & detect hydration
  Hydration-->>HackerForm: set hasHydrated=true after mount
  User->>HackerForm: fill phone (10 digits or XXX-XXX-XXXX)
  User->>HackerForm: uncheck MLH+DEV consent (now optional)
  HackerForm->>API: submit form (phoneNumber="", agreesToReceiveEmailsFromMLH=false)
  API->>DB: createHacker/updateHacker with "" instead of null
  DB-->>API: hacker record saved
  API-->>HackerForm: success
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • KnightHacks/forge#465: Both PRs modify navigation controls (Back/Next/submit button UI and wiring) in HackerFormPage, with this PR adding hydration-aware disabled state gating to prevent premature form submission.

Suggested labels

Feature, Major, Blade, API, Database, Constants, UI

Suggested reviewers

  • DVidal1205
  • DGoel1602
🚥 Pre-merge checks | ✅ 6 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title does not start with an issue number in brackets (e.g., '[#123]') as required, and lacks a concise description of the changes. Update the title to follow the format '[#ISSUE_NUMBER] Brief description' and keep it under 72 characters. Example: '[#XXX] Add MLH certification updates for 2027 season'
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No Hardcoded Secrets ✅ Passed Comprehensive search across all modified files found no hardcoded API keys, passwords, tokens, or secrets as string literals. Code changes are legitimate (form validation, DB schema, MLH updates, U...
Validated Env Access ✅ Passed No direct process.env usage found in any of the 6 modified code files. All files comply with the validated env access pattern.
No Typescript Escape Hatches ✅ Passed No instances of TypeScript escape hatches (any, @ts-ignore, @ts-expect-error, or non-null assertions) found in the modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mlhedits

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/api/src/routers/hackers/mutations.ts (1)

31-39: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Enforce phone validation in the API instead of persisting empty strings

The API currently allows "" and explicitly stores it (Lines 127 and 210). With NOT NULL, this still permits “missing” phone numbers and bypasses required-phone enforcement outside this one form client.

Suggested server-side hardening
+const phoneNumberSchema = z
+  .string()
+  .min(1, "Phone number is required")
+  .regex(/^\d{10}$|^\d{3}-\d{3}-\d{4}$/, "Invalid phone number");

 createHacker: protectedProcedure
   .input(
     z.object({
       ...InsertHackerSchema.omit({
         userId: true,
         age: true,
         discordUser: true,
       }).shape,
+      phoneNumber: phoneNumberSchema,
       hackathonName: z.string(),
     }),
   )

 ...
-            phoneNumber:
-              hackerData.phoneNumber === "" ? "" : hackerData.phoneNumber,
+            phoneNumber: hackerData.phoneNumber,

 updateHacker: protectedProcedure
   .input(
-    InsertHackerSchema.omit({
+    InsertHackerSchema.omit({
       userId: true,
       age: true,
       discordUser: true,
-    }),
+    }).extend({
+      phoneNumber: phoneNumberSchema,
+    }),
   )

-      const normalizedPhone = phoneNumber === "" ? "" : phoneNumber;
+      const normalizedPhone = phoneNumber;

As per coding guidelines, packages/api/** requires robust Zod input validation across procedures; relying on frontend-only validation breaks that contract.

Also applies to: 126-127, 182-188, 210-210

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/api/src/routers/hackers/mutations.ts` around lines 31 - 39, The
input schema for this mutation is allowing empty string values for the phone
field, which should be rejected at the API level. Add explicit Zod validation
for the phone field in the input schema to enforce that it must be a non-empty
string, using something like z.string().min(1) instead of allowing empty
strings. This applies to all similar mutation procedures in the hackers router
that accept phone input to ensure server-side validation enforces the phone
requirement consistently across all API endpoints.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/db/drizzle/0009_smooth_forgotten_one.sql`:
- Line 1: The migration in the drizzle SQL file attempts to set a NOT NULL
constraint on the "phone_number" column in the "knight_hacks_hacker" table, but
this will fail if existing NULL values are present in that column. Add a data
cleanup step before the ALTER TABLE statement that either backfills NULL values
with a sensible default (such as an empty string or a placeholder value) or
deletes rows with NULL phone_number values, depending on your business
requirements. This ensures the migration is deterministic and will not fail
during deployment on databases that contain legacy NULL values in that column.

---

Outside diff comments:
In `@packages/api/src/routers/hackers/mutations.ts`:
- Around line 31-39: The input schema for this mutation is allowing empty string
values for the phone field, which should be rejected at the API level. Add
explicit Zod validation for the phone field in the input schema to enforce that
it must be a non-empty string, using something like z.string().min(1) instead of
allowing empty strings. This applies to all similar mutation procedures in the
hackers router that accept phone input to ensure server-side validation enforces
the phone requirement consistently across all API endpoints.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: f023ddd7-b4e8-41aa-9a57-55d5db139a59

📥 Commits

Reviewing files that changed from the base of the PR and between 3206fdf and cbc4752.

📒 Files selected for processing (7)
  • apps/blade/src/app/_components/dashboard/hacker/hacker-application-form.tsx
  • packages/api/src/routers/hackers/mutations.ts
  • packages/consts/src/forms/schools.ts
  • packages/db/drizzle/0009_smooth_forgotten_one.sql
  • packages/db/drizzle/meta/0009_snapshot.json
  • packages/db/drizzle/meta/_journal.json
  • packages/db/src/schemas/knight-hacks.ts

Comment thread packages/db/drizzle/0009_smooth_forgotten_one.sql
@Adr1an04 Adr1an04 self-requested a review June 17, 2026 23:52

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/blade/src/app/_components/settings/hacker-profile-form.tsx (1)

102-104: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep hacker profile edits aligned with the required phone contract.

This form updates the hacker application row via updateHacker, but it still accepts "" and labels the phone number optional. That lets existing/edited hacker applications keep a blank phone number despite this PR making phone required.

🐛 Proposed fix
       phoneNumber: z
         .string()
-        .regex(/^(\d{10}|\d{3}-\d{3}-\d{4})?$/, "Invalid phone number"),
+        .min(1, "Required")
+        .regex(/^\d{10}$|^\d{3}-\d{3}-\d{4}$/, "Invalid phone number"),
                 <FormLabel>
-                  Phone Number
-                  <span className="text-gray-400">
-                    {" "}
-                    , <i>Optional</i>
-                  </span>
+                  Phone Number <span className="text-destructive">*</span>
                 </FormLabel>

Also applies to: 228-228, 358-371

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/blade/src/app/_components/settings/hacker-profile-form.tsx` around lines
102 - 104, The phoneNumber field in the hacker profile form currently allows
empty strings due to the optional pattern in the regex, which conflicts with the
requirement to make phone mandatory. Update the phoneNumber validation in the
schema to enforce phone as required: remove the optional pattern markers from
the regex (the trailing and internal `?` characters) and ensure the field does
not accept empty strings, so that edited hacker applications must include a
valid phone number in either the ten-digit or XXX-XXX-XXXX format.
apps/blade/src/app/_components/dashboard/hacker/hacker-application-form.tsx (1)

2106-2119: ⚠️ Potential issue | 🟡 Minor

Fix duplicate "administration" in MLH consent wording.

Line 2108–2109 contains redundant text: "event administration, ranking, and administration." Since the parenthetical describes "creation of linked accounts," use "account creation" as the third item for clarity and conciseness.

📝 Suggested fix
-                                  Major League Hacking for event administration,
-                                  ranking, and administration (including the
+                                  Major League Hacking for event administration,
+                                  ranking, and account creation (including the
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/blade/src/app/_components/dashboard/hacker/hacker-application-form.tsx`
around lines 2106 - 2119, The MLH consent wording in the
hacker-application-form.tsx file contains a duplicate word "administration" in
the phrase "event administration, ranking, and administration." Replace the
second instance of "administration" with "account creation" to make the text
read "event administration, ranking, and account creation" since the
parenthetical immediately following describes the creation of linked accounts on
MLH and DEV platforms.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/blade/src/app/_components/dashboard/hacker/hacker-application-form.tsx`:
- Around line 1031-1034: The navigation button disabled states in the
hacker-application-form component are currently conditioned on hasHydrated being
true, which means the buttons render enabled before hydration completes,
allowing clicks that get dropped by the goToStep guard. Fix the
backButtonDisabled and forwardButtonDisabled variable assignments by inverting
the hydration check: change hasHydrated to !hasHydrated and replace the AND
operator with an OR operator so that buttons start disabled until hydration
completes. For backButtonDisabled, the condition should be !hasHydrated OR
(activeStep === 0 || navigationLocked), and for forwardButtonDisabled, it should
be !hasHydrated OR navigationLocked.

---

Outside diff comments:
In `@apps/blade/src/app/_components/dashboard/hacker/hacker-application-form.tsx`:
- Around line 2106-2119: The MLH consent wording in the
hacker-application-form.tsx file contains a duplicate word "administration" in
the phrase "event administration, ranking, and administration." Replace the
second instance of "administration" with "account creation" to make the text
read "event administration, ranking, and account creation" since the
parenthetical immediately following describes the creation of linked accounts on
MLH and DEV platforms.

In `@apps/blade/src/app/_components/settings/hacker-profile-form.tsx`:
- Around line 102-104: The phoneNumber field in the hacker profile form
currently allows empty strings due to the optional pattern in the regex, which
conflicts with the requirement to make phone mandatory. Update the phoneNumber
validation in the schema to enforce phone as required: remove the optional
pattern markers from the regex (the trailing and internal `?` characters) and
ensure the field does not accept empty strings, so that edited hacker
applications must include a valid phone number in either the ten-digit or
XXX-XXX-XXXX format.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 9e88ce1e-b0d4-464a-9e44-0e2e38d59691

📥 Commits

Reviewing files that changed from the base of the PR and between cbc4752 and 60b3851.

📒 Files selected for processing (6)
  • apps/blade/src/app/_components/dashboard/hacker/hacker-application-form.tsx
  • apps/blade/src/app/_components/settings/hacker-profile-form.tsx
  • packages/api/src/routers/hackers/mutations.ts
  • packages/consts/src/forms/schools.ts
  • packages/db/drizzle/0009_smooth_forgotten_one.sql
  • packages/ui/src/responsive-combo-box.tsx
✅ Files skipped from review due to trivial changes (1)
  • packages/consts/src/forms/schools.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/api/src/routers/hackers/mutations.ts

Comment thread apps/blade/src/app/_components/dashboard/hacker/hacker-application-form.tsx Outdated
@Adr1an04 Adr1an04 added this pull request to the merge queue Jun 18, 2026
Merged via the queue into main with commit dad3342 Jun 18, 2026
11 checks passed
@Adr1an04 Adr1an04 deleted the mlhedits branch June 18, 2026 05:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants