Skip to content

Commit 959411f

Browse files
committed
feat: initial commit
0 parents  commit 959411f

181 files changed

Lines changed: 10498 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.editorconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[*]
2+
charset = utf-8
3+
end_of_line = lf
4+
indent_size = 2
5+
indent_style = space
6+
insert_final_newline = false
7+
max_line_length = 120
8+
tab_width = 2
9+
ij_continuation_indent_size = 2
10+
ij_formatter_off_tag = @formatter:off
11+
ij_formatter_on_tag = @formatter:on
12+
ij_formatter_tags_enabled = true
13+
ij_smart_tabs = false
14+
ij_visual_guides =
15+
ij_wrap_on_typing = false

.github/workflows/build.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Build
2+
3+
on:
4+
- push
5+
- pull_request
6+
7+
jobs:
8+
build:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Check out
12+
uses: actions/checkout@v4
13+
- name: Set up Java
14+
uses: actions/setup-java@v4
15+
with:
16+
java-version: 25
17+
distribution: temurin
18+
cache: maven
19+
- name: Build
20+
run: mvn -B package --file pom.xml

.gitignore

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
HELP.md
2+
target/
3+
!.mvn/wrapper/maven-wrapper.jar
4+
!**/src/main/**/target/
5+
!**/src/test/**/target/
6+
7+
### STS ###
8+
.apt_generated
9+
.classpath
10+
.factorypath
11+
.project
12+
.settings
13+
.springBeans
14+
.sts4-cache
15+
16+
### IntelliJ IDEA ###
17+
.idea
18+
*.iws
19+
*.iml
20+
*.ipr
21+
22+
### NetBeans ###
23+
/nbproject/private/
24+
/nbbuild/
25+
/dist/
26+
/nbdist/
27+
/.nb-gradle/
28+
build/
29+
!**/src/main/**/build/
30+
!**/src/test/**/build/
31+
32+
### VS Code ###
33+
.vscode/

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Spring Boot DDD Sample
2+
3+
[![Build](https://github.com/mtamme/spring-boot-ddd-sample/actions/workflows/build.yaml/badge.svg)](https://github.com/mtamme/spring-boot-ddd-sample/actions/workflows/build.yaml)
4+
5+
This is the sample bounded context from the [<CODE/CRAFTS>](https://code-crafts.com) conference
6+
workshop [From Strategy to Tactics – Kickstart Your DDD Journey Collaboratively](https://2025.code-crafts.com/workshop-from-strategy-to-tactics).
7+
8+
## Usage
9+
10+
### Requires
11+
12+
- Java 25
13+
- Maven 3.9+
14+
15+
### Build
16+
17+
```
18+
$ mvn clean package
19+
```

booking/pom.xml

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>com.github</groupId>
8+
<artifactId>spring-boot-ddd-sample</artifactId>
9+
<version>1.0.0-SNAPSHOT</version>
10+
</parent>
11+
12+
<artifactId>booking</artifactId>
13+
14+
<dependencies>
15+
<!-- Spring -->
16+
<dependency>
17+
<groupId>org.springframework.boot</groupId>
18+
<artifactId>spring-boot-starter-actuator</artifactId>
19+
</dependency>
20+
<dependency>
21+
<groupId>org.springframework.boot</groupId>
22+
<artifactId>spring-boot-starter-data-jpa</artifactId>
23+
</dependency>
24+
<dependency>
25+
<groupId>org.springframework.boot</groupId>
26+
<artifactId>spring-boot-starter-flyway</artifactId>
27+
</dependency>
28+
<dependency>
29+
<groupId>org.springframework.boot</groupId>
30+
<artifactId>spring-boot-starter-validation</artifactId>
31+
</dependency>
32+
<dependency>
33+
<groupId>org.springframework.boot</groupId>
34+
<artifactId>spring-boot-starter-web</artifactId>
35+
</dependency>
36+
37+
<!-- Springdoc -->
38+
<dependency>
39+
<groupId>org.springdoc</groupId>
40+
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
41+
</dependency>
42+
43+
<!-- Swagger -->
44+
<dependency>
45+
<groupId>io.swagger.core.v3</groupId>
46+
<artifactId>swagger-annotations</artifactId>
47+
</dependency>
48+
49+
<!-- H2 -->
50+
<dependency>
51+
<groupId>com.h2database</groupId>
52+
<artifactId>h2</artifactId>
53+
<scope>runtime</scope>
54+
</dependency>
55+
56+
<!-- Seedwork -->
57+
<dependency>
58+
<groupId>com.github</groupId>
59+
<artifactId>seedwork</artifactId>
60+
<version>1.0.0-SNAPSHOT</version>
61+
</dependency>
62+
63+
<!-- Test -->
64+
<dependency>
65+
<groupId>org.springframework.boot</groupId>
66+
<artifactId>spring-boot-starter-test</artifactId>
67+
</dependency>
68+
<dependency>
69+
<groupId>com.tngtech.archunit</groupId>
70+
<artifactId>archunit</artifactId>
71+
</dependency>
72+
<dependency>
73+
<groupId>com.tngtech.archunit</groupId>
74+
<artifactId>archunit-junit5</artifactId>
75+
</dependency>
76+
</dependencies>
77+
78+
<build>
79+
<plugins>
80+
<plugin>
81+
<groupId>org.apache.maven.plugins</groupId>
82+
<artifactId>maven-surefire-plugin</artifactId>
83+
</plugin>
84+
<plugin>
85+
<groupId>org.springframework.boot</groupId>
86+
<artifactId>spring-boot-maven-plugin</artifactId>
87+
</plugin>
88+
<plugin>
89+
<groupId>org.openapitools</groupId>
90+
<artifactId>openapi-generator-maven-plugin</artifactId>
91+
<executions>
92+
<execution>
93+
<goals>
94+
<goal>generate</goal>
95+
</goals>
96+
<configuration>
97+
<inputSpec>${project.basedir}/src/main/resources/static/booking-openapi.yaml</inputSpec>
98+
<apiPackage>com.github.booking.infrastructure.web</apiPackage>
99+
<modelPackage>com.github.booking.infrastructure.web.representation</modelPackage>
100+
</configuration>
101+
</execution>
102+
</executions>
103+
</plugin>
104+
</plugins>
105+
</build>
106+
</project>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.github.booking;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
@SpringBootApplication
7+
public class Main {
8+
9+
static void main(final String[] args) {
10+
SpringApplication.run(Main.class, args);
11+
}
12+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.github.booking.application.booking;
2+
3+
import com.github.booking.application.booking.command.CancelBookingCommand;
4+
import com.github.booking.application.booking.command.ConfirmBookingCommand;
5+
import com.github.booking.application.booking.command.InitiateBookingCommand;
6+
import com.github.booking.application.booking.command.InitiateBookingResult;
7+
import com.github.booking.application.booking.command.ReleaseSeatCommand;
8+
import com.github.booking.application.booking.command.ReserveSeatCommand;
9+
import org.springframework.transaction.annotation.Transactional;
10+
11+
@Transactional
12+
public interface BookingCommandHandler {
13+
14+
InitiateBookingResult initiateBooking(InitiateBookingCommand command);
15+
16+
void reserveSeat(ReserveSeatCommand command);
17+
18+
void releaseSeat(ReleaseSeatCommand command);
19+
20+
void confirmBooking(ConfirmBookingCommand command);
21+
22+
void cancelBooking(CancelBookingCommand command);
23+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package com.github.booking.application.booking;
2+
3+
import com.github.booking.application.booking.command.CancelBookingCommand;
4+
import com.github.booking.application.booking.command.ConfirmBookingCommand;
5+
import com.github.booking.application.booking.command.InitiateBookingCommand;
6+
import com.github.booking.application.booking.command.InitiateBookingResult;
7+
import com.github.booking.application.booking.command.ReleaseSeatCommand;
8+
import com.github.booking.application.booking.command.ReserveSeatCommand;
9+
import com.github.booking.domain.booking.BookingException;
10+
import com.github.booking.domain.booking.BookingId;
11+
import com.github.booking.domain.booking.BookingRepository;
12+
import com.github.booking.domain.hall.SeatNumber;
13+
import com.github.booking.domain.show.ShowException;
14+
import com.github.booking.domain.show.ShowId;
15+
import com.github.booking.domain.show.ShowRepository;
16+
import org.springframework.stereotype.Service;
17+
18+
import java.util.Objects;
19+
20+
@Service
21+
public class BookingCommandHandlerImpl implements BookingCommandHandler {
22+
23+
private final BookingRepository bookingRepository;
24+
private final ShowRepository showRepository;
25+
26+
public BookingCommandHandlerImpl(final BookingRepository bookingRepository, final ShowRepository showRepository) {
27+
this.bookingRepository = Objects.requireNonNull(bookingRepository);
28+
this.showRepository = Objects.requireNonNull(showRepository);
29+
}
30+
31+
@Override
32+
public InitiateBookingResult initiateBooking(final InitiateBookingCommand command) {
33+
final var show = showRepository.findByShowId(new ShowId(command.showId()))
34+
.orElseThrow(ShowException::notFound);
35+
final var booking = show.initiateBooking(bookingRepository.nextBookingId());
36+
37+
bookingRepository.save(booking);
38+
39+
return new InitiateBookingResult(booking.bookingId()
40+
.value());
41+
}
42+
43+
@Override
44+
public void reserveSeat(final ReserveSeatCommand command) {
45+
final var booking = bookingRepository.findByBookingId(new BookingId(command.bookingId()))
46+
.orElseThrow(BookingException::notFound);
47+
final var show = showRepository.findByShowId(booking.showId())
48+
.orElseThrow(ShowException::notFound);
49+
50+
show.reserveSeat(booking, new SeatNumber(command.seatNumber()));
51+
showRepository.save(show);
52+
}
53+
54+
@Override
55+
public void releaseSeat(final ReleaseSeatCommand command) {
56+
final var booking = bookingRepository.findByBookingId(new BookingId(command.bookingId()))
57+
.orElseThrow(BookingException::notFound);
58+
final var show = showRepository.findByShowId(booking.showId())
59+
.orElseThrow(ShowException::notFound);
60+
61+
show.releaseSeat(booking, new SeatNumber(command.seatNumber()));
62+
showRepository.save(show);
63+
}
64+
65+
@Override
66+
public void confirmBooking(final ConfirmBookingCommand command) {
67+
final var booking = bookingRepository.findByBookingId(new BookingId(command.bookingId()))
68+
.orElseThrow(BookingException::notFound);
69+
70+
booking.confirm();
71+
bookingRepository.save(booking);
72+
}
73+
74+
@Override
75+
public void cancelBooking(final CancelBookingCommand command) {
76+
final var booking = bookingRepository.findByBookingId(new BookingId(command.bookingId()))
77+
.orElseThrow(BookingException::notFound);
78+
79+
booking.cancel();
80+
bookingRepository.save(booking);
81+
}
82+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.github.booking.application.booking;
2+
3+
import com.github.booking.application.booking.query.BookingDetailView;
4+
import com.github.booking.application.booking.query.BookingSummaryView;
5+
import com.github.booking.application.booking.query.GetBookingQuery;
6+
import com.github.booking.application.booking.query.ListBookingsQuery;
7+
import org.springframework.transaction.annotation.Transactional;
8+
9+
import java.util.List;
10+
11+
@Transactional(readOnly = true)
12+
public interface BookingQueryHandler {
13+
14+
BookingDetailView getBooking(GetBookingQuery query);
15+
16+
List<BookingSummaryView> listBookings(ListBookingsQuery query);
17+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.github.booking.application.booking.command;
2+
3+
public record CancelBookingCommand(String bookingId) {
4+
}

0 commit comments

Comments
 (0)