DEV Community

hediyeh kianmehr
hediyeh kianmehr

Posted on • Edited on

TrustedCloud User & Dashboard Guide

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, Rejected

  • Can access the list of all approved requests that exist in the Service List

2. Approver Dashboard

  • Can view requests in: Audited, Approved

  • Can 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 1Authentication Interface:
handles user authentication flows — including Sign In, Sign Up, and Password Reset.

UIBuilder 2Dashboard 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();
Enter fullscreen mode Exit fullscreen mode

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"),
    },
  });
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
        }
    });
}
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode
  • 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"
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
        }
    });
}
Enter fullscreen mode Exit fullscreen mode

Sample Request Payload:

{
  "auth": {},
  "clientId": "oD6i_WpIes8pBvWjNXy81",
  "email": "h@gmail.com",
  "password": "111111",
  "rememberMe": false,
  "type": "login",
  "_socketId": "70nLJLlIrgzsiFLpAEhQ",
  "topic": "uibuilder",
  "_msgid": "2e88832acfbcd402"
}
Enter fullscreen mode Exit fullscreen mode

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 email is provided.
  • Queries the Users collection 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 profile object including userId, id, email, roles, and fullName.
  • Sends response to frontend and inserts token into Tokens collection.
  • If the email or password is 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"
}

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
  });
}
Enter fullscreen mode Exit fullscreen mode

Sample Request Payload:

{
  "auth": {
    "email": "user@example.com",
    "type": "resetPassword"
  },
  "_socketId": "TtK9mNkl_2Fh8Wx2K3DdW"
}

Enter fullscreen mode Exit fullscreen mode

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 auth object and email field exist.
  • Attaches socketId and 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 Users collection 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 ResetCodes collection with:
    • userId
    • email
    • createdAt
    • expiresAt
    • used: 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
}
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
  • verificationDigits.join('') ensures the code is concatenated properly.
  • auth payload structure matches your sample request payload.

resendCode method

   resendCode() {


            this.verificationDigits = ['', '', '', '', '', ''];
            this.startTimer();

            uibuilder.send({
                auth:{
                    email: this.resetEmail,
                    type: "resendResetPassword",
                }
            })
        },
Enter fullscreen mode Exit fullscreen mode

Sample Request Payload

{
  "auth": {},
  "type": "sendResetCode",
  "code": "373600",
  "email": "h@gmail.com",
  "_socketId": "TQQZkMEJW3yr8AXbAEhi",
  "topic": "uibuilder",
  "_msgid": "563ae2fa2bd25a81"
}
Enter fullscreen mode Exit fullscreen mode

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.

Update used flag if valid

  • Nodes: Compare Code & Update Used Flag + Update Used Flag.

Send response back to frontend

  • Nodes: Prepare Success Response and 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
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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();
}

Enter fullscreen mode Exit fullscreen mode
  • Validates that both new password and confirmation are entered and match.
  • Sends the setNewPassword action along with the email and new password to the backend via uibuilder.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"
}
Enter fullscreen mode Exit fullscreen mode

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 auth object and email.
    • Adds socketId and preserves the original payload for tracking.
  • Check User Existence (Check User by Email + Find User Record)


    Queries the Users collection 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 invalidEmail response.
  • Password Update (Update User Password Function + 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 success response.
    • If the user is invalid or not found: sends invalidUser response.
  • 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"
}
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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"),
    },
  });
}

Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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')
        }
    });
Enter fullscreen mode Exit fullscreen mode
  • uibuilder.start() starts the communication channel with Node-RED via WebSocket.
  • It sets isLoading = true to 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"
}

Enter fullscreen mode Exit fullscreen mode

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 roles array in the user object.
    • Maps combinations to one of four categories:
    • Applicant
    • ApplicantandAuditor
    • ApplicantandApprover
    • Admin
  • Output: Sets msg.payload to role type and attaches full user info in msg.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 Requests collection where createdBy.id = userId.

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.
  • Output: msg.payload ready to send to UI via uibuilder.

