Import Page Simplification and UI Refinements

Monday, June 16, 2025 –  Last week, I returned to the Next.js project. My first task was to create a new page for the Import Entity feature. Fortunately, the process was simple and straightforward, I only needed to add logic to retrieve files and send them directly to the API. I didn’t have to handle any filtering or validation, as all the data processing was managed on the backend. The implementation was notably clean and efficient, thanks to Mr. Peter’s foresight in designing a simplified UI experience.

Later on, I was also assigned to make a few minor updates to existing features from the backend and reflect those changes on the UI side.

Integrating Entity and Enhancing API Query Logic

Monday, June 9, 2025 –  Previously, I was working on updating a new small entity, which I’ll refer to as Entity D in this writing. The goal was to integrate this entity into the update command of an existing item entity. After some trial and error, the implementation was finally successful when I discovered that certain renamed fields needed to remain consistent in order to map correctly.

Following that, I moved on to the next task, which involved updating the API list query for the item entity. This new task included incorporating Entity D that I had previously added. Additionally, I was required to extend the query by introducing several conditional booleans. What set this API apart from the previous ones was that it combined data from both MongoDB and MySQL, with only minimal logic changes needed for the integration.

Adding New Properties to an Existing MongoDB Entity

Tuesday, June 3, 2025 –  Last week, I was assigned a new backend-related task. The objective was to enhance an existing API by adding a few new properties to one of the current entities.

I started by updating the existing database diagram using Visio to reflect the new properties. Since the system uses MongoDB, there was no need to handle database migrations, MongoDB’s schema-less nature made the update process more straightforward.

After confirming the updated design with Mr. Peter, I proceeded to add the new properties directly into the existing entity class. These properties didn’t require any new relationships, so I was able to jump straight into modifying the update command. Note that the create command didn’t need any changes, as the new fields weren’t involved in initial data creation.

Once the update command logic was in place, I wrote a new unit test to ensure the changes worked as expected. After verifying that the backend logic was functional, I moved on to the UI. The UI changes were relatively simple, involving just an additional checkbox. I created the wrapper component and mapped the new property accordingly.

However, during testing, the update functionality didn’t behave as expected. Although everything seemed correctly configured, the data wasn’t updating. This led me to re-run the unit tests. One of them failed, while another passed but revealed that a property expected to be non-nullable was receiving zero or empty data instead.

After some debugging and with help from Mr. Peter, we discovered the issue: a DTO (Data Transfer Object) required the same property name as the corresponding entity to ensure correct mapping. Once this was corrected, everything functioned as expected. With the update logic complete, I’ll now move on to the Get List API Query, which I plan to work on next week.

Challenges in Securing Backend API Exposure

Monday, May 26, 2025 – Continuing from last week’s progress, I was assigned a new task: to hide the actual backend API URL from the client. Previously, the client exposed the API URL whenever a user made a request. Although our backend was already secured with proper authentication and authorization mechanisms, we wanted to add an additional layer of protection to prevent outsiders from even knowing the real API URL.

Initially, my first approach was to call the API from the server side, aiming to mask the actual URL. However, I quickly ran into a challenge, this approach would require rewriting each API call manually. Considering that there are potentially hundreds of endpoints, this method was not practical or scalable.

Eventually, I came across a more efficient solution: implementing a reverse proxy using Nginx. The idea behind a reverse proxy is that all client requests are routed through the Next.js server, which in turn forwards them to the backend API. This setup effectively hides the real backend URL, as the client only sees the requests going to the Next.js frontend. In addition, it allows for better control over request handling, logging, and access restrictions.

However, during a code review session with Mr. Peter, we discovered a flaw in my implementation. While the reverse proxy did manage to change the port and redirect the requests, it didn’t completely fulfill the goal. The real backend endpoint was still accessible, meaning it wasn’t truly hidden from external users. Our actual objective was to ensure that the backend communicates only with the Next.js frontend, preventing any direct access from outsiders. Unfortunately, my current setup didn’t enforce that restriction.

