1. Install VSCode Plugin and PUML Definitions
1.1. VSCode Plugin
Install the following plugin in VSCode
1.2. The Visualized Result
Now we make use of the plugin we just installed in vscode to preview the puml file:

We get the live-preview visualized from the PlantUML definitions:
2. Custom Definition of Objects in PlantUML and Examples in DDD
2.1. lib_eventstorming.puml, a Modularized File
In this file we have defined the following syntax:
The ones we use most of the time:
CommandAggrgatePolicyHandler
The remaining comes in handy:
EsEntityArrowFacadeCommmandResultEventDomainEventIntegrationEventQueryReadeModelUserInterfaceServiceSagaProcessTimerPersonSystemComment
1!global $ICON_FORMAT="png" 2!global $TEXT_WIDTH_MAX=200 3!global $MSG_WIDTH_MAX=150 4!global $FONT_SIZE_XS=10 5!global $FONT_SIZE_SM=12 6!global $FONT_SIZE_MD=16 7!global $FONT_SIZE_LG=20 8!global $FONT_COLOR="#212121" 9!global $FONT_COLOR_LIGHT="#757575" 10 11!procedure EsEntity($shape, $stereotype, $id, $label="") 12 !if ($label != "") 13 $shape "$label" as $id <<$stereotype>> 14 !else 15 $shape $id <<$stereotype>> 16 !endif 17!endprocedure 18 19show stereotype 20 21skinparam defaultTextAlignment center 22skinparam wrapWidth 400 23skinparam maxMessageSize 150 24 25skinparam Arrow { 26 Color $FONT_COLOR 27 FontColor $FONT_COLOR 28 FontSize $FONT_SIZE_SM 29} 30 31' definition of the Item eventstorming/Element/FacadeCommand 32skinparam file<<FacadeCommand>> { 33 StereotypeFontSize $FONT_SIZE_SM 34 shadowing false 35 FontColor $FONT_COLOR 36 BorderColor $FONT_COLOR 37 BackgroundColor #779fae 38} 39 40!procedure FacadeCommand($id, $label="") 41 EsEntity('file', 'FacadeCommand', $id, $label) 42!endprocedure 43' definition of the Item eventstorming/Element/Command 44 45skinparam file<<Command>> { 46 StereotypeFontSize $FONT_SIZE_SM 47 shadowing false 48 FontColor $FONT_COLOR 49 BorderColor $FONT_COLOR 50 BackgroundColor #aec6cf 51} 52 53!procedure Command($id, $label="") 54 EsEntity('file', 'Command', $id, $label) 55!endprocedure 56 57' definition of the Item eventstorming/Element/Result 58skinparam file<<Result>> { 59 StereotypeFontSize $FONT_SIZE_SM 60 shadowing false 61 FontColor $FONT_COLOR 62 BorderColor $FONT_COLOR 63 BackgroundColor #cfcfc4 64} 65 66!procedure Result($id, $label="") 67 EsEntity('file', 'Result', $id, $label) 68!endprocedure 69' definition of the Item eventstorming/Element/Event 70 71 72skinparam file<<Event>> { 73 StereotypeFontSize $FONT_SIZE_SM 74 shadowing false 75 FontColor $FONT_COLOR 76 BorderColor $FONT_COLOR 77 BackgroundColor #ffb853 78} 79 80!procedure Event($id, $label="") 81 EsEntity('file', 'Event', $id, $label) 82!endprocedure 83 84' definition of the Item eventstorming/Element/DomainEvent 85skinparam file<<DomainEvent>> { 86 StereotypeFontSize $FONT_SIZE_SM 87 shadowing false 88 FontColor $FONT_COLOR 89 BorderColor $FONT_COLOR 90 BackgroundColor #ffcb81 91} 92 93!procedure DomainEvent($id, $label="") 94 EsEntity('file', 'DomainEvent', $id, $label) 95!endprocedure 96 97' definition of the Item eventstorming/Element/IntegrationEvent 98skinparam file<<IntegrationEvent>> { 99 StereotypeFontSize $FONT_SIZE_SM 100 shadowing false 101 FontColor $FONT_COLOR 102 BorderColor $FONT_COLOR 103 BackgroundColor #ffdeaf 104} 105 106!procedure IntegrationEvent($id, $label="") 107 EsEntity('file', 'IntegrationEvent', $id, $label) 108!endprocedure 109 110' definition of the Item eventstorming/Element/Query 111skinparam file<<Query>> { 112 StereotypeFontSize $FONT_SIZE_SM 113 shadowing false 114 FontColor $FONT_COLOR 115 BorderColor $FONT_COLOR 116 BackgroundColor #62d862 117} 118 119!procedure Query($id, $label="") 120 EsEntity('file', 'Query', $id, $label) 121!endprocedure 122 123' definition of the Item eventstorming/Element/ReadModel 124aram file<<ReadModel>> { 125 StereotypeFontSize $FONT_SIZE_SM 126 shadowing false 127 FontColor $FONT_COLOR 128 BorderColor $FONT_COLOR 129 BackgroundColor #77dd77 130} 131 132!procedure ReadModel($id, $label="") 133 EsEntity('file', 'ReadModel', $id, $label) 134!endprocedure 135 136' definition of the Item eventstorming/Element/UserInterface 137skinparam file<<UserInterface>> { 138 StereotypeFontSize $FONT_SIZE_SM 139 shadowing false 140 FontColor $FONT_COLOR 141 BorderColor $FONT_COLOR 142 BackgroundColor #a2e8a2 143} 144 145!procedure UserInterface($id, $label="") 146 EsEntity('file', 'UserInterface', $id, $label) 147!endprocedure 148 149' definition of the Item eventstorming/Element/Aggregate 150skinparam file<<Aggregate>> { 151 StereotypeFontSize $FONT_SIZE_SM 152 shadowing false 153 FontColor $FONT_COLOR 154 BorderColor $FONT_COLOR 155 BackgroundColor #fdfd9d 156} 157 158!procedure Aggregate($id, $label="") 159 EsEntity('file', 'Aggregate', $id, $label) 160!endprocedure 161 162' definition of the Item eventstorming/Element/Service 163skinparam file<<Service>> { 164 StereotypeFontSize $FONT_SIZE_SM 165 shadowing false 166 FontColor $FONT_COLOR 167 BorderColor $FONT_COLOR 168 BackgroundColor #fcfc78 169} 170 171!procedure Service($id, $label="") 172 EsEntity('file', 'Service', $id, $label) 173!endprocedure 174' definition of the Item eventstorming/Element/Policy 175 176skinparam file<<Policy>> { 177 StereotypeFontSize $FONT_SIZE_SM 178 shadowing false 179 FontColor $FONT_COLOR 180 BorderColor $FONT_COLOR 181 BackgroundColor #b6a2db 182} 183 184!procedure Policy($id, $label="") 185 EsEntity('file', 'Policy', $id, $label) 186!endprocedure 187 188' definition of the Item eventstorming/Element/Saga 189skinparam file<<Saga>> { 190 StereotypeFontSize $FONT_SIZE_SM 191 shadowing false 192 FontColor $FONT_COLOR 193 BorderColor $FONT_COLOR 194 BackgroundColor #c9bbe5 195} 196 197!procedure Saga($id, $label="") 198 EsEntity('file', 'Saga', $id, $label) 199!endprocedure 200 201' definition of the Item eventstorming/Element/Process 202skinparam file<<Process>> { 203 StereotypeFontSize $FONT_SIZE_SM 204 shadowing false 205 FontColor $FONT_COLOR 206 BorderColor $FONT_COLOR 207 BackgroundColor #ddd4ee 208} 209 210!procedure Process($id, $label="") 211 EsEntity('file', 'Process', $id, $label) 212!endprocedure 213 214' definition of the Item eventstorming/Element/Timer 215skinparam file<<Timer>> { 216 StereotypeFontSize $FONT_SIZE_SM 217 shadowing false 218 FontColor $FONT_COLOR 219 BorderColor $FONT_COLOR 220 BackgroundColor #cfcfc4 221} 222 223!procedure Timer($id, $label="") 224 EsEntity('file', 'Timer', $id, $label) 225!endprocedure 226 227' definition of the Item eventstorming/Element/Person 228skinparam actor<<Person>> { 229 StereotypeFontSize 0 230 shadowing false 231 FontColor $FONT_COLOR 232 BorderColor $FONT_COLOR 233 BackgroundColor #ffd1dc 234} 235 236!procedure Person($id, $label="") 237 EsEntity('actor', 'Person', $id, $label) 238!endprocedure 239 240' definition of the Item eventstorming/Element/System 241skinparam file<<System>> { 242 StereotypeFontSize $FONT_SIZE_SM 243 shadowing false 244 FontColor $FONT_COLOR 245 BorderColor $FONT_COLOR 246 BackgroundColor #ffd1dc 247} 248 249!procedure System($id, $label="") 250 EsEntity('file', 'System', $id, $label) 251!endprocedure 252 253' definition of the Item eventstorming/Element/Comment 254skinparam file<<Comment>> { 255 StereotypeFontSize $FONT_SIZE_SM 256 shadowing false 257 FontColor $FONT_COLOR 258 BorderColor $FONT_COLOR 259 BackgroundColor transparent 260} 261 262!procedure Comment($id, $label="") 263 EsEntity('file', 'Comment', $id, $label) 264!endprocedure 265 266 267skinparam rectangle<<Handler>> { 268 StereotypeFontSize $FONT_SIZE_SM 269 shadowing false 270 FontColor $FONT_COLOR 271 BorderColor $FONT_COLOR 272 BackgroundColor #e8f4fd 273} 274 275!procedure Handler($id, $label="") 276 EsEntity('file', 'Handler', $id, $label) 277!endprocedure
2.2. timetable.puml
2.2.1. The Diagram Result
2.2.2. The Code Implementation
Let's import the definition (the highlighted line) and draw the diagram as follows:
1@startuml 2!include lib_eventstorming.puml 3 4actor Teacher as Teacher 5 6 7Aggregate("Student") 8 9together { 10 Command("CreateCourseCommand") 11 Command("UpdateCourseCommand") 12 Command("DeleteStudentCommand") 13} 14 15Command("CreateStudentPackageCommand") 16 17together{ 18 Command("CreateStudentCommand") 19 Command("UpdateStudentCommand") 20 Command("CreateCustomHolidayCommand") 21 Command("AssignDayAsCustomHolidyCommand") 22} 23 24Handler("CreateCourseHandler") 25Event("CourseCreatedEvent") 26CreateCourseCommand --> CreateCourseHandler : "processed by" 27CreateCourseHandler --> CourseCreatedEvent 28Handler("UpdateCourseHandler") 29Event("CourseUpdatedEvent") 30UpdateCourseCommand --> UpdateCourseHandler : "processed by" 31UpdateCourseHandler --> CourseUpdatedEvent 32Handler("DeleteStudentHandler") 33Event("StudentDeletedEvent") 34DeleteStudentCommand --> DeleteStudentHandler : "processed by" 35DeleteStudentHandler --> StudentDeletedEvent 36Handler("UpdateStudentHandler") 37Event("StudentUpdatedEvent") 38UpdateStudentCommand --> UpdateStudentHandler : "processed by" 39UpdateStudentHandler --> StudentUpdatedEvent 40 41CreateCourseCommand-[hidden]down-CreateStudentCommand 42Handler("CreateCustomHolidayHandler") 43Event("CustomHolidayCreatedEvent") 44CreateCustomHolidayCommand --> CreateCustomHolidayHandler : "processed by" 45CreateCustomHolidayHandler --> CustomHolidayCreatedEvent 46Handler("CreateStudentHandler") 47Event("StudentCreatedEvent") 48CreateStudentCommand --> CreateStudentHandler : "processed by" 49CreateStudentHandler --> StudentCreatedEvent 50Event("DayAssignedAsCustomHolidayEvent") 51 52Handler("AssignDayAsCustomHolidyHandler") 53AssignDayAsCustomHolidyCommand --> AssignDayAsCustomHolidyHandler : "processed by" 54AssignDayAsCustomHolidyHandler --> DayAssignedAsCustomHolidayEvent 55 56together{ 57 Command("CreateClassesCommand")[ 58 CreateClassesCommand 59 --validations-- 60 **1.** The new total minutes of all classes cannot exceed the limit of the student package 61 **2.** Cannot overlap with existing classes that the student possesses 62 ] 63 Aggregate("StudentPackage") 64 Command("UpdateClassCommand") 65 Command("RemoveClassCommand") 66 Command("UpdateStudentPackageCommand") 67} 68 69CreateClassesCommand-[hidden]down-StudentPackage 70 71Policy("ClassOnHolidayMustExtendPolicy")[ 72 Class On Holiday Must be Extended Policy 73 -- 74 **1.** A class on a custom holiday must be extended to another day of the same time 75 **2.** That day will be the same as the class being extended 76] 77 78' Position ExtendClassCommand directly below the policy 79Command("ExtendClassCommand") 80 81Policy("ExtendClassPolicy")[ 82 Extend Class due to Status Change Policy 83 -- 84 **1.** When class status was changed to LEGIT_ABSENSE, an extended class will be created 85 **2.** When a class was changed from LEGIT_ABSENSE back to anything else, the corresponding extended class must be removed 86] 87 88 89DayAssignedAsCustomHolidayEvent --> ClassOnHolidayMustExtendPolicy 90ClassOnHolidayMustExtendPolicy --> ExtendClassCommand 91 92' Use hidden connection to force vertical alignment 93ClassOnHolidayMustExtendPolicy -[hidden]down- ExtendClassCommand 94 95together{ 96 Event("ClassExtendedEvent") 97 Event("ClassUpdatedEvent") 98 Event("ClassRemovedEvent") 99 Event("StudentPackageUpatedEvent") 100} 101 102Student --> StudentPackage 103 104Teacher --> CreateCourseCommand 105Teacher --> UpdateCourseCommand 106Teacher --> CreateStudentCommand 107Teacher --> UpdateStudentCommand 108Teacher --> DeleteStudentCommand 109Teacher --> CreateStudentPackageCommand 110Teacher --> UpdateStudentPackageCommand 111Teacher --> CreateClassesCommand 112Teacher --> UpdateClassCommand 113Teacher --> RemoveClassCommand 114Teacher --> ExtendClassCommand 115Teacher --> CreateCustomHolidayCommand 116Teacher --> AssignDayAsCustomHolidyCommand 117 118UpdateStudentPackageCommand --> StudentPackage 119CreateClassesCommand --> StudentPackage 120UpdateClassCommand --> StudentPackage 121RemoveClassCommand --> StudentPackage 122CreateStudentPackageCommand --> Student 123 124UpdateStudentPackageCommand-[hidden]down-StudentPackage 125 126StudentPackage --> ClassExtendedEvent 127StudentPackage --> ClassUpdatedEvent 128StudentPackage --> ClassRemovedEvent 129StudentPackage --> StudentPackageUpatedEvent 130ClassUpdatedEvent --> ExtendClassPolicy 131ExtendClassPolicy --> ExtendClassCommand 132ExtendClassPolicy --> RemoveClassCommand 133ExtendClassCommand --> StudentPackage 134 135actor Scheduler as Scheduler 136 137Command("CreateDeadlineComingNotificationCommand")[ 138 CreateDeadlineComingNotificationCommand 139 --rules-- 140 **1.** When package official_endDate - today = 1month, a notification should be recorded in a table 141 **2.** notification should have an identifier so that repeated notification will not be made again, e.g., {package_id}:deadline_coming:{officiend_endDdate} 142] 143Handler("CreateDeadlineComingNotificationHandler") 144Event("DeadlineComingNotificationCreatedEvent") 145CreateDeadlineComingNotificationCommand --> CreateDeadlineComingNotificationHandler 146CreateDeadlineComingNotificationHandler --> DeadlineComingNotificationCreatedEvent 147 148Scheduler --> CreateDeadlineComingNotificationCommand 149 150@enduml
3. Some Useful Reposition Trick
3.1. Group Together
1together { 2 <element1> 3 <element2> 4}
3.2. Align Vertically
Note that it is not strictly vertically aligned, the horizontal position is still calculated by the native algorithm
1<element1>-[hidden]down-<element2>
4. Generate PDF File
I have built a docker image to produce a pdf file inside the container:
1docker run --rm -v $(pwd):/data machingclee/plantuml-pdf -tpdf timetable.puml
5. GUI Application
5.1. Pladitor
When our diagram becomes very huge, it would be better to reach our code via clicking the diagram. Luckily there is already a GUI-application to achieve this called Pladitor:
it costs HKD 88 but now we can click our "card" to reach our code easily:
5.2. !include failed, now we use !includeurl
Unforturnately the !incldue macro is not available in pladitor, however we can upload the puml definition to github and import it as follows:
1@startuml 2!includeurl https://raw.githubusercontent.com/machingclee/2025-08-23-plantUML-config/refs/heads/main/lib_eventstorming.puml


















