CareSync

A full-stack web app allowing small, self-managed teams of personal carers and support workers to easily roster shifts and create and edit shift notes, incident reports, and handover.

Front-End Developer
Node React HTML SCSS JavaScript JSX Git GitHub MUI FullCalendar Railway

Project Brief

Purpose

Support workers often make use of typed or handwritten notes along with more generalised calendar and chat software to coordinate their work, and can lack software that is specifically designed to cater to their needs on the job.

CareSync is designed to streamline scheduling, record-keeping, and handover for shift workers in the personal care/support space, allowing care coordinators and workers to easily keep shift schedules and documentation in sync.

Requirements

The brief for this project was to build a full-stack application using the “MERN” stack, consisting of a MongoDB document database, a backend API server running the Express web framework, and a frontend user interface (UI) built using the React JavaScript library, both running on the Node JavaScript runtime.

The key technical project requirements were a well-designed codebase with clear separation of concerns between program modules, a demonstration of “Don’t Repeat Yourself” (DRY) coding, well-judged use of third-party libraries, good code flow control, and the application of Object-Oriented Programming (OOP) principles using appropriate data structures.

The interface of the application needed to be responsive, providing a functional user experience at all screen sizes, from small mobile devices, to mid-sized tablets and large wide-screen desktop monitors.

Working in development teams of two, we were also required to demonstrate teamwork and the adoption of a recognised project management methodology to delegate tasks, design, build, and deliver the project, within a five week timeframe (two weeks for planning and three weeks for development).

We used Trello to list and track work items on a kanban board, categorising tasks using labels such as "frontend", "backend", "documenation", and "user story", and moving them through a workflow of "To Do", "In Progress", "Testing", and "Done" to ensure delivery of the project by the deadline.

Technologies

After a collaborative planning process, my role was to take on the front-end development of the app, building the user interface and integrating it with the API being developed by my project partner.

In addition to building the app front-end in React, I made use of:

  • The React Router library for client-side routing
  • The Material UI (MUI) component library to build the user interface (UI) components, such as menus, buttons, lists, forms, tabs, and dialogs
  • Sass (SCSS syntax) to further customise the UI component styling
  • The FullCalendar library to build the interactive calendar grid
  • Git and GitHub to manage version control and merge in new features
  • Railway for deployment of the database, backend server, and frontend server

Planning & Design

Data Flow

When designing the data flow of the app, we took the client being cared for as the central entity that everything else is connected to. Within the object database, the key collections are users, clients, and shifts, with most data stored in a shift object, and a client and carer ID associated with each shift.

The calendar of the selected client then acts as the primary view/workspace, from which a user can access functions to create and edit shifts, view historical shifts, manage a client's care team, and drill down into a shift's details and documentation, such as notes and incident reports.

The controller functions of the app's API endpoints have typically been written to receive an object ID corresponding to a user, client, or shift, in the URL parameters of the request.

This, along with authorisation and error-handling middleware, and JSON data in the request body, are used to appropriately check authentication and authorisation, create/read/update/delete the corresponding document in the database, and return a response.

Wireframing

The visual interface of the app revolves around the calendar as the central component, and I took a mobile-first approach to the design. The goal was to keep things clean, simple, and centrally accessible, allowing the user to complete a task without having to navigate through too many different views.

In planning, we identified two key groups of users—carers and coordinators—as well as a few different user personas that belonged to each, and some accompanying user stories. We then thought through design considerations that would apply to each group.

Carers may want to be able to quickly enter notes on their phone during a shift, while coordinators may organise the shift calendar and review shift notes and incident reports on a larger screen such as a tablet or desktop monitor.

These considerations informed the presence, placement and grouping of elements at different screen sizes, ensuring a responsive interface that enabled the user to perform their required tasks on a variety of devices.

User Flows

As part of the wireframing process, I designed wireframes for the key user flows that the app would require, such as logging in, selecting a client, and adding and editing shifts and documentation.

