Developer Guide
About OmniHealth
OmniHealth is a Patient Management System designed specifically for private clinicians to manage their patients’ information, records, and scheduled appointments. OmniHealth allows its users to manage and monitor their patient database from a single location. Furthermore, users can use OmniHealth’s sorting and filtering tool to conveniently manage and find their patients’ details and records of previous visits. Additionally, OmniHealth’s appointment tracker allows users to tag upcoming appointments for each patient.
This Developer Guide explains in detail how OmniHealth is developed and implemented. It begins with an overview of OmniHealth’s system architecture, then breaks it down into smaller components and provides detailed descriptions for each component, and ultimately explains the reasoning behind how key functionalities of this application are implemented. As a developer, you can utilise this guide to maintain and update OmniHealth.
Table of Contents
- Acknowledgements
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
-
Appendix: Instructions for manual testing
- Launch and shutdown
- Displaying a patient’s record list
- Adding a record
- Editing a record
- Find a record in a patient’s record list
- Undo a find command
- Deleting a record
- Clearing all records from a patient’s record list
- Adding an appointment to a patient
- Removing an appointment from a patient
- Saving data
- Appendix: Effort
Acknowledgements
- Adapted from AB3 https://github.com/nus-cs2103-AY2223S1/tp
- Icon was adapted from Eatlogos https://www.eatlogos.com/download-logo/vector-medical-logo/96
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 delete 1
.
Each of the four main components (also shown in the diagram above),
- defines its API in an
interface
with the same name as the Component. - implements its functionality using a concrete
{Component Name}Manager
class (which follows the corresponding APIinterface
mentioned 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 consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, PersonListPanel
, RecordListPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class which captures the commonalities between classes that represent parts of the visible GUI.
The UI
component uses the JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that are in the src/main/resources/view
folder. For example, the layout of the MainWindow
is specified in MainWindow.fxml
The UI
component,
- executes user commands using the
Logic
component. - listens for changes to
Model
data so that the UI can be updated with the modified data and display the correct panel. - keeps a reference to the
Logic
component, because theUI
relies on theLogic
to execute commands. - depends on some classes in the
Model
component, as it displaysPerson
andRecord
object residing in theModel
.
Logic component
API : Logic.java
Here’s a (partial) class diagram of the Logic
component:
How the Logic
component works:
- When
Logic
is called upon to execute a command, it uses theAddressBookParser
class to parse the user command. - This results in a
Command
object (more precisely, an object of one of its subclasses e.g.,AddCommand
) which is executed by theLogicManager
. - The command can communicate with the
Model
when it is executed (e.g. to add a person). - The result of the command execution is encapsulated as a
CommandResult
object which is returned back fromLogic
.
The Sequence Diagram below illustrates the interactions within the Logic
component for the execute("delete 1")
API call.
DeleteCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Here are the other classes in Logic
(omitted from the class diagram above) that are used for parsing a user command:
How the parsing works:
- When called upon to parse a user command, the
AddressBookParser
class creates anXYZCommandParser
(XYZ
is a placeholder for the specific command name e.g.,AddCommandParser
) which uses the other classes shown above to parse the user command and create aXYZCommand
object (e.g.,AddCommand
) which theAddressBookParser
returns back as aCommand
object. - All
XYZCommandParser
classes (e.g.,AddCommandParser
,DeleteCommandParser
, …) inherit from theParser
interface so that they can be treated similarly where possible e.g, during testing.
Model component
API : Model.java
The Model
component,
- stores the address book data.
- all
Person
objects (which are contained in aUniquePersonList
object) - all
Record
objects (which are contained in aRecordList
object)
- all
- stores the currently ‘selected’
Person
objects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Person>
that can be ‘observed’ e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change. - likewise, the currently ‘selected’
Record
objects are stored as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Record>
that can be ‘observed’. - stores a
UserPref
object that represents the user’s preferences. This is exposed to the outside as aReadOnlyUserPref
objects. - does not depend on any of the other three components (as the
Model
represents data entities of the domain, they should make sense on their own without depending on other components)
Tag
list in the AddressBook
, which Person
references. This allows AddressBook
to only require one Tag
object per unique tag, instead of each Person
needing their own Tag
objects.Storage component
API : Storage.java
The Storage
component,
- can save both address book data and user preference data in json format, and read them back into corresponding objects.
- inherits from both
AddressBookStorage
andUserPrefStorage
, which means it can be treated as either one (if only the functionality of only one is needed). - depends on some classes in the
Model
component (because theStorage
component’s job is to save/retrieve objects that belong to theModel
)
Common classes
Classes used by multiple components are in the seedu.addressbook.commons
package.
Implementation
This section describes the details on how certain noteworthy features are implemented.
About Patient Records
OmniHealth manages patient records generated during patient consultations. Each
Patient
holds a list of medical records that the user is able to modify and edit. TheRecord
class encapsulates a medical record that comprises a date, medical information and medicine prescribed (if any).
Add record feature
Implementation
Following the command execution pathway, the implementation of adding records uses the exposed Model#addRecord(Record)
operation in the Model
API which operates through a DisplayedPerson
which encapsulates the current patient whose list of records is being
displayed to the user. Record operations are performed through the displayed person, for example,DisplayedPerson#addRecord(Record)
.
The current patient can be set by DisplayedPerson#setPerson(Person, AddressBook)
.
The parsing of user input is facilitated by AddRecordCommandParser
. AddRecordCommandParser#parse()
parses user
input string to return a AddRecordCommand
object with a Record
derived from the given inputs.
Given below is an example usage scenario.
Precondition: User should be currently viewing a specific patient’s record list using the rlist
command. The current
patient is set using DisplayedPerson#setPerson(Person, AddressBook)
.
Execution: User executes radd d/01-02-2013 1230 r/Patient developed fever. m/Paracetamol
to add a new record containing
the date/time of 01-02-2013 1230
, medication remark of Patient developed fever.
and medication prescription of
Paracetamol
into the current displayed person’s record list. The radd
command calls Model#addRecord(Record)
which performs the adding of records to the DisplayedPerson
held by the Model
.
The following sequence diagram shows how the add record operation works:
Design considerations:
Aspect: Model-Person Interaction:
-
Alternative 1 (current choice): Use DisplayedPerson as a wrapper class.
- Pros: Maintain immutability within Person and Model classes, Easy to set current person whose record list is being displayed
- Cons: Longer command execution pathway as DisplayedPerson acts as an intermediary class between Model and Person.
-
Alternative 2: Allow model to directly interact with Person’s record list.
- Pros: Easy to implement, simpler command execution pathway.
- Cons: Potentially violates OOP.
List records feature
Implementation:
The implemented list records mechanism is facilitated by ListRecordCommandParser
, which extends AddressBookParser
. ListRecordCommandParser
implements the following operations:
-
ListRecordCommandParser#parse()
- Parses the input argument into anIndex
and creates a newListRecordCommand
object with the parsedIndex
.
The ListRecordCommand
object then communicates with the Model
API when it is executed, more specifically, by calling the following methods that are implemented in ModelManager
:
-
Model#setPersonWithRecords(Person)
- Sets the person whose record list is being displayed (ModelManager#personWithRecords
) to the givenPerson
, so that the displayed record list can be manipulated by calling methods such asModel#addRecord()
andModel#deleteRecord()
. -
Model#setRecordListDisplayed(boolean)
- Setter for a flag to determine if a record list is being displayed; set totrue
. -
Model#setFilteredRecordList(Person)
- Sets the filtered list of records (ModelManager#filteredRecords
) to the record list of the given Person. -
Model#updateFilteredRecordList(Predicate)
- Updates the filter of the filtered list of records to the filter given by the predicate; analways true
predicate is given so that all records will be included in the filtered list.
At the final step of the execution of the ListRecordCommand
object, a CommandResult
object is returned.
The Sequence Diagram below shows how the list record operation works:
Example usage scenario:
- Precondition: The user should be viewing the patient list by using the
list
command. - Execution: The user executes
rlist 1
to list the records of the 1st patient in the displayed patient list.
Delete record feature
Implementation:
The delete record mechanism is facilitated by DeleteRecordCommandParser
which extends AddressbookParser
.
DeleteRecordCommandParser
implements the following operations:
-
DeleteRecordCommandParser#parse()
- Parses the input argument into anIndex
and creates a newDeleteRecordCommand
object with the parsedIndex
.
The DeleteRecordCommand
object then communicates with the Model
API when it is executed, more specifically, by calling the following methods that are implemented in ModelManager
:
-
Model#getFilteredRecordList()
- Returns the record list which is displayed. -
Model#isRecordListDisplayed()
- Returns a boolean result if a record list is being displayed. -
Model#deleteRecord(Record)
- Deletes the input record from the DisplayedPerson (Model#personWithRecords
).
Given below is an example usage scenario for the command.
- Precondition:
- User should be currently viewing a specific patient’s record list using the
rlist
command. - The current patient is set using
DisplayedPerson#setPerson(Person, AddressBook)
.
- User should be currently viewing a specific patient’s record list using the
- Execution:
- User executes
rdelete 1
to delete the 1st record in the displayed record list. Therdelete
command callsModel#deleteRecord(Record)
which performs the deletion of records from theDisplayedPerson
held by theModel
.
- User executes
Edit record feature
Implementation:
The edit record mechanism is facilitated by EditRecordCommandParser
which extends AddressbookParser
.
EditRecordCommandParser
implements the following operations:
-
EditRecordCommandParser#parse()
- Parses the input argument by storing the index and respective prefix as inArgumentMultimap
The EditRecordCommand
object then calls createEditedRecord
and communicates with the EditRecordDescriptor
to create
a new editedRecord
to replace the Record
that is to be edited.
The EditRecordCommand
object then communicates with the Model
API when it is executed, more specifically,
by calling the following methods that are implemented in ModelManager
:
-
Model#setRecord(Record, Record)
- Sets the target record ofModel#personWithRecords
to the new edited record. -
Model#updateFilteredRecordList(Predicate<Record>)
- Updates the filter of the filtered record list to filter by the given predicate; in this case, show all the records.
Given below is an example usage scenario for the command.
- Precondition:
- User should be currently viewing a specific patient’s record list using the
rlist
command. - The current patient is set using
DisplayedPerson#setPerson(Person, AddressBook)
.
- User should be currently viewing a specific patient’s record list using the
- Execution:
- User executes
redit 1 r/Fever d/12-12-2012 1200 m/
to set the 1st record in the displayed record list to a new record containing the date/time of12-12-2012 1200
, record data ofFever
and sets the medications to empty.
- User executes
Find records feature
Implementation:
While the find patient function only searches the name field, the find record function searches for Record
objects
based on multiple specified search parameters namely the recorddata
, medications
and recorddate
field. This is done using
the rFind
command implemented in the FindRecordCommand
class which is facilitated by helper classes
RecordContainsKeywordPredicate
and FindRecordCommandParser
which extends Predicate
and AddressbookParser
respectively. The following operations are implemented for the rfind
command:
-
FindRecordCommandParser#parse()
- Parses the input arguments by extracting the required arguments and creates a newFindRecordCommand
with the correct inputs. -
RecordContainsKeywordPredicate#test()
- Tests whether the record under testing contains any of the keywords in the correct fields.
Only FindRecordCommandParser#parse
is exposed in the Parser interface as Parser#parse().
Given below is an example usage and how the find record mechanism works at each step.
- Precondition:
- User should be currently viewing a specific patient’s record list using the
rlist
command. - The current patient is set using
DisplayedPerson#setPerson(Person, AddressBook)
.
- User should be currently viewing a specific patient’s record list using the
- Execution:
- User executes
rfind m/Paracetamol d/10-2022
. - The input is parsed by the
AddressBookParser#Parse()
which callsFindRecordCommandParser#parse()
. Here, the input
is checked for which are the fields that have been specified. AFindRecordCommand
object is then created containing aRecordContainsKeywordPredicate
that represents the search parameters to match aRecord
object to. - The record list that is being displayed is implemented using an
FilteredList
. This means that theRecordContainsKeywordPredicate
object can be passed into theFilteredList#setPredicate()
method. This tests eachrecord
object stored inside the record list. - The record list that is displayed is updated to only show
record
objects that pass the test.
- User executes
The following sequence diagram demonstrates how the find record mechanism works:
The following activity diagram demonstrates what happens when a find record command is used:
Design Considerations:
Aspect: The effect of multiple search parameters
-
Alternative 1 (current choice): More search parameters tightens the search constraints
- Pros: The user is able to narrow down the search to easily find a specific record. This is especially useful when the record list becomes very large. For example, searching by medication alone may not be very effective since medications like Paracetamol are commonly prescribed. Instead, it will be more useful to specify which month was a particular medication prescribed.
- Cons: A record may become more difficult to find if the user does not remember the correct details regarding what is stored in the record.
-
Alternative 2: More search parameters loosens the search constraints
- Pros: Searching for multiple records that may not share commonalities in the data stored becomes easier.
- Cons: Scenerios where this would be useful may not occur frequently.
Aspect: How an unspecified field is represented
Since the search parameters are optional, there is a problem during parsing of differentiating between a parameter that is not specified and a parameter that is not specified but is left blank.
-
Alternative 1 (current choice): A specific String is used to replace the value of a parameter that is not specified
- Pros: Since this string acts as an identifier that the parameter is valid even though it was empty, it is easy to implement.
-
Alternative 2: Use a boolean value to represent if a parameter is specified by the user input
- Pros: This is relatively simple to implement.
- Cons: This requires constant checks by multiple classes to test if the parameter has been specified and thus breaks the abstraction barrier.
Clear all records feature
The clear record command rclear
allows the application to clear all the existing records in the current active record
list.
Implementation:
Given below is an example usage scenario for the command.
Step 1: The user launches the application.
Step 2: The user executes the rlist INDEX
command to show the record list of a specified patient.
Step 3: The user executes the rclear
command to clear all existing records in the record list.
About Appointment Features
Each
Patient
holds an appointment reference for record keeping that the user is able to edit and clear. There is currently no support for the automatic removal of appointments which dates have passed.
Past appointments needs to either be overwritten by a new appointment or be cleared with theapptcl
command.
Add appointment feature
The add appointment feature allows OmniHealth to manage future appointments for patients.
Implementation:
The add appointment command mechanism is facilitated by the AddAppointmentCommandParser
class which extends the AddressbookParser
.
AddAppointmentParser#parse()
is exposed in the Parser interface as Parser#parse().
AddAppointmentParser
implements the following operations:
-
AddAppointmentParser#parse()
- Parses the input arguments by storing the index and the prefix of its respective values as anArgumentMultimap
, and creates a newAddAppointmentCommand
object with the parsed time and index.
The AddAppoinmentCommand
object then communicates with the Model
API by calling the following methods:
-
Model#setPerson(Person, Person)
- Sets the person in the existing patient list to the newPerson
object which has been edited byAddAppointmentCommand#execute()
. -
Model#updateFilteredPersonList(Predicate)
- Updates the view of the application to show all patients.
The method AddAppointmentCommand#execute()
returns a CommandResult
object, which stores information about the completion
of the command.
The diagram below details how the operation of adding an appointment works.
Given below is an example usage scenario for the command.
Step 1: The user launches the application.
Step 2: The user executes the appt INDEX d/ dd-MM-yyyy
command in the CLI.
Step 3: An appointment will be assigned to the patient specified with the index input.
Design considerations:
Aspect: Model-Person Interaction:
-
Alternative 1 (current choice): Utilise
model#setPerson
to add the edited person into the model, doing the direct editing inAddAppointmentCommand#execute()
.- Pros: Maintain immutability within Person and Model classes.
- Cons: Potentially violates the Single Responsibility Principle.
-
Alternative 2: Create methods in model specifically to edit the appointment fields of the patients.
- Pros: More OOP, follows the Single Responsibility Principle by not having
AddAppointmentCommand#execute()
perform the editing directly. - Cons: Longer command execution, requiring more parts to work together.
- Pros: More OOP, follows the Single Responsibility Principle by not having
Clear appointment feature
Implementation:
The add appointment mechanism is facilitated by ClearAppointmentCommandParser
which extends AddressbookParser
.
ClearAppointmentParser
implements the following operations:
-
ClearAppointmentParser#parse()
- Parses the input arguments by storing the index and the prefix of its respective values as anArgumentMultimap.
ClearAppointmentParser#parse()
is exposed in the Parser interface as Parser#parse().
Given below is an example usage scenario for the command.
Step 1: The user launches the application.
Step 2: The user executes the apptcl INDEX
command in the CLI.
Step 3: The patient’s appointment(if any) will be cleared.
Below is an activity diagram illustrating an example process of how the Appointment
commands can be utilised.
[Proposed] Upcoming appointment tracker feature
The proposed upcoming appointment feature will be a display to show upcoming appointments for the user upon application start.
Proposed Implementation
The proposed implementation is facilitated by AppointmentWindow
. It extends UiPart<Stage>
with a new window.
Given below is an example usage scenario for the command.
Step 1: The user launches the application.
Step 2: A additional window appears, showing the current upcoming appointments.
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- private clinic practitioners who do not have access to general health service management applications like Healthhub
- private clinic practitioners of clinics who still utilise physical paper records to store patient information
- is reasonably comfortable typing
- has a need to manage a significant number of records
- has a need to find a particular record quickly
Value proposition: OmniHealth is a patient database management tool that centralises and digitalises medical record storage. This makes finding specific details of a patient as well as inputting new details easy and fast.
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 | view the entire list of patients | see all my patients I have added. |
* * * |
user | add a new patient and their details | save them for later viewing |
* * * |
user | delete an existing patient and their details | remove an inactive patient |
* * * |
user | edit a new patient and their details | change the personal particulars of that patient |
* * |
user | find an existing patient’s details | know more about the patient |
* * |
user | clear the patient list | save time by not deleting one by one |
* * * |
user | view a specific patient’s records | remember past visits recorded |
* * * |
user | add a patient’s record | store details of the patient’s visit for the future |
* * * |
user | edit a patient’s record | change details of a record in the future |
* * * |
user | delete a patient’s records | remove a particular patient’s medical records upon request. (E.g. due to privacy reasons) |
* * |
user | find a patient’s record | avoid manually scrolling through multiple records to get to the record that I want |
* * |
user | clear all of a patient’s records | save time by not deleting one by one |
* * |
user | clear the search parameters | view the whole list of patients or records |
* * * |
new user | view the user guide easily | learn more about the product usage |
* * |
schedule-oriented user | add appointments scheduled for a patient | keep track of my appointments |
* * |
schedule-oriented user | clear an appointment of an existing patient | stop seeing reminders of a past appointment |
* |
schedule-oriented user | see upcoming appointments as a popup upon starting Omnihealth | better plan my schedule for the day |
* |
schedule-oriented user | receive notifications about upcoming appointments | be reminded of my schedule during a busy day |
* * * |
new user | view the user guide easily | learn more about the product usage |
* * * |
user | exit the program |
Use cases
(For all use cases below, the System is the OmniHealth
and the Actor is the user
, unless specified otherwise)
Use case: UC01 - Add a patient
Precondition: Patient List View is displayed
MSS
- User requests to add a patient with given input fields.
-
OmniHealth adds patients with given fields into the list of patients.
Use case ends.
Extensions
-
1a. The given input fields are invalid.
-
1a1. OmniHealth shows an error message.
Use case ends.
-
Use case: UC02 - Add a record
Precondition: Patient List View is displayed
MSS
- User requests to display record list of specific patient (UC06)
- User requests to add record with given fields into to the patient.
-
OmniHealth adds a record with given fields to the record list of the patient.
Use case ends.
Extensions
-
2a. The given input fields are invalid.
-
2a1. OmniHealth shows an error message.
Use case resumes at step 2.
-
Use case: UC03 - Delete a patient
Precondition: Patient List View is displayed
MSS
- User requests to delete a specific patient in the list
-
OmniHealth deletes the person
Use case ends.
Extensions
- 1a. The list is empty.
-
1a1. OmniHealth shows an error message.
Use case ends.
-
-
1b. The given index is invalid.
-
1b1. OmniHealth shows an error message.
Use case ends.
-
Use case: UC04 - Delete a record
Precondition: Patient List View is displayed
MSS
- User requests to display record list of specific patient (UC06).
- User requests to delete a specific record in the list.
-
OmniHealth deletes the record.
Use case ends.
Extensions
-
2a. The record list is empty.
-
2a1. OmniHealth shows an error message.
Use case ends.
-
-
2b. The given index is invalid.
-
2b1. OmniHealth shows an error message.
Use case ends.
-
Use case: UC05 - List all patients
Precondition: Record List View is displayed
MSS
- User requests to list all patients.
-
OmniHealth shows a list of all patients.
Use case ends.
Use case: UC06 - List all records for a specified patient
Precondition: Patient List View is displayed
MSS
- User requests to display all records for the specified patient.
-
OmniHealth shows a list of all records for the specified patient.
Use case ends.
Extensions
-
1a. The given index is invalid.
-
1a1. OmniHealth shows an error message.
Use case ends.
-
Use case: UC07 - Clear patient list
Precondition: Patient List View is displayed
MSS
- User requests to clear all patients from list
-
OmniHealth deletes patient list
Use case ends
Extensions
-
1a. Patient list is empty
Use case ends
Use case: UC08 - Clear patient records
Precondition: Patient List View is displayed
MSS
- User requests to display record list of specific patient (UC06)
- User requests to clear all records from a patient
-
OmniHealth deletes all patient records
Use case ends
Extensions
- 1a. Patient does not exist
- 1a1. OmniHealth displays error message
Use case ends
-
2a. Patient record list is empty
Use case ends
Use case: UC09 - Find patient
Precondition: Patient List View is displayed
MSS
- User requests to find a patient by name.
- OmniHealth shows a list of all patients matching the input by the user.
Use case: UC10 - Find patient records
Precondition: Patient List View is displayed
MSS
- User requests to display record list of specific patient (UC06)
- User requests to find a record that matches the input search parameters.
- OmniHealth shows all the relevant records of the specified patient.
Extensions
- 1a. Patient does not exist
- 1a1. OmniHealth displays error message
Use case ends
- 2a. Search parameters are in an invalid format
- 2a1. OmniHealth displays an error message
Use case ends
Use case: UC11 - Add patient appointment
Precondition: Patient List View is displayed
MSS
- User requests to add an appointment with a specified date.
- An appointment is created for the patient.
Extensions
- 1a. Patient list is empty
- 1a1. OmniHealth displays an error message
Use case ends
- 1b. Patient index does not exist
- 1b1. OmniHealth displays an error message
Use case ends
- 1c. Date is specified in wrong formatting
- 1c1. OmniHealth displays an error message
Use case ends
- 1d. Appointment already exists for the patient
- 1d1. Old appointment is overriden by the new appointment
Use case ends
Use Case: UC12 - Clear patient appointment
Precondition: Patient List View is displayed
MSS
- User requests to remove the existing appointment of the patient.
- The specified appointment is removed.
Extensions
- 1a. Patient list is empty
- 1a1. OmniHealth displays an error message
Use case ends
- 1b. Patient index does not exist
- 1b1. OmniHealth displays an error message.
Use Case ends
Use Case: UC13 - Edit a patient’s record
Precondition: Patient List View is displayed
MSS
- User requests to display the record list of specific patient (UC06).
- User requests to edit a record
- OmniHealth replaces the record in the record list with a new edited one
Extensions
-
2a. The record list is empty.
-
2a1. OmniHealth shows an error message.
Use case ends.
-
-
2b. The given index is invalid.
-
2b1. OmniHealth shows an error message.
Use case ends.
-
Use Case: UC14 - Edit a patient’s details
Precondition: Patient List View is displayed
MSS
- User requests to edit a patient’s details
- OmniHealth replaces the patient in the patient database with a new edited one
Extensions
-
1a. The patient list is empty.
-
1a1. OmniHealth shows an error message.
Use case ends.
-
-
1b. The given index is invalid.
-
1b1. OmniHealth shows an error message.
Use case ends.
-
Non-Functional Requirements
- Should work as long as Java
11
or above is installed. - Should store personal particulars of patients in a way that it is not at risk of being leaked.
- Should be able to handle large amounts of data without feeling sluggish.
- Patient list should be able to store up to 500 patients (Target users are small clinics)
- Likewise, Patient Record List should be able to store up to 500 records
- A typist with average typing speed should be able to perform their desired task faster than when using a mouse. (Designed with CLI in mind)
- Should be simple to use for a user that is not proficient with technology. (Target users are used to pen and paper records)
- Should have simple and intuitive commands that can be learned within a few minutes
- Should be more efficient than using paper records.
- Finding a patients information using Omnihealth is faster than manaully searching for it.
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
- MSS: Main success scenerio
- GUI: Graphical user interface
- CLI: Command line interface
- Address book: The component of Omnihealth that stores all patients and information related to a patient
- Patient: A patient of the clinic using Omnihealth
- Person: A model representing a patient
- Doctor: A doctor working at the clinic using Omnihealth
- (Patient) Record: Digital copy of a patient’s record stored by Omnihealth
- Paper Records: Physical copy of a patient’s record
- Patient List: A list of patients stored by Omnihealth
- Patient List View: A viewing mode that shows the patient list
- Record List View: A viewing mode that shows the record list
- (Patient) Record List: A list of a patient’s records stored by Omnihealth
- Appointment: Date of the next visit of the patient
Appendix: Instructions for manual testing
Given below are instructions to test the app manually.
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.
-
Displaying a patient’s record list
-
View a particular patient’s record list while all persons are being shown
-
Prerequisites: Patient List is currently displayed. At least 1 patient in the list. If record list is displayed instead, use the
list
command. -
Test case:
rlist 1
Expected: Record list of the patient at index 1 will be displayed instead of the patient list. -
Test case:
rlist 0
Expected: Patient list remains displayed. Error details shown in the status message. -
Other incorrect delete commands to try:
rlist
,rlist x
,...
(where x is larger than the list size)
Expected: Similar to previous.
-
Adding a record
-
Add a record to a particular patient’s record list
-
Prerequisites: Record List is currently displayed. If the patient list is displayed instead, use the
rlist
command. -
Test case:
radd d/31-10-2022 1430 r/suffers from common cold m/Paracetamol 500mg
,radd d/31-10-2022 1430 r/suffers from common cold
Expected: Details of the record added will be shown in the status message. Record list will be updated to include the added record -
Test case:
radd
Expected: No record is added. Error details shown in the status message. Record list remains the same. -
Other incorrect delete commands to try:
radd d/x r/suffers from common cold
,...
(where x is in an invalid datetime format)
Expected: Similar to previous.
-
Editing a record
-
Edit an existing record in a particular patient’s record list
-
Prerequisites: Record List is currently displayed. At least 1 record in the list. If the patient list is displayed instead, use the
rlist
command. -
Test case:
redit 1
,redit 1 d/31-10-2022 1430 r/suffers from common cold m/Paracetamol 500mg
Expected: Details of the selected record in the record list will be edited and displayed. The updated details of the selected record is then shown in the status message. -
Test case:
redit
Expected: No record is edited. Error details shown in the status message. Record list remains the same. -
Other incorrect delete commands to try:
redit d/x r/suffers from common cold
,...
(where x is in an invalid datetime format)
Expected: Similar to previous.
-
Find a record in a patient’s record list
-
Find an existing record in a particular patient’s record list
-
Prerequisites: Record List is currently displayed. If the patient list is displayed instead, use the
rlist
command. -
Test case:
rfind d/10-2022
,rfind r/suffers from common cold
rfind m/Paracetamol 500mg
Expected: The record list will display all records matching the search parameters. The number of matching records will be shown in the status message. -
Test case:
rfind
Expected: No record is edited. Error details shown in the status message. Record list remains the same. -
Other incorrect delete commands to try:
rfind d/x r/suffers from common cold
,...
(where x is in an invalid datetime format)
Expected: Similar to previous.
-
Undo a find command
-
Undo a find command (either
find
orrfind
)- Test case:
showall
,showall 123
,showall abc
Expected: If a record list is displayed, a record list containing all records is shown. If a patient list is displayed, a patient list containing all patients is shown instead. A Status message indicating a successful command execution will be displayed.
- Test case:
Deleting a record
-
Delete a record from a particular patient’s record list
-
Prerequisites: Record List is currently displayed. At least 1 record in the list. If the patient list is displayed instead, use the
rlist
command. -
Test case:
rdelete 1
Expected: Details of the deleted record will be shown in the status message. Record list will be updated to exclude the deleted record. -
Test case:
rdelete 0
Expected: No record is deleted. Error details shown in the status message. Record list remains the same. -
Other incorrect delete commands to try:
rdelete
,rdelete x
rdelete 1 r/record
,...
(where x is in an out of bound/invalid index)
Expected: Similar to previous.
-
Clearing all records from a patient’s record list
-
Clear all records from a particular patient’s record list
-
Prerequisites: Record List is currently displayed. If the patient list is displayed instead, use the
rlist
command. -
Test case:
rclear
,rclear 1
Expected: A Status message indicating a successful command execution will be displayed. The record list is now empty and there are no records displayed.
-
Adding an appointment to a patient
-
Add an upcoming appointment to a particular patient
-
Prerequisites: Patient List is currently displayed. At least 1 patient in the list. If the record list is displayed instead, use the
list
command. -
Test case:
appt 1 d/01-01-2023 1200
Expected: Details of the appointment set will be shown in the status message. The specified patient in the patient list will be updated to include the upcoming appointment. -
Test case:
appt 0
Expected: No appointment is added. Error details shown in the status message. Patient list remains the same. -
Other incorrect delete commands to try:
appt
,appt 1 d/x
,...
(where x is in an invalid datetime format or before the current date)
Expected: Similar to previous.
-
Removing an appointment from a patient
-
Remove an appointment from a particular patient
-
Prerequisites: Patient List is currently displayed. At least 1 patient in the list. If the record list is displayed instead, use the
list
command. -
Test case:
apptcl 1
Expected: A Status message indicating a successful command execution will be displayed. The specified patient in the patient list will be updated to not show any upcoming appointment. -
Test case:
apptcl 0
Expected: No appointment is removed. Error details shown in the status message. Patient list remains the same. -
Other incorrect delete commands to try:
apptcl
,apptcl 1 hello
,...
Expected: Similar to previous.
-
Saving data
-
Dealing with corrupted data files
- Prerequisites: The file addressbook.json exists.
- Test case: Edit the data in the file manually from outside Omnihealth.
Expected: Omnihealth starts up as usual. If the data in the file is readable, Omnihealth displays the data. Else, Omnihealth starts up with no data.
-
Dealing with missing data files
- Test case: Delete the adressbook.json file if it exists.
Expected: Omnihealth starts up as usual but displays a blank list since there is no data found.
- Test case: Delete the adressbook.json file if it exists.
Appendix: Effort
- Difficulty Level:
- Overall, we thought the project’s difficulty level was Moderate.
- We implemented a wide range of features with differing degrees of difficulty and complexity.
- We needed a thorough understanding of the system architecture, as this was necessary in order to extend AB-3 in a way that integrates well with the existing design and features of AB-3.
- Challenges Faced:
- Because each member worked on many issues and features, the list below is not exhaustive.
- Having to integrate the list of medical records of a specific patient into the UI, so that the application’s main window can switch between a patient list and a medical record list.
- The records subsystem was constructed on top of the existing AB-3 architecture, which required extensive modification and extensions to obtain the desired final result.
- Due to the large number of possible test cases, the Record and Appointment commands were difficult to test, necessitating further testing and rectification.
- The inconsistency of JavaFX UI elements between platforms necessitates additional manual testing.
- Because each member worked on many issues and features, the list below is not exhaustive.
- Effort Required:
- The current code base has to be heavily modified for our application.
- A large number of test cases were written in order to cover as many possibilities as practical.
- We held comprehensive weekly meetings early in the week to ensure that every developer is well-informed about what is planned for the rest of the week.
- Achievements of the Project:
- Our team created a software product that we believe meets our intended goals.
- All of the Must-have User Stories were met by our software application.
- Our team has met all set milestones and deadlines.