Developer Guide
CourseBook (v1.6)
Table of Contents
- Acknowledgements
- 1. Introduction
- 2. Setting up, getting started
- 3. Architecture
- 4. UI Component
- 5. Logic Component
-
6. Model Component
- 6.1 Structure and Responsibilities
- 6.2 Data Model
- 6.3 Alternative Model Design
- 6.4 Undo/Redo Implementation
- 6.5 Undo/Redo Example Usage Scenario
- 6.6 Undo Sequence Diagram (Logic Layer)
- 6.7 Undo Sequence Diagram (Model Layer)
- 6.8 Redo
- 6.9 Design Considerations for Undo/Redo
- 6.10 Filtering and Sorting
- 7. Storage Component
- 8. Common Classes
- 9. Implementation Details
- 10. Logging
- 11. Configuration
- 12. Documentation, logging, configuration, dev-ops
- 13. Appendix: Requirements
- 14. Appendix: Effort
- 15. Appendix: Planned Enhancements
- 16. Summary
Acknowledgements
- The features undo and redo were inspired by similar features of the SE-EDU Address Book (Level 4) https://se-education.org/addressbook-level4/
- CourseBook is built upon the AddressBook-Level3 (AB3) foundation created by the SE-EDU initiative
1. Introduction
1.1 About CourseBook
CourseBook is a desktop application designed for university students to efficiently manage their academic network by organizing contacts based on shared courses. It combines the efficiency of a Command Line Interface (CLI) with the intuitiveness of a Graphical User Interface (GUI), making it ideal for fast typists who want quick access to their academic contacts.
Key Features:
- Organize contacts by course enrollment
- Manage favorites for quick access to close friends
- Search across multiple contact fields
- Track birthdays and sort by upcoming birthdays
- Color-code courses for visual clarity
- Comprehensive undo/redo functionality
- Customizable themes
1.2 Purpose of this Guide
This Developer Guide provides comprehensive documentation for developers who wish to:
- Understand the architecture and design decisions behind CourseBook
- Contribute new features or enhancements
- Maintain and debug the existing codebase
- Extend the application for custom use cases
1.3 Target Audience
This guide is intended for:
- Software Engineers working on CourseBook
- Module Tutors evaluating the project design
- Contributors from the open-source community
- Students learning software architecture patterns
2. Setting up, getting started
Refer to the guide Setting up and getting started.
3. Architecture
.puml files used to create diagrams in this document are in the docs/diagrams folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
3.1 High-Level Architecture

Figure 1: The above diagram shows the high-level design of CourseBook with five main components: Main, UI, Logic, Model, Storage, and Commons
The Architecture Diagram above explains the high-level design of the application. CourseBook follows a 4-layer architecture with a shared Commons component containing utility classes used across layers.
Main components of the architecture
Main (consisting of classes Main and MainApp) is responsible for application launch and shutdown.
- At app launch, it initializes the other components in the correct sequence and connects them.
- At shutdown, it saves user preferences and shuts down the other components.
The four main functional components are:
-
UI: The User Interface component that renders the GUI and receives user input. -
Logic: The command executor that parses and executes user commands. -
Model: Holds application data in memory and manages state. -
Storage: Reads data from and writes data to persistent storage (JSON files).
Commons represents a collection of classes used by multiple other components, including logging, configuration management, and utility functions.
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.

Figure 2: Shows inter-component interactions for delete 1 command
Each of the four main components:
- Defines its API in an
interfacewith the same name as the component. - Implements its functionality using a concrete
{Component Name}Managerclass (which implements the corresponding APIinterface).
For example, the Logic component defines its API in the Logic.java interface and implements its functionality using the LogicManager.java class which implements the Logic interface. Other components interact with a given component through its interface rather than the concrete class (reason: to prevent outside components from being coupled to the implementation of a component), as illustrated in the (partial) class diagram below.

Figure 3: Shows the interface-implementation pattern for component managers
The sections below give more details of each component.
3.2 Architectural Patterns and Principles
CourseBook employs several key architectural patterns:
1. Layered Architecture
- Clear separation between UI, Logic, Model, and Storage layers
- Each layer depends only on the layers below it
- Changes to one layer have minimal impact on others
2. Dependency Inversion Principle (DIP)
- Components depend on abstractions (interfaces) rather than concrete implementations
- Example:
LogicManagerdepends on theModelinterface, notModelManager
3. Single Responsibility Principle (SRP)
- Each component has a single, well-defined responsibility
- Example:
Storagehandles only persistence, not business logic
4. Command Pattern
- All user actions are represented as
Commandobjects - Enables undo/redo functionality and command history
5. Observer Pattern
- UI components observe Model changes through JavaFX
ObservableList - Automatic UI updates when data changes
Design Rationale: These patterns enable maintainability, testability, and extensibility. The layered architecture with dependency inversion allows components to be tested independently and replaced without affecting other parts of the system.
4. UI Component
API: Ui.java
Figure 4: Shows the structure of UI components including MainWindow, PersonListPanel, CourseListPanel, CommandBox, ResultDisplay, etc.
4.1 Structure
The UI consists of a MainWindow that is made up of several parts:
-
CommandBox- Text input field for user commands -
ResultDisplay- Shows command execution results and feedback -
PersonListPanel- Displays the list of persons (contains multiplePersonCardobjects) -
CourseListPanel- Displays the list of courses (contains multipleCourseCardobjects) -
StatusBarFooter- Shows the data file path -
HelpWindow- Displays help information (opened on demand) -
PersonDetailWindow- Shows detailed information for a specific person (opened on demand)
All these UI parts, including the MainWindow, inherit from the abstract UiPart class which captures the commonalities between classes that represent parts of the visible GUI.
4.2 Technology Stack
The UI component uses the JavaFX UI framework. The layout of these UI parts is defined in matching .fxml files located in the src/main/resources/view folder. For example, the layout of the MainWindow is specified in MainWindow.fxml.
4.3 Responsibilities
The UI component:
- Executes user commands using the
Logiccomponent - Listens for changes to
Modeldata so that the UI can be updated with the modified data automatically - Keeps a reference to the
Logiccomponent because theUIrelies on theLogicto execute commands - Depends on some classes in the
Modelcomponent, as it displaysPersonandCourseobjects residing in theModel
4.4 Key Interactions
Command Execution Flow:
- User types a command in
CommandBoxand presses Enter -
CommandBoxpasses the command text toLogic.execute() -
Logicreturns aCommandResultobject -
ResultDisplayshows the feedback message fromCommandResult - If
CommandResultcontains flags (e.g.,showHelp,showPersonDetail), appropriate windows are opened
Data Binding:
-
PersonListPanelis bound toLogic.getFilteredPersonList()(anObservableList<Person>) -
CourseListPanelis bound toLogic.getFilteredCourseList()(anObservableList<Course>) - When the Model updates these lists, the UI automatically refreshes
4.5 Theming
CourseBook supports multiple themes:
-
Dark (default) -
DarkTheme.css -
Blue -
BlueTheme.css -
Love -
LoveTheme.css -
Tree -
TreeTheme.css
Each theme consists of:
- A main stylesheet (e.g.,
DarkTheme.css) - An extensions file (e.g.,
Extensions.cssorBlueExtensions.css)
The theme command triggers a theme change by updating the CommandResult with the new CSS file paths, which MainWindow applies dynamically.
5. Logic Component
API: Logic.java
5.1 Structure
Here’s a (partial) class diagram of the Logic component:

