NUStudy uses the following tools for development and testing:
Overview
The command component is centered on the Command interface which defines an execution contract for all commands.
Each command implements this interface and provide its own specific execution logic. This ensures consistent behaviour
across commands.
Implementation details
The following diagram is the class diagram for Command and its subclasses.

The Command interface is implemented by the following command classes:
AddCourseCommand, AddSessionCommandDeleteCourseCommand, DeleteSessionByDateCommand, DeleteSessionByIndexCommandEditCourseNameCommand, EditSessionCommandListCourseCommand, ListCourseHoursPerSessionCommandFilterByDateCommand, FilterByNameAndDateCommand, FilterByNameCommandResetCourseHoursCommand, ExitCommand, HelpCommandMethods
The Command interface defines the following methods:
execute(CourseManager courses, SessionManager sessions): Executes the specific command logic. Takes the course and
session managers as parameters to perform operations. Throws NUStudyException if execution fails.isExit(): Returns a boolean indicating whether the command is an exit command.The following sections provide detailed examples of specific command implementations to illustrate how the Command
interface is used in practice.
Overview
ListCourseCommand is a concrete implementation of the Command interface that lists all courses managed by
CourseManager. It performs basic sanity checks, logs its actions, and delegates the rendering of the course list to
UserInterface.
Implementation details
arpa.home.nustudy.commandpublic class ListCourseCommand implements CommandDependencies:
| Component | Responsibility |
|---|---|
CourseManager |
Provides the collection of courses to be listed. |
SessionManager |
Present for consistency with command signature. |
UserInterface |
Renders the course list or an appropriate message. |
NUStudyException |
Thrown if listing fails (not expected in current impl). |
Logger |
Records info/fine level logs for tracing execution. |
Workflow
The activity diagram below illustrates the ListCourseCommand.execute() flow:

Key steps:
courses and sessions) to catch programming errors early.UserInterface.printCourseList(courses) to render the list.Notes:
-ea). Production callers should
ensure valid arguments.Overview
DeleteCourseCommand is a concrete implementation of the Command interface in the NUStudy system. The primary
function is to handle user requests to delete an existing course by its name from the courses ArrayList managed by
the CourseManager.
This command does the following:
Implementation details
arpa.home.nustudy.commandpublic class DeleteCourseCommand implements CommandDependencies:
| Component | Responsibility |
|---|---|
CourseManager |
Manages the list of existing courses, including lookup and deletion. |
SessionManager |
Provided for command consistency, though not used directly in this class. |
UserInterface |
Displays confirmation messages to the user. |
Storage |
Used as a reference for the logger name. |
NUStudyException |
Thrown for invalid inputs or deletion failures. |
NUStudyNoSuchCourseException |
Thrown when the specified course does not exist. |
Logger |
Provides runtime logging for debug, info, and error tracking. |
Workflow
The following activity diagram illustrates the complete removing course workflow:

Overview
The course component is responsible for representing and managing course-related entities in the NUStudy application.
It consists of 2 main classes:
Course — a class that encapsulates all information about a Course.CourseManager — a class that manipulates and maintains a collection of Course objects.These 2 classes forms the layer for handling the entity of Course. It is responsible for the CRUD of the entity Course.
Implementation details
The following diagram is the class diagram for Course and CourseManger:

The CourseManager class acts as a controller or manager, handling a dynamic list of Course instances using an internal
ArrayList.
Course methods:
The Course class defines the following methods:
Course(String courseName): Constructs a new Course with the given code.getCourseName(): Retrieves the course code attribute of a Course.setCourseName(String courseName): Updates the course code of a Course used for the edit feature.toString(): Returns the course code as a readable string.toStorageString(): Returns the course data formatted for file storage.CourseManager methods:
The CourseManager class defines the following methods:
add(Course course): Adds a Course Object to the list.delete(Course course): Removes a Course Object from the list.getCourses(): Retrieves all courses managed by this class.findCourse(String courseName): Searches for a course by name.iterator(): Returns an iterator to traverse through all courses.Overview
The session component is responsible for representing a study session, and managing the list of existing study sessions.
It consists of 2 main classes:
Session — responsible for representing a study session, which consists of the study session’s logged hours, the
course studied, and the date of the study sessionSessionManager — responsible for managing the list of existing study sessions, and contains helper methods to
query the list of existing study sessionsImplementation details
The following is the class diagram for Session and SessionManager:

