By: Team T09-3
Since: Sep 2019
Licence: MIT
- 1. Introduction
- 2. Setting up
- 3. Design
- 4. Implementation
- 5. Documentation
- 6. Testing
- 7. Dev Ops
- Appendix A: Product Scope
- Appendix B: User Stories
- Appendix C: Use Cases
- Appendix D: Non Functional Requirements
- Appendix E: Glossary
- Appendix F: Product Survey
- Appendix G: Instructions for Manual Testing
ClerkPro is an appointment and queue management system targeted at clerks working in small clinics. This developer guide is organised in a top-down approach, beginning with the Architecture Design. You may jump to any section by clicking on the heading in the contents page.
Refer to the guide here.
The Architecture Diagram given above explains the high-level design of ClerkPro. Given below is a quick overview of each component.
-
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 method where necessary.
Commons
represents a collection of classes used by multiple other components.
The following class plays an important role at the architecture level:
-
LogsCenter
: Used by many classes to write log messages to the App’s log file.
The rest of the App consists of four components.
API : Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, OmniPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class.
The UI
component uses 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.
API :
Logic.java
-
Logic
uses theSystemCommandParser
class to parse the user command. -
This results in a
Command
object which is executed by theLogicManager
.-
A
Command
object can be classified as one of two types, aReversibleCommand
and aNonActionableCommand
. -
A
ReversibleCommand
refers to any command which modifies the data in the system’s model. To enable the user to revert their changes, the actions of such commands needs to be reversible. -
Conversely, a
NonActionableCommand
only reads data from the system’s model without modifying it.
-
-
The command execution can affect the
Model
(e.g. adding a patient).-
If the user intends to execute a reversible command, a
ReversibleActionPairCommand
is created and pushed into an undo stack. This action pair command contains a pairing of of the action itself and its inverse. (e.g. Pairing 'add person A' and 'delete person A' command). -
If the user intends to execute a
NonActionableCommand
, the command will be directly executed.
-
-
The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
. -
In addition, the
CommandResult
object can also instruct theUi
to perform certain actions, such as displaying help to the user. -
Handles the mutli-threading of reactive search requests by the user.
-
When the user is searching for an existing entry, the system will attempt to filter through the results as the user types.
-
Each key stroke will trigger a new reactive search request which is processed on a separate thread. This is done to avoid lagging the UI.
-
If a new reactive search request is triggered before the previous request has been completed. The previous request thread will be interrupted before the new request thread is allowed to be executed.
-
The execution of a reactive search differs from the normal command, in the way that it only allows the execution of
NonActionableCommand
types. Hence, there is no modification of any data in the system’s model when executing a reactive search.
-
Given below is the Sequence Diagram for interactions within the Logic
component for the enqueue E0000001A
API call.
API : Model.java
The Model
,
-
stores a
UserPref
object that represents the user’s preferences. -
does not depend on any of the other three components:
Logic
,Ui
, andStorage
. -
consists of 3 sub-components:
QueueManager
,AddressBook
andAppointmentBook
. -
stores the details of patients and staff in 2 separate instances of
AddressBook
. -
stores the patients' appointments and duty shifts of staff doctors in 2 separate instances of `Appointment Book.
-
exposes an unmodifiable
ObservableList<Person>
andObservableList<Event>
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. -
stores a unique list of
Tags
andReferenceId
, whichPerson
can reference. This would allowAddress Book
to only require oneTag
object per uniqueTag
, instead of eachPerson
needing their ownTag
object.
The QueueManager
,
-
stores a
QueueList
object that represents the queue. -
stores a
UniqueElementList<Room>
which represents a list of consultation rooms where staff doctors are stationed.
The AddressBook
,
-
stores a
Person
object that, depending on its usage, can represent either a staff doctor or patients. -
stores a
UniquePersonList
which represents a list of all registered doctors or patients.
The AppointmentBook
,
-
stores a
Event
object that, depending on its usage, can represent either a patient’s appointment and staff duty shift. -
stores a
UniquePersonList
which represents a list of all registered appointments or shifts.
API : Storage.java
The Storage
component,
-
saves
UserPref
objects in json format and read it back. -
saves and read data of the particulars of patients and doctors in json format.
-
saves and read data of the Appointments and duty shifts data in json format.
JsonAddressBookStorage
class is reused to store the details of both doctors and patients.
Likewise, the JsonAppointmentBookStorage
class can be reused to store the details of both staff duty shifts and patient’s appointments.
This section describes some noteworthy details on how certain features are implemented.
In ClerkPro, each person is assigned a unique ReferenceId
.
Appointments and duty shifts are tagged to the respective patients and doctors through the use of ReferenceId
.
This unique reference identifier consist of two parts:
-
a unique case-insensitive string, which consist of 9 alphanumeric characters, referring to its unique ID
-
a boolean referring to whether the reference identifier belonged to a person who is registered as a patient or a staff doctor.
The undo/redo feature allows users to revert the action of a command or redo a command action that has been undone.
A Command can be classified as one of two types, a ReversibleCommand
or NonActionableCommand
.
A ReversibleCommand
refers to any command which modifies the data stored by the system.
Conversely, a NonActionableCommand
only reads data from the system’s model without modifying it.
By pairing of two ReversibleCommand
commands together, we can describe an action that has the undone.
This pairing is encapsulated as a ReversibleActionPairCommand
, which consists of
two ReversibleCommand
classes: the command to be executed and its inverse.
Consider that our appointment management system provides the user the ability to
add, cancelling and reschedule an appointment using the commands named
AddApptCommand
, CancelApptCommand
, EditApptCommand
respectively.
By executing the CancelApptCommand
, we can mimic the undo functionality of the AddApptCommand
,
which is simply cancelling the same appointment the AddApptCommand
had scheduled.
The following activity diagram describes the sequence of events when a user executes a new command:
The undo/redo mechanism is facilitated by the CommandHistoryManager
class, which is found in the logic
component.
The history stores actions that can be undone as a ReversibleActionPairCommand
and implements the following operations:
-
CommandHistoryManager#addToCommandHistory()
— Saves the most recent command that modifies the system’s model in its undo history. -
CommandHistoryManager#performUndo()
— Performs the inverse operation to restore the system to its previous state. -
CommandHistoryManager#performRedo()
— Restores a previously undone state by re-executing the respective undone command. -
CommandHistoryManager#canUndo()
— Checks if there are previous states to be restored -
CommandHistoryManager#canRedo()
— Checks if the a previously undone state can be restored
These operations are all contained within the Logic
component and do not depend on any other components.
On initialisation of the application, the undo and redo stack of the CommandHistoryManager
would be empty.
As the user executes commands that modifies the data stored by the system, the commands invokes CommandHistoryManager#addToCommandHistory()
and are pushed in the undo stack of the CommandHistoryManager
.
Given below is an example usage scenario and how the undo/redo mechanism behaves.
Step 1. Suppose that the user has already executed several commands earlier, with the latest command being newpatient … -name John Doe
,
which registers a patient named 'John Doe'.
Step 2. The user now decides that adding the patient was a mistake, and decides to undo that action by executing the undo
command.
The undo command will call CommandHistoryManager#performUndo()
, which in turn
invokes the UnregisterPatientCommand
which reverts the system to its previous state.
ℹ️
|
The lifeline for UndoCommand should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
|
An empty undo stack implies that there are no previous states to be restored.
The undo
command uses Model#canUndoAddressBook()
to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.
After the successful execution of the UnregisterPatientCommand
command,
the action from the top undo stack is transferred to the top of the redo history stack.
Conversely, the redo
command does the opposite — it calls CommandHistoryManager#performRedo()
which restores the address book to that state by invoking the original command again.
Similarly, if the commandRedoHistory
is empty, then there are no undone states to restore. The redo command uses Model#canRedoAddressBook()
to check if this is the case.
If so, it will return an error to the user rather than attempting to perform the redo.
Step 3. The user then decides to execute the command patient S9482963D
.
A command that searches for a patient whose id matches S9482963D
,
only reads and does not modify any data from the model.
Such commands will not invoke CommandHistoryManager#addToCommandHistory()
,
CommandHistoryManager#performUndo()
, CommandHistoryManager#performRedo()
.
Thus, the undo and redo stacks remain unchanged.
Step 4. The user executes newappt …
to schedule a new appointment for a patient.
This action invokes CommandHistoryManager#addToCommandHistory()
, pushing the new action pair command in the undo stack.
However, the commands in the redo stack will be purged.
We designed it this way because it no longer makes sense to redo the newpatient … -name John Doe
command.
This is the behavior that most modern desktop applications follow.
The main concept behind reactive searching is to provide feedback to the user of their search results for
a given keyword as they type. However, filtering larger data sets may be a time consuming process.
Hence, the queries are processed on a separate thread to avoid blocking the UI
thread.
This is achieved in two phases:
Similar to eager evaluation, Reactive Search attempts to process commands if it does not mutate the storage. Otherwise it does a simple redirect to the tab relevant to the command.
After which, changes to the ObservableList will trigger the updateItem listener in UI. And since each graphical update is fast and can only be executed from the JavaFX main application thread, we defer each of them via Platform.run() so that the FX main application thread can execute them in order whenever it is free.
class EventListViewCell extends ListCell<Event> {
@Override
protected void updateItem(Event event, boolean empty) {
super.updateItem(event, empty);
if (empty || event == null) {
Platform.runLater(() -> setGraphic(null));
} else {
Platform.runLater(() -> setGraphic(new EventCard(event, getIndex() + 1, displayStatus).getRoot()));
}
}
}
Hence, this ensures the main FX application thread is always polling for user inputs or graphical updates and handles them rapidly as they are lightweight tasks.
If the UI
triggers another reactive search request before previous request is completed,
the thread of the previous request is first interrupted and joined to the thread of the new request.
Only after the previous thread has been successfully interrupted, the new request will be processed.
This is done to ensure that the UI thread only displays the results of the latest request.
We are using Prefix Tree which is known as a Trie for AutoComplete. This gives us a worst case time complexity of O(m), where m is length of the search string. While the space complexity is O(bm), where b is number of unique characters used, m is length of longest word stored.
-
Alternative 1 (current choice): Using Trie (as known as Prefix Tree).
Pros
1. Search Time Complexity Efficient: O(m), where m is length of searched word.
2. One of the most natural data structure for text prediction.Cons
1. Requires initialisation.
2. Requires rebuilding of strings. -
Alternative 2: Using ArrayList.
Pros
1. Extremely simple to implement.
Cons
1. Search Time Complexity Inefficient: O(nm), where n is number of words and m is length of searched word.
The queue feature allows the user to enqueue and dequeue a patient from the queue.
-
e.g.
enqueue 003A
- Enqueues the patient withreferenceId
003A. -
e.g.
next 1
Serves the next patient in queue and allocates him/her to room 1.
Queue supports a few basic commands:
-
Enqueue — Enqueues a patient into the queue.
Format:enqueue <PATIENT_REFERENCE_ID>
-
Dequeue — Dequeues a patient from the queue.
Format:dequeue <QUEUE_INDEX>
-
Next — Assigns the next patient in the queue to a doctor.
Format:next <ENTRY_ID>
-
Break — Avoids directing patients to a doctor. e.g. Doctor is on a lunch break
Format:break <ENTRY_ID>
-
Resume — Allows patients to be directed to a doctor. e.g. Doctor is back from his/her break.
Format:resume <ENTRY_ID>
The queue will be displayed in a list.
The following activity diagram summarizes what happens when a user executes an enqueue command:
The following activity diagram summarizes what happens when a user executes a next command:
Below is an example usage of the queue feature.
Step 1: User enters the enqueue E0000001A
command.
Step 2: The command then calls Model#enqueuePatient to enqueue the patient into the queue.
Step 3: Patient will then displayed in the queue.
The Appointment feature enables users to manage appointments for patients by providing basic Create, Read, Update, Delete (CRUD) of appointments. User is also able to find missed appointments and settle each missed appointment efficiently.
The number of scheduled appointments cannot be more than the number of on-duty staff doctors at any given time.
The current appointment feature is implemented using a list which works like a balanced binary search tree. This allows us to search for an appointment within O(logn) instead of O(n) time, where n is the number of appointments in the list.
The Appointment feature contains multiple operations to indirectly manipulate the UniqueEventList
. The implemented operations include:
newappt
Command - Creates an new appointment or reoccurring appointments for a patient.
ackappt
Command - Acknowledges an appointment whenever the patient checks in with the clerk.
appointments
Command - Lists all upcoming appointments or appointments which involves the patient whose referenceId contains a certain keyword.
editappt
Command - Edits an appointment timing.
cancelappt
Command - Cancels an appointment.
missappt
Command - Lists all missed appointments.
settleappt
Command - Removes a missed appointment.
The appointment class diagram below illustrates the interactions between the Appointment class and associated classes.
The appointment will be rejected by the system, if there are insufficient staff doctors on duty at the time of the appointment.
Each Appointment
object consists of a PersonReferenceId
, Timing
, Status
. Timing
class has 2 DateTime
objects which indicates the start and end time of the appointment
. The UniqueEventList
contains 0 or more appointments.
The current implementation of Appointment
checks with patient
object by the unique referenceId
and also checks the timing with doctors' dutyRoster. If the referenceId
exists within the Model#UniquePersonList and the timing is valid, then the Appointment
object is constructed. This ensures that the patient is registered before making any appointments and the appointment’s timing is valid.
The appointment will be rejected by the system, if there are insufficient staff doctors on duty at the time of the appointment.
Before an appointment can be scheduled, the system first checks the total number of staff doctors on duty in that timeslot. Next, the system checks the existing appointments in that timeslot. If the number of appointments in that timeslot is less than the number of doctors, the appointment will be scheduled. Otherwise, the appointment will not be scheduled.
The newappt
command is similar to the new
command of patient and doctor. The command takes in the parameters required to construct ReferenceId
, DateTime
and Status
. The image below shows how the Appointment
object is constructed.
The following activity diagram summarizes what happens when a user executes a newappt
command:
The ackappt
command marks the patient’s the most upcoming appointment as acknowledged only if it is on the same day and it is before the appointment’s end time and also updates UniqueEventList
to display the rest appointments belonging to the patient.
The appointments
command works in two different ways.
Case 1: appointments referenceId
The appointments
command searches for appointments that belong to the patient based on the given referenceId
. The filtered appointments are found in ModelManager
. The list is instantiated by filtering the UniqueEventList
using EventContainsKeywordPredicate
which is created from the ReferenceId
argument supplied by the user.
Case 2: appointments
If the appointments
command is executed without any other arguments, it executes with the predicate EventContainsApprovedStatusPredicate
. updateFilteredAppointmentList() is called and the entire list of upcoming appointments is shown to the user.
The following activity diagram summarizes what happens when a user executes a editappt
command:
cancelappt
simply takes in the index of the target appointment to cancel according to the displayed appointment list.
Given below is the sequence diagram for interactions within the Logic
component for the execute("cancelappt 1")
API call.
The missappt
command displays appointments that patients did not attend. The filtered appointments are found in ModelManager
. The list is instantiated by filtering the UniqueEventList
using EventsMissedPredicate
which checks all APPROVED-Status appointments' end times with current time.
The settleappt
command helps users to remove any missed appointments once users have settled it. It will also update UniqueEventList
to display the rest of the missed appointments.
In future implementations, i.e. v2.0, the valid timing slot will be given based on the doctor’s availability. This ensures users can easily choose a slot to arrange appointments for patients.
-
Alternative 1 (current choice): Create
DateTime
andTiming
class to storePros
1. Makes it easier to calculate timings and clashes between multiple appointments with different timing field.
Cons
1. Requires additional code to implement Timing class and interact with other common methods that rely on DateTime.
-
Alternative 2: Store as Strings
Pros
1. Makes it easier to implement.
Cons
1. Requires additional code to convert into
DateTime
class when carrying out calculating methods.
-
Alternative 1 (current choice): Display appointments in a tab
Pros
1. Creates an intuitive and easily navigable screen to display appointments.
Cons
1. Decreases the efficiency of CLI by having to use GUI inputs.
-
Alternative 2: Keeps the onscreen clutter at a minimum and stays in line with the CLI concept.
Pros
1. Makes it easier to implement.
Cons
1. Increases difficulty in freely accessing appointments.
The duty shift scheduling provides users the ability to schedule duty shifts for doctors. It can help doctors to check, add, edit duty shifts efficiently.
The duty shift scheduling contains multiple operations to indirectly manipulate the UniqueEventList
. The implemented operations include:
newshift
Command - Adds a duty shift or reoccurring duty shifts to a doctor.
shifts
Command - Lists all duty shifts involving the doctor’s referenceId which contains the keyword.
editshift
Command - Change a current duty shift’s timing.
cancelshift
Command - Cancels duty shift.
Each Duty Shift is an Event
object consists of a PersonReferenceId
, Timing
, Status
. Timing
class has 2 DateTime
object as they indicate the start and end times of the duty shift.
The current implementation of duty shift checks with doctor object by the unique referenceId
and also checks the timing with appointments. If the referenceId
exists within the Model#UniquePersonList and the timing is valid, then the duty shift is constructed. This ensures that the doctor is registered and the duty shift’s timing is valid before making any duty shifts.
The duty shift will be rejected by the system, if there are insufficient staff doctors on duty at the given time.
Before a duty shift’s time can be edited, the system first checks the total number of staff doctors on duty in that timeslot. Next, the system checks the existing appointments in that timeslot. If the number of appointments in that timeslot is less than the number of doctors, the duty shift’s time will be changed. Otherwise, the duty shift will not be allowed to edit.
The newshift
command behaves similarly to the new
command used for patient and doctor. The command takes in the parameters required to construct ReferenceId
, DateTime
and Status
.
The shifts
command works in two different ways.
Case 1: shifts ReferenceId
The shifts command searches for duty shifts that belong to the doctor based on the given ReferenceId
. The filtered shifts are found in ModelManager
. The list is instantiated by filtering the UniqueEventList
using EventContainsKeywordPredicate
which is created from the referenceId
argument supplied by the user.
Case 2: shifts
The shifts command behaves similarly to shifts ReferenceId
when it does not take in any other arguments. Instead, it automatically executes with the predicate EventContainsApprovedStatusPredicate
. updateFilteredEventList() is called and the entire list of the upcoming duty shifts is shown to the user.
The following activity diagram summarizes what happens when a user executes a editshift
command:
We are using java.util.logging
package for logging. The LogsCenter
class is used to manage the logging levels and logging destinations.
-
The logging level can be controlled using the
logLevel
setting in the configuration file (See Section 4.9, “Configuration”) -
The
Logger
for a class can be obtained usingLogsCenter.getLogger(Class)
which will log messages according to the specified logging level -
Currently log messages are output through:
Console
and to a.log
file.
Logging Levels
-
SEVERE
: Critical problem detected which may possibly cause the termination of the application -
WARNING
: Can continue, but with caution -
INFO
: Information showing the noteworthy actions by the App -
FINE
: Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size
Refer to the guide here.
Refer to the guide here.
Refer to the guide here.
Target user profile:
-
has a need to manage a significant number of patients and doctors
-
is a clerk/receptionist working at a small clinic
-
prefer desktop apps over other types
-
can type fast
-
prefers typing over mouse input
-
is reasonably comfortable using CLI apps
Value proposition: manage queue and appointments faster than a typical mouse/GUI driven app
Priorities: High (must have) - * * *
, Medium (nice to have) - * *
, Low (unlikely to have) - *
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
|
new user |
see usage instructions |
refer to instructions when I forget how to use the App |
|
clerk |
find out the upcoming appointments for given patients |
|
|
clerk |
update the doctors' details by typing commands and user details |
|
|
clerk |
add new doctors into system |
|
|
clerk |
edit patients' details |
keep their particulars up to date |
|
clerk |
register new patients with optional fields |
|
|
clerk |
add ad-hoc patients to the queue |
|
|
clerk |
search for patients using their name or phone number |
|
|
clerk |
look up how many patients are in the queue, on a side panel |
recommend estimated time that the patient will be attended to |
|
clerk |
look up patient using a reference id |
|
|
clerk |
reschedule appointments of patients |
|
|
clerk |
search for appointment slots easily |
schedule appointments for patients easily |
|
clerk |
assign a queue number to each patient in the queue |
|
|
clerk |
use the appointment scheduler |
schedule appointments for my patients |
|
clerk |
add reoccurring appointments |
schedule new reoccurring appointments for my patients |
|
clerk |
save time managing the queue |
have more time to do my own work |
|
clerk |
take note of the doctors that are on-shift |
effectively direct patients to available doctors |
|
clerk |
remove a patient from the queue if they leave. |
|
|
clerk |
view the number of patients who visited the clinic today |
|
|
clerk |
schedule patient’s follow up appointments |
|
|
clerk |
find all patients who have missed their appointments |
keep track of the list of patients whom I need to inform |
|
clerk |
see relevant information only |
so that my focus is not lost |
|
clerk |
use auto-complete to predict my commands |
save time on verifying its existence and correctness |
|
clerk |
quick-fill the command box with the suggestions of Auto-Complete |
so that it reduces typing of the entire command |
|
clerk |
refer to command history |
review entered commands that maybe incorrect |
|
clerk |
quick-fill the command box with history commands |
inputting last few commands is easier |
|
receptionist |
use the undo and redo feature |
to remedy any mistakes |
|
clerk |
acknowledge appointments if patients are present for their appointments |
keep track of patients who came for their appointments |
|
clerk |
tag patient with known allergies |
keep track of their allegies |
|
clerk |
cancel appointments for patients |
free up appointment time slots |
(For all use cases below, the System is the ClerkPro
and the Actor is the user
, unless specified otherwise)
MSS
-
New patient arrives at the clinic
-
User wants to add new patient into the queue
-
System adds the patient into the queue
Use case ends.
Extensions
-
2a. User inputs invalid format
-
2a1. System requests for correct input format.
Use case resumes at step 2.
-
MSS
-
Patient wants to leave
-
User requests to remove patient from the queue
-
System removes the patient from queue
Use case ends.
Extensions
-
2a. Person is not in queue
Use case ends.
-
3a. The given index is invalid.
-
3a1. System shows an error message.
Use case resumes at step 2.
-
MSS
-
Patient exits from room 1
-
User requests to allocate patient into room 1
-
System removes the patient from queue and allocates him/her to room 1
Use case ends.
Extensions
-
2a. Doctor is resting
Use case ends.
-
3a. The given index is invalid.
-
3a1. System shows an error message.
Use case resumes at step 2.
-
MSS
-
User requests to avoid directing patients to the doctor in room 1
-
System sets the doctor to be on break
Use case ends.
Extensions
-
1a. Doctor is already on break
-
1a1. System shows an error message.
Use case ends.
-
-
2a. The given index is invalid.
-
2a1. System shows an error message.
Use case resumes at step 1.
-
Pre-condition: Doctor is on break
MSS
-
User requests to start directing patients to the doctor in room 1
-
System sets the doctor to be on duty
Use case ends.
Extensions
-
1a. Doctor is already on duty
-
1a1. System shows an error message.
Use case ends.
-
-
2a. The given index is invalid.
-
2a1. System shows an error message.
Use case resumes at step 1.
-
Pre-condition: Patient exists in the system
MSS
-
Patient wants to have a new appointment
-
User wants to add a appointments for the patient
-
ClerkPro adds this appointment
Use case ends.
Extensions
-
2a. User inputs invalid format
-
2a1. ClerkPro requests for correct input format
-
2a2. User inputs correct format
Steps 2a1-2a2 are repeated until the appointment has the correct format
-
Use case resumes at step 2
-
2b. User inputs a appointment which is conflicted with other appointments and the appointment cannot be assigned to a doctor as all doctors has other appointments with other patients at that time.
-
2b1. User ask patient to make provide a new appointment timing
-
2b2. patient give a new appointment date
Steps 2b1-2b2 are repeated until the appointment is not conflicted
Use case resumes at step 2.
-
Pre-condition: Patient’s appointment exists and Application is displaying the patient’s list of appointments
MSS
-
User provides a new time slots for a current apointment to change.
-
ClerkPro updates the appointment date of the patient.
Use case ends.
Extensions
-
2a. Current appointment date is invalid format
-
2a1. ClerkPro requests for correct input format
-
2a2. User inputs correct format
Steps 2a1-2a2 are repeated until the appointment has the correct format
-
-
2b. Appointment date is conflict with other appointments
-
2b1. User ask patient to make a new appointment
-
2b2. patient change appointment to another date
Steps 2b1-2b2 are repeated until the appointment is not conflicted
Use case resumes at step 2
-
MSS
-
User requests to find patient’s appointment list
-
System retrieve and display patient’s appointments
Use case ends.
Extensions
-
2a. patient is not exist
-
System displays an error message "No such patient"
-
Use case ends
Pre-condition: Patient’s record exists
MSS
-
User requests to retrieve patient’s appointment list
-
System finds and display patient’s appointments
-
User request to cancel patient’s appointment’s timing.
-
System updates patient’s appointments and patient’s appointment list
-
System displays success message of cancelling appointment’s timing
Use case ends.
Extensions
-
2a. The system cannot find the requested patient’s record
-
2a1. System displays an error message. "No such appointment"
-
Use case ends
Pre-condition: Details of the doctor is already registered in system.
MSS
-
User finds the doctor using either his/her name or staff id.
-
User assigns the on-duty doctor to a consultation room.
-
System updates the ui to display the available consultation rooms and doctors.
Use case ends.
Extensions
-
2a. Consultation room has already been taken.
-
2a1. System shows an error message. Informing the user that the room has already been assigned to another doctor.
-
-
Use case ends.
-
2b. Doctor has already been assigned to a consultation room.
-
2b1. System shows an error message. Informing the user that the doctor has already been assigned to a room.
-
-
Use case ends.
Actor: Clerk
Guarantees:
-
Display suggestions of commands available from whatever has been typed.
-
Autofill of commands selected from AutoCompleter into Command Box.
MSS:
-
Clerk types "a" into the Command Box.
-
ClerkPro shows suggestions of commands available for "a".
-
Clerk selects a command from AutoCompleter.
-
ClerkPro auto-fills the selected command into Command Box.
Use case ends.
Actor: Clerk
Guarantees:
-
Autofill of commands while traversing History.
MSS:
-
If AutoCompleter is not suggesting, Clerk can traverse history commands.
-
While traversing, the command box is auto-filled with the history command.
Use case ends.
-
Should work on any mainstream OS as long as it has Java
11
or above installed. -
Should be able to hold up to 1,000,000 persons and 1,000,000 events without noticeable lag in User Interface within typical usage.
-
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.
-
No internet required.
-
System allows user to undo incorrect or accidental destructive actions
-
App can be downloaded and run via a jar file
Given below are instructions to test the app manually.
ℹ️
|
These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing. |
-
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. If window settings underpreferences.json
is corrupted and becomes reasonably small or large, the default size of 800x600 will be used instead.
-
-
Editing a patient while certain patient(s) have been searched.
-
Prerequisites: Search for an interested person via
patient [<SEARCH_KEYWORD>]
then press kbd:[ENTER]. -
Test case:
editpatient -entry 1 -name test
Expected: All patients will be listed again with the particular patient of index found after searching has his or her name modified totest
.
-
-
Dealing with missed/corrupted data files
-
Prerequisites: Removing or Modifying files in data folder residing in same directory as
ClerkPro.jar
. -
Test case: Deleting the entire data folder.
Expected: ClerkPro will attempt to access the folder. If it does not exists, the data folder will be automatically created with default settings. Other jsons besidepreferences.json
will be created upon modification of sample data loaded. -
Test case: Corrupting data files by modifying its entries.
Expected: ClerkPro will try its best to parse the data. If it is not valid, it must be corrupted. Therefore the application will load up with default settings and sample data.
-
-
Navigating with keyboard only
-
Test case: kbd:[TAB] key should change focus from the upper panels to Command Box and Command Box to Tab Bar.
Expected: When TabBar or Command Box is in focus, there should exist an indication of turquoise/blue border. -
Test case: Both kbd:[UP] and kbd:[DOWN] keys should also work even if the selected item is of the first or last index.
Expected: When UP is pressed during a selected item in the list view or Tab Bar is of first index, it should brings the selection to the last index of the list view or Tab Bar. Vice versa for the last index when selected.
-
-
AutoComplete
-
Test case: *Any partial commands with leading spaces.
Expected: AutoComplete appears in an aligned overlay showing available commands for whatever has been typed. -
Test case:
newpatient -id
with any number of leading spaces but at least one ending space(s).
Expected: AutoComplete does not suggest any other flags because its previous word is in a flag format. -
Test case:
newpatient -id Mo-name
with any number of leading spaces but at least one ending space(s).
Expected: SinceMo-name
is not a flag, AutoComplete should suggest all unused flags but not-id
. -
Test case: Lengthy Command in Command Box reaching the right-most end of the Command Box.
Expected: AutoComplete will display all suggestions visibly at the right-most end but will lose the perfect alignment since its impossible to align any further while staying visible to the user. -
Test case: kbd:[UP] & kbd:[DOWN] & kbd:[ENTER] while focus is still on the Command Box.
Expected: The selection should change according to kbd:[UP] & kbd:[DOWN]. While kbd:[ENTER] should set the selected tag into the Command Box, instead of executing the unfinished Command.
-
-
History
-
Prerequisites:
-
Some commands that has been entered regardless if it is invalid or valid.
-
Command Box is focused.
-
AutoComplete is not in action.
-
-
Test case: Press kbd:[UP] then kbd:[DOWN]
Expected: Upon kbd:[UP], current text in Command Box is replaced with previously entered command. Then after, pressing kbd:[DOWN] displays an empty command box since the last text that was in the Command Box is not entered and thus not part of history.
-