Requirements for the Task Manager
Functional Requirements
Let's define exactly what our Task Management System must do. Each requirement is specific enough to drive a class, method, or relationship in our design.
Task Lifecycle:
-
R1 — Create a Task: A user can create a new task with a title (required), description (optional), priority (LOW, MEDIUM, HIGH, URGENT), and an optional due date. Every task receives a unique identifier on creation. The initial status is always TODO.
-
R2 — Update a Task: A user can modify a task's title, description, priority, or due date after creation. Each update is recorded so it can be undone.
-
R3 — Delete a Task: A user can delete a task from a task list. Deleted tasks are removed permanently. The deletion itself is undoable (the task can be restored).
-
R4 — Task Status Transitions: A task's status can transition through the following states: TODO → IN_PROGRESS → DONE. Additionally, any state can transition to CANCELLED. Moving backward (e.g., DONE → IN_PROGRESS) is allowed for reopening tasks. Invalid transitions (e.g., TODO → DONE directly) are rejected.
Assignment and Organization:
-
R5 — Assign a Task: A task can be assigned to exactly one user at a time. Reassigning a task to a different user replaces the current assignee. Unassigned tasks are permitted.
-
R6 — Task Lists: Tasks are organized into task lists (think Trello boards or Jira projects). A task belongs to exactly one task list. A task list has a name and can contain zero or more tasks.
-
R7 — Search and Filter: Users can retrieve tasks filtered by: status, priority, assignee, or due date range. Multiple filters can be combined (e.g., "all HIGH priority tasks assigned to Alice that are IN_PROGRESS").
Notifications:
-
R8 — Watch a Task: Users can subscribe to (watch) a task. A user who watches a task receives notifications when the task's status, assignee, priority, or due date changes.
-
R9 — Notification on Change: When a watched task is modified, all watchers are notified with the change details (what field changed, old value, new value). The assignee is implicitly a watcher.
Undo/Redo:
-
R10 — Undo: The system supports undoing the most recent task operation (create, update, delete, status change, assignment). Undo reverses the operation — restoring the previous state.
-
R11 — Redo: After an undo, the user can redo to reapply the undone operation. If a new operation is performed after an undo, the redo history is cleared.
User Management:
- R12 — User Identification: Each user has a unique ID and a name. Users can create tasks, be assigned tasks, and watch tasks.
Non-Functional Requirements
Beyond what the system does, here's how it should behave:
-
Extensibility (Open/Closed Principle): Adding a new task status (e.g., BLOCKED, IN_REVIEW) should not require modifying existing classes that handle status transitions. Similarly, adding new notification channels (e.g., email, Slack webhook) should not require changes to the task update logic.
-
Testability: Each component — task CRUD, notification dispatch, undo/redo — should be testable in isolation. The Observer and Command patterns help here by decoupling responsibilities.
-
Single Responsibility: The class that manages task storage should not also handle notifications. The class that executes commands should not also manage the undo/redo stack. Each class has one reason to change.
-
Undo Safety: The undo/redo mechanism must be consistent — undoing a "create" must fully remove the task, undoing a "delete" must fully restore it, and undoing a field update must restore the exact previous value.
Scope Clarification
In Scope:
- Task CRUD operations (create, read, update, delete)
- Task status transitions with validation
- Task assignment to users
- Task lists as organizational containers
- Observer-based notification system for task watchers
- Command-based undo/redo for all task mutations
- Filtering tasks by status, priority, assignee, and due date
- User identification (ID + name)
Out of Scope:
- Persistence — no database layer; all data lives in memory. In a real system, you'd add a repository layer.
- Authentication/Authorization — we assume any user can perform any operation. A real system would enforce role-based access (admin, member, viewer).
- REST API layer — no HTTP endpoints. We design the domain model that an API layer would call.
- Real-time sync — no WebSocket notifications. Our Observer delivers in-memory callbacks.
- Sub-tasks and dependencies — tasks are standalone. Adding parent-child relationships is a natural extension but not core.
- Comments and attachments — these are common features in real task managers but add complexity without introducing new design patterns.
- Recurring tasks and templates — out of scope for this design.
Requirements → Design Mapping
Here's a preview of how each requirement will drive our class design:
| Requirement | Design Element |
|---|---|
| R1 (Create Task) | Task class with id, title, description, priority, dueDate, status |
| R2 (Update Task) | UpdateTaskCommand encapsulating field-level changes |
| R3 (Delete Task) | DeleteTaskCommand with undo restoring the task |
| R4 (Status Transitions) | TaskStatus enum + validation logic in Task.transition() |
| R5 (Assign Task) | AssignTaskCommand + assignee field on Task |
| R6 (Task Lists) | TaskList class composing multiple Task objects |
| R7 (Filter) | Filter methods on TaskManager accepting status, priority, assignee, date criteria |
| R8 (Watch) | Observer pattern — Task maintains list of TaskObserver subscribers |
| R9 (Notify) | TaskObserver interface with onTaskChanged() callback |
| R10 (Undo) | Command pattern — CommandHistory managing an undo stack |
| R11 (Redo) | CommandHistory maintaining a redo stack cleared on new commands |
| R12 (Users) | User class with id and name |
Every class in our design traces back to at least one requirement. If a class can't be justified by a requirement, it shouldn't exist.
Interview Tip
In a real LLD interview, spend 3-5 minutes clarifying requirements before jumping into design. For a Task Management System, smart clarifying questions include:
- "Should tasks support sub-tasks or dependencies?" — This dramatically increases complexity. Clarify early.
- "Is undo per-user or global?" — We'll design it as global (one shared history), but per-user undo is a valid extension.
- "Can a task exist outside a task list?" — We'll require every task to belong to exactly one list.
- "How many watchers per task do we expect?" — This helps determine if a simple list suffices or if we need a more scalable structure.
- "Are status transitions strictly linear, or can tasks move backward?" — Our design allows reopening (DONE → IN_PROGRESS) but rejects skipping (TODO → DONE).
These questions show the interviewer that you think about edge cases and scope boundaries — not just the happy path.