The SessionManager class acts as a controller or manager, keeping track of a dynamic list of Session instances
using an internal ArrayList.
Session methods:
The Session class defines the following methods:
Session(Course course, int loggedHours, LocalDate date): Create a new Session for the specified course codegetLoggedHours(): Get logged hours for this sessionsetLoggedHours(int loggedHours): Set logged hours for this sessiongetCourse(): Get course for this sessiongetDate(): Return the date of the sessiongetDateString(): Return a formatted string representation of the datesetDate(LocalDate date): Set the date of the sessiontoStorageString(): Return a string representation to be stored in the data filetoString(): Return a string representation of the course and/or sessionSessionManager methods:
The SessionManager class defines the following methods:
add(Course course, int loggedHours, LocalDate date): Add a study session to the list of study sessionssessionExists(Course course, int loggedHours): Return true if the given course and logged hours exist in the list of
study sessionsgetAllLoggedHoursForCourse(Course course): Get a list of all logged hours for a specific coursegetAllDateStringsForCourse(Course course): Get a list of all dates for a specific courseclearAllSessions(): Clear all study sessions regardless of course from study session listremoveAllSessionsForCourse(Course course): Remove all study sessions associated with the given coursegetSessionCount(): Return the number of sessions in the study session listgetAllSessionsForCourse(Course course): Get a list of all study sessions for a specific courseremoveSession(Session session): Remove a specified session from the study session listremoveAllSessionsByDate(LocalDate date): Remove all study sessions on a specified dateiterator(): Return an iterator to the list of study sessionsOverview
The Storage class is responsible for managing the saving and loading of Course and Study Session to and from the
local machine. NUStudy will load the saved data from the saved txt file if present when starting the application, and
saving all data back to the saved txt file when application exits.
Implementation details
The Storage component consists of the following key classes:
Storage — Main class that handles file I/O operations for saving and loading dataCourse — Represent a course with a name, provides serialisation via toStorageString()Session — Represents a study session linked to a course with logged hours, provides serialisation via
toStorageString()CourseManager — Manages the collection of coursesSessionManager — Manages the collection of study sessionsThe class diagram below illustrates the relationships between these classes:

File format and conventions
Storage creates a NUStudy.txt in the directory ./data when the application first run and performs a save
operation. Subsequent runs of the application will load data from this file.
The storage file is lined-based, with each line representing a single record:
Format:
C <courseName>
S <courseName> <loggedHours>
Where:
C prefix denotes a Course recordS prefix denotes a Session record\t<courseName> is the course identifier<loggedHours> is an integer representing study hoursExamples:
C CS2113
C MA1508E
S MA1508E 6 2025-10-31
S CS2113 2 2025-10-31
S CS2113 5 2025-10-31
This example shows:
Save operation
The following sequence diagram illustrates how data is stored to storage:

Load operation
The following sequence diagrams illustrate how data is loaded from storage:
sd parsing courses or sessions showcases how each line is interpreted and
converted into Course or Session objects.Main load sequence diagram for data loading:

The load(courses, sessions) method in Storage executes the following:
ensureParentDirectoryexists() checks for the parent directory. If non-existent, it attempts to create one using
mkdirs().NUStudy.txt is checked. If it is non-existent, a
note is logged to notify user and empty managers are initialised.BufferedReader is initiailsed to read in contents from the text file line by line.ArrayList<String> object is initialised to collect all ignored entries which will be later displayed to the
user for refrence.Session or Course object creation and insertion into the respective managers.BufferedReader is closed and returns to App.Referenced sequence diagram for parsing logic:

