Developer Guide
- Acknowledgements
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
-
Appendix: Requirements
- Product scope
- User stories
-
Use cases
- UC-PAT-001 - Add patient
- UC-PAT-002 - Detail patient
- UC-PAT-003 - List patients
- UC-PAT-004 - Find patients
- UC-PAT-005 - Edit patient
- UC-PAT-006 - Delete patient
- UC-PAT-007 - Clear patients
- UC-APT-001 - Add appointment
- UC-APT-002 - List appointments
- UC-APT-003 - Edit appointment
- UC-APT-004 - Delete appointment
- UC-APT-005 - Find appointments
- UC-APT-006 - Mark appointments
- UC-APT-007 - Unmark appointments
- UC-VAC-001 - Add vaccination
- UC-VAC-002 - List vaccination
- UC-VAC-003 - Edit vaccination
- UC-VAC-004 - Delete vaccination
- UC-VAC-005 - Clear vaccinations
- UC-VAC-006 - Filter vaccinations
- UC-VAC-007 - Detail a vaccination
- UC-KEY-001 - Add keyword
- UC-KEY-002 - Delete keyword
- Non-Functional Requirements
- Glossary
- Appendix: Instructions for manual testing
- Appendix: Planned enhancements
Acknowledgements
- COVID-19 vaccination data - MOH | COVID-19 Vaccination
- Chemical name synonyms - PubChem
- Code snippet in
ResultMessageBoxto sizeTextAreaadapted and modified from - StackOverflow - Javafx textfield resize to text length? - CLI presentation format in UG adapted from - Document command-line syntax
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
.puml files used to create diagrams in this document can be found in the diagrams folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Architecture

The Architecture Diagram given above explains the high-level design of the App.
Given below is a quick overview of main components and how they interact with each other.
Main components of the architecture
Main has two classes called Main and MainApp. It is responsible for,
- At app launch: Initializes the components in the correct sequence, and connects them up with each other.
- At shut down: Shuts down the components and invokes cleanup methods where necessary.
Commons represents a collection of classes used by multiple other components.
The rest of the App consists of four components.
-
UI: The UI of the App. -
Logic: The command executor. -
Model: Holds the data of the App in memory. -
Storage: Reads data from, and writes data to, the hard disk.
How the architecture components interact with each other
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command patient delete 1.

