Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
username: ${{ secrets.SSH_USERNAME }}
key: ${{ secrets.SSH_KEY }}
port: 22
source: "docker-compose.yml,.env"
source: "docker/,.env,nginx/,deploy.sh"
target: "/home/ubuntu/growin/"

# EC2์—์„œ ๋„์ปค ์ปจํ…Œ์ด๋„ˆ ์žฌ๋ฐฐํฌ
Expand All @@ -43,10 +43,8 @@ jobs:
export GHCR_USERNAME=${{ github.actor }}
echo $GHCR_TOKEN | docker login ghcr.io -u $GHCR_USERNAME --password-stdin

sudo docker-compose pull

sudo docker-compose down || true

sudo docker-compose up -d

sudo docker image prune -a -f
# ๊ณตํ†ต ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰
sudo docker compose -f docker/docker-compose.common.yml up -d

# ๋ฐฐํฌ ๋กœ์ง ์‹คํ–‰
./deploy.sh
49 changes: 49 additions & 0 deletions .github/workflows/pr_upload_notify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Notify Slack on Pull Request Upload

on:
pull_request:
types: [opened]

jobs:
slack_notification:
runs-on: ubuntu-latest
steps:
- name: Send Slack notification
uses: slackapi/slack-github-action@v1.27.0
with:
payload: |
{
"text": ":bell: *New Pull Request!*",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":sparkles: *${{ github.actor }}* opened a PR"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Title:*\n${{ github.event.pull_request.title }}"
},
{
"type": "mrkdwn",
"text": "*Base Branch:*\n${{ github.base_ref }}"
},
{
"type": "mrkdwn",
"text": "*From Branch:*\n${{ github.head_ref }}"
},
{
"type": "mrkdwn",
"text": "*Link:*\n<${{ github.event.pull_request.html_url }}|View PR>"
}
]
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
77 changes: 77 additions & 0 deletions deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/bin/bash

APP_NAME=growin-api
BLUE_PORT=8080
GREEN_PORT=8081
NGINX_CONF=/home/ubuntu/growin/nginx/default.conf


echo "deploy start"

if ! docker ps --format '{{.Names}}' | grep -q "${APP_NAME}-blue" && \
! docker ps --format '{{.Names}}' | grep -q "${APP_NAME}-green"; then
echo "First deployment detected โ€” starting blue container..."
docker compose -f docker/docker-compose.blue.yml up -d
exit 0
fi


if docker ps --format '{{.Names}}' | grep -q "${APP_NAME}-blue"; then
CURRENT="blue"
NEXT="green"
CURRENT_PORT=$BLUE_PORT
NEXT_PORT=$GREEN_PORT
else
CURRENT="green"
NEXT="blue"
CURRENT_PORT=$GREEN_PORT
NEXT_PORT=$BLUE_PORT
fi


ehco "Current Container : $CURRENT"
echo "Next Container : $NEXT"

echo "deploy $NEXT Container"
docker compose -f docker/docker-compose.${NEXT}.yml up -d


echo "running health check"
success=false
for i in {1..20}; do
sleep 3
if curl -fs "http://localhost:${NEXT_PORT}/test/health" | grep -q "UP"; then
ehco "Health Check Passed"
success=true
break
fi
echo "Waiting for Service to be UP ... (${i}/10)"
done


# ์‹คํ–‰ ์‹คํŒจ ์‹œ -> ๋กค๋ฐฑ ์ง„ํ–‰ ํ›„ ์ข…๋ฃŒ
if [ "$success" = false ]; then
echo "Health check failed! Rolling back..."
docker compose -f docker/docker-compose.${NEXT}.yml down
exit 1
fi


# Reload Nginx
echo "if success, switch nginx conf and stop old container"
sudo sed -i "s/${APP_NAME}-${CURRENT}/${APP_NAME}-${NEXT}/" $NGINX_CONF
sudo sed -i "s/${CURRENT_PORT}/${NEXT_PORT}/" $NGINX_CONF
sudo docker exec nginx nginx -s reload

# Stop old container
echo "==> Stopping old container ${APP_NAME}_${CURRENT}"
docker stop ${APP_NAME}-${CURRENT} || true
docker rm ${APP_NAME}-${CURRENT} || true

echo "Cleaning unused images"
docker image prune -f >/dev/null 2>&1

echo "=============================="
echo "DEPLOYMENT SUCCESSFUL"
echo "Active container: ${NEXT}"
echo "=============================="
8 changes: 0 additions & 8 deletions docker-compose.yml

