PROJECT: NurseTraverse


Overview

NurseTraverse is a desktop application designed to help community nurses manage all the data they may need, including visit management, appointment scheduling, and importing and exporting of patient data. The user interacts with the app using a CLI (Command Line Interface) enhanced with an autocomplete functionality and ability to undo and redo commands. The app has a GUI created with JavaFX and is written in Java. NurseTraverse is built by me and 4 other students.

Summary of contributions

  • Major enhancement: added the function to export and import patient data.

    • What it does:

      • Exporting features: allows the user to export patient data into a comma separated values (CSV) file. Patient data can be exported all at once, or selectively by index.

      • Importing features: allows the user to import patient data from a CSV file. Imported patient data can either be used to replace all existing patient data or be merged with existing patient data.

    • Justification: This feature improves the functionality of the product by facilitating convenient data sharing. To add data for a few patients, there is no longer a need to use the add command multiple times, which can be a hassle. Example use cases:

      • A freshly trained nurse has been assigned her first set of patients. The patients' data can be passed to the nurse in the CSV format and imported in one go.

      • A (few) patient(s) has been transferred from the care of one nurse to another. The relevant patient data can be exported, passed to the other nurse, and imported.

      • An archive of patient data has to be kept for records purposes. The export feature allows for a "snapshot" of all patient data to be saved easily.

    • Highlights: This feature was implementation with Jackson’s dataformat.csv library. The library is full of functions but is not exactly well documented, and thus the implementation took significant research and experimentation. The final implementation with this library is such that the export and import functionality can easily be extended to include additional data fields in the future, using Jackson’s Annotation feature. Apart the CSV parsing aspect, coding the data interaction for reading and writing patients to the address book had its challenges as well, due to the potential (buggy) interactions with the data from other features.

    • Credits: Jackson Dataformat CSV, along with the existing Jackson annotations in AB3 used for JSON processing.

  • Code contributed: My contributed code can be found here. Use the filters to sort functional and test code as needed.

  • Other contributions:

    • Project management:

      • Opened milestones and user stories issues.

      • Managed milestones v1.0 and v1.1.

    • Documentation:

      • Created the product README

      • Sanitized irrelevant aspects of the User Guide and Developer Guide : #200

    • Community:

      • PRs reviewed (with non-trivial review comments) or approved: #66, #74, #75, #76, #95, #108, #109, and everything else here

      • Reported bugs (example: #103) and another severe bug reported offline fixed in #120

    • Tools:

      • Integrated coveralls to the project.

Contributions to the User Guide

Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users.

Importing and Exporting of Patient Data

Importing and Exporting of Patient Data

As a community nurse, you may be assigned new patients, or some of your patients may be assigned to other community nurses. To facilitate the transferring of patient information from one device to another, you can import and export the data of your patients. This section describes the features that will allow you to import and export patient information.

CSV Compatibility

You may encounter issues when trying to import a CSV file written by another machine with a different operating system. As of v1.4, CSV files written by Windows and Unix machines are not cross-compatible. This means that the app, running on Windows, can only import CSV files written by a Windows machine. The same goes for Unix systems.

This issue can be circumvented by using text file format converters to convert a Windows written CSV to a Unix one, and vice versa. The recommended converters are Dos2Unix and Unix2Dos, both available here.

Importing Patients from a CSV file: app-import-replace, app-import-merge

You can import patient data from a .csv file into the application using app-import-replace or app-import-merge.

  • Only the file format .csv is supported.

  • The application will look for the specified .csv file in the ./imports folder.

  • Both import commands are undoable.

CSV files used for importing must adhere to the following format requirements.

  • Provided file name should not be blank, and can contain only alphanumerics, hyphens and underscores.

  • The top row of the file must be exactly the following headers in the order:

    name, phone, email, address, tagged, visitTodos
  • Each row in the .csv corresponds to one patient.

  • There may not be duplicate patients in the .csv file.

  • The data in each cell must adhere to the format of the field it belongs in.

    • Cells under phone must contain 3 to 8 digit numbers, cells under name must contain only alphanumerics and spaces, etc.

    • For the fields tagged and visitTodos with multiple elements per cell, each element is to be separated with a newline.

  • The data row for any patient cannot have empty cells in the following fields:

    `name`, `phone`, `address`, `email`
  • The .csv file should adhere to the RFC 2048 standard.

Examples of valid CSV files can be seen here

Import and Replace: app-import-replace

Reads patient data from a specified .csv file.

".csv" will be auto-appended to the specified FILENAME, so there is no need to type in the file extension.

All existing patient data will be deleted and replaced with this new data.

All existing appointment data will be deleted.

  • Provided file should not be empty.

  • Cannot be executed when there is an ongoing visit.

Format: app-import-replace n/FILENAME

Examples:

  • app-import-replace n/my_assigned_patients

    • Patient data will be entirely replaced with new data from ./imports/my_assigned_patients.csv.

Import and Merge: app-import-merge

Patient data will be read from a specified .csv file and merged without affecting existing data.

".csv" will be auto-appended to the specified FILENAME, so there is no need to type in the file extension.

  • Provided file should not be empty.

  • The .csv file cannot contain a patient that already exists in the app.

  • Can be executed when there is an ongoing visit.

Format: app-import-merge n/FILENAME

Examples:

  • app-import-replace n/my_new_patients

    • Patient data from ./imports/my_new_patients.csv will be added into the app.

Exporting patients into a CSV file: app-export

You can export patient data from the application into a .csv file using app-export.

A new .csv file will be created and data will be written into it.

Indexes can be provided to selectively export data of specific persons.

".csv" will be auto-appended to the specified FILENAME, so there is no need to type in the file extension.

  • Only the file format .csv is supported.

  • Creates FILENAME.csv in the ./exports folder

  • The provided file name must not be already in use.

Format: app-export n/FILENAME [i/INDEX…​]

Examples:

  • app-export n/patients

    • All patient data will be exported to ./exports/patients.csv.

  • app-export n/alex i/1

    • The data of the patient at index 1 will be exported to ./exports/alex.csv.

  • app-export n/tomorrow i/2 i/4 i/6

    • The data of the patients at indexes 2, 4 and 6 will be exported to ./exports/tomorrow.csv.

  • As of version 1.4, the export feature does not support Visits and Appointments.

  • Patients' visit data will not be exported. This feature will be implemented in v2.0.

  • The provided file name cannot be blank, and can contain only alphanumerics, hyphens and underscores.

Exporting Appointments [coming in v2.0]

You can export your appointment data into a .csv file using app-export-appt. A new .csv file will be created and data will be written into it.

Format: app-export-appt n/FILENAME

Examples:

  • app-export-appt n/appointments

    • All appointment data will be exported to ./exports/appointments.csv.

Contributions to the Developer Guide

Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project.

Import and export functionality are split into three commands:

  1. app-export

  2. app-import-replace

  3. app-import-merge

Jackson Library

The current import and export features are built upon the the existing Jackson libraries, in particular the dataformat, databind and datatype modules. Technical knowledge of the Jackson library will be helpful for maintenance of feature, but is not necessary.

However, understanding Jackson 's annotations will be needed in order to extend export and import functionality to cover new data fields or classes implemented in the future. They are explained here.

Csv Processing

All of the data processing needed for this feature can be found in the CsvUtil file; it is responsible for converting the data of Patient objects into a .csv friendly String format and vice versa. The actual reading and writing of .csv files is then done with existing FileUtil functionality.

The conversion of Patient objects to and from .csv formatted Strings are handled by the CsvMapper and CsvSchema classes implemented in dataformat.

  • The CsvMapper is responsible for managing custom configurations for the conversions. For instance, it can toggle headers with withHeader() and skip unknown fields with the IGNORE_UNKNOWN feature, both of which are used in the feature implementation.

  • The CsvSchema object is created by a configured CsvMapper object and an Object.class, in this case, Patient.class. It dictates the scheme for how data in each column of the .csv corresponds with the fields in the Object class. This schema can then be used to instantiate a reader or a writer object.

The following functions are implemented:

  1. CsvUtil#writePatientsToCsv(List<Patient>, String) — Write a list of Patient objects into a .csv file to the path at the specified pathString.

  2. CstUtil#readPatientsFromCsv(String) — Read a .csv file at the specified path indicated by pathString and return a corresponding list of Patient objects.

  3. importsContainDupes(List<Patient>) — Check if the given list contains duplicate patients, i.e. the list is not unique.

Csv Processing Design Considerations

  • Alternative 1 (current choice): Use Jackson 's dataformat.csv library.

    • Pros: Well integrated with the existing Jackson JSON parsing libraries. Tons of functions for CSV parsing.

    • Cons: Does not support Excel formats. Comprehensive library, recently updated but not well-documented. Hard to understand.

  • Alternative 2: Use other libraries, like Apache Commons CSV.

    • Pros: More features like Excel format parsing. Well documented.

    • Cons: Does not integrate well with the existing Jackson libraries used.

  • Alternative 3: Build your own parser!

    • Pros: Lightweight, implement only what is needed. Can be white box tested.

    • Cons: Lots of developer work to reinvent the wheel. Likely to be buggy as there are tons of edge cases to consider, due to many special characters.

Command Implementation

Command: app-export

The app-export command works by retrieving a list of Patient objects from the Model and passing it to CsvUtil to process and write into a .csv file. If provided with indexes, the app-export feature can selectively export the Patient objects that correspond to the specified indexes. To facilitate the selective export functionality, the following methods were implemented in Model and PatientBook.

  • Model#GetPatientsByIndexes(Set<Indexes>) — Retrieves and returns a list of Patient objects corresponding to the provided indexes from the PatientBook , if the indexes are valid.

  • PatientBook#GetPatientByIndex(Index) — Returns the Patient object corresponding to the specified index, if the index is valid.

If indexes are not specified in the command arguments, a list of all currently existing Patient objects will be retrieved with Model#getStagedPatientList().

The app-export command MUST be provided with a desired file name for the .csv file. The .csv file will be written to /exports/[FILENAME].csv. Existing files will NOT be overridden and thus the provided file name cannot already exist in /exports.

The following diagrams show how an export command works:

ExportSequenceDiagram
Figure 1. Export Sequence Diagram
ExportSequenceDiagramRef
Figure 2. Reference: get patient list
ExportSequenceDiagramRef2
Figure 3. Reference: write patients to csv file
ExportCommand Design Considerations
Aspect: File Overriding
  • Alternative 1 (current choice): Disallow overriding, file name provided must be new

    • Pros: Existing .csv files will not be accidentally overridden. Prevents potential loss of data.

    • Cons: Additional hassle for the user to delete files that they want to replace.

  • Alternative 2: Allow overriding

    • Pros: Conveniently replace existing, unused files.

    • Cons: May accidentally override and lose important data.

Aspect: Illegal Characters in Data Fields
  • Alternative 1 (current choice): Allow forbidden characters

    • Pros: Certain fields may be more accurately represented, i.e. addresses.

    • Cons: The exported csv file may be bugged in edge cases, i.e. have data in the wrong columns. Exported fields with forbidden characters may not be properly handled and escaped all of the time. More developer work to test around edge cases.

  • Alternative 2: Disallow forbidden characters

    • Pros: Exported .csv files are guaranteed to be in the correct format.

    • Cons: Data fields are restricted and cannot have commas, semi-colons, etc.

Import

The import commands work by reading a .csv file and converting it into a list of Patient objects by using CsvUtil. The list is then passed to Model. What happens next depends on which variant of import is called.

For both variants of the command, the imported list of patients CANNOT have any duplicates. This is ensured with CsvUtil#importsContainDupes(List<Patient>).

Command: app-import-replace

The Model will replace all existing Patient data in the PatientBook with the data of the new list of Patient objects. To do this, the following was implemented:

  • Model#replaceStagedPatientBook(List<Patient>) — Creates a new PatientBook object containing the Patient objects in the provided list. The old PatientBook stored in the Model is then replaced with the new PatientBook by calling Model#setStagedPatientBook(PatientBook).

Command app-import-merge

The Model will add all Patient data in the new list of Patient objects into the PatientBook. To do this, the following was implemented:

  • Model#hasAnyPatientInGivenList(List<Patient>) — Checks if the model contains any Patient in the given list of Patient objects.

  • Model#addPatients(List<Patient>) — Adds all Patient objects in the given list into the Model.

If the operation will result in duplicate Patient objects in the PatientBook, it will not be executed. This is checked by the function stated above, Model#hasAnyPatientInGivenList(List<Patient>).

Import Design Considerations
Aspect: Allowing Patient Overriding for app-import-merge
  • Alternative 1 (current choice): Disallow overriding.

    • Pros: Existing Patient data will not be accidentally overridden. No need to deal with potential merge conflicts.

    • Cons: User may have intended to use app-import-merge to update old data. More hassle for the user to delete old Patient data that they want to replace.

  • Alternative 2: In case of duplicates, replace old Patient data.

    • Pros: Conveniently update old Patient data.

    • Cons: May accidentally override and lose important data, though not a big deal with app-undo.

  • Alternative 3: Implement a flag to toggle overriding.

    • Pros: Best of both worlds.

    • Cons: More coding and debugging work.