backend implementation on NPS Satisfaction Survey Automation and Door…#1311
Merged
yusuftomilola merged 1 commit intoJun 29, 2026
Merged
Conversation
… Access Hardware Integration (Kisi / Brivo)
|
@feyishola is attempting to deploy a commit to the naijabuz's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@feyishola Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
… Access Hardware Integration (Kisi / Brivo)
closes #1232
closes #1230
What's Been Implemented
Goal: Automatically measure member satisfaction after completed bookings.
What was built:
NpsSurveyResponse entity — tracks both survey sends and member responses in one table (score/comment/submittedAt are null until the member responds; createdAt serves as the "sent at" timestamp for rate limiting)
Bull queue processor (nps-survey) — picks up delayed jobs and fires the survey email 2 hours after booking completion
NpsService:
scheduleIfEligible — checks the 30-day rate limit, deduplicates by booking, inserts the NpsSurveyResponse record, then enqueues the delayed job
respond — validates ownership, rejects duplicate submissions, writes score/comment/submittedAt
getSummary — computes promoters (9–10), passives (7–8), detractors (0–6), NPS score (P% − D%) × 100, average, and recent comments
getResponses — paginated admin view of submitted responses
3 REST endpoints:
POST /nps/respond — member submits score + comment
GET /nps/summary — admin aggregate stats
GET /nps/responses — admin paginated raw responses
Email template (nps-survey.hbs) + EmailService.sendNpsSurveyEmail()
CompleteBookingProvider modified — after status → COMPLETED, fires scheduleIfEligible non-blocking (skips guest bookings)
Goal: Auto-grant door access on booking confirmation and revoke it on cancellation or completion.
What was built:
AccessIntegration entity — singleton config row storing the active provider (KISI or BRIVO), AES-256-CBC encrypted API key, enabled flag, and provider-specific doorGroupId in a JSONB meta column
AccessCredential entity — per-booking log of every grant/revoke event (externalCredentialId, provider, isActive, grantedAt, revokedAt)
KisiProvider — calls Kisi API v3: resolves user by email (or creates via invite), creates a group grant, stores the grant ID; deletes grant on revoke
BrivoProvider — calls Brivo API: finds user by email, assigns a credential template, stores credential ID; deletes credential on revoke
DoorAccessService:
configure — upsert integration config, encrypts API key before storing
getStatus — returns { configured, provider, isEnabled }
grantAccess — decrypts key, calls the right provider, saves AccessCredential
revokeAccess — finds the active credential by bookingId, calls provider revoke, marks isActive = false
getLogs — paginated credential event log
3 REST endpoints (admin-only):
POST /integrations/access/configure
GET /integrations/access/status
GET /integrations/access/logs
3 booking providers modified (all non-blocking):
ConfirmBookingProvider → grantAccess on CONFIRMED
CancelBookingProvider → revokeAccess on CANCELLED
CompleteBookingProvider → revokeAccess on COMPLETED (alongside NPS scheduling)
Shared patterns across both features
All side-effects (email sends, provider API calls) are fire-and-forget with .catch(() => void 0) — failures never break the core booking response
Both modules export their primary service and are imported into BookingsModule and AppModule
TypeORM synchronize: true means both entities auto-create their tables on next boot — no migration needed