Hello,
To build a robust exam timer in Mendix, you should shift away from using a static duration and instead treat the deadline as a piece of dynamic data stored on the server. The most reliable pattern involves creating an ExamInstance entity that records the exact moment a user clicks the Start Exam button. At that point, a microflow should calculate and store an EndTime attribute by adding the exam duration to the current server time. This ensures that the countdown is tied to a specific timestamp in the database rather than a volatile value in the browser's memory, which would otherwise reset if the user refreshes the page or experiences a network hiccup.
For the user interface, you can use a specialized Marketplace widget designed for countdowns that accepts a Target Date attribute. If you prefer a custom approach, you can implement a Nanoflow that runs on a loop or uses a JavaScript action to update a non-persistent display string every second. This Nanoflow calculates the difference between the stored EndTime and the current time to provide the ticking clock effect. It is also a best practice to configure an "on-load" microflow for the exam page so that if a student navigates away and returns, the system can instantly resume the countdown based on the previously saved timestamp.
Data integrity is the most critical factor, so you must never trust the client-side timer to be the final word on when an exam ends. Since users can technically manipulate JavaScript or pause a browser-based timer, your "Submit" microflow must perform a server-side check. When the user submits their answers, the server should verify the current time against the stored EndTime, allowing for a few seconds of grace to account for network latency. If the time has expired, the microflow should automatically flag the submission as late or close the exam instance regardless of what the user sees on their screen.
Finally, you should handle timezones and synchronization by performing all core calculations in UTC on the server side. This prevents issues where a user might attempt to gain extra time by manually changing their computer's system clock. By combining a server-side "source of truth" with a reactive client-side display, you create a seamless experience that remains fair and accurate even under suboptimal conditions like browser crashes or intentional tampering.
Hope this helps!
The key point in the domain model is to avoid storing a “remaining time” value. Instead, store the fixed moment when the exam must end. The Exam entity should only contain the duration (for example, in minutes), while the ExamAttemptentity should store StartTime and EndTime as DateTime attributes, along with a flag such as IsSubmitted. This ensures the timer cannot be reset by refreshing the page or reopening the app.
When the user clicks Start Exam, a microflow should be triggered. In this microflow, first check whether an ExamAttempt already exists for the current user and exam to prevent resetting the timer. If no active attempt exists, set StartTime to [%CurrentDateTime%] and calculate EndTime using addMinutes([%CurrentDateTime%], $Exam/DurationMinutes). After that, navigate the user to the exam page.
For rendering the countdown on the UI, the timer should update every second without a page refresh. A common solution is to use a Marketplace Timer widget configured to run every 1000 ms and trigger a nanoflow. The nanoflow retrieves the current date and time, calculates the difference between EndTime and the current time, formats it into a display value (such as MM:SS), and stores it in a non-persistable entity that is shown on the page. If the remaining time reaches zero or below, the nanoflow calls the submit or lock exam microflow automatically.
Finally, server-side enforcement is essential. The client-side countdown is only for user experience and must not be trusted for validation. In the Submit Exam microflow (and ideally also in any microflow that saves answers), always check whether [%CurrentDateTime%] is greater than the attempt’s EndTime (optionally allowing a small grace period for network latency). If the time is exceeded, reject or flag the submission; otherwise, mark the attempt as submitted.
In summary, using a StartTime / EndTime DateTime model, a one-second client-side timer for display, and strict server-side validation is the most reliable and accepted pattern for implementing exam timers in Mendix.