Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
515ef8e
♻️ Refactor codes by adding final keyword
choridev Jul 28, 2025
f495900
🧑‍💻 Change the examples of ErrorResponse
choridev Jul 28, 2025
1c455b6
🔒️ Provide JWT exceptions according to the env
choridev Jul 29, 2025
069f5d6
♻️ Delegate token verification responsibility
choridev Jul 29, 2025
159ce76
🔧 Set branch coverage to 0.60
choridev Jul 29, 2025
3c6e8ca
💚 Change the name of branch from develop to dev
choridev Jul 29, 2025
7ac8c9c
📝 Change the example of merging branches
choridev Jul 29, 2025
9099a4c
🔒️ Delete the RT if the AT is not expired
choridev Jul 29, 2025
b99328e
🔀 Merge pull request #67 from feat/error
choridev Jul 29, 2025
cfea38e
Refactor codes related to Auth and Member (#68)
choridev Jul 30, 2025
a1f7ae7
Add Logout API (#75)
choridev Jul 30, 2025
2ff9be2
Separate source code by domain (#78)
choridev Jul 31, 2025
3f9f340
Add delete account API (#79)
choridev Aug 1, 2025
1165e68
Add change nickname API (#80)
choridev Aug 1, 2025
2baeb76
Refactor/#81 common exception (#82)
sotogito Aug 2, 2025
bdbd75b
Separate exceptions by domain (#85)
choridev Aug 3, 2025
0d350fc
🔀 Verify ID Token from Apple (#86)
choridev Aug 8, 2025
82e8a4b
Add scenario and mission domain CRUD feat (#88)
sotogito Aug 18, 2025
3b6dce3
Refactor/#89 scenario api (#90)
sotogito Aug 25, 2025
8153f2a
Feat/#87-terms-of-service (#91)
choridev Aug 27, 2025
ca18da7
Feat/#74 notification (#92)
sotogito Aug 30, 2025
33e9540
🔀 Merge branch 'dev' into bugfix/#95-terms-is-over-14
choridev Aug 30, 2025
cd690fe
Feat/#72 weather (#94)
sotogito Sep 1, 2025
727956c
Feat/#73 scenario backup (#97)
sotogito Sep 3, 2025
f85210f
Feat/#100 future basic missio check (#102)
sotogito Sep 6, 2025
fdae09d
Refactor/#98 api docs (#103)
sotogito Sep 9, 2025
5819198
Bug/#104 scenario (#105)
sotogito Sep 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
- [ ] sre: 시스템 관리 및 IT 인프라 자동화 작업

### 🪾 반영 브랜치
<!-- 예) feat/login -> main -->
<!-- 예) feat/login -> dev -->

### ✨ 변경 사항
<!-- 예) 로그인 시, 구글 소셜 로그인 기능을 추가했습니다.-->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: Deployment to Development Server
name: Deploy to Development Server

on:
push:
branches: [develop]
branches: [dev]

env:
AWS_IAM_ROLE_TO_ASSUME: ${{ secrets.DEV_AWS_IAM_ROLE_TO_ASSUME }}
Expand Down Expand Up @@ -168,7 +168,7 @@ jobs:
{
"author": { "name": "${{ github.actor }}" },
"title": "Deployment Succeeded",
"description": "Branch: `${{ github.ref_name }}`\nWorkflow: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"description": "Branch: `${{ github.ref_name }}`\nWorkflow: [View on GitHub](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})",
"color": 10478271,
"fields": [
{ "name": "Service", "value": "`${{ steps.extract-name.outputs.service_name }}`", "inline": true },
Expand All @@ -189,7 +189,7 @@ jobs:
{
"author": { "name": "${{ github.actor }}" },
"title": "Deployment Failed",
"description": "Branch: `${{ github.ref_name }}`\nWorkflow: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n\n**Action**: App Runner will automatically attempt to roll back to the last known good configuration.",
"description": "Branch: `${{ github.ref_name }}`\nWorkflow: [View on GitHub](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})\n\n**Action**: App Runner will automatically attempt to roll back to the last known good configuration.",
"color": 13458524,
"fields": [
{ "name": "Service", "value": "`${{ steps.extract-name.outputs.service_name }}`", "inline": true },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Deployment to Production Server
name: Deploy to Production Server

on:
push:
Expand Down Expand Up @@ -145,7 +145,7 @@ jobs:
{
"author": { "name": "${{ github.actor }}" },
"title": "Deployment Succeeded",
"description": "Branch: `${{ github.ref_name }}`\nWorkflow: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"description": "Branch: `${{ github.ref_name }}`\nWorkflow: [View on GitHub](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})",
"color": 10478271,
"fields": [
{ "name": "Cluster", "value": "`${{ env.ECS_CLUSTER }}`", "inline": true },
Expand Down Expand Up @@ -188,7 +188,7 @@ jobs:
{
"author": { "name": "${{ github.actor }}" },
"title": "Deployment Failed",
"description": "Branch: `${{ github.ref_name }}`\nWorkflow: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n\n**Action**: Attempted to roll back to the previous stable task definition.",
"description": "Branch: `${{ github.ref_name }}`\nWorkflow: [View on GitHub](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})\n\n**Action**: Attempted to roll back to the previous stable task definition.",
"color": 13458524,
"fields": [
{ "name": "Service", "value": "`${{ env.ECS_SERVICE }}`", "inline": true },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Deployment to Staging Server
name: Deploy to Staging Server

on:
push:
Expand Down Expand Up @@ -145,7 +145,7 @@ jobs:
{
"author": { "name": "${{ github.actor }}" },
"title": "Deployment Succeeded",
"description": "Branch: `${{ github.ref_name }}`\nWorkflow: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"description": "Branch: `${{ github.ref_name }}`\nWorkflow: [View on GitHub](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})",
"color": 10478271,
"fields": [
{ "name": "Cluster", "value": "`${{ env.ECS_CLUSTER }}`", "inline": true },
Expand Down Expand Up @@ -188,7 +188,7 @@ jobs:
{
"author": { "name": "${{ github.actor }}" },
"title": "Deployment Failed",
"description": "Branch: `${{ github.ref_name }}`\nWorkflow: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n\n**Action**: Attempted to roll back to the previous stable task definition.",
"description": "Branch: `${{ github.ref_name }}`\nWorkflow: [View on GitHub](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})\n\n**Action**: Attempted to roll back to the previous stable task definition.",
"color": 13458524,
"fields": [
{ "name": "Service", "value": "`${{ env.ECS_SERVICE }}`", "inline": true },
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/notify-assigned-issue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
{
"title": "${{ github.event.issue.title }}",
"color": 10478271,
"description": "${{ github.event.issue.html_url }}",
"description": "[View on GitHub](${{ github.event.issue.html_url }})",
"fields": [
{
"name": "Issue Number",
Expand Down
67 changes: 67 additions & 0 deletions .github/workflows/notify-on-comment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Notify on Comment

on:
issue_comment:
types: [created]

env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}

permissions:
contents: read

jobs:
notify-on-comment:
runs-on: ubuntu-latest
steps:
- name: Send PR Comment Notification
if: github.event.issue.pull_request
uses: Ilshidur/action-discord@0.3.2
with:
args: "A new comment has been added to the pull request 💬"
env:
DISCORD_WEBHOOK: ${{ env.DISCORD_WEBHOOK }}
DISCORD_EMBEDS: |
[
{
"author": {
"name": "${{ github.event.comment.user.login }}"
},
"title": "Comment on PR #${{ github.event.issue.number }}: ${{ github.event.issue.title }}",
"color": 10478271,
"description": "${{ github.event.comment.body }}\n\n[View Comment](${{ github.event.comment.html_url }})",
"fields": [
{
"name": "Pull Request",
"value": "[Link](${{ github.event.issue.html_url }})",
"inline": true
}
]
}
]

- name: Send Issue Comment Notification
if: ${{ !github.event.issue.pull_request }}
uses: Ilshidur/action-discord@0.3.2
with:
args: "A new comment has been added to the issue 💬"
env:
DISCORD_WEBHOOK: ${{ env.DISCORD_WEBHOOK }}
DISCORD_EMBEDS: |
[
{
"author": {
"name": "${{ github.event.comment.user.login }}"
},
"title": "Comment on Issue #${{ github.event.issue.number }}: ${{ github.event.issue.title }}",
"color": 10478271,
"description": "${{ github.event.comment.body }}\n\n[View Comment](${{ github.event.comment.html_url }})",
"fields": [
{
"name": "Issue",
"value": "[Link](${{ github.event.issue.html_url }})",
"inline": true
}
]
}
]
7 changes: 4 additions & 3 deletions .github/workflows/validate-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ jobs:
--health-retries 5

steps:
- uses: actions/checkout@v4
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis

Expand Down Expand Up @@ -71,7 +72,7 @@ jobs:
},
"title": "#${{ github.event.pull_request.number }}: ${{ github.event.pull_request.title }}",
"color": 10478271,
"description": "${{ github.event.pull_request.html_url }}",
"description": "[View on GitHub](${{ github.event.pull_request.html_url }})",
"fields": [
{
"name": "Base Branch",
Expand Down Expand Up @@ -102,7 +103,7 @@ jobs:
},
"title": "#${{ github.event.pull_request.number }}: ${{ github.event.pull_request.title }}",
"color": 13458524,
"description": "${{ github.event.pull_request.html_url }}",
"description": "[View on GitHub](${{ github.event.pull_request.html_url }})",
"fields": [
{
"name": "Base Branch",
Expand Down
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ repositories {

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-log4j2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Expand Down Expand Up @@ -137,7 +138,8 @@ jacocoTestCoverageVerification {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, excludes: [
'**/*Application.class',
'**/config/*Config.class'
'**/config/*Config.class',
'**/GlobalExceptionHandler.class'
])
}))
}
Expand Down
4 changes: 2 additions & 2 deletions checkstyle/naver-checkstyle-rules.xml
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ The following rules in the Naver coding convention cannot be checked by this con

<!--- Exclude module-info.java -->
<module name="BeforeExecutionExclusionFileFilter">
<property name="fileNamePattern" value="module\-info\.java$"/>
</module>
<property name="fileNamePattern" value="module\-info\.java$|.*ApiDocs\.java$"/>
</module>

</module>
2 changes: 2 additions & 0 deletions src/main/java/com/und/server/ServerApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableFeignClients
@EnableScheduling
@ConfigurationPropertiesScan
public class ServerApplication {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.und.server.config;
package com.und.server.auth.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
Expand All @@ -10,14 +10,19 @@
@Configuration
public class ObservabilityUserConfig {

@Value("${observability.prometheus.username}")
private String prometheusUsername;
private final String prometheusUsername;
private final String prometheusPassword;

@Value("${observability.prometheus.password}")
private String prometheusPassword;
public ObservabilityUserConfig(
@Value("${observability.prometheus.username}") final String prometheusUsername,
@Value("${observability.prometheus.password}") final String prometheusPassword
) {
this.prometheusUsername = prometheusUsername;
this.prometheusPassword = prometheusPassword;
}

@Bean
public InMemoryUserDetailsManager prometheusUserDetails(PasswordEncoder passwordEncoder) {
public InMemoryUserDetailsManager prometheusUserDetails(final PasswordEncoder passwordEncoder) {
return new InMemoryUserDetailsManager(User.builder()
.username(prometheusUsername)
.password(passwordEncoder.encode(prometheusPassword))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.und.server.config;
package com.und.server.auth.config;

import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Bean;
Expand All @@ -15,8 +15,9 @@
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.und.server.security.CustomAuthenticationEntryPoint;
import com.und.server.security.JwtAuthenticationFilter;
import com.und.server.auth.filter.CustomAuthenticationEntryPoint;
import com.und.server.auth.filter.JwtAuthenticationFilter;
import com.und.server.common.util.ProfileManager;

import lombok.RequiredArgsConstructor;

Expand All @@ -27,6 +28,7 @@ public class SecurityConfig {

private final JwtAuthenticationFilter jwtAuthenticationFilter;
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
private final ProfileManager profileManager;

@Bean
public PasswordEncoder passwordEncoder() {
Expand All @@ -35,7 +37,7 @@ public PasswordEncoder passwordEncoder() {

@Bean
@Order(1)
public SecurityFilterChain actuatorSecurityFilterChain(HttpSecurity http) throws Exception {
public SecurityFilterChain actuatorSecurityFilterChain(final HttpSecurity http) throws Exception {
return http
.securityMatcher(EndpointRequest.toAnyEndpoint())
.authorizeHttpRequests(authorize -> authorize
Expand All @@ -51,21 +53,27 @@ public SecurityFilterChain actuatorSecurityFilterChain(HttpSecurity http) throws

@Bean
@Order(2)
public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http) throws Exception {
public SecurityFilterChain apiSecurityFilterChain(final HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(authorize -> {
authorize
.requestMatchers(HttpMethod.POST, "/v*/auth/**").permitAll()
.requestMatchers("/error").permitAll();

if (!profileManager.isProdOrStgProfile()) {
authorize
.requestMatchers(HttpMethod.POST, "/v*/test/access").permitAll()
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll();
}

authorize.anyRequest().authenticated();
})
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling(handler -> handler.authenticationEntryPoint(customAuthenticationEntryPoint))
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.csrf(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable)
.httpBasic(AbstractHttpConfigurer::disable)
.sessionManagement(sessionManagement -> sessionManagement
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorize -> authorize
// FIXME: Remove "/v*/test/access" when deleting TestController
.requestMatchers(HttpMethod.POST, "/v*/auth/**", "/v*/test/access").permitAll()
.requestMatchers("/error").permitAll()
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
.anyRequest().authenticated())
.exceptionHandling(handler -> handler.authenticationEntryPoint(customAuthenticationEntryPoint))
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}

Expand Down
63 changes: 63 additions & 0 deletions src/main/java/com/und/server/auth/controller/AuthController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.und.server.auth.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.und.server.auth.dto.request.AuthRequest;
import com.und.server.auth.dto.request.NonceRequest;
import com.und.server.auth.dto.request.RefreshTokenRequest;
import com.und.server.auth.dto.response.AuthResponse;
import com.und.server.auth.dto.response.NonceResponse;
import com.und.server.auth.filter.AuthMember;
import com.und.server.auth.service.AuthService;

import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@RequestMapping("/v1/auth")
public class AuthController {

private final AuthService authService;

@PostMapping("/nonce")
@ApiResponse(responseCode = "201", description = "Nonce created")
public ResponseEntity<NonceResponse> generateNonce(@RequestBody @Valid final NonceRequest nonceRequest) {
final NonceResponse nonceResponse = authService.generateNonce(nonceRequest);

return ResponseEntity.status(HttpStatus.CREATED).body(nonceResponse);
}

@PostMapping("/login")
public ResponseEntity<AuthResponse> login(@RequestBody @Valid final AuthRequest authRequest) {
final AuthResponse authResponse = authService.login(authRequest);

return ResponseEntity.status(HttpStatus.OK).body(authResponse);
}

@PostMapping("/tokens")
@ApiResponse(responseCode = "201", description = "Tokens reissued")
public ResponseEntity<AuthResponse> reissueTokens(
@RequestBody @Valid final RefreshTokenRequest refreshTokenRequest
) {
final AuthResponse authResponse = authService.reissueTokens(refreshTokenRequest);

return ResponseEntity.status(HttpStatus.CREATED).body(authResponse);
}

@DeleteMapping("/logout")
@ApiResponse(responseCode = "204", description = "Logout successful")
public ResponseEntity<Void> logout(@Parameter(hidden = true) @AuthMember final Long memberId) {
authService.logout(memberId);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}

}
Loading
Loading