Fixing Token Expiry Access in Next.js Layout

Monday, May 19, 2025 – Last week’s issue was related to authentication. Previously, I had already implemented an authentication layout to prevent outsiders or logged-out users from accessing UI pages. Although the backend was already secure, blocking unauthorized data access, we still didn’t want unauthenticated users to even see the UI. That’s why the layout-based authentication was put in place.
However, I noticed a new problem: when a user’s token expired, they could still access the

UI pages. The backend continued to block the data, but the frontend still rendered the components, which wasn’t ideal. So, I decided to add another layer of protection by checking whether the token had expired and redirecting the user to the login page if it had.
On my first attempt, I tried adding the logic directly in the layout file, but I immediately ran into an error “window or localStorage is not defined”. This happens because Next.js layout files run on the server by default, and these browser-specific objects don’t exist in that context.

After looking into it further, I created a custom hook to handle the token expiration logic and tried calling it from the layout. That also didn’t work, since React hooks can only be used inside client components, and layouts are server components by default.
To get around this, I created a new client-only component specifically for token validation. I then placed this component inside the layout, which made the logic work correctly. Thanks to Mr. Peter’s tip on how to simulate an expired token, I was able to test the flow and confirm it behaved as expected.

This also required me to store another value in localStorage, “sessionExpiry” in addition to the existing “isLoggingOut”. With both of these in place, I could now reliably determine whether a user should still have access. The session is considered expired if either there’s no token or if the current time has passed the session expiry timestamp. Now, the UI is finally in sync with the authentication state, users are redirected when they’re no longer supposed to be there.

Improving Error Handling

Monday, May 12, 2025 – Last week, while reviewing the overall project, I came across a minor but important bug related to how error messages were being handled across the application. The issue stemmed from an earlier implementation by a previous intern, where the error handling was too generic. In particular, the logic often defaulted to a fallback else condition, which resulted in inaccurate or misleading error messages being shown to users. This became especially problematic in situations where the error was caused by something specific, like a validation issue or a network failure, but the application simply displayed a vague message like “Unexpected error occured.”

To fix this, I refactored the code and improved the error-handling mechanism to deliver clearer and more accurate feedback. I began by updating the try-catch block that handles API calls. First, I checked if the error was an instance of AxiosError. If the error didn’t contain a response (which typically indicates a network issue), I displayed a message stating “Network error.” This ensures that users understand when the issue is with their internet connection rather than with the application itself.

Next, I refactored a helper function responsible for interpreting and extracting meaningful messages from different error formats returned by the API. This function supports multiple known error structures, such as general error messages, validation errors with multiple fields, and fallback cases where the message is returned as plain text or JSON. This is a significant improvement over the previous implementation, which would have shown a single, generic message regardless of the actual issue.

In summary, this small but important update ensures that users are better informed about what went wrong when an error occurs. It enhances the clarity and reliability of our application’s error reporting and contributes to a better overall user experience.

Preserving Pagination State with URL Syncing

Monday, May 5, 2025 – Last week, I worked on a task where users view a paginated list of data, and when they click into a detail page and return, they should land back on the same page they left. However, the page would always reset to page 1, which was frustrating and not user-friendly. Initially, I was confused because I couldn’t find any logic in the code that explicitly reset the page to 1. Since the project had many layers of logic, Mr. Peter advised me to comment out everything and test step by step to identify the root cause. Following his advice, I eventually discovered that a custom pagination hook was resetting the page to 1 each time. After removing the part of the hook responsible for this, the issue was resolved, the page no longer jumped back to the first one when returning from a detailed view.