When a user logs in, they can:

  • Create care clients
  • Select a client and assign carers to their care team
  • View a client's calendar of historical and upcoming shifts
  • Add new shifts and edit pending shifts (if they are the client's coordinator)
  • Enter shift notes, incident reports, and handover for the shift (if they are the assigned carer for the shift)

Key components

Client Cards

The Client List view is displayed after login. Client cards are generated for each client that the logged-in user is the coordinator or carer for, and are populated with the client's name and details of their next next upcoming shift.

From this view, users can add clients, remove clients, and select a client to navigate to their shift calendar.

The Calendar

The core functionality of the app centres on the Calendar view and calendar day grid component, which makes viewing, creating, and editing shifts and their associated documentation centrally accessible once the user selects a client.

From here, the user can see all shifts for a client during the selected month, including the date/time range and the assigned carer. The calendar can also be toggled between a grid and a list view, which can provide a better user experience at smaller screen sizes.

Shift Cards

Shift cards display a summary of shift information that's designed to give the most helpful details about the shift at a glance. The next upcoming shift and recent previous shifts can be accessed via quick-access cards beside or below the calendar, depending on the screen size.

Shift cards link to the shift details panel, accessible by selecting the entire card or one of its document icon buttons. This allows users to quickly navigate to the shift overview, or directly to its shift notes, incident reports, or handover.

The shift icon buttons are responsively displayed below or beside the rest of the card, depending on the size of the screen. If the type of note the icon represents is present, it is displayed in colour rather than greyed out.

Dynamic Modal & Drawer

The modal component is used to display informational dialog boxes and confirmations shown before taking destructive actions like deleting documents from the database.

I built the modal and confirmations to be as flexible as possible, taking data such as their title, body text, alert messages, and action buttons, as well as onClose and callbackhandlers and child components, as props.

This made the components highly versatile and re-usable in many different contexts, reducing the amount of boilerplate code used to display dialogs and confirmations throughout the app.

The Shifts Details Drawer component is a modal drawer that opens on the right-hand side of the viewport (or full-screen, on mobile) when the user selects a shift. Here, users can view shift details; make edits to its start and end time, carer, and coordinator notes; and view and add shift documentation.

I used React Router's browserRouter and Outlet components, as well as conditional rendering, to display the sub-sections of the Shift Details Drawer depending on the URL, the properties of the selected shift, and the application state. The drawer displays an overview of the shift, and users can drill down into views of specific shift details and notes by selecting cards in the overview.

Learning & Challenges

State and Session Management

The app makes use of React's context API to store key state data for the logged-in user, making it globally accessible and avoiding excessive prop drilling where data needs to be passed to deeply-nested components.

In the first iteration of the app, we used localStorage to persist the application state between page loads, but this was a rather insecure solution, especially with the state containing potentially sensitive information such as internal resource IDs, user data, and client shift data.

I later reworked the app's session and state management to be handled server-side using the express-session and connect-mongodb-session libraries on the backend, and the Web Crypto API on the frontend, to encrypt session data before sending it to the backend server, associating it with the user, and inserting it into the database.

When the user performs an action that modifies the global state store, the store object is encrypted and uploaded to the server. If the user reloads the page, or closes and reopens the window, and their authentication and session cookies are still present in the browser, the previously stored session is fetched and loaded, allowing the previous application state to be restored.

Time-Based Conditional Logic

Creating, viewing, and editing shifts depends on the current user’s relationship to the client (coordinator/carer), as well as the current time relative to the shift's date and time. This required the etablishment of some business rules, based on the processes and conventions used to coordinate and document shifts, and the corresponding logic.

To add a shift, the user must be a coordinator for the client. To add shift notes and incident reports, the user must be the assigned carer for the shift and the shift must be “in progress” (that is, the current time is after the shift start time and before the shift end time), OR within an eight-hour edit window after the shift. If there is a subsequent shift for the same client, notes must be added within the first two hours of that shift.

These kinds of considerations demanded careful thought when building the UI, displaying placeholder messages and help text, and determining the conditions under which a given user could view and/or edit certain pieces of information.

For example, the Shift Notes area in the Shift Details component will alternatively display existing shift notes, “You’ll be able to add shift notes here once the shift starts”, or “Enter your shift notes” (and a submission form), depending on whether the shift is in the past, in the future, or currently active.

API Resource Representation

Another challenge I encountered was inconsistency with API response values, with variable fields of the same resource being returned by different routes, and actual data requirements not always matching the initial API design.

In some cases, the data initially returned ended up being insufficient for the action being taken, or the result that needed to be displayed on the front-end, requiring additional API calls for more data from the resource.

For example, fetching the selected client returned the ObjectId, but not the name of, the coordinator, so in contexts where the name of the coordinator needed to be displayed immediately upon fetching the client, this required another database query.

In some instances, these issues could be resolved by modifying the controller function's return values as needed, or simply double-checking the code to see which parts of a resource would, or would not, be returned by a given route.

As development progressed, it became clear that having good API documentation, establishing clear response formatting conventions during the design and early build phase, and returning entire (rather than partial) resources where the data was relatively small in size would have made for cleaner, less brittle code and a better developer experience when working with the API.

Deployment

A key project requirement was the deployment of the app to a live hosting service, and we opted for Railway for its simplicity and ease of use. This gave me exposure to the basics of a setting up an automated deployment pipeline.

The app consists of three separate services: a MongoDB database, a backend server running the Express API, and a frontend server for the React UI.

Deployments on GitHub trigger automatic rebuilds and redeployments of the relevant services, and a custom start command in the frontend deployment settings ensures that the app starts in production mode, bypassing startup of the React development server.

Environment variables supplied to each service securely provide information such as the URLs and credentials needed to communicate with other services like cloud file storage (Cloudinary) and email (Mailtrap), and the secrets, passphrases, and salts used to encrypt and decrypt session data and sign JSON Web Tokens (JWT).

Conclusion

As the capstone project for my Diploma of IT in Web Development, tackling this project gave insight into, and hands-on experience with, the many complexities of collaboratively building and deploying a full-stack application.

I gained experience in determining end-user requirements; designing an application architecture and data flow; web API and database design; methods of updating, storing, and retrieving application state; authenticating users and controlling access; and wireframing and building a responsive, user-friendly interface with the help of component libraries.

Explore other projects