Introduction to Software Engineering · Chapter 06
Lab-06: Unified Modeling Language (UML)
Your team turns the Lab-05 requirements into the core UML models of ITC Club Hub: a use case diagram, a domain class diagram that you translate into C++ headers, a sequence diagram for "register for an event", an activity diagram for check-in at the door, and a state machine for Registration that you implement and test in C++. The challenge models the monthly activity report and gives a component overview of the whole system.
Setup
20 min- Tools. Diagram sources are plain text: PlantUML (
.puml) for the use case diagram and Mermaid (.mmd) for the others. Install VS Code with the extensions PlantUML (jebbs) and Markdown Preview Mermaid Support, or use the online editorsplantuml.com/plantumlandmermaid.liveto preview and export PNG. For the C++ part you need the toolchain from earlier labs: a C++20 compiler (GCC 13, Clang 17 or Visual Studio 2022), CMake 3.28 or later, Git.git switch main && git pull git switch -c lab-06 cmake --version # 3.28 or later g++ --version # or clang++ / cl: must support C++20 java -version # optional: only to render PlantUML locally # optional command-line export of Mermaid diagrams (needs Node.js) npx -p @mermaid-js/mermaid-cli mmdc -h - Inputs from earlier labs. This lab turns the Lab-05 requirements into models and extends the C++ project from earlier labs. If one of your earlier deliverables is incomplete, use the fallback; do not stop to repair the earlier lab.
Input File (your team's name may differ) What you need from it Fallback if missing User stories lab05/user-stories.mdRoles ("As a ...") become actors; goals ("I want to ...") become use cases (Task 1) The feature list in the case-study brief below; one story per bullet. Textual use case lab05/use-case-register-for-event.mdMain flow and alternative flows of "Register for event" (Task 4) Main flow: student picks an event, system checks it is in the future, not full and not already registered, stores the registration, confirms. Alternatives: event full, already registered, event in the past. SRS lab05/srs.mdGlossary, data items and business rules BR-01..BR-05 (Tasks 2 and 5) Business rules and personal data in the case-study brief. Traceability matrix lab05/traceability-matrix.csvStory ids to link use cases back to stories (Task 1) Number the stories US-01.. yourself in lab06/use-case-notes.md.C++ project CMakeLists.txt,include/clubhub/,src/,tests/A building project with GoogleTest via FetchContent(Tasks 3 and 5)The minimal CMakeLists.txtin the Task 3 starter. - Case-study brief. The box below holds every fact about ITC Club Hub that this lab needs.
Case-study brief: ITC Club Hub
- Purpose
- An application for student clubs at the Institute of Technology of Cambodia. Teams model it as a web and mobile system and implement its core in C++20: domain model, business rules, a command-line front end and CSV or JSON file storage.
- Actors
- Student browses events, registers, cancels and receives a reminder. Organiser checks registered students in at the door and sees attendance. Club Leader registers a club and publishes its events. Administrator approves clubs and sees a monthly activity report across clubs. Email Service is an external system that delivers reminders.
- Data
- Club: name, description, status (Pending, Approved, Rejected). Event: title, date and time, location, capacity, description. Student: student ID (for example
e20230001), name, email, phone (optional), club membership. Registration: status (Registered, Cancelled, CheckedIn, Waitlisted), time of registration; attendance is derived from check-ins. - Business rules
BR-01capacity cannot be exceeded (a waiting list is a Should feature) ·BR-02a student cannot register twice for the same event ·BR-03cancellation closes 24 hours before the start ·BR-04events in the past cannot be registered for ·BR-05only approved clubs can publish events. If your Lab-05 SRS numbers them differently, use your numbers.- Code names
- Namespace
clubhub; classesClub,Event,Student,Registration; enumsClubStatus,RegistrationStatus;RegistrationServicewithregisterStudent,cancel,checkIn; interfacesEventRepository,RegistrationRepositorywith CSV-backed implementations. Layout:CMakeLists.txt,src/,include/clubhub/,tests/,.github/workflows/ci.yml. - Rhythm
- Week 7: this lab. Week 8: midterm and project checkpoint 1, where these models are reviewed. Sprint 1 (weeks 9 and 10) implements the first stories from them. Roles: one Product Owner, a rotating Scrum Master, the rest Developers.
- Deliverable folder. Create
lab06/with these files; every task fills some of them.clubhub/ ├── lab05/ # earlier lab, read-only here ├── lab06/ │ ├── use-case-diagram.puml + .png # Task 1 │ ├── use-case-notes.md # Task 1 │ ├── class-diagram.mmd + .png # Task 2 │ ├── consistency.md # Task 3 │ ├── sequence-register.mmd + .png # Task 4 │ ├── activity-checkin.mmd + .png # Task 4 │ ├── state-registration.mmd + .png # Task 5 │ ├── state-table.md # Task 5 │ ├── README.md # Task 5 (record what changed) │ └── challenge/ # Challenge (optional) ├── include/clubhub/ # Tasks 3 and 5: *.hpp ├── src/ # Tasks 3 and 5: *.cpp └── tests/registration_rules_test.cpp # Task 5 - Conventions. Every diagram source starts with a title, a version and a date (
' v1.0 2026-10-..in PlantUML,%% v1.0 2026-10-..in Mermaid). Names in diagrams are the code names from the brief, spelled identically. Commit the source and the exported PNG together, one commit per diagram at least.
Use case diagram from the user stories
Easy 40 min · led by the Product OwnerGoal
Show who uses ITC Club Hub and for which goals in one PlantUML use case diagram, derived from your Lab-05 user stories, with one justified «include» and one justified «extend».
Steps
- Go through
lab05/user-stories.md. Every role in "As a <role>" is an actor candidate; merge synonyms ("member" and "student" are one role). You should end withStudent,Organiser,Club Leader,Administratorand the secondary actorEmail Service. - Turn every goal ("I want to ...") into a use case named verb + object ("Register for event", "Approve club"). Drop user-interface steps such as "click", "type" or "open the menu". Aim for 10 to 14 use cases.
- Write
lab06/use-case-diagram.pumlfrom the starter:left to right direction, arectangle "ITC Club Hub"as system boundary with all use cases inside, actors outside, one association line per actor goal. - Add exactly one «include» (a step that two use cases always share, for example "Identify student") and one «extend» (optional behaviour under a condition, for example "Join waiting list" when the event is full). Check the arrow directions: include from base to included, extend from extension to base.
- In
lab06/use-case-notes.md, justify each of the two relationships in two or three sentences, and add a table use case → story ids. Every Must story must appear in at least one row. - Export
lab06/use-case-diagram.png(VS Code: PlantUML: Export Current Diagram; orjava -jar plantuml.jar -tpng lab06/use-case-diagram.puml) and commit the source, the PNG and the notes.
Starter
@startuml
' ITC Club Hub: use case diagram · v1.0 · 2026-10-..
left to right direction
actor Student
actor Organiser
actor "Club Leader" as Leader
actor Administrator as Admin
actor "Email Service" as Mail
rectangle "ITC Club Hub" {
usecase "Browse events" as UC1
usecase "Register for event" as UC2
' TODO: one usecase line per goal from lab05/user-stories.md
}
Student -- UC1
Student -- UC2
' TODO: associations for Organiser, Leader, Admin, Mail
' TODO: one include and one extend, for example
' UC2 ..> UCx : <<include>>
' UCy ..> UC2 : <<extend>>
@enduml
Expected output
A diagram shaped like the one on slide 8 of the chapter, but built from your stories. An excerpt of a good use-case-notes.md:
## Relationships
- «include» Register for event → Identify student: both "Register for
event" (US-04) and "Check in student" (US-11) always identify the
student by student ID first; the shared steps are written once.
- «extend» Join waiting list → Register for event: only when the event
is full (BR-01) does the student get the waiting-list offer (US-06,
Should).
## Use case to story
| Use case | Actor(s) | Stories |
|---------------------|-------------------------|--------------|
| Register for event | Student | US-04, US-05 |
| Check in student | Organiser | US-11 |
| Send reminder | Email Service | US-08 |
- An actor is a role, never a person ("Dara") or a job title outside the system ("Dean").
- A reminder that is sent automatically is still a use case; its primary trigger is time, and the Email Service is the secondary actor that delivers it.
- If PlantUML shows actors inside the rectangle, you declared them inside the
rectangle { }block: move theactorlines above it. - «include» and «extend» are optional in general, but this task requires one of each so that you practise the arrow directions.
Acceptance checklist
Domain class diagram in Mermaid
Easy 45 min · two Developers, reviewed by the Product OwnerGoal
Model the Club Hub domain as a Mermaid classDiagram with typed attributes, associations with multiplicities on both ends, one composition and the two enumerations.
Steps
- Underline the nouns in the SRS and the stories. Keep as classes the concepts with their own identity and data:
Club,Event,Student,Registration. Nouns that are just a value ("location", "capacity") become attributes. - In
lab06/class-diagram.mmd, give each class all attributes from the brief with visibility and type:-id: int,-start: sys_seconds,-phone: optional~string~(Mermaid writes generics with~). - Add
ClubStatus(Pending,Approved,Rejected) andRegistrationStatus(Registered,Cancelled,CheckedIn,Waitlisted) with the<<enumeration>>annotation, and use them as attribute types. - Draw the associations with a multiplicity on both ends: exactly one composition
Club "1" *-- "0..*" Event, plusEvent "1" -- "0..*" RegistrationandStudent "1" -- "0..*" Registration. Add club membership (Student "0..*" -- "0..*" Club) if your stories need it. - Add the operations the business rules need:
Club+approve(),+publish(e: Event);Registration+cancel(now, eventStart),+checkIn();Event+isInPast(now) bool. - Test the model with one real situation: can you place "Dara is registered for the Arduino Workshop of the Robotics Club, and is on the waiting list of the Robot Race"? If not, fix the diagram. Export
lab06/class-diagram.png(mermaid.live, ornpx -p @mermaid-js/mermaid-cli mmdc -i lab06/class-diagram.mmd -o lab06/class-diagram.png) and commit.
Starter
%% ITC Club Hub: domain class diagram · v1.0 · 2026-10-..
classDiagram
class Club {
-id: int
-name: string
-status: ClubStatus
+approve() void
+publish(e: Event) void
}
class Event {
-id: int
-title: string
%% TODO: start, location, capacity, description, isInPast(now)
}
class Student {
%% TODO: studentId, name, email, phone (0..1)
}
class Registration {
%% TODO: id, status, registeredAt, cancel(now, eventStart), checkIn()
}
class ClubStatus {
<<enumeration>>
Pending
Approved
Rejected
}
%% TODO: RegistrationStatus
Club "1" *-- "0..*" Event : publishes
%% TODO: the two associations of Registration
Expected output
The Registration corner of a good diagram (your complete diagram has all four classes and both enumerations):
classDiagram
class Event {
-id: int
-capacity: int
+isInPast(now) bool
}
class Student {
-studentId: string
-phone: optional~string~
}
class Registration {
-id: int
-status: RegistrationStatus
-registeredAt: sys_seconds
+cancel(now, eventStart) void
+checkIn() void
}
class RegistrationStatus {
<<enumeration>>
Registered
Cancelled
CheckedIn
Waitlisted
}
Event "1" -- "0..*" Registration
Student "1" -- "0..*" Registration
Registration ..> RegistrationStatus
- Do not put
event: Eventas an attribute ofRegistrationand draw the association: show the link once, as the line. - Composition fits
Club/Eventbecause an event cannot exist without its club and is deleted with it. A registration is not "owned" by a student in that sense: use a plain association. - Inside a
<pre>or Markdown file you can write<<enumeration>>directly; only HTML pages need it escaped. - If mermaid.live reports a parse error, check for a missing closing brace or a space between a class name and
{on the same line.
Acceptance checklist
From the class diagram to C++ headers
Medium 60 min · each Developer writes one headerGoal
Translate the class diagram into four headers in include/clubhub/ that compile with the team's CMake project, and prove with a consistency table that diagram and code contain exactly the same classes, attributes, associations and enum values.
Steps
- Create
include/clubhub/event.hpp,club.hpp,student.hppandregistration.hpp:#pragma once, namespaceclubhub, one class per header. Split the four headers between the Developers so that each appears in a different member's commit. - Apply the mapping from the chapter:
-attributes becomeprivatemembers with a trailing underscore andconstgetters;+operations becomepublicmember functions; enumerations becomeenum class(ClubStatusinclub.hpp,RegistrationStatusinregistration.hpp); time isstd::chrono::sys_seconds. - Map the relationships: the composition becomes
std::vector<Event> events_;inClub; the associations ofRegistrationbecome ids (int eventId_;,std::string studentId_;);0..1becomesstd::optional<std::string> phone_;. No rawnewor owning pointers. - Put member function bodies that are more than one line in
src/club.cppandsrc/registration.cpp(for exampleClub::publishthrowsstd::logic_errorunless the club isApproved, rule BR-05) and add both files to theclubhub_corelibrary inCMakeLists.txt. - Build from a clean folder:
cmake -S . -B build && cmake --build build. Fix every warning. - Fill
lab06/consistency.md: one row per class, attribute, association end and enum value, with its place in code. Then read the headers and add a row for anything in code that is missing from the diagram. Fix the diagram or the code until every row is ✓.
Starter
// include/clubhub/registration.hpp
#pragma once
#include <chrono>
#include <stdexcept>
#include <string>
namespace clubhub {
enum class RegistrationStatus { Registered, Cancelled, CheckedIn, Waitlisted };
// thrown when a business rule (BR-01..BR-05) rejects an operation
class RegistrationError : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
};
class Registration {
public:
Registration(int id, int eventId, std::string studentId,
std::chrono::sys_seconds registeredAt);
void cancel(std::chrono::sys_seconds now,
std::chrono::sys_seconds eventStart);
void checkIn();
int id() const { return id_; }
int eventId() const { return eventId_; }
// TODO: studentId(), status(), registeredAt()
private:
int id_;
int eventId_; // association Registration -- "1" Event
// TODO: studentId_ (association to Student), status_, registeredAt_
};
} // namespace clubhub
# CMakeLists.txt (fallback if your project has no core library yet)
cmake_minimum_required(VERSION 3.28)
project(clubhub LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(clubhub_core
src/club.cpp
src/registration.cpp
)
target_include_directories(clubhub_core PUBLIC include)
if(MSVC)
target_compile_options(clubhub_core PRIVATE /W4)
else()
target_compile_options(clubhub_core PRIVATE -Wall -Wextra -Wpedantic)
endif()
Expected output
$ cmake -S . -B build && cmake --build build
-- Configuring done
-- Generating done
[ 33%] Building CXX object CMakeFiles/clubhub_core.dir/src/club.cpp.o
[ 66%] Building CXX object CMakeFiles/clubhub_core.dir/src/registration.cpp.o
[100%] Linking CXX static library libclubhub_core.a
[100%] Built target clubhub_core
| Diagram element | C++ | ✓ |
|----------------------------------------|---------------------------------------------|---|
| class Registration | include/clubhub/registration.hpp | ✓ |
| Registration -status: RegistrationStatus | Registration::status_ | ✓ |
| Event "1" -- "0..*" Registration | Registration::eventId_ (many side: repo) | ✓ |
| Club "1" *-- "0..*" Event | Club::events_ (std::vector<Event>) | ✓ |
| Student -phone [0..1] | Student::phone_ (std::optional) | ✓ |
| RegistrationStatus::Waitlisted | enum class RegistrationStatus | ✓ |
| (code only) Event::description_ | added to the diagram in v1.1 | ✓ |
- A header that is never included is never compiled.
src/club.cppincludesclub.hpp, which includesevent.hpp; make surestudent.hppandregistration.hppare included by some.cpptoo. - Why ids instead of
const Event&? Registrations and events are loaded from different CSV files; a reference would dangle after a reload. The chapter's slide 12 explains it. std::chrono::sys_secondsneeds<chrono>; build a value withstd::chrono::sys_days{2026y / std::chrono::October / 15} + 14h.- The "many" side of an association (an event's registrations) is usually not a member: a repository answers that question later.
Acceptance checklist
Sequence diagram and activity diagram
Medium 60 min · two pairs in parallel, Scrum Master runs the walk-throughGoal
Model the behaviour of two scenarios: "register for an event" as a sequence diagram whose messages are real C++ function names, including the full-event and already-registered alternatives, and "check-in at the door" as an activity diagram with decisions, a fork/join and one lane per participant.
Steps
- Pair A reads the textual use case from Lab-05 and lists the main flow and the alternative flows event is full (BR-01) and already registered (BR-02). Pair B lists the check-in steps as an organiser at the door would do them.
- Pair A writes
lab06/sequence-register.mmdwith the lifelinesStudent(actor),CLI,RegistrationService,EventRepository,RegistrationRepository, and messagesregisterStudent(studentId, eventId, now),findById,findActive(studentId, eventId),countActive(eventId),save(registration)with dashed returns. - Pair A adds one
altfragment with three operands:[already registered],[event is full],[else]; each ends with the message the CLI prints. Show the activation ofRegistrationService. - Pair B writes
lab06/activity-checkin.mmdas aflowchart LR: start and end nodes (@{ shape: sm-circ },@{ shape: fr-circ }), onesubgraphper lane (Student, Organiser, Club Hub), decisions registered for this event? and already checked in? with a guard on every outgoing branch, and a fork/join (@{ shape: fork },@{ shape: join }) around "mark CheckedIn" and "update attendance count". - Walk-through (Scrum Master): one member plays each lifeline and reads the messages aloud. Every message must exist as a declaration in
include/clubhub/; add the missing ones toregistration_service.hpp,event_repository.hpporregistration_repository.hpp(declarations only, bodies come in Sprint 1). - Export both PNGs, commit sources, PNGs and the new declarations, and rebuild to be sure the headers still compile.
Starter
%% Register for an event: main flow and alternatives · v1.0 · 2026-10-..
sequenceDiagram
actor S as Student
participant CLI
participant RS as RegistrationService
participant ER as EventRepository
participant RR as RegistrationRepository
S->>CLI: register 12
CLI->>RS: registerStudent("e20230001", 12, now)
activate RS
RS->>ER: findById(12)
ER-->>RS: Event
%% TODO: findActive and countActive calls
alt already registered
RS-->>CLI: throw RegistrationError
CLI-->>S: "You are already registered"
else event is full
%% TODO
else
%% TODO: save(registration), return, confirmation
end
deactivate RS
Expected output
The shape of a good activity diagram (your version adds the already checked in? decision and your own action names):
flowchart LR
start@{ shape: sm-circ, label: "start" }
subgraph O["Organiser"]
o1[Type student ID]
d1{Registered?}
o3[Send to club desk]
end
subgraph C["Club Hub"]
c0[Look up registration]
f1@{ shape: fork, label: "fork" }
c1[Mark CheckedIn]
c2[Update attendance]
j1@{ shape: join, label: "join" }
end
stop@{ shape: fr-circ, label: "end" }
start --> o1 --> c0 --> d1
d1 -- "[no]" --> o3 --> stop
d1 -- "[yes]" --> f1
f1 --> c1 --> j1
f1 --> c2 --> j1
j1 --> stop
- Order the checks in the diagram as the code will run them: find the event, then the duplicate check, then the capacity check. Cheap checks first.
- Mermaid: an
altwith severalelselines is allowed; a plainelsewithout text is fine for the success branch. - The fork/join shapes need Mermaid 11.3 or later (mermaid.live is always current). If your editor is older, use a node labelled "fork" and mention it in the notes.
- A decision diamond is a question; its outgoing edges carry the answers in brackets, for example
d1 -- "[no]" --> o3.
Acceptance checklist
State machine for Registration, implemented and tested
Hard
75 min · Developers, one commit per member
Goal
Draw the life cycle of a Registration as a state machine, implement exactly its allowed transitions in C++ (illegal transitions throw), prove it with GoogleTest, and record what this lab changed in lab06/README.md.
Steps
- Write
lab06/state-registration.mmd(stateDiagram-v2) with the statesRegistered,Waitlisted,Cancelled,CheckedIn, the initial and final pseudo-states, the eventsregister,seatFreed,cancel,checkIn, and the guards[seat free],[event full],[start - now >= 24 h]. - Derive
lab06/state-table.md: rows = the four states, columns =seatFreed,cancel,checkIn, cells = next state or illegal. Diagram and table must agree cell by cell. - Implement
include/clubhub/registration_rules.hppandsrc/registration_rules.cpp:enum class Trigger,toString(RegistrationStatus)andnext(RegistrationStatus from, Trigger t)as aswitchonfromthat returns the new state or throwsIllegalTransition. Add the file toclubhub_core. - Use
nextinRegistration::cancel(after checking the 24-hour guard, BR-03) andRegistration::checkIn, so the class cannot reach a state the diagram does not allow. - Write
tests/registration_rules_test.cpp: one test per legal transition (four) and at least three illegal ones withEXPECT_THROW, plus one test for the 24-hour guard. Register it withgtest_discover_testsand runctest --test-dir build --output-on-failure. - Record what changed. Create
lab06/README.mdfrom the template below: the table of this lab's files, the Lab-05 inputs reused with their commit hash (git log -1 --format=%h -- lab05/), who led each task, and one change-log row.
Starter
// include/clubhub/registration_rules.hpp
#pragma once
#include <stdexcept>
#include <string_view>
#include "clubhub/registration.hpp"
namespace clubhub {
enum class Trigger { SeatFreed, Cancel, CheckIn };
class IllegalTransition : public std::logic_error {
public:
using std::logic_error::logic_error;
};
std::string_view toString(RegistrationStatus s);
// Returns the state after trigger t, or throws IllegalTransition
// for every arrow that is not in lab06/state-registration.mmd.
RegistrationStatus next(RegistrationStatus from, Trigger t);
} // namespace clubhub
// tests/registration_rules_test.cpp
#include <gtest/gtest.h>
#include "clubhub/registration_rules.hpp"
using clubhub::next;
using clubhub::RegistrationStatus;
using clubhub::Trigger;
TEST(RegistrationRules, WaitlistedBecomesRegisteredWhenSeatFreed) {
EXPECT_EQ(next(RegistrationStatus::Waitlisted, Trigger::SeatFreed),
RegistrationStatus::Registered);
}
TEST(RegistrationRules, CheckedInCannotBeCancelled) {
EXPECT_THROW(next(RegistrationStatus::CheckedIn, Trigger::Cancel),
clubhub::IllegalTransition);
}
// TODO: the three other legal transitions, two more illegal ones,
// and Registration::cancel less than 24 h before the start
# Lab-06 · UML models (v1.0, 2026-10-..)
| File | Content | Led by |
|------|---------|--------|
| use-case-diagram.puml / .png | actors and goals, 1 include, 1 extend | PO |
| ... | ... | ... |
## Inputs reused
| Input | Version / commit |
|-------|------------------|
| lab05/user-stories.md | a1b2c3d |
## Change log
| Date | Change | Reason |
|------|--------|--------|
| 2026-10-.. | Lab-06 models and headers created | Lab-06 |
Expected output
$ ctest --test-dir build --output-on-failure
Test project C:/work/clubhub/build
1/8 Test #1: RegistrationRules.WaitlistedBecomesRegisteredWhenSeatFreed ... Passed
2/8 Test #2: RegistrationRules.WaitlistedCanBeCancelled ................ Passed
3/8 Test #3: RegistrationRules.RegisteredCanBeCancelled ................ Passed
4/8 Test #4: RegistrationRules.RegisteredCanCheckIn .................... Passed
5/8 Test #5: RegistrationRules.CheckedInCannotBeCancelled .............. Passed
6/8 Test #6: RegistrationRules.CancelledCannotCheckIn .................. Passed
7/8 Test #7: RegistrationRules.WaitlistedCannotCheckIn ................. Passed
8/8 Test #8: Registration.CancelLessThan24hBeforeStartThrows ........... Passed
100% tests passed, 0 tests failed out of 8
- Write the
switchwithout adefault:label: then GCC and Clang with-Wallwarn when a new enumerator is not handled (MSVC only with the off-by-default warning C4062). using enum RegistrationStatus;(C++20) inside the function lets you writeRegisteredinstead of the full name.- The guard belongs to the operation, the transition to the rules function:
if (eventStart - now < 24h) throw RegistrationError{...}; status_ = next(status_, Trigger::Cancel); - If GoogleTest is not yet in your project, add it with
FetchContent_Declare(googletest URL https://github.com/google/googletest/archive/refs/tags/v1.15.2.zip),FetchContent_MakeAvailable(googletest),enable_testing()andinclude(GoogleTest).
Acceptance checklist
Challenge: model the monthly activity report
Hard 90–120 min · optional, extra creditScenario
The Administrator wants, for any month, one line per approved club: number of events held, registrations, check-ins and attendance rate. Before anyone writes code, the team models the feature: how the report is computed (sequence), which new classes it needs, and where it fits in the system (component overview).
Requirements
lab06/challenge/report-sequence.mmd: Administrator → CLI →ReportService::monthlyReport(year_month)→EventRepository::findByMonthandRegistrationRepository::findByEvent, with aloopfragment over the events and anoptfragment for "no events this month".lab06/challenge/report-classes.mmd: the classes the report needs (for exampleReportService,MonthlyReport,ClubActivity), with attributes, multiplicities and the dependencies on the two repository interfaces.lab06/challenge/components.puml: a PlantUML component diagram withclubhub-cli,clubhub_core(domain and services),clubhub_storage(CSV repositories) and the CSV files, showing the repository interfaces as provided/required interfaces.lab06/challenge/notes.md: five to eight sentences on what the Software Engineering course will add to this picture (a web layer with a REST API, a database behind the same repository interfaces, authentication, a mobile or browser client) and which of today's components survive unchanged.
Skeleton
@startuml
' ITC Club Hub: component overview · v1.0 · 2026-10-..
component "clubhub-cli" as CLI
component "clubhub_core" as Core
component "clubhub_storage" as Storage
interface EventRepository
interface RegistrationRepository
artifact "events.csv" as EvCsv
' TODO: registrations.csv
CLI ..> Core : uses
Core --( EventRepository
Storage -- EventRepository
' TODO: the second interface, and Storage ..> the CSV artifacts
@enduml
Expected output
Monthly activity report · 2026-10
Club Events Registrations Check-ins Attendance
Robotics Club 3 74 61 82 %
Photography Club 2 40 29 73 %
English Club 0 0 0 n/a
- Attendance rate = check-ins / registrations that were not cancelled; decide and write down what "n/a" means when a club had no events.
std::chrono::year_month(C++20) is a precise type for "a month"; use it in the operation signature.- In PlantUML,
A --( Idraws a required interface (socket) andB -- Ia provided one (ball). - A web layer would call
ReportServiceexactly as the CLI does: that is the point of keeping the core independent of the front end.
Acceptance checklist
Grading rubric
| Component | Points | Full marks when… |
|---|---|---|
| Task 1 · Use case diagram | 10 | Five actors outside the boundary, goal-level use cases traced to every Must story, one include and one extend drawn correctly and justified. |
| Task 2 · Domain class diagram | 15 | Four classes with typed attributes, both enumerations with canonical values, multiplicities on every association end, one composition; renders without errors. |
| Task 3 · C++ headers | 20 | Four headers compile cleanly with the CMake project; mapping rules applied (vector, ids, optional, enum class); consistency table complete in both directions. |
| Task 4 · Sequence and activity | 20 | Sequence diagram with real function names, activation and a three-branch alt; activity diagram with lanes, guarded decisions and matching fork/join; declarations exist in code. |
| Task 5 · State machine in C++ | 25 | Diagram, state table and next() agree exactly; illegal transitions throw; eight or more passing tests; README with inputs, roles and change log. |
| Diagram and code quality | 10 | Titles, versions and dates on every diagram; consistent names across diagrams and code; readable layout; contributions from every member visible in Git. |
| ★ Challenge (extra credit) | +20 | Report sequence with loop and opt, report classes, component overview with interfaces, and a clear note on what the Software Engineering course adds. |
| Total | 100 (+20) |
lab-06 branch · -5 per transition that exists in code but not in the state machine (or the reverse).Submission
- Repository layout after this lab:
clubhub/ ├── CMakeLists.txt ├── include/clubhub/ │ ├── club.hpp event.hpp student.hpp registration.hpp │ ├── registration_rules.hpp │ └── registration_service.hpp event_repository.hpp registration_repository.hpp ├── src/ │ ├── club.cpp registration.cpp registration_rules.cpp ├── tests/ │ └── registration_rules_test.cpp ├── lab05/ ... └── lab06/ ├── use-case-diagram.puml use-case-diagram.png use-case-notes.md ├── class-diagram.mmd class-diagram.png consistency.md ├── sequence-register.mmd sequence-register.png ├── activity-checkin.mmd activity-checkin.png ├── state-registration.mmd state-registration.png state-table.md ├── README.md └── challenge/ # optional - Self-check from a clean checkout; all three commands must succeed:
and everycmake -S . -B build && cmake --build build && ctest --test-dir build.mmdand.pumlfile opens without errors in mermaid.live or the PlantUML preview, with its PNG next to it. - Push branch
lab-06and open a pull request titledLab-06 – <team name>. In the description, list who led each task and linklab06/README.md. At least one other team member approves before merge.