This file was deleted.

16 changes: 16 additions & 0 deletions docker/docker-compose.blue.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: '3.8'

services:
growin-api-blue:
image: ghcr.io/growin-2025/growin-server:latest
container_name: growin-api-blue
ports:
- "8080:8080"
env_file:
- .env
networks:
- app-network

networks:
app-network:
external: true
31 changes: 31 additions & 0 deletions docker/docker-compose.common.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
version: '3.8'

services:
nginx:
container_name: nginx
image: nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx:/etc/nginx/conf.d
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
restart: always
networks:
- growin-network

certbot:
container_name: certbot
image: certbot/certbot
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
entrypoint: /bin/sh -c "trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;"
networks:
- growin-network

networks:
app-network:
name: growin-network
driver: bridge
16 changes: 16 additions & 0 deletions docker/docker-compose.green.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: '3.8'

services:
growin-api-green:
image: ghcr.io/growin-2025/growin-server:latest
container_name: growin-api-green
ports:
- "8081:8080"
env_file:
- .env
networks:
- app-network

networks:
app-network:
external: true
32 changes: 32 additions & 0 deletions nginx/default.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# HTTP โ†’ HTTPS ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
server {
listen 80;
server_name growinserver.shop;
server_tokens off;

location /.well-known/acme-challenge/ {
root /var/www/certbot;
allow all;
}

location / {
return 301 https://$host$request_uri;
}
}

