Pre-request feedback
User story
As a Zenika employee, I would like to request feedback from colleagues when I don't know their email addresses upfront. Instead of specifying individual emails, I can generate a shareable "magic link" that colleagues can use to provide their email address and trigger a feedback request.
This is particularly useful when:
- I want to share the request in a Slack channel or Teams group
- My colleagues' company blocks emails sent via Mailgun. However, they can still give me feedback using their personal email addresses, which I don't know in advance.
Once a colleague uses the magic link and provides their email, they receive a feedback request email just like in the standard feedback request workflow.
Technical specifications
Be sure to read Request feedback first, as this feature is an enhancement of that workflow.
Magic link generation workflow
- The requester (authenticated user) navigates to
/request - Selects "With a magic link" method
- Fills and Submits the form (the recipients field is disabled for this method)
- Client calls
POST /feedback/pre-request/token - Server creates a document in the
feedbackPreRequestTokencollection and returns{ token: string } - Client navigates to the success page displaying the magic link
The requester can copy this link and share it through any channel (Slack, Teams, email, etc.).
Firestore schema
A document is added in the feedbackPreRequestToken collection to store magic link tokens:
const preRequestToken: FeedbackPreRequestToken = {
receiverEmail: 'pinocchio@zenika.com', // Who will receive the feedback
message: 'Hi team, please share your feedback...', // Encrypted
shared: true, // Whether to share with manager
expiresAt: 1711662999463, // Timestamp
usedBy: ['gimini@gmail.com', 'gepetto@gmail.com'], // Emails that used this token
};
- The document ID is the token itself (auto-generated by Firestore).
- The
usedByarray tracks which emails have already used this token - Each use of the token triggers a separate feedback request
Magic link format
The magic link format is: {origin}/pre-request/token/{token}
Example:
https://feedzback.znk.io/pre-request/token/abc123xyz
The magic link does not contain the locale.
The redirection to /fr or /en occurs when the colleague visits the magic link page (see src/404.html for details).
However, since this redirection is not functional in the dev-local environment, the locale is explicitly added only in this case.
Example in dev-local environment:
https://feedzback.znk.io/fr/pre-request/token/abc123xyz
Magic link usage workflow
When a colleague accesses the magic link:
- The colleague (not authenticated) visits
/pre-request/token/{token} - The colleague's browser redirects to the appropriate locale (example:
/fr/pre-request/token/{token}) - Client calls
GET /feedback/check-pre-request/{token}to validate the token - If valid, the page displays the details of the pre-request and a form field allowing the colleague to enter their email address
- The colleague enters their email and submits
- Client calls
POST /feedback/pre-request/emailwith{ token, recipient } - Server validates the token and email, then:
- Adds the email to the
usedByarray infeedbackPreRequestTokendocument - Triggers the standard feedback request workflow:
- Creates
feedbackandfeedbackRequestTokendocuments - Sends a feedback request email to the colleague
- Creates
- Adds the email to the
- Client navigates to a success page confirming the email was sent
From this point forward, the flow is identical to the standard Reply to feedback request workflow.
Token constraints
- Expiration configured via
FEEDBACK_PRE_REQUEST_EXPIRATION_IN_DAYSconstant (3 days) - Maximum uses configured via
FEEDBACK_PRE_REQUEST_MAX_USESconstant (10 uses per token)
When a colleague attempts to use a magic link, the following checks are performed:
| Validation | Error Type | Description |
|---|---|---|
| Token exists | token_invalid | The token doesn't exist in the database |
| Not expired | token_expired | The current time exceeds expiresAt |
| Under max uses | token_max_uses_reached | The usedBy array length has reached the limit |
| Email not used | recipient_already_used | The email is already in the usedBy array |
| Not self-request | recipient_forbidden | The email matches the receiverEmail |
If any validation fails, a BadRequestException or ForbiddenException is thrown with the corresponding error type.
Links
- Client
- Server
FeedbackControllerpreRequestToken- Creates pre-request tokencheckPreRequest- Validates token and returns detailspreRequestEmail- Processes email submission and triggers feedback request