Skip to content

Enforce program support email#4039

Open
devkiran wants to merge 4 commits into
mainfrom
enforce-program-support-email
Open

Enforce program support email#4039
devkiran wants to merge 4 commits into
mainfrom
enforce-program-support-email

Conversation

@devkiran

@devkiran devkiran commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Added stricter validation for the program support email field to require a properly formatted email address.
  • Bug Fixes

    • Improved onboarding checks so submissions correctly fail when required onboarding fields are missing, including support email.
    • Updated form initialization/state handling so empty support email inputs are treated consistently, reducing confusing validation outcomes.
    • Tightened support email schema behavior to accept valid emails (when provided) and treat it as optional rather than null-based.

@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dub Ready Ready Preview Jun 19, 2026 11:23am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

supportEmail is promoted from an optional/nullable field to a required one in the program onboarding flow. updateProgramSchema changes supportEmail from nullish() to optional(), programSupportSchema is extended with an explicit email validator for supportEmail, four intermediate onboarding schemas are de-exported, the onboarding overview UI's isValid check now gates form progression on supportEmail being present, and form components adjust type derivation and value mapping to align with the schema contract.

Changes

supportEmail required in program onboarding

Layer / File(s) Summary
Schema contracts: supportEmail nullish→optional and programSupportSchema extension
apps/web/lib/zod/schemas/programs.ts, apps/web/lib/zod/schemas/program-onboarding.ts
updateProgramSchema.supportEmail changes from z.email().max(255).nullish() to z.email().max(255).optional(), removing null as valid. programSupportSchema is redefined locally and extended with an explicit z.email().max(255) validator for supportEmail. programInfoSchema, programRewardSchema, and programInvitePartnersSchema are also changed from exported to local constants.
UI isValid gate includes supportEmail
apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/overview/page-client.tsx
isValid useMemo destructures supportEmail from form data and returns false when it is absent, in addition to existing checks for name, url, domain, logo, type, and amount.
Form integration: schema-derived types and value coercion
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/resources/program-help-and-support.tsx, apps/web/ui/partners/program-onboarding-form-wrapper.tsx
ProgramHelpAndSupportContent redefines FormData to derive field types from updateProgramSchema via z.infer and adjusts defaultValues.supportEmail to coerce falsy values to undefined. ProgramOnboardingFormWrapper removes the `

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • steven-tey

Poem

🐇 A rabbit checked the form one day,
"No support email? You can't play!"
nullish gone, optional too—
The schema now demands its due.
Forms align from dash to wrap,
Hop along, there's no gap! ✉️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective of the PR—enforcing supportEmail as a required field during program onboarding—and directly corresponds to the primary changes across all modified files.
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.

✏️ 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 enforce-program-support-email

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
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/web/lib/zod/schemas/programs.ts (1)

106-106: 💤 Low value

Misleading comment: field is optional() but comment says "required".

The comment states support email is required, but this schema marks it as .optional(). The actual requirement is enforced in programSupportSchema (in program-onboarding.ts). Consider clarifying or removing the comment to avoid confusion.

-  supportEmail: z.email().max(255).optional(), // Support email is required for a program
+  supportEmail: z.email().max(255).optional(), // Requirement enforced in programSupportSchema for onboarding
🤖 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/web/lib/zod/schemas/programs.ts` at line 106, The comment on the
`supportEmail` field in the `supportEmail: z.email().max(255).optional()` line
is misleading because it states the field is required, but the schema marks it
as `.optional()`. Remove or clarify this comment to accurately reflect that the
field is optional in this schema, but note that the actual requirement is
enforced in the `programSupportSchema` in `program-onboarding.ts` to avoid
confusion for future maintainers.
🤖 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.

Nitpick comments:
In `@apps/web/lib/zod/schemas/programs.ts`:
- Line 106: The comment on the `supportEmail` field in the `supportEmail:
z.email().max(255).optional()` line is misleading because it states the field is
required, but the schema marks it as `.optional()`. Remove or clarify this
comment to accurately reflect that the field is optional in this schema, but
note that the actual requirement is enforced in the `programSupportSchema` in
`program-onboarding.ts` to avoid confusion for future maintainers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4230e566-e0a6-446f-958c-2812ee6bf3de

📥 Commits

Reviewing files that changed from the base of the PR and between 9e76dc7 and f4ebc5b.

📒 Files selected for processing (3)
  • apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/overview/page-client.tsx
  • apps/web/lib/zod/schemas/program-onboarding.ts
  • apps/web/lib/zod/schemas/programs.ts

@devkiran

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review please

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read all changed files
echo "=== programs.ts ===" 
cat apps/web/lib/zod/schemas/programs.ts

echo ""
echo "=== program-onboarding.ts ==="
cat apps/web/lib/zod/schemas/program-onboarding.ts

echo ""
echo "=== page-client.tsx (overview) ==="
cat "apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/overview/page-client.tsx"

echo ""
echo "=== program-help-and-support.tsx ==="
cat apps/web/app/app.dub.co/\(dashboard\)/\[slug\]/\(ee\)/program/resources/program-help-and-support.tsx

echo ""
echo "=== program-onboarding-form-wrapper.tsx ==="
cat apps/web/ui/partners/program-onboarding-form-wrapper.tsx

Length of output: 26076


🏁 Script executed:

#!/bin/bash
echo "=== updateProgramAction ==="
fd "update-program" apps/web/lib/actions --type f -x cat {}

echo ""
echo "=== onboard-program action ==="
fd "onboard-program" apps/web/lib/actions --type f -x cat {}