The abstracted logic parsing frame executes the following:
Storage component assigns parsing logic as shown by the opt frame.
C, it calls parseCourse(line) through the DataParser class, constructs a new
Course object and inserts it into the CourseManager instance.S, it calls parseSession(line) through the DataParser class, constructs a
new Session object with its corresponding Course reference and inserts it into the SessionManager
instance if a matching course already exists.NUStudy includes a built-in data validation to protect against corrupted or manually modified storage files.
Validation checks
The following validations are performed on each line during load:
\t (TAB) are flagged as manually injected data-, _, /) for flexibilityHandling invalid entries
The following is executed when invalid entries are detected:
Overview
The reset functionality enables users to clear logged study hours for either all or a specified course. A double confirmation flow is developed to prevent any unintended and thus, accidental deletions.
Implementation details
y or n regardless of capitalisation. This prompt loops until valid input is receivedn is received, reset operation is cancelledsafeword — RESET ALL for all courses and RESET for a specific coursesafeword must strictly be equivalent, else reset operation is cancelledReset workflow
The following activity diagram illustrates the complete reset workflow:

Design considerations
Aspect: Confirmation mechanism
safeword
reset all usageOverview
The exception component package defines a proper hierarchy of custom exceptions used across the NUStudy application
to handle various error conditions gracefully. All exceptions in this package inherit from base class
NUStudyException, which extends the internal Java Exception class.
Implementation details
| Class Name | Description |
|---|---|
NUStudyException(String message) |
Base class for all custom exceptions in NUStudy. |
FutureDateException(String message) |
Thrown when a provided date is in the future. |
NUStudyCommandException(String message) |
Handles invalid or unrecognized user commands. |
NUStudyCourseAlreadyExistException(String message) |
Raised when trying to add a course that already exists. |
NUStudyNoSuchSessionException() |
Thrown when the user enters an invalid or nonexistent session ID. |
WrongDateFormatException(String message) |
Raised when a user inputs an invalid date or unsupported format. |
Design Considerations
Helps students to track their study hours for each course, see gaps and understand what courses to focus on next. Students often struggle to manage study time across multiple courses, leading to missed deadlines. Existing tools can be distracting, requiring internet access, or bloated with unnecessary features.
Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (optional) - *
| Priority | As a… | I want to… | So that I can… |
|---|---|---|---|
* * * |
Organised student | add a new course | track number of hours required for it |
* * * |
Organised student | log study time spent for a specific course | keep track of the amount of time spent studying per module |
* * * |
Organised student | remove a course | keep my study list relevant |
* * * |
Visual learner | be given proper feedback as I manipulate stuff (CRUD) | be visually stimulated and be informed of my actions |
* * * |
Organised student | reset logged hours | know what to focus on next |
UC1 — Add course (MSS)
add <course>list shows itExtensions: missing/invalid input → system prompts; duplicate (case-insensitive) → system rejects
UC2 — Add study session (MSS)
add <course> or add <course> <hours> or add <course> <hours> <date>Extensions: invalid course/date/hours → system shows error
UC3 — List courses / sessions (MSS)
list or list <course>Extensions: no data → empty message
UC4 — Edit session (MSS)
edit <course> <index> <hours> or edit <course> <index> <date>Extensions: invalid course/index/date → system shows error
UC5 — Filter (MSS)
filter <course> or filter <date> or filter <course> <date>Extensions: invalid/ future dates → informative error; no matches → empty message
UC6 — Reset hours (MSS)
reset <course> or reset allRESET, RESET ALL)Technical requirements:
Please refer to the User Guide for the full list of features and instructions on how to use them.
JUnit tests are provided for core components of NUStudy. To run the tests, follow these steps:
./gradlew.bat test
./gradlew test