Figure 5: Shows LogicManager, CourseBookParser, Command hierarchy, and parser classes
5.2 Command Execution Lifecycle
The sequence diagram below illustrates the interactions within the Logic component for the API call execute("delete 1").
Figure 6: Shows the detailed flow from parsing to execution for a delete command
DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline continues till the end of diagram.
5.3 How the Logic Component Works
Step-by-Step Execution:
-
User Input Reception: When
Logicis called upon to execute a command, it receives a command string (e.g.,"delete 1"). -
Command Parsing: The string is passed to a
CourseBookParserobject which:- Tokenizes the input to identify the command word (e.g.,
"delete") - Creates the appropriate command-specific parser (e.g.,
DeleteCommandParser) - The specific parser parses the arguments and creates a
Commandobject (e.g.,DeleteCommand)
- Tokenizes the input to identify the command word (e.g.,
-
Command Execution: The
Commandobject is executed byLogicManager:-
command.execute(model, history)is called - The command interacts with the
Modelto perform its action (e.g., delete a person) - Note: In the code, this may involve multiple interactions with the Model
-
-
Result Encapsulation: The result of the command execution is encapsulated as a
CommandResultobject which contains:- Feedback message to display to the user
- Flags indicating required UI actions (e.g.,
showHelp,exit,showPersonDetail) - Theme CSS file paths (if theme was changed)
-
Persistence: If the Model was modified during execution,
LogicManagerautomatically saves the data toStorage. -
Command History: The command text is added to
CommandHistoryfor later retrieval via thehistorycommand.
5.4 Parsing Architecture
Here are the classes in Logic used for parsing a user command:

Figure 7: Shows the parser hierarchy and how CourseBookParser dispatches to specific command parsers
How Parsing Works:
- When called upon to parse a user command, the
CourseBookParserclass:- Uses
ArgumentTokenizerto split the command into a command word and argument string - Creates an
XYZCommandParserbased on the command word (e.g.,AddCommandParserforadd) - The
XYZCommandParserusesArgumentMultimapandParserUtilto extract and validate arguments - Creates and returns an
XYZCommandobject (e.g.,AddCommand)
- Uses
- All
XYZCommandParserclasses (e.g.,AddCommandParser,DeleteCommandParser) inherit from theParserinterface so that they can be treated similarly where possible (e.g., during testing).
5.5 Command Classes
CourseBook implements 27 command classes following the Command Pattern:
Person Management:
-
AddCommand- Add new contact -
EditCommand- Edit existing contact details -
DeleteCommand- Delete one or more contacts -
ListCommand- List all persons -
FindCommand- Search persons by keywords -
ViewPersonCommand- Show detailed person information -
FavouriteCommand,UnfavouriteCommand,FavCommand- Manage favorites -
BirthdayCommand- Add/update birthday -
SortCommand,SortBirthdayCommand- Sort persons
Course Management:
-
AddCourseCommand- Add courses to a person -
RemoveCourseCommand- Remove courses from a person -
EditCourseColorCommand- Change course color globally -
ListCoursesCommand- List all courses -
ListByCourseCommand- Filter persons by course
Application Commands:
-
ClearCommand- Clear all data -
ExitCommand- Exit application -
HelpCommand- Show help -
HistoryCommand- Show command history -
SummaryCommand- Display summary statistics -
ThemeCommand- Change theme -
UndoCommand,RedoCommand- Undo/redo operations -
ConfirmDeleteCommand- Confirm deletion (internal use)
5.6 Argument Parsing Infrastructure
Key Classes:
-
CliSyntax: Defines prefix constants (e.g.,PREFIX_NAME = new Prefix("n/"),PREFIX_PHONE = new Prefix("p/")) -
ArgumentTokenizer: Splits arguments string by prefixes (e.g.,"n/John p/91234567"→ map of{n/ -> "John", p/ -> "91234567"}) -
ArgumentMultimap: Maps prefixes to their values, supports multiple values per prefix -
ParserUtil: Contains static utility methods for parsing and validating specific types (e.g.,parseIndex(),parseName(),parsePhone())
Example - Parsing add n/John p/91234567 e/john@example.com a/123 Main St:
-
CourseBookParseridentifies command word"add" - Creates
AddCommandParser, passes arguments string"n/John p/91234567 e/john@example.com a/123 Main St" -
AddCommandParserusesArgumentTokenizer.tokenize()to createArgumentMultimap - Calls
ParserUtil.parseName(argMultimap.getValue(PREFIX_NAME))→ returnsNameobject - Similarly parses phone, email, address, tags, courses
- Creates and returns
AddCommand(name, phone, email, address, tags, courses)
5.7 Design Rationale
Why Command Pattern?
- Undo/Redo: Each command can be stored in history and reversed
- Testability: Commands can be tested in isolation
- Extensibility: Adding new commands doesn’t require changes to existing code
Why Separate Parsers?
- Single Responsibility: Each parser handles one command type
- Maintainability: Changes to command syntax affect only one parser
-
Reusability: Common parsing logic is extracted to
ParserUtil
6. Model Component
API: Model.java

Figure 8: Shows ModelManager, CourseBook, VersionedCourseBook, Person, Course, Tag, UniquePersonList, and their relationships
6.1 Structure and Responsibilities
The Model component:
- Stores the address book data in memory (all
Personobjects are contained in aUniquePersonListobject withinCourseBook) - Stores the currently ‘selected’
Personobjects (e.g., results of a search query) as a separate filtered list which is exposed to outsiders as an unmodifiableObservableList<Person>that can be ‘observed’ (the UI is bound to this list so that the UI automatically updates when the data in the list changes) - Stores a
UserPrefsobject that represents the user’s preferences (file paths, GUI settings, theme). This is exposed to the outside as aReadOnlyUserPrefsobject. - Does not depend on any of the other three components (as the
Modelrepresents data entities of the domain, they should make sense on their own without depending on other components) - Manages undo/redo history through
VersionedCourseBook - Maintains a dynamically updated
ObservableList<Course>derived from all persons’ course enrollments
6.2 Data Model
Person Entity:
A Person object consists of:
-
Name(required, alphanumeric + spaces) -
Phone(required, 7-15 digits) -
Email(required, valid email format) -
Address(required, non-empty string) -
Set<Tag>(optional, 0 or more tags) -
Set<Course>(optional, 0 or more courses) -
Birthday(optional, format: dd-MM-yyyy) -
isFavourite(boolean flag)
Uniqueness Constraint: No two persons can have the same name (case-insensitive, whitespace-normalized) OR the same phone OR the same email.
Course Entity:
A Course object consists of:
-
courseCode(required, alphanumeric + hyphens, uppercase) -
CourseColor(enum: GREEN, BLUE, RED, ORANGE, PINK, PURPLE, GRAY, YELLOW)
Tag Entity:
A Tag is a simple label with a tagName (alphanumeric only).
6.3 Alternative Model Design
Tag list in the CourseBook, which Person references. This allows CourseBook to only require one Tag object per unique tag, instead of each Person needing their own Tag objects.
Figure 9: Shows a design where CourseBook maintains a centralized Tag list referenced by Persons
Current Design (Tag/Course instances per Person):
- Pros: Simpler implementation, easier to serialize/deserialize, no referential integrity concerns
-
Cons: Duplicate objects in memory (multiple identical
Tag/Courseinstances)
Alternative Design (Centralized Tag/Course list):
- Pros: Memory efficient, single source of truth, easier global course color management
- Cons: More complex implementation, referential integrity issues, cascading deletions
Chosen Approach: CourseBook uses the current design (instances per Person) for Tags but effectively implements a hybrid approach for Courses - each Person has Course instances, but course colors are managed globally through Model methods.
6.4 Undo/Redo Implementation
The undo/redo mechanism is facilitated by VersionedCourseBook, which extends CourseBook with undo/redo history stored internally as a courseBookStateList and currentStatePointer.
Key Operations:
-
VersionedCourseBook#commit()— Saves the current course book state in its history -
VersionedCourseBook#undo()— Restores the previous course book state from its history -
VersionedCourseBook#redo()— Restores a previously undone course book state from its history
These operations are exposed in the Model interface as Model#commitCourseBook(), Model#undoCourseBook(), and Model#redoCourseBook() respectively.
6.5 Undo/Redo Example Usage Scenario
Step 1. Initial State
The user launches the application for the first time. The VersionedCourseBook will be initialized with the initial course book state, and the currentStatePointer pointing to that single course book state.

Figure 10: Shows initial state with one CourseBook snapshot and pointer at index 0
Step 2. Delete Command
The user executes delete 5 command to delete the 5th person in the course book. The delete command calls Model#commitCourseBook(), causing the modified state of the course book after the delete 5 command executes to be saved in the courseBookStateList, and the currentStatePointer is shifted to the newly inserted state.

Figure 11: Shows two states: initial and after delete, pointer at index 1
Step 3. Add Command
The user executes add n/David … to add a new person. The add command also calls Model#commitCourseBook(), causing another modified course book state to be saved into the courseBookStateList.

Figure 12: Shows three states, pointer at index 2
Model#commitCourseBook(), so the course book state will not be saved into the courseBookStateList.
Step 4. Undo
The user now decides that adding the person was a mistake, and decides to undo that action by executing the undo command. The undo command will call Model#undoCourseBook(), which will shift the currentStatePointer once to the left, pointing it to the previous course book state, and restores the course book to that state.

Figure 13: Shows three states with pointer moved back to index 1
currentStatePointer is at index 0, pointing to the initial CourseBook state, then there are no previous CourseBook states to restore. The undo command uses Model#canUndoCourseBook() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the undo.
6.6 Undo Sequence Diagram (Logic Layer)
The following sequence diagram shows how an undo operation goes through the Logic component:

Figure 14: Shows the flow from UndoCommand through LogicManager and back
UndoCommand should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
6.7 Undo Sequence Diagram (Model Layer)
Similarly, how an undo operation goes through the Model component is shown below:

Figure 15: Shows interactions between ModelManager and VersionedCourseBook during undo
6.8 Redo
The redo command does the opposite — it calls Model#redoCourseBook(), which shifts the currentStatePointer once to the right, pointing to the previously undone state, and restores the course book to that state.
currentStatePointer is at index courseBookStateList.size() - 1, pointing to the latest course book state, then there are no undone CourseBook states to restore. The redo command uses Model#canRedoCourseBook() 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 5. Non-Modifying Command
The user then decides to execute the command list. Commands that do not modify the course book, such as list, will usually not call Model#commitCourseBook(), Model#undoCourseBook(), or Model#redoCourseBook(). Thus, the courseBookStateList remains unchanged.

Figure 16: Shows three states with pointer still at index 1 after list command
Step 6. State Branching
The user executes clear, which calls Model#commitCourseBook(). Since the currentStatePointer is not pointing at the end of the courseBookStateList, all course book states after the currentStatePointer will be purged. Reason: It no longer makes sense to redo the add n/David … command. This is the behavior that most modern desktop applications follow.

Figure 17: Shows two states: original and clear state, with the “add David” state purged
The following activity diagram summarizes what happens when a user executes a new command:

Figure 18: Shows decision flow: if command modifies data → check if states after pointer exist → purge if yes → add new state
6.9 Design Considerations for Undo/Redo
Aspect: How undo & redo executes:
Alternative 1 (current choice): Saves the entire course book.
- Pros: Easy to implement, guaranteed consistency (entire state snapshot)
- Cons: My have performance issues in terms of memory usage (multiple full copies in memory)
Alternative 2: Individual command undo (Command Pattern with reverse operations).
- Pros: Memory efficient (only store deltas), potentially faster
- Cons: Complex implementation, each command needs reverse logic, error-prone (e.g., reversing an edit requires storing old values)
Rationale: CourseBook uses Alternative 1 because:
- Simplicity: Easier to implement and maintain
- Reliability: No risk of inconsistent state from failed reverse operations
- Acceptable Trade-off: For typical usage (100-1000 persons), memory overhead is acceptable on modern systems
- Course Color Consistency: Full snapshots preserve global course color mappings correctly
Enhancement Possibility: Future versions could implement a hybrid approach where only changed persons are stored with copy-on-write semantics to reduce memory usage while maintaining simplicity.
6.10 Filtering and Sorting
Filtered Lists:
-
filteredPersonsis aFilteredList<Person>wrapper aroundversionedCourseBook.getPersonList() - Predicates are set via
Model#updateFilteredPersonList(Predicate<Person> predicate) - Used by
FindCommand,ListByCourseCommand,FavCommand
Sorting:
-
Model#sortSelectedPersons(Comparator<Person> comparator)re-orders the underlyingCourseBook - Used by
SortCommand(sort by name) andSortBirthdayCommand - Note: Sorting modifies the model directly (not just a view), so it can be undone
Course List:
-
courseListis dynamically updated by listening to changes in the person list - Extracts all unique courses from all persons
- Sorted alphabetically by course code
7. Storage Component
API: Storage.java

Figure 19: Shows StorageManager, JsonCourseBookStorage, JsonUserPrefsStorage, and JSON adapter classes
7.1 Structure and Responsibilities
The Storage component:
- Can save both address book data and user preference data in JSON format, and read them back into corresponding objects
- Inherits from both
CourseBookStorageandUserPrefsStorage, which means it can be treated as either one (if only the functionality of one is needed) - Depends on some classes in the
Modelcomponent (because theStoragecomponent’s job is to save/retrieve objects that belong to theModel)
7.2 JSON Serialization
CourseBook Data Structure (coursebook.json):
{
"persons": [
{
"name": "John Doe",
"phone": "98765432",
"email": "john@example.com",
"address": "123 Main St",
"birthday": "20-02-2000",
"favourite": true,
"tagged": ["friend", "classmate"],
"courses": [
{"courseCode": "CS2103T", "color": "YELLOW"},
{"courseCode": "CS2101", "color": "GREEN"}
]
}
],
"theme": "DARK"
}
User Preferences Data Structure (preferences.json):
{
"guiSettings": {
"windowWidth": 900.0,
"windowHeight": 740.0,
"windowCoordinates": {
"x": 100,
"y": 100
}
},
"courseBookFilePath": "data/coursebook.json"
}
7.3 JSON Adapter Classes
To convert between Java objects and JSON, CourseBook uses Jackson library with custom adapter classes:
-
JsonAdaptedPerson- ConvertsPerson↔ JSON -
JsonAdaptedCourse- ConvertsCourse↔ JSON -
JsonAdaptedTag- ConvertsTag↔ JSON
Example - JsonAdaptedPerson:
// Converting Person to JSON JsonAdaptedPerson jsonPerson = new JsonAdaptedPerson(personObject); // Jackson serializes jsonPerson to JSON
// Converting JSON to Person JsonAdaptedPerson jsonPerson = // deserialized from JSON personObject = jsonPerson.toModelType(); // throws IllegalValueException if invalid
7.4 Data Loading and Saving Flow
Application Startup (Load):
-
MainApp.init()createsJsonCourseBookStorageandJsonUserPrefsStorage -
StorageManagerwraps both storages -
MainApp.initModelManager()callsstorage.readCourseBook() -
JsonCourseBookStorage.readCourseBook():- Reads JSON file using Jackson
- Deserializes to
JsonSerializableCourseBook(contains list ofJsonAdaptedPerson) - Converts each
JsonAdaptedPersontoPersonviatoModelType() - Returns
Optional<ReadOnlyCourseBook>
- If file not found or invalid, loads sample data or empty CourseBook
During Runtime (Save):
- User executes command that modifies data (e.g.,
add,delete,edit) - Command calls
model.commitCourseBook()(for undo/redo) -
LogicManagerdetectscourseBookModifiedflag -
LogicManagercallsstorage.saveCourseBook(model.getCourseBook()) -
JsonCourseBookStorage.saveCourseBook():- Converts
CourseBooktoJsonSerializableCourseBook - Converts each
PersontoJsonAdaptedPerson - Serializes to JSON file using Jackson
- Converts
Application Shutdown:
-
MainApp.stop()saves user preferences viastorage.saveUserPrefs(model.getUserPrefs())
7.5 Error Handling and Data Integrity
File Not Found:
- If
coursebook.jsondoesn’t exist on startup → load sample data (first run experience) - If
preferences.jsondoesn’t exist → use default preferences
Corrupted Data:
- If JSON is malformed →
DataLoadingExceptionis thrown → log warning → start with empty CourseBook - If JSON is valid but data is invalid (e.g., invalid email format) →
IllegalValueExceptionduringtoModelType()→ that person is skipped
Write Failures:
- If disk is full or permissions denied →
IOException→ command fails with error message → user can retry
Data Validation:
- All data is validated during JSON → Model conversion via
JsonAdaptedPerson.toModelType() - Same validation logic as used by parsers (e.g.,
Name.isValidName(),Email.isValidEmail())
7.6 File Paths and Configuration
Default Paths:
- CourseBook data:
data/coursebook.json - User preferences:
preferences.json - Application config:
config.json
Custom Paths:
- User can specify custom config file via command line:
java -jar coursebook.jar --config myconfig.json - User preferences file path is read from config
- CourseBook file path is read from preferences
Cross-Platform Compatibility:
- File paths use
Pathobjects (platform-independent) - Automatic creation of parent directories if they don’t exist
7.7 Design Rationale
Why JSON over XML?
- Human-readable: Easier for advanced users to edit manually
- Compact: Smaller file size
- Native Java Support: Jackson library is mature and widely used
Why Jackson over Gson?
- Flexibility: Supports complex object graphs
- Performance: Faster serialization/deserialization
- Annotations: Cleaner code with annotations for custom serialization
Why Separate Adapters?
- Single Responsibility: Each adapter handles one entity type
- Testability: Adapters can be tested independently
- Flexibility: Easy to change JSON structure without affecting Model
8. Common Classes
Classes used by multiple components are in the seedu.coursebook.commons package.
8.1 Commons Core
Config
- Stores application configuration (log level, user prefs file path)
- Loaded from
config.jsonon startup
LogsCenter
- Centralized logging infrastructure
- Provides logger instances to all components
- Log levels: SEVERE, WARNING, INFO, FINE, FINER, FINEST
- Logs to both console and file (
coursebook.log)
GuiSettings
- Stores GUI window settings (size, position)
- Persisted in user preferences
Version
- Represents application version (major.minor.patch + early access flag)
- Current version:
1.5(with early access)
Index
- Wrapper class for 1-based indices
- Prevents off-by-one errors (internally stores 0-based, exposes 1-based)
- Used throughout Logic and Model for list operations
8.2 Commons Exceptions
DataLoadingException
- Thrown when data files cannot be loaded (missing, corrupted, permission denied)
IllegalValueException
- Thrown when data validation fails during deserialization (e.g., invalid email format in JSON)
8.3 Commons Utilities
StringUtil
- String manipulation helpers (e.g.,
containsWordIgnoreCase(),getDetails()for exception messages)
FileUtil
- File path validation and operations (e.g.,
isValidPath(),createIfMissing())
JsonUtil
- JSON serialization/deserialization wrapper around Jackson
- Generic methods:
serializeObjectToJsonFile(),deserializeObjectFromJsonFile()
ConfigUtil
- Config file read/write operations
CollectionUtil
- Collection validation helpers (e.g.,
requireAllNonNull())
AppUtil
- Application-wide validation utilities (e.g.,
checkArgument())
9. Implementation Details
9.1 Course Color Management
Challenge: Maintain consistent course colors across all persons while allowing per-course color customization.
Implementation:
CourseBook uses a hybrid approach:
- Each
Personobject contains aSet<Course>, and eachCoursehas aCourseColorenum value. - When adding a course to a person:
-
If the course code already exists in the system (found in another person), the existing color is used (enforced by
AddCommandandAddCourseCommand) - If the course is new, the user-specified color is used (defaults to GREEN if not specified)
-
If the course code already exists in the system (found in another person), the existing color is used (enforced by
-
EditCourseColorCommandchanges the color globally:-
Model#setCourseColor(String courseCode, CourseColor color)iterates through all persons - Creates updated
Courseobjects with the new color - Rebuilds the entire
CourseBookwith updated persons - Commits the change (enables undo)
-
Code Pointer:
-
ModelManager.java:233-254-setCourseColor()method -
AddCommand.java- Course color resolution logic -
EditCourseColorCommand.java- Global color update
Design Rationale:
- Pros: Simple implementation, works with current architecture, supports undo/redo
- Cons: O(n) complexity for color updates (n = number of persons)
- Trade-off: Acceptable for typical usage (few color changes, ≤1000 persons)
9.2 Delete Confirmation Dialog
Challenge: Prevent accidental deletions while maintaining CLI efficiency.
Implementation:
CourseBook uses a two-phase deletion process:
-
Phase 1 - Prepare:
DeleteCommand.execute():- Validates indices/names
- Identifies persons to be deleted
- Returns
CommandResultwithrequiresConfirmation = trueandpersonsToDeletelist
-
Phase 2 - Confirm: User sees dialog via
MainWindow:- If user clicks OK →
ConfirmDeleteCommandis executed - If user clicks Cancel → no action taken
- If user clicks OK →
-
Actual Deletion:
ConfirmDeleteCommand.execute():- Deletes persons from model
- Commits change
- Returns success message
Code Pointers:
-
DeleteCommand.java- Phase 1 logic -
ConfirmDeleteCommand.java- Phase 2 logic -
MainWindow.java- Dialog display and ConfirmDeleteCommand invocation
Design Rationale:
- Pros: Prevents accidental deletions, gives user chance to review
- Cons: Requires two steps (less efficient than one-shot delete)
- Trade-off: Safety over speed for irreversible operations
9.3 Theme Persistence in Undo/Redo
Challenge: Theme changes should be undoable, but theme is not part of the CourseBook model.
Implementation:
-
Theme Storage:
CourseBookhas acurrentThemefield (enum: DARK, BLUE, LOVE, TREE) -
Theme Change:
ThemeCommand.execute()callsmodel.setCurrentTheme()which:- Updates
versionedCourseBook.setCurrentTheme() - Returns
CommandResultwith CSS file paths -
MainWindowapplies CSS -
ThemeCommandthen callsmodel.commitCourseBook()(saves state for undo)
- Updates
-
Undo/Redo with Theme Detection:
-
ModelManager.undoCourseBook()andredoCourseBook()detect if theme changed during undo/redo - If theme changed,
themeChangedDuringUndoflag is set -
UndoCommandandRedoCommandcheck this flag - If flag is true,
CommandResultincludes theme CSS file paths - UI applies the theme
-
Code Pointers:
-
CourseBook.java-currentThemefield -
VersionedCourseBook.java- Theme field is part of snapshots -
ModelManager.java:203-225- Theme detection during undo/redo -
UndoCommand.javaandRedoCommand.java- Theme CSS handling in CommandResult
Design Rationale:
- Pros: Theme changes are undoable, consistent with other commands
- Cons: Slightly complex logic for detecting theme changes during undo/redo
- Trade-off: Consistency (all changes are undoable) over implementation simplicity
9.4 Birthday Sorting
Challenge: Sort persons by “days until next birthday” (considering current year vs. next year).
Implementation:
-
Birthday Normalization:
- For each person, compute their next birthday date
- If birthday has passed this year → use next year’s date
- If birthday hasn’t passed this year → use this year’s date
-
Sorting:
- Create a
Comparator<Person>that compares normalized birthday dates - Persons without birthdays are placed at the end
- Create a
-
Application:
-
SortBirthdayCommand.execute()callsmodel.sortSelectedPersons(comparator) -
ModelManager.sortSelectedPersons()rebuildsCourseBookin sorted order - Commits change (enables undo)
-
Code Pointers:
-
SortBirthdayCommand.java- Comparator logic -
Birthday.java- Date parsing and normalization utilities -
ModelManager.java:173-187- Sorting implementation
Design Rationale:
- Pros: Intuitive behavior (upcoming birthdays first), handles year boundaries correctly
- Cons: O(n log n) sorting operation
- Trade-off: Acceptable performance for typical usage
9.5 Favorite Status Preservation
Challenge: Favorite status should persist across edits and undo/redo operations.
Implementation:
-
Favorite as Person Field:
-
Personhas anisFavouriteboolean field - Immutable like other Person fields
-
-
Edit Command:
-
EditCommanddoes not touchisFavouritefield -
EditPersonDescriptordoesn’t have a favorite field - When creating edited person, existing favorite status is preserved
-
-
Undo/Redo:
- Since
isFavouriteis part ofPerson, it’s automatically saved in undo/redo snapshots
- Since
Code Pointers:
-
Person.java-isFavouritefield -
EditCommand.java- Favorite preservation logic -
FavouriteCommand.javaandUnfavouriteCommand.java- Set favorite status
Design Rationale:
- Pros: Simple, consistent with other Person fields
- Cons: None
- Trade-off: N/A (clear best approach)
10. Logging
10.1 Logging Infrastructure
CourseBook uses java.util.logging package through a centralized LogsCenter class.
Log Levels (highest to lowest severity):
-
SEVERE- Critical errors that prevent functionality -
WARNING- Recoverable errors or unexpected situations -
INFO- Key application events (startup, shutdown, user commands) -
FINE- Detailed tracing for debugging -
FINER- Very detailed tracing -
FINEST- Extremely detailed tracing
10.2 Log Output
Console Output:
- Only
INFOand above are logged to console by default - Configurable via
config.json
File Output:
- All levels logged to
coursebook.log - File is created in the same directory as the JAR file
- Rotated when it exceeds 5MB
10.3 Using Logs
Obtaining a Logger:
import seedu.coursebook.commons.core.LogsCenter;
public class MyClass {
private static final Logger logger = LogsCenter.getLogger(MyClass.class);
public void myMethod() {
logger.info("Executing myMethod");
logger.fine("Detailed information: " + details);
}
}
Logging Best Practices:
- Log user commands at
INFOlevel (seeLogicManager.java:57) - Log data loading/saving at
INFOlevel - Log warnings for data corruption or recoverable errors
- Log severe errors for unrecoverable errors
- Avoid logging sensitive data (passwords, etc.)
- Use appropriate log levels (don’t log everything at
INFO)
10.4 Configuration
Log level is configured in config.json:
{
"logLevel": "INFO"
}
11. Configuration
Refer to the guide Configuration guide.
Key Configuration Files:
-
config.json- Application config (log level, user prefs path) -
preferences.json- User preferences (window size, theme, data file path) -
coursebook.json- Data file (persons, courses)
12. Documentation, logging, configuration, dev-ops
13. Appendix: Requirements
13.1 Product Scope
Target user profile:
- Is a university student
- Has a need to manage a significant number of academic contacts (classmates, professors, TAs)
- Takes multiple courses/modules each semester
- Wants to easily identify and connect with classmates in specific courses
- Prefers desktop apps over other types
- Can type fast
- Prefers typing to mouse interactions
- Is reasonably comfortable using CLI apps
- Values quick access to course-related contact information
- Seeks academic collaboration and support from peers
Value proposition:
CourseBook helps university students efficiently manage and organize their academic contacts by course affiliation, making it easy to identify classmates, access instructor information, and foster academic collaboration within specific modules. It is faster than typical mouse-driven GUI apps for users who can type fast.
13.2 User Stories
Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *
| Priority | As a … | I want to … | So that I can… |
|---|---|---|---|
* * * |
user | launch coursebook from my laptop | use it |
* * * |
new user | see usage instructions | refer to instructions when I forget how to use the App |
* * * |
user | add a new person | keep track of my academic contacts |
* * * |
user | delete a person | remove entries that I no longer need |
* * * |
user | edit a contact | keep contact information up to date |
* * * |
user | input all the courses that I am taking | identify friends taking the same courses as me |
* * * |
user | view contacts by course | easily find classmates for specific modules |
* * * |
user | list all my contacts | see everyone in my address book |
* * * |
user | find contacts by name or keyword | quickly locate specific persons |
* * |
time-conscious user | search for friends by multiple fields | find a person quickly even with partial information |
* * |
user | see my friends who have common courses with me | identify and contact them for study groups or collaboration |
* * |
user | differentiate courses by colours | visually identify which courses my friends take easily |
* * |
user with many persons in the course book | keep a list of favourite contacts | find my close friends easily |
* * |
user | add birthdays to contacts | remember and celebrate friends’ birthdays |
* * |
user | sort contacts by name | find people alphabetically |
* * |
user | sort contacts by upcoming birthdays | see whose birthday is coming up soon |
* * |
user | undo my last action | revert mistakes quickly |
* * |
user | redo an undone action | restore changes if I undid by mistake |
* * |
user | view command history | recall what commands I ran recently |
* * |
user | see a summary of my contacts and courses | get an overview of my network |
* * |
user | change the application theme | customize the appearance to my preference |
* * |
user | view detailed information about a person | see all their details in one place |
* |
user | export course contact lists | share them with study group members |
* |
user | import contacts from a file | quickly populate my address book |
13.3 Use Cases
(For all use cases below, the System is the CourseBook and the Actor is the user, unless specified otherwise)
Use Case: UC01 - Add a Contact
MSS
- User enters command to add a new person with name, phone, email, address, and optionally tags/courses.
- CourseBook validates all fields.
- CourseBook checks for duplicates (by name/email/phone).
- CourseBook adds the contact to in-memory data.
- CourseBook updates the UI to show the new contact.
- CourseBook persists the change to the JSON file.
-
CourseBook displays success message.
Use case ends.
Extensions
- 1a. Missing required fields (name, phone, email, or address):
- 1a1. CourseBook shows error: “Invalid command format!”
- Use case ends.
- 2a. Invalid field format (e.g., non-numeric phone, invalid email):
- 2a1. CourseBook shows field-specific error message.
- Use case resumes at step 1.
- 3a. Duplicate name, email, or phone exists:
- 3a1. CourseBook shows: “This person already exists in the address book.”
- Use case ends.
Use Case: UC02 - Delete a Contact
MSS
- User requests to list persons (UC03) or find persons (UC05).
- CourseBook shows a list of persons.
- User requests to delete a specific person by index or name.
- CourseBook displays a confirmation dialog with the person(s) to be deleted.
- User confirms deletion.
- CourseBook deletes the person.
- CourseBook updates the UI.
- CourseBook persists the change.
-
CourseBook displays success message.
Use case ends.
Extensions
- 2a. The list is empty:
- Use case ends.
- 3a. The given index is invalid:
- 3a1. CourseBook shows an error message.
- Use case resumes at step 2.
- 3b. The given name does not match any contact:
- 3b1. CourseBook shows “No such contact found!”
- Use case resumes at step 2.
- 5a. User cancels deletion:
- Use case ends.
Use Case: UC03 - List All Contacts
MSS
- User enters
listcommand. -
CourseBook displays all contacts in the person list panel.
Use case ends.
Extensions
- 1a. No contacts exist:
- 1a1. CourseBook shows an empty list.
- Use case ends.
Use Case: UC04 - List Contacts by Course
MSS
- User enters command to list contacts by a specific course code.
- CourseBook normalizes the course code (trim + uppercase).
- CourseBook finds all contacts enrolled in that course.
-
CourseBook displays the matching contacts in the person list panel.
Use case ends.
Extensions
- 1a. Missing course code:
- 1a1. CourseBook shows error: “Invalid command format!”
- Use case ends.
- 3a. Course does not exist or no contacts are enrolled:
- 3a1. CourseBook shows “No such course: {course code}”
- 3a2. CourseBook displays an empty list.
- Use case ends.
Use Case: UC05 - Find Contacts by Keywords
MSS
- User enters command to find contacts by keywords in specific fields (name, phone, email, address, tags).
- CourseBook parses the keywords and prefixes.
- CourseBook filters the person list to show matching contacts.
- CourseBook displays the filtered list in the person list panel.
-
CourseBook shows the number of persons listed.
Use case ends.
Extensions
- 2a. Invalid prefix or field format:
- 2a1. CourseBook shows error with correct format.
- Use case ends.
- 3a. No contacts match the keywords:
- 3a1. CourseBook shows “No such contact found”
- 3a2. CourseBook displays an empty list.
- Use case ends.
Use Case: UC06 - Edit a Contact
MSS
- User requests to list persons (UC03) or find persons (UC05).
- CourseBook shows a list of persons.
- User enters command to edit a specific person with new values for one or more fields.
- CourseBook validates the fields.
- CourseBook checks that the edited person doesn’t create a duplicate.
- CourseBook updates the person with the new values.
- CourseBook updates the UI.
- CourseBook persists the change.
-
CourseBook displays success message.
Use case ends.
Extensions
- 3a. No fields specified:
- 3a1. CourseBook shows “At least one field to edit must be provided.”
- Use case resumes at step 2.
- 3b. Invalid index:
- 3b1. CourseBook shows “The person index provided is invalid”
- Use case resumes at step 2.
- 4a. Invalid field format:
- 4a1. CourseBook shows field-specific error message.
- Use case resumes at step 2.
- 5a. Edited person creates a duplicate:
- 5a1. CourseBook shows “This person already exists in the address book.”
- Use case resumes at step 2.
Use Case: UC07 - Add Course to Contact
MSS
- User requests to list persons (UC03) or find persons (UC05).
- CourseBook shows a list of persons.
- User enters command to add one or more courses to a specific person.
- CourseBook validates the course codes and colors.
- CourseBook checks if the person already has any of the specified courses.
- CourseBook resolves course colors (uses existing global color or user-specified color).
- CourseBook adds the courses to the person.
- CourseBook updates the UI.
- CourseBook persists the change.
- CourseBook displays success message.
Use case ends.
Extensions
- 3a. Invalid index:
- 3a1. CourseBook shows “The person index provided is invalid”
- Use case resumes at step 2.
- 4a. Invalid course code format:
- 4a1. CourseBook shows course code validation error.
- Use case resumes at step 2.
- 5a. Person already has one or more of the courses:
- 5a1. CourseBook shows “This person already has one or more of these courses”
- Use case resumes at step 2.
Use Case: UC08 - Undo Last Command
MSS
- User executes a command that modifies the course book (add, edit, delete, etc.).
- User realizes a mistake and enters
undocommand. - CourseBook checks if there are any undoable states.
- CourseBook restores the previous course book state.
- CourseBook checks if theme changed during undo.
- CourseBook updates the UI (and applies theme if changed).
-
CourseBook displays “Undo success!”
Use case ends.
Extensions
- 3a. No undoable states (at the beginning of history):
- 3a1. CourseBook shows “No more commands to undo!”
- Use case ends.
Use Case: UC09 - Redo Last Undone Command
MSS
- User has undone one or more commands (UC08).
- User enters
redocommand. - CourseBook checks if there are any redoable states.
- CourseBook restores the next course book state.
- CourseBook checks if theme changed during redo.
- CourseBook updates the UI (and applies theme if changed).
-
CourseBook displays “Redo success!”
Use case ends.
Extensions
- 3a. No redoable states (at the end of history or user made a new change after undo):
- 3a1. CourseBook shows “No more commands to redo!”
- Use case ends.
Use Case: UC10 - Change Theme
MSS
- User enters command to change theme to a specific theme (dark, blue, love, tree).
- CourseBook validates the theme name.
- CourseBook checks if the target theme is different from the current theme.
- CourseBook updates the current theme in the model.
- CourseBook commits the change (for undo/redo).
- CourseBook returns CommandResult with CSS file paths.
- UI applies the new theme stylesheets.
- CourseBook persists user preferences.
-
CourseBook displays “Theme changed to: {theme name}”
Use case ends.
Extensions
- 2a. Invalid theme name:
- 2a1. CourseBook shows “Invalid theme name. Available themes: dark, blue, love, tree”
- Use case ends.
- 3a. Target theme is the same as current theme:
- 3a1. CourseBook shows “Theme is already {theme name}!”
- Use case ends.
13.4 Non-Functional Requirements
-
Platform Compatibility: Should work on any mainstream OS as long as it has Java
17or above installed. -
Performance - Data Capacity: Should be able to hold up to 1000 persons without noticeable sluggishness in performance for typical usage (command execution <1 second, UI updates <500ms).
-
Performance - Command Response Time: Results of commands should be returned within 1 second to ensure a smooth user experience.
-
Usability: 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.
-
CLI-First Design: A user should be able to complete all tasks using the command-line interface without needing to use the mouse.
-
Reliability - Data Integrity: Application data should be automatically saved after every command that modifies data. Data should not be lost if the application crashes (last saved state is preserved).
-
Reliability - Uptime: The application should aim for less than 1 hour of downtime per month to ensure continuous availability for users (assuming proper system maintenance).
-
Maintainability - Bug Resolution: Developers should resolve critical bugs within 1 day of detection. Quick issue resolution is vital for maintaining a positive user experience.
-
Maintainability - Code Quality: Code should follow established Java coding standards (Checkstyle compliant) and include comprehensive JavaDocs for public APIs.
-
Security - No Interference with Antivirus: The application should not interfere with existing antivirus software. This compatibility is essential for ensuring seamless integration into users’ workflows.
-
Security - No Network Access: The application should not require internet connectivity and should not transmit any user data over the network.
-
Portability - Data Transfer: Users should be able to transfer their data to another computer by copying the data file. No additional setup or conversion should be required.
-
Extensibility - Plugin Architecture: The codebase should support easy addition of new commands without requiring changes to existing commands or core components.
-
Documentation: The product should come with comprehensive user and developer documentation.
13.5 Glossary
| Term | Definition |
|---|---|
| Mainstream OS | Windows, Linux, Unix, MacOS |
| Actor | A user or external entity that interacts with the system |
| CourseBook | The system that stores and manages contact information |
| Contact | A person whose details are stored in the course book |
| Person | Same as Contact (used interchangeably in the code) |
| Course | A university module or class (e.g., CS2103T) |
| Course Code | The unique identifier for a course (e.g., CS2103T, CS2101) |
| Tag | A label attached to a person for categorization (e.g., “friend”, “classmate”) |
| Favorite | A contact marked as favorite for quick access |
| Main Success Scenario (MSS) | The typical flow of events in a use case when everything goes as expected |
| Parser | The component that interprets user input and converts it into a command that the program can execute |
| Command | An object representing a user action (e.g., AddCommand, DeleteCommand) |
| Model | The component that holds the application data in memory |
| Storage | The component that persists data to disk (JSON files) |
| UI | User Interface - the graphical components the user interacts with |
| Logic | The component that parses and executes commands |
| CLI | Command Line Interface - text-based interface where users type commands |
| GUI | Graphical User Interface - visual interface with windows, buttons, etc. |
| Undo/Redo | Features that allow reverting or reapplying previous commands |
| Predicate | A function that tests whether a condition is true (used for filtering) |
| ObservableList | A JavaFX list that notifies listeners when its contents change |
| JSON | JavaScript Object Notation - a text format for storing structured data |
| Jackson | A Java library for converting between Java objects and JSON |
| JavaFX | A Java framework for building graphical user interfaces |
| FXML | XML format for defining JavaFX UI layouts |
14. Appendix: Effort
14.1 Difficulty Level
CourseBook represents a moderate to high difficulty extension of AB3. While the core architecture remained similar, significant effort was invested in:
-
Course Management System
- Implementing global course color management (ensuring consistency across all persons)
- Dynamically updating course lists from person enrollments
- Resolving color conflicts when adding courses
-
Enhanced Undo/Redo
- Extending undo/redo to support theme changes
- Detecting theme changes during undo/redo operations
- Ensuring theme persistence in snapshots
-
Two-Phase Deletion
- Implementing confirmation dialog for destructive operations
- Supporting bulk deletion with mixed valid/invalid indices
- Designing
ConfirmDeleteCommandfor internal use
-
Advanced Search & Filtering
- Supporting multi-field search with OR logic
- Implementing partial/substring matching
- Handling multiple keywords per field
-
Birthday Management & Sorting
- Implementing birthday normalization logic (current year vs. next year)
- Sorting by “days until next birthday”
- Handling edge cases (leap years, invalid dates)
-
Theming System
- Supporting 4 distinct themes with CSS
- Making theme changes undoable
- Persisting theme in both undo/redo history and user preferences
14.2 Challenges Faced
Challenge 1: Global Course Color Consistency
Problem: When a user adds CS2103T with color YELLOW to Person A, then adds CS2103T with color BLUE to Person B, what should happen?
Solution: Implemented a hybrid approach where:
- Existing course codes enforce their current color
- New course codes accept user-specified color or default to GREEN
-
EditCourseColorCommandglobally updates all instances of a course code
Effort: ~10 hours design and implementation
Challenge 2: Theme Persistence in Undo/Redo
Problem: Theme is a UI concern, but undo/redo operates on Model data. How to make theme changes undoable without violating architectural boundaries?
Solution: Added currentTheme field to CourseBook (Model), with special handling in ModelManager to detect theme changes during undo/redo and communicate them to UI via CommandResult.
Effort: ~7 hours design and implementation
Challenge 3: Two-Phase Deletion with Bulk Operations
Problem: Deleting multiple persons (e.g., delete 1 2 3) requires confirmation, but some indices might be invalid. How to show meaningful confirmation dialog?
Solution: DeleteCommand validates all indices/names, separates valid and invalid, returns CommandResult with confirmation request. MainWindow displays dialog. ConfirmDeleteCommand performs actual deletion.
Effort: ~13 hours design and implementation
14.3 Effort Comparison to AB3
| Aspect | AB3 | CourseBook | Effort Multiplier |
|---|---|---|---|
| Commands | 7 | 27 | ~3.9x |
| Parsers | 5 | 19 | ~3.8x |
| Model Entities | Person, Tag | Person, Course, Tag, Birthday | ~2x |
| Undo/Redo Complexity | Basic | Theme-aware | ~1.5x |
| UI Components | Basic | + Themes, CourseListPanel, PersonDetailWindow | ~1.8x |
Overall Effort Multiplier: ~2.5x relative to AB3
14.4 Achievements
-
Comprehensive Feature Set: 27 commands covering person management, course management, favorites, birthdays, sorting, searching, undo/redo, theming, and more.
-
Robust Architecture: Clean separation of concerns, strong adherence to SOLID principles, extensible design.
-
Excellent User Experience: Intuitive commands, helpful error messages, confirmation dialogs for destructive operations, multiple themes, fast performance.
-
Thorough Documentation: Comprehensive Developer Guide (this document) and User Guide with detailed command reference.
14.5 Effort Summary
Total Effort (Team of 5):
- Design & Planning: ~30 person-hours
- Implementation: ~250 person-hours
- Documentation: ~60 person-hours
- Bug Fixing & Refinement: ~40 person-hours
Total: ~380 person-hours (~76 hours per team member over ~8 weeks)
15. Appendix: Planned Enhancements
Team Size: 5
Enhancement 1: Allow Birthday Deletion
Current Limitation: Once a birthday is added, it cannot be deleted. If a birthday is entered, the user cannot remove it.
Proposed Enhancement: Allow users to delete/remove birthday field using edit command.
Implementation:
- Update
EditCommandto support empty birthday parameter (e.g.,edit 1 b/) to delete birthday - Update
EditPersonDescriptorto distinguish between “no change” and “delete birthday” - Add validation to prevent invalid dates from being added in the first place
- Update UI to handle missing birthday gracefully
Effort Estimate: ~1.5 hours
Enhancement 2: Module Code Validation
Current Limitation: Module codes do not have any validation or restrictions, allowing invalid codes like “ABC” or “12345”.
Proposed Enhancement: Add validation for module codes to ensure they follow standard university module code formats (e.g., CS2103T, MA1521, GEH1001).
Implementation:
- Add regex validation in
Courseclass for module code format - Update
AddCommandandEditCommandparsers to validate module codes - Display clear error messages for invalid module codes
- Support configurable module code patterns for different universities
Effort Estimate: ~2 hours
Enhancement 3: Confirmation Dialog for Clear Command
Current Limitation: The clear command immediately deletes all contacts without confirmation, risking accidental data loss.
Proposed Enhancement: Add a confirmation dialog before executing the clear command.
Implementation:
- Update
ClearCommandto trigger confirmation dialog - Add confirmation dialog UI component
- Only execute clear if user confirms
- Add option to bypass confirmation with flag (e.g.,
clear --force) for advanced users
Effort Estimate: ~1 hour
Enhancement 4: Support for International Phone Number Formats
Current Limitation: Phone numbers only accept digits; country codes with “+” and spaces (e.g., “+65 1234 5678”) are rejected.
Proposed Enhancement: Accept international phone number formats including “+” prefix and spaces for readability.
Implementation:
- Update
Phonevalidation regex to accept “+”, spaces, and hyphens - Normalize phone numbers for storage (remove spaces/hyphens)
- Display phone numbers in formatted style
- Support multiple international formats
Effort Estimate: ~2 hours
Enhancement 5: Persistent Theme Settings
Current Limitation: Theme selection is not saved and resets to default on restart.
Proposed Enhancement: Persist theme preference across application restarts.
Implementation:
- Add theme preference to
UserPrefsclass - Save theme selection to
preferences.json - Load and apply saved theme on application startup
- Ensure theme preference survives application updates
Effort Estimate: ~1 hour
Enhancement 6: Persistent Course Tag Colors
Current Limitation: Color-coded course tags are default green and change on restart, so color changes are lost after app is closed.
Proposed Enhancement: Persist the color assigned to each course tag across restarts.
Implementation:
- Add color mapping to
UserPrefsor create separate color configuration file - Store course code to color mappings
- Load color mappings on startup and apply to course tags
- Ensure consistent color assignment for the same course
Effort Estimate: ~1 hours
Enhancement 7: Display What Will Be Undone
Current Limitation: Users cannot easily keep track of which command will be undone next. After performing multiple commands, it becomes unclear what the undo command will revert.
Proposed Enhancement: Improve the undo command feature to display what action will be undone before execution, and show a summary of what was actually undone afterward. This helps users better understand and confirm their undo operations.
Implementation:
- Maintain descriptive history stack of executed commands that can be undone
- Enhance the
undocommand to show a confirmation message detailing what was undone after execution.
Effort Estimate: ~8 hours
Enhancement 8: Fuzzy Search
Current Limitation: Search only supports exact substring matching.
Proposed Enhancement: Implement fuzzy search using Levenshtein distance or similar algorithm.
Implementation:
- Add
FuzzySearchPredicatethat accepts similarity threshold - Update
FindCommandto support fuzzy mode (e.g.,find n/alic --fuzzy) - Rank results by similarity score
Effort Estimate: ~5 hours
Enhancement 9: Keyboard Shortcuts for Commands
Current Limitation: All commands must be typed (no shortcuts).
Proposed Enhancement: Support keyboard shortcuts for common commands (e.g., Ctrl+L for list, Ctrl+F for find).
Implementation:
- Add keyboard event handlers in
MainWindow - Map shortcuts to command text
- Add shortcuts to help window
Effort Estimate: ~3 hours
Enhancement 10: Export to CSV/vCard
Current Limitation: No optimised way to export contacts for use in other applications.
Proposed Enhancement: Add export command to export contacts to CSV or vCard format.
Implementation:
- Add
ExportCommandwith format parameter (csv, vcf) - Implement CSV and vCard serialization
- Add file chooser dialog for output path
Effort Estimate: ~7 hours
16. Summary
CourseBook is a robust, well-architected application for managing academic contacts. This Developer Guide provides comprehensive documentation of the system’s design, and implementation. Key highlights:
- Clean 4-layer architecture with strong separation of concerns
- 27 feature-rich commands covering all aspects of contact and course management
- Comprehensive undo/redo with theme persistence
- Extensible design following SOLID principles
- Thorough documentation for both users and developers
Whether you’re a new contributor, a student learning software architecture, or a teaching staff member evaluating the project, this guide should provide you with a deep understanding of CourseBook’s design and implementation.
For questions or contributions, please visit our GitHub repository.
End of Developer Guide