echo "=== ProgramData type ==="
rg -n "ProgramData" apps/web/lib/types.ts | head -20
rg -n "supportEmail" apps/web/lib/types.ts

echo ""
echo "=== Check DB update for supportEmail ==="
rg -rn "supportEmail" apps/web/lib --include="*.ts" -C 2

Length of output: 15674



@devkiran: Here's my full review of PR #4039Enforce program support email.


Summary

The PR correctly enforces supportEmail as a required field during the onboarding flow: the programSupportSchema now requires it explicitly, the page-client.tsx overview gate checks for it before enabling "Create program", and the program-onboarding-form-wrapper.tsx stops coercing it to null. The settings-page form also marks the field required. Overall the approach is sound. A few things to tighten up:


1. Misleading comment in programs.ts

supportEmail: z.email().max(255).optional(), // Support email is required for a program

The comment contradicts the code — the field is .optional() in this schema (by necessity, since updateProgramAction uses .partial() over it). Suggest removing or rewording the comment, e.g.:

supportEmail: z.email().max(255).optional(), // Required during onboarding; see programSupportSchema

2. No server-side guard at the create-program step (most important)

When the "Create program" button is clicked, it calls onboardProgramAction with { step: "create-program", workspaceId }. The schema for that discriminated union variant is:

z.object({
  step: z.literal("create-program"),
  workspaceId: z.string(),
}),

This carries no supportEmail — the action delegates straight to createProgram(), which reads supportEmail from the workspace store. There's nothing on the server that verifies the stored programOnboarding data actually has a supportEmail before the program is created.

A user who calls the server action directly (bypassing the UI's isValid guard) can create a program without a support email. Consider adding a guard inside createProgram (or the create-program branch of onboardProgramAction) that reads the stored programOnboarding data and validates the required fields — or at minimum checks supportEmail:

if (data.step === "create-program") {
  const stored = store?.programOnboarding;
  if (!stored?.supportEmail) {
    throw new Error("Support email is required to create a program.");
  }
  await createProgram({ workspace, user, isProgramOnboarding: true });
  return;
}

3. programDataSchema type vs. reality in page-client.tsx

ProgramData (inferred from programDataSchema) has supportEmail: string as required (via the programSupportSchema.shape spread with z.email().max(255)). But the form's stored data may not have it populated yet (e.g., user jumps directly to the overview step). The isValid check correctly handles this at runtime, but TypeScript won't flag the !supportEmail guard as necessary — a small type/reality gap worth keeping in mind if the type is used elsewhere.


4. Minor: no email format validation in RHF for the settings form

In program-help-and-support.tsx:

{...register("supportEmail", {
  required: true,
})}

The required: true rule prevents submission when empty, but RHF won't validate email format client-side — relying on type="email" (browser-level) and server-side Zod. This is acceptable, but adding pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ or a validate function would give consistent inline error messages via RHF's formState.errors.


Nits

  • program-onboarding-form-wrapper.tsxhelpUrl: programOnboarding.helpUrl || null still coerces falsy to null (correct, those fields are nullish() in their schema). Consistent with the change removing || null only for supportEmail. ✅
  • updateProgramAction passes supportEmail directly into the Prisma data object. When supportEmail is undefined (field not submitted), Prisma skips it — so the existing email is preserved. ✅
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 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/web/lib/zod/schemas/programs.ts`:
- Line 106: The inline comment for the supportEmail field in the programs schema
contradicts the actual schema definition. The field is marked as optional() but
the comment states "Support email is required for a program," which is incorrect
and misleading. Update the comment on the supportEmail field to accurately
reflect that the field is optional, not required, or clarify the intent if this
is intentional and the optional requirement is conditional.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: e7e24ce3-58a3-4af5-8c5e-285d4ff5f50a

📥 Commits

Reviewing files that changed from the base of the PR and between 7bbacf9 and 14cb8bd.

📒 Files selected for processing (5)
  • apps/web/app/(ee)/app.dub.co/(new-program)/[slug]/program/new/overview/page-client.tsx
  • apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/resources/program-help-and-support.tsx
  • apps/web/lib/zod/schemas/program-onboarding.ts
  • apps/web/lib/zod/schemas/programs.ts
  • apps/web/ui/partners/program-onboarding-form-wrapper.tsx

message: `Minimum payout amount must be one of ${ALLOWED_MIN_PAYOUT_AMOUNTS.join(", ")}`,
}),
supportEmail: z.email().max(255).nullish(),
supportEmail: z.email().max(255).optional(), // Support email is required for a program

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix contradictory inline comment for supportEmail.

The schema is optional() here, but the comment says “required,” which misstates this specific contract and can mislead future edits.

Suggested clarification
-  supportEmail: z.email().max(255).optional(), // Support email is required for a program
+  supportEmail: z.email().max(255).optional(), // Required during onboarding; optional in update schema (often consumed via .partial())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
supportEmail: z.email().max(255).optional(), // Support email is required for a program
supportEmail: z.email().max(255).optional(), // Required during onboarding; optional in update schema (often consumed via .partial())
🤖 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/web/lib/zod/schemas/programs.ts` at line 106, The inline comment for the
supportEmail field in the programs schema contradicts the actual schema
definition. The field is marked as optional() but the comment states "Support
email is required for a program," which is incorrect and misleading. Update the
comment on the supportEmail field to accurately reflect that the field is
optional, not required, or clarify the intent if this is intentional and the
optional requirement is conditional.

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.

1 participant