Skip to content

Feature/251 waitlist landing page#330

Merged
bllr777 merged 23 commits into
fix/employee-role-assignment-migrationfrom
feature/251-waitlist-landing-page
May 25, 2026
Merged

Feature/251 waitlist landing page#330
bllr777 merged 23 commits into
fix/employee-role-assignment-migrationfrom
feature/251-waitlist-landing-page

Conversation

@bllr777
Copy link
Copy Markdown
Collaborator

@bllr777 bllr777 commented May 25, 2026

No description provided.

bllr777 and others added 23 commits May 15, 2026 21:03
…gration

fix(api): populate empty AddEmployeeRoleAssignment migration
…gration

refactor(api): replace EmployeeInvite.RoleIdsCsv with EmployeeInviteRoleAssignments join table
…tus-default

fix(api): default EmployeeInvite.Status to Pending so accept-by-code works
…oints-allow-anonymous

fix(api): allow anonymous access to invite lookup and accept endpoints
StripePaymentProcessor.RefundPaymentAsync previously let StripeException propagate to ErrorHandlingMiddleware, which converted every Stripe error into a generic STRIPE_UNAVAILABLE 503. Now the processor catches StripeException and returns a PaymentOperationResult failure with the actual Stripe error message, which the controller surfaces as a 400 BadRequest.

Changes:
[1] Wrapped refundService.CreateAsync in try/catch(StripeException) — returns failure result with ex.StripeError?.Message

