Skip to content

MSPCA-8/create & withdraw match endpoints - #7

Merged
Yurika-Kan merged 14 commits into
mainfrom
yk/mspca-8-create-withdraw-match
Oct 6, 2026
Merged

Yurika-Kan merged 14 commits into
mainfrom
yk/mspca-8-create-withdraw-match

Conversation

@Yurika-Kan

@Yurika-Kan Yurika-Kan commented Sep 29, 2026 •

Copy link
Copy Markdown

ℹ️ Issue

Closes MSPCA-8

📝 Description

Volunteers can apply to foster an animal and withdraw their own application without going through a coordinator. The assigned coordinator is emailed on each new application.

  1. POST /matches: creates a match from a volunteer ID and a Chameleon animal ID. Status is always PENDING, set server-side.
  2. CreateMatchDto validates both IDs, and whitelist: true strips extra body fields so a client can't set status itself.
  3. Emails the volunteer's assigned coordinator via the assignedCoordinator relation. Placeholder body for now.
  4. PATCH /matches/:matchId/withdraw: sets status to WITHDRAWN. Only PENDING matches qualify, anything else is a 400. The record is kept, so volunteers still see withdrawn applications.
  5. validateId in the controller: 400 on a bad ID, 404 when not found.
  6. Registered MatchesModule and CoordinatorsModule in AppModule; no match route was mounted before.
  7. Service and controller tests.

If the volunteer has no coordinator, or the send fails, the match is still created and the problem is logged.

✔️ Verification

yarn test and yarn prepush pass. No AWS setup needed: EmailsService no-ops unless SES_ENABLED=true. Set AUTH_DISABLED=true locally, so no bearer token is required.

  1. curl -X POST http://localhost:3000/api/matches -H 'Content-Type: application/json' -d '{"volunteerId":1,"chameleonAnimalId":42}' → 201, "Pending"
  2. curl -X PATCH http://localhost:3000/api/matches/1/withdraw → 200, "Withdrawn"
  3. Repeat step 2 → 400. ID 0 → 400. ID 9999 → 404.
image

🏕️ (Optional) Future Work / Notes

Align with PR-3

Out of scope: no duplicate-match check, no authorization (any volunteer can withdraw another's application), and VolunteersModule is still unregistered in AppModule.

POST /matches creates a PENDING match from a volunteer and Chameleon
animal ID, then emails the volunteer's assigned foster coordinator.
Volunteers with no assigned coordinator still get a match; the send is
logged and skipped. Email failures are logged rather than surfaced,
since the match is already committed by then.

PATCH /matches/:matchId/withdraw sets a match to WITHDRAWN. The record
is kept so volunteers can still see their withdrawn applications.

Registers MatchesModule in AppModule, which previously imported only
CognitoModule, so no match route was mounted.
Copilot AI balanced review requested due to automatic review settings September 29, 2026 22:16

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Once a coordinator has approved, denied or cancelled an application,
reversing it is their call rather than the volunteer's, so withdraw now
rejects any match that is not PENDING with a 400.
Covers the From address from AWS_SES_SENDER_EMAIL, To/Cc in both the
SES Destination and the MIME headers, Bcc in Destination only, empty
address lists omitted from Destination, attachment encoding, and error
propagation from the SES client.
columnName was declared with a single parameter, so it never received
TypeORM's customName argument and discarded every explicit
@column({ name: '...' }). Queries used the TS property name instead of the
real column, e.g. "column Match.matchId does not exist" against a table
whose column is match_id.

DefaultNamingStrategy already resolves customName || propertyName. The
tableName override was also redundant: every entity passes an explicit name
to @entity(), so the pluralization branch never ran.
Comment thread apps/backend/src/strategies/plural-naming.strategy.ts

@dburkhart07 dburkhart07 left a comment

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.

mostly some small nits, but looking great. thanks for adding in docstrings for service tests too!

Comment thread apps/backend/src/config/typeorm.ts
Comment thread apps/backend/src/matches/dtos/create-match.dto.ts Outdated
Comment thread apps/backend/src/matches/matches.controller.ts
Comment thread apps/backend/src/matches/matches.service.ts
Comment thread apps/backend/src/matches/matches.controller.spec.ts
Comment thread apps/backend/src/matches/matches.service.spec.ts
Comment thread apps/backend/src/matches/matches.service.spec.ts Outdated
Comment thread apps/backend/src/matches/matches.service.spec.ts Outdated
Comment thread apps/backend/src/aws/ses/awsSes.wrapper.spec.ts Outdated
Comment thread apps/backend/src/aws/ses/awsSes.wrapper.spec.ts
Yurika-Kan and others added 4 commits October 1, 2026 02:00
Bring back the naming strategy, keeping only the tableName override. The
columnName and relationName overrides stay out: columnName was declared with
a single parameter, so it never received TypeORM's customName argument and
discarded every explicit @column({ name: '...' }), producing errors like
"column Match.matchId does not exist".

DefaultNamingStrategy already resolves customName || propertyName, so the
mapping is correct without those overrides.
Assert the coordinator email subject and body name the volunteer and
animal, and run the real SendEmailDTO decorators over the payload the
service builds, since EmailsService is stubbed in these tests.
@Yurika-Kan
Yurika-Kan force-pushed the yk/mspca-8-create-withdraw-match branch from 2954e38 to 736bf48 Compare October 1, 2026 06:36
Swap @min(1) for @ispositive on volunteerId and chameleonAnimalId to match
the validators used in the other PRs. Also tighten the controller spec:
mocks are now set per test, invalid bodies run through the real
ValidationPipe, and service exceptions are asserted to pass through
the handler untouched.
Tag the controller as Matches and add an ApiOperation, happy-path
ApiResponse, and ApiParam where there is a path param, so the endpoints
are readable in Swagger without opening the repo.
Set mock return values inside the tests that need them, assert the
volunteer and match lookups get the right arguments, rename the email
failure test to say it still creates the match, and keep one
non-pending status case instead of all five.
Note that it never throws, since the match is already committed when it
runs and the email is best-effort.
@Yurika-Kan
Yurika-Kan requested a review from dburkhart07 October 1, 2026 07:43

@dburkhart07 dburkhart07 left a comment

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.

mostly small comments so imma approve. tested both endpoints, emails are working, yay!!!!

Comment thread apps/backend/src/matches/matches.service.ts Outdated
Comment thread apps/backend/src/matches/matches.service.spec.ts
Comment thread apps/backend/src/matches/matches.service.spec.ts Outdated
Comment thread apps/backend/src/matches/matches.service.spec.ts Outdated
Comment thread apps/backend/src/matches/matches.controller.ts Outdated
Comment thread apps/backend/src/matches/matches.controller.spec.ts
Comment thread apps/backend/src/matches/matches.service.spec.ts
Comment thread apps/backend/src/matches/matches.controller.ts
…hdraw-match

# Conflicts:
#	apps/backend/src/app.module.ts
#	apps/backend/src/matches/matches.service.spec.ts
#	apps/backend/src/matches/matches.service.ts
- use the volunteers service findActiveOrFail instead of a local active check
- load the assigned coordinator relation in findByIdOrFail so match emails
  still go out
- use the httpstatus enum and document 400/404 responses on both match
  endpoints
- define mock implementations per test in the match service spec

@shreeyaadhikari shreeyaadhikari 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.

everything looks good to me!!

@Yurika-Kan
Yurika-Kan merged commit 92daa3f into main Oct 6, 2026
10 checks passed
@Yurika-Kan
Yurika-Kan deleted the yk/mspca-8-create-withdraw-match branch October 6, 2026 19:55
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.

4 participants