Table of Contents
Introduction
TrustedCloud is a secure platform that allows users to easily sign up, log in, and manage their onboarding requests through personalized dashboards.
When users create an account using Sign Up or access an existing one through Sign In, they are automatically taken to a dashboard that matches their role and responsibilities in the system.
After logging in, users are directed to one of four dashboards:
- Admin Dashboard
- Applicant & Approver Dashboard
- Applicant & Auditor Dashboard
- Applicant Dashboard
Note:
New users are given the Applicant role by default when they first register. Later, administrators can update their roles and provide additional permissions if needed.
Applicants can submit onboarding requests through the platform.
Approvers and Auditors then review these requests — they can approve or reject them and add comments or feedback to help clarify their decisions.
Role-Based Dashboard Access
1. Admin Dashboard
Can view requests in:
Pending, Audited, Approved, RejectedCan access the list of all approved requests that exist in the Service List
2. Approver Dashboard
Can view requests in:
Audited, ApprovedCan see only rejected requests that were rejected by Approvers, not those rejected by Auditors
3. Auditor Dashboard
- Can view requests in:
Pending, Audited, Rejected
4. Applicant Dashboard
Can view requests in: Pending, Audited, Approved, Rejected
Overview
The TrustedCloud platform uses two independent UIBuilder frontends, each connected to its own Node-RED backend. Both frontends communicate through WebSocket channels for secure, real-time interaction between the browser and their respective Node-RED instances.
UIBuilder 1 – Authentication Interface:
handles user authentication flows — including Sign In, Sign Up, and Password Reset.
UIBuilder 2 – Dashboard Interface:
manages authenticated, role-based operations such as getDashboard, editProfile, archiveRequest, and others.
Although the backends are separate, both follow the same token-based authentication and authorization structure, ensuring consistent session validation and user experience across the system.
| Feature | Sign-In UIBuilder | Dashboard UIBuilder |
|---|---|---|
| Purpose | User authentication and registration | Role-based request management and dashboards |
| Token Handling | Generates and stores JWT in MongoDB | Validates and consumes JWT for session restoration |
| Communication | WebSocket (uibuilder) | WebSocket (uibuilder) |
| Key Identifiers |
clientId, socketId
|
clientId, userToken
|
| Backend Validation | Token existence, expiry, email/password match | Token validity, role extraction, route handling |
Authentication Interface
1. UIBuilder Frontend Initialization
When the user opens any authentication page — such as signup, login, sendResetCode, resendResetPassword, setNewPassword, or resetPassword — the Vue app starts the uibuilder connection:
uibuilder.start();
This initializes a WebSocket connection between the browser and Node-RED.
Each client is automatically assigned a unique clientId (stored as a uibuilder-client-id cookie), allowing Node-RED to respond directly to the same active user session.
2. Cookie-Based Session Check
On page load (mounted() hook), the app checks whether a userToken cookie already exists:
if (this.getCookie("userToken")) {
uibuilder.send({
auth: {
userToken: this.getCookie("userToken"),
clientId: this.getCookie("uibuilder-client-id"),
},
});
}
Purpose:
If the token exists, the backend verifies it and restores the user’s session automatically — enabling persistent login.
If no token is found, Node-RED treats it as a new session, and the user continues with normal authentication flow (e.g., login or signup).
3. Token Validation and Routing Flow
| Node Name | Type | Description |
|---|---|---|
| link in 1 | link in | Receives incoming messages from multiple linked flows and passes them to the uibuilder node. |
| uibuilder | uibuilder | Handles WebSocket communication between the frontend and Node-RED backend on the /signin URL. |
| ui output | debug | Displays the full message from the frontend in the debug sidebar for inspection. |
| Check Token | function | Checks if the incoming message contains a valid userToken. Sets msg.payload to hasToken or hasNotToken. |
| Token Route | switch | Routes messages based on token presence: with token → validate token in MongoDB, without token → handle authentication requests. |
| check URL | switch | Routes authentication requests by auth.type (e.g., signup, login, resetPassword, sendResetCode, setNewPassword, resendResetPassword). |
| Find Token | function | Extracts userToken from the message and prepares a MongoDB query to find it in the Tokens collection. |
| Find Token Record | mongodb4 | Executes the MongoDB find operation on the Tokens collection to locate the token document. |
| Token Expiration | function | Checks if the token exists and whether it’s expired. Returns status as empty, expired, or valid. |
| status | switch | Routes based on token validation result: expired and empty → back to frontend; valid → proceed to redirect. |
| Redirect | function | Constructs a redirect response message indicating that the user is already logged in. |
| link out 12 | link out | Sends output messages (responses) back to the uibuilder node for frontend delivery. |
| mongodb4-client | mongodb4-client | Defines the MongoDB connection configuration for the hediyehTC database hosted on DigitalOcean. |
4. Authentication Flow Integration
Once token validation is complete, the flow dynamically routes the request based on the auth.type received from the frontend.
Each auth.type corresponds to a dedicated backend sub-flow that performs specific MongoDB operations and response handling:
| Auth Type | Description | Target Collection |
|---|---|---|
| signup | Creates a new user record with validated credentials and role. | Users |
| login | Authenticates credentials and generates a new userToken. |
Users / Tokens |
| sendResetCode | Creates a verification code for password recovery. | PasswordResets |
| resendResetPassword | Regenerates or resends the reset code if expired. | PasswordResets |
| setNewPassword | Updates the password after verifying reset code. | Users / PasswordResets |
| resetPassword | Finalizes password change after verification. | Users / PasswordResets |
4.1 Sign Up Flow
High-level flow:
Frontend (Vue/React)
↓ uibuilder.send
Node-RED Flow
↓ MongoDB Users Collection
↓ uibuilder.onChange (response)
Frontend Redirect
When the user clicks Sign Up, this runs:
signupButton() {
const clientId = uibuilder.get("clientId");
uibuilder.send({
auth: {
clientId: clientId,
fullName: this.fullName,
email: this.email,
password: this.password,
confirmPassword: this.confirmPassword,
type: "signup"
}
});
}
Sample request payload:
{
"auth": {},
"clientId": "oD6i_WpIes8pBvWjNXy81",
"fullName": "hediyeh",
"email": "h@gmail.com",
"password": "111111",
"confirmPassword": "111111",
"type": "signup",
"_socketId": "kmN2iMG_VAMQ7WSFAEhJ",
"topic": "uibuilder",
"_msgid": "96c8e068f17bef90"
}
Backend Flow:
| Node Name | Type | Responsibility |
|---|---|---|
Validate Auth Payload |
Function | Checks payload existence, validates email format, attaches socketId, prepares original payload. |
User Query |
Function | Queries Users collection for existing email. |
Query Users Collection |
MongoDB | Executes the email query. |
Check Email Availability |
Function | Determines if email exists; sets status failed or prepares data for insertion. |
Evaluate Registration Status |
Switch | Routes flow based on payload.status (success or failed). |
Get Last User ID |
Function | Fetches highest id from Users collection to increment. |
Fetch Last User |
MongoDB | Executes query for last user document. |
Generate New User Data |
Function | Hashes password, generates roles, constructs profile, prepares insertOne payload. |
Insert New User |
MongoDB | Inserts new user document into the Users collection. |
Registration Success Response |
Function | Returns success response with redirect URL. |
set warning |
Function | Returns failure response when email exists. |
signin |
Debug | Logs final response for monitoring. |
- Node-RED receives the signup data.
- Validates if the email already exists.
- Hashes the password before saving to the Users collection.
- Returns a success message with:
{
"payload": {
"action": "register",
"status": "success",
"URL": "/hediyeh/trustedcloud2"
}
}
- The frontend receives it and redirects the user to the dashboard.
Sample Responses (uibuilder.onChange)
| Status | Response |
|---|---|
| Success | { "action": "register", "status": "success", "message": "You have registered successfully!", "URL": "https://codenxa.leanea.com/hediyeh/signin" } |
| Failure | { "action": "register", "status": "failed", "message": "Email already exists. Please use a different email." } |
MongoDB Users Collection Schema
| Field | Type | Description |
|---|---|---|
_id |
ObjectId | Unique document ID |
clientId |
string | Unique client identifier |
fullName |
string | User full name |
email |
string | Unique email |
password |
string | Hashed password |
confirmPassword |
string | Hashed password (same as password) |
roles |
array | Assigned roles (e.g., ["Applicant","Auditor"]) |
status |
string | Registration status (not_found, success) |
profile |
object | User profile data (avatar, first/last name, contact info) |
createdAt |
Date | Timestamp of account creation |
updatedAt |
Date | Last update timestamp |
Sample document:
{
"_id": "68f830f9d6c4398ea5f5cbdf",
"clientId": "GiHBKhnJvqNbA6dYRqWHF",
"fullName": "David Kim",
"email": "david.kim@brightwave.co",
"password": "$2b$10$MiGhJqBXNIJhayVOnqG1C...",
"roles": ["Applicant","Auditor"],
"status": "not_found",
"profile": {
"firstName": "David",
"lastName": "Kim",
"avatarUrl": "data:image/jpeg;base64,..."
},
"createdAt": "2025-10-22T01:18:49.129Z",
"updatedAt": "2025-10-28T02:20:04.260Z"
}
Security Considerations
- Passwords are hashed using bcrypt before storage.
- Emails must be unique; duplicate entries are rejected.
- The clientId is used to track frontend sessions securely.
- Ensure HTTPS is enforced for all frontend/backend communications.
4.2 Sign In Flow
High-Level Flow:
Frontend (Vue/React)
↓ uibuilder.send
Node-RED Flow
↓ MongoDB Users & Tokens Collections
↓ uibuilder.onChange (response)
Frontend Redirect / Error Handling
Frontend Sign In Action
When the user clicks the Sign In button, the following function runs:
signinButton() {
const isEmailValid = this.validateEmail();
const isPasswordValid = this.validatePassword();
if (!isEmailValid || !isPasswordValid) {
return;
}
const clientId = uibuilder.get("clientId");
uibuilder.send({
auth: {
clientId: clientId,
email: this.email,
password: this.password,
rememberMe: this.rememberMe,
type: "login"
}
});
}
Sample Request Payload:
{
"auth": {},
"clientId": "oD6i_WpIes8pBvWjNXy81",
"email": "h@gmail.com",
"password": "111111",
"rememberMe": false,
"type": "login",
"_socketId": "70nLJLlIrgzsiFLpAEhQ",
"topic": "uibuilder",
"_msgid": "2e88832acfbcd402"
}
Backend Node-RED Flow
| Node Name | Type | Responsibility |
|---|---|---|
Prepare Auth Data |
Function | Validates auth payload, ensures email exists, attaches socketId and saves original payload |
Prepare Filter for Email Check |
Function | Creates MongoDB query payload to find user by email |
Find User by Email |
MongoDB | Queries Users collection for the given email |
Check Email & Password |
Function | Compares entered password with stored hashed password; generates JWT if successful |
Check Login Result |
Switch | Routes flow based on payload.status (success or invalidCredentials) |
Sign JWT |
JWT Sign | Signs a JWT token using HS256 with 1-hour expiration |
Save JWT to DB |
Function | Prepares messages for both MongoDB Tokens collection insert and frontend response |
Prepare Filter for DB Insert |
Function | Inserts token into Tokens collection |
set warning |
Function | Returns failure response when credentials are invalid |
login |
Debug | Logs final response for monitoring |
Backend Flow Summary
- Node-RED receives login data from the frontend via
uibuilder.send. - Validates payload and ensures
emailis provided. - Queries the
Userscollection for the given email. - If the email exists, compares the entered password against the stored hashed password using
bcrypt. - If the password matches:
- Generates a JWT token.
- Prepares a
profileobject includinguserId,id,email,roles, andfullName. - Sends response to frontend and inserts token into Tokens collection.
- If the
emailorpasswordis invalid, returns a failure message with status invalidCredentials.
Sample Responses (uibuilder.onChange)
| Status | Response |
|---|---|
| Invalid Email | { "action": "login", "status": "invalidCredentials", "message": "Email not found." } |
| Invalid Password | { "action": "login", "status": "invalidCredentials", "message": "Password does not match." } |
| Success | { "action": "login", "status": "success", "message": "Logged In Successfully" } |
Security Considerations
- Passwords are stored as bcrypt hashes.
- JWT tokens are signed with a secret key and expire after 1 hour.
- Tokens are saved in the Tokens collection for session tracking.
- Always use HTTPS for communication between frontend and Node-RED.
- Ensure JWT tokens are stored securely on the client (
cookies with Secure;SameSite=Strict).
MongoDB Tokens Collection
| Field | Type | Description |
|---|---|---|
_id |
ObjectId | Unique document ID |
email |
string | User email |
userId |
string | MongoDB user _id
|
id |
number | Internal user ID |
token |
string | JWT token |
createdAt |
Date | Token creation timestamp |
expiresAt |
Date | Token expiration timestamp (1 hour by default) |
Sample Document
{
"_id": "69024c1bd6c4398ea5f5cd17",
"email": "david.kim@brightwave.co",
"userId": "68f830f9d6c4398ea5f5cbdf",
"id": 1,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9...",
"createdAt": "2025-10-29T17:17:15.326Z",
"expiresAt": "2025-10-29T18:17:15.326Z"
}
4.3 Reset Password Flow
High-Level Flow:
[User clicks "Forgot Password"]
│
▼
[Frontend: Sends reset request with email]
│
▼
[Node-RED: Validate Reset Request Input]
│
├── Invalid → Stop flow (missing auth/email)
└── Valid → Attach socketId & forward for email verification
Frontend Reset Password Action
When a user submits their email in the Forgot Password form, the frontend sends a request via uibuilder:
resetPasswordRequest() {
const clientId = uibuilder.get("clientId");
uibuilder.send({
auth: {
email: this.email,
type: "resetPassword"
},
_socketId: clientId
});
}
Sample Request Payload:
{
"auth": {
"email": "user@example.com",
"type": "resetPassword"
},
"_socketId": "TtK9mNkl_2Fh8Wx2K3DdW"
}
Backend Node-RED Flow
| Node Name | What It Does |
|---|---|
| resetPassword(in) | Entry point for the reset password flow; receives incoming reset requests. |
| Validate Reset Request Input | Checks that msg.auth and msg.auth.email exist, attaches socketId, saves original payload. |
| Users Collection | Prepares MongoDB find operation on the Users collection using the email. |
| Find User by Email | Queries the MongoDB Users collection to check if the email exists. |
| Validate User Existence | Checks the query result, sets msg.payload.status to success or invalidEmail, prepares user data. |
| Branch by User Status | Routes the flow based on user existence (success → generate code, invalidEmail → failure response). |
| Generate and Store Reset Code | Generates a 6-digit reset code, inserts a record into PasswordResets collection, sets expiration. |
| Insert Reset Code Record | Inserts the reset code record into MongoDB. |
| Compose Reset Email Message | Prepares the email content with the reset code to be sent to the user. |
| Prepare Success Response | Prepares the response message indicating that the reset code was sent. |
| Prepare Failure Response | Prepares the response message indicating the email was not found. |
| validEmail (debug) | Debug node to inspect successful reset responses in the sidebar. |
| invalidEmail (debug) | Debug node to inspect failed reset responses in the sidebar. |
Backend Flow Summary
Validate Reset Request Input
- Receives the reset request from the frontend via
uibuilder.send. - Validates that the
authobject andemailfield exist. - Attaches
socketIdand preserves the original payload for tracking. - Stops the flow if validation fails.
Prepare Filter for Email Check
- Constructs a MongoDB query:
{ email: msg.auth.email }. - Prepares the message for the next MongoDB node.
Find User by Email
- Queries the
Userscollection in MongoDB. - Returns an array (
msg.payload) containing matching user(s). - If no user is found → triggers a generic response to prevent enumeration attacks.
- If a user exists → forwards data to generate a reset token.
Generate Reset Token & Save (Next Step in Flow)
- Creates a unique 6-digit code or UUID token.
- Stores token in
ResetCodescollection with:userIdemailcreatedAtexpiresAtused: false
- Prepares payload for sending email.
Send Reset Code / Email
- Sends an email to the user with the reset code.
- Returns a generic success response to the frontend.
Sample Responses (uibuilder.onChange)
| status | Response |
|---|---|
| Valid request | { "status": "ok", "message": "Email validation initiated." } |
| Missing email | { "status": "error", "message": "Email is required." } |
MongoDB PasswordResets Collection
| Field | Type | Description |
|---|---|---|
_id |
ObjectId | Unique document ID |
email |
string | User email |
userId |
string | MongoDB _id of the user |
code |
string | One-time 6-digit reset code |
used |
boolean | Whether code has been used (default false) |
createdAt |
Date | Timestamp of token creation |
expiresAt |
Date | Expiration timestamp (e.g., 2 minutes) |
Sample Document
{
"_id": "69078db8d6c4398ea5f5cd54",
"code": "994015",
"email": "li@gmail.com",
"userId": "69076591d6c4398ea5f5cd48",
"id": 15,
"createdAt": "2025-11-02T16:58:32.299+00:00",
"expiresAt": "2025-11-02T17:00:32.299+00:00",
"used": false
}
4.4 sendResetCode Flow
High-Level Flow:
User clicks "Forgot Password" → Enter email
↓
Vue.js Frontend
↓ uibuilder.send
Node-RED Backend Flow
↓ MongoDB Users & ResetCodes
↓ uibuilder.onChange (response)
Frontend Shows Verification Code Input
Frontend Reset Password Action
handleDigitInput method
handleDigitInput(index, event) {
const value = event.target.value;
if (value && index < 5) {
this.verificationInputs[index + 1].focus();
} else if (value && index === 5) {
const allFilled = this.verificationDigits.every(digit => digit !== '');
if (allFilled) {
const code = this.verificationDigits.join('');
uibuilder.send({
auth: {
type: "sendResetCode",
email: this.resetEmail,
code: code
}
});
this.showVerificationSuccess = true;
}
}
}
-
verificationDigits.join('')ensures the code is concatenated properly. -
authpayload structure matches your sample request payload.
resendCode method
resendCode() {
this.verificationDigits = ['', '', '', '', '', ''];
this.startTimer();
uibuilder.send({
auth:{
email: this.resetEmail,
type: "resendResetPassword",
}
})
},
Sample Request Payload
{
"auth": {},
"type": "sendResetCode",
"code": "373600",
"email": "h@gmail.com",
"_socketId": "TQQZkMEJW3yr8AXbAEhi",
"topic": "uibuilder",
"_msgid": "563ae2fa2bd25a81"
}
Backend Node-RED Flow
| Node Name | Type | Responsibility / Description |
|---|---|---|
sendResetCode(in) |
Link In | Entry point for the send reset code flow; triggers when a reset code request comes in. |
Validate Auth & Prepare Payload |
Function | Validates that auth object and email exist; attaches socketId and stores original payload. |
Prepare DB Query |
Function | Prepares a MongoDB query to check if a reset code record exists for the email. |
Find Password Reset Record |
MongoDB4 | Queries the PasswordResets collection in MongoDB. Returns matching records as an array. |
Check Reset Record Existence |
Function | Checks if a record exists; sets status to success if found, invalidEmail if not. Prepares _data for next node. |
Branch by Status |
Switch | Routes the flow based on payload.status: success → process code, invalidEmail → failure response. |
Handle Invalid Email |
Function | Prepares payload for invalid email or missing code scenarios. |
link out 48 |
Link Out | Connects the invalid email path to the main response flow. |
Prepare DB Query (for code) |
Function | Prepares MongoDB query to find the specific reset code that is not used and matches the email/code. |
Find Password Reset Record |
MongoDB4 | Queries PasswordResets collection to verify the entered code. |
Check Reset Record Existence |
Function | Validates if code exists, is unused, and not expired. Sets success, invalidCode, or expired. |
Branch by Status (code) |
Switch | Routes flow based on code verification status: success → update used flag, invalidCode or expired → fail. |
Compare Code & Update Used Flag |
Function | Prepares updateOne operation to mark the reset code as used in MongoDB. |
Update Used Flag |
MongoDB4 | Executes the update operation to mark the reset code as used. |
Prepare Success Response |
Function | Prepares the success payload (validCode) for frontend consumption. |
validCode |
Debug | Displays success message and payload in the Node-RED sidebar. |
invalidEmail |
Debug | Displays invalid email or missing code payload in the sidebar. |
link out 49/50/51 |
Link Out | Connects the flow outputs to the main response flow to send back to frontend. |
Backend Flow Summary
User submits email
- Validated by
Validate Auth & Prepare Payload.
Check for existing reset record
- Nodes:
Prepare DB Query+Find Password Reset Record.
Record exists?
- Checked via
Check Reset Record Existence. - Branch by status:
- If invalid email → handled by
Handle Invalid Email. - If code entered → verify via
Find Password Reset Record+Check Reset Record Existence.
- If invalid email → handled by
Update used flag if valid
- Nodes:
Compare Code & Update Used Flag+Update Used Flag.
Send response back to frontend
- Nodes:
Prepare Success Responseand debug nodes.
Response Examples (uibuilder.onChange)
| Status | Response |
|---|---|
| invalidCode | { "action": "resetPassword", "status": "invalidCode", "message": "code not found" } |
| expired | { "action": "resetPassword", "status": "expired", "message": "your code has been expired" } |
| validCode | { "action": "resetPassword", "status": "validCode", "message": "Code matched successfully" } |
MongoDB PasswordResets Collection
| Field | Type | Description |
|---|---|---|
_id |
ObjectId | Unique document ID |
email |
string | User email |
userId |
string | MongoDB _id of the user |
code |
string | One-time 6-digit reset code |
used |
boolean | Whether code has been used (default false) |
createdAt |
Date | Timestamp of token creation |
expiresAt |
Date | Expiration timestamp (e.g., 2 minutes) |
Sample Document
{
"_id": "69078db8d6c4398ea5f5cd54",
"code": "994015",
"email": "li@gmail.com",
"userId": "69076591d6c4398ea5f5cd48",
"id": 15,
"createdAt": "2025-11-02T16:58:32.299+00:00",
"expiresAt": "2025-11-02T17:00:32.299+00:00",
"used": false
}
4.5 setNewPassword Flow
High-Level Flow:
User enters email & new password
↓
Frontend (Vue.js)
↓ uibuilder.send
Node-RED: setNewPassword flow
↓
Check email in MongoDB
↓
┌───────────────┐
│ Email exists │ → Update password → Success response
└───────────────┘
┌───────────────┐
│ Email invalid │ → Error response
└───────────────┘
↓
Frontend shows result
Frontend setNewPassword Action
submitNewPassword() {
if (!this.newPassword) {
alert('Please enter a new password');
return;
}
if (this.newPassword !== this.confirmNewPassword) {
alert('Passwords do not match');
return;
}
// Send new password to backend via uibuilder
uibuilder.send({
auth: {
type: "setNewPassword",
email: this.resetEmail,
password: this.newPassword
}
});
console.log('New password set for:', this.resetEmail);
// Close modal and reset fields
this.closeSetNewPasswordModal();
}
- Validates that both new password and confirmation are entered and match.
- Sends the
setNewPasswordaction along with the email and new password to the backend viauibuilder.send(). - Closes the modal and clears fields.
Sample Request Payload
{
"auth": {},
"type": "setNewPassword",
"email": "h@gmail.com",
"password": "123456",
"_socketId": "3hHNyKWUI-Khbn9cAEh0",
"topic": "TrustedCloud Password Reset Code – Action Required",
"_msgid": "4a86446e49c05025"
}
Backend Node-RED Flow
| Node Name | Type | Responsibility / Description |
|---|---|---|
setNewPassword(in) |
Link In | Entry point of the flow; receives the request to set a new password. |
Validate Auth & Prepare Payload |
Function | Checks if msg.auth exists and has an email. Adds socketId and preserves the original payload. |
Check User by Email |
Function | Prepares a MongoDB query to find the user in the Users collection by email. |
Find User Record |
MongoDB | Executes the query against the Users collection and returns the matching user document(s). |
Check if Email Exists in DB |
Function | Checks if the user exists. Prepares a response: success if email exists, invalidEmail if not. Also stores user data for further processing. |
Branch by Email Status |
Switch | Routes the flow depending on whether the email exists (success) or not (invalidEmail). |
Update User Password |
Function | Hashes the new password using bcrypt, prepares the MongoDB update operation, and stores a success response. |
Update User Password |
MongoDB | Updates the user’s password in the Users collection. |
Branch by Update Result |
Switch | Checks the result of the update operation; routes to success or invalid user. |
Prepare Success Response |
Function | Prepares the final success payload: "Password updated successfully" with status success. |
Handle Invalid Email |
Function | Prepares a response if the email was not found: "Email address not found" with status invalidEmail. |
Handle Invalid User |
Function | Prepares a response if the user is invalid: "User not found" with status invalidUser. |
invalidEmail |
Debug | Outputs invalid email response for debugging. |
success |
Debug | Outputs success response for debugging. |
invalidUser |
Debug | Outputs invalid user response for debugging. |
Backend Flow Summary
-
Validation & Payload Preparation (
Validate Auth & Prepare Payload)- Validates the request contains a valid
authobject and email. - Adds
socketIdand preserves the original payload for tracking.
- Validates the request contains a valid
Check User Existence (
Check User by Email+Find User Record)
Queries theUserscollection in MongoDB to verify whether the provided email exists.-
Decision Branching (
Check if Email Exists in DB+Branch by Email Status)- If the email exists: proceeds to update the password.
- If not: sends an
invalidEmailresponse.
-
Password Update (
Update User PasswordFunction + MongoDB node)- Hashes the new password using bcrypt.
- Updates it in the database.
- Prepares a success response.
-
Post-Update Decision (
Branch by Update Result)- If update is successful: sends
successresponse. - If the user is invalid or not found: sends
invalidUserresponse.
- If update is successful: sends
Response Handling (
Prepare Success Response,Handle Invalid Email,Handle Invalid User)
Response Examples (uibuilder.onChange)
| Status | Response |
|---|---|
| invalidEmail | { "action": "sendResetCode", "status": "invalidEmail", "message": "Email address not found." } |
| invalidUser | { "action": "setNewPassword", "status": "invalidUser", "message": "User not found." } |
| success | { "action": "setNewPassword", "status": "success", "message": "Password updated successfully." } |
MongoDB Users Collection Schema
| Field | Type | Description |
|---|---|---|
_id |
ObjectId | Unique document ID |
clientId |
string | Unique client identifier |
fullName |
string | User full name |
email |
string | Unique email |
password |
string | Hashed password |
confirmPassword |
string | Hashed password (same as password) |
roles |
array | Assigned roles (e.g., ["Applicant","Auditor"]) |
status |
string | Registration status (not_found, success) |
profile |
object | User profile data (avatar, first/last name, contact info) |
createdAt |
Date | Timestamp of account creation |
updatedAt |
Date | Last update timestamp |
Sample document:
{
"_id": "68f830f9d6c4398ea5f5cbdf",
"clientId": "GiHBKhnJvqNbA6dYRqWHF",
"fullName": "David Kim",
"email": "david.kim@brightwave.co",
"password": "$2b$10$MiGhJqBXNIJhayVOnqG1C...",
"roles": ["Applicant","Auditor"],
"status": "not_found",
"profile": {
"firstName": "David",
"lastName": "Kim",
"avatarUrl": "data:image/jpeg;base64,..."
},
"createdAt": "2025-10-22T01:18:49.129Z",
"updatedAt": "2025-10-28T02:20:04.260Z"
}
Dashboard Interface
1. UIBuilder Frontend Initialization
Before accessing any dashboard or request management page — such as getDashboard, editCompanyDetails, archiveRequest, editProfile, auditRequest, approveRequest, or createRequest — the user must be authenticated.
Once the user logs in or registers successfully, the Vue/React app starts the uibuilder connection:
uibuilder.start();
Key points:
- Establishes a WebSocket connection between the browser and Node-RED.
Each client is assigned a unique clientId
(stored as a uibuilder-client-id cookie)for session tracking.Every new user is initially assigned the Applicant role.
If a userToken exists and is valid, Node-RED restores the session and redirects the user to the correct dashboard based on their role.
If authentication fails or no token is present, the user must log in or register before accessing any dashboard or request functionality.
Purpose:
- Ensures that only authenticated users can access dashboards or perform request-related actions.
- Enables role-based access control and persistent login.
- Provides a consistent framework for all request types (getDashboard, editProfile, etc.).
2. Cookie-Based Session Check
On page load (mounted() hook in Vue or onMounted() in React), the app checks whether a userToken cookie already exists:
if (this.getCookie("userToken")) {
uibuilder.send({
auth: {
userToken: this.getCookie("userToken"),
clientId: this.getCookie("uibuilder-client-id"),
},
});
}
Behavior:
Token exists: Node-RED validates it and restores the session. The user is then redirected to the dashboard corresponding to their role (Applicant, Approver, Auditor, etc.).
Token missing or invalid: Node-RED treats it as a new session. The user must log in or register to access the dashboard or perform request-related actions.
Purpose:
- Enables persistent login across sessions.
- Ensures role-based access control from the first page load.
3. Token Validation and Routing Flow
| Node Name | Type | Description |
|---|---|---|
| Identify Action Type | function |
Checks the incoming message msg.type and sets flags like _archiveRequest, _editCompanyDetails, _editProfile, _auditRequest, _approveRequest. Also extracts the user token and prepares a MongoDB query to validate it. |
| Extract User Record | function |
Extracts the first user record from MongoDB results (msg.payload[0]) and attaches it to msg.payload.user. If no record found, sets user: null. |
| Handle Action Type | switch |
Routes the message based on msg.type to different flows: getDashboard, editCompanyDetails, archiveRequest, editProfile, auditRequest, approveRequest, or createRequest. |
| Prepare User Lookup | function |
Uses the token to fetch the corresponding user ID and prepares a MongoDB query to find the user by _id in the Users collection. |
| Find User by ID | mongodb4 |
Queries the Users collection in MongoDB using the _id prepared in the previous node. |
| Find Token Record | mongodb4 |
Queries the Tokens collection in MongoDB to validate the token provided in the request. |
| Check Token Presence | function |
Checks if msg.auth.userToken exists and is valid. If not, redirects to signin. If valid, continues the flow. |
| TrustedCloud UI | debug |
Logs the full incoming message for debugging purposes. |
| Not Logged In | function |
Prepares a msg.payload indicating the user is not logged in (state: "notLoggedIn") and passes it to the appropriate link output. |
| status | switch |
Routes messages based on token validation status (expired, empty, valid) to either Not Logged In or Prepare User Lookup. |
| Token Expiration | function |
Checks whether the token exists and is still valid. Updates msg.payload.status to valid, expired, or empty. |
| link out 7 | link out |
Sends the message to another part of the flow (1a592f68894d0c59). |
| link out 36 | link out |
Sends messages to another part of the flow when the user is not logged in. |
| getDashboard | link out |
Sends messages to the getDashboard flow (f69577e33ab460d9). |
| MongoDB Client | mongodb4-client |
MongoDB client configuration connecting to hediyehTC database using TLS. |
4. Authentication Flow Integration
Once token validation is complete, the flow dynamically routes the request based on the auth.type received from the frontend.
Each auth.type corresponds to a dedicated backend sub-flow that performs specific MongoDB operations and response handling:
| Request Type | Description | Target Collection | Roles / Access |
|---|---|---|---|
| getDashboard | Fetches dashboard data tailored to the user’s role. | Dashboard | - Applicant & Auditor: Sees requests they created or audited. - Applicant & Approver: Sees requests they created or approved. - Applicant: Sees only their own requests. - Admin: Full dashboard access. |
| editCompanyDetails | Updates company information for the authenticated user. | CompanyDetails | |
| archiveRequest | Toggles the archived state of a request. | Requests | |
| editProfile | Updates the user’s profile information (name, email, etc.). | Users | |
| auditRequest | Records the auditing action taken on a request. | Requests / AuditLog | |
| approveRequest | Records the approval of a request. | Requests / AuditLog | |
| createRequest | Creates a new request record in the system. | Requests |
Behavior:
- Frontend sends msg.type to Node-RED via uibuilder.
- Node-RED checks user token and validates session.
- Switch node routes the request to the corresponding sub-flow
(getDashboard, editProfile, etc.). - Role-based access checks are applied for sensitive actions
(approveRequest, auditRequest, etc.). - The backend performs the database operation and sends the response back to the frontend.
Purpose:
- Ensures that each request type has a dedicated processing flow.
- Implements role-based access control for dashboard and request management.
- Maintains a consistent pattern for routing, validation, and response handling across all request types.
4.1.1 getDashboard (Applicant) Flow
High-Level Flow:
User logs in
↓
Node-RED: Determine User Roles
↓
Switch routes by role:
├─ Applicant → Fetch user's own requests
│ ↓
│ MongoDB: Requests collection
│ ↓
│ Dashboard Payload → uibuilder (frontend)
Frontend getDashboard (Applicant)
uibuilder.start();
this.isLoading = true;
var vueApp = this;
// Send dashboard request
uibuilder.send({
type: 'getDashboard',
auth: {
userToken: this.getCookie('userToken'),
clientId: this.getCookie('uibuilder-client-id')
}
});
-
uibuilder.start()starts the communication channel with Node-RED via WebSocket. - It sets
isLoading = trueto show a loading indicator (e.g., spinner). - Then it sends a message to Node-RED requesting the dashboard data.
- The request message looks like:
Sample Request Payload
{
"type": "getDashboard",
"auth": {},
"userToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTU5OTExNzkxNCIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmZmNjMjFkNmM0Mzk4ZWE1ZjVjY2Y5IiwiaWQiOjEwLCJlbWFpbCI6ImhAZ21haWwuY29tIiwicm9sZXMiOlsiYXBwbGljYW50Il0sImZ1bGxOYW1lIjoiaGVkaXllaCJ9LCJhY3Rpb24iOiJsb2dpbiIsImlhdCI6MTc2MTU5OTExNywiZXhwIjoxNzYxNjAyNzE3fQ.mkvYqaZX1Y8m8gJdS3VAlQvDJ7zj3amk-Rc59rKkR8k",
"clientId": "DucPqZtrHFQNgOnyiGV02",
"_socketId": "X6ZKjzzFvV-ibjhwAEiI",
"_msgid": "8bd0ae08cdfe06a9"
}
Backend Node-RED Flow
| Node Name | Type | Responsibility |
|---|---|---|
| Determine User Roles | Function | Reads user object from msg.user or msg.payload. Checks user roles (Applicant, Auditor, Approver) and sets msg.payload to one of: Applicant, ApplicantandAuditor, ApplicantandApprover, or Admin. Attaches full user info in msg.user. |
| Route by Role Type | Switch | Routes flow based on msg.payload role type. Sends messages to different paths for each role type. |
| Fetch Applicant Requests | Function | Prepares MongoDB query for Requests collection. Filters requests where createdBy.id matches user ID. Sets msg.collection and msg.payload for MongoDB node. |
| Applicant Requests | MongoDB4 | Executes query to fetch requests created by the applicant. Returns results as an array in msg.payload. |
| Dashboard Payload | Function | Builds the final dashboard payload: type, state, applicantRequests, requests. Adds profile info from msg.user or msg.userData including user ID, email, name, roles, avatar, and contact info. |
| Applicant (Debug) | Debug | Logs the final payload for the applicant to the Node-RED debug sidebar. Useful for monitoring and troubleshooting. |
Backend Flow Summary
Determine User Roles
- Purpose: Identify the user’s role(s) based on data from MongoDB.
-
Logic:
- Checks the
rolesarray in the user object. - Maps combinations to one of four categories:
ApplicantApplicantandAuditorApplicantandApproverAdmin
- Checks the
-
Output: Sets
msg.payloadto role type and attaches full user info inmsg.user.
Route by Role Type
- Purpose: Directs the flow depending on the role determined.
- Logic: Uses a Switch node to route messages to different downstream nodes for Applicants, Approvers, Auditors, or Admins.
- Outcome: Ensures role-specific logic is applied to dashboard requests.
Fetch Requests (Role-Based)
- Purpose: Retrieve relevant requests from MongoDB for the user.
-
Logic:
- For Applicants: query
Requestscollection wherecreatedBy.id = userId.
- For Applicants: query
Note:
Applicant Dashboard
Can view requests in: Pending, Audited, Approved, Rejected
Prepare Dashboard Payload
- Purpose: Format data for front-end consumption.
-
Logic:
- Combines request data (
applicantRequests,requests) with user profile info (id,email,name,roles,avatar,contact info). - Ensures front-end receives a standardized object regardless of role.
- Combines request data (
-
Output:
msg.payloadready to send to UI via uibuilder.
Sending Data to Front-End
-
Link/Debug Nodes:
-
Link Outnode passes data to the front-end flow. -
Debugnodes monitor output for verification and troubleshooting.
-
Response Examples (uibuilder.onChange)
{
"type": "getDashboard",
"auth": {},
"userToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTU5OTkyNTMyNCIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmZmUxOTZkNmM0Mzk4ZWE1ZjVjZDA2IiwiaWQiOjksImVtYWlsIjoibEBnbWFpbC5jb20iLCJyb2xlcyI6WyJBcHBsaWNhbnQiXSwiZnVsbE5hbWUiOiJsaWxpYSJ9LCJhY3Rpb24iOiJsb2dpbiIsImlhdCI6MTc2MTU5OTkyNSwiZXhwIjoxNzYxNjAzNTI1fQ.SJLPhRoJOVnLvUQLsk5ngvdw4d2MgFw28p5yG6Uh4wc",
"clientId": "DucPqZtrHFQNgOnyiGV02",
"_socketId": "2xxN12-ysdStG4sBAEj5",
"_msgid": "09d2712e6aea20b0",
"collection": "Requests",
"operation": "find",
"payload": {
"type": "getDashboard",
"state": "requestsFetched",
"applicantRequests": [
{
"_id": "68ffe1e7d6c4398ea5f5cd08",
"id": 18,
"createdBy": {},
"companyDetails": {},
"priority": "low",
"status": "Pending",
"archive": false,
"timeEstimation": "10 business day",
"assignedTo": "",
"auditInfo": {},
"approveInfo": {},
"createdAt": "2025-10-27T21:19:35.315Z",
"profile": {
"userId": "68ffe196d6c4398ea5f5cd06",
"email": "l@gmail.com",
"name": "",
"role": "",
"roles": ["Applicant"],
"avatarUrl": "./images/sara-profile.png",
"firstName": "lilia",
"lastName": "",
"contactNumber": "",
"address": "",
"country": "",
"stateOrProvince": "",
"postalCode": "",
"options": {},
"output": "toArray"
}
}
]
}
}
MongoDB Requests Collection Schema
| Field | Type | Description |
|---|---|---|
| _id | String | Unique MongoDB document identifier |
| id | Number | Internal record ID |
| createdBy.userId | String | ID of the user who created the record |
| createdBy.id | Number | Creator’s internal ID |
| createdBy.fullName | String | Name of the creator (e.g., David Kim) |
| createdBy.email | String | Creator’s email address |
| createdBy.avatarUrl | String | Base64-encoded profile image URL |
| companyDetails.priority | String | Task or request priority (e.g., low) |
| companyDetails.status | String | Current status (e.g., Approved) |
| companyDetails.archive | Boolean | Indicates if the record is archived |
| companyDetails.timeEstimation | String | Estimated completion time |
| companyDetails.assignedTo | String | Assigned user (empty if none) |
| auditInfo | Object | Audit tracking data (timestamps, etc.) |
| approveInfo | Object | Approval metadata or history |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Last update timestamp |
Sample document:
{
"_id": "6907636ed6c4398ea5f5cd42",
"id": 2,
"createdBy": {
"userId": "68f830f9d6c4398ea5f5cbdf",
"id": 1,
"fullName": "David Kim",
"email": "david.kim@brightwave.co",
"avatarUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEhUSEhI…"
},
"companyDetails": {
"priority": "low",
"status": "Approved",
"archive": false,
"timeEstimation": "10 business day",
"assignedTo": ""
},
"auditInfo": {},
"approveInfo": {},
"createdAt": "2025-11-02T13:58:06.411+00:00",
"updatedAt": "2025-11-02T14:05:05.471+00:00"
}
4.1.2 getDashboard(Applicant and Auditor) Flow
High-Level Flow:
User logs in
↓
Node-RED: Determine User Roles
↓
Switch routes by role:
├─ Applicant and Auditor → Fetch user's own requests
│ ↓
│ MongoDB: Requests collection
│ ↓
│ Dashboard Payload → uibuilder (frontend)
Frontend getDashboard (Applicant and Auditor)
uibuilder.start();
this.isLoading = true;
var vueApp = this;
// Send dashboard request
uibuilder.send({
type: 'getDashboard',
auth: {
userToken: this.getCookie('userToken'),
clientId: this.getCookie('uibuilder-client-id')
}
});
-
uibuilder.start()starts the communication channel with Node-RED via WebSocket. - It sets
isLoading = trueto show a loading indicator (e.g., spinner). - Then it sends a message to Node-RED requesting the dashboard data.
- The request message looks like:
Sample Request Payload
{
"type": "getDashboard",
"auth": {},
"userToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTU5OTExNzkxNCIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmZmNjMjFkNmM0Mzk4ZWE1ZjVjY2Y5IiwiaWQiOjEwLCJlbWFpbCI6ImhAZ21haWwuY29tIiwicm9sZXMiOlsiYXBwbGljYW50Il0sImZ1bGxOYW1lIjoiaGVkaXllaCJ9LCJhY3Rpb24iOiJsb2dpbiIsImlhdCI6MTc2MTU5OTExNywiZXhwIjoxNzYxNjAyNzE3fQ.mkvYqaZX1Y8m8gJdS3VAlQvDJ7zj3amk-Rc59rKkR8k",
"clientId": "DucPqZtrHFQNgOnyiGV02",
"_socketId": "X6ZKjzzFvV-ibjhwAEiI",
"_msgid": "8bd0ae08cdfe06a9"
}
Backend Node-RED Flow
| Node Name | Type | Description |
|---|---|---|
| Determine User Roles | Function | Identifies the user’s roles from the MongoDB user object and categorizes them into one of four types: Applicant, ApplicantandAuditor, ApplicantandApprover, or Admin. Sets msg.payload to the detected role and attaches user details to msg.user. |
| Route by Role Type | Switch | Routes the message to the appropriate flow branch based on msg.payload (role type). For example, users with the ApplicantandAuditor role are routed to nodes that handle both applicant and auditor data retrieval. |
| Fetch Applicant Requests | Function | Builds a MongoDB query to fetch all requests created by the logged-in user (createdBy.id = userId). Adds _phase: "Applicant" for tracking. |
| Applicant Requests | MongoDB4 | Executes the database query built in the previous function and retrieves all applicant-related requests. Passes the data to the next node. |
| Fetch Auditor Requests | Function | Executes only after applicant requests are fetched. Builds a new MongoDB query to find all requests requiring auditor attention (status: Pending, Audited, or Rejected). Sets _phase: "Auditor". |
| Auditor Requests | MongoDB4 | Runs the MongoDB query for auditor-related requests and returns matching records as an array in msg.payload. |
| Normalize Auditor Requests | Function | Cleans and enriches the auditor requests array by adding user metadata (name, email, avatar). Ensures consistent structure for UI rendering. |
| Dashboard Payload | Function | Combines applicantRequests, auditorRequests, and full user profile data into a single msg.payload formatted for front-end use (type: "getDashboard"). |
| Link Out | Link Out | Sends the final formatted dashboard payload to the front-end flow handled by uibuilder. |
| ApplicantandAuditor (Debug) | Debug | Displays the final output payload in Node-RED’s debug sidebar for inspection and troubleshooting. |
Backend Flow Summary
Purpose
This backend flow dynamically builds the Applicant and Auditor dashboard by retrieving and combining user-specific and role-specific data from MongoDB.
Process Overview
Identify User Role:
Extracts and interprets the user’s roles to determine access type (Applicant, Auditor, etc.).
Route by Role:
Directs the flow to the appropriate logic branch depending on the identified role.
Retrieve Requests:
- Applicant Requests: Queries records created by the user.
- Auditor Requests: Fetches items pending review or action based on role permissions.
Note:
Auditor Dashboard
Can view requests in: Pending, Audited, Rejected
Applicant Dashboard
Can view requests in: Pending, Audited, Approved, Rejected
Normalize Data:
Standardizes each record’s format for the front-end, enriching it with user and request metadata.
Prepare Final Dashboard Payload:
Merges both Applicant and Auditor data streams with the user’s full profile to produce a unified, front-end-ready response.
Send to Front-End (uibuilder):
The formatted payload is sent through a Link Out node, then displayed in the user’s dashboard interface.
Response Examples (uibuilder.onChange)
{
{
"type": "getDashboard",
"auth": {},
"_socketId": "0KAO_QB8U2vpv5xDAElI",
"_msgid": "b668b84c0ec154e7",
"collection": "Requests",
"operation": "find",
"payload": {
"options": {},
"userId": "68f830f9d6c4398ea5f5cbdf",
"user": {},
"_phase": "Auditor",
"applicantRequests": [
/* 13 request objects */
],
"auditorRequests": [
/* 16 request objects */
]
}
}
MongoDB Requests Collection Schema
| Field | Type | Description |
|---|---|---|
| _id | String | Unique MongoDB document identifier |
| id | Number | Internal record ID |
| createdBy.userId | String | ID of the user who created the record |
| createdBy.id | Number | Creator’s internal ID |
| createdBy.fullName | String | Name of the creator (e.g., David Kim) |
| createdBy.email | String | Creator’s email address |
| createdBy.avatarUrl | String | Base64-encoded profile image URL |
| companyDetails.priority | String | Task or request priority (e.g., low) |
| companyDetails.status | String | Current status (e.g., Approved) |
| companyDetails.archive | Boolean | Indicates if the record is archived |
| companyDetails.timeEstimation | String | Estimated completion time |
| companyDetails.assignedTo | String | Assigned user (empty if none) |
| auditInfo | Object | Audit tracking data (timestamps, etc.) |
| approveInfo | Object | Approval metadata or history |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Last update timestamp |
Sample document:
{
"_id": "6907636ed6c4398ea5f5cd42",
"id": 2,
"createdBy": {
"userId": "68f830f9d6c4398ea5f5cbdf",
"id": 1,
"fullName": "David Kim",
"email": "david.kim@brightwave.co",
"avatarUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEhUSEhI…"
},
"companyDetails": {
"priority": "low",
"status": "Approved",
"archive": false,
"timeEstimation": "10 business day",
"assignedTo": ""
},
"auditInfo": {},
"approveInfo": {},
"createdAt": "2025-11-02T13:58:06.411+00:00",
"updatedAt": "2025-11-02T14:05:05.471+00:00"
}
4.1.3 getDashboard(Applicant and Approver) Flow
High-Level Flow:
User logs in
↓
Node-RED: Determine User Roles
↓
Switch routes by role:
├─ Applicant and Approver→ Fetch user's own requests
│ ↓
│ MongoDB: Requests collection
│ ↓
│ Dashboard Payload → uibuilder (frontend)
Frontend getDashboard (Applicant and Approver)
uibuilder.start();
this.isLoading = true;
var vueApp = this;
// Send dashboard request
uibuilder.send({
type: 'getDashboard',
auth: {
userToken: this.getCookie('userToken'),
clientId: this.getCookie('uibuilder-client-id')
}
});
-
uibuilder.start()starts the communication channel with Node-RED via WebSocket. - It sets
isLoading = trueto show a loading indicator (e.g., spinner). - Then it sends a message to Node-RED requesting the dashboard data.
- The request message looks like:
Sample Request Payload
{
"type": "getDashboard",
"auth": {},
"userToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTU5OTExNzkxNCIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmZmNjMjFkNmM0Mzk4ZWE1ZjVjY2Y5IiwiaWQiOjEwLCJlbWFpbCI6ImhAZ21haWwuY29tIiwicm9sZXMiOlsiYXBwbGljYW50Il0sImZ1bGxOYW1lIjoiaGVkaXllaCJ9LCJhY3Rpb24iOiJsb2dpbiIsImlhdCI6MTc2MTU5OTExNywiZXhwIjoxNzYxNjAyNzE3fQ.mkvYqaZX1Y8m8gJdS3VAlQvDJ7zj3amk-Rc59rKkR8k",
"clientId": "DucPqZtrHFQNgOnyiGV02",
"_socketId": "X6ZKjzzFvV-ibjhwAEiI",
"_msgid": "8bd0ae08cdfe06a9"
}
Backend Node-RED Flow
| Node Name | Type | Description |
|---|---|---|
| Determine User Roles | Function | Determines the user’s role(s) from MongoDB and categorizes into Applicant, ApplicantandApprover, ApplicantandAuditor, or Admin. Sets msg.payload to the role and attaches the full user object in msg.user. |
| Route by Role Type | Switch | Routes messages based on msg.payload (role type) to the correct downstream flow for Applicants, Approvers, or Admins. |
| Fetch Applicant Requests | Function | Prepares MongoDB query to fetch requests created by the logged-in user (createdBy.id = userId). Adds _phase: "Applicant" to track workflow. |
| Applicant Requests (MongoDB) | MongoDB4 | Executes the applicant request query and returns results in msg.payload array. |
| Fetch Approver Requests | Function | Prepares MongoDB query for requests the approver needs to act on (status: Audited, Approved, Rejected). Sets _phase: "Approver" for tracking. |
| Approver Requests (MongoDB) | MongoDB4 | Executes the approver request query and returns matching requests as an array in msg.payload. |
| Normalize Approver Requests | Function | Standardizes the structure of approver requests. Adds creator metadata (name, email, avatar) for UI display. |
| Dashboard Payload | Function | Combines applicantRequests and approverRequests with the user’s profile info into a single object formatted for the front-end (msg.payload.type = "getDashboard"). |
| Link Out | Link Out | Sends the final dashboard payload to the front-end via uibuilder or other linked flows. |
| ApplicantandApprover (Debug) | Debug | Shows final combined dashboard payload for testing and verification. |
Backend Flow Summary
Purpose
The backend flow dynamically generates the Applicant and Approver dashboard by fetching and combining requests based on user role from MongoDB.
Workflow
Role Detection:
Extracts the user’s roles and categorizes them into one of four types. Sets msg.payload and msg.user.
Role-Based Routing:
Uses a switch node to send messages to different flow branches depending on the user role.
Fetch Requests:
Applicant Requests: Fetches all requests created by the logged-in user.
Approver Requests: Fetches requests with:
- Status Audited or Approved.
- Rejected requests, but only those rejected by Approvers, excluding any rejected by Auditors.
Normalize Data:
Formats requests to include essential user metadata for consistent front-end rendering.
Prepare Dashboard Payload:
Combines applicant and approver requests with full user profile to generate msg.payload for the front-end.
Send to Front-End:
Final payload is passed through a Link Out node to UI components (e.g., uibuilder).
Response Examples (uibuilder.onChange)
{
""type"": ""getDashboard"",
""auth"": {
""userToken"": ""eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTYxODg3NTczNSIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmODM2MzhkNmM0Mzk4ZWE1ZjVjYmU2IiwiaWQiOjIsImVtYWlsIjoibGVpbGEuaGFzc2FuQHNreW5ldC5zeXN0ZW1zIiwicm9sZXMiOlsiQXBwbGljYW50IiwiQXBwcm92ZXIiXSwiZnVsbE5hbWUiOiJMZWlsYSBIYXNzYW4ifSwiYWN0aW9uIjoibG9naW4iLCJpYXQiOjE3NjE2MTg4NzUsImV4cCI6MTc2MTYyMjQ3NX0.yC6fr76smTVPPr0kCrmTARcJQ5qiuGqYKvl8_16rcts""
},
""clientId"": ""DucPqZtrHFQNgOnyiGV02"",
""_socketId"": ""l9Mu_3V_ZjsFAHcfAElj"",
""_msgid"": ""235919a3a70d095a"",
""collection"": ""Requests"",
""operation"": ""find"",
""payload"": {},
""options"": {},
""userId"": ""68f83638d6c4398ea5f5cbe6"",
""user"": {},
""_phase"": ""Approver"",
""applicantRequests"": [],
""approverRequests"": [
{},
{},
{},
{}
]
}
MongoDB Requests Collection Schema
| Field | Type | Description |
|---|---|---|
| _id | String | Unique MongoDB document identifier |
| id | Number | Internal record ID |
| createdBy.userId | String | ID of the user who created the record |
| createdBy.id | Number | Creator’s internal ID |
| createdBy.fullName | String | Name of the creator (e.g., David Kim) |
| createdBy.email | String | Creator’s email address |
| createdBy.avatarUrl | String | Base64-encoded profile image URL |
| companyDetails.priority | String | Task or request priority (e.g., low) |
| companyDetails.status | String | Current status (e.g., Approved) |
| companyDetails.archive | Boolean | Indicates if the record is archived |
| companyDetails.timeEstimation | String | Estimated completion time |
| companyDetails.assignedTo | String | Assigned user (empty if none) |
| auditInfo | Object | Audit tracking data (timestamps, etc.) |
| approveInfo | Object | Approval metadata or history |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Last update timestamp |
Sample document:
{
"_id": "6907636ed6c4398ea5f5cd42",
"id": 2,
"createdBy": {
"userId": "68f830f9d6c4398ea5f5cbdf",
"id": 1,
"fullName": "David Kim",
"email": "david.kim@brightwave.co",
"avatarUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEhUSEhI…"
},
"companyDetails": {
"priority": "low",
"status": "Approved",
"archive": false,
"timeEstimation": "10 business day",
"assignedTo": ""
},
"auditInfo": {},
"approveInfo": {},
"createdAt": "2025-11-02T13:58:06.411+00:00",
"updatedAt": "2025-11-02T14:05:05.471+00:00"
}
4.1.4 getDashboard(Admin) Flow
High-Level Flow:
User logs in
↓
Node-RED: Determine User Roles
↓
Switch routes by role:
├─ Admin→ Fetch user's own requests
│ ↓
│ MongoDB: Requests collection
│ ↓
│ Dashboard Payload → uibuilder (frontend)
Frontend getDashboard (Admin)
uibuilder.start();
this.isLoading = true;
var vueApp = this;
// Send dashboard request
uibuilder.send({
type: 'getDashboard',
auth: {
userToken: this.getCookie('userToken'),
clientId: this.getCookie('uibuilder-client-id')
}
});
-
uibuilder.start()starts the communication channel with Node-RED via WebSocket. - It sets
isLoading = trueto show a loading indicator (e.g., spinner). - Then it sends a message to Node-RED requesting the dashboard data.
- The request message looks like:
Sample Request Payload
{
"type": "getDashboard",
"auth": {},
"userToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTU5OTExNzkxNCIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmZmNjMjFkNmM0Mzk4ZWE1ZjVjY2Y5IiwiaWQiOjEwLCJlbWFpbCI6ImhAZ21haWwuY29tIiwicm9sZXMiOlsiYXBwbGljYW50Il0sImZ1bGxOYW1lIjoiaGVkaXllaCJ9LCJhY3Rpb24iOiJsb2dpbiIsImlhdCI6MTc2MTU5OTExNywiZXhwIjoxNzYxNjAyNzE3fQ.mkvYqaZX1Y8m8gJdS3VAlQvDJ7zj3amk-Rc59rKkR8k",
"clientId": "DucPqZtrHFQNgOnyiGV02",
"_socketId": "X6ZKjzzFvV-ibjhwAEiI",
"_msgid": "8bd0ae08cdfe06a9"
}
Backend Node-RED Flow
| Node Name | Type | Description |
|---|---|---|
| Route by Role Type | Switch | Routes messages based on msg.payload (role type) to the correct downstream flow. Here, the Admin role is handled separately. |
| Prepare Requests Query | Function | Prepares a generic MongoDB query for fetching all requests (no filter) for the Admin role. Sets collection to Requests and output format to toArray. |
| Fetch Requests | MongoDB4 | Executes the Admin requests query and returns all requests in msg.payload array. |
| Dashboard Payload | Function | Combines fetched requests with the Admin user’s profile into a structured object for the front-end (msg.payload.type = "getDashboard"). |
| Link Out 16 | Link Out | Sends the final Admin dashboard payload to the front-end or linked flows. |
| Admin | Debug | Displays the Admin dashboard payload for testing and verification. |
Backend Flow Summary
- The flow identifies the user role as Admin via the Route by Role Type switch.
- Prepare Requests Query constructs a MongoDB query with no restrictions, allowing Admins to see all requests.
- Fetch Requests node executes the query on the Requests collection in MongoDB.
- Dashboard Payload formats the data together with Admin profile information (email, name, roles, avatar, contact info, etc.) for front-end consumption.
- Link Out 16 sends the formatted payload to the UI, while the Admin Debug node allows developers to verify the output.
Response Examples (uibuilder.onChange)
{
"{
""type"": ""getDashboard"",
""auth"": {
""userToken"": ""eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTYxOTI0MjQ4MiIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmODQ0NDlkNmM0Mzk4ZWE1ZjVjYmVlIiwiaWQiOjQsImVtYWlsIjoiZmFyaWQubW9yYWRpQHF1YW50dW1lZGdlLmlvIiwicm9sZXMiOlsiQWRtaW4iXSwiZnVsbE5hbWUiOiJGYXJpZCBNb3JhZGkifSwiYWN0aW9uIjoibG9naW4iLCJpYXQiOjE3NjE2MTkyNDIsImV4cCI6MTc2MTYyMjg0Mn0.GhkUkVsHVYPN3HtrJ8dgnCggAdXGXP0KSQIJYWtPx_w""
},
""clientId"": ""DucPqZtrHFQNgOnyiGV02"",
""_socketId"": ""pP_KxEJNyY96NbnHAEl1"",
""_msgid"": ""1f420fa785af463d"",
""collection"": ""Requests"",
""operation"": ""find"",
""payload"": {
""type"": ""getDashboard"",
""requests"": [
{},
],
""profile"": {},
""options"": {}
},
""userId"": ""68f84449d6c4398ea5f5c""
}
"
MongoDB Requests Collection Schema
| Field | Type | Description |
|---|---|---|
| _id | String | Unique MongoDB document identifier |
| id | Number | Internal record ID |
| createdBy.userId | String | ID of the user who created the record |
| createdBy.id | Number | Creator’s internal ID |
| createdBy.fullName | String | Name of the creator (e.g., David Kim) |
| createdBy.email | String | Creator’s email address |
| createdBy.avatarUrl | String | Base64-encoded profile image URL |
| companyDetails.priority | String | Task or request priority (e.g., low) |
| companyDetails.status | String | Current status (e.g., Approved) |
| companyDetails.archive | Boolean | Indicates if the record is archived |
| companyDetails.timeEstimation | String | Estimated completion time |
| companyDetails.assignedTo | String | Assigned user (empty if none) |
| auditInfo | Object | Audit tracking data (timestamps, etc.) |
| approveInfo | Object | Approval metadata or history |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Last update timestamp |
Sample document:
{
"_id": "6907636ed6c4398ea5f5cd42",
"id": 2,
"createdBy": {
"userId": "68f830f9d6c4398ea5f5cbdf",
"id": 1,
"fullName": "David Kim",
"email": "david.kim@brightwave.co",
"avatarUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEhUSEhI…"
},
"companyDetails": {
"priority": "low",
"status": "Approved",
"archive": false,
"timeEstimation": "10 business day",
"assignedTo": ""
},
"auditInfo": {},
"approveInfo": {},
"createdAt": "2025-11-02T13:58:06.411+00:00",
"updatedAt": "2025-11-02T14:05:05.471+00:00"
}
4.2.editCompanyDetails Flow
High-Level Flow:
Incoming Message (msg._editCompanyDetails)
↓
Validate Existence of _editCompanyDetails and id
↓
Convert id to Numeric → Return null if invalid
↓
Extract companyDetails Object
↓
Remove Empty or Undefined Fields
↓
Prepare MongoDB Update Payload
↓
Send to → "Update CompanyDetails" (MongoDB Node)
Frontend editCompanyDetails
The editCompanyDetails method is part of the frontend logic responsible for sending updated company information to the backend and updating the local UI state reactively.
editCompanyDetails(request) {
// 1️⃣ Send update to backend
uibuilder.send({
type: 'editCompanyDetails',
auth: {
userToken: this.getCookie('userToken'),
clientId: this.getCookie('uibuilder-client-id')
},
requestID: request.id || request._id,
companyDetails: { ...this.formData }
});
// 2️⃣ Update local array reactively (Vue 3)
const reqId = request.id || request._id;
const index = this.applicantRequests.findIndex(
r => (r.id || r._id) === reqId
);
if (index !== -1) {
// Use splice instead of $set in Vue 3
this.applicantRequests.splice(index, 1, {
...this.applicantRequests[index],
companyDetails: { ...this.formData }
});
}
this.waitingForResponse = true;
setTimeout(() => {
if (this.waitingForResponse) {
this.showNotification('Network error! Please refresh.', 'error');
this.waitingForResponse = false;
this.submissionSuccess = false;
this.closeModal(); // optional: close modal automatically
}
}, 6000);
},
Sending Update Request
When a user edits company information and confirms changes, the method sends a structured message to the Node-RED backend using uibuilder.send().
Purpose:
This ensures that the backend flow (editCompanyDetails) receives the request along with the necessary authentication context.
Reactive Local Update
After sending the update request, the function updates the applicantRequests array locally to reflect the new company details immediately — without waiting for a server response.
- Finds the target record by matching
_id. - Uses
splice()to replace the updated record. - Ensures the UI remains synchronized with the user’s latest input.
Response Handling & Timeout Control
To manage network reliability, a 6-second timeout is implemented.
If the backend does not respond within this period:
- A network error notification is displayed.
- The
waitingForResponseflag is reset. - The modal window is optionally closed.
Example:
setTimeout(() => {
if (this.waitingForResponse) {
this.showNotification('Network error! Please refresh.', 'error');
this.waitingForResponse = false;
this.submissionSuccess = false;
this.closeModal();
}
}, 6000);
Sample Request Payload
{
""type"": ""editCompanyDetails"",
""auth"": {
""userToken"": ""eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTYxNjk5NjI1NSIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmODMwZjlkNmM0Mzk4ZWE1ZjVjYmRmIiwiaWQiOjEsImVtYWlsIjoiZGF2aWQua2ltQGJyaWdodHdhdmUuY28iLCJyb2xlcyI6WyJBcHBsaWNhbnQiLCJBdWRpdG9yIl0sImZ1bGxOYW1lIjoiRGF2aWQgS2ltIn0sImFjdGlvbiI6ImxvZ2luIiwiaWF0IjoxNzYxNjE2OTk2LCJleHAiOjE3NjE2MjA1OTZ9.I0hARpxoFQPfZjfn5ZqjV-sRJO6SKpAw7KZBR4mH6iI""
},
""clientId"": ""DucPqZtrHFQNgOnyiGV02"",
""companyDetails"": {},
""_socketId"": ""0KAO_QB8U2vpv5xDAElI"",
""topic"": ""uibuilder"",
""_msgid"": ""318f5048ec2d""
}
Backend Node-RED Flow
| Node Name | Type | Description |
|---|---|---|
| Log Captured EditCompanyDetails | function |
Checks if an edit request exists in msg._editCompanyDetails. If missing, logs a warning message. If present, logs the captured request for debugging. Passes the message to the next node. |
| Prepare CompanyDetails Update | function |
Validates the presence of msg._editCompanyDetails.id. If valid, extracts the id and builds an update payload containing non-empty companyDetails fields. Configures MongoDB update parameters using: - msg.collection = "Requests" - msg.operation = "updateOne" - msg.payload = [ { id }, { $set: updateData }, { upsert: false } ]
|
| Update CompanyDetails | mongodb4 |
Executes the MongoDB updateOne operation on the Requests collection, applying the $set changes defined in the previous node. Returns a result array for further processing. |
| Change (Set Response) | change |
Creates a success response payload: msg.response = { "status": "success", "action": "editCompanyDetails", "message": "success" }. This response is later sent to the frontend. |
| editCompanyDetails | debug |
Outputs the final message (including the success response) to the Node-RED Debug sidebar for monitoring and validation. |
| link out 39 | link out |
Sends the message to another flow via a link node (connected to "1a592f68894d0c59"), allowing the response to be transmitted to the UI or a higher-level flow controller. |
Backend Flow Summary
The editCompanyDetails backend flow in Node-RED is designed to handle update operations for company details associated with a request record stored in MongoDB.
Input Message Reception
The flow receives a message (msg._editCompanyDetails) containing updated company details and the corresponding request ID.
Validation & Logging
The Log Captured EditCompanyDetails node ensures that a valid edit request object exists.
- If not, a warning is logged to help debug missing or malformed requests.
- If valid, the message proceeds to the update preparation stage.
Update Preparation
The Prepare CompanyDetails Update node constructs a clean MongoDB update payload:
- Verifies that
idis numeric and valid. - Removes empty or undefined fields from
companyDetailsto prevent overwriting existing data with null values. - Sets operation parameters for MongoDB (
collection,operation, andpayload).
Example Payload:
{
"collection": "Requests",
"operation": "updateOne",
"payload": [
{ "id": 123 },
{ "$set": { "companyDetails": { "name": "New Corp" } } },
{ "upsert": false }
]
}
Database Update Execution
The Update CompanyDetails node performs the MongoDB updateOne operation in the Requests collection using the prepared payload.
Response Handling
After the database operation, the Change node generates a standardized success response:
{
"status": "success",
"action": "editCompanyDetails",
"message": "success"
}
Response Examples (uibuilder.onChange)
// Success Response
{
"status": "success",
"action": "editCompanyDetails",
"message": "success"
}
MongoDB Requests Collection Schema
| Field | Type | Description |
|---|---|---|
| _id | String | Unique MongoDB document identifier |
| id | Number | Internal record ID |
| createdBy.userId | String | ID of the user who created the record |
| createdBy.id | Number | Creator’s internal ID |
| createdBy.fullName | String | Name of the creator (e.g., David Kim) |
| createdBy.email | String | Creator’s email address |
| createdBy.avatarUrl | String | Base64-encoded profile image URL |
| companyDetails.priority | String | Task or request priority (e.g., low) |
| companyDetails.status | String | Current status (e.g., Approved) |
| companyDetails.archive | Boolean | Indicates if the record is archived |
| companyDetails.timeEstimation | String | Estimated completion time |
| companyDetails.assignedTo | String | Assigned user (empty if none) |
| auditInfo | Object | Audit tracking data (timestamps, etc.) |
| approveInfo | Object | Approval metadata or history |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Last update timestamp |
Sample document:
{
"_id": "6907636ed6c4398ea5f5cd42",
"id": 2,
"createdBy": {
"userId": "68f830f9d6c4398ea5f5cbdf",
"id": 1,
"fullName": "David Kim",
"email": "david.kim@brightwave.co",
"avatarUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEhUSEhI…"
},
"companyDetails": {
"priority": "low",
"status": "Approved",
"archive": false,
"timeEstimation": "10 business day",
"assignedTo": ""
},
"auditInfo": {},
"approveInfo": {},
"createdAt": "2025-11-02T13:58:06.411+00:00",
"updatedAt": "2025-11-02T14:05:05.471+00:00"
}
4.3.archiveRequest Flow
High-Level Flow:
Incoming Message (msg._archiveRequest)
↓
Log Captured EditRequest
↓
Prepare Archive Toggle Update
↓
Update Request Archive (MongoDB)
↓
Set Success Response
↓
Send to → archiveRequest (Debug + Link Out)
Frontend archiveRequest
archiveRequest(request){
request.archive = !request.archive
uibuilder.send({
type: 'archiveRequest',
auth: {
userToken: this.getCookie('userToken'),
clientId:this.getCookie('uibuilder-client-id')
},
requestID: request.id
})
},
Purpose:
This function is responsible for triggering the archive/unarchive action of a specific request directly from the UIBuilder frontend.
It toggles the request’s archive status locally in the UI and sends an update event to the Node-RED backend via the uibuilder communication channel.
archiveRequest(request) {
request.archive = !request.archive
The function receives a request object (typically an entry displayed in the user interface, e.g., a row in a request table).
It immediately toggles the current state of the archive property:
If archive was true, it becomes false.
If archivewas false, it becomes true.
- This local toggle gives instant UI feedback without waiting for the backend response.
uibuilder.send({
type: 'archiveRequest',
auth: {
userToken: this.getCookie('userToken'),
clientId: this.getCookie('uibuilder-client-id')
},
requestID: request.id
})
- After toggling, the function sends a message to the Node-RED backend using
uibuilder.send()— the built-in communication bridge between the frontend and Node-RED.
Sample Request Payload
{
""type"": ""archiveRequest"",
""auth"": {
""userToken"": ""eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTYxNjk5NjI1NSIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmODMwZjlkNmM0Mzk4ZWE1ZjVjYmRmIiwiaWQiOjEsImVtYWlsIjoiZGF2aWQua2ltQGJyaWdodHdhdmUuY28iLCJyb2xlcyI6WyJBcHBsaWNhbnQiLCJBdWRpdG9yIl0sImZ1bGxOYW1lIjoiRGF2aWQgS2ltIn0sImFjdGlvbiI6ImxvZ2luIiwiaWF0IjoxNzYxNjE2OTk2LCJleHAiOjE3NjE2MjA1OTZ9.I0hARpxoFQPfZjfn5ZqjV-sRJO6SKpAw7KZBR4mH6iI""
},
""clientId"": ""DucPqZtrHFQNgOnyiGV02"",
""requestID"": 13,
""_socketId"": ""0KAO_QB8U2vpv5xDAElI"",
""topic"": ""uibuilder"",
""_msgid"": ""7c5fc73c0374d772""
}
Backend Node-RED Flow
| Node Name | Type | Description / Function | Key Operations / Outputs |
|---|---|---|---|
| Log Captured EditRequest | function | Checks whether an incoming _archiveRequest exists in the message. Logs it for debugging. |
Warns “No editRequest captured yet” if missing. Logs full request if present. Passes message forward. |
| Prepare Archive Toggle Update | function | Extracts the request ID from _archiveRequest or msg.payload, validates it, and prepares the MongoDB update payload to toggle the archive field. |
Determines requestId. Builds msg.payload for MongoDB updateOne. Operation: { $set: { archive: { $not: ["$archive"] } } }. Sets collection = "Requests". |
| Update Request Archive | mongodb4 | Executes the prepared MongoDB updateOne operation against the Requests collection. |
Performs update with upsert: false. Output mode: toArray. Uses MongoDB client: 3947f4ac602166f9. |
| (Unnamed) | change | Sets a structured response message indicating success. | Sets msg.response = { "status": "success", "action": "archiveRequest", "message": "success" }. |
| archiveRequest | debug | Displays the final message (full msg object) in the Node-RED Debug sidebar for inspection. |
Outputs final message for confirmation and troubleshooting. |
| link out 40 | link out | Sends the successful result (msg.response) to another linked flow for further processing. |
Connects to Link node: 1a592f68894d0c59 (destination flow). |
Backend Flow Summary
Purpose
This flow manages toggling the archive status of a specific request in the Requests MongoDB collection.
It validates incoming data, performs a conditional update, and returns a structured success response.
Log Captured EditRequest
This function node checks whether an incoming _archiveRequest exists in the message.
- If it’s missing, a warning message is logged:
No editRequest captured yet
- If it’s present, the full request object is logged for debugging. After logging, the message is passed to the next node.
Prepare Archive Toggle Update
This Function node extracts and validates the request ID, then prepares the MongoDB update operation.
It searches for the ID in _archiveRequest or msg.payload, checking fields such as:
id, requestID, requestId, or _id.
If no ID is found, the node returns null to stop the flow.
If a valid ID is found, it builds the parameters needed for a MongoDB updateOne operation.
This operation is designed to toggle the value of the archive field using the following expression:
{ $set: { archive: { $not: ["$archive"] } } }
It then sets the target collection to Requestsand attaches the constructed payload to msg.
Update Request Archive
The Update Request Archive MongoDB node executes the update operation using the configured client connection:
3947f4ac602166f9.
- The node performs the update with
upsertdisabled (so it won’t create new documents). - The operation output is returned as an array.
Change Node
After a successful update, the message passes through a Change node that creates a structured response object:
{
"status": "success",
"action": "archiveRequest",
"message": "success"
}
This response replaces msg.response, preparing it for output or further handling.
Response Examples (uibuilder.onChange)
// Success Response
{
"status": "success",
"action": "archiveRequest",
"message": "success"
}
MongoDB Requests Collection Schema
| Field | Type | Description |
|---|---|---|
| _id | String | Unique MongoDB document identifier |
| id | Number | Internal record ID |
| createdBy.userId | String | ID of the user who created the record |
| createdBy.id | Number | Creator’s internal ID |
| createdBy.fullName | String | Name of the creator (e.g., David Kim) |
| createdBy.email | String | Creator’s email address |
| createdBy.avatarUrl | String | Base64-encoded profile image URL |
| companyDetails.priority | String | Task or request priority (e.g., low) |
| companyDetails.status | String | Current status (e.g., Approved) |
| companyDetails.archive | Boolean | Indicates if the record is archived |
| companyDetails.timeEstimation | String | Estimated completion time |
| companyDetails.assignedTo | String | Assigned user (empty if none) |
| auditInfo | Object | Audit tracking data (timestamps, etc.) |
| approveInfo | Object | Approval metadata or history |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Last update timestamp |
Sample document:
{
"_id": "6907636ed6c4398ea5f5cd42",
"id": 2,
"createdBy": {
"userId": "68f830f9d6c4398ea5f5cbdf",
"id": 1,
"fullName": "David Kim",
"email": "david.kim@brightwave.co",
"avatarUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEhUSEhI…"
},
"companyDetails": {
"priority": "low",
"status": "Approved",
"archive": false,
"timeEstimation": "10 business day",
"assignedTo": ""
},
"auditInfo": {},
"approveInfo": {},
"createdAt": "2025-11-02T13:58:06.411+00:00",
"updatedAt": "2025-11-02T14:05:05.471+00:00"
}
4.4.editProfile Flow
High-Level Flow:
Incoming _editProfile Request
↓
┌────────────────────────────┐
│ Log Captured EditProfile │
│ Checks if _editProfile │
│ exists → Logs details │
└────────────────────────────┘
↓
┌────────────────────────────┐
│ Prepare EditProfile Update │
│ - Validates userId & │
│ profileDetails │
│ - Converts userId to │
│ ObjectId │
│ - Builds updateOne query │
│ for MongoDB │
└────────────────────────────┘
↓
┌────────────────────────────┐
│ Update User (MongoDB4) │
│ Executes updateOne on │
│ Users collection │
│ Updates profile, email, │
│ and updatedAt fields │
└────────────────────────────┘
↓
┌────────────────────────────┐
│ Change Node │
│ Creates standardized │
│ response JSON: │
│ {status:"success", │
│ action:"editProfile"} │
└────────────────────────────┘
↓
┌────────────────────────────┐
│ editProfile (Debug) │
│ Shows final response in │
│ debug sidebar │
└────────────────────────────┘
↓
┌────────────────────────────┐
│ link out │
│ Sends response to connected│
│ flow (e.g., frontend) │
└────────────────────────────┘
Frontend editProfile
uibuilder.send({
type: 'editProfile',
auth: {
userToken: this.getCookie('userToken'),
clientId:this.getCookie('uibuilder-client-id')
},
profile: this.profile,
userId: this.profile.userId
})
this.showNotification('Profile updated successfully!', 'success');
this.originalProfile = JSON.parse(JSON.stringify(this.profile));
this.isProfileEdited = false;
},
Sending a Message
The uibuilder.send() function sends a structured JSON message from the frontend (browser) to the Node-RED flow connected to this UI.
-
Message Type:
type: 'editProfile'- Defines the message category.
- The Node-RED backend can filter based on this type:
if (msg.type === 'editProfile') { // Handle edit profile logic }
Authentication Object
The auth object includes:
auth: {
userToken: this.getCookie('userToken'),
clientId: this.getCookie('uibuilder-client-id')
}
User Authentication
- userToken: Retrieved from browser cookies; acts as a session token to verify user identity.
- clientId: Unique identifier for this connected UIBuilder client instance. This helps Node-RED know which user’s UI sent the message.
This provides an authentication and traceability layer for the backend.
Profile Data
profile:
profile: this.profileThe entire profile object containing updated user data (e.g., name, email, phone, etc.).
userId: this.profile.userId
- Explicitly adds the userId to make it easy for Node-RED to target the correct database entry or API endpoint.
Show Notification
this.showNotification('Profile updated successfully!', 'success');
Purpose: Immediately give UX feedback to the user that their profile
update was sent successfully.
-
showNotification()is likely a local method that triggers a UI alert or toast popup. - The 'success' type may apply specific colors/icons (e.g., green checkmark).
This runs immediately after sending the request, not after backend confirmation — so it’s a frontend optimistic update.
Reset State
this.originalProfile = JSON.parse(JSON.stringify(this.profile));
this.isProfileEdited = false;
Purpose and behavior:
JSON.parse(JSON.stringify(...))
- Deep-copies the current profile object.
- Ensures that originalProfile and profile are not referencing the same object in memory.
this.originalProfile = ...
- Stores the last successfully sent version of the user’s profile.
- Used later to detect unsaved changes.
this.isProfileEdited = false;
- Resets the “edit mode” flag, telling the UI that there are no pending unsaved edits anymore.
- Often used to disable “Save” buttons or hide “unsaved changes” warnings.
Sample Request Payload
"{
""type"": ""editProfile"",
""auth"": {
""userToken"": ""eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTYxNjk5NjI1NSIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmODMwZjlkNmM0Mzk4ZWE1ZjVjYmRmIiwiaWQiOjEsImVtYWlsIjoiZGF2aWQua2ltQGJyaWdodHdhdmUuY28iLCJyb2xlcyI6WyJBcHBsaWNhbnQiLCJBdWRpdG9yIl0sImZ1bGxOYW1lIjoiRGF2aWQgS2ltIn0sImFjdGlvbiI6ImxvZ2luIiwiaWF0IjoxNzYxNjE2OTk2LCJleHAiOjE3NjE2MjA1OTZ9.I0hARpxoFQPfZjfn5ZqjV-sRJO6SKpAw7KZBR4mH6iI""
},
""clientId"": ""DucPqZtrHFQNgOnyiGV02"",
""profile"": {
""userId"": ""68f830f9d6c4398ea5f5cbdf"",
""email"": ""david.kim@brightwave.co"",
""role"": ""Applicant"",
""roles"": [""Applicant"", ""Auditor""],
""avatarUrl"": ""data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEhUSEhIVFhAXFRUSFRUVFRAVFRAVFRIXFxcVFRUYHSggGBolHRUVITEhJSkrLi4uFx8zODMtNygtLisBCgoKDg0OFxAQFS0dIB0tLS0tLSstLSstLS0tKystLSsrLS0tKy0tLS0rLS0rLS0tNys3Ky0tLSsrLSsrKy0rK//AABEIARMAtwMBIgACEQEDEQA/ANulCQXQnRFnIXQE6F2EhjQE6F2F2EANhdDV1dSA5lXCE9cIQAzKugLqc1qBnIShPhIhAhkLoXYSQAl0JhcuZkDJUkzMlnSAekmSugoAckkkgCqE5PypZVZA0Jy6GruVAzgC6AuhqcAkMbCUJySAGJLpWY4p4vpWQc0eOt+Qf093Hl5IA0r3gCSQB1Og+Khp4lScYbUYT0D2k/AFeI4rxXWu3EOcQIJ00a0cg0dU3D7xzADlMxuIPqE6Ge5uvWBwbmGc8pE/BTryUcSVKrQ1whwdIMBp84566rV4TxqwhrKzXNqbEwIMc/VSFGtKjcU62rNqtDmmWlPNNAiq5yUqc0Vz2KBkcroUgpJ4poAiATpTi1NISAQKSQCSAJcqWVPXU7FQwNXcqeuosZHlShOe6FWddhFgSkKpiV/Tt2GpVdlYPiew6rmJYm2hSfVds0T5rxbiHiepc1HOfsJyN/pYOW257pxViZp8Z42uawLbdgpt2znV3pyWQuKZAJeRn11cZkk8pPxKEVMRq..."",
""firstName"": ""David"",
""lastName"": ""Kim"",
""contactNumber"": """",
""address"": """",
""country"": """",
""stateOrProvince"": """",
""postalCode"": """"
},
""_socketId"": ""0KAO_QB8U2vpv5xDAElI"",
""topic"": ""uibuilder"",
""_msgid"": ""37a193fd9e74e""
}
"
Backend Node-RED Flow
| Node Name | Type | Description |
|---|---|---|
| Log Captured EditProfile | function |
Checks if an _editProfile object exists in the incoming message. If it does not exist, logs a warning message "No editProfile captured yet". If it exists, logs the captured editProfile details as a JSON string for debugging. Passes the message to the next node. |
| Prepare EditProfile Update | function |
Validates the _editProfile object. Extracts userId and profileDetails from it. If either is missing, stops the flow. Removes the email field from profileDetails, stores it separately, and converts userId into a MongoDB ObjectId. Prepares an updateOne operation for the Users collection, setting new profile data, email, and an updated timestamp. Passes the MongoDB query to the next node. |
| Update User | mongodb4 |
Executes the prepared updateOne operation on the Users collection in the connected MongoDB database. Updates the user’s profile and email based on the provided ObjectId. After the operation, sends the output to the next node. |
| Change | change |
Creates a standardized response object inside the message payload: {"status":"success","action":"editProfile","message":"success"}. This ensures the front end receives a clear and consistent update confirmation. Sends the message to the debug and link nodes. |
| editProfile | debug |
Displays the final message in the Node-RED debug sidebar for verification and troubleshooting. Useful for confirming successful updates and checking the output data structure. |
| link out | link out |
Sends the final response message to another flow or group in Node-RED that is linked via the same link ID. This allows the result of the profile update operation to be routed to other connected processes (such as UI feedback or logging flows). |
Backend Flow Summary
The EditProfile flow handles updating a user’s profile information in the MongoDB database. It performs input validation, data transformation, and database update operations, followed by returning a success response.
Input and Validation
- The process begins with the Log Captured
EditProfilefunction node. - It checks whether
msg._editProfileexists.
If not found, it logs a warning and halts further updates.
If found, it logs the full content for debugging.
- This ensures only valid edit requests proceed to the update logic.
Data Preparation
The Prepare EditProfile Update node extracts userId and profileDetails from msg._editProfile.
It performs the following technical steps:
Validates both fields’ existence.
Separates the
emailfrom theprofileDetailsobject (to be updated independently).Converts the
userIdstring into a valid mongodb.ObjectId.If the
ObjectIdis invalid, the flow logs an error and stops.Constructs an
updateOneoperation with$set:
{
"profile": "<profileDetails>",
"email": "<email>",
"updatedAt": "<current timestamp>"
}
Stores the query as:
msg.collection = "Users";
msg.operation = "updateOne";
msg.payload = [ { _id: ObjectId }, { $set: {...} }, { upsert: false } ];
Database Operation
- The Update User node (MongoDB4 node) connects to the defined MongoDB cluster.
- Executes the updateOne operation on the Users collection.
- It ensures only one matching record (by _id) is updated without inserting a new one.
Response Construction
- After the update completes, the change node builds a standardized response:
{
"status": "success",
"action": "editProfile",
"message": "success"
}
- This structured response ensures the front-end receives consistent output regardless of internal flow complexity.
Response Examples (uibuilder.onChange)
// Success Response
{
"status": "success",
"action": "editProfile",
"message": "success"
}
MongoDB Requests Collection Schema
| Field | Type | Description |
|---|---|---|
| _id | String | Unique MongoDB document identifier |
| id | Number | Internal record ID |
| createdBy.userId | String | ID of the user who created the record |
| createdBy.id | Number | Creator’s internal ID |
| createdBy.fullName | String | Name of the creator (e.g., David Kim) |
| createdBy.email | String | Creator’s email address |
| createdBy.avatarUrl | String | Base64-encoded profile image URL |
| companyDetails.priority | String | Task or request priority (e.g., low) |
| companyDetails.status | String | Current status (e.g., Approved) |
| companyDetails.archive | Boolean | Indicates if the record is archived |
| companyDetails.timeEstimation | String | Estimated completion time |
| companyDetails.assignedTo | String | Assigned user (empty if none) |
| auditInfo | Object | Audit tracking data (timestamps, etc.) |
| approveInfo | Object | Approval metadata or history |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Last update timestamp |
Sample document:
{
"_id": "6907636ed6c4398ea5f5cd42",
"id": 2,
"createdBy": {
"userId": "68f830f9d6c4398ea5f5cbdf",
"id": 1,
"fullName": "David Kim",
"email": "david.kim@brightwave.co",
"avatarUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEhUSEhI…"
},
"companyDetails": {
"priority": "low",
"status": "Approved",
"archive": false,
"timeEstimation": "10 business day",
"assignedTo": ""
},
"auditInfo": {},
"approveInfo": {},
"createdAt": "2025-11-02T13:58:06.411+00:00",
"updatedAt": "2025-11-02T14:05:05.471+00:00"
}
4.5.auditRequest Flow
High-Level Flow:
Incoming _auditRequest
↓
┌─────────────────────────────────────┐
│ Log Captured Audit Request │
│ Checks if _auditRequest exists │
│ → Logs full request for debugging │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Prepare Audit Update │
│ - Extracts audit.id and userId │
│ - Determines decision and newStatus │
│ - Builds updateOne query for MongoDB│
│ to update status and auditInfo │
│ { date, auditorId, comment } │
│ - Adds updatedAt timestamp │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Update Request Record (MongoDB4) │
│ Executes updateOne on "Requests" │
│ collection to apply audit decision │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Change Node │
│ Sets standardized response: │
│ {status:"success", action:"auditRequest"} │
│ Prepares final output message │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ auditRequest (Debug) │
│ Displays final response in debug │
│ sidebar for verification │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ link out │
│ Sends response to connected flows │
│ (e.g., UI or further processing) │
└─────────────────────────────────────┘
Frontend auditRequest
auditRequest() {
const req = this.currentRequest;
const updatedStatus = req.status.charAt(0).toUpperCase() + req.status.slice(1).toLowerCase();
const auditDate = req.auditDate || new Date().toISOString().split('T')[0];
const comment = req.auditorComment || '';
// send to backend
uibuilder.send({
type: 'auditRequest',
auth: {
userToken: this.getCookie('userToken'),
clientId: this.getCookie('uibuilder-client-id')
},
userId: this.profile.userId,
requestId: req.id || req._id,
auditDecision: { status: updatedStatus, auditDate, comment }
});
// show waiting state
this.waitingForResponse = true;
// update in all dashboards immediately
const updateLists = [this.applicantRequests, this.auditorRequests, this.adminRequests];
updateLists.forEach(list => {
const index = list.findIndex(r => (r.id || r._id) === (req.id || req._id));
if (index !== -1) {
list.splice(index, 1, {
...list[index],
status: updatedStatus,
auditDate,
auditorComment: comment
});
}
});
setTimeout(() => {
if (this.waitingForResponse) {
this.showNotification('Network error! Please refresh.', 'error');
this.waitingForResponse = false;
this.submissionSuccess = false;
this.closeModal(); // optional: close modal automatically
}
}, 6000);
},
The auditRequest() function handles sending an audit decision from the frontend to the backend and updates the UI immediately.
Extract & Normalize Data
-
Gets current request:
- This is done using
this.currentRequest.
- This is done using
-
Formats:
- Status
- Sets
auditDate - Extracts
auditorComment
Send to Backend
- Uses
uibuilder.send()with the following parameters:authenticationuserIdrequestId-
auditDecisionpayload
Optimistic UI Update
- Instantly updates the following lists for a responsive UI:
applicantRequestsauditorRequestsadminRequests
Error Handling
- Sets a 6-second timeout:
- If no response is received, it shows a network error.
- Resets flags.
- Optionally closes the modal.
Purpose
The purpose of this function is to ensure fast and responsive feedback to the auditor while securely submitting the decision to the backend for database updates.
Sample Request Payload
"{
""type"": ""auditRequest"",
""auth"": {
""userToken"": ""eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTYxNjk5NjI1NSIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmODMwZjlkNmM0Mzk4ZWE1ZjVjYmRmIiwiaWQiOjEsImVtYWlsIjoiZGF2aWQua2ltQGJyaWdodHdhdmUuY28iLCJyb2xlcyI6WyJBcHBsaWNhbnQiLCJBdWRpdG9yIl0sImZ1bGxOYW1lIjoiRGF2aWQgS2ltIn0sImFjdGlvbiI6ImxvZ2luIiwiaWF0IjoxNzYxNjE2OTk2LCJleHAiOjE3NjE2MjA1OTZ9.I0hARpxoFQPfZjfn5ZqjV-sRJO6SKpAw7KZBR4mH6iI""
},
""clientId"": ""DucPqZtrHFQNgOnyiGV02"",
""userId"": ""68f830f9d6c4398ea5f5cbdf"",
""requestId"": 18,
""auditDecision"": {
""status"": ""Audited"",
""auditDate"": ""2025-10-28"",
""comment"": ""yes""
},
""_socketId"": ""0KAO_QB8U2vpv5xDAElI"",
""topic"": ""uibuilder"",
""_msgid"": ""196c7d70d5cc4""
}
"
Backend Node-RED Flow
| Node Name | Type | Description |
|---|---|---|
| Log Captured Audit Request | function |
Checks whether an incoming _auditRequest exists in the message. If missing, logs a warning “No auditRequest captured yet”. If present, logs the full audit request for debugging. Passes the message to the next node. |
| Prepare Audit Update | function |
Extracts audit details from msg._auditRequest and determines the target user ID from either msg.userId or msg.auth.userId. If no valid audit data or ID is found, the message is dropped. Otherwise, it prepares a MongoDB updateOne operation for the Requests collection, updating fields such as status, audit information (date, auditor ID, comment, decision), and timestamp. |
| Update Request Record | mongodb4 |
Executes the MongoDB update operation prepared by the previous node. It connects to the specified MongoDB cluster (hediyehTC database) and applies the update to the Requests collection. |
change |
Creates a standardized response message confirming successful audit update. Sets msg.response to a JSON object containing status: success, action: auditRequest, and message: success. Passes the response to the debug and link-out nodes. |
|
| auditRequest | debug |
Displays the final message object in the Node-RED debug sidebar, allowing developers to verify the response payload and data structure after database update. |
| link out 38 | link out |
Forwards the processed message to another part of the flow using a link connection (1a592f68894d0c59), typically to send the response back to the frontend or trigger additional logic. |
Backend Flow Summary
Capture and Log the Incoming Audit Request
- The Log Captured Audit Request function node checks for the presence of
_auditRequestin the message. - If the field is missing, it logs a warning to indicate no request has been received yet.
- If present, the entire request object is logged for traceability and debugging.
- This ensures early validation and helps identify missing or malformed messages before database operations begin.
Prepare MongoDB Update Operation
- The Prepare Audit Update node extracts and structures the necessary update parameters.
- It determines:
The request ID from audit.id
The auditor ID from msg.userId or msg.auth.userId
The new status based on audit.auditDecision.status or audit.status
If no valid audit data is found, the message flow stops (return null).
Otherwise, it constructs a MongoDB
updateOnecommand
Execute Database Update
- The Update Request Record node (mongodb4) connects to the
hediyehTCMongoDB database. - It applies the update operation defined in the previous node to the
Requestscollection. - The operation updates the record matching the provided request ID without inserting new records
(upsert: false).
Generate Standardized Response
- After a successful update, the change node sets a response object:
{
"status": "success",
"action": "auditRequest",
"message": "success"
}
- This response is stored in
msg.responsefor consistent backend–frontend communication.
Response Examples (uibuilder.onChange)
// Success Response
{
"status": "success",
"action": "auditRequest",
"message": "success"
}
MongoDB Requests Collection Schema
| Field | Type | Description |
|---|---|---|
| _id | String | Unique MongoDB document identifier |
| id | Number | Internal record ID |
| createdBy.userId | String | ID of the user who created the record |
| createdBy.id | Number | Creator’s internal ID |
| createdBy.fullName | String | Name of the creator (e.g., David Kim) |
| createdBy.email | String | Creator’s email address |
| createdBy.avatarUrl | String | Base64-encoded profile image URL |
| companyDetails.priority | String | Task or request priority (e.g., low) |
| companyDetails.status | String | Current status (e.g., Approved) |
| companyDetails.archive | Boolean | Indicates if the record is archived |
| companyDetails.timeEstimation | String | Estimated completion time |
| companyDetails.assignedTo | String | Assigned user (empty if none) |
| auditInfo | Object | Audit tracking data (timestamps, etc.) |
| approveInfo | Object | Approval metadata or history |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Last update timestamp |
Sample document:
{
"_id": "6907636ed6c4398ea5f5cd42",
"id": 2,
"createdBy": {
"userId": "68f830f9d6c4398ea5f5cbdf",
"id": 1,
"fullName": "David Kim",
"email": "david.kim@brightwave.co",
"avatarUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEhUSEhI…"
},
"companyDetails": {
"priority": "low",
"status": "Approved",
"archive": false,
"timeEstimation": "10 business day",
"assignedTo": ""
},
"auditInfo": {},
"approveInfo": {},
"createdAt": "2025-11-02T13:58:06.411+00:00",
"updatedAt": "2025-11-02T14:05:05.471+00:00"
}
4.6.approveRequest Flow
High-Level Flow:
Incoming _approveRequest
↓
┌─────────────────────────────────────┐
│ Log Captured Approve Request │
│ Checks if _approveRequest exists │
│ → Logs full request for debugging │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Prepare Approve Update │
│ - Extracts approve.id and userId │
│ - Determines decision and newStatus │
│ - Builds updateOne query for MongoDB│
│ to update status and approveInfo │
│ { date, approverId, comment } │
│ - Adds updatedAt timestamp │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Update Request Record (MongoDB4) │
│ Executes updateOne on "Requests" │
│ collection to apply approval decision│
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Change Node │
│ Sets standardized response: │
│ {status:"success", action:"approveRequest"} │
│ Prepares final output message │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ approveRequest (Debug) │
│ Displays final response in debug │
│ sidebar for verification │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ link out │
│ Sends response to connected flows │
│ (e.g., UI or further processing) │
└─────────────────────────────────────┘
Frontend approveRequest
uibuilder.send({
type: 'approveRequest',
auth: {
userToken: this.getCookie('userToken'),
clientId: this.getCookie('uibuilder-client-id')
},
userId: this.profile.userId,
requestId: req.id || req._id,
approverDecision: { status: updatedStatus, date: approveDate, comment }
});
this.waitingForResponse = true;
const updateLists = [this.applicantRequests, this.approverRequests, this.adminRequests];
updateLists.forEach(list => {
const index = list.findIndex(r => (r.id || r._id) === (req.id || req._id));
if (index !== -1) {
list.splice(index, 1, {
...list[index],
status: updatedStatus,
approveDate,
approveComment: comment
});
}
});
Uses uibuilder.send() to submit an approval decision.
Payload includes:
-
type:
"approveRequest" - auth: User token and client ID from cookies
- userId: ID of the approver
- requestId: Target request ID
-
approverDecision:
- status
- date
- comment
Set Waiting State
-
this.waitingForResponse = trueindicates that the frontend is awaiting backend confirmation.
Optimistic UI Update
Updates local request lists immediately:
- applicantRequests
- approverRequests
- adminRequests
Updates the matching request by ID:
- status → Updated approval status
- approveDate → Date of approval
- approveComment → Approver comment
Provides instant feedback to the user while backend processing completes.
Purpose
Ensures responsive UI and secure submission of approval decisions to the backend.
Sample Request Payload
"{
""type"": ""approveRequest"",
""auth"": {
""userToken"": ""eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTYxODg3NTczNSIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmODM2MzhkNmM0Mzk4ZWE1ZjVjYmU2IiwiaWQiOjIsImVtYWlsIjoibGVpbGEuaGFzc2FuQHNreW5ldC5zeXN0ZW1zIiwicm9sZXMiOlsiQXBwbGljYW50IiwiQXBwcm92ZXIiXSwiZnVsbE5hbWUiOiJMZWlsYSBIYXNzYW4ifSwiYWN0aW9uIjoibG9naW4iLCJpYXQiOjE3NjE2MTg4NzUsImV4cCI6MTc2MTYyMjQ3NX0.yC6fr76smTVPPr0kCrmTARcJQ5qiuGqYKvl8_16rcts""
},
""clientId"": ""DucPqZtrHFQNgOnyiGV02"",
""userId"": ""68f83638d6c4398ea5f5cbe6"",
""requestId"": 18,
""approverDecision"": {},
""_socketId"": ""fVUzLOHQeYT96ZrqAEla"",
""topic"": ""uibuilder"",
""_msgid"": ""b26bc97d28188""
}
"
Backend Node-RED Flow
| Node Name | Type | Description |
|---|---|---|
| Log Captured Approve Request | function | Checks if _approveRequest exists in the incoming message. Logs a warning if missing and logs the captured request for debugging if present. Passes the message to the next node. |
| Prepare Approve Update | function | Extracts approval details from msg._approveRequest. Determines the user ID from msg.userId or msg.auth.userId. If no valid approval data or ID is found, stops the flow. Otherwise, prepares a MongoDB updateOne operation to update the Requests collection with the new status, approver info (date, ID, comment, decision), and timestamp. |
| Update Request Record | mongodb4 | Executes the prepared update operation in the Requests collection of the hediyehTC MongoDB database. Updates the record matching the approval request ID without inserting new records. |
| approveRequest | debug | Displays the final message object in the Node-RED debug sidebar for verification, including the standardized response message. |
| change | change | Sets msg.response to a JSON object indicating success: status: success, action: approveRequest, and message: success. Passes the message to debug and link-out nodes. |
| link out | link out | Forwards the processed message to another part of the flow (1a592f68894d0c59), typically to send the response back to the frontend or trigger additional backend logic. |
| mongodb4-client | mongodb4-client | Provides the MongoDB connection to the hediyehTC database on DigitalOcean, supporting secure TLS connection and pooling. Used by the Update Request Record node for executing operations. |
Backend Flow Summary
Capture and Log the Incoming Approval Request
The Log Captured Approve Request function node checks for the presence of _approveRequest in the message.
-
If missing:
- Logs a warning.
-
If present:
- Logs the full request object for debugging and traceability.
This ensures that all subsequent operations have valid approval data.
Prepare MongoDB Update Operation
The Prepare Approve Update function extracts the request and user details:
-
Approval request object:
msg._approveRequest -
User ID:
msg.userIdormsg.auth.userId -
Decision details:
- Status
- Date
- Comment
Validates that the approval request exists and has an ID. If not, the flow stops.
Constructs a MongoDB updateOne operation to ensure only the targeted request is updated with new approval info, without creating a new record.
Execute Database Update
The Update Request Record node connects to the hediyehTC MongoDB database.
- Executes the prepared
updateOneoperation to update the Requests collection. - Ensures atomic and safe updates of request status and approver information.
Generate Standardized Response
After a successful update, the change node sets a consistent response in msg.response.
{
"status": "success",
"action": "approveRequest",
"message": "success"
}
This allows the frontend to handle success consistently for UI feedback.
Response Examples (uibuilder.onChange)
// Success Response
{
"status": "success",
"action": "approveRequest",
"message": "success"
}
MongoDB Requests Collection Schema
| Field | Type | Description |
|---|---|---|
| _id | String | Unique MongoDB document identifier |
| id | Number | Internal record ID |
| createdBy.userId | String | ID of the user who created the record |
| createdBy.id | Number | Creator’s internal ID |
| createdBy.fullName | String | Name of the creator (e.g., David Kim) |
| createdBy.email | String | Creator’s email address |
| createdBy.avatarUrl | String | Base64-encoded profile image URL |
| companyDetails.priority | String | Task or request priority (e.g., low) |
| companyDetails.status | String | Current status (e.g., Approved) |
| companyDetails.archive | Boolean | Indicates if the record is archived |
| companyDetails.timeEstimation | String | Estimated completion time |
| companyDetails.assignedTo | String | Assigned user (empty if none) |
| auditInfo | Object | Audit tracking data (timestamps, etc.) |
| approveInfo | Object | Approval metadata or history |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Last update timestamp |
Sample document:
{
"_id": "6907636ed6c4398ea5f5cd42",
"id": 2,
"createdBy": {
"userId": "68f830f9d6c4398ea5f5cbdf",
"id": 1,
"fullName": "David Kim",
"email": "david.kim@brightwave.co",
"avatarUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEhUSEhI…"
},
"companyDetails": {
"priority": "low",
"status": "Approved",
"archive": false,
"timeEstimation": "10 business day",
"assignedTo": ""
},
"auditInfo": {},
"approveInfo": {},
"createdAt": "2025-11-02T13:58:06.411+00:00",
"updatedAt": "2025-11-02T14:05:05.471+00:00"
}
4.7.createRequest Flow
High-Level Flow:
Frontend sends request creation data
↓
┌─────────────────────────────────────┐
│ Prepare Last Request Query │
│ - Extracts user info from payload │
│ - Builds MongoDB find query to get │
│ the last request (sort by id desc)│
│ - Attaches companyDetails and user │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Find Last Request (MongoDB4) │
│ - Executes find query to get last │
│ request to determine new requestId│
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Build New Request Document │
│ - Calculates new request ID │
│ - Populates createdBy info (user) │
│ - Sets companyDetails, default status,│
│ priority, archive, timeEstimation │
│ - Initializes auditInfo and approveInfo │
│ - Adds createdAt timestamp │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Insert Request into MongoDB (MongoDB4) │
│ - Inserts the new request document into│
│ "Requests" collection │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Prepare Response Data │
│ - Extracts key fields from request │
│ - Prepares payload for frontend: │
│ { id, status, companyDetails, auditDate,│
│ auditorComment, timeEstimation } │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Change Node │
│ - Sets standardized response: │
│ {status:"success", action:"createRequest"} │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ success (Debug) │
│ - Outputs response for verification │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ link out / further processing │
│ - Sends response to connected flows │
└─────────────────────────────────────┘
Frontend sends request creation data
↓
┌─────────────────────────────────────┐
│ Prepare Last Request Query │
│ - Extracts user info from payload │
│ - Builds MongoDB find query to get │
│ the last request (sort by id desc)│
│ - Attaches companyDetails and user │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Find Last Request (MongoDB4) │
│ - Executes find query to get last │
│ request to determine new requestId│
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Build New Request Document │
│ - Calculates new request ID │
│ - Populates createdBy info (user) │
│ - Sets companyDetails, default status,│
│ priority, archive, timeEstimation │
│ - Initializes auditInfo and approveInfo │
│ - Adds createdAt timestamp │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Insert Request into MongoDB (MongoDB4) │
│ - Inserts the new request document into│
│ "Requests" collection │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Prepare Response Data │
│ - Extracts key fields from request │
│ - Prepares payload for frontend: │
│ { id, status, companyDetails, auditDate,│
│ auditorComment, timeEstimation } │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Change Node │
│ - Sets standardized response: │
│ {status:"success", action:"createRequest"} │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ success (Debug) │
│ - Outputs response for verification │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ link out / further processing │
│ - Sends response to connected flows │
└─────────────────────────────────────┘
Frontend createRequest
uibuilder.send({
type: 'createRequest',
auth: {
userToken: this.getCookie('userToken'),
clientId: this.getCookie('uibuilder-client-id')
},
companyDetails: { ...this.formData }
});
this.waitingForResponse = true;
setTimeout(() => {
if (this.waitingForResponse) {
this.showNotification('Network error! Please refresh.', 'error');
this.waitingForResponse = false;
this.submissionSuccess = false;
this.closeModal(); // optional: close modal automatically
}
}, 6000);
},
Uses uibuilder.send() to submit a new request.
Payload includes:
- type: "createRequest"
- auth: User token and client ID from cookies
- companyDetails: Form data from the user
Set Waiting State
-
this.waitingForResponse = trueindicates the frontend is waiting for backend confirmation.
Error Handling / Timeout
- Sets a 6-second timeout.
- If no response:
- Displays a network error notification.
- Resets
waitingForResponseandsubmissionSuccess. - Optionally closes the modal.
Purpose
Ensures secure submission of new requests to the backend with responsive feedback to the user while handling potential network issues.
Sample Request Payload
{
"type": "createRequest",
"auth": {
"userToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTYxNjk5NjI1NSIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmODMwZjlkNmM0Mzk4ZWE1ZjVjYmRmIiwiaWQiOjEsImVtYWlsIjoiZGF2aWQua2ltQGJyaWdodHdhdmUuY28iLCJyb2xlcyI6WyJBcHBsaWNhbnQiLCJBdWRpdG9yIl0sImZ1bGxOYW1lIjoiRGF2aWQgS2ltIn0sImFjdGlvbiI6ImxvZ2luIiwiaWF0IjoxNzYxNjE2OTk2LCJleHAiOjE3NjE2MjA1OTZ9.I0hARpxoFQPfZjfn5ZqjV-sRJO6SKpAw7KZBR4mH6iI"
},
"clientId": "DucPqZtrHFQNgOnyiGV02",
"companyDetails": {},
"_socketId": "0KAO_QB8U2vpv5xDAElI",
"topic": "uibuilder",
"_msgid": "46c1c3b28576"
}
Backend Node-RED Flow
| Node Name | Type | Description |
|---|---|---|
| success | debug | Displays the final message in the Node-RED debug sidebar for verification of the request creation process. |
| Build New Request Document | function | Extracts the last request to determine a new id. Extracts user information from msg.user and company details from msg.companyDetails or msg.auth. Prepares a new request object with default fields (status: Pending, priority: low, auditInfo, approveInfo, etc.) and sets msg.collection to Requests with insertOne operation. Stores the new request in msg.request. |
| Insert Request into MongoDB | mongodb4 | Executes the insertOne operation to add the newly built request document to the Requests collection in the hediyehTC database. |
| Prepare Last Request Query | function | Prepares a MongoDB find query to retrieve the last request document, sorted by id descending, limited to 1. Passes user info and company details along for the next node. |
| Find Last Request | mongodb4 | Executes the find query to fetch the last request from the Requests collection. Outputs the result as an array for the next function node to calculate the new request ID. |
| Prepare Response Data | function | Formats the inserted request data into a simplified response object, including archive, auditDate, auditorComment, companyDetails, id, status, timeEstimation, and title. |
| change | change | Sets a standardized msg.response JSON object indicating success (status: success, action: createRequest, message: success). Passes the message to debug and link-out nodes. |
| mongodb4-client | mongodb4-client | Provides the MongoDB connection to the hediyehTC database, with TLS security and connection pooling. Used by the MongoDB nodes to perform find and insert operations. |
Backend Flow Summary
Retrieve Last Request
The Prepare Last Request Query node constructs a MongoDB find query:
- Collection: Requests
- Sorted by: ID descending
- Limit: 1
The Find Last Request node executes this query to fetch the last request in the collection.
Purpose
Determine the next request ID for the new request.
Build New Request Document
The Build New Request Document node:
- Calculates
newIdbased on the last request ID. - Extracts user information from
msg.user. - Extracts company details from
msg.companyDetailsormsg.auth.
Builds a request object with default fields:
- status: Pending
- priority: low
- timeEstimation: 10 business days
- auditInfo: initialized as null
- approveInfo: initialized as null
- createdAt: timestamp
Sets msg.collection to Requests and operation to insertOne.
Insert Request into MongoDB
The Insert Request into MongoDB node performs the insertOne operation on the Requests collection.
Ensures
The new request is saved atomically in the database.
Prepare Response Data
The Prepare Response Data node formats the inserted request into a simplified response object for the frontend:
Fields include:
- archive
- auditDate
- auditorComment
- companyDetails
- id
- status
- timeEstimation
- title
Generate Standardized Response
- The change node sets
msg.responsewith a standard JSON structure:
{
"status": "success",
"action": "createRequest",
"message": "success"
}
- The success debug node logs this response for verification.
- The message can then be sent back to the frontend via a link-out node.
Response Examples (uibuilder.onChange)
{
"status": "success",
"action": "createRequest",
"message": "Request created successfully."
}
MongoDB Requests Collection Schema
| Field | Type | Description |
|---|---|---|
| _id | String | Unique MongoDB document identifier |
| id | Number | Internal record ID |
| createdBy.userId | String | ID of the user who created the record |
| createdBy.id | Number | Creator’s internal ID |
| createdBy.fullName | String | Name of the creator (e.g., David Kim) |
| createdBy.email | String | Creator’s email address |
| createdBy.avatarUrl | String | Base64-encoded profile image URL |
| companyDetails.priority | String | Task or request priority (e.g., low) |
| companyDetails.status | String | Current status (e.g., Approved) |
| companyDetails.archive | Boolean | Indicates if the record is archived |
| companyDetails.timeEstimation | String | Estimated completion time |
| companyDetails.assignedTo | String | Assigned user (empty if none) |
| auditInfo | Object | Audit tracking data (timestamps, etc.) |
| approveInfo | Object | Approval metadata or history |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Last update timestamp |
Sample document:
{
"_id": "6907636ed6c4398ea5f5cd42",
"id": 2,
"createdBy": {
"userId": "68f830f9d6c4398ea5f5cbdf",
"id": 1,
"fullName": "David Kim",
"email": "david.kim@brightwave.co",
"avatarUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEhUSEhI…"
},
"companyDetails": {
"priority": "low",
"status": "Approved",
"archive": false,
"timeEstimation": "10 business day",
"assignedTo": ""
},
"auditInfo": {},
"approveInfo": {},
"createdAt": "2025-11-02T13:58:06.411+00:00",
"updatedAt": "2025-11-02T14:05:05.471+00:00"
}
UIBuilder Authentication Flow Overview
| Type | Flow Overview | Collections / Description |
|---|---|---|
| signup | Handles new user registration and account creation. | Users — A new record is added with details such as fullName, email, password, and role. Validation ensures the email is unique before saving. |
| login | Authenticates existing users and establishes a secure session. | Users — Validates credentials (email, password). Tokens — Generates a new authentication token to manage the session and track expiration. |
| sendResetCode | Initiates the password recovery process when a user requests to reset their password. | PasswordResets — Creates a record with a verification code, userId, email, createdAt, and expiresAt. This is used to validate the reset request. |
| resendResetPassword | Resends the password reset code when the previous one expires or is lost. | PasswordResets — Updates or regenerates a reset code and resends it to the registered email. |
| setNewPassword | Updates the password after the reset code is verified. | PasswordResets — Marks the code as “used.” Users — Updates the password field for the corresponding account. |
| resetPassword | Finalizes password change after user validation, ensuring secure update of credentials. | Users — Commits the new password. PasswordResets — Confirms the reset process is completed and the code is invalidated. |
UIBuilder Dashboard Flow Overview
| Type | Flow Overview | Collections / Description |
|---|---|---|
| getDashboard | Retrieves and displays user-specific dashboard data such as pending, approved, or audited requests. | Requests — Fetches request data based on user role and status. Users — Determines user role to tailor dashboard view. |
| editCompanyDetails | Allows users (e.g., Applicants) to update company-related information in an existing request. | Requests — Updates companyDetails fields for a specific requestId. Includes validation and status tracking for edited data. |
| archiveRequest | Moves completed or inactive requests to an archived state to declutter active dashboards. | Requests — Sets the archive flag to true to mark the request as archived while preserving its existing status for historical tracking and filtered retrieval. |
| editProfile | Enables users to modify their personal information such as full name, email, or password. | Users — Updates user profile fields. |
| auditRequest | Used by an Auditor to review and mark requests as “Audited.” | Requests — Updates the status to “Audited” and records auditor details (userId, timestamp, comments). |
| approveRequest | Allows Approvers to review and mark a request as “Approved.” | Requests — Updates the status to “Approved” and logs approver information. May trigger notification workflows. |
| createRequest | Initiates a new request submission by an Applicant. | Requests — Creates a new record containing companyDetails, userId, status, and timestamps. Users — Associates request with the creator’s user profile. |
Collections Overview
| Collection | Collection Overview | Contains / Description |
|---|---|---|
| PasswordResets | The Password Reset Collection is used to manage and validate password reset requests in the system. | Fields such as _id, code, email, userId, id, createdAt, expiresAt, and used — used to track temporary password reset codes, their status, and validity period. |
| Requests | Stores user-submitted requests (e.g., access, approvals, or application actions). | Fields like requestId, userId, status, companyDetails, and timestamps — representing workflow requests and their approval states. |
| Tokens | Handles session and authentication tokens for secure user access. | Contains token, userId, issuedAt, expiresAt — used to authenticate users and manage session expiration. |
| Users | Maintains registered user account information. | Includes fields such as userId, fullName, email, password, roles, and profile metadata. Roles define access and permissions in the system and may include: Admin, Applicant, Applicant & Approver, or Applicant & Auditor. |
Request and Response
| Action | Request Payload | Response Payload |
|---|---|---|
| signup | { "auth": {}, "clientId": "oD6i_WpIes8pBvWjNXy81", "fullName": "hediyeh", "email": "h@gmail.com", "password": "111111", "confirmPassword": "111111", "type": "signup", "_socketId": "kmN2iMG_VAMQ7WSFAEhJ", "topic": "uibuilder", "_msgid": "96c8e068f17bef90" } |
// Failure Response { "action": "register", "status": "failed", "message": "Email already exists. Please use a different email." } // Success Response { "action": "register", "status": "success", "message": "You have registered successfully!", "URL": "https://codenxa.leanea.com/hediyeh/signin" } |
| login | { "auth": {}, "clientId": "oD6i_WpIes8pBvWjNXy81", "email": "h@gmail.com", "password": "111111", "rememberMe": false, "type": "login", "_socketId": "70nLJLlIrgzsiFLpAEhQ", "topic": "uibuilder", "_msgid": "2e88832acfbcd402" } |
// Failure Response 1 { "action": "login", "status": "invalidCredentials", "message": "Email not found." } // Failure Response 2 { "action": "login", "status": "invalidCredentials", "message": "Password does not match." } // Success Response { "action": "login", "status": "success", "message": "Logged In Successfully" } |
| logOut | { "type": "logOut", "auth": {}, "userToken": "...", "clientId": "DucPqZtrHFQNgOnyiGV02", "_socketId": "0TlVsj-P27gZSW9TAEhb", "topic": "uibuilder", "_msgid": "9cfd70eb231eb96c" } |
// Success Response: Typically { "status": "success", "action": "logOut", "message": "Logged out successfully" } |
| sendResetCode | { auth: object, type: "sendResetCode", email: "david.kim@brightwave.co", code: "373600", _socketId: "WGHrhQQe1a8e0uh4AFZJ", topic: "TrustedCloud Password Reset Code – Action Required" } |
// Failure Response 1 { "action": "resetPassword", "status": "invalidCode", "message": "code not found" } // Failure Response 2 { "action": "resetPassword", "status": "expired", "message": "your code has been expired" } // Success Response { "action": "resetPassword", "status": "validCode", "message": "Code matched successfully" } |
| resetPassword | { "auth": {}, "type": "resetPassword", "email": "h@gmail.com", "_socketId": "TQQZkMEJW3yr8AXbAEhi", "topic": "uibuilder", "_msgid": "563ae2fa2bd25a81" } |
// Failure Responses // Invalid Email { "action": "sendResetCode", "status": "invalidEmail", "message": "Email address not found." } // Invalid User { "action": "setNewPassword", "status": "invalidUser", "message": "User not found." } // Success Responses { "action": "setNewPassword", "status": "success", "message": "Password updated successfully." } |
| resendResetPassword | { "auth": {}, "email": "h@gmail.com", "type": "resendResetPassword", "_socketId": "TQQZkMEJW3yr8AXbAEhi", "topic": "TrustedCloud Password Reset Code – Action Required", "_msgid": "a8539873adf09c69" } |
// Failure Response { "action": "resetPassword", "status": "invalidEmail", "message": "Email address not found." } // Success Response { "action": "resetPassword", "status": "validEmail", "message": "Reset code sent to your email" } |
| setNewPassword | { "auth": {}, "type": "setNewPassword", "email": "h@gmail.com", "password": "123456", "_socketId": "3hHNyKWUI-Khbn9cAEh0", "topic": "TrustedCloud Password Reset Code – Action Required", "_msgid": "4a86446e49c05025" } |
{ "action": "setNewPassword", "status": "success", "message": "Password updated successfully." } |
| archiveRequest | { "type": "archiveRequest", "auth": { "userToken": "..." }, "clientId": "DucPqZtrHFQNgOnyiGV02", "requestID": 13, "_socketId": "0KAO_QB8U2vpv5xDAElI", "topic": "uibuilder", "_msgid": "7c5fc73c0374d772" } |
{ "status": "success", "action": "archiveRequest", "message": "success" } |
| editCompanyDetails | { "type": "editCompanyDetails", "auth": { "userToken": "..." }, "clientId": "DucPqZtrHFQNgOnyiGV02", "companyDetails": {}, "_socketId": "0KAO_QB8U2vpv5xDAElI", "topic": "uibuilder", "_msgid": "318f5048ec2d" } |
{ "status": "success", "action": "editCompanyDetails", "message": "success" } |
| editProfile | { "type": "editProfile", "auth": { "userToken": "..." }, "clientId": "DucPqZtrHFQNgOnyiGV02", "profile": { ... }, "_socketId": "0KAO_QB8U2vpv5xDAElI", "topic": "uibuilder", "_msgid": "37a193fd9e74e" } |
{ "status": "success", "action": "editProfile", "message": "success" } |
| auditRequest | { "type": "auditRequest", "auth": { "userToken": "..." }, "clientId": "DucPqZtrHFQNgOnyiGV02", "userId": "68f830f9d6c4398ea5f5cbdf", "requestId": 18, "auditDecision": { "status": "Audited", "auditDate": "2025-10-28", "comment": "yes" }, "_socketId": "0KAO_QB8U2vpv5xDAElI", "topic": "uibuilder", "_msgid": "196c7d70d5cc4" } |
{ "status": "success", "action": "auditRequest", "message": "success" } |
| approveRequest | { "type": "approveRequest", "auth": { "userToken": "..." }, "clientId": "DucPqZtrHFQNgOnyiGV02", "userId": "68f83638d6c4398ea5f5cbe6", "requestId": 18, "approverDecision": {}, "_socketId": "fVUzLOHQeYT96ZrqAEla", "topic": "uibuilder", "_msgid": "b26bc97d28188" } |
{ "status": "success", "action": "approveRequest", "message": "success" } |
| createRequest(Applicant) | { "type": "createRequest", "auth": { "userToken": "..." }, "clientId": "DucPqZtrHFQNgOnyiGV02", "companyDetails": {}, "_socketId": "0KAO_QB8U2vpv5xDAElI", "topic": "uibuilder", "_msgid": "46c1c3b28576" } |
{ "status": "success", "action": "createRequest", "message": "Request created successfully." } |
| getDashboard(Applicant & Auditor) | { "type": "getDashboard", "auth": {}, "userToken": "...", "clientId": "DucPqZtrHFQNgOnyiGV02", "_socketId": "X6ZKjzzFvV-ibjhwAEiI", "_msgid": "8bd0ae08cdfe06a9" } |
{ "type": "getDashboard", "payload": { "applicantRequests": [/* ... */], "auditorRequests": [/* ... */] } } |
| getDashboard(Applicant & Approver) | { "type": "getDashboard", "auth": {}, "userToken": "...", "clientId": "DucPqZtrHFQNgOnyiGV02", "_socketId": "X6ZKjzzFvV-ibjhwAEiI", "_msgid": "8bd0ae08cdfe06a9" } |
{ "type": "getDashboard", "payload": { "applicantRequests": [], "approverRequests": [{},{},{},{}] } } |
| getDashboard(Admin) | { "type": "getDashboard", "auth": {}, "userToken": "...", "clientId": "DucPqZtrHFQNgOnyiGV02", "_socketId": "X6ZKjzzFvV-ibjhwAEiI", "_msgid": "8bd0ae08cdfe06a9" } |
{ "type": "getDashboard", "payload": { "requests": [{}], "profile": {}, "options": {} } } |
| getDashboard(Applicant) | { "type": "getDashboard", "auth": {}, "userToken": "...", "clientId": "DucPqZtrHFQNgOnyiGV02", "_socketId": "X6ZKjzzFvV-ibjhwAEiI", "_msgid": "8bd0ae08cdfe06a9" } |
{ "type": "getDashboard", "payload": { "applicantRequests": [{ "_id": "68ffe1e7d6c4398ea5f5cd08", "id": 18, "status": "Pending", ... }] } } |







Top comments (0)