Sending Data to Front-End

  • Link/Debug Nodes:
    • Link Out node passes data to the front-end flow.
    • Debug nodes 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"
        }
      }
    ]
  }
}

Enter fullscreen mode Exit fullscreen mode

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"
}

Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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')
        }
    });
Enter fullscreen mode Exit fullscreen mode
  • uibuilder.start() starts the communication channel with Node-RED via WebSocket.
  • It sets isLoading = true to 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"
}

Enter fullscreen mode Exit fullscreen mode

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 */
    ]
  }
}

Enter fullscreen mode Exit fullscreen mode

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"
}

Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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')
        }
    });
Enter fullscreen mode Exit fullscreen mode
  • uibuilder.start() starts the communication channel with Node-RED via WebSocket.
  • It sets isLoading = true to 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"
}

Enter fullscreen mode Exit fullscreen mode

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"": [
    {},
    {},
    {},
    {}
  ]
}
Enter fullscreen mode Exit fullscreen mode

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"
}

Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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')
        }
    });
Enter fullscreen mode Exit fullscreen mode
  • uibuilder.start() starts the communication channel with Node-RED via WebSocket.
  • It sets isLoading = true to 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"
}

Enter fullscreen mode Exit fullscreen mode

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""
}
"
Enter fullscreen mode Exit fullscreen mode

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"
}

Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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);

        },
Enter fullscreen mode Exit fullscreen mode

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 waitingForResponse flag 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);
Enter fullscreen mode Exit fullscreen mode

Sample Request Payload

{
  ""type"": ""editCompanyDetails"",
  ""auth"": {
    ""userToken"": ""eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IiJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwidXNlclRva2VuIjoiU09NRV9SQU5ET01fVE9LRU5fMTc2MTYxNjk5NjI1NSIsInByb2ZpbGUiOnsidXNlcklkIjoiNjhmODMwZjlkNmM0Mzk4ZWE1ZjVjYmRmIiwiaWQiOjEsImVtYWlsIjoiZGF2aWQua2ltQGJyaWdodHdhdmUuY28iLCJyb2xlcyI6WyJBcHBsaWNhbnQiLCJBdWRpdG9yIl0sImZ1bGxOYW1lIjoiRGF2aWQgS2ltIn0sImFjdGlvbiI6ImxvZ2luIiwiaWF0IjoxNzYxNjE2OTk2LCJleHAiOjE3NjE2MjA1OTZ9.I0hARpxoFQPfZjfn5ZqjV-sRJO6SKpAw7KZBR4mH6iI""
  },
  ""clientId"": ""DucPqZtrHFQNgOnyiGV02"",
  ""companyDetails"": {},
  ""_socketId"": ""0KAO_QB8U2vpv5xDAElI"",
  ""topic"": ""uibuilder"",
  ""_msgid"": ""318f5048ec2d""
}


Enter fullscreen mode Exit fullscreen mode

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 id is numeric and valid.
  • Removes empty or undefined fields from companyDetails to prevent overwriting existing data with null values.
  • Sets operation parameters for MongoDB (collection, operation, and payload).

Example Payload:

{
  "collection": "Requests",
  "operation": "updateOne",
  "payload": [
    { "id": 123 },
    { "$set": { "companyDetails": { "name": "New Corp" } } },
    { "upsert": false }
  ]
}

Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

Response Examples (uibuilder.onChange)

// Success Response
{
    "status": "success",
    "action": "editCompanyDetails",
    "message": "success"
}


Enter fullscreen mode Exit fullscreen mode

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"
}

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

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

              })


          },

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • 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
})
Enter fullscreen mode Exit fullscreen mode
  • 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""
}


Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • 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"] } } }
Enter fullscreen mode Exit fullscreen mode

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 upsert disabled (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"
}
Enter fullscreen mode Exit fullscreen mode

This response replaces msg.response, preparing it for output or further handling.

Response Examples (uibuilder.onChange)

// Success Response
{
    "status": "success",
    "action": "archiveRequest",
    "message": "success"
}

Enter fullscreen mode Exit fullscreen mode

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"
}

