Skip to content
This repository was archived by the owner on Jul 6, 2025. It is now read-only.

Commit f6f537d

Browse files
authored
Merge pull request #81 from Zenfulcode/80-complete-project-restructure
total project restructure
2 parents 3e5049d + fc00841 commit f6f537d

424 files changed

Lines changed: 11630 additions & 7544 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.

.dockerignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ deploy/
2323
*.log
2424

2525
# Environment files
26-
deploy/.env
2726
*.env
2827

2928
# Documentation

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ build/
3131

3232
### VS Code ###
3333
.vscode/
34-
/deploy/.env
35-
.env
34+
.env
35+
deploy/.env

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ FROM eclipse-temurin:21-jre-alpine
99
WORKDIR /app
1010
COPY --from=build /app/target/*.jar app.jar
1111
COPY --from=build /app/src/main/resources/db/changelog /app/resources/db/changelog
12+
COPY --from=build /app/src/main/resources/templates /app/resources/templates
1213

1314
EXPOSE 6091
1415
ENTRYPOINT ["java", "-jar", "app.jar"]

deploy/.env.example

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,18 @@ DATASOURCE_USERNAME=commercifyapp
44
DATASOURCE_PASSWORD=password123!
55
STRIPE_SECRET_TEST_KEY=
66
STRIPE_WEBHOOK_SECRET=
7+
STRIPE_WEBHOOK_ENDPOINT=https://<insert_host>/api/v2/payments/webhooks/stripe/callback
78
JWT_SECRET_KEY=
89
ADMIN_EMAIL=admin@commercify.app
9-
ADMIN_PASSWORD=commercifyadmin123!
10+
ADMIN_PASSWORD=admin
1011
MOBILEPAY_CLIENT_ID=
1112
MOBILEPAY_CLIENT_SECRET=
1213
MOBILEPAY_SUBSCRIPTION_KEY=
1314
MOBILEPAY_MERCHANT_ID=
14-
MOBILEPAY_API_URL=https://apitest.vipps.no
15+
MOBILEPAY_API_URL=
1516
MOBILEPAY_SYSTEM_NAME=Commercify
16-
# used for outgoing emails
17-
MAIL_HOST=smtp.gmail.com
18-
MAIL_PORT=587
17+
MOBILEPAY_WEBHOOK_CALLBACK=https://<insert_host>/api/v2/payments/webhooks/mobilepay/callback
1918
MAIL_USERNAME=
2019
MAIL_PASSWORD=
21-
# used for email confirmation token (WIP)
22-
FRONTEND_URL=http://localhost:3000
23-
# The email address that will receive new order notifications emails
24-
ORDER_EMAIL_RECEIVER=
25-
# used for mobilepay webhook callback
26-
BACKEND_HOST=
20+
MAIL_HOST=smtp.ethereal.email
21+
MAIL_PORT=587

deploy/docker-compose.yml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ services:
2929
- SPRING_DATASOURCE_URL=${DATASOURCE_URL}
3030
- SPRING_DATASOURCE_USERNAME=${DATASOURCE_USERNAME}
3131
- SPRING_DATASOURCE_PASSWORD=${DATASOURCE_PASSWORD}
32+
- STRIPE_SECRET_TEST_KEY=${STRIPE_SECRET_TEST_KEY}
33+
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
3234
- JWT_SECRET_KEY=${JWT_SECRET_KEY}
3335
- ADMIN_EMAIL=${ADMIN_EMAIL}
3436
- ADMIN_PASSWORD=${ADMIN_PASSWORD}
@@ -38,15 +40,11 @@ services:
3840
- MOBILEPAY_SUBSCRIPTION_KEY=${MOBILEPAY_SUBSCRIPTION_KEY}
3941
- MOBILEPAY_API_URL=${MOBILEPAY_API_URL}
4042
- MOBILEPAY_SYSTEM_NAME=${MOBILEPAY_SYSTEM_NAME}
41-
- STRIPE_SECRET_TEST_KEY=${STRIPE_SECRET_TEST_KEY}
42-
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
43-
- MAIL_USERNAME=${MAIL_USERNAME}
44-
- MAIL_PASSWORD=${MAIL_PASSWORD}
43+
- MOBILEPAY_WEBHOOK_CALLBACK=${MOBILEPAY_WEBHOOK_CALLBACK}
4544
- MAIL_HOST=${MAIL_HOST}
4645
- MAIL_PORT=${MAIL_PORT}
47-
- ORDER_EMAIL_RECEIVER=${ORDER_EMAIL_RECEIVER}
48-
- FRONTEND_URL=${FRONTEND_URL}
49-
- BACKEND_HOST=${BACKEND_HOST}
46+
- MAIL_USERNAME=${MAIL_USERNAME}
47+
- MAIL_PASSWORD=${MAIL_PASSWORD}
5048
depends_on:
5149
mysql:
5250
condition: service_healthy

example.env

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
DATASOURCE_URL=jdbc:mysql://localhost/commercifydb?createDatabaseIfNotExist=true
2+
DATASOURCE_USERNAME=
3+
DATASOURCE_PASSWORD=
4+
STRIPE_SECRET_TEST_KEY=
5+
STRIPE_WEBHOOK_SECRET=
6+
JWT_SECRET_KEY=7581e8477a88733917bc3b48f683a827935a492a0bd976a59429a72f28c71fd3
7+
ADMIN_EMAIL=<a valid email, order notification are sent here>
8+
ADMIN_PASSWORD=commercifyadmin123!
9+
ADMIN_ORDER_DASHBOARD=https://<admin dashboard>/admin/orders
10+
MOBILEPAY_CLIENT_ID=
11+
MOBILEPAY_CLIENT_SECRET=
12+
MOBILEPAY_SUBSCRIPTION_KEY=
13+
MOBILEPAY_MERCHANT_ID=
14+
MOBILEPAY_API_URL=
15+
MOBILEPAY_SYSTEM_NAME=
16+
MOBILEPAY_WEBHOOK_CALLBACK=https://<publicdomain>/api/v2/payments/webhooks/mobilepay/callback
17+
MAIL_HOST=smtp.gmail.com
18+
MAIL_PORT=
19+
MAIL_USERNAME=
20+
MAIL_PASSWORD=

pom.xml

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102
<dependency>
103103
<groupId>com.stripe</groupId>
104104
<artifactId>stripe-java</artifactId>
105-
<version>26.11.0</version>
105+
<version>28.3.0</version>
106106
<scope>compile</scope>
107107
</dependency>
108108
<dependency>
@@ -154,6 +154,10 @@
154154
<groupId>org.thymeleaf.extras</groupId>
155155
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
156156
</dependency>
157+
<dependency>
158+
<groupId>org.springframework.boot</groupId>
159+
<artifactId>spring-boot-starter-validation</artifactId>
160+
</dependency>
157161
</dependencies>
158162

159163
<build>
@@ -172,7 +176,28 @@
172176
</excludes>
173177
</configuration>
174178
</plugin>
179+
180+
<plugin>
181+
<groupId>cz.habarta.typescript-generator</groupId>
182+
<artifactId>typescript-generator-maven-plugin</artifactId>
183+
<version>3.2.1263</version>
184+
<executions>
185+
<execution>
186+
<id>generate</id>
187+
<goals>
188+
<goal>generate</goal>
189+
</goals>
190+
<phase>process-classes</phase>
191+
</execution>
192+
</executions>
193+
<configuration>
194+
<jsonLibrary>jackson2</jsonLibrary>
195+
<outputKind>module</outputKind>
196+
<classPatterns>
197+
<pattern>com.zenfulcode.commercify.api.**.dto.**</pattern>
198+
</classPatterns>
199+
</configuration>
200+
</plugin>
175201
</plugins>
176202
</build>
177-
178203
</project>

src/main/java/com/zenfulcode/commercify/commercify/CommercifyApplication.java renamed to src/main/java/com/zenfulcode/commercify/CommercifyApplication.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1-
package com.zenfulcode.commercify.commercify;
1+
package com.zenfulcode.commercify;
22

33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.web.client.RestTemplate;
57

68
@SpringBootApplication
79
public class CommercifyApplication {
810
public static void main(String[] args) {
911
SpringApplication.run(CommercifyApplication.class, args);
1012
}
11-
}
1213

14+
@Bean
15+
public RestTemplate restTemplate() {
16+
return new RestTemplate();
17+
}
18+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package com.zenfulcode.commercify.api.auth;
2+
3+
import com.zenfulcode.commercify.api.auth.dto.request.LoginRequest;
4+
import com.zenfulcode.commercify.api.auth.dto.request.RefreshTokenRequest;
5+
import com.zenfulcode.commercify.api.auth.dto.request.RegisterRequest;
6+
import com.zenfulcode.commercify.api.auth.dto.response.AuthResponse;
7+
import com.zenfulcode.commercify.api.auth.dto.response.NextAuthResponse;
8+
import com.zenfulcode.commercify.auth.application.service.AuthenticationApplicationService;
9+
import com.zenfulcode.commercify.auth.application.service.AuthenticationResult;
10+
import com.zenfulcode.commercify.auth.domain.exception.InvalidAuthenticationException;
11+
import com.zenfulcode.commercify.auth.domain.model.AuthenticatedUser;
12+
import com.zenfulcode.commercify.shared.interfaces.ApiResponse;
13+
import com.zenfulcode.commercify.user.application.service.UserApplicationService;
14+
import lombok.RequiredArgsConstructor;
15+
import lombok.extern.slf4j.Slf4j;
16+
import org.springframework.http.HttpStatus;
17+
import org.springframework.http.ResponseEntity;
18+
import org.springframework.web.bind.annotation.*;
19+
20+
@Slf4j
21+
@RestController
22+
@RequestMapping("/api/v2/auth")
23+
@RequiredArgsConstructor
24+
public class AuthController {
25+
private final AuthenticationApplicationService authService;
26+
private final UserApplicationService userService;
27+
28+
@PostMapping("/nextauth")
29+
public ResponseEntity<ApiResponse<NextAuthResponse>> nextAuthSignIn(@RequestBody LoginRequest request) {
30+
log.info("Next auth request: {}", request);
31+
32+
// Authenticate through the application service
33+
AuthenticationResult result = authService.authenticate(request.toCommand());
34+
35+
// Create and return the NextAuth response
36+
return ResponseEntity.ok(ApiResponse.success(NextAuthResponse.from(result)));
37+
}
38+
39+
@GetMapping("/session")
40+
public ResponseEntity<ApiResponse<NextAuthResponse>> validateSession(@RequestHeader("Authorization") String authHeader) {
41+
try {
42+
// Extract token using a domain service method
43+
String token = authService.extractTokenFromHeader(authHeader).orElseThrow(() -> new InvalidAuthenticationException("Invalid authorization header"));
44+
45+
// Validate token through the application service
46+
AuthenticatedUser user = authService.validateAccessToken(token);
47+
48+
// Create and return the NextAuth session response
49+
return ResponseEntity.ok(ApiResponse.success(NextAuthResponse.fromUser(user)));
50+
} catch (InvalidAuthenticationException e) {
51+
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
52+
}
53+
}
54+
55+
@PostMapping("/signin")
56+
public ResponseEntity<ApiResponse<AuthResponse>> login(@RequestBody LoginRequest request) {
57+
AuthenticationResult result = authService.authenticate(request.toCommand());
58+
59+
AuthResponse response = AuthResponse.from(result);
60+
return ResponseEntity.ok(ApiResponse.success(response));
61+
}
62+
63+
@PostMapping("/signup")
64+
public ResponseEntity<ApiResponse<AuthResponse>> register(@RequestBody RegisterRequest request) {
65+
66+
userService.registerUser(request.firstName(), request.lastName(), request.email(), request.password(), request.phone());
67+
68+
// Authenticate the newly registered user
69+
AuthenticationResult result = authService.authenticate(new LoginRequest(request.email(), request.password(), false).toCommand());
70+
71+
AuthResponse response = AuthResponse.from(result);
72+
return ResponseEntity.ok(ApiResponse.success(response));
73+
}
74+
75+
@PostMapping("/refresh")
76+
public ResponseEntity<ApiResponse<AuthResponse>> refreshToken(@RequestBody RefreshTokenRequest request) {
77+
78+
AuthenticationResult result = authService.refreshToken(request.refreshToken());
79+
AuthResponse response = AuthResponse.from(result);
80+
return ResponseEntity.ok(ApiResponse.success(response));
81+
}
82+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.zenfulcode.commercify.api.auth.dto.request;
2+
3+
import com.zenfulcode.commercify.auth.application.command.LoginCommand;
4+
5+
public record LoginRequest(
6+
String email,
7+
String password,
8+
Boolean isGuest
9+
) {
10+
public LoginCommand toCommand() {
11+
return new LoginCommand(email, password, isGuest != null && isGuest);
12+
}
13+
}

0 commit comments

Comments
 (0)