# HTTPS ์„ค์ •
server {
listen 443 ssl;
server_name growinserver.shop;

ssl_certificate /etc/letsencrypt/live/growinserver.shop/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/growinserver.shop/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

location / {
proxy_pass http://growin-api-blue:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//package ita.growin.domain.task.controller;
//
//import io.swagger.v3.oas.annotations.Operation;
//import io.swagger.v3.oas.annotations.tags.Tag;
//import ita.growin.domain.task.dto.CreateTaskRequestDto;
//import ita.growin.domain.task.dto.UpdateTaskRequestDto;
//import ita.growin.domain.task.service.TaskService;
//import ita.growin.global.response.APIResponse;
//import org.springframework.data.domain.Pageable;
//import org.springframework.data.domain.Slice;
//import org.springframework.data.web.PageableDefault;
//import org.springframework.lang.Nullable;
//import org.springframework.web.bind.annotation.*;
//
//@RestController
//@RequestMapping("/api/v1/tasks")
//@Tag(name = "ํ•  ์ผ", description = "ํ•  ์ผ ๊ด€๋ จ API")
//public class TaskController {
//
// private final TaskService taskService;
//
// public TaskController(TaskService taskService) {
// this.taskService = taskService;
// }
//
// @PostMapping
// @Operation(summary = "ํ•  ์ผ ์ƒ์„ฑ API")
// public APIResponse<?> createTask(
// @RequestParam("eventId") @Nullable Long eventId,
// @RequestBody CreateTaskRequestDto req) {
// taskService.createTask(eventId, req);
// return APIResponse.success();
// }
//
// @PatchMapping("/{taskId}")
// @Operation(summary = "ํ•  ์ผ ์ˆ˜์ • API")
// public APIResponse<?> updateTask(
// @PathVariable Long taskId,
// @RequestBody UpdateTaskRequestDto req) {
// taskService.updateTask(taskId, req);
// return APIResponse.success();
// }
//
// @DeleteMapping("/{taskId}")
// @Operation(summary = "ํ•  ์ผ ์‚ญ์ œ API")
// public APIResponse<?> deleteTask(
// @RequestParam("eventId") @Nullable Long eventId,
// @PathVariable Long taskId) {
// taskService.deleteTask(eventId, taskId);
// return APIResponse.success();
// }
//
// @GetMapping("/{taskId}")
// @Operation(summary = "ํ•  ์ผ ๋‹จ๊ฑด ์กฐํšŒ")
// public APIResponse<?> getTask(@PathVariable Long taskId) {
// return APIResponse.success(taskService.getTask(taskId));
// }
//
// @GetMapping("/event/{eventId}/tasks")
// @Operation(summary = "์ผ์ • ๋‚ด ํ•  ์ผ ์กฐํšŒ")
// public APIResponse<Slice<?>> getTasks(
// @PathVariable Long eventId,
// @PageableDefault(size = 20) Pageable pageable) {
// return APIResponse.success(taskService.getTasks(eventId, pageable));
// }
//
// @GetMapping("/tasks/today")
// @Operation(summary = "์˜ค๋Š˜ ํ•  ์ผ ์กฐํšŒ")
// public APIResponse<?> getTodayTasks(
// @PageableDefault(size = 20) Pageable pageable
// ) {
// return APIResponse.success(taskService.getTodayTasks(pageable));
// }
//
// @GetMapping("/tasks/someday")
// @Operation(summary = "์–ธ์  ๊ฐ€ ํ•  ์ผ ์กฐํšŒ")
// public APIResponse<?> getSomedayTasks(
// @PageableDefault(size = 20) Pageable pageable
// ) {
// return APIResponse.success(taskService.getSomedayTasks(pageable));
// }
//}
Comment on lines +1 to +82
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

โš ๏ธ Potential issue | ๐ŸŸก Minor

์ฃผ์„ ์ฒ˜๋ฆฌ๋œ ์ฝ”๋“œ ์ •๋ฆฌ ํ•„์š”

์ „์ฒด ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ฃผ์„ ์ฒ˜๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜๋ฅผ ์˜๋ฏธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  1. ๋ฏธ์™„์„ฑ ๊ธฐ๋Šฅ์˜ ์Šค์ผˆ๋ ˆํ†ค ์ฝ”๋“œ
  2. ํ–ฅํ›„ ๊ตฌํ˜„ ์˜ˆ์ •์ธ ํ”Œ๋ ˆ์ด์Šคํ™€๋”
  3. ์‹ค์ˆ˜๋กœ ํฌํ•จ๋œ ์ฝ”๋“œ

์ด ํŒŒ์ผ์ด PR์— ํฌํ•จ๋œ ์˜๋„๋ฅผ ๋ช…ํ™•ํžˆ ํ•ด์ฃผ์„ธ์š”:

  • ํ–ฅํ›„ ๊ตฌํ˜„์„ ์œ„ํ•œ ์Šค์ผˆ๋ ˆํ†ค์ด๋ผ๋ฉด, TODO ์ฃผ์„์ด๋‚˜ ์ด์Šˆ ์ฐธ์กฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค
  • ํ˜„์žฌ PR์˜ ๋ฒ”์œ„์— ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ํŒŒ์ผ์„ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ ๋ณ„๋„ PR๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค
  • ๊ตฌํ˜„์ด ์™„๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด, ์ฃผ์„์„ ์ œ๊ฑฐํ•˜๊ณ  ํ•„์š”ํ•œ ์„œ๋น„์Šค ๋ ˆ์ด์–ด์™€ DTO๋ฅผ ํ•จ๊ป˜ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

ํ•„์š”ํ•˜๋‹ค๋ฉด ์ด์Šˆ ์ƒ์„ฑ์„ ๋„์™€๋“œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿค– Prompt for AI Agents
In src/main/java/ita/growin/domain/task/controller/TaskController.java lines
1-82 the entire controller is commented out; clarify intent and fix by either
(a) if this is a skeleton for future work, keep the file but replace the block
comment with a single-line TODO at the top referencing an issue/ticket number
and a short note (e.g., "TODO: implement TaskController - see ISSUE-123"), (b)
if not part of this PR remove the file from the commit/branch, or (c) if
implementation is complete, uncomment the class and ensure required DTOs and
TaskService are present and wired before committing; pick and apply one of these
actions and update the PR description accordingly.

20 changes: 20 additions & 0 deletions src/main/java/ita/growin/global/config/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ita.growin.global.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
.formLogin(AbstractHttpConfigurer::disable)
.httpBasic(AbstractHttpConfigurer::disable);
return http.build();
}
Comment on lines +12 to +19
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

โš ๏ธ Potential issue | ๐Ÿ”ด Critical

๐Ÿงฉ Analysis chain

ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ ๋ณด์•ˆ ์„ค์ • ํ•„์š”

ํ˜„์žฌ ๋ชจ๋“  ์š”์ฒญ์— ๋Œ€ํ•ด ์ธ์ฆ ์—†์ด ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(permitAll()). ์ด๋Š” ๊ฐœ๋ฐœ ์ดˆ๊ธฐ ๋‹จ๊ณ„์—๋Š” ์ ํ•ฉํ•˜์ง€๋งŒ, ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ์‹ฌ๊ฐํ•œ ๋ณด์•ˆ ์œ„ํ—˜์ด ๋ฉ๋‹ˆ๋‹ค. ๋ฐฐํฌ ์ „์— ๋‹ค์Œ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

  • ์ ์ ˆํ•œ ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ ๊ทœ์น™
  • ๋ณดํ˜ธ๊ฐ€ ํ•„์š”ํ•œ ์—”๋“œํฌ์ธํŠธ์™€ ๊ณต๊ฐœ ์—”๋“œํฌ์ธํŠธ ๊ตฌ๋ถ„
  • ํ•„์š”ํ•œ ๊ฒฝ์šฐ CSRF ๋ณดํ˜ธ ํ™œ์„ฑํ™”

ํ˜„์žฌ ๊ตฌ์„ฑ์ด ๊ฐœ๋ฐœ ๋‹จ๊ณ„์šฉ ์ž„์‹œ ์„ค์ •์ธ์ง€, ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ ์ „ ๋ณด์•ˆ ๊ฐ•ํ™” ๊ณ„ํš์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. SwaggerConfig์—์„œ BearerAuth๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ, ํ–ฅํ›„ JWT ๊ธฐ๋ฐ˜ ์ธ์ฆ ๊ตฌํ˜„์„ ๊ณ„ํš ์ค‘์ธ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.



---

๐Ÿ Script executed:

```shell
#!/bin/bash
# Find and examine SecurityConfig.java
find . -name "SecurityConfig.java" -type f 2>/dev/null | head -20

Length of output: 60


๐Ÿ Script executed:

#!/bin/bash
# Find and examine SwaggerConfig or similar configuration files
find . -name "*Swagger*" -o -name "*swagger*" 2>/dev/null | grep -E "\.(java|yml|yaml)$"

Length of output: 59


๐Ÿ Script executed:

#!/bin/bash
# Search for TODO/FIXME comments related to security or auth
rg -n -i "(TODO|FIXME).*(security|auth|jwt|bearer)" --type java

Length of output: 0


๐Ÿ Script executed:

#!/bin/bash
# Check for application properties/yml files with profiles
find . -name "application*.properties" -o -name "application*.yml" -o -name "application*.yaml" 2>/dev/null

Length of output: 166


๐Ÿ Script executed:

#!/bin/bash
# Examine the full SecurityConfig.java file
find . -name "SecurityConfig.java" -exec cat {} \;

Length of output: 816



---

๐Ÿ Script executed:

```shell
#!/bin/bash
# Examine SwaggerConfig.java
cat ./src/main/java/ita/growin/global/config/SwaggerConfig.java

Length of output: 1619


๐Ÿ Script executed:

#!/bin/bash
# Examine main application.yaml
cat ./src/main/resources/application.yaml

Length of output: 120


๐Ÿ Script executed:

#!/bin/bash
# Search for JWT, Bearer, Authentication related code
rg -n -i "(jwt|bearer|authentication|authoriz)" --type java -C 2

Length of output: 2955


๐Ÿ Script executed:

#!/bin/bash
# Search for @ConditionalOnProfile or profile-conditional configurations
rg -n "@ConditionalOnProfile\|@Profile" --type java

Length of output: 0


ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ ๋ณด์•ˆ ์„ค์ • ํ•„์ˆ˜ ๊ตฌํ˜„

ํ˜„์žฌ SecurityConfig์—์„œ ๋ชจ๋“  ์š”์ฒญ์— ์ธ์ฆ ์—†์ด ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(permitAll()). ์ด ์„ค์ •์ด ๋ชจ๋“  ํ™˜๊ฒฝ(๋กœ์ปฌ, ๊ฐœ๋ฐœ, ํ…Œ์ŠคํŠธ, ํ”„๋กœ๋•์…˜)์— ๋™์ผํ•˜๊ฒŒ ์ ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํ™•์ธ๋œ ๋ฌธ์ œ:

  • permitAll()๋กœ ์ธํ•ด ๋ชจ๋“  ์—”๋“œํฌ์ธํŠธ๊ฐ€ ๋ฌด์กฐ๊ฑด ์ ‘๊ทผ ๊ฐ€๋Šฅ
  • csrf, formLogin, httpBasic ๋ชจ๋‘ ๋น„ํ™œ์„ฑํ™”
  • SwaggerConfig์—์„œ BearerAuth JWT๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์œผ๋‚˜ ์‹ค์ œ ๊ตฌํ˜„์€ ์—†์Œ
  • ํ™˜๊ฒฝ๋ณ„ ํ”„๋กœํ•„(@Profile)์„ ํ†ตํ•œ ๋ณด์•ˆ ์„ค์ • ๋ถ„๋ฆฌ ๋ฏธ์ ์šฉ

ํ•„์ˆ˜ ์กฐ์น˜:
ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ ์ „์— ๋‹ค์Œ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

  • JWT ๊ธฐ๋ฐ˜ ์ธ์ฆ ํ•„ํ„ฐ ๊ตฌํ˜„
  • ๋ณดํ˜ธ๊ฐ€ ํ•„์š”ํ•œ ์—”๋“œํฌ์ธํŠธ ์ •์˜ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ ๊ทœ์น™ ์„ค์ •
  • ๊ณต๊ฐœ ์—”๋“œํฌ์ธํŠธ(์˜ˆ: ํšŒ์›๊ฐ€์ž…, ๋กœ๊ทธ์ธ) ๊ตฌ๋ถ„
  • ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ๋ณ„๋„ ๋ณด์•ˆ ์„ค์ • ์ ์šฉ

SwaggerConfig์˜ BearerAuth ์ •์˜์™€ CommonErrorCode์˜ UNAUTHORIZED/FORBIDDEN ์ฝ”๋“œ๋ฅผ ๊ณ ๋ คํ•˜๋ฉด JWT ์ธ์ฆ ๊ตฌํ˜„์ด ๊ณ„ํš ์ค‘์ธ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ๊ตฌํ˜„ ์ผ์ •๊ณผ ๊ณ„ํš์„ ๋ช…ํ™•ํžˆ ํ•˜๊ณ , ๋ฐฐํฌ ์ „์— ๋ฐ˜๋“œ์‹œ ๋ณด์•ˆ ๊ฐ•ํ™”๋ฅผ ์™„๋ฃŒํ•˜์„ธ์š”.

๐Ÿค– Prompt for AI Agents
src/main/java/ita/growin/global/config/SecurityConfig.java lines 12-19: ํ˜„์žฌ ๋ชจ๋“ 
์š”์ฒญ์— permitAll()์„ ์ ์šฉํ•˜๊ณ  CSRF/formLogin/httpBasic์„ ๋น„ํ™œ์„ฑํ™”ํ•œ ์ƒํƒœ๋กœ ํ”„๋กœ๋•์…˜ ๋ณด์•ˆ์ด ๋ฏธ๊ตฌํ˜„๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ,
ํ”„๋กœ๋•์…˜ ํ”„๋กœํŒŒ์ผ์šฉ ๋ณด์•ˆ ์„ค์ •์„ ์ถ”๊ฐ€ํ•˜๊ณ  JWT ๊ธฐ๋ฐ˜ ์ธ์ฆ์„ ์ ์šฉํ•˜๋„๋ก ์ˆ˜์ •ํ•˜์„ธ์š”: JWT ํ† ํฐ์„ ๊ฒ€์ฆํ•˜๋Š” OncePerRequestFilter
๊ตฌํ˜„์„ ์ถ”๊ฐ€ํ•˜๊ณ  SecurityFilterChain์—์„œ stateless ์„ธ์…˜ ์ •์ฑ…์„ ์„ค์ •ํ•œ ๋’ค ๋ณดํ˜ธํ•  ์—”๋“œํฌ์ธํŠธ์™€ ๊ณต๊ฐœ ์—”๋“œํฌ์ธํŠธ(์˜ˆ:
/api/auth/**, /signup ๋“ฑ)๋ฅผ ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„ํ•ด ๊ถŒํ•œ ๊ทœ์น™์„ ์ ์šฉํ•˜๋ฉฐ, Swagger์šฉ BearerAuth์™€ ์—ฐ๋™๋˜๋„๋ก
Authorization ํ—ค๋”์—์„œ ํ† ํฐ์„ ์ฝ์–ด ์ธ์ฆ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์ธ์ฆ/์ธ๊ฐ€ ์‹คํŒจ ์‹œ ์ ์ ˆํ•œ 401/403 ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ํ•ธ๋“ค๋Ÿฌ๋ฅผ
๋“ฑ๋กํ•˜์„ธ์š”; ๋˜ํ•œ @Profile("prod") ๋˜๋Š” ํ™˜๊ฒฝ๋ณ„ ๋ถ„๊ธฐ์œผ๋กœ ํ”„๋กœ๋•์…˜์—์„œ๋งŒ ์—„๊ฒฉํ•œ ๋ณด์•ˆ์ฒด๊ณ„๊ฐ€ ํ™œ์„ฑํ™”๋˜๋„๋ก ๊ตฌ์„ฑํ•˜์„ธ์š”.

}
Loading