References:
[1] [JobFlow.Infrastructure/PaymentGateways/Stripe/StripePaymentProcessor.cs:155](https://github.com/Katharix/JobFlow.API/blob/feature/288-fix-stripe-refund-exception-handling/JobFlow.Infrastructure/PaymentGateways/Stripe/StripePaymentProcessor.cs#L155)
…xception-handling

fix(api): Catch StripeException in RefundPaymentAsync [AB#288]
Added an early-return guard in PaymentController.RefundPayment: if the provider is Stripe and the org's StripeConnectAccountId is null or whitespace, return a 400 with a descriptive message before attempting the refund. This prevents the 'No such payment_intent' error that occurs when the refund is sent to the platform account instead of the connected account.

Changes:
[1] Early BadRequest when StripeConnectAccountId is missing for a Stripe refund

References:
[1] [JobFlow.API/Controllers/PaymentController.cs:457](https://github.com/Katharix/JobFlow.API/blob/feature/288-fix-stripe-refund-exception-handling/JobFlow.API/Controllers/PaymentController.cs#L457)
…xception-handling

fix(api): [AB#288] guard null StripeConnectAccountId before refund
Fixed the invite redirect URL to point to the correct Angular route, and changed resend behaviour to revoke the existing pending invite rather than rejecting the request.

Changes:
[1] Revoke existing pending invite on resend instead of returning AlreadyInvited error
[2] Fixed redirect URL from /invite/{token} to /i/{shortCode} to match Angular route

References:
[1] [JobFlow.Business/Services/EmployeeInviteService.cs:52](https://github.com/Katharix/JobFlow.API/blob/feature/288-fix-stripe-refund-exception-handling/JobFlow.Business/Services/EmployeeInviteService.cs#L52)
[2] [JobFlow.Business/Services/EmployeeInviteService.cs:207](https://github.com/Katharix/JobFlow.API/blob/feature/288-fix-stripe-refund-exception-handling/JobFlow.Business/Services/EmployeeInviteService.cs#L207)
…xception-handling

fix(api): [AB#288] fix employee invite redirect and resend
…ccount linking

- Add EmployeeInvite email template (id 7) with friendlier copy including org and role

- Add AcceptInviteRequest DTO carrying firebaseUid, firstName, lastName

- Introduce IFirebaseUserManager abstraction in Business + FirebaseUserManager impl in Infrastructure (keeps FirebaseAdmin out of Business)

- Rewrite AcceptInviteAsync to link Firebase UID to a new User + Employee, assign OrganizationEmployee role, and set custom claims

- Add EmployeeInviteErrors.FirebaseUidRequired and AccountLinkFailed
…xception-handling

feat(api): [AB#288] redesign employee invitation flow with Firebase account linking
AcceptInviteAsync now finds existing Employee by Email+OrgId and updates in place (clears + re-adds RoleAssignments), preventing duplicate rows when admin resends an invite to a previously-orphaned employee.
…xception-handling

feat(api): [AB#288] de-dupe Employee on invite accept
Added POST /assignments/{id}/en-route endpoint for client en-route notifications and fixed assignment DTO to fall back to client address when assignment has no address set.

Changes:
[1] Added POST en-route endpoint in AssignmentController calling NotifyEnRouteAsync
[2] Added NotifyEnRouteAsync in AssignmentService to send client en-route notification
[3] Added client address fallback in MapToDtoAsync when assignment address fields are empty
[4] Added BuildClientJobTrackingEnRoute notification message builder
[5] Added SendClientJobTrackingEnRouteNotificationAsync to notification service
[6] Updated interfaces and test stub for new notification method

References:
[1] [JobFlow.API/Controllers/AssignmentController.cs:126](https://github.com/Katharix/JobFlow.API/blob/fix/mobile-bugs-backend/JobFlow.API/Controllers/AssignmentController.cs#L126)
[2] [JobFlow.Business/Services/AssignmentService.cs:349](https://github.com/Katharix/JobFlow.API/blob/fix/mobile-bugs-backend/JobFlow.Business/Services/AssignmentService.cs#L349)
[3] [JobFlow.Business/Services/AssignmentService.cs:425](https://github.com/Katharix/JobFlow.API/blob/fix/mobile-bugs-backend/JobFlow.Business/Services/AssignmentService.cs#L425)
[4] [JobFlow.Business/Notifications/Builders/NotificationMessageBuilder.cs:213](https://github.com/Katharix/JobFlow.API/blob/fix/mobile-bugs-backend/JobFlow.Business/Notifications/Builders/NotificationMessageBuilder.cs#L213)
[5] [JobFlow.Business/Notifications/NotificationService.cs:135](https://github.com/Katharix/JobFlow.API/blob/fix/mobile-bugs-backend/JobFlow.Business/Notifications/NotificationService.cs#L135)
[6] [JobFlow.Tests/FollowUpAutomationServiceTests.cs:275](https://github.com/Katharix/JobFlow.API/blob/fix/mobile-bugs-backend/JobFlow.Tests/FollowUpAutomationServiceTests.cs#L275)
feat(api): En-route client notification and address fallback [AB#266]
- Add EmailTemplate.WaitlistConfirmation = 8
- Add BrevoListIds.Waitlist = 5 to BrevoService
- Add INotificationMessageBuilder.BuildWaitlistSignup + implementation
  (confirmation email: founding-member $19/mo rate reserved)
- Add INotificationService.SendWaitlistSignupNotificationAsync + implementation
- Add POST /api/email/waitlist-signup endpoint: Turnstile verify (waitlist-signup),
  adds contact to Brevo list 5 (hardcoded, not client-supplied), fires
  confirmation email fire-and-forget with CancellationToken.None
- Add SendWaitlistSignupNotificationAsync stub to NoOpNotificationService in tests

ADO: #251, #254
- Add FoundingMemberInvite domain model and EF configuration
- Add FoundingMemberInviteStatus enum (Queued, InviteSent, Redeemed, Expired)
- Add FoundingMemberService with capacity check, waitlist join, invite send, redeem logic
- Add FoundingMemberController with endpoints: capacity (anon), waitlist join, invite send (admin), redeem, list
- Add FoundingMemberInviteJob (Hangfire recurring): ProcessPendingInvites + ExpireStaleInvites
- Add FoundingMemberErrors model errors
- Add FoundingMemberInviteDto
- Add FoundingMemberGoPrice to StripeSettings
- Register DI and Hangfire recurring jobs in Program.cs
- Add EF migration: AddFoundingMemberInvites
- Extend Organization model with IsFoundingMember, FoundingMemberSince, FoundingMemberForfeitedAt
- Wire founding member redemption into stripe webhook (subscription created event)
- Add waitlist invite email template
…t stub

## Summary
WaitlistConfirmation was mapped to Brevo template ID 8 (the invoice template),
causing waitlist signup emails to render invoice content. Corrected to template ID 2.
Also adds missing SendFoundingMemberInviteNotificationAsync stub to test NoOpNotificationService.

## Changes
### Business
- EmailTemplate.WaitlistConfirmation: 8 -> 2

### Tests
- NoOpNotificationService: add SendFoundingMemberInviteNotificationAsync stub
…ites

## Summary
The initial AddFoundingMemberInvites migration created Token, SentAt, ExpiresAt,
and RedeemedAt as non-nullable, but the domain model defines them as nullable.
This migration corrects the column nullability and recreates the unique index
on Token with a null filter.

## Changes
### Infrastructure.Persistence
- Migration FoundingMemberInviteSentinel: alter Token/SentAt/ExpiresAt/RedeemedAt
  to nullable; recreate IX_FoundingMemberInvites_Token with IS NOT NULL filter
- Update model snapshot
…ging

## Summary
If MigrateAsync() throws at startup (e.g. transient DB connectivity issue,
schema mismatch on staging), the entire process was crashing before UseCors
ran — causing 503 on ALL endpoints and no CORS headers on any response.

Wrap MigrateAsync in try-catch so the app starts and serves requests even
if the migration step fails. The error is logged for ops visibility.

## Changes
### API
- Program.cs: wrap startup MigrateAsync in try-catch with error logging
@bllr777 bllr777 merged commit 6aaac5c into fix/employee-role-assignment-migration May 25, 2026
10 checks passed
@bllr777 bllr777 deleted the feature/251-waitlist-landing-page branch May 25, 2026 15:00
bllr777 added a commit that referenced this pull request May 25, 2026
…gration

Merge pull request #330 from Katharix/feature/251-waitlist-landing-page
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