Skip to content

212 error email#227

Open
chnnick wants to merge 12 commits intomainfrom
212-error-email
Open

212 error email#227
chnnick wants to merge 12 commits intomainfrom
212-error-email

Conversation

@chnnick
Copy link
Copy Markdown

@chnnick chnnick commented Apr 1, 2026

ℹ️ Issue

Closes #212

📝 Description

Write a short summary of what you added. Why is it important? Any member of C4C should be able to read this and understand your contribution -- not just your team members.

Because the DTO already includes input validation, I added a filter on the controller that handles BadRequestExceptions and sends the user an email with the errors in human-readable format.

Example DTO with input validation:
Screenshot 2026-04-01 at 1 15 23 AM

Briefly list the changes made to the code:

  1. Created logic for sending emails when a form validation error happens at the controller-level
  2. Put logic in NestJS filter
  3. Added Filter as a provider in the applications module
  4. Put the filter as a decorator on POST route on the applications controller for creating new applications
  5. Imported email services into applications module to allow for finding user names by application and sending emails
  6. Matched the email to the template provided
  7. Made the email error messages much more human readable by translating from camelCase
  8. Created tests for newly-created filters, these run on the HTTP layer when endpoints first receive data regarding an application.

✔️ Verification

What steps did you take to verify your changes work? These should be clear enough for someone to be able to clone the branch and follow the steps themselves.

Example email:
Screenshot 2026-04-01 at 1 12 05 AM

🏕️ (Optional) Future Work / Notes

Got rid of input validation in service, as it is redundant and requests hitting the endpoint already get validated and error-handled by the controller. The filter handles errors thrown by controller-level validation errors, and sends emails from there

@SamNie2027 SamNie2027 self-requested a review April 1, 2026 11:44
Copy link
Copy Markdown
Collaborator

@SamNie2027 SamNie2027 left a comment

Choose a reason for hiding this comment

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

Please resolve the failing tests

* POST /api/applications endpoint fails due to validation errors.
*
* Applied at the controller-method level so it only intercepts
* BadRequestExceptions thrown during application creation.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It should intercept all error messages, not just BadRequestExceptions.
If the other Exceptions/ Errors aren't covered too, then a person will submit a Pandadoc and we will error out, causing their application not to be a part of our database, and the person who submitted it will never know that it failed.

'No email found in request body. Skipping error email.',
);
} else {
const applicant = await this.usersService.findOne(recipientEmail);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Don't check for applicant existing at this point - because at this point the user won't even exist yet, this is at step 1 when the user submits the pandadoc before any data about them is written in the backend

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I am checking for this because I need to get the name of the applicant as per the email template. This name field does not exist in ApplicationDTO, but in Users which is tied to the application via its email? Should I fetch the name from somewhere else? or just Ignore the name field


if (!applicant) {
this.logger.warn(
`No user found for email: ${recipientEmail}. Skipping error email.`,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

To the above point ^ don't have this check

);
} else {
const applicantName = `${escapeHtml(
applicant.firstName,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Get the firstname and lastname from the application data from pandadoc instead, not the applicant as previously discussed

import { UsersService } from '../users/users.service';
import { FIELD_LABELS } from './types';

function escapeHtml(text: string): string {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Documentation here would be nice

* "appStatus must be one of..." → "Application Status must be one of..."
* "each value in interest must be one of..." → "Each value in Areas of Interest must be one of..."
*/
private humanizeErrorMessage(message: string): string {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Remember to include info about the parameter when doing documentation

applicantName: string,
requestBody: Record<string, unknown>,
errorMessages: string[],
): string {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Remember to include info about parameter format when doing documentation and also include what it returns

* Only includes fields that have a friendly label defined in FIELD_LABELS.
* Skips null/undefined values.
*/
private formatSubmittedFields(body: Record<string, unknown>): string {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Again remember to put info about the parameters in the documentation

}

/** User-friendly labels for request body fields displayed in the error email. */
export const FIELD_LABELS: Record<string, string> = {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

My issue with this is that this is not the pandadoc fields - these are out database fields, which are in a different format than what the applicant submits.
Instead of fixing this, if alternatively you can find evidence that pandadoc can send a copy of their submission back to the user every time they submit, then that will negate the need for this

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yea i totally agree i think having a mapping is a bit impractical, ill go look around for functionality on how to get pandadoc to send a copy of the submission in human-readable format over

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Can use this instead to fetch the fields:
https://developers.pandadoc.com/reference/document-details

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Would require saving a formsubmission document ID, and using that ID to fetch
Screenshot 2026-04-03 at 2 30 01 PM

chnnick added 8 commits April 3, 2026 13:26
…error when processing email past the DTO validation stage + moved filters to filter folder
… before app validation (NestJS reverses the order) no longer need to check for badrequestexception in the second filter
@chnnick chnnick requested a review from SamNie2027 April 5, 2026 02:51
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.

Send Email to candidate when application creation errors (they filled pandadoc wrong)

2 participants