Developer Guide
- Setting up, getting started
- Design
- Implementation
- Effort
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
Architecture
The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.
.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.
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 five 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. -
State
: Holds the states of the App while the app is active.
The first four components,
- defines its API in an
interface
with the same name as the Component. - exposes its functionality using a concrete
{Component Name}Manager
class (which implements the corresponding APIinterface
mentioned in the previous point.
For state component, it is managed by two classes:
-
StateManager
class which provides general access to the state of the App. -
UIStateManager
class which provides the GUI access to the state of the app.
Example of architecture: The Logic
component (see the class diagram given below) defines its API in the Logic.java
interface and exposes its functionality using the LogicManager.java
class which implements the Logic
interface.
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
.
The sections below give more details of each component.
UI component
API :
Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, PersonListPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class. The Class Diagram below shows the components in greater detail. Each component of the MainWindow is a composition.
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. - Listens for changes to
State
data so that the UI can be updated with the modified data.
The example for observing states is illustrated with the Sequence Diagram below.
The MainWindow
observes the UiStateManager
for any changes to its internal state.
Upon invoking open case 1
, the state changes and the MainWindow
if notified by its Observer
.
It then retrieves the information it requires and displays on its display panel.
Logic component
API :
Logic.java
-
Logic
uses thePivotParser
class to parse the user command. - This results in a
Command
object which is executed by theLogicManager
. - The command execution can affect the
Model
(e.g. deleting a case). - 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.
Given below is the Sequence Diagram for interactions within the Logic
component for the execute("delete case 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.
The case below follows the same execution above. However, the AddCommandParser further calls the AddCaseCommandParser which returns the respective AddCaseCommand, which has been extended from the AddCommand Class.
AddCommandParser
and AddCaseCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Model component
API : Model.java
The Model
,
- stores a
UserPref
object that represents the user’s preferences. - stores the PIVOT data.
- stores the history of PIVOT states.
- exposes an unmodifiable
ObservableList<Case>
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. - does not depend on any of the other three components.
The detailed class diagram for the investigation case package is shown below.
Storage component
API : Storage.java
The Storage
component,
- can save
UserPref
objects in json format and read it back. - can save Pivot’s data in json format and read it back.
State component
API : StateManager.java
, UiStateManager.java
The StateManager
component,
- can set the state for an opened
Case
in the app, denoted by itsIndex
. - can set the state for an opened
Section
in the app, denoted by itsArchiveStatus
. - can set the state for an opened
Tab
in the app, denoted by itsTabState
. - can reset the state.
- can return the state.
- can request the
UiStateManager
to refresh its state.
The UiStateManager
component,
- can set the state for an opened
Case
in the app, denoted by itsIndex
. - can set the state for an opened
Section
in the app, denoted by itsArchiveStatus
. - can set the state for an opened
Tab
in the app, denoted by itsTabState
. - can reset the state.
- can refresh its state.
When the StateManager
modifies its State, it will also call upon UiStateManager
to update its state as well.
This triggers any observation set on the respective State
managers by the other components.
One such example can be found in the UI
component.
Common classes
Classes used by multiple components are in the seedu.pivot.commons
package.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Open Case/Return feature
The open case
command allows the user to open an investigation case listed on the Main Page
in the GUI.
PIVOT then extracts and displays the key information about the Case
in the Case Page
Panel.
Implementation: Open Case
The open case
mechanism is facilitated by OpenCaseCommand
. It extends abstract class OpenCommand
and contains a target Index
of the Case
to be opened.
It implements OpenCaseCommand#execute()
as required in the abstract parent class. The Sequence Diagram below shows how the OpenCaseCommand
works.
As the user invokes open case [INDEX]
, the arguments are passed from the GUI to the Logic
component, which is then passed to the Parser
, implemented by PivotParser
.
In PivotParser
, the arguments are processed and passed onto the OpenCommandParser
to further process the arguments and create a new OpenCaseCommand
.
type
, such as open suspect 1
, OpenCommandParser
will raise and error and display the proper command format for the user.
Upon invoking OpenCaseCommand#execute()
, the class will extract the Case
that is to be opened, and update the state in StateManager
.
Upon observing a change in state, the GUI will then extract the Case
and update its display panel with the case information.
Index
, such as open case -1
, OpenCaseCommand
will raise and error and display the proper command format for the user.
Implementation: Return
The return
mechanism is facilitated by ReturnCommand
.
It allows the user to close the Case Page
panel and return to the Main Page
.
Its implementation is similar to the OpenCaseCommand
except it resets the state in StateManager
instead of setting a state.
Including Documents to PIVOT
Reference class
The Reference
class represents a file location in the directory ./references
of the program. A reference
only
exists if there is a file present at the file location in the user’s local directory. The validity of a
reference
depends on the user’s operating system and the different acceptable file names. A reference
object must
have a valid file name on creation.
Document class
The Document
class represents a file on the user’s local computer. It contains a name
for easy viewing
and a reference
to the file location. It is used for tracking files that are stored in PIVOT and for opening
of documents.
The documents are stored in a list for a particular case and you can only manipulate
documents(adding, deleting, opening) while inside a case
. This is because the program stores a state of which
interface (main page or case) the user is at and will manipulate the documents according to the document list
in that
current case
.
Adding a Document
When a user executes add doc n:name r:reference.txt
, to add a document with the specified name and file reference
to the current “opened” case in the state, AddDocumentCommandParser
will be invoked to parse the
name (prefixed with n:) and reference (prefixed with r:) inputs. The program must be at an “opened” case at this point.
AddDocumentCommandParser
will check for a valid name as well as a valid
reference that exists in the ./references
directory. This is to prevent a user from creating a document when the
program is active when they have yet to include the file in the program’s directory. The appropriate error message
should be returned for a better user experience. It will then successfully create a Document
and
return AddDocumentCommand
AddDocumentCommand
will get the current case
in the program state
and adds the new Document
to this case
.
It will check for duplicated documents at this point as this is where the program accesses the list of documents in the
current state. The model
will then be updated with the updated case
.
The following sequence diagram shows adding a document to the current case:
Deleting a Document
Deleting a document works about the same as adding a document. When a user executes delete doc 2
, to delete the
second document
in the list of documents of the current “opened” case in the state. The program must be at an
“opened” case at this point.DeleteCommandParser
parses the given index as a Index
object and gets the case index
in the current state. It returns DeleteDocumentCommand
if the inputs are valid.
DeleteDocumentCommand
gets the list of documents in the current case using the case index
and checks if the
input index
is within bounds. The check occurs in the Command
rather than DeleteDocumentParser
so that we
can distinguish between ParseException
and CommandException
. The command then removes the specified document
in the list and updates the model
.
The following activity diagram shows a successful delete document operation at a case page:
Design considerations
Aspect: For Reference
object, separate validity (of the String) and existence (of the actual file path) checks.
-
Alternative 1 (current choice): A reference object can be both valid but doesn’t exists at the same time.
- Pros: A document file deletion on the user’s local machine will not affect loading the current cases in the Json file
- Cons: User will only know that the file doesn’t exist when he opens it
-
Alternative 2: A reference object must be both valid and exists to be created.
- Pros: A document is only created when we know there is a valid and existing
Reference
. Easier for testing. - Cons: The program cannot load if there is a missing file (due to external user deletion) which was previously saved in the Json file
- Pros: A document is only created when we know there is a valid and existing
Aspect: Integrate ReferenceStorage
with current Storage Design
-
Alternative 1 (current choice): Separate
ReferenceStorage
to handle allReference
and storage interactions.- Pros: Easier to implement and increases cohesion.
- Cons: More classes and code in the program
-
Alternative 2: Make use of
Config.java
andUserPrefsStorage
to integrateReferenceStorage
such as saving default file paths.- Pros: Makes use of existing infrastructure, lesser code and possibly lesser code duplication.
- Cons: Increased coupling, more prone to bugs and harder to test
Undo/Redo feature
Commands that are able to be undone/redone will implement an interface Undoable
, with the method Undoable#getPage())
.
When a main page command is being undone/redone, PIVOT will return to the main page. The method Undoable#getPage())
informs the caller whether the command is a main page command or a case page command.
The undo/redo feature is facilitated by VersionedPivot
. It has an undo/redo history of PivotState
objects,
stored internally as a pivotStateList
, and a currentStatePointer
.
VersionedPivot
also keeps track of the command that is to be undone/redone as commandResult
, and the corresponding
command message as commandMessageResult
. Both commandResult
and commandMessageResult
will be retrieved from
the PivotState
objects stored in pivotStateList
.
PivotState
stores the current ReadOnlyPivot
as a pivotState
, the corresponding command
that led to that
pivotState
, as well as the commandMessage
displayed to the user when the command was called.
VersionedPivot
will only interact with the Commands via the Undoable
interface.
Additionally, VersionedPivot
implements the following operations:
-
VersionedPivot#canUndo()
— Indicates whether the current state can be undone. -
VersionedPivot#canRedo()
— Indicates whether the current state can be redone. -
VersionedPivot#commit(String commandMessage, Undoable command)
— Saves the current Pivot state, the corresponding command that was called and its command message in its history. -
VersionePivot#undo()
— Restores the previous Pivot state from its history. -
VersionedPivot#redo()
— Restores a previously undone Pivot state from its history. -
VersionedPivot#purgeStates()
— Purges the all the states after the current pointer. -
VersionedPivot#updateRedoUndoResult()
— Updates thecommand
that is being undone/redone and the correspondingcommandMessage
. -
VersionedPivot#isMainPageCommand()
— Indicates whether the current command stored incommandResult
is a main page command by using the methodUndoable#getPage())
ofcommandResult
.
These operations are exposed in the Model
interface as Model#canUndoPivot()
,Model#canRedoPivot()
,
Model#commitPivot(String commandMessage, Undoable command)
, Model#undoPivot()
, Model#redoPivot()
,
Model#getCommandMessage()
and Model#isMainPageCommand()
respectively.
Given below is an example usage scenario and how the undo/redo mechanism behaves at each step.
Step 1. The user launches the application for the first time. The VersionedPivot
will be initialized with the initial PivotState
,
and the currentStatePointer
pointing to that single PivotState
.
Step 2. The user executes delete case 5
command to delete the 5th case in Pivot. The delete case
command calls
Model#commitPivot(String commandMessage, Undoable command)
. This will create a new PivotState
object with
the modified state of Pivot, the delete case command and its command message. This PivotState
object will then be saved in
pivotStateList
. The currentStatePointer
is shifted to the newly inserted PivotState
object.
Step 3. The user executes add case t:Lost Wallet …
to add a new case. The add case
command also calls
Model#commitPivot(String commandMessage, Undoable command)
. This creates another PivotState
object with the
modified Pivot, the add case command and its corresponding command message.
The PivotState
object is saved into pivotStateList
.
Model#commitPivot(String commandMessage, Undoable command)
, so a new PivotState
object will not be created and will not be
be saved into pivotStateList
.
Step 4. The user then decides to open the newly added case and executes the command open case 6
(assuming that the
newly added case is the 6th case in the list). Commands that do not modify Pivot, such as open case
commands, will
not call Model#commitPivot(String commandMessage, Undoable command)
. Thus, the pivotStateList
remains unchanged.
Step 5. The user now decides that adding the case was a mistake, and decides to undo that action by executing the undo
command.
The undo
command will call Model#undoPivot()
, which will update commandResult
to the command being undone, and
commandMessageResult
to the corresponding message to display to the user the exact command that is being undone.
The currentStatePointer
will also be shifted once to the left, pointing it to the previous PivotState
object, and
restores PIVOT to that state.
undo
command uses Model#isMainPageCommand()
to check if this
is the case. If so, it will use StateManager#resetState()
to return PIVOT to the main page. This is done because the
list of cases in the main page changes as a result of the undo, which may affect the case page that is open currently.
For instance, undo might result in the currently open case being removed from PIVOT (like in the above sequence of commands),
and since the case that is open will no longer exist, it is necessary for PIVOT to return to the main page.
currentStatePointer
is at index 0, pointing to the
initial Pivot state, then there are no previous Pivot states to restore. The undo
command uses Model#canUndoPivot()
to check if this
is the case. If so, it will return an error to the user rather than attempting to perform the undo.
The following sequence diagram shows how the undo operation works:
UndoCommand
should end
at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
The redo
command does the opposite — it calls Model#redoPivot()
, which shifts the currentStatePointer
once
to the right, pointing to the previously undone state, and restores Pivot to that state. commandResult
will be updated to
the command being redone, and commandMessageResult
will be updated to the corresponding message in order to display to the
user the exact command that is being redone.
redo
command uses Model#isMainPageCommand()
to check
if this is the case. If so, it will use StateManager#resetState()
to return PIVOT to the main page.
currentStatePointer
is at index
pivotStateList.size() - 1
, pointing to the latest PivotState
object, then there are no undone PivotState
objects to restore.
The redo
command uses Model#canRedoPivot()
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 6. The user executes open case 1
, followed by edit title t:Robbery
. The edit title command calls
Model#commitPivot(String commandMessage, Undoable command)
. Since the currentStatePointer
is not pointing at the end
of the pivotStateList
, all PivotState
objects after the currentStatePointer
will be purged. Reason: It
no longer makes sense to redo the add case t:Lost Wallet …
command. This is the behavior that most modern desktop
applications follow.
The following activity diagram summarizes what happens when a user executes a new command:
Design consideration:
Aspect: How undo executes
-
Alternative 1 (current implementation): Saves the entire Pivot.
- Pros: Easy to implement.
- Cons: May have performance issues in terms of memory usage.
-
Alternative 2: Individual command knows how to undo by
itself.
- Pros: Will use less memory (e.g. for
delete case
, just save the case being deleted). - Cons: We must ensure that the implementation of each individual command are correct.
- Pros: Will use less memory (e.g. for
Archiving cases
The archiveStatus
field of each Case
determines whether a case is archived or not archived.
The archiveStatus
is ArchiveStatus.ARCHIVED
if archived, and ArchiveStatus.DEFAULT
if not archived.
Implementation: Archive case
The archive case
command allows the user to archive an investigation case listed in the Main Page
of the Home
section in the GUI.
The specified case will be removed from the list in the Home
section and added to the Archive
section in the GUI.
The archive case
command mechanism is facilitated by ArchiveCommand
. It extends the abstract class Command
and contains
a Index
of the Case
to be archived. It implements the ArchiveCommand#execute()
operation as required in the abstract parent class.
The Sequence Diagram below shows how the ArchiveCommand
works.
The user inputs the command archive case 1
and the arguments are passed to the Logic
component.
PivotParser
processes the provided input and passes the arguments to ArchiveCommandParser
to be processed.
If the command is of a valid format, a new ArchiveCommand
will be created.
archive c 1
, ArchiveCommandParser
will raise an error and display the proper command format for the user.
Upon invoking ArchiveCommand#execute()
, the class will extract the Case
to be archived as specified by the Index
provided.
A new Case
with the same details will be created, except the archiveStatus
field which will be set as ArchiveStatus.ARCHIVED
.
The case to be archived will be deleted from the model
and the new Case
object will be added to the model.
Thus, we have ensured that the Case
is effectively archived.
The GUI will be updated correspondingly, with the archived case being removed from the Home
section. The archived case will
appear in the Archive
section when users input list archive
.
Implementation: Unarchive case
The unarchive case
command allows the user to unarchive an investigation case listed in the Main Page
of the Archive
section in the GUI.
The specified case will be removed from the list in the Archive
section and added to the Home
section in the GUI.
The archive case
command mechanism is facilitated by UnarchiveCommand
. It extends the abstract class Command
and contains
a Index
of the Case
to be unarchived. It implements the UnarchiveCommand#execute()
operation as required in the abstract parent class.
The Sequence Diagram below shows how the UnarchiveCommand
works.
The unarchive case
command works in a similar manner to the archive case
command,
except that it sets the newly created Case
object’s archiveStatus
as ArchiveStatus.DEFAULT
before
adding it to the model
.
Implementation: List case and List archive
The GUI is split into the Home
section and the Archive
section.
By using the commands list case
and list archive
, users can switch between the two sections and interact
with the cases at that particular section.
The list archive
command mechanism is facilitated by ListArchiveCommand
. It extends the abstract class ListCommand
.
It implements the ListArchiveCommand#execute()
operation as required in the abstract parent class.
The Sequence Diagram below shows how the ListArchiveCommand
works.
Upon invoking ListArchiveCommand#execute()
, the StateManager
will be notified via the StateManager#setArchivedSection()
method, which will update and store the program’s state to be in the Archive
section.
The filtered case list in model will also be updated with the predicate to show archived cases.
This predicate checks for the archiveStatus
of cases, taking those that are ArchiveStatus.ARCHIVED
.
With this update, the GUI will also be automatically updated, bringing the program to the Archive
section
and listing all archived cases.
To switch back to the Home
section, users can input the list case
command. The list case
command works in a similar manner
to the list archive
command, but now, the filtered case list in model
will be updated with the predicate to show all unarchived cases,
and the StateManager
will be notified that the program’s state is the Home
section now.
Design consideration:
Aspect: How to consider a case as archived, and list archived cases.
-
Alternative 1 (current implementation): Store as an enum field in
Case
and make use of appropriate predicates to show the cases- Pros: Easier to implement.
- Cons: Do not have two separate lists for archived and unarchived cases, which results in more checks needed for other
functionalities like
find
command.
-
Alternative 2: Store archived cases and unarchived cases as two different lists in
Model
.- Pros: More clarity in terms of which cases are being shown, hence other functionalities are less likely to be affected from the implementation. This could result in less bugs.
- Cons: Difficult to implement this as we need to take into consideration the parsing of JSON files, and the creation of two lists on startup.
Effort
The original AB3 is a one-layered implementation, where users can only interact with one list of items, such as adding and deleting items.
In PIVOT, we adopt a two-layer approach, which increases the complexity of the project.
In the Main Page
, users can interact with the list of Cases
they see, such as adding and deleting a Case
.
Then, they can open a specific Case
, opening up the Case Page
which shows the details of the Case
. They can interact with that particular Case
, such as adding Documents
, Suspects
etc.
This approach required us to consider the design of the program carefully, so as to ensure that we are able to
successfully open the correct Case
, and ensure that the program is at the correct state each time, so that
only valid commands can be used. This led to the decision of a StateManager
class to handle the states of the program.
Various new features are also implemented.
The new Open Document
feature allows users to easily open Documents
that are stored in our program. The implementation of this feature
meant that we had to create a references
folder on start-up, as well as properly store the file paths of the Documents
.
The implementation of the feature had to be carefully designed, as we had to consider the different ways a user might use
the program and handle them properly such that the program will not crash (e.g. if the user deletes a document that they added to PIVOT).
The Archive
feature also required a careful consideration of the design alternatives, so as to show a different view in the GUI.
We also had to consider how this feature would affect the existing commands.
Much thought and effort has been given to the design of this project, and enhancements have been made to the existing features as well. The new features added will also increase the effectiveness of the program.
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- police investigators who require an organisational tool
- has a need to manage a significant number of investigation cases
- prefer a structured app to organise information related to their cases
- prefer desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
- has a basic understanding of file paths to manage his/her files
Value proposition:
A lot of detectives use physical folders, whiteboards to consolidate their investigation information. This uses up a lot of physical resources such as printing papers. There may also exist cluttered information across multiple cases. This leads to disorganisation of evidence and documents during investigations, which makes it difficult to link the investigation together. Furthermore, physically looking through archive files can be time-consuming, and they might miss out important information in the process.
PIVOT can help to better organise investigation cases and group the relevant information on a digital platform. This helps investigators to manage and easily locate the required information. It also links up relations between people for better visualisation of the case so that detectives will not miss any information.
PIVOT can assist to manage investigation cases 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… |
---|---|---|---|
* * * |
investigator | create investigation cases with a relevant title | store resources inside |
* * * |
investigator | archive my cases | organize and store records that are not relevant to me now |
* * * |
investigator | restore my cases from the archive | update past records when there is new information |
* * * |
investigator | view the list of investigation cases that I’m currently handling | get an overview of the cases that I have |
* * * |
investigator | view the list of investigation cases stored in the archive | retrieve past cases that I have |
* * * |
investigator | open individual investigation cases | view the relevant details of that case |
* * * |
investigator | find for cases using their case details | quickly retrieve cases based on my search terms |
* * * |
investigator | indicate a state for different cases (e.g. closed/in-progress/cold case) | easily see the status of my cases |
* * * |
investigator | add a description to an investigation case | capture key information about the investigation case |
* * * |
investigator | delete investigation cases | delete unwanted cases or cases that are wrongly created |
* * * |
investigator | edit the status of a case | update the status of a case to have the most updated information |
* * * |
investigator | add relevant documents to an investigation case | store multiple files related to a case |
* * * |
investigator | view the list of documents in an investigation case | |
* * * |
investigator | edit the documents in an investigation case | give the document another name or change its file reference |
* * * |
investigator | delete irrelevant documents to an investigation case | remove outdated documents |
* * * |
investigator | add relevant suspects to an investigation case | link suspects to an investigation case with their personal information |
* * * |
investigator | view the list of suspects tied to an investigation case | refer to all suspects in an investigation case |
* * * |
investigator | edit the suspects in an investigation case | add or update information pertaining to that suspect |
* * * |
investigator | delete suspects tied to an investigation case | delete irrelevant suspects |
* * * |
investigator | add relevant witnesses to an investigation case | link witnesses to an investigation case with their personal information |
* * * |
investigator | view the list of witnesses tied to an investigation case | refer to all witnesses in an investigation case |
* * * |
investigator | edit the witness in an investigation case | add or update information pertaining to that witness |
* * * |
investigator | delete witnesses tied to an investigation case | delete irrelevant witnesses |
* * * |
investigator | add relevant victims to an investigation case | link victims to an investigation case with their personal information |
* * * |
investigator | view the list of victims tied to an investigation case | refer to all victims in an investigation case |
* * * |
investigator | edit the victims in an investigation case | add or update information pertaining to that victim |
* * * |
investigator | delete victims tied to an investigation case | delete irrelevant victims |
* * * |
new user | view the available functions available in PIVOT | |
* * * |
careless investigator | undo my previous command | quickly remove the changes from my previous command |
* * * |
expert investigator | undo and redo multiple commands | navigate to the state of the program exactly as I need |
* * * |
investigator | close the application when I am done using it | safely exit the application |
Use cases
(For all use cases below, the System is the PIVOT
and the Actor is the user
, unless specified otherwise)
Use case: Add Investigation Case
MSS
- User requests to create a new active investigation case
- User specifies a title.
-
PIVOT adds the new investigation case
Use case ends.
Extensions
- 2a. The title is invalid.
-
2a1. PIVOT shows an error message.
Use case ends.
-
- 2b. User specifies a status for the case.
-
2b1. PIVOT adds the new investigation case
Use case ends.
-
- 2c. User specifies a status for the case.
- 2c1. The status is invalid.
-
2c2. PIVOT shows an error message.
Use case ends.
Use case: List Investigation Case
MSS
- User requests to list investigation cases
-
PIVOT shows a list of investigation cases
Use case ends.
Use case: List Cases in Archive
MSS
- User requests to list investigation cases in the archive
-
PIVOT shows a list of investigation cases in the archive
Use case ends.
Use case: Delete Investigation Case
MSS
- User requests to list investigation cases
- PIVOT shows a list of investigation cases
- User requests to delete a specific investigation case in the list
-
PIVOT deletes the investigation case
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. PIVOT shows an error message.
Use case resumes at step 3.
-
Use case: Archive an investigation case
MSS
- User requests to list investigation cases
- PIVOT shows a list of investigation cases
- User requests to archive a specific case in the list
-
PIVOT moves the investigation case to the archive
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. PIVOT shows an error message.
Use case resumes at step 3.
-
Use case: Restore a Case from the Archive
MSS
- User requests to list investigation cases in the Archive
- PIVOT shows a list of investigation cases in the Archive
- User requests to restore a specific case in the list
-
PIVOT moves the investigation case from the archive to the Home section
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. PIVOT shows an error message.
Use case resumes at step 3.
-
Use case: Find an Investigation Case
MSS
- User requests to list investigation cases
- PIVOT shows a list of investigation cases
- User requests to find a specific investigation case in the list
- User specified search terms
-
PIVOT shows a filtered list of the investigation cases which contain any search term
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
Use case: Find an Investigation Case in the Archive
MSS
- User requests to list investigation cases in the archive
- PIVOT shows a list of investigation cases in the archive
- User requests to find a specific investigation case in the list
- User specified search terms
-
PIVOT shows a filtered list of the investigation cases which contain any search term
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
Use case: Open Investigation Case
MSS
- User requests to list investigation cases
- PIVOT shows a list of investigation cases
- User requests to open a specific investigation case in the list
-
PIVOT navigates to the specified investigation case page
Use case ends.
Extensions
-
2a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. PIVOT shows an error message.
Use case resumes at step 1.
-
Use case: Add Description for an Investigation Case
MSS
- User does (Use case: Open Investigation Case)
- User requests to add a description to the investigation case and specifies a description
-
PIVOT adds the description to the investigation case
Use case ends.
Extensions
- 2a. The description is empty.
-
2a1. PIVOT shows an error message.
Use case resumes at step 2.
-
- 2b. There is already an existing description.
-
2b1. PIVOT shows an error message.
Use case resumes at step 2.
-
Use case: Add Document to Investigation Case
MSS
- User does (Use case: Open Investigation Case)
- User requests to add a document to investigation case, specifies a document name and reference
-
PIVOT adds a new document to the investigation case
Use case ends.
Extensions
- 2a. The name is invalid.
-
2a1. PIVOT shows an error message.
Use case resumes at step 2.
-
- 2b. The reference is invalid.
-
2b1. PIVOT shows an error message.
Use case resumes at step 2.
-
Use case: Add Person[Suspect/Witness/Victim] in Investigation Case
MSS
- User does (Use case: Open Investigation Case)
- User requests to add a person to a specified category (suspect/witness/victim).
- User specifies all the name, sex and phone number of that person.
-
PIVOT adds the person to a specified category (suspect/witness/victim).
Use case ends.
Extensions
- 2a. The given category of person to add is invalid.
-
2a1. PIVOT shows an error message.
Use case resumes at step 1.
-
- 3a. The name is invalid.
-
3a1. PIVOT shows an error message.
Use case resumes at step 3.
-
- 3b. The sex is invalid.
-
3b1. PIVOT shows an error message.
Use case resumes at step 3.
-
- 3c. The phone number is invalid.
-
3c1. PIVOT shows an error message.
Use case resumes at step 3.
-
- 3d. User specifies other optional fields (email address and address).
- 3d1. PIVOT recognizes that fields are invalid.
-
3d1. PIVOT shows an error message.
Use case resumes at step 3.
- 3e. User specifies other optional fields (email address and address).
- 3e1. PIVOT recognizes that fields are valid.
-
3e1. PIVOT adds the person to a specified category (suspect/witness/victim).
Use case ends.
Use case: List Person[Suspect/Witness/Victim] in Investigation Case
MSS
- User does (Use case: Open Investigation Case)
- User requests to list Persons in the case.
-
PIVOT shows a list of Persons in the case.
Use case ends.
Use case: List Document related to Investigation Case
MSS
- User does (Use case: Open Investigation Case)
- User requests to list documents in the case
-
PIVOT shows a list of documents in the case
Use case ends.
Use case: Edit Investigation Case Title
MSS
- User does (Use case: Open Investigation Case)
- User requests to edit the title of the investigation case
- User specifies a title
-
PIVOT updates the title of the investigation case
Use case ends.
Extensions
- 3a. The title is invalid.
-
3a1. PIVOT shows an error message.
Use case ends.
-
Use case: Edit Investigation Case Status
MSS
- User does (Use case: Open Investigation Case)
- User requests to edit the status of the investigation case
- User specifies a status
-
PIVOT updates the status of the investigation case
Use case ends.
Extensions
- 3a. The status is invalid.
-
3a1. PIVOT shows an error message.
Use case ends.
-
Use case: Edit Description for an Investigation Case
MSS
- User does (Use case: Open Investigation Case)
- User requests to edit the description of the investigation case
- User specifies a description
-
PIVOT updates the description of the investigation case
Use case ends.
Extensions
- 3a. The description is empty.
-
3a1. PIVOT shows an error message.
Use case resumes at step 3.
-
Use case: Edit Document to Investigation Case
MSS
- User does (Use case: List Document related to Investigation Case)
- User requests to edit a document to investigation case
- User specifies a document’s index in the list
- User specifies fields(name and reference) that they want to edit
-
PIVOT updates the document with the specified fields
Use case ends.
Extensions
-
1a. The list is empty.
Use case ends.
- 3a. The index is invalid.
-
3a1. PIVOT shows an error message.
Use case resumes at step 3.
-
- 4a. The name given is invalid.
-
4a1. PIVOT shows an error message.
Use case resumes at step 4.
-
- 4b. The reference given is invalid.
-
4b1. PIVOT shows an error message.
Use case resumes at step 4.
-
- 4c. User did not specify any fields to change.
-
4c1. PIVOT shows an error message.
Use case resumes at step 4.
-
Use case: Edit Person[Suspect/Witness/Victim] in Investigation Case
MSS
- User does (Use case: List Person[Suspect/Witness/Victim] in Investigation Case)
- User requests to edit a person of a specified category (suspect/witness/victim).
- User specifies a person’s index in the list
- User specifies fields(name/sex/phone/email/address) that they want to edit
-
PIVOT updates the person of a specified category (suspect/witness/victim) with the specified fields.
Use case ends.
Extensions
-
1a. The list is empty.
Use case ends.
- 2a. The given category of person to add is invalid.
-
2a1. PIVOT shows an error message.
Use case resumes at step 2.
-
- 3a. The index is invalid.
-
3a1. PIVOT shows an error message.
Use case resumes at step 3.
-
- 4a. The fields specified are invalid.
- 4a1. PIVOT recognizes that fields are invalid.
-
4a1. PIVOT shows an error message.
Use case resumes at step 4.
- 4b. User did not specify any fields to change.
-
4b1. PIVOT shows an error message.
Use case ends.
-
Use case: Delete Description for an Investigation Case
MSS
- User does (Use case: Open Investigation Case)
- User requests to delete the description of the investigation case
-
PIVOT deletes the description of the investigation case
Use case ends.
Extensions
- 2a. The case has no description to delete.
-
2a1. PIVOT shows an error message.
Use case resumes at step 2.
-
Use case: Delete Document from Investigation Case
MSS
- User does (Use case: List Document related to Investigation Case)
- User requests to delete a document to investigation case
- User specifies a document’s index in the list
-
PIVOT deletes the document from the list
Use case ends.
Extensions
-
1a. The list is empty.
Use case ends.
-
3a. The given index is invalid.
-
3a1. PIVOT shows an error message.
Use case resumes at step 1.
-
Use case: Delete Person[Suspect/Witness/Victim] in Investigation Case
MSS
- User does (Use case: List Person[Suspect/Witness/Victim] in Investigation Case)
- User requests to delete a person of a specified category (suspect/witness/victim).
- User specifies a person’s index in the list
-
PIVOT deletes the person from the list.
Use case ends.
Extensions
-
1a. The list is empty.
Use case ends.
- 2a. The given category of person to add is invalid.
-
2a1. PIVOT shows an error message.
Use case resumes at step 2.
-
- 3a. The given index is invalid.
-
3a1. PIVOT shows an error message.
Use case resumes at step 3.
-
Use case: Open Document
MSS
- User does (Use case: List Document related to Investigation Case)
- User requests to open a specific document in the list
- User specifies a document’s index in the list to open
-
PIVOT opens the specified document
Use case ends.
Extensions
-
1a. The list is empty.
Use case ends.
- 3a. The given index is invalid.
-
3a1. PIVOT shows an error message.
Use case resumes at step 3.
-
- 3b. The specified document does not exist in the saved reference.
-
3b1. PIVOT shows an error message.
Use case resumes at step 3.
-
Use case: Return to the Main Page
MSS
- User does (Use case: Open Investigation Case)
- User requests to navigate to the main page
-
PIVOT navigates to the main page
Use case ends.
Extensions
- *a. At any time, user can request to navigate to the main page.
- *a1. PIVOT brings the user back to the main page.
Use case ends.
Use case: Exit Application
MSS
- User requests to exit the application
-
PIVOT terminates.
Use case ends.
Use case: Undo command
MSS
- User starts up PIVOT
- User does a command
- User requests to undo the previous command
-
PIVOT reverts the effects of the previous command that can be undone
Use case ends.
Extensions
- 1a. User requests to undo the previous command.
- 1a1. There is no command to undo
Use case ends.
- 2a. User does a command that can be un-done.
- 2a1. User does (Use case: Delete Document from Investigation Case)
- 2a2. User requests to undo the previous command
- 2a3. PIVOT restores the Document which has been deleted by the previous command
Use case ends.
- 2b. User does a command that cannot be undone.
- 2b1. User does (Use case: List Investigation Case)
- 2b2. User requests to undo the previous command
- 2b3. PIVOT is already at its initial state
Use case ends.
Use case: Redo command
MSS
- User does (Use case: Undo command)
- User requests to redo a command
-
PIVOT restores the effects of the previous command that was undone, if any
Use case ends.
Extensions
-
1a. Undo command was successful.
Use case resumes at step 2.
-
1b. There was nothing to undo.
Use case resumes at step 2.
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11
or above installed. - Should be able to hold up to 1000 Cases without a noticeable sluggishness in performance for 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.
- The system should not take above 2 seconds to execute any command.
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
- Investigation Case: The investigation case encapsulating all relevant data the police wants to keep track of
- Investigation Case Tag: The status of the case (Active/In-Progress, Closed, Cold Case)
- Document: An actual document/file stored in the project directory
- Person: Data stored in the investigation case (For suspects, witnesses or victims related)
- File Paths: System Location of the specified file inside the project directory
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
-
Run the command
java -jar pivot.jar
using the Command Line at the home folder. Expected: Shows the GUI with a set of sample cases. 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 running the command
java -jar pivot.jar
using the Command Line at the home folder to start the app.
Expected: The most recent window size and location is retained.
-
Deleting a Case
-
Deleting a Case while all Cases are being shown
-
Prerequisites: List all cases using the
list case
command. Multiple cases in the list. -
Test case:
delete case 1
Expected: First case is deleted from the list. Details of the deleted case shown in the result display. -
Test case:
delete case 0
Expected: No case is deleted. Error details shown in the result display. List of cases remains the same. -
Other incorrect delete commands to try:
delete case
,delete case x
,...
(where x is larger than the list size)
Expected: Similar to previous.
-
Archive
-
Archiving a Case while all Cases are being shown
-
Prerequisites: List all cases using the
list case
command. Multiple cases in the list. -
Test case:
archive case 1
Expected: First case is archived. Details of the archived case shown in the result display. Doing alist archive
should show the archived case at the bottom of the list of archive cases. -
Test case:
archive case 0
Expected: No case is archived. Error details shown in the result display. List of cases remains the same. -
Other incorrect archive commands to try:
archive
,archive case
,archive case x
(where x is larger than the list size)
Expected: Similar to previous. -
Unarchive commands can be tested in a similar fashion, with the prerequisites: List all archived cases using the
list archive
command. Multiple archived cases in the list.
-
Undo
-
Undoing a command
-
Prerequisites: No prior commands entered into the system. PIVOT starts with multiple cases in the list.
-
Test case:
undo
Expected: Nothing is undone. Error details shown in the result display. List of cases remains the same. -
Test case:
add case t:Ang Murders
,open case 1
thenundo
Expected: The added case is removed from the list. PIVOT returns back to the main page. The details of the undone command is shown in the result display. -
Test case:
open case 1
,edit title t:New Title
thenundo
Expected: The edited title is undone and the previous title of the case is displayed. PIVOT remains at the case page. The details of the undone command is shown in the result display.
-
Redo
-
Redoing a command
-
Prerequisites: No prior commands entered into the system. PIVOT starts with multiple cases in the list.
-
Test case:
redo
Expected: Nothing is redone. Error details shown in the result display. List of cases remains the same. -
Test case:
add case t:Ang Murders
,undo
,redo
Expected: The added case is removed from the list. The details of the redone command is shown in the result display. -
Test case:
add case t:Ang Murders
,undo
,add case t:Bishan Theft
,redo
Expected: The commandadd case t:Ang Murders
is not redone. Error details shown in the result display. List of cases remains the same as after theadd case t:Bishan Theft
command is executed.
-
Adding a document
-
Adding a document in a case
-
Prerequisites: Open a case with
open case INDEX
using a valid INDEX. -
Test case:
add doc n:NAME r:REFERENCE
Expected: The given NAME and REFERENCE is valid. New document added to the case and shown in the document list. -
Test case:
add doc n:NAME r:REFERENCE
Expected: The given NAME or REFERENCE is invalid. Error details shown in the result display. New document is not added.
-
Opening a document
-
Opening a document in a case with a document list
-
Prerequisites: Open a case with
open case INDEX
using a valid INDEX and list the documents withlist doc
. Multiple documents being shown. -
Test case:
open doc 1
Expected: The reference of document 1 is valid. The document representing this file opens up in the Desktop. -
Test case:
open doc 1
Expected: The reference of document 1 does not exist. The document representing this file does not open.Error details shown in the result display. -
Test case:
open doc 0
Expected: No document is opened. Error details shown in the result display.
-
Saving data
- Dealing with missing data files for documents
- Prerequisites: PIVOT starts with multiple cases in the list and the file
abc.txt
in the./references
folder. - Steps to simulate:
- A user adds a valid document in PIVOT with reference
abc.txt
usingadd doc n:document r:abc.txt
in an opened case. - The user manually deletes the file
abc.txt
in the./references
folder. - The user tries to open the document using
open doc INDEX
. The given INDEX is the INDEX of the document in the document list.
- A user adds a valid document in PIVOT with reference
- Expected behavior:
- There is no such file and the document is unable to be opened. Error details shown in the result display.
- Prerequisites: PIVOT starts with multiple cases in the list and the file
- Dealing with missing
data
folder which containspivot.json
data file.- Steps to simulate:
- The user deletes the
data
folder and runs the commandjava -jar pivot.jar
using the Command Line at the home folder wherepivot.jar
is located.
- The user deletes the
- Behavior:
- PIVOT creates the sample file
test1.txt
in the./references
folder for the sample data. - The user executes a command
add case t:Ang Robbery
. - The
data
folder will appear in the root directory and contains thepivot.json
file with existing sample data.
- PIVOT creates the sample file
- Steps to simulate: