diff --git a/docs/workshops/day_1_sqa.md b/docs/workshops/day_1_sqa.md
index 9165c5f4fca4eddee066903790d6e967ff50536b..e9b91b8b505a4a06a94a2fb0dc115a8d5d91a9b2 100644
--- a/docs/workshops/day_1_sqa.md
+++ b/docs/workshops/day_1_sqa.md
@@ -32,6 +32,7 @@ Persiapkan _tools_ berikut di komputer anda:
 - _Web browser_ seperti [Mozilla Firefox](https://www.mozilla.org/en-US/firefox/new/)
   atau [Google Chrome](https://www.google.com/chrome/index.html).
 - (Opsional) [Docker dan Docker Compose](https://docs.docker.com/desktop/) apabila ingin menjalankan contoh proyek di dalam _container_.
+  Catatan instalasi Docker dapat dilihat di halaman berikut: [(klik)](./prep.md)
 
 Pastikan anda dapat memanggil program-program berikut dari dalam _shell_ favorit anda:
 
@@ -47,16 +48,12 @@ Hasil pemanggilan program-program di atas seharusnya akan mencetak versi program
 Selain itu, pastikan anda telah memiliki akun di [GitLab CSUI](https://gitlab.cs.ui.ac.id)
 dan [SonarQube CSUI](https://sonarqube.cs.ui.ac.id). Pastikan anda bisa berhasil login ke masing-masing sistem.
 
-> TODO: Minta peserta untuk membuat _fork_ terlebih dahulu
->       dan buat _clone_ Git dari _fork_ yang telah mereka buat.
->       Kemudian ingatkan mereka agar menyimpan hasil pekerjaannya ke _fork_.
-
 Mari mulai dengan menyalin contoh proyek yang akan dibahas di hari pertama workshop,
 yaitu [Sitodo PMPL][Sitodo PMPL @ GitLab CSUI]. Buka laman proyek Sitodo PMPL di tautan berikut [(klik)][Sitodo PMPL @ GitLab CSUI],
 lalu klik tombol "Fork" untuk membuat salinan proyek tersebut ke dalam akun/_namespace_ GitLab CSUI anda.
 
 Apabila sudah membuat _fork_ proyek Sitodo PMPL,
-buka laman proyek GitLab CSUI _fork_-nya
+buka laman _fork_ proyek tersebut di GitLab CSUI
 dan salin repositori kode proyeknya ke suatu lokasi di sistem berkas komputer anda menggunakan Git:
 
 ```shell
@@ -81,18 +78,21 @@ Namun untuk keperluan workshop hari ini, anda tidak perlu memasang database Post
 Sebagai gantinya, anda akan menggunakan database _in-memory_ bernama HSQLDB yang akan selalu di-_reset_ setiap kali aplikasi dimatikan.
 
 Untuk membuat _build_ dan menjalankan aplikasinya secara lokal menggunakan database HSQLDB,
-panggil perintah Maven berikut:
+panggil perintah Maven untuk membuat _build_ terlebih dahulu:
 
 ```shell
 mvn -DskipTests package
 ```
 
-Kemudian jalankan berkas JAR aplikasinya dengan mengaktifkan _profile_ `hsqldb`:
+Kemudian jalankan berkas JAR aplikasinya:
 
 ```shell
-java -D"spring.profiles.active=hsqldb" -jar ./target/sitodo-0.1.3-SNAPSHOT.jar
+java -jar ./target/sitodo-0.1.4-SNAPSHOT.jar
 ```
 
+> Catatan: Jika ingin mencoba menjalankan aplikasinya menggunakan _database_ PostgreSQL,
+> silakan tambah opsi `-D"spring.profiles.active=postgresql` di pemanggilan perintah `java -jar`.
+
 Aplikasi akan jalan dan dapat diakses melalui alamat [`http://127.0.0.1:8080`](http://127.0.0.1:8080).
 Apabila sudah ada aplikasi lain yang jalan di alamat yang sama (misal: bentrok nomor _port_),
 tambahkan parameter `-D"server.port=<nomor port lain>` ketika memanggil perintah Maven.
@@ -107,6 +107,7 @@ Kemudian perhatikan kondisi-kondisi pada aplikasi, seperti:
 
 - Alamat (URL) yang tercantum di _address bar_ pada _web browser_ yang anda gunakan.
 - Pesan yang muncul setelah anda mengubah status penyelesaian _item_ di dalam todo list.
+- URL aplikasi ketika anda melakukan _refresh_ atau mengunjungi kembali aplikasi di alamat [`http://127.0.0.1:8080`](http://127.0.0.1:8000).
 
 ## Test Automation
 
@@ -116,7 +117,7 @@ Sedangkan kolega anda tidak menekan tombol "Enter" ketika membuat _item_ baru, m
 Mungkin skenario di atas terdengar sepele, namun menggambarkan adanya potensi proses uji coba dilakukan secara tidak konsisten jika dilakukan oleh manusia.
 
 Langkah-langkah yang cenderung repetitif dapat diotomasi dan dijalankan oleh bantuan program test.
-Pada dasarnya, program tidak akan "lelah" ketika harus menjalankan instruksi yang sama berulang kali.
+Program tidak akan "lelah" ketika harus menjalankan instruksi yang sama berulang kali.
 Bayangkan fitur membuat todo list baru tersebut diuji coba secara otomatis setiap kali ada perubahan baru pada kode proyek.
 Tim pengembang dapat lebih fokus untuk menyelesaikan fitur-fitur yang dibutuhkan
 dan menyiapkan prosedur uji coba yang dibutuhkan untuk dijalankan secara otomatis.
@@ -125,16 +126,86 @@ Saat ini kode proyek Sitodo PMPL telah memiliki kumpulan _test suite_,
 yaitu kumpulan _test case_ yang dapat dijalankan sebagai program test oleh _test runner_ terhadap subjek uji coba.
 Subjek uji coba berupa _software_/sistem secara utuh (seringkali disebut sebagai _System/Software Under Test_ atau SUT).
 
-### Unit Test
+## Struktur Test Case
+
+Sebuah _test case_ yang diimplementasikan sebagai program test biasanya akan memiliki struktur yang terdiri dari empat bagian prosedur,
+yaitu:
+
+1. Setup - menyiapkan _testing environment_ dan SUT ke kondisi siap diuji coba, termasuk menyiapkan nilai masukan _test case_
+2. Exercise - menjalankan skenario uji coba pada SUT
+3. Verify - membuktikan hasil skenario uji coba pada SUT dengan hasil yang diharapkan
+4. Teardown - mengembalikan kondisi _testing environment_ dan SUT ke kondisi awal sebelum uji coba
+
+Mari coba identifikasi keempat bagian tersebut pada dua contoh _test case_.
+Pertama, lihat _test case_ berikut yang membuktikan kebenaran _method_ `equals` pada _class_ `TodoItem`:
+
+```java
+@Test
+void testEquals() {
+    // Setup
+    TodoItem first = new TodoItem("Buy milk");
+    TodoItem second = new TodoItem("Cut grass");
+
+    // Exercise (implisit) & Verify
+    assertNotEquals(first, second);
 
-Mari coba lihat contoh _test suite_ yang termasuk dalam golongan "unit test".
-"Unit" dalam konteks ini mengacu pada komponen terkecil pada _software_.
-Sebagai contoh, fungsi, metode (_method_), hingga modul dapat diklasifikasikan sebagai "unit".
+    // Tidak ada Teardown secara eksplisit
+}
+```
+
+_Setup_ mengandung instruksi untuk menyiapkan SUT, yaitu membuat dua buah objek `TodoItem` yang berperan sebagai subjek yang akan diujicobakan.
+Kemudian _Exercise_ dilakukan secara implisit ketika _Verify_ dilakukan pada contoh di atas,
+yaitu pemanggilan `assertNotEquals` akan memanggil implementasi `equals` milik masing-masing SUT
+dan membandingkan hasil kembaliannya.
+Pada contoh di atas, tidak ada prosedur _Teardown_ secara eksplisit.
+Namun, anda bisa menganggap proses _garbage collection_ yang dilakukan _runtime_ (JVM) secara implisit sebagai prosedur _Teardown_.
+
+Mari lihat contoh _test case_ lain yang lebih kompleks, yaitu _test case_ untuk _class_ `MainController`:
+
+```java
+@WebMvcTest(MainController.class)   // <-- Setup
+class MainControllerTest {
+
+    @Autowired  // <-- Setup
+    private MockMvc mockMvc;
+
+    @Test
+    @DisplayName("HTTP GET '/' redirects to '/list")
+    void showMainPage_resolvesToIndex() throws Exception {
+        mockMvc.perform(get("/"))   // <-- Exercise
+               .andExpectAll(   // <-- Verify
+                   status().is3xxRedirection(),
+                   redirectedUrl("/list")
+               );
+        // Tidak ada Teardown secara eksplisit
+    }
+}
+```
+
+Prosedur _Setup_ pada _test case_ di atas melakukan:
+
+1. `@WebMvcTest` menyiapkan _environment_ minimalis berupa server untuk menjalankan SUT (yaitu: objek `MainController`)
+   beserta _dependency_ yang dibutuhkan oleh SUT.
+2. `@Autowired` menyiapkan objek _mock_ bertipe `MockMvc` sebagai _client_ untuk menyimulasikan pertukaran pesan HTTP Request & Response terhadap SUT.
+
+Sedangkan prosedur _Exercise_ cukup jelas, yaitu menggunakan `mockMvc` untuk mengirimkan HTTP GET Request ke URL `/`.
+HTTP GET Request tersebut akan diterima oleh SUT, yaitu objek `MainController`.
+Kemudian prosedur _Verify_ mengandung beberapa kondisi akhir yang akan dibuktikan dengan menginspeksi HTTP Response yang dikembalikan oleh SUT.
+
+Setelah mengetahui struktur _test case_ secara umum,
+mari membahas TDD secara garis besar dengan melihat contoh beberapa _test_,
+yaitu [_unit test_](#unit-test) dan [_functional test_](#functional-test).
+
+## Unit Test
+
+Mari coba lihat contoh _test suite_ yang termasuk dalam golongan _unit test_.
+_Unit_ dalam konteks ini mengacu pada komponen terkecil pada _software_.
+Sebagai contoh, fungsi dan metode (_method_) dapat diklasifikasikan sebagai _unit_.
 
 Jalankan perintah Maven berikut di _shell_ untuk menjalankan _test suite_ bertipe `unit`:
 
 ```shell
-mvn test -D"groups=unit" -D"spring.profiles.active=hsqldb"
+mvn test -D"groups=unit"
 ```
 
 > Catatan: Bagi pengguna IntelliJ IDEA, anda dapat membuat Run Configuration untuk menjalankan perintah Maven di atas.
@@ -143,28 +214,50 @@ Maven akan menjalankan _test suite_ yang berisi kumpulan _test case_ dari grup `
 Hasil eksekusi setiap _test case_ kemudian dilaporkan ke _standard output_
 dan berkas-berkas laporan di folder `target/surefire-reports`.
 
-### Functional Test
+### Isolasi Pada Unit Test
+
+Idealnya sebuah _test case_ pada _unit test suite_ akan menguji _unit_ secara terisolasi.
+Isolasi test disini mengacu pada praktik untuk **hanya** menguji sebuah _unit_ tanpa mengikutsertakan _unit_ lain yang dibutuhkan.
+Namun pada praktiknya, batasan isolasi bisa "dilanggar" untuk membuat prosedur uji coba terhadap sebuah _unit_ lebih tepat guna.
+
+Ambil contoh misalnya ketika menguji implementasi fungsi yang bertanggung jawab sebagai _request handler_ pada komponen _controller_ di Spring Boot.
+Apabila mengikuti idealisme membuat _unit test_ yang murni terisolasi,
+maka uji coba pada _request handler_ akan berisi prosedur yang membandingkan string nama berkas _template_ HTML yang akan dikirimkan sebagai HTTP Response.
+
+Apakah salah jika _unit test_ pada fungsi _request handler_ hanya sekedar membandingkan string nama berkas _template_ HTML?
+Tentu saja tidak. _Unit test_ tersebut bisa bermanfaat untuk menjamin developer agar menggunakan nama berkas _template_ HTML yang tepat.
+Secara idealisme, _unit test_ tersebut juga memenuhi kriteria isolasi murni sehingga _test_ bisa berjalan dengan cepat tanpa mengikutsertakan _unit_ lain
+ataupun _dependency_ yang dibutuhkan untuk menjalankan fungsi _request handler_.
 
-Sekarang coba jalankan _test suite_ untuk menguji "fungsionalitas" pada SUT,
-atau seringkali dikenal sebagai "functional test".
+Jika ingin benar-benar menguji perilaku _request handler_,
+yakni memastikan fungsinya bisa menerima masukan berupa HTTP Request dan mengembalikan HTTP Response dengan tepat,
+maka batasan isolasi bisa dilanggar dengan membuat prosedur uji coba agar berjalan di dalam server aplikasi yang menjalankan _framework_ Spring Boot secara minimal.
+Oleh karena itu, _unit test suite_ bagi komponen-komponen _controller_ di proyek ini diberikan anotasi `@WebMvcTest`.
+Anotasi tersebut bertujuan untuk menjalankan _framework_ Spring Boot dan server aplikasi ketika _test case_ berjalan
+sehingga komponen _controller_ dapat menerima HTTP Request dan mengembalikan HTTP Response.
+
+## Functional Test
+
+Sekarang coba jalankan _test suite_ untuk menguji fungsionalitas pada SUT,
+atau seringkali dikenal sebagai _functional test_.
 Pengujian dilakukan terhadap SUT yang sudah di-_build_ dan berjalan di sebuah _environment_.
 
 Jalankan perintah Maven berikut di _shell_:
 
 ```shell
-mvn test -D"groups=e2e" -D"spring.profiles.active=hsqldb"
+mvn test -D"groups=func"
 ```
 
-Serupa dengan contoh eksekusi sebelumnya, Maven akan menjalankan _test suite_ yang berisi kumpulan _test case_ dari grup `@Tag("e2e")` di kode test.
+Serupa dengan contoh eksekusi sebelumnya, Maven akan menjalankan _test suite_ yang berisi kumpulan _test case_ dari grup `@Tag("func")` di kode test.
 _Test suite_ jenis ini disebut sebagai _functional test_, dimana _test case_ akan menggunakan _web browser_ untuk menjalankan aksi-aksi pengguna terhadap SUT.
-Pada contoh aplikasi Sitodo PMPL, aksi-aksi pengguna dijalankan pada _web browser_ secara otomatis dengan bantuan Selenium.
+Pada contoh aplikasi Sitodo PMPL, aksi-aksi pengguna dijalankan pada _web browser_ secara otomatis dengan bantuan _library_ [Selenium](https://www.selenium.dev/).
 Oleh karena itu, anda akan melihat _web browser_ anda bergerak secara otomatis ketika _functional test_ berjalan.
 
 Jika anda ingin menjalankan seluruh _test suite_,
 maka perintah Maven yang dapat anda panggil adalah sebagai berikut:
 
 ```shell
-mvn test -D"spring.profiles.active=hsqldb"
+mvn test
 ```
 
 _Unit test_ akan berjalan sangat cepat dimana durasi tiap eksekusi _test case_ berada dalam rentang kurang dari 1 detik per _test case_.
@@ -201,26 +294,361 @@ yaitu:
 3. Fase "Refactor"
 
 Fase "Red" adalah fase awal dimana developer mengembangkan _test case_ untuk implementasi sebuah fitur terlebih dahulu.
-"Red" mengacu pada status "_fail_"/gagal yang dilaporkan oleh _test runner_ secara visual.
+"Red" mengacu pada status gagal/_fail_ yang dilaporkan oleh _test runner_ secara visual.
 Tentu saja hasil test akan gagal karena kode implementasi masih kosong.
 
 Setelah mengembangkan _test case_ yang dibutuhkan, developer masuk ke fase "Green"
-dimana developer mengembangkan kode implementasi fitur sehingga _test case_ berhasil ("_pass_").
+dimana developer mengembangkan kode implementasi fitur sehingga _test case_ berhasil/_pass_.
 
 Fase terakhir, yaitu fase "Refactor", bertujuan untuk meningkatkan kualitas kode
-serta menjaga agar _test case_-_test case_ yang sudah ada tidak kembali gagal ("_fail_").
+serta menjaga agar _test case_-_test case_ yang sudah ada tidak kembali gagal/_fail_.
+
+Untuk memberikan gambaran lebih konkrit mengenai fase-fase TDD,
+mari coba berlatih mengimplementasikan sebuah fitur sederhana dengan gaya TDD,
+yaitu fitur "Visitor Counter" yang akan menghitung dan menampilkan jumlah pengunjung yang pernah membuka aplikasi.
+
+Buat _branch_ baru untuk keperluan pengerjaan latihan selama _workshop_.
+Misalnya, buat _branch_ baru bernama `workshop` dengan perintah Git berikut:
+
+```shell
+git checkout -b workshop
+# Alternatif perintah Git jika menggunakan program Git versi terkini:
+git switch -c workshop
+```
+Kemudian ikuti instruksi pada latihan masing-masing fase berikut secara berurutan.
+
+### Latihan Singkat: Fase "Red"
+
+Misalnya deskripsi fitur "View Counter" dalam gaya _user story_ adalah sebagai berikut: "_As a user, I would like to see how frequent the app has been visited._"
+Kita dapat membayangkan bahwa pengguna perlu dapat melihat jumlah kunjungan pada aplikasi.
+Untuk keperluan _workshop_ ini, mari coba implementasikan secara sederhana saja,
+yaitu dengan memunculkan sebuah pesan berisi angka kunjungan di halaman Todo List
+dan jumlah data kunjungan tidak perlu disimpan ke dalam _database_.
+
+Pertama, buka _class_ Java `TodoListControllerTest` untuk mulai menambahkan _test case_ baru,
+yaitu _test case_ yang membuktikan bahwa jumlah kunjungan akan dilampirkan ke dalam _template_ HTML halaman Todo List.
+_Test case_ dituliskan sebagai _method_ baru bernama `showList_countFirstVisit` sebagai berikut:
+
+```java
+@Test
+@DisplayName("First visit to /list should produce a correct string in the HTML page")
+void showList_countFirstVisit() throws Exception {
+    mockMvc.perform(get("/list"))
+           .andExpectAll(
+               status().isOk(),
+               content().contentTypeCompatibleWith(TEXT_HTML),
+               content().encoding(UTF_8),
+               content().string(containsString("This list has been viewed 1 time"))
+           );
+}
+```
+
+Kemudian coba jalankan _test case_ baru tersebut dari dalam IDE dengan menekan tombol di samping baris deklarasi _test case_ tersebut,
+seperti yang digambarkan pada _screenshot_ berikut:
+
+![Contoh menjalankan sebuah test case di IDE](./images/day_1_sqa_-_run_test_case_ide.png)
+
+Hasil dari _test case_ tersebut pasti akan gagal/_fail_.
+Jangan khawatir karena fase "Red" pada TDD memang mengharapkan awal dari implementasi setiap fitur harus gagal terlebih dahulu.
+Developer kemudian akan mengimplementasikan fitur dengan benar di fase berikutnya ("Green") sehingga lulus/_pass_ setiap _test case_ yang ada.
+
+Silakan simpan terlebih dahulu hasil pekerjaan dengan membuat _commit_ Git.
+Pesan _commit_ bisa disesuaikan agar menunjukkan bahwa saat ini anda baru saja menyelesaikan fase "Red" TDD,
+misal: "_[RED] Write test for displaying visit counter_"
+
+### Latihan Singkat: Fase "Green"
+
+Sebelum mulai membuat implementasi dengan benar,
+mari pikirkan sebuah solusi paling sederhana yang akan meluluskan _test case_ di atas.
+Jika mengacu pada kode _test_ saat ini,
+_test case_ di atas akan melakukan verifikasi pada halaman HTML dengan mencari kemunculan teks "_This list has been viewed 1 time_".
+Supaya _test case_ dapat lulus, maka salah satu solusi paling sederhana
+(dan juga paling naif) adalah menambahkan teks yang diharapkan di dalam dokumen _template_ HTML yang akan dikirimkan sebagai HTTP Response.
+
+Buka berkas HTML bernama `list.html` dan tambahkan kode HTML berikut di antara penutup _tag_ `</form>` dan penutup _tag_ `</div>`:
+
+```html
+<footer>
+    <p class="text-muted" id="view_count">This list has been viewed 1 time.</p>
+</footer>
+```
+
+Kemudian jalankan kembali _test case_ dan lihat hasilnya.
+Hasilnya pasti akan lulus/_pass_.
+
+Secara TDD, solusi naif di atas memang sah tapi hanya berlaku ketika halaman Todo List hanya dikunjungi satu kali.
+Oleh karena itu, mari coba menambahkan _test case_ baru yang menyimulasikan ketika halaman Todo List sudah pernah dibuka dua kali.
+Buka kembali _class_ Java `TodoListControllerTest` dan tambahkan _method_ baru berikut sebagai _test case_ kunjungan dilakukan dua kali:
+
+```java
+@Test
+@DisplayName("Second visit to /list should produce a correct string in the HTML page")
+void showList_countSecondVisit() throws Exception {
+    mockMvc.perform(get("/list"))
+           .andExpectAll(
+               status().isOk(),
+               content().contentTypeCompatibleWith(TEXT_HTML),
+               content().encoding(UTF_8),
+               content().string(containsString("This list has been viewed 1 time"))
+           );
+
+    mockMvc.perform(get("/list"))
+           .andExpectAll(
+               status().isOk(),
+               content().contentTypeCompatibleWith(TEXT_HTML),
+               content().encoding(UTF_8),
+               content().string(containsString("This list has been viewed 2 time"))
+           );
+}
+```
+
+Jalankan _test case_ baru tersebut.
+Hasilnya pasti gagal, karena halaman HTML saat ini hanya mengandung "_This list has been viewed 1 time_".
+
+Untuk membuat _test case_ baru tersebut lulus,
+maka solusi naif yang bisa diikuti adalah menambahkan teks yang diharapkan di dalam dokumen _template_ HTML.
+Tapi pikirkan kembali, apakah mau membuat implementasi fitur hingga tuntas dengan cara tersebut?
+Oleh karena itu, mari ubah kembali dokumen HTML sehingga pesan jumlah kunjungannya dihasilkan secara dinamis berdasarkan perhitungan yang dilakukan oleh _backend_ aplikasi.
+Silakan ubah kembali dokumen HTML `list.html` dengan mengganti isi _tag_ `<p>` dengan sintaks Thymeleaf
+sehingga teks yang ditampilkan mengandung nominal angka kunjungan yang dihitung dari _backend_.
+Contoh kode HTML versi akhirnya dapat dilihat pada potongan kode berikut:
+
+```html
+<footer>
+    <p class="text-muted" id="view_count" th:if="${viewCount}"
+       th:text="'This list has been viewed ' + ${viewCount} + ' time(s)'">
+        This list has been viewed 0 time(s).
+    </p>
+</footer>
+```
+
+Jalankan kembali _test case_.
+Hasilnya akan kembali gagal karena implementasi saat ini mengharapkan nilai `viewCount` dari _backend_ aplikasi.
+
+Sekarang buatlah sebuah _class_ Java baru bernama `ViewCounterService` di dalam _package_ `com.example.sitodo.service`.
+Objek dari _class_ Java ini akan berperan sebagai _service_ yang menyediakan implementasi _business logic_ perhitungan kunjungan.
+Isi dari _class_ Java tersebut dapat mengikuti kode berikut:
+
+```java
+package com.example.sitodo.service;
+
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+@Service
+public class ViewCounterService {
+
+    private final AtomicInteger viewCount = new AtomicInteger(0);
+
+    public int incrementAndGet() {
+        return viewCount.incrementAndGet();
+    }
+}
+```
 
-### Latihan Singkat: Implementasi Fitur Sederhana
+Setelah membuat _service class_ baru, buka _class_ Java `TodoListController`
+dan tambahkan _field_ yang akan menampung objek _service_ baru tersebut.
+Sebagai contoh, potongan kode berikut menambahkan _field_ baru bernama `viewCounterService`
+dan _setter method_ terkait dengan konfigurasi _dependency injection_ melalui _setter method_:
 
-> TODO: Tulis instruksi latihan yang membimbing peserta mengerjakan sebuah fitur sederhana
->       pada Sitodo PMPL menggunakan metode TDD.
->       Fitur sederhana yang akan dikerjakan: Visitor Counter (menghitung jumlah kunjungan ke situs).
+```java
+private ViewCounterService viewCounterService;
+
+@Autowired
+public void setViewCounterService(ViewCounterService viewCounterService) {
+    this.viewCounterService = viewCounterService;
+}
+```
+
+Kemudian perbaharui implementasi _method_ `showList` yang menerima URL tanpa parameter dan dengan parameter.
+Tambahkan _statement_ untuk menambahkan atribut `viewCount` yang mengandung perhitungan jumlah kunjungan.
+Contoh kodenya adalah sebagai berikut:
+
+```java
+@GetMapping("/list")
+public String showList(TodoList todoList, Model model) {
+    model.addAttribute("todoList", todoList);
+    model.addAttribute("motivationMessage", todoListService.computeMotivationMessage(todoList));
+    model.addAttribute("viewCount", viewCounterService.incrementAndGet());
+
+    return "list";
+}
+
+@GetMapping("/list/{id}")
+public String showList(@PathVariable("id") Long id, Model model) {
+    TodoList foundTodoList = todoListService.getTodoListById(id);
+
+    model.addAttribute("todoList", foundTodoList);
+    model.addAttribute("motivationMessage", todoListService.computeMotivationMessage(foundTodoList));
+    model.addAttribute("viewCount", viewCounterService.incrementAndGet());
+
+    return "list";
+}
+```
+
+Sekarang jalankan _test case_ yang telah dibuat sebelumnya.
+Hasilnya akan kembali gagal karena `TodoListController` membutuhkan objek `ViewCounterService` ketika test berjalan.
+Oleh karena itu, buka kembali berkas `TodoListControllerTest` dan tambahkan _mock object_ `ViewCounterService` sebagai _field_:
+
+```java
+@MockBean
+private ViewCounterService viewCounterService;
+```
+
+Kemudian perbaharui instruksi pada _test case_ agar menyimulasikan perilaku `ViewCounterService` seakan-akan melakukan perhitungan kunjungan.
+Tambahkan potongan kode berikut sebelum memanggil objek `mockMvc` di dalam _method_ `showList_countFirstVisit`:
+
+```java
+when(viewCounterService.incrementAndGet()).thenReturn(1);
+```
+
+Lalu tambahkan kode serupa di dalam _method_ `showList_countSecondVisit`:
+
+```java
+// Sebelum pemanggilan mockMvc pertama
+when(viewCounterService.incrementAndGet()).thenReturn(1);
+
+// Sebelum pemanggilan mockMvc kedua
+when(viewCounterService.incrementAndGet()).thenReturn(2);
+```
+
+Versi akhir _method_ `showList_countFirstVisit` dan `showList_countSecondVisit` adalah sebagai berikut:
+
+```java
+@Test
+@DisplayName("First visit to /list should produce a correct string in the HTML page")
+void showList_countFirstVisit() throws Exception {
+    when(viewCounterService.incrementAndGet()).thenReturn(1);
+    mockMvc.perform(get("/list"))
+           .andExpectAll(
+               status().isOk(),
+               content().contentTypeCompatibleWith(TEXT_HTML),
+               content().encoding(UTF_8),
+               content().string(containsString("This list has been viewed 1 time"))
+           );
+}
+
+@Test
+@DisplayName("Second visit to /list should produce a correct string in the HTML page")
+void showList_countSecondVisit() throws Exception {
+    when(viewCounterService.incrementAndGet()).thenReturn(1);
+    mockMvc.perform(get("/list"))
+           .andExpectAll(
+               status().isOk(),
+               content().contentTypeCompatibleWith(TEXT_HTML),
+               content().encoding(UTF_8),
+               content().string(containsString("This list has been viewed 1 time"))
+           );
+
+    when(viewCounterService.incrementAndGet()).thenReturn(2);
+    mockMvc.perform(get("/list"))
+           .andExpectAll(
+               status().isOk(),
+               content().contentTypeCompatibleWith(TEXT_HTML),
+               content().encoding(UTF_8),
+               content().string(containsString("This list has been viewed 2 time"))
+           );
+}
+```
+
+Jalankan kembali _test case_ yang menyimulasikan satu kali dan dua kali kunjungan.
+Hasilnya akan lulus/_pass_.
+Simpan hasil pekerjaan dengan membuat _commit_ Git lalu _push_ ke _fork_.
+
+### Fase "Refactor"
+
+Setelah menuntaskan fase "Red" dan "Green", developer dapat memasuki fase "Refactor" untuk memperbaiki desain kode yang telah dibuat.
+Fase "Refactor" mengacu pada kegiatan _refactoring_ yang bertujuan untuk meningkatkan kualitas kode tanpa merusak kebenaran kode tersebut.
+Fase ini dibutuhkan karena proses implementasi yang dilakukan pada fase "Green" seringkali fokus untuk meluluskan _test_ dengan cepat
+sehingga kode yang dituliskan mungkin dibuat tanpa mempertimbangkan aspek kualitas.
+
+Potensi perbaikan yang dapat dilakukan bisa diidentifikasi dari ada tidaknya _code smells_ pada kode.
+Proses identifikasi dapat dilakukan oleh developer berdasarkan pengalaman dan pengetahuan,
+ataupun dibantu dengan _tools_ yang dapat menganalisis kualitas kode.
+
+Contoh-contoh _code smells_ yang umum ditemukan antara lain:
+
+- Duplikasi pada kode, seperti ada kumpulan _statement_ identik yang dituliskan berulang kali di beberapa _method_ dalam sebuah _class_ Java.
+- Penamaan yang kurang deskriptif, seperti memberikan nama variabel dengan nama yang tidak bermakna.
+- Penerapan praktik yang sudah kuno, seperti menggunakan `@RequestMapping` pada _controller_ Spring Boot.
+
+### Latihan Mandiri: Membuat Test Pada Objek Service
+
+Ingat kembali bahwa anda telah membuat implementasi _controller_
+dan _service_ di satu siklus TDD yang dijelaskan di atas.
+Saat ini _test suite_ hanya mencakup pembuktian kebenaran implementasi _controller_,
+sedangkan _service_ belum memiliki _test suite_ terkait.
+
+Tugas anda selanjutnya adalah membuat _test case_ untuk _service_ perhitungan kunjungan,
+yaitu _class_ Java `ViewCounterService`.
+Langkah-langkah pengerjaannya adalah sebagai berikut:
+
+1. [ ] Buat _class_ Java baru bernama `ViewCounterServiceTest` di dalam folder `src/test/java/com/example/sitodo/service`.
+2. [ ] Buat satu _test case_ yang akan menguji kebenaran implementasi perhitungan kunjungan yang dilakukan oleh objek _service_.
+   Misalnya dengan membuat _method_ baru bernama `testIncrementAndGet` di dalam _class_ `ViewCounterServiceTest`.
+3. [ ] Tambahkan anotasi `@Test` di atas _method_ baru tersebut.
+4. [ ] Tuliskan _statement_ Java yang akan membuat objek _service_ yang akan diujicobakan di dalam _method_ baru.
+5. [ ] Implementasikan prosedur uji coba yang memanggil _method_ perhitungan kunjungan lalu membuktikan bahwa hasil akhirnya sesuai dengan ekspektasi.
+   Misalnya setelah memanggil _method_ `incrementAndGet`, maka buktikan kembalian dari pemanggilan _method_ tersebut sesuai dengan ekspektasi anda.
+6. [ ] Jalankan _test case_ tersebut dan pastikan verifikasi berhasil dilakukan.
+
+Contoh solusi dari latihan di atas dapat dilihat di contoh kode berikut:
+
+```java
+package com.example.sitodo.service;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ViewCounterServiceTest {
+
+    @Test
+    void testIncrementAndGet_once() {
+        ViewCounterService viewCounterService = new ViewCounterService();
+
+        int result = viewCounterService.incrementAndGet();
+
+        assertEquals(1, result);
+    }
+}
+```
+
+> Catatan: Mungkin anda akan bertanya mengapa contoh solusi tidak memiliki anotasi `@WebMvcTest`.
+> Alasannya adalah pengujian pada objek _service_ kebetulan tidak membutuhkan server ataupun _dependency_ terhadap komponen yang disediakan _framework_ Spring Boot.
+> Oleh karena itu, objek _service_ dapat diujicobakan secara independen sebagai objek Java,
+> atau dikenal sebagai Plain Old Java Object (POJO).
+
+Jangan lupa untuk menyimpan hasil pekerjaan.
+Buat _commit_ Git, lalu _push_ ke _fork_.
 
 ## Analisis & Laporan Kualitas Kode
 
-> TODO: Tambah paragraf pengantar. Jelaskan alternatif-alternatif static analysis seperti
->       CodeQuality yang tersedia di CI/CD GitLab dan SonarQube.
+Setelah melihat bagaimana menerapkan metode TDD pada proses pengembangan _software_
+sekarang mari mengenali bagaimana kualitas kode dapat dianalisis dan dijamin menggunakan bantuan _tools_ seperti GitLab CI/CD dan SonarQube.
+
+Saat ini contoh proyek Sitodo PMPL telah memiliki konfigurasi _pipeline CI/CD_ dengan beberapa _stage_ sebagai berikut:
+
+1. `build` - menjamin kode proyek dapat di-_build_ menjadi berkas JAR aplikasi.
+2. `test` - menjalankan _test suite_ bertipe _unit test_ sekaligus melakukan analisis terhadap kode proyek
+3. `deploy` - menjalankan _deployment_ ke server tujuan
+4. `post-deploy` - menjalan _test suite_ BDD, akan dibahas pada workshop hari ketiga
+5. `report` - melaporkan hasil test dan analisis kode ke GitLab dan SonarQube
+
+Sebagai bagian dari penjaminan kualitas, _pipeline_ CI/CD dapat dirancang agar menjalankan serangkaian program secara otomatis setiap kali ada perubahan pada kode proyek.
+Salah satu kasus yang dapat diantisipasi dengan adanya _pipeline_ CI/CD adalah melakukan mitigasi terhadap regresi pada aplikasi.
+Eksekusi _test_ secara otomatis dapat membuktikan bahwa perubahan terbaru pada kode proyek tidak merusak kondisi kode saat ini.
+Namun tentu saja mitigasi terhadap regresi baru bisa tercapai jika kode proyek memang mengandung _test_ dengan cakupan yang menyeluruh
+dan kode _test_ memang dituliskan dengan tujuan untuk menjamin kebenaran implementasi.
+
+Salah satu tolok ukur "cakupan pengujian" yang umum digunakan di industri adalah _line coverage_,
+yaitu persentase baris atau _statement_ kode proyek yang telah dijalankan oleh _test suite_.
+Jika melihat pada nilai _line coverage_ kode proyek Sitodo PMPL, saat ini _line coverage_ bernilai 97%.
+Artinya adalah 97% _statement_ kode pada proyek sudah pernah dijalankan oleh _test suite_.
 
+Kualitas kode proyek juga dapat dianalisis dari bagaimana kode proyek dituliskan.
+Analisis kualitas kode dapat dilakukan melalui _tool_ yang didukung oleh SonarQube, yaitu [SonarScanner](https://docs.sonarsource.com/sonarqube/latest/analyzing-source-code/scanners/sonarscanner/).
 Cara kerja SonarScanner adalah sebagai berikut:
 
 1. SonarScanner melakukan analisis terhadap kode program
@@ -241,7 +669,7 @@ Menurut dokumentasi SonarQube, sebuah proyek dianggap lulus _Quality Gate_ jika:
 - Tidak ada _bug_ baru pada kode.
 - Tidak ada celah keamanan baru pada kode.
 - Semua isu terkait keamanan ("_security hotspot_") sudah ditindaklanjuti.
-- Perubahan baru pada kode mengandung _technical debt_ di bawah batasan tertentu.
+- Perubahan baru pada kode mengandung _technical debt_/_code smells_ di bawah batasan tertentu.
 - Perubahan baru pada kode mengandung duplikasi kode di bawah batasan tertentu.
 - Perubahan baru pada kode di-_cover_ oleh test.
 
@@ -250,18 +678,35 @@ Apabila sudah sempat memenuhi _Quality Gate_, maka selanjutnya tim pengembang di
 mempertahankan kualitas kode yang telah tercapai di setiap perubahan yang dilakukan.
 Jika sudah berhasil mempertahankan kualitas, maka tim pengembang juga diharapkan untuk memperbaiki isu-isu yang sudah sempat terdeteksi.
 
-### Technical Debt & Code Smells
+### Latihan Singkat: Membuat Proyek Analisis Baru di SonarQube
 
-Dengan waktu yang terbatas, mari fokus mengulas tiga contoh _code smell_ berikut, yaitu:
+Saat ini kode proyek Sitodo PMPL masih diatur untuk mengirimkan hasil analisis SonarScanner ke proyek analisis SonarQube milik organisasi perkuliahan PMPL.
+Mari mencoba untuk membuat proyek analisis baru yang akan menampung analisis SonarScanner dari _fork_ anda:
 
-- Duplikasi Kode
-- for & foreach Loop
-- Cyclomatic/Cognitive Complexity
+1. Masuk ke [SonarQube CSUI](https://sonarqube.cs.ui.ac.id)
+2. Pilih "Add Project" > "Manually" dari laman depan daftar proyek di SonarQube.
+3. Masukkan "Project Key" dan "Display Name" dengan format `sitodo-pmpl-[nama anda]`.
+   Misal: `sitodo-pmpl-bambang`
+   Kemudian pilih "Set up".
+4. Di layar berikutnya, pilih "Generate a token" dan salin nilai token yang dibuatkan oleh SonarQube.
+5. Setelah membuat token, pilih opsi analisis menggunakan Maven.
+   SonarQube akan mencantumkan contoh perintah Maven yang dapat dipanggil untuk melakukan analisis secara lokal.
+   Silakan dicoba apabila ingin memastikan analisis SonarScanner berhasil dikirimkan ke SonarQube dari komputer anda.
 
-> TODO: Jelaskan singkat masing-masing contoh _code smell_.
+Selanjutnya, anda perlu memperbaharui konfigurasi Maven dan _pipeline CI/CD_ agar bisa membuat analisis SonarScanner dilakukan dengan benar di lingkungan CI:
+
+1. Buka `pom.xml` kode proyek Sitodo PMPL, lalu ubah nilai _property_ `sonar.projectKey` dengan "Project Key" anda.
+2. Buka konfigurasi variabel CI/CD di laman proyek _fork_ Sitodo PMPL dan tambahkan dua variabel baru bernama `SONAR_TOKEN` dan `SONAR_HOST`.
+   Isi `SONAR_TOKEN` dengan token yang dibuat sebelumnya, lalu isi `SONAR_HOST` dengan alamat SonarQube CSUI (https://sonarqube.cs.ui.ac.id).
+
+Simpan pekerjaan anda.
+Buat _commit_ Git dan _push_ ke _fork_ proyek Sitodo PMPL.
 
 ### Latihan Singkat: Mengurangi Tingkat Kompleksitas Kode Melalui Refactoring
 
+Dengan waktu yang terbatas, mari fokus mengulas sebuah contoh _code smell_, yaitu
+_Cyclomatic/Cognitive Complexity_. Perhatikan contoh kode berikut:
+
 ```java
 public String computeMotivationMessage(TodoList todoList) {
     List<TodoItem> items = todoList.getItems();
@@ -326,7 +771,7 @@ klik kanan dan pilih opsi Refactoring > Extract Method.
 Kemudian berikan nama fungsi yang mengandung hasil enkapsulasi,
 lalu pilih opsi untuk mengganti ("_Replace_") semua blok percabangan yang duplikat dengan pemanggilan fungsi baru.
 
-> Note: _Extract Method_ juga dapat dilakukan melalui _keyboard shortcut_ Ctrl+Alt+M di IntelliJ.
+> Catatan: _Extract Method_ juga dapat dilakukan melalui _keyboard shortcut_ Ctrl+Alt+M di IntelliJ.
 
 Versi akhir fungsi `computeMotivationMessage` setelah _refactoring_ adalah sebagai berikut:
 
@@ -374,14 +819,29 @@ private String getMotivationMessageByTotalItems(long totalFinishedItems, long to
 
 Untuk memastikan kegiatan _refactoring_ tidak merusak kode implementasi sehingga menyebabkan regresi,
 jalankan kembali _test suite_ yang menguji kebenaran implementasi fungsi `computeMotivationMessage`.
-Jika hasil eksekusi _test suite_ sukses ("pass"),
+Jika hasil eksekusi _test suite_ sukses/_pass_,
 maka dapat disimpulkan _refactoring_ berhasil dilakukan tanpa merusak kebenaran implementasi.
 Sebaliknya, jika ternyata hasilnya gagal,
 maka ada kesalahan pada _refactoring_ yang dilakukan.
 
+### Latihan Mandiri: Membersihkan Beberapa Code Smells
+
+Jika masih ada waktu tersisa, maka lihat koleksi _code smells_ yang telah diidentifikasi dan dilaporkan ke proyek SonarQube anda.
+Kemudian, pilih minimal tiga buah _code smells_ dan coba perbaiki _code smells_ tersebut.
+Untuk setiap perbaikan sebuah _code smell_, simpan pekerjaan anda sebagai _commit_ Git dengan pesan _commit_ yang mencantumkan nama _code smell_ terkait.
+
 ## Penutup
 
-> TODO: Tulis paragraf meringkas kegiatan hari ini dan berikan _preview_ agenda hands-on hari berikutnya.
+Anda sudah mencoba secara garis besar bagaimana menerapkan TDD
+serta bagaimana aktivitas penjaminan kualitas dapat dilakukan dengan bantuan _tools_.
+
+Untuk bahan diskusi saat refleksi:
+
+- Apa saja kendala Bapak/Ibu dalam pekerjaan saat ini yang mungkin dapat diperbaiki dengan menerapkan materi yang dipelajari hari ini?
+- Jika sudah pernah menerapkan _test automation_, apa kendala Bapak/Ibu saat ini dalam membuat kode test dan menjalankan _test suite_?
+- Setelah melihat contoh-contoh _code smells_ yang diidentifikasi oleh SonarQube, apakah semua _code smells_ perlu ditindaklanjuti?
+
+Hari kedua workshop akan fokus mendalami TDD, terutama pada implementasi kode test terisolasi dengan teknik _mocking_.
 
 [1]: https://docs.google.com/presentation/d/1fDJF9ocOiDXEqm8WCDX_vWSPoG3L3PNI?rtpof=true&usp=drive_fs
 [2]: https://docs.google.com/presentation/d/1f1uDiI4npQOSih5o0EnqBcJqJL2LBLVk?rtpof=true&usp=drive_fs
diff --git a/docs/workshops/images/Screenshot 2023-11-02 at 06-43-05 Add a project.png b/docs/workshops/images/Screenshot 2023-11-02 at 06-43-05 Add a project.png
new file mode 100644
index 0000000000000000000000000000000000000000..123841a09c472f3b74cbffa8f42f1835ffed8f39
Binary files /dev/null and b/docs/workshops/images/Screenshot 2023-11-02 at 06-43-05 Add a project.png differ
diff --git a/docs/workshops/images/Screenshot 2023-11-02 at 06-43-41 sitodo-pmpl-bambang.png b/docs/workshops/images/Screenshot 2023-11-02 at 06-43-41 sitodo-pmpl-bambang.png
new file mode 100644
index 0000000000000000000000000000000000000000..3fb90aaffeffb6bf09cb0af62c155dd5bb597cf0
Binary files /dev/null and b/docs/workshops/images/Screenshot 2023-11-02 at 06-43-41 sitodo-pmpl-bambang.png differ
diff --git a/docs/workshops/images/day_1_sqa_-_run_test_case_ide.png b/docs/workshops/images/day_1_sqa_-_run_test_case_ide.png
new file mode 100644
index 0000000000000000000000000000000000000000..a3b2caf0ed94ce6b2ed0db877f814162480db609
Binary files /dev/null and b/docs/workshops/images/day_1_sqa_-_run_test_case_ide.png differ
diff --git a/mkdocs.yml b/mkdocs.yml
index f10a5e4c579ca1b4e3c95a8093274ea455d2ce89..2f8d608bdcac7018d5dcd656cb76fe42b80d4c12 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -53,10 +53,10 @@ nav:
   - Home: index.md
   - Workshops:
     - workshops/index.md
-    - Preparation: workshops/prep.md
     - Day 1 - SQA: workshops/day_1_sqa.md
     - Day 2 - TDD: workshops/day_2_tdd.md
     - Day 3 - BDD: workshops/day_3_bdd.md
+    - Docker Installation: workshops/prep.md
   - Problem Set:
     - (2023) Exercise 1 - Automated QA: 2023/exercise1.md
     - (2022) Exercise 1 - Automated QA: 2022/exercise1.md