Once that was fixed, the next goal was to make pagination even more seamless by syncing the page state with the URL. I created a custom hook that reads the page number from the URL and updates it dynamically as users navigate. This means users can now move between pages, use the browser’s back/forward buttons, and even share links with the exact page state preserved. The hook keeps the UI state and URL in sync, making navigation more intuitive and consistent. This improvement made the pagination feel much more natural and user-friendly, especially when dealing with long lists of data or when users need to return to the same context after viewing details.

Securing Routes and Role-Based Access in Next.js

Monday, April 28 2025 – Last week, I continued working on restricting unauthorized users from directly accessing UI pages, such as when they try to search for a page URL manually. To guide me, I referred to a blog titled “Authorization in Next.js” by Robin Wieruch, published on March 25, 2025. The blog explored several methods for implementing authorization, and I decided to focus on securing routing.

One key takeaway from the blog was the importance of a defense mechanism in place for routing. Without it, unauthorized users might still manage to navigate to the page (which is a security risk). However, if the necessary authorization checks are implemented within the API, Service, and Data Access Layers, unauthorized users won’t be able to read or modify any data. Still, adding this layer of protection not only enhances security but also improves the user experience, which is why it’s highly recommended.

To implement this in my project, I placed all related files into an “authorized” folder and created a layout file that included the necessary security check. The layout file essentially checks whether the user has access; if they don’t, they’re automatically redirected to the login page.

Once that was in place, I focused on implementing role-based authorization, with admin users. I customized the navigation bar to ensure that features specific to certain roles only appear for users with the correct role. To do this, I added a “role” property to the page configuration so that only users with the “Admin” role could see certain features in the navbar.

Finally, I worked on page-level authorization for each individual page. For each one, I added a check to determine the user’s role. If the user is an admin, they can access the page’s data; otherwise, they will be shown an “Unauthorized” page. This added layer of security ensures that only authorized users can access specific content.

Improving UI Usability and Securing Access

Monday, April 21 2025 –Last week, Mr. Peter asked me to redesign part of a page layout to improve readability and make it easier to extract information. The page contained multiple tables and lots of data, so clarity was key. Since the existing layout was developed by the previous person in charge, I first took time to understand the underlying code to ensure a smoother redesign process.

After familiarizing myself with the structure, I experimented with various styles and layout arrangements through trial and error. My goal was to achieve a cleaner, more user-friendly interface and in the end, I landed on a final version that I believe significantly improved the overall look and feel.

In addition to the redesign, I continued testing other features as thoroughly as possible. During this process, I discovered a small but important bug: when creating a new data entry, the recorded time (not the date) was incorrect. Once the underlying issue in the API was fixed, I proceeded to implement the necessary changes, and the bug was successfully resolved.

Toward the end of the week, I began tackling another concern, restricting unauthorized users from accessing the UI page directly. Although they couldn’t access any data, having the UI visible still posed a security concern. After some research, I found an article suggesting several methods to handle this. One approach seemed practical and aligned with our needs, so I discussed it with Mr. Peter. He agreed to let me try it out.

Before making the changes, I cleaned up the code and committed all current updates to avoid mixing them with the upcoming major changes. Although I attempted to implement the new method by the end of the week, it didn’t fully work. I shall continue this task this week.

Testing Phase : Bug hunting and Feature Validation

Monday, April 14 2025 – Last week, since the development of our features had been completed, it was time to thoroughly test the application.

Initially, I focused on testing the newly developed feature that I had worked on. After that, I started diving into other features developed by the previous intern. I also took the initiative to understand how the code worked so I could handle any bugs that might be discovered later. I consulted Mr. Peter for clarification on how certain buttons and modes were supposed to function.

A few bugs were identified, mostly minor, but still important to resolve.

Since there were numerous updates happening on both the frontend and backend, including major logic changes to enable syncing between the new and previous systems, I tried testing as many scenarios as I could and reported bugs as soon as I found them.

By the end of the week, we had discovered and resolved a number of bugs, especially in the critical features. However, there are still some features I need to continue testing, which I unfortunately didn’t manage to cover last week.