Enter fullscreen mode Exit fullscreen mode

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)      │
 └────────────────────────────┘


Enter fullscreen mode Exit fullscreen mode

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;


          },

Enter fullscreen mode Exit fullscreen mode

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')
}

Enter fullscreen mode Exit fullscreen mode

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.profile

  • The 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');
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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""
}
"

Enter fullscreen mode Exit fullscreen mode

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 EditProfile function node.
  • It checks whether msg._editProfile exists.

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 email from the profileDetails object (to be updated independently).

  • Converts the userId string into a valid mongodb.ObjectId.

  • If the ObjectId is invalid, the flow logs an error and stops.

  • Constructs an updateOne operation with $set:

{
  "profile": "<profileDetails>",
  "email": "<email>",
  "updatedAt": "<current timestamp>"
}
Enter fullscreen mode Exit fullscreen mode

Stores the query as:

msg.collection = "Users";
msg.operation = "updateOne";
msg.payload = [ { _id: ObjectId }, { $set: {...} }, { upsert: false } ];
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode
  • 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"
}

Enter fullscreen mode Exit fullscreen mode

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"
}

Enter fullscreen mode Exit fullscreen mode

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)    │
 └─────────────────────────────────────┘

Enter fullscreen mode Exit fullscreen mode

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);
            },

Enter fullscreen mode Exit fullscreen mode

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.
  • Formats:
    • Status
    • Sets auditDate
    • Extracts auditorComment

Send to Backend

  • Uses uibuilder.send() with the following parameters:
    • authentication
    • userId
    • requestId
    • auditDecision payload

Optimistic UI Update

  • Instantly updates the following lists for a responsive UI:
    • applicantRequests
    • auditorRequests
    • adminRequests

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""
}
"
Enter fullscreen mode Exit fullscreen mode

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 _auditRequest in 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 updateOne command

Execute Database Update

  • The Update Request Record node (mongodb4) connects to the hediyehTC MongoDB database.
  • It applies the update operation defined in the previous node to the Requests collection.
  • 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"
}
Enter fullscreen mode Exit fullscreen mode
  • This response is stored in msg.response for consistent backend–frontend communication.

Response Examples (uibuilder.onChange)

// Success Response
   {
    "status": "success",
    "action": "auditRequest",
    "message": "success"
    }

Enter fullscreen mode Exit fullscreen mode

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"
}

Enter fullscreen mode Exit fullscreen mode

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)    │
 └─────────────────────────────────────┘


Enter fullscreen mode Exit fullscreen mode

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
                  });
                }
              });
Enter fullscreen mode Exit fullscreen mode

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 = true indicates 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""
}
"
Enter fullscreen mode Exit fullscreen mode

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.userId or msg.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 updateOne operation 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"
}
Enter fullscreen mode Exit fullscreen mode

This allows the frontend to handle success consistently for UI feedback.

Response Examples (uibuilder.onChange)

// Success Response
 {
    "status": "success",
    "action": "approveRequest",
    "message": "success"
}

Enter fullscreen mode Exit fullscreen mode

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"
}

Enter fullscreen mode Exit fullscreen mode

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 │
 └─────────────────────────────────────┘



Enter fullscreen mode Exit fullscreen mode

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);

        },
Enter fullscreen mode Exit fullscreen mode

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 = true indicates the frontend is waiting for backend confirmation.

Error Handling / Timeout

  1. Sets a 6-second timeout.
  2. If no response:
    • Displays a network error notification.
    • Resets waitingForResponse and submissionSuccess.
    • 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"
}

Enter fullscreen mode Exit fullscreen mode

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:

  1. Calculates newId based on the last request ID.
  2. Extracts user information from msg.user.
  3. Extracts company details from msg.companyDetails or msg.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.response with a standard JSON structure:
{
  "status": "success",
  "action": "createRequest",
  "message": "success"
}
Enter fullscreen mode Exit fullscreen mode
  • 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."
}
Enter fullscreen mode Exit fullscreen mode

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"
}

Enter fullscreen mode Exit fullscreen mode

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)