Each of the four main components (also shown in the diagram above),
- defines its API in an
interfacewith the same name as the Component. - implements its functionality using a concrete
{Component Name}Managerclass (which follows the corresponding APIinterfacementioned in the previous point.
For example, the Logic component defines its API in the Logic.java interface and implements its functionality using the LogicManager.java class which follows the Logic interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside component’s being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.

The sections below give more details of each component.
UI component
The API of this component is specified in Ui.java
The UI is responsible for the GUI of VMS. It does so with the aid of JavaFX UI framework. To simplify the creation of GUI layouts of different parts, several classes extends UiPart which is responsible for the creation of JavaFX scene graph structures through .fxml files. The .fxml files of these UI parts are stored in src/main/resources/view in with matching names to the class using them. For example, the .fxml file of MainWindow is specified in MainWindow.fxml.
UiPart. UiPart is used as a tool to simplify the creation of complicated GUI layout. Simple GUI parts such as DetailedView and ListViewPanel do not extend UiPart.
Below shows a (partial) class diagram of the main parts of Ui component.

UiPart has been omitted as the purpose of this diagram is to show the structure between the main parts of the UI component.
As seen from the class diagram above, MainWindow has composition type relationship with several other classes. Namely,
-
DetailedView- responsible for the graphical display of the detail panels.- 1 each for patients and vaccinations.
-
CommandBox- responsible for gathering the user’s command input. -
HelpWindow- responsible for the graphical display of the help window. -
ListViewPanel- responsible for the graphical display of the list view panels.- 1 each for patients, vaccinations and appointments.
-
ResultDisplay- responsible for displaying messages to the user.
The classes mentioned above are only initialized when fillInnerParts() method of MainWindow is called. The object diagram below show the state after fillInnerParts() has been called.

LogicManager is a concrete implementation of Logic. LogicManager was not shown in the complementing class diagram as it is not involved in the structure of the UI component. see Logic component to learn more about LogicManager.
Refreshing
In order to maintain the responsiveness of the GUI, the FX Application thread is used solely for GUI related processes such as event handling and display updates. For parsing and the execution of commands, their processes are dispatched on a separate thread. To learn more about this, see Logic component.
To handle display changes due to changes in the state of data that the different GUI parts are displaying, all classes of the UI component in the class diagram above with the exception of HelpWindow implements Refreshable. This is a functional interface whose functional method is refresh(). Calling this method will cause the implementing UI classes to check for changes in the data that they are displaying and update their display accordingly. To invoke the refresh() method continuously, a ScheduledThreadPoolExecutor is created in MainApp that is tasked to call refresh() of UiManager 30 times every second.
Unlike the implementation where the displays are updated as soon as it a change happens, this implementation is able to accumulate and differ the displaying of changes. This improves the responsiveness of the GUI in scenarios where there is a spike in the number of changes in data as the GUI does not update for every change. Such scenarios may happen when the use uses patient’s clear command when there are a large number of patient.
DetailedView
To display its contents, DetailedView uses an observer pattern to observe for the data that it needs to display. It observes an ObjectProperty through a ChangeListener, both of which are defined by JavaFX. To convert the observed object to the Node object that JavaFX can display, DetailedView will also have a Function, that is provided on construction, which will handle this conversion.
To collect and store changes to be displayed, 2 private class fields are defined:
-
isUpdatedof typeboolean.- Will be
trueif the change has been displayed andfalseotherwise.
- Will be
-
valueof typeTwhereTis the type of the object being detailed.- The object that has to be displayed.
- Can be
nullwhich will signify that nothing should be displayed.
isUpdated is required as value can be null. Thus checks to see if value is null will not work.
Below shows the class diagram, showing the structure of DetailedView. Notice how that there are no external dependencies to other parts of VMS.

Below shows the object diagram showing the state after fillInnerParts() of MainWindow is called for the patient detail panel to highlight the listener pattern structure that DetailView implements. A similar object diagram can be drawn for the vaccination detail panel by changing the relevant variable names and types.

The activity diagram below shows the work flow of DetailedDisplay as it checks for changes and update its display when refresh() is invoked.

As seen, no display updates are done if isUpdate is true, which signifies that the display has already been updated. This improves efficiency as the display is only updated when necessary.
ListViewPanel
Similar to DetailedView, ListViewPanel also uses an observer pattern and a Function to convert the observed object to a Node. However, it observes an ObservableMap through a MapChangeListener, both of which also defined by JavaFX. Only the values of the observed map will be displayed and the Function of ListViewPanel is used to convert these values to their equivalent Node representations. The order in which the values of the observed map are displayed is defined by a Comparator by default is the comparator produced from Comparator.naturalOrder(). This comparator is stored in an ObjectProperty in ListViewPanel
To collect changes to be displayed for the refresh, the latest MapChangeListener.Change (referred to as Change in this section) is stored in an ObjectProperty. Change is an inner class of MapChangeListener and defines a method, getMap() which allows the retrieval of the state of the map to be displayed. Unlike DetailedView, a null check to the value of this ObjectProperty can be done to verify if a an update to the display is required as its value will only be null if there is nothing to update.
Below shows the class diagram of ListViewPanel to graphically view this structure.

The complementing object diagram for appointment list view is shown below. Some AppointmentManager components are also added to detail the observer pattern structure of ListViewPanel. A similar diagram can be done for the patient list view panel.

To be able to refer to vaccinations by the index that they are displayed in the vaccination list panel, ModelManager will need to have a list view that describes the order in which the vaccinations are displayed. To avoid coupling, ModelManager observes the ListViewPanel, that is responsible for displaying the vaccination list panel, through the observer pattern. The items and order in which ListViewPanel is displaying is kept in an ObservableList as defined by JavaFX ListView which ListViewPanel extends. As such, obtain the required list view, ModelManager keeps another ObservableList that is bounded to the ObservableList defined by ListView through the observer pattern. Refer to the object diagram below for a graphical visualization of the structure described. The object diagram shows the state after fillInnerParts() is called.

Below show the activity diagram when the refresh() method is invoked. The item list referred to in the diagram is the ObservableList that ListView defines. Updates to this list will update the display.

ResultDisplay
To display messages to the user after every command that they have inputted, a Consumer, that accepts a list of CommandMessage, is used to update ResultDisplay whenever Logic has completed the execution of a command regardless if it was successful. The Consumer only function is to call the queueMessages(List<CommandMessage>) method of ResultDisplay. This method will queue all CommandMessage to be displayed in the order of the given list. When the refresh() method is called, elements in the queue will be polled and converted to their Node representation until the queue is emptied. To understand more about when this Consumer is called within Logic, read Executing a command.
Below shows the class diagram of the described structure. Logic, LogicManager and Consumer are not shown as there are no dependencies between these classes/interfaces and ResultDisplay.

Below shows the object diagram of ResultDisplay after the fillInnerParts() method has been called. This diagram reveals the observer pattern structure which the class diagram does not.

The following diagram shows the activity diagram when the refresh() method is called. On top of how messages are displayed, the procedure of how the 30 message history limit is maintained is shown as well.

Logic component
API : Logic.java
Here’s a (partial) class diagram of the Logic component:

LogicManager is a concrete implementation of Logic which handles the logical components of VMS. Its main responsibility is to handle the execution of user entered commands.
LogicManager handles command execution in the form of an execution queue. When the user enters a command, that command is queued into an execution queue in LogicManager. Both queueing and the execution of commands can happen in parallel. However, at any one time, at most one command will be executed at a time.
Command execution
For the entire command execution portion of the Logic component, only queue(String) method is exposed to the outside. As such, to queue and execute a user command, only the queue(String) method of Logic will have to be called. This method will queue the command for execution and execute it when it is its turn. Command inputs are stored and queued in an internal queue called the command queue (cmdQueue). To allow for parallel queuing and dequeuing, this queue has a type of LinkedBlockingDeque. The elements stored within the queue are the String of the command input that the user has entered.
To avoid dependencies with other classes, specifically UI related classes, ModelManager stores a completionHandler, which is a Consumer<List<CommandMessage>>. completionHandler can be set and changed by other classes and is called whenever a command execution is completed.
Queuing a command
When the queue(String) is called upon, the following happens.
- The command input is added to the end of
cmdQueue. - An attempt is then made to start the execute the next command in the queue through
startNext(). This is described in detail in the next section.

Starting a command
The method startNext() is a private method in LogicManager that handles the starting of the execution of a command. When it is called upon, a check is done to check if there are any command still in execution and that there are still commands yet to be executed in cmdQueue. If this is not the case, nothing happens and the method returns silently. If not, the following happens.
- The next command input in
cmdQueueis polled. - A new
Threadobject is created whose task is to parse and execute the command input polled in step 1. - The created
Threadobjects is then started on a separate thread to perform its task of executing the command.

Executing a command
When the created Thread in startNext() is started, Java Virtual Machine will call its run() method at an appropriate time. This will start the parsing then execution of a command input by calling the processCommand(String) of LogicManager. The following sequence describes how a command input is executed when processCommand(String) is called.
- The command input is passed to the stored instance of
ModelinLogicManagerto be parsed. The returned result is aParseResultwhich is an association class of the parsedCommandand its correspondingCommandMessageif there are warnings while parsing. More accurately, the parsedCommandis one of the concrete implementations ofCommand. - The
Commandin the returnedParseResultobject of step 1 is then executed. It is given the stored instance ofModelto perform its task and its interaction with model depends on the concrete implementation ofCommandparsed. This is represented as a ref frame in the sequence diagram below to highlight that theCommandobject andModelinteracts with each other, but their interactions may vary depending on the implementation of the parsedCommand. Once done it returns aCommandMessage. - The new state of
Modelis then saved into hard disk throughsaveModel()method. This will return a list ofCommandMessagecontaining the error messages that occurred while saving. - All
CommandMessages that have been created from steps 1 to 3 are combined as a list and passed tocompleteExecution(List<String>)method. - The
completionHandleris then passed the combined list ofCommandMessagein step 5 to handle the completion of the command. - An attempt is then made to start the next command through
startNext()as described in the section before.

Model to allow for user custom keywords.
Model component
API : Model.java
Here’s a (partial) class diagram of the Model component:

ModelManager is a concrete implementation of Model which handles the model components of VMS.
The responsibilities of Model component,
- stores the runtime state of the other managers:
PatientManagerVaxTypeManagerAppointmentManagerKeywordManager
- stores the objects to be displayed as a separate filtered map which is exposed to outsiders as an unmodifiable
ObservableMap<K, V>, whereVis the type of object being stored (eg.IdData<Patient>) andKis the type of the key the stored object is mapped to (forPatientandAppointment, this is anIntegerand as forVaxType, this is aString). - stores the object to be detailed as a
ObjectProperty<V>whereVis the type of the object to be displayed (eg.IdData<Patient>). - store a
UserPrefobject that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPrefobject.
Patient component
API : Patient.java
Here’s a (partial) class diagram of the Patient component:

To represent a patient, Patient contains the Identity and Medical information using the following attributes:
- Identity:
- The
nameof the patient - The
phoneof the patient - The
dateOfBirthof the patient
- The
- Medical:
- The
bloodTypeof the patient - The
allergiesof the patient - The
vaccinesof the patient
- The
Patient have limitations on its attributes according to the Non-Functional Requirements.
PatientManager
API : PatientManager.java
On top of storing Patient objects, PatientManager ensures the patient’s vaccination records are updated if the name of a vaccination changes. It also ensures that there is a maximum limit of Patient objects allowed to be stored according to the Non-Functional Requirements.
Vaccination component
Vaccinations are represented as VaxType objects and stored within VaxTypeManager.
VaxType
API : VaxType.java
Here’s a (partial) class diagram of the VaxType component:

To represent a vaccination, VaxType contains the following attributes:
- A name represented as a
GroupNameobject. - A set of groups which the vaccination classifies under as a set of
GroupNameobjects. - A minimum age as an
Ageobject. - A maximum age as an
Ageobject. - A set ingredients of the vaccination as a set of
GroupNameobjects. - A list of requirements of vaccination groups that will have to be taken before this vaccination can be taken as a list of
Requirementobjects.
VaxTypeManager
API : VaxTypeManager.java
On top of storing VaxType objects, VaxTypeManager ensures the uniqueness of VaxType. It also ensures that there is a maximum limit of VaxType objects allowed to be stored according to the Non-Functional Requirements.
Appointment component
API : Appointment.java
Here’s a (partial) class diagram of the Appointment component:

The Appointment component,
- Contains the details of patients’ appointment
- The patients’
Patient id. - The duration of each appointment (Uses the
start timeandend time). - The type and dose of
vaccineto be administered. - The
statusof the appointment.
- The patients’
AppointmentManager
API : AppointmentManager.java
On top of storing Appointment objects, AppointmentManager ensures the uniqueness of Appointment. It also ensures that there is a maximum limit of Appointment objects allowed to be stored according to the Non-Functional Requirements.
Keyword component
API : Keyword.java
Here’s a (partial) class diagram of the Keyword component:

The Keyword component,
- Contains the mapping of a custom keyword to a main keyword
- The custom’
<keyword>. - The main
<keyword>:-
appointmentforAppointmentclass. -
patientforPatientclass. -
vaccinationforVaxTypeclass.
-
- The custom’
KeywordManager
API : KeywordManager.java
The KeywordManager main responsibility is the storing of Keyword objects.
Storage component
API : Storage.java

The Storage component is responsible for the reading and writing of the states of the different managers in Model to and from the hard disk. As shown in the diagram above, it inherits from PatientManagerStorage, UserPrefsStorage, VaxTypeStorage, AppointmentStorage and KeywordStorage. As such, it can be treated as either one (if only the functionality of only one is needed).
Cascading delete
The cascading delete feature is an important part of the VMS’s design, as it helps to maintain data integrity and avoid orphaned records in the system. When a object is deleted from the VMS, any related records should also be deleted to ensure that the system remains consistent.
Relationship between Patient and Appointment
When a Patient record is deleted from the system, any associated Appointment records will be deleted as well. This is because Appointment records are directly linked to a specific Patient, and it would not make sense to keep these records around if the Patient is no longer in the system. The implementation can be found in AppointmentManager.java.
Relationship between VaxType and Appointment
When a VaxType record is deleted from the system, any associated Appointment records will be deleted as well. This is because VaxType records are directly linked to a specific Appointment, and it would not make sense to keep these records around if the VaxType record is no longer offered by the VaxType center. The implementation can be found in AppointmentManager.java.
Relationship between Patient and VaxType
On the other hand, Patient records are not deleted when a VaxType record is deleted from the system. This is because Patient records should not be modified if a VaxType is no longer offered. If a VaxType record is deleted, the associated Appointment records will be deleted, but any Patient records associated with those VaxType records will not be updated in the system. This is because the Patient records may still be relevant, even if the VaxType is no longer in the system.
Cascading Change
The cascading change feature is an important part of the VMS’s design, as it helps to maintain data integrity and avoid orphaned records in the system. When a object is changed in the VMS, any related records should also be changed to ensure that the system remains consistent.
Relationship between Patient and Appointment
When a Patient record is updated in the system, any associated Appointment records will be updated as well. This is because Appointment records are directly linked to a specific Patient, and if the patient’s information changes, it is important to update any related appointments to reflect this change. The implementation can be found in AppointmentManager.java.
Relationship between VaxType and Patient
When a VaxType record is updated in the system, any associated Patient records will be updated as well. This is because VaxType records contain information about the VaxTypes that a patient has taken, and if the VaxType information changes, it is important to update any related patient records to reflect this change. The implementation can be found in PatientManager.java.
Relationship between VaxType and Appointment
Additionally, when a VaxType record is updated in the system, any associated Appointment records will be updated as well. This is because VaxType records are directly linked to a specific Appointment, and if the VaxType information changes, it is important to update any related appointment records to reflect this change. The implementation can be found in AppointmentManager.java.
Common classes
Classes used by multiple components are in the seedu.vms.commons package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Patient
Adding a Patient
The Adding a Patient mechanism is facilitated by VMS. The Patient created is stored inside PatientManager object.
Execution Sequence
Given below is an example usage scenario when a user enter patient add --n John Doe --p 98765432 --d 2001-03-19 --b B+ --a catfur --a pollen --v covax as a command.
- The user enters the command in the
UI component - It will be passed to the
Logic component - When
AddCommandParserreceives the information fromPatientParser, it will invoke the following methods to help with the parsing.-
ParserUtil#parseNamewill be called to create a Name object using “John Doe”. -
ParserUtil#parsePhonewill be called to create a Phone object using “98765432”. -
ParserUtil#parseDobwill be called to create a Dob object using “2001-03-19”. -
ParserUtil#parseBloodTypewill be called to create a BloodType object using “B+”. -
ParserUtil#parseGroupswill be called to create GroupName[] object named allergies using [“catfur”, “pollen”]. -
ParserUtil#parseGroupswill be called to create GroupName[] object named vaccines using [“covax”].
-
- After successfully parsing the args,
AddCommandParserwill create a Patient using the new Name, Phone, Dob, BloodType, Allergies, Vaccines . Then it will create an `AddCommand` with the new Patient object. - When
AddCommand#executeis called,model#addPatientwill be called to add the new Patient into the model.AddCommandwill then returnCommandMessageto indicate it’s success.
Note that Allergies and Vaccines are optional, so the user does not need to include --a or --v if the it is not applicable.
The activity diagram below summarises the action when the patient AddCommand is executed.

Given below is an sequence diagram that illustrates the Adding a Patient parsing mechanism behaves at every step.

Patient parsing detail here:

Detailing Patients
The Detailing Patients mechanism is facilitated by VMS. It will update the UI with the Patient requested.
Execution Sequence
Given below is an example usage scenario when a user enter patient detail 1 as a command.
- The user enters the command in the
UI component. - It will be passed to the
Logic component. - When
DetailCommandParserreceives the information fromPatientParser, it will invoke theParseUtil#parseIndexto parse PATIENT_ID. It will throw aParseExceptionif there are no args present. - After successfully parsing the args,
FindCommandParserwill create anDetailCommandwith the parsed index. - When
DetailCommand#executeis called,model#setDetailedPatientwill be called to update the ui to display the Patient requested.
The activity diagram below summarises the action when the patient DetailCommand is executed.

Listing Patients
The Listing Patients mechanism is facilitated by VMS. It will list all the Patients that are stored in the PatientManager.
Execution Sequence
Given below is an example usage scenario when a user enter patient list as a command.
- The user enters the command in the
UI component. - It will be passed to the
Logic component. -
PatientParserwill invokeListCommandParser, which will createListCommanddirectly as they do not use any args. - When
ListCommand#executeis called,model#updateFilteredPatientListwill be called to update the list with thePREDICATE_SHOW_ALL_PATIENTSto display all Patients.
The activity diagram below summarises the action when the patient ListCommand is executed.

Finding a Patient
The Finding a Patient mechanism is facilitated by VMS. It will find specific list of Patient objects from PatientManager inside VMS object with the keywords provided.
The user can choose to add flags when searching, to search for the specific attributes of a Patient. If no flags are present, the mechanism will assume that it is searching the Patient’s name.
Execution Sequence
Given below is an example usage scenario when a user enter patient find --n John Deer --p 98765431 --d 2001-03-19 --b B+ --a catfur --v covax as a command.
- The user enters the command in the
UI component - It will be passed to the
Logic component - When
FindCommandParserreceives the information fromPatientParser, it will invoke the following methods to help with the parsing. It will throw aParseExceptionif there are no args present.-
ParserUtil#parseNamewill be called to create a Name object using “John Doe”. -
ParserUtil#parsePhonewill be called to create a Phone object using “98765432”. -
ParserUtil#parseDobwill be called to create a Dob object using “2001-03-19”. -
ParserUtil#parseBloodTypewill be called to create a BloodType object using “B+”. -
ParserUtil#parseGroupswill be called to create GroupName[] object named allergies using [“catfur”, “pollen”]. -
ParserUtil#parseGroupswill be called to create GroupName[] object named vaccines using [“covax”].
-
- After successfully parsing the args, the following will happen
-
FindCommandParserwill create an FindPatientDescriptor using the new Name, Phone, Dob, BloodType, Allergies<GroupName>, Vaccines<GroupName>. 1a. If none of the flags are present, it will take the entire arg as asetNameSearch. - Then it will create an
FindCommandwith the new FindPatientDescriptor object.
-
- When
FindCommand#executeis called, the following will happen.- It will check if the different attributes of FindPatientDescriptor is present.
- It will find the patient by creating different
Optional<AttributePredicate>. - The different predicates will be added into a
List<Predicate<Patient>>and passed tomodel#setPatientFiltersto display the filtered Patients. -
FindCommandwill then returnCommandMessageto indicate it’s success and the number of patients found.
The activity diagram below summarises the action when the patient FindCommand is executed.

FindCommandParser#parse will call String#trim to trim the search request. If there is no additional flags, it will fall back to the default of using the search term to find Names.
Editing a Patient
The Editing a Patient mechanism is facilitated by VMS. It will read and modify a target Patient object from PatientManger inside VMS object.
Execution Sequence
Given below is an example usage scenario when a user enter patient edit 5 --n John Deer --p 98765431 --d 2001-03-19 --b B+ --a catfur --a pollen --v covax as a command.
- The user enters the command in the
UI component - It will be passed to the
Logic component - When
EditCommandParserreceives the information fromPatientParser, it will invoke the following methods to help with the parsing. It will short circuit and throw aParseExceptionif 1. is not fulfilled.-
ParserUtil#parseIndexwill be called to create a Index object using “5”. -
ParserUtil#parseNamewill be called to create a Name object using “John Doe”. -
ParserUtil#parsePhonewill be called to create a Phone object using “98765432”. -
ParserUtil#parseDobwill be called to create a Dob object using “2001-03-19”. -
ParserUtil#parseBloodTypewill be called to create a BloodType object using “B+”. -
ParserUtil#parseGroupswill be called to create GroupName[] object named allergies using [“catfur”, “pollen”]. -
ParserUtil#parseGroupswill be called to create GroupName[] object named vaccines using [“covax”].
-
- After successfully parsing the args,
EditCommandParserwill create an editPatientDescriptor using the new Name, Phone, Dob, BloodType, Allergies<GroupName>, Vaccines<GroupName>. Then it will create anEditCommandwith the new editPatientDescriptor object with the index. - When
EditCommand#executeis called, the following will happen.- It will ensure that the Index given is within the list, else it will throw a CommandException
- It will edit the patient by creating a new patient with the new values from the Parser as Patients are Immutable
- Then
model#setPatientwill be called to add the new Patient into the model. -
EditCommandwill then returnCommandMessageto indicate it’s success.
The activity diagram below summarises the action when the patient EditCommand is executed.

Deleting a Patient
The Deleting a Patients mechanism is facilitated by VMS. It will delete specific Patient objects from PatientManager inside VMS object with using the index provided.
Execution Sequence
Given below is an example usage scenario when a user enter patient delete 5 as a command.
- The user enters the command in the
UI component - It will be passed to the
Logic component - When
DeleteCommandParserreceives the information fromPatientParser, it will invoke theParseUtil#parseIndexto parse PATIENT_ID. It will throw aParseExceptionif there are no args present. - After successfully parsing the args,
FindCommandParserwill create anDeleteCommandwith the parsed index - When
DeleteCommand#executeis called,model#setDeletedPatientwill be called to update the ui to display the Patient requested.
The activity diagram below summarises the action when the patient DeleteCommand is executed.

Clearing Patients
The Clearing Patients mechanism is facilitated by VMS. It will set the patient manager with a new empty patient manager, effectively clearing all the Patients
Execution Sequence
Given below is an example usage scenario when a user enter patient clear as a command.
- The user enters the command in the
UI component. - It will be passed to the
Logic component. -
PatientParserwill invokeClearCommandwhich will createClearCommandas they do not use any args. - When
ClearCommand#executeis called,model#setPatientManagerwill be called to update the list a new PatientManger() with no patients.
The activity diagram below summarises the action when the patient ClearCommand is executed.

Keyword
Adding a Keyword
The Keyword Adding mechanism is facilitated by VMS. The Keyword created is stored inside KeywordManager object.
Execution Sequence
Given below is an example usage scenario when a user enters keyword add --k patient --n p as a command.
- The user enters the command in the
UI Component. - It will be passed to the
Logic component. - When
AddCommandParserreceives the information fromKeywordParser, it will invoke the following methods for parsing.-
ParserUtil#parseMainKeywordwill be called to create a String object usingpatient. -
ParserUtil#parseKeywordwill be called to create a String object usingp.
-
- After successfully parsing the args,
AddCommandParserwill create a Keyword using the newpatientandpstrings created. - When
AddCommand#executeis called,model#addKeywordwill be called to add the new Keyword into the model.AddCommandwill then returnCommandMessageto indicate it’s success.
Note that MainKeyword and Keyword are required args, hence the user must include --k and --n in the command.
The activity diagram below summarises the action when the keyword AddCommand is executed.

Given below is a sequence diagram that illustrates the Keyword Adding parsing mechanism at every step.

Keyword parsing detail here:

Deleting a Keyword
The Keyword Delete mechanism is facilitated by VMS. It will delete specific Keyword objects from KeywordManager
inside VMS object using the string provided.
Execution Sequence
Given below is an example usage scenario when a user enters keyword delete p as a command.
- The user enters the command in the
UI Component. - It will be passed to the
Logic component. - When
DeleteCommandParserreceives the information fromKeywordParser, it will invoke theParserUtil#parseDeleteKeywordto parse the stringpprovided. It will throw aParseExceptionif there are no args present. - After successfully parsing the arg,
DeleteCommandParserwill create aDeleteCommandwith the parsedpstring. - When
DeleteCommand#executeis called,model#deleteKeywordwill be called to delete the specified Keyword from the model.DeleteCommandwill then returnCommandMessageto indicate it’s success.
The activity diagram below summarises the action when the keyword DeleteCommand is executed.

Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- a receptionist of small size private clinics in charge of managing vaccination appointments.
- prefer desktop apps over other types.
- can type fast.
- prefers typing to mouse interactions.
- is reasonably comfortable using CLI apps for speed and efficiency.
Value proposition: Application will
- Validate the eligibility of patients to take vaccinations faster than manual means.
- Manage patients.
- Manage vaccinations.
- Manage appointments.
- All of which faster than a typical mouse/GUI driven app.
User stories
Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *
| Priority | As a … | I want to … | So that I can … |
|---|---|---|---|
* * * |
User | get the patient’s contact easily | contact them when needed. |
* * * |
User | be able to key in people with the same name | save the data of people with the same name |
* * * |
User | view patient details | recall the details of a patient |
* * * |
User | add a patient | |
* * * |
User | update a patient | |
* * * |
User | delete a patient | |
* * * |
User | view appointment details | recall the details of an appointment |
* * * |
User | add an appointment | |
* * * |
User | delete an appointment | |
* * * |
User | update an appointment | |
* * * |
User | view upcoming appointments | so that I know what appointments are coming soon |
* * * |
User | view vaccination details | recall the details of a vaccination type |
* * * |
User | add a vaccination | |
* * * |
User | delete a vaccination | |
* * * |
User | update a vaccination | |
* * * |
User | check the eligibility of a patient to take a vaccination | verify if I can schedule the appointment that the patient requested |
* * |
Forgetful user | view the guide page of the application | understand of the parts of the application that I have forgotten works |
* * |
Forgetful user | see the syntax of commands | know how to use the command |
* * |
New user | see the app populated with sample data | use it as a tutorial for how the app will work |
* * |
New User | purge all the current data | get rid of sample data |
* * |
User | generate patient numbers | uniquely identify a patient by their patient number |
* * |
User | generate appointment numbers | uniquely identify an appointment by its appointment number |
* * |
User | find patients | view details about the patient I am looking for faster |
* * |
User | list all patients | clear my find filters for patients |
* * |
User | find vaccinations | view details about the vaccination I am looking for faster |
* * |
User | list all vaccinations | clear my find filters for vaccinations |
* * |
User | find appointments | view details about the appointment I am looking for faster |
* * |
User | list all appointments | clear my find filters for appointments |
* |
Forgetful user | see what commands there are | know what commands I can use |
* |
User | check what is the next free appointment slot | choose the best time for the patient quicker |
* |
User | undo my latest action | undo my mistakes |
Use cases
For all use cases below, the System is the VMS and the Actor is the user, unless specified otherwise.
UC-PAT-001 - Add patient
MSS
- User enters command to add a patient.
-
VMS adds the patient.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
UC-PAT-002 - Detail patient
MSS
- User enters command to view details of a patient.
- VMS shows the details of the patient requested.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to detail a patient that does not exist.
-
1a1. VMS shows an error message.
Use case ends.
-
UC-PAT-003 - List patients
MSS
- User enters command to list patients.
- VMS shows the list of patients with their corresponding IDs.
Use case ends.
UC-PAT-004 - Find patients
MSS
- User enter command to find patients.
- VMS shows the list of matched patients with their corresponding IDs.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
UC-PAT-005 - Edit patient
MSS
- User enters command to edit a specific patient.
-
VMS edits the patients
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to edit a patient that does not exist.
-
1a1. VMS shows an error message.
Use case ends.
-
UC-PAT-006 - Delete patient
MSS
- User requests to delete a specific patient in the list.
-
VMS deletes the patient.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to delete a patient that does not exist.
-
1a1. VMS shows an error message.
Use case ends.
-
- 1c. VMS detects that some appointments will become invalid after deletion.
- 1c1. VMS requests user to force the change.
- 1c2. User enters command to force the change.
-
1c3. VMS deletes the patient and all invalid appointments.
Use case ends.
UC-PAT-007 - Clear patients
MSS
- User requests to list patients.
- VMS shows the list of patients with their corresponding IDs.
Use case ends.
UC-APT-001 - Add appointment
MSS
- User request to add an appointment.
- User enters the start and end timing of the appointment, and the associated patient.
-
VMS adds the appointment.
Use case ends.
Extensions
- 2a. timing format or patient ID is invalid.
-
2a1. VMS shows an error message.
Use case resumes at step 1.
-
UC-APT-002 - List appointments
MSS
- User requests to list appointments.
-
VMS shows a list of appointments.
Use case ends.
UC-APT-003 - Edit appointment
MSS
- User enters command to edit an appointment.
-
VMS edits the appointment.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to edit an appointment that does not exist.
-
1a1. VMS shows an error message.
Use case ends.
-
UC-APT-004 - Delete appointment
MSS
- User enters command to delete an appointment.
-
VMS deletes the appointment.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to delete an appointment that does not exist.
-
1a1. VMS shows an error message.
Use case ends.
-
UC-APT-005 - Find appointments
MSS
- User requests to find appointments.
-
VMS shows a list of appointments that matches search criteria.
Use case ends.
Extensions
- 1a. The list is empty.
-
1a1. VMS returns an empty list.
Use case resumes at step 1.
-
- 1b. Some appointments match the search criteria.
-
1b1. VMS returns the list of appointment that matches.
Use case resumes at step 1.
-
- 1c. No appointment match the search criteria.
-
1c1. VMS returns an empty list.
Use case resumes at step 1.
-
UC-APT-006 - Mark appointments
MSS
- User requests to mark a specified appointment.
-
VMS marks the appointment.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to mark an appointment that does not exist.
-
1a1. VMS shows an error message.
Use case ends.
-
- 1b. User requested to mark an appointment that is already marked.
- 1a1. If assertion is enabled
-
1a11. VMS shows an error message.
Use case ends.
-
- 1b1. If assertion is disabled
Use case resumes from step 1.
- 1a1. If assertion is enabled
UC-APT-007 - Unmark appointments
MSS
- User requests to unmark a specified appointment.
-
VMS changes the status of the appointment to not completed.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to unmark an appointment that does not exist.
-
1a1. VMS shows an error message.
Use case ends.
-
- 1b. User requested to unmark an appointment that is already unmarked.
- 1a1. If assertion is enabled
-
1a11. VMS shows an error message.
Use case ends.
-
-
1b1. If assertion is disabled
Use case resumes from step 1.
- 1a1. If assertion is enabled
UC-VAC-001 - Add vaccination
MSS
- User enters command to add a vaccination.
-
VMS adds the vaccination.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to add a vaccination that already exist.
-
1a1. VMS shows an error message.
Use case ends.
-
UC-VAC-002 - List vaccination
MSS
- User enters the command to list vaccination.
-
VMS lists all vaccination.
Use case ends.
UC-VAC-003 - Edit vaccination
MSS
- User enters command to edit a vaccination.
-
VMS edits the vaccination.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to edit a vaccination that does not exist.
-
1a1. VMS shows an error message.
Use case ends.
-
UC-VAC-004 - Delete vaccination
MSS
- User enters command to delete a vaccination.
-
VMS deletes the vaccination.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to delete a vaccination that does not exist.
-
1a1. VMS shows an error message.
Use case ends.
-
- 1c. VMS detects that some appointments will become invalid after deletion.
- 1c1. VMS requests user to force the change.
- 1c2. User enters command to force the change.
-
1c3. VMS deletes the vaccination and all invalid appointments.
Use case ends.
UC-VAC-005 - Clear vaccinations
- User enters command to clear vaccinations.
-
VMS deletes all vaccinations.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. VMS detects that some appointments will become invalid after clearing.
- 1b1. VMS requests user to force the change.
- 1b2. User enters command to force the change.
-
1b3. VMS deletes all vaccinations and all invalid appointments.
Use case ends.
UC-VAC-006 - Filter vaccinations
MSS
- User enters command to filter vaccinations.
-
VMS shows only filtered vaccinations.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to apply no filters.
-
1b1. VMS shows an error message.
Use case ends.
-
UC-VAC-007 - Detail a vaccination
MSS
- User enters command to detail a vaccination.
-
VMS shows details about that vaccination.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to detail a vaccination that does not exist.
-
1a1. VMS shows an error message.
Use case ends.
-
UC-KEY-001 - Add keyword
MSS
- User enters command to add a keyword.
-
VMS adds the keyword.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to add a keyword that overrides a main component keyword.
-
1a1. VMS shows an error message.
Use case ends.
-
- 1c. User requested to add a keyword with a main keyword that is not
patient,appointmentorvaccination.-
1a1. VMS shows an error message.
Use case ends.
-
UC-KEY-002 - Delete keyword
MSS
- User requests to delete a specific keyword in the list.
-
VMS deletes the keyword.
Use case ends.
Extensions
- 1a. VMS detects error in the command entered.
-
1a1. VMS shows an error message.
Use case resumes from step 1.
-
- 1b. User requested to delete a keyword that does not exist.
-
1a1. VMS shows an error message.
Use case ends.
-
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11or above installed. - Should be able to handle the following limits without any noticeable sluggishness in performance on typical usage:
- 1000 patients, each with a limit of:
- 100 allergies
- 30 vaccines
- 30 vaccination types, each with a limit of:
- 10 groups
- 30 ingredients
- 10 requirements
- 1000 appointments.
- 1000 patients, each with a limit of:
- On top of 2, should also be able to handle these names up to 30 characters without any noticeable sluggishness in performance on typical usage:
- Allergy
- Vaccination name
- Vaccination group name
- Vaccination ingredient name
- On top of 2, should also be able to handle requirement set of sizes up to 30.
- A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
- Should auto save to prevent data loss if application crashes.
- Should save its data in a human readable file.
- All functional features should be accessible through CLI.
- Should work without requiring an installer.
- Should not depend on a remote server.
- Should not cause any resolution related inconveniences to the user for:
- Screen resolutions 1920x1080 and higher.
- Screen scales 100% and 125%.
- Application executable JAR file should be less than 100MB.
Glossary
-
Component:
- In the context of application usage - the main functionalities of the application:
- Basic
- Keyword
- Patient
- Vaccination
- Appointment
- In the context of application design - the parts of the application design:
- Main
- Ui
- Logic
- Model
- Storage
- In the context of application usage - the main functionalities of the application:
- DOB: Date of birth of a patient.
- Group (in the context of vaccination): A group that the vaccination can be classified under.
- History requirement (in the context of vaccination): A set of vaccination groups that either has to be present or cannot be present in the groups that a vaccination classifies under.
- Index: The position of an element in a list-like structure (eg. position of a vaccination in the vaccination list panel).
- Ingredients: ingredients used to make the vaccination / things that the patient cannot be allergic to.
- Keyword: A user defined word to refer to one of the main keywords.
-
Mainkeyword: One of these 3 that refers to the main component of VMS.
patientvaccinationappointment
- Mainstream OS: Windows, Linux, Unix, OS-X
- Patient: A person who may receive the vaccination.
- Patient/Appointment ID: A unique serial number for patient/appointment.
- VMS: Vaccination Management System.
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.
PATIENT_ID will have to be changed accordingly.
Launch and shutdown
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
-
{ more test cases … }
Adding a patient
Prerequisites
Before every test case, ensure that the patient “John Doe” does not exist. This can be done by executing the following before every test case:
patient clear --force true
Test: All optional parameters omitted
patient add --n John Doe --p 98765432 --d 2001-03-19 --b B+
Expected

Test: Optional parameters present
patient add --n John Doe --p 98765432 --d 2001-03-19 --b B+ --a catfur --a pollen --v covax
Expected

Patient attribute validation
Before every test case, ensure that the there are no patients. This can be done by executing the following before every test case:
patient clear --force true
Test: Name validation
Valid Name
patient add --n John Doe --p 98765432 --d 2001-03-19 --b B+patient add --n John Doe --p 98765432 --d 2001-03-19 --b B+patient add --n John Doe2 --p 98765432 --d 2001-03-19 --b B+
Invalid Name
patient add --n John-Doe --p 98765432 --d 2001-03-19 --b B+patient add --n --p 98765432 --d 2001-03-19 --b B+patient add --n John D. --p 98765432 --d 2001-03-19 --b B+patient add --n John s/o Alex --p 98765432 --d 2001-03-19 --b B+patient add --n --p 98765432 --d 2001-03-19 --b B+
Test: Phone validation
Valid Phone
patient add --n John Doe --p 98765432 --d 2001-03-19 --b B+patient add --n John Doe --p 999 --d 2001-03-19 --b B+patient add --n John Doe --p 12345678912345 --d 2001-03-19 --b B+
Invalid Phone
patient add --n John Doe --p +65 98765432 --d 2001-03-19 --b B+patient add --n John Doe --p 99 --d 2001-03-19 --b B+patient add --n John Doe --p 123-456 --d 2001-03-19 --b B+patient add --n John Doe --p (123) 2345 --d 2001-03-19 --b B+patient add --n John Doe --p --d 2001-03-19 --b B+
Test: Dob validation
Valid Dob
patient add --n John Doe --p 98765432 --d 2001-03-19 --b B+patient add --n John Doe --p 98765432 --d 2001-03-19 0800 --b B+patient add --n John Doe --p 98765432 --d 2001-03-19 1600 --b B+
Invalid Dob
patient add --n John Doe --p 98765432 --d 2001-03-19T2000 --b B+patient add --n John Doe --p 98765432 --d 2001-03-50 --b B+patient add --n John Doe --p 98765432 --d 2040-03-19 --b B+patient add --n John Doe --p 98765432 --d --b B+
Test: Blood Type validation
Valid Blood Type
List of valid Blood Type test non exhaustive
patient add --n John Doe --p 98765432 --d 2001-03-19 --b A+patient add --n John Doe --p 98765432 --d 2001-03-19 --b A-patient add --n John Doe --p 98765432 --d 2001-03-19 --b AB+
Invalid Blood Type
patient add --n John Doe --p 98765432 --d 2001-03-19 --b C+patient add --n John Doe --p 98765432 --d 2001-03-19 --b C*patient add --n John Doe --p 98765432 --d 2001-03-19 --b
Test: Group Name validation
GroupName validation will include both allergies and vaccination as their underlying type is the same GroupName type
Valid Group Name
patient add --n John Doe --p 98765432 --d 2001-03-19 --b B+ --a catfur --a pollen --v covaxpatient add --n John Doe --p 98765432 --d 2001-03-19 --b B+ --a catfur, pollen --v covaxpatient add --n John Doe --p 98765432 --d 2001-03-19 --b B+ --a cat(fur) --a pol-len --v covax
Invalid Group Name
patient add --n John Doe --p 98765432 --d 2001-03-19 --b B+ --a catfur --a poll*en --v covaxpatient add --n John Doe --p 98765432 --d 2001-03-19 --b B+ --a catfurcatfurcatfurcatfurcatfurcatfur --v covax
Viewing details of a patient
Prerequisites
Before every test case, ensure that the there are no patients. This can be done by executing the following before every test case:
patient clear --force true
patient add --n John Doe --p 98765432 --d 2001-03-19 --b B+ --a catfur --a pollen --v covaxpatient detail 1
Expected

Listing all patients
Prerequisites
Before every test case, ensure that the there are no patients. This can be done by executing the following before every test case:
patient clear --force true
patient add --n John Doe --p 98765432 --d 2001-03-19 --b B+ --a catfur --a pollen --v covaxpatient add --n John Doe --p 98765432 --d 2001-03-19 --b B+ --a catfur --a pollen --v covaxpatient add --n John Doe --p 98765432 --d 2001-03-19 --b B+ --a catfur --a pollen --v covaxpatient list
Expected

Locating a patient
Prerequisites
Before every test case, ensure that the there are no patients. This can be done by executing the following before every test case:
patient clear --force true
- Add patients with different Names, Blood Type
patient add --n John Doe --p 98765432 --d 2001-03-19 --b A+ --a catfur --a pollen --v covaxpatient add --n John Does --p 98765432 --d 2001-03-19 --b B+ --a catfur --a pollen --v covaxpatient add --n John Po --p 98765432 --d 2001-03-19 --b AB+ --a catfur --a pollen --v covax- Find patient with name “John Doe”
patient find John Doe
Expected: 2 patients listed! (John Doe, John Does) - Find patient with name “John Does”
patient find John Does
Expected: 1 patients listed! (John Does) - Find patient with name “John”
patient find John
Expected: 3 patients listed! (John Doe, John Does, John Po) - Find patient with “A+” Blood Type
patient find --b A+
Expected: 1 patients listed! (John Doe) - Find patient with “A+” Blood Type and named “John”
patient find --b A+ --n John
Expected: 1 patients listed! (John Doe)
Adding a vaccination
In all cases, vaccination “a” will be added but its state is determined through the display.
Prerequisites
Before every test case, ensure that the vaccination “a” does not exist and that there are no vaccination filters applied. This can be done by executing the following before every test case:
vaccination clear --force truevaccination list
Test: All optional parameters omitted
vaccination add a
Expected

Test: Optional parameters present
vaccination add a --lal 45 --g a,b,c --i a,b,c --h all::all --h any::any --h none::none
Expected

Vaccination validation
Prerequisites
Before every test case, ensure that the there are no patients and vaccinations.
patient clear --force truevaccination clear --force true
PATIENT_ID will have to be changed accordingly.
Test: History requirement - ALL
- Add vaccination “TAKING” which will be the vaccination to be taken with
ALLtype history requirement.
vaccination add TAKING --h ALL::G1, G2, G3 - Add vaccination “LACKING” that will lack a required group.
vaccination add LACKING --g G1, G2 - Add vaccination “ALL” that will have all required groups.
vaccination add ALL --g G1, G2, G3 - Add vaccination “EXTRA” that will have all required groups and extra.
vaccination add EXTRA --g G1, G2, G3, G4 - Add patient “LACKING” who has taken a vaccination with lacking required groups.
patient add --n LACKING --p 445 --d 0001-1-1 --b A+ --v LACKING - Add patient “ALL” who has taken a vaccination with all required groups.
patient add --n ALL --p 445 --d 0001-1-1 --b A+ --v ALL - Add patient “EXTRA” who has taken a vaccination with all required groups and extra.
patient add --n EXTRA --p 445 --d 0001-1-1 --b A+ --v EXTRA - Schedule an appointment for patient “LACKING”
appointment add --p 1 --v TAKING --s 9999-1-1 --e 9999-1-2.
Expected: Patient cannot take the vaccination - Schedule an appointment for patient “ALL”
appointment add --p 2 --v TAKING --s 9999-1-1 --e 9999-1-2.
Expected: Appointment added - Schedule an appointment for patient “EXTRA”.
appointment add --p 3 --v TAKING --s 9999-1-1 --e 9999-1-2
Expected: Appointment added
Test: History requirement - ANY
- Add vaccination “TAKING” which will be the vaccination to be taken with
ANYtype history requirement.
vaccination add TAKING --h ANY::G1, G2, G3 - Add vaccination “LACKING” that will lack required groups.
vaccination add LACKING --g G1 - Add vaccination “ALL” that will have all required groups.
vaccination add ALL --g G1, G2, G3 - Add vaccination “EXTRA” that will have all required groups and extra.
vaccination add EXTRA --g G1, G2, G3, G4 - Add vaccination “NONE” that will have none of the required groups.
vaccination add NONE --g G4, G5 - Add patient “LACKING” who has taken a vaccination with lacking required groups.
patient add --n LACKING --p 445 --d 0001-1-1 --b A+ --v LACKING - Add patient “ALL” who has taken a vaccination with all required groups.
patient add --n ALL --p 445 --d 0001-1-1 --b A+ --v ALL - Add patient “EXTRA” who has taken a vaccination with all required groups and extra.
patient add --n EXTRA --p 445 --d 0001-1-1 --b A+ --v EXTRA - Add patient “NONE” who has taken a vaccination with none of the required groups.
patient add --n NONE --p 445 --d 0001-1-1 --b A+ --v NONE - Schedule an appointment for patient “LACKING”.
appointment add --p 1 --v TAKING --s 9999-1-1 --e 9999-1-2
Expected: Appointment added - Schedule an appointment for patient “ALL”.
appointment add --p 2 --v TAKING --s 9999-1-1 --e 9999-1-2
Expected: Appointment added - Schedule an appointment for patient “EXTRA”.
appointment add --p 3 --v TAKING --s 9999-1-1 --e 9999-1-2
Expected: Appointment added - Schedule an appointment for patient “NONE”.
appointment add --p 4 --v TAKING --s 9999-1-1 --e 9999-1-2
Expected: Patient cannot take the vaccination
Test: History requirement - NONE
- Add vaccination “TAKING” which will be the vaccination to be taken with
NONEtype history requirement.
vaccination add TAKING --h NONE::G1, G2, G3 - Add vaccination “PRESENT” which will have a group that cannot be present.
vaccination add PRESENT --g G1 - Add vaccination “PRESENT EXTRA” which will have a group that cannot be present and another that can.
vaccination add PRESENT EXTRA --g G1, G4 - Add vaccination “NONE” that will have none of the groups that cannot be present.
vaccination add NONE --g G4, G5 - Add patient “PRESENT” who has taken a vaccination with a group that cannot be present.
patient add --n PRESENT --p 445 --d 0001-1-1 --b A+ --v PRESENT - Add patient “PRESENT EXTRA” who has taken a vaccination with a group that cannot be present and another that can.
patient add --n PRESENT EXTRA --p 445 --d 0001-1-1 --b A+ --v PRESENT EXTRA - Add patient “NONE” who has taken a vaccination with a groups that can be present.
patient add --n NONE--p 445 --d 0001-1-1 --b A+ --v NONE - Schedule an appointment for patient “PRESENT”.
appointment add --p 1 --v TAKING --s 9999-1-1 --e 9999-1-2
Expected: Patient cannot take the vaccination - Schedule an appointment for patient “PRESENT EXTRA”.
appointment add --p 2 --v TAKING --s 9999-1-1 --e 9999-1-2
Expected: Patient cannot take the vaccination - Schedule an appointment for patient “NONE”.
appointment add --p 3 --v TAKING --s 9999-1-1 --e 9999-1-2
Expected: Appointment added
Adding a appointment
Adds an appointment to the VMS.
Prerequisites
Before every test case, ensure that the list of appointments is empty, and the list of patients and vaccinations contains the patient and vaccine to be added.
Clears the list of patients and vaccines
patient clear --force true
vaccination clear --force true
Adds the necessary patient and vaccine
patient add --n John Doe --p 98765432 --d 2001-03-19 --b B+ --a catfur \
--a pollen --v Moderna
vaccination add Dose 1 (Moderna)
Adding a valid appointment
appointment add --p 1 --s 2024-01-01 1330 --e 2024-01-01 1400 --v Dose 1 (Moderna)
Prerequisites
- There must be a patient with an id of
<Index>#0001. - There must be a vaccine
Dose 1 (Moderna).
Expected
Adding an invalid appointment
Invalid appointments include:
- missing parameters
- existing upcoming appointment
Prerequisites
- There must be a patient with an id of
<Index>#0001. - There must be a vaccine
Dose 1 (Moderna).
Adding a invalid appointment - Missing parameters
appointment add --p 1 --s 2024-01-01 1330 --e 2024-01-01 1400
Expected
Adding a invalid appointment - Existing upcoming appointment
appointment add --p 1 --s 2024-01-01 1330 --e 2024-01-01 1400 --v Dose 1 (Moderna)
appointment add --p 1 --s 2024-01-01 1330 --e 2024-01-01 1400 --v Dose 1 (Moderna)
Expected
Adding a keyword
Prerequisites
Before every test case, ensure that the keyword mapping of main keyword “patient” and keyword “pa” does not exist. This can be done by executing the following before every test case:
keyword delete pa
Test:
keyword add --k patient --n pa
Expected

Keyword attribute validation
Before every test case, ensure that keyword mapping of main keyword “patient” and keyword “pa”, main keyword “appointment” and keyword “appo”, and main keyword “vaccination” and keyword “vacci” does not exist. This can be done by executing all of the following commands before every test case:
keyword delete pa
keyword delete appo
keyword delete vacci
Test: Keyword validation
Valid Keyword
keyword add --k patient --n pakeyword add --k appointment --n appokeyword add --k vaccination --n vacci
Invalid Keyword
keyword add --k patient --n patientkeyword add --k vaccination --n appointmentkeyword add --k appointment --n ap pt
Test: Main Keyword validation
Valid Main Keyword
keyword add --k patient --n pakeyword add --k appointment --n appokeyword add --k vaccination --n vacci
Invalid Main Keyword
keyword add --k patientt --n pakeyword add --k help --n appokeyword add --k blank --n vacci
Appendix: Planned enhancements
Less strict patient name check
We plan to update NAME to allow for other possible name formats, not limited to the ones listed above (see invalid patient name). The VALIDATION_REGEX currently does not restrict the length of Name to accommodate patients with long names. We also plan to limit the name to prevent UI elements from being overflowed.
The following is an example of the problem:

A proposed solution is to update the validation regex to something like public static final String VALIDATION_REGEX = "[\\p{Alnum}][\\p{Alnum}\\-.,/@ ]*";
Phone number limit
We plan to cap the max length of the phone number type so that the UI elements does not get overflowed.
The following is an example of the problem:

A proposed solution would be to limit the phone number to 32 character long.
Decrease the warning severity message of invalid appointment data file
On start up, in same cases, the DEATH severity (the highest due to an uncaught exception) will show if the loaded appointment file is invalid (eg. start time of an appointment after end time). We plan to decrease this severity.
ID count saving
We plan to save the current ID count to hard disk as well on every auto save. This will resolve the issue where the ID counts is forgotten when the application is closed and defaulted to the highest ID. Here are some examples on what may happen if the ID count is forgotten:
- User adds 100 patients and then deletes all of them. ID count is at 100. A restart of the application will cause the ID count to reset to 1.
- User adds 1000 patients, deletes the patients with IDs 11 to 20, adds 5 additional patients and deletes the added 5. ID count will be 15. A restart of the application will cause the ID count to reset to 1000 and the addition of the next patient will have an ID of 11.
Validation of requirements of type NONE
The validation checks for history requirements specifically the NONE type is planned to be enhanced. The enhancement will disallow the addition or creation of a history requirement if there exist a requirement of NONE that causes the entire history requirement to become meaningless. These cases are as follows:
- Duplicate requirements of
NONEtype (eg. 2NONE::G1). - Conflicting requirements with a
NONEtype (eg.NONE::G1andANY::G1).
Ignore whitespace for name parsing
We plan to improve teh parsing of names such that any additional whitespace characters between non-whitespace characters are taken only to be 1. For example, the following names A NAME, A NAME or A NAME will be parsed to be A NAME. Extra spaces are likely to be an error by the user and in the real world, these extra whitespace characters are taken to be a single space. This enhancement applies to patient names, vaccination names, allergy names and vaccination group names.
Emptying vaccination history requirement
Currently when a vaccination has been added, there is no way to update its history requirement to become empty if it is not. The --set true argument flag is only able to replace the entire history requirement list with another that is not empty.
We plan to enhance this by adding an additional flag to vaccination’s edit --empty SHOULD_EMPTY where SHOULD_EMPTY is of boolean type with a default value of false. The presence of this argument in the vaccination edit command will cause the history requirement of the vaccination to be emptied.
The enhancement will also be implemented such that if both --h and --empty argument were to appear in the same edit command, the command will not be processed and an error message will be shown. This is the protect the user’s data from unintended changes.
Stricter date validation fo days of month
We plan to implement a stricter date validation checks for dates. The stricter check will disallow dates fo months that exceeds the number of days in that month. For example 2023-2-31 (2023 Feb 31 as February does not have 31 days) will be disallowed. These invalid dates will show an error message, informing the user that the date is invalid.