From a1075ffd35df2937cbccf1e507d1541927e9a2c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Wed, 27 Nov 2024 21:51:49 +0900 Subject: [PATCH 01/33] feat: Add WebSocket adapter and update namespace configuration --- docker-compose.yml | 2 -- server/src/chat/chat.gateway.ts | 2 +- server/src/drawing/drawing.gateway.ts | 2 +- server/src/game/game.gateway.ts | 2 +- server/src/main.ts | 9 +++++++++ 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 14217294..d0a075bf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3' - services: api: build: diff --git a/server/src/chat/chat.gateway.ts b/server/src/chat/chat.gateway.ts index beb61a7e..89d98b1c 100644 --- a/server/src/chat/chat.gateway.ts +++ b/server/src/chat/chat.gateway.ts @@ -7,7 +7,7 @@ import { BadRequestException } from 'src/exceptions/game.exception'; @WebSocketGateway({ cors: '*', - namespace: 'chat', + namespace: '/socket.io/chat', }) @UseFilters(WsExceptionFilter) export class ChatGateway { diff --git a/server/src/drawing/drawing.gateway.ts b/server/src/drawing/drawing.gateway.ts index 36760c7a..61fe64bd 100644 --- a/server/src/drawing/drawing.gateway.ts +++ b/server/src/drawing/drawing.gateway.ts @@ -13,7 +13,7 @@ import { WsExceptionFilter } from 'src/filters/ws-exception.filter'; @WebSocketGateway({ cors: '*', - namespace: 'drawing', + namespace: '/socket.io/drawing', }) @UseFilters(WsExceptionFilter) export class DrawingGateway implements OnGatewayConnection { diff --git a/server/src/game/game.gateway.ts b/server/src/game/game.gateway.ts index 9ecf64fa..6d2c9e26 100644 --- a/server/src/game/game.gateway.ts +++ b/server/src/game/game.gateway.ts @@ -18,7 +18,7 @@ import { TimerType } from 'src/common/enums/game.timer.enum'; @WebSocketGateway({ cors: '*', - namespace: 'game', + namespace: '/socket.io/game', }) @UseFilters(WsExceptionFilter) export class GameGateway implements OnGatewayDisconnect { diff --git a/server/src/main.ts b/server/src/main.ts index a33713c2..95c970b3 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -1,12 +1,21 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; +import { IoAdapter } from '@nestjs/platform-socket.io'; async function bootstrap() { const app = await NestFactory.create(AppModule); + + app.setGlobalPrefix('api'); + app.enableCors({ origin: '*', methods: '*', }); + + const httpServer = app.getHttpServer(); + const ioAdapter = new IoAdapter(httpServer); + app.useWebSocketAdapter(ioAdapter); + await app.listen(process.env.PORT ?? 3000); } bootstrap(); From e2bd7604af91aa08e60e1bb9fed455dccfbfa3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Wed, 27 Nov 2024 22:34:37 +0900 Subject: [PATCH 02/33] chore: Update Nginx proxy_pass to use Docker service name --- nginx.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nginx.conf b/nginx.conf index ac92736f..47f702be 100644 --- a/nginx.conf +++ b/nginx.conf @@ -12,7 +12,7 @@ server { } location /api { - proxy_pass http://api:3000; + proxy_pass http://troublepainter_api:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -21,7 +21,7 @@ server { } location /socket.io { - proxy_pass http://api:3000; + proxy_pass http://troublepainter_api:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; From 2f8484eb65e2db1d25c2a0010fd4a7b44c8268f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Wed, 27 Nov 2024 23:19:12 +0900 Subject: [PATCH 03/33] feat: Configure HTTPS with SSL certificate --- docker-compose.yml | 3 +++ nginx.conf | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index d0a075bf..0b1a92da 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,8 +19,11 @@ services: context: . dockerfile: Dockerfile.nginx container_name: troublepainter_nginx + volumes: + - /etc/letsencrypt:/etc/letsencrypt ports: - "80:80" + - "443:443" depends_on: - api networks: diff --git a/nginx.conf b/nginx.conf index 47f702be..37ea4d11 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,6 +1,14 @@ server { listen 80; - server_name 175.45.205.6; + server_name www.troublepainter.site; + return 301 https://$server_name$request_uri; +} +server { + listen 443 ssl; + server_name www.troublepainter.site; + + ssl_certificate /etc/letsencrypt/live/www.troublepainter.site/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/www.troublepainter.site/privkey.pem; gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; @@ -12,7 +20,7 @@ server { } location /api { - proxy_pass http://troublepainter_api:3000; + proxy_pass http://api:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -21,7 +29,7 @@ server { } location /socket.io { - proxy_pass http://troublepainter_api:3000; + proxy_pass http://api:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; From 966b3c02c5cfe95825d738a6d8e6879faae054ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Wed, 27 Nov 2024 23:40:05 +0900 Subject: [PATCH 04/33] chore: Explicitly define network name in docker-compose.yml --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index 0b1a92da..c2339a20 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -32,4 +32,5 @@ services: networks: app_network: + name: app_network driver: bridge \ No newline at end of file From def2b19daf66b3359b8b7c49f92e558712410b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 01:03:53 +0900 Subject: [PATCH 05/33] feat: Optimize Docker-based deployment and CI/CD pipelines --- .github/workflows/client-ci-cd.yml | 30 +++++++++++++++++++---- .github/workflows/server-ci-cd.yml | 13 +++------- Dockerfile.nestjs | 5 ---- Dockerfile.nginx | 2 +- client/src/api/api.config.ts | 2 +- client/src/stores/socket/socket.config.ts | 6 ++--- docker-compose.yml | 4 +++ 7 files changed, 37 insertions(+), 25 deletions(-) diff --git a/.github/workflows/client-ci-cd.yml b/.github/workflows/client-ci-cd.yml index 75eea801..63c63b90 100644 --- a/.github/workflows/client-ci-cd.yml +++ b/.github/workflows/client-ci-cd.yml @@ -46,10 +46,33 @@ jobs: VITE_SOCKET_URL: ${{secrets.VITE_SOCKET_URL}} run: pnpm build - deploy: + docker-deploy: needs: ci runs-on: ubuntu-latest steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Docker Setup + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and Push Docker Image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile.nginx + push: true + tags: ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-nginx:latest + build-args: | + VITE_API_URL=${{secrets.VITE_API_URL}} + VITE_SOCKET_URL=${{secrets.VITE_SOCKET_URL}} + - name: Deploy to Server uses: appleboy/ssh-action@v1.0.0 with: @@ -57,8 +80,5 @@ jobs: username: mira key: ${{ secrets.SSH_PRIVATE_KEY }} script: | - cd /home/mira/web30-stop-troublepainter - git pull origin develop - - docker compose build nginx + docker pull ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-nginx:latest docker compose up -d nginx \ No newline at end of file diff --git a/.github/workflows/server-ci-cd.yml b/.github/workflows/server-ci-cd.yml index e5aa6dd3..baf49e20 100644 --- a/.github/workflows/server-ci-cd.yml +++ b/.github/workflows/server-ci-cd.yml @@ -60,7 +60,7 @@ jobs: context: . file: ./Dockerfile.nestjs push: true - tags: ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter:latest + tags: ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-api:latest build-args: | REDIS_HOST=${{ secrets.REDIS_HOST }} REDIS_PORT=${{ secrets.REDIS_PORT }} @@ -74,12 +74,5 @@ jobs: username: mira key: ${{ secrets.SSH_PRIVATE_KEY }} script: | - cd /home/mira/web30-stop-troublepainter - git pull origin develop - - echo "REDIS_HOST=${{ secrets.REDIS_HOST }}" > .env - echo "REDIS_PORT=${{ secrets.REDIS_PORT }}" >> .env - echo "CLOVA_API_KEY=${{ secrets.CLOVA_API_KEY }}" >> .env - echo "CLOVA_GATEWAY_KEY=${{ secrets.CLOVA_GATEWAY_KEY }}" >> .env - - docker compose up -d \ No newline at end of file + docker pull ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-api:latest + docker compose up -d api \ No newline at end of file diff --git a/Dockerfile.nestjs b/Dockerfile.nestjs index 18a9fa34..8971ea5e 100644 --- a/Dockerfile.nestjs +++ b/Dockerfile.nestjs @@ -28,13 +28,8 @@ RUN corepack enable && corepack prepare pnpm@9.12.3 --activate && cd server && p WORKDIR /app/server -ARG REDIS_HOST -ARG REDIS_PORT - ENV NODE_ENV=production ENV PORT=3000 -ENV REDIS_HOST=$REDIS_HOST -ENV REDIS_PORT=$REDIS_PORT EXPOSE 3000 diff --git a/Dockerfile.nginx b/Dockerfile.nginx index 73a78717c..2d93a9bc 100644 --- a/Dockerfile.nginx +++ b/Dockerfile.nginx @@ -13,6 +13,6 @@ FROM nginx:alpine COPY nginx.conf /etc/nginx/templates/default.conf.template COPY --from=builder /app/client/dist /usr/share/nginx/html -EXPOSE 80 +EXPOSE 80 443 CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/client/src/api/api.config.ts b/client/src/api/api.config.ts index 672c05c9..92ec8b04 100644 --- a/client/src/api/api.config.ts +++ b/client/src/api/api.config.ts @@ -6,7 +6,7 @@ export const API_CONFIG = { BASE_URL, ENDPOINTS: { GAME: { - CREATE_ROOM: '/game/rooms', + CREATE_ROOM: '/api/game/rooms', }, }, OPTIONS: { diff --git a/client/src/stores/socket/socket.config.ts b/client/src/stores/socket/socket.config.ts index e714a3d8..87b5ef3e 100644 --- a/client/src/stores/socket/socket.config.ts +++ b/client/src/stores/socket/socket.config.ts @@ -85,9 +85,9 @@ export const SOCKET_CONFIG = { }, /** 네임스페이스별 경로 */ PATHS: { - [SocketNamespace.GAME]: '/game', - [SocketNamespace.DRAWING]: '/drawing', - [SocketNamespace.CHAT]: '/chat', + [SocketNamespace.GAME]: '/socket.io/game', + [SocketNamespace.DRAWING]: 'socket.io/drawing', + [SocketNamespace.CHAT]: '/socket.io/chat', }, } as const; diff --git a/docker-compose.yml b/docker-compose.yml index c2339a20..cf733085 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,6 +19,10 @@ services: context: . dockerfile: Dockerfile.nginx container_name: troublepainter_nginx + environment: + - NODE_ENV=production + - VITE_API_URL=${VITE_API_URL} + - VITE_SOCKET_URL=${VITE_SOCKET_URL} volumes: - /etc/letsencrypt:/etc/letsencrypt ports: From 16fa032942dc60c80f6f38795101eccad847d312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 01:08:25 +0900 Subject: [PATCH 06/33] fix: Resolve missing Docker Compose file issue --- .github/workflows/client-ci-cd.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/client-ci-cd.yml b/.github/workflows/client-ci-cd.yml index 63c63b90..e2a309e2 100644 --- a/.github/workflows/client-ci-cd.yml +++ b/.github/workflows/client-ci-cd.yml @@ -80,5 +80,7 @@ jobs: username: mira key: ${{ secrets.SSH_PRIVATE_KEY }} script: | + cd /home/mira/web30-stop-troublepainter + docker pull ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-nginx:latest docker compose up -d nginx \ No newline at end of file From c50f3063a0e7765e2fe1f8c218b3182c14bd39a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 01:08:45 +0900 Subject: [PATCH 07/33] fix: Resolve missing Docker Compose file issue --- .github/workflows/server-ci-cd.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/server-ci-cd.yml b/.github/workflows/server-ci-cd.yml index baf49e20..ea2e884b 100644 --- a/.github/workflows/server-ci-cd.yml +++ b/.github/workflows/server-ci-cd.yml @@ -74,5 +74,7 @@ jobs: username: mira key: ${{ secrets.SSH_PRIVATE_KEY }} script: | + cd /home/mira/web30-stop-troublepainter + docker pull ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-api:latest docker compose up -d api \ No newline at end of file From 88ed5779d07380b889f46a01c8825aa04eef08d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 01:19:39 +0900 Subject: [PATCH 08/33] chore: Update environment variables setup for Nginx deployment --- .github/workflows/client-ci-cd.yml | 4 ++-- .github/workflows/server-ci-cd.yml | 4 ++-- Dockerfile.nginx | 6 ++++++ docker-compose.yml | 7 +++---- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/client-ci-cd.yml b/.github/workflows/client-ci-cd.yml index e2a309e2..a50b02c9 100644 --- a/.github/workflows/client-ci-cd.yml +++ b/.github/workflows/client-ci-cd.yml @@ -80,7 +80,7 @@ jobs: username: mira key: ${{ secrets.SSH_PRIVATE_KEY }} script: | - cd /home/mira/web30-stop-troublepainter - docker pull ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-nginx:latest + + cd /home/mira/web30-stop-troublepainter docker compose up -d nginx \ No newline at end of file diff --git a/.github/workflows/server-ci-cd.yml b/.github/workflows/server-ci-cd.yml index ea2e884b..3661bb33 100644 --- a/.github/workflows/server-ci-cd.yml +++ b/.github/workflows/server-ci-cd.yml @@ -74,7 +74,7 @@ jobs: username: mira key: ${{ secrets.SSH_PRIVATE_KEY }} script: | - cd /home/mira/web30-stop-troublepainter - docker pull ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-api:latest + + cd /home/mira/web30-stop-troublepainter docker compose up -d api \ No newline at end of file diff --git a/Dockerfile.nginx b/Dockerfile.nginx index 2d93a9bc..2bb71eb1 100644 --- a/Dockerfile.nginx +++ b/Dockerfile.nginx @@ -10,6 +10,12 @@ RUN pnpm install --frozen-lockfile && pnpm build FROM nginx:alpine +ARG VITE_API_URL +ARG VITE_SOCKET_URL + +ENV VITE_API_URL=$VITE_API_URL +ENV VITE_SOCKET_URL=$VITE_SOCKET_URL + COPY nginx.conf /etc/nginx/templates/default.conf.template COPY --from=builder /app/client/dist /usr/share/nginx/html diff --git a/docker-compose.yml b/docker-compose.yml index cf733085..c83ed84d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,11 +18,10 @@ services: build: context: . dockerfile: Dockerfile.nginx + args: + VITE_API_URL: ${VITE_API_URL} + VITE_SOCKET_URL: ${VITE_SOCKET_URL} container_name: troublepainter_nginx - environment: - - NODE_ENV=production - - VITE_API_URL=${VITE_API_URL} - - VITE_SOCKET_URL=${VITE_SOCKET_URL} volumes: - /etc/letsencrypt:/etc/letsencrypt ports: From f5c267570d76b0d3005d29ed7f25c897432c010f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 01:26:55 +0900 Subject: [PATCH 09/33] fix: Ensure environment variables are properly passed during client build --- Dockerfile.nginx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.nginx b/Dockerfile.nginx index 2bb71eb1..cf47f3b1 100644 --- a/Dockerfile.nginx +++ b/Dockerfile.nginx @@ -6,7 +6,7 @@ WORKDIR /app COPY . . -RUN pnpm install --frozen-lockfile && pnpm build +RUN pnpm install --frozen-lockfile && VITE_API_URL=$VITE_API_URL VITE_SOCKET_URL=$VITE_SOCKET_URL pnpm build FROM nginx:alpine From 9049294d468f1de0d1ea141e6b300be59012e79f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 01:46:08 +0900 Subject: [PATCH 10/33] Chore: configure ARG for build-time environment variables --- Dockerfile.nginx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Dockerfile.nginx b/Dockerfile.nginx index cf47f3b1..1658a35f 100644 --- a/Dockerfile.nginx +++ b/Dockerfile.nginx @@ -6,15 +6,12 @@ WORKDIR /app COPY . . -RUN pnpm install --frozen-lockfile && VITE_API_URL=$VITE_API_URL VITE_SOCKET_URL=$VITE_SOCKET_URL pnpm build - -FROM nginx:alpine - ARG VITE_API_URL ARG VITE_SOCKET_URL -ENV VITE_API_URL=$VITE_API_URL -ENV VITE_SOCKET_URL=$VITE_SOCKET_URL +RUN pnpm install --frozen-lockfile && VITE_API_URL=$VITE_API_URL VITE_SOCKET_URL=$VITE_SOCKET_URL pnpm build + +FROM nginx:alpine COPY nginx.conf /etc/nginx/templates/default.conf.template COPY --from=builder /app/client/dist /usr/share/nginx/html From c5068cd8d005ed3b950fbc22711728ad5f09a9f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 01:54:28 +0900 Subject: [PATCH 11/33] fix: Set VITE_API_URL and VITE_SOCKET_URL environment variables in builder and final Nginx stages --- Dockerfile.nginx | 8 +++++++- docker-compose.yml | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Dockerfile.nginx b/Dockerfile.nginx index 1658a35f..722d39ac 100644 --- a/Dockerfile.nginx +++ b/Dockerfile.nginx @@ -9,13 +9,19 @@ COPY . . ARG VITE_API_URL ARG VITE_SOCKET_URL -RUN pnpm install --frozen-lockfile && VITE_API_URL=$VITE_API_URL VITE_SOCKET_URL=$VITE_SOCKET_URL pnpm build +ENV VITE_API_URL=$VITE_API_URL +ENV VITE_SOCKET_URL=$VITE_SOCKET_URL + +RUN pnpm install --frozen-lockfile && pnpm build FROM nginx:alpine COPY nginx.conf /etc/nginx/templates/default.conf.template COPY --from=builder /app/client/dist /usr/share/nginx/html +ENV VITE_API_URL=$VITE_API_URL +ENV VITE_SOCKET_URL=$VITE_SOCKET_URL + EXPOSE 80 443 CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index c83ed84d..7b5d4b4a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,6 +22,9 @@ services: VITE_API_URL: ${VITE_API_URL} VITE_SOCKET_URL: ${VITE_SOCKET_URL} container_name: troublepainter_nginx + environment: + VITE_API_URL: ${VITE_API_URL} + VITE_SOCKET_URL: ${VITE_SOCKET_URL} volumes: - /etc/letsencrypt:/etc/letsencrypt ports: From c776d773a185e9aef28438c13a7e694277e12122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 02:03:22 +0900 Subject: [PATCH 12/33] debug: Add logging to verify ARG values during Docker build --- Dockerfile.nginx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile.nginx b/Dockerfile.nginx index 722d39ac..2433f6d9 100644 --- a/Dockerfile.nginx +++ b/Dockerfile.nginx @@ -9,6 +9,8 @@ COPY . . ARG VITE_API_URL ARG VITE_SOCKET_URL +RUN echo "VITE_API_URL=$VITE_API_URL" && echo "VITE_SOCKET_URL=$VITE_SOCKET_URL" + ENV VITE_API_URL=$VITE_API_URL ENV VITE_SOCKET_URL=$VITE_SOCKET_URL From 07e44cd464dc2629904593446a42ea7e388b8c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 02:08:16 +0900 Subject: [PATCH 13/33] build: use ARG for build-time environment variables in Dockerfile --- .github/workflows/client-ci-cd.yml | 1 - Dockerfile.nginx | 10 +--------- docker-compose.yml | 3 --- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/.github/workflows/client-ci-cd.yml b/.github/workflows/client-ci-cd.yml index a50b02c9..d3110e89 100644 --- a/.github/workflows/client-ci-cd.yml +++ b/.github/workflows/client-ci-cd.yml @@ -81,6 +81,5 @@ jobs: key: ${{ secrets.SSH_PRIVATE_KEY }} script: | docker pull ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-nginx:latest - cd /home/mira/web30-stop-troublepainter docker compose up -d nginx \ No newline at end of file diff --git a/Dockerfile.nginx b/Dockerfile.nginx index 2433f6d9..1658a35f 100644 --- a/Dockerfile.nginx +++ b/Dockerfile.nginx @@ -9,21 +9,13 @@ COPY . . ARG VITE_API_URL ARG VITE_SOCKET_URL -RUN echo "VITE_API_URL=$VITE_API_URL" && echo "VITE_SOCKET_URL=$VITE_SOCKET_URL" - -ENV VITE_API_URL=$VITE_API_URL -ENV VITE_SOCKET_URL=$VITE_SOCKET_URL - -RUN pnpm install --frozen-lockfile && pnpm build +RUN pnpm install --frozen-lockfile && VITE_API_URL=$VITE_API_URL VITE_SOCKET_URL=$VITE_SOCKET_URL pnpm build FROM nginx:alpine COPY nginx.conf /etc/nginx/templates/default.conf.template COPY --from=builder /app/client/dist /usr/share/nginx/html -ENV VITE_API_URL=$VITE_API_URL -ENV VITE_SOCKET_URL=$VITE_SOCKET_URL - EXPOSE 80 443 CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 7b5d4b4a..c83ed84d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,9 +22,6 @@ services: VITE_API_URL: ${VITE_API_URL} VITE_SOCKET_URL: ${VITE_SOCKET_URL} container_name: troublepainter_nginx - environment: - VITE_API_URL: ${VITE_API_URL} - VITE_SOCKET_URL: ${VITE_SOCKET_URL} volumes: - /etc/letsencrypt:/etc/letsencrypt ports: From 5639ca022fb57060bf2cf086e804ed499819c567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 02:22:17 +0900 Subject: [PATCH 14/33] fix: Create .env file with VITE_API_URL and VITE_SOCKET_URL before building Vite client --- .github/workflows/client-ci-cd.yml | 6 ++++++ Dockerfile.nginx | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/client-ci-cd.yml b/.github/workflows/client-ci-cd.yml index d3110e89..5bf39420 100644 --- a/.github/workflows/client-ci-cd.yml +++ b/.github/workflows/client-ci-cd.yml @@ -39,6 +39,12 @@ jobs: working-directory: ./client run: pnpm test | true + - name: Create .env file + working-directory: ./client + run: | + echo "VITE_API_URL=${{ secrets.VITE_API_URL }}" >> .env + echo "VITE_SOCKET_URL=${{ secrets.VITE_SOCKET_URL }}" >> .env + - name: Build Client working-directory: ./client env: diff --git a/Dockerfile.nginx b/Dockerfile.nginx index 1658a35f..674545d0 100644 --- a/Dockerfile.nginx +++ b/Dockerfile.nginx @@ -9,7 +9,7 @@ COPY . . ARG VITE_API_URL ARG VITE_SOCKET_URL -RUN pnpm install --frozen-lockfile && VITE_API_URL=$VITE_API_URL VITE_SOCKET_URL=$VITE_SOCKET_URL pnpm build +RUN pnpm install --frozen-lockfile && pnpm build FROM nginx:alpine From c7cbf5d456c8b4db66578cbc1a241dd7ac7ae00c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 10:08:47 +0900 Subject: [PATCH 15/33] chore: Add environment variable debug logging to Dockerfile --- .github/workflows/client-ci-cd.yml | 13 ------------- Dockerfile.nginx | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/.github/workflows/client-ci-cd.yml b/.github/workflows/client-ci-cd.yml index 5bf39420..746da41e 100644 --- a/.github/workflows/client-ci-cd.yml +++ b/.github/workflows/client-ci-cd.yml @@ -39,19 +39,6 @@ jobs: working-directory: ./client run: pnpm test | true - - name: Create .env file - working-directory: ./client - run: | - echo "VITE_API_URL=${{ secrets.VITE_API_URL }}" >> .env - echo "VITE_SOCKET_URL=${{ secrets.VITE_SOCKET_URL }}" >> .env - - - name: Build Client - working-directory: ./client - env: - VITE_API_URL: ${{secrets.VITE_API_URL}} - VITE_SOCKET_URL: ${{secrets.VITE_SOCKET_URL}} - run: pnpm build - docker-deploy: needs: ci runs-on: ubuntu-latest diff --git a/Dockerfile.nginx b/Dockerfile.nginx index 674545d0..52899fa0 100644 --- a/Dockerfile.nginx +++ b/Dockerfile.nginx @@ -9,7 +9,7 @@ COPY . . ARG VITE_API_URL ARG VITE_SOCKET_URL -RUN pnpm install --frozen-lockfile && pnpm build +RUN echo "VITE_API_URL = $VITE_API_URL" && echo "VITE_SOCKET_URL = $VITE_SOCKET_URL" && echo "VITE_API_URL=$VITE_API_URL" >> client/.env && echo "VITE_SOCKET_URL=$VITE_SOCKET_URL" >> client/.env && cat client/.env && pnpm install --frozen-lockfile && pnpm build FROM nginx:alpine From 389b55653cf1ecdab2f49bfef7138c2573266066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 10:18:57 +0900 Subject: [PATCH 16/33] chore: Modify environment variable debug logging to Dockerfile --- Dockerfile.nginx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.nginx b/Dockerfile.nginx index 52899fa0..f29b0c40 100644 --- a/Dockerfile.nginx +++ b/Dockerfile.nginx @@ -9,7 +9,7 @@ COPY . . ARG VITE_API_URL ARG VITE_SOCKET_URL -RUN echo "VITE_API_URL = $VITE_API_URL" && echo "VITE_SOCKET_URL = $VITE_SOCKET_URL" && echo "VITE_API_URL=$VITE_API_URL" >> client/.env && echo "VITE_SOCKET_URL=$VITE_SOCKET_URL" >> client/.env && cat client/.env && pnpm install --frozen-lockfile && pnpm build +RUN if [ -z "$VITE_API_URL" ]; then echo "VITE_API_URL is empty" && exit 1; fi && if [ -z "$VITE_SOCKET_URL" ]; then echo "VITE_SOCKET_URL is empty" && exit 1; fi && echo "VITE_API_URL=$VITE_API_URL" >> client/.env && echo "VITE_SOCKET_URL=$VITE_SOCKET_URL" >> client/.env && pnpm install --frozen-lockfile && pnpm build FROM nginx:alpine From 31170b1192eec2f0bd80c782e2054c6b59edb497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 10:21:52 +0900 Subject: [PATCH 17/33] refactor: Apply environment variable validation --- .github/workflows/client-ci-cd.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/client-ci-cd.yml b/.github/workflows/client-ci-cd.yml index 746da41e..683f205f 100644 --- a/.github/workflows/client-ci-cd.yml +++ b/.github/workflows/client-ci-cd.yml @@ -74,5 +74,6 @@ jobs: key: ${{ secrets.SSH_PRIVATE_KEY }} script: | docker pull ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-nginx:latest + cd /home/mira/web30-stop-troublepainter docker compose up -d nginx \ No newline at end of file From b7cb0fa63be2c1b7eaa3143b93ec6154aaf2ad71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 10:35:21 +0900 Subject: [PATCH 18/33] chore: Add environment variable debug logging --- client/src/api/api.config.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/api/api.config.ts b/client/src/api/api.config.ts index 92ec8b04..7a989b8b 100644 --- a/client/src/api/api.config.ts +++ b/client/src/api/api.config.ts @@ -92,6 +92,8 @@ export class ApiError extends Error { * }; */ export async function fetchApi(endpoint: string, options?: RequestInit): Promise { + console.log(import.meta.env.VITE_API_URL); + const response = await fetch(`${API_CONFIG.BASE_URL}${endpoint}`, { ...API_CONFIG.OPTIONS, ...options, From b61bcf5d7ef44ff562a1d5bb931f50e1da8e7345 Mon Sep 17 00:00:00 2001 From: Taeyeon Yoon Date: Thu, 28 Nov 2024 11:33:18 +0900 Subject: [PATCH 19/33] feat: Enhance navigation(refresh, popstate, URL etc.) handling and accessibility in game layout (#146) * feat: Implement usePageLeaveConfirm hook to prevent unintended page refreshes and navigation - Add page leave confirmation with useBeforeUnload and useBlocker - Handle ESC key prevention - Support custom messages and blocking conditions * feat: Apply page leave prevention to GameLayout - Add usePageLeaveConfirm hook to GameLayout - Show different warning messages based on game status - Block page refresh and navigation during active game sessions * feat: Enhance round start handling in useGameSocket.tsx - Updated drawingGroupRoundStarted and guesserRoundStarted functions to use `replace: true` in navigation, removing the waiting room from history. - This prevents users from returning to the waiting room using the back button when transitioning to the game, providing a better user experience. * feat: Add logo navigation to main page with replace option - Add clickable logo button to navigate to main page - Include replace:true to maintain navigation stack consistency - Apply hover and focus effects for better UX Adding main page navigation through logo since the lobby-to-game navigation uses replace:true, which removes the main page from history stack. This ensures users can always return to the main page via logo click. * refactor: Migrate navigation guard to component architecture BREAKING CHANGE: Removed usePageLeaveConfirm hook - Replace hook with BrowserNavigationGuard component - Move guard logic to layout level - Implement in routes.tsx using layout wrapper Improves maintainability, reduces prop drilling, and simplifies integration. * feat: Implement navigation modal and store for popstate and header click handler - Globalizing modal state to prevent modal state duplication - Add NavigationModal and BrowserNavigationGuard to GameLayout for consistency * feat: Implement GameHeader component * feat: Apply modalActions of NavigationModal to BrowserNavigationGuard - Delete window.confirm logic * feat: Enhance Modal accessibility with auto-focus functionality - Import useEffect and useRef hooks from React - Add useRef hook to create a reference to the modal container - Implement useEffect hook to automatically focus on the modal when it opens - Move ref from inner div to outer div for better focus management - Adjust component structure to support new focus behavior * feat: Enhance NavigationModal accessibility and keyboard navigation - Add keyboard event handling for Enter and Escape keys - Implement useCallback hook for optimized event handling - Add aria-label attributes to improve screen reader compatibility - Include role and aria-label for button group - Add descriptive aria-labels to individual buttons - Improve modal accessibility with aria-label attribute * style: Add scroll css to index.css --- .../src/components/modal/NavigationModal.tsx | 66 +++++++++++ client/src/components/ui/Modal.tsx | 10 +- client/src/hooks/socket/useGameSocket.ts | 4 +- client/src/index.css | 48 ++++++++ client/src/layouts/BrowserNavigationGuard.tsx | 56 +++++++++ client/src/layouts/GameHeader.tsx | 19 +++ client/src/layouts/GameLayout.tsx | 112 +++++++++--------- client/src/stores/navigationModal.store.ts | 17 +++ 8 files changed, 275 insertions(+), 57 deletions(-) create mode 100644 client/src/components/modal/NavigationModal.tsx create mode 100644 client/src/layouts/BrowserNavigationGuard.tsx create mode 100644 client/src/layouts/GameHeader.tsx create mode 100644 client/src/stores/navigationModal.store.ts diff --git a/client/src/components/modal/NavigationModal.tsx b/client/src/components/modal/NavigationModal.tsx new file mode 100644 index 00000000..aecfa94b --- /dev/null +++ b/client/src/components/modal/NavigationModal.tsx @@ -0,0 +1,66 @@ +import { KeyboardEvent, useCallback } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { Button } from '@/components/ui/Button'; +import { Modal } from '@/components/ui/Modal'; +import { useNavigationModalStore } from '@/stores/navigationModal.store'; + +export const NavigationModal = () => { + const navigate = useNavigate(); + const { isOpen, actions } = useNavigationModalStore(); + + const handleConfirmExit = () => { + actions.closeModal(); + navigate('/', { replace: true }); + }; + + const handleKeyDown = useCallback( + (e: KeyboardEvent) => { + switch (e.key) { + case 'Enter': + handleConfirmExit(); + break; + case 'Escape': + actions.closeModal(); + break; + } + }, + [actions, navigate], + ); + + return ( + +
+

+ 정말 게임을 나가실거에요...?? +
+ 퇴장하면 다시 돌아오기 힘들어요! 🥺💔 +

+
+ + +
+
+
+ ); +}; diff --git a/client/src/components/ui/Modal.tsx b/client/src/components/ui/Modal.tsx index 943ad734..26342631 100644 --- a/client/src/components/ui/Modal.tsx +++ b/client/src/components/ui/Modal.tsx @@ -1,4 +1,4 @@ -import { HTMLAttributes, KeyboardEvent, PropsWithChildren } from 'react'; +import { HTMLAttributes, KeyboardEvent, PropsWithChildren, useEffect, useRef } from 'react'; import ReactDOM from 'react-dom'; // Import ReactDOM explicitly import { cn } from '@/utils/cn'; @@ -11,11 +11,19 @@ export interface ModalProps extends PropsWithChildren { const modalRoot = document.getElementById('modal-root'); + const modalRef = useRef(null); if (!modalRoot) return null; + useEffect(() => { + if (isModalOpened && modalRef.current) { + modalRef.current.focus(); + } + }, [isModalOpened]); + return ReactDOM.createPortal(
{ if (word) gameActions.updateCurrentWord(word); gameActions.updateTimer(TimerType.DRAWING, drawTime); gameActions.updateRoomStatus(RoomStatus.DRAWING); - navigate(`/game/${roomId}`); + navigate(`/game/${roomId}`, { replace: true }); // replace: true로 설정, 히스토리에서 대기방 제거 }, guesserRoundStarted: (response: RoundStartResponse) => { @@ -164,7 +164,7 @@ export const useGameSocket = () => { guessers?.forEach((playerId) => gameActions.updatePlayerRole(playerId, PlayerRole.GUESSER)); gameActions.updateTimer(TimerType.DRAWING, drawTime); gameActions.updateRoomStatus(RoomStatus.DRAWING); - navigate(`/game/${roomId}`); + navigate(`/game/${roomId}`, { replace: true }); }, timerSync: (response: TimerSyncResponse) => { diff --git a/client/src/index.css b/client/src/index.css index b5c61c95..07fbb39e 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -1,3 +1,51 @@ @tailwind base; @tailwind components; @tailwind utilities; + +@layer components { + /* 스크롤바 hide 기능 */ + /* Hide scrollbar for Chrome, Safari and Opera */ + .scrollbar-hide::-webkit-scrollbar { + display: none; + } + /* Hide scrollbar for IE, Edge and Firefox */ + .scrollbar-hide { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + } + + .scrollbar-custom { + scrollbar-width: thin; /* Firefox */ + } + + /* ===== Scrollbar CSS ===== */ + /* Firefox */ + * { + scrollbar-width: auto; + scrollbar-color: rgb(67, 79, 115) rgba(178, 199, 222, 0.5); + } + /* Chrome, Safari and Opera etc. */ + *::-webkit-scrollbar { + width: 6px; + /* height: 6px; */ + } + *::-webkit-scrollbar-track { + background-color: rgba(178, 199, 222, 0.5); /* eastbay-500 with opacity */ + border-radius: 9999px; + } + *::-webkit-scrollbar-thumb { + background-color: rgb(67, 79, 115); /* eastbay-900 */ + border-radius: 9999px; + } + *::-webkit-scrollbar-thumb:hover { + background-color: rgb(84, 103, 161); /* eastbay-700 */ + } + + /* 가로 스크롤바 변형 */ + .scrollbar-custom.horizontal::-webkit-scrollbar-track { + background-color: rgba(178, 199, 222, 0.5); + } + .scrollbar-custom.horizontal::-webkit-scrollbar-thumb { + background-color: rgb(67, 79, 115); + } +} diff --git a/client/src/layouts/BrowserNavigationGuard.tsx b/client/src/layouts/BrowserNavigationGuard.tsx new file mode 100644 index 00000000..61669d5c --- /dev/null +++ b/client/src/layouts/BrowserNavigationGuard.tsx @@ -0,0 +1,56 @@ +import { useEffect } from 'react'; +import { useLocation, useNavigate } from 'react-router-dom'; +import { useNavigationModalStore } from '@/stores/navigationModal.store'; + +const BrowserNavigationGuard = () => { + const navigate = useNavigate(); + const location = useLocation(); + const { actions: modalActions } = useNavigationModalStore(); + + useEffect(() => { + // 새로고침, beforeunload 이벤트 핸들러 + const handleBeforeUnload = (e: BeforeUnloadEvent) => { + // 브라우저 기본 경고 메시지 표시 + e.preventDefault(); + e.returnValue = ''; // 레거시 브라우저 지원 + + // 새로고침 시 메인으로 이동하도록 로컬스토리지에 플래그 저장 + localStorage.setItem('shouldRedirect', 'true'); + + // 사용자 정의 메시지 반환 (일부 브라우저에서는 무시될 수 있음) + return '게임을 종료하시겠습니까? 현재 진행 상태가 저장되지 않을 수 있습니다.'; + }; + + // popstate 이벤트 핸들러 (브라우저 뒤로가기/앞으로가기) + const handlePopState = (e: PopStateEvent) => { + e.preventDefault(); // 기본 동작 중단 + modalActions.openModal(); + + // 취소 시 현재 URL 유지를 위해 history stack에 다시 추가하도록 조작 + window.history.pushState(null, '', location.pathname); + }; + + // 초기 진입 시 history stack에 현재 상태 추가 + window.history.pushState(null, '', location.pathname); + + // 이벤트 리스너 등록 + window.addEventListener('beforeunload', handleBeforeUnload); + window.addEventListener('popstate', handlePopState); + + // 새로고침 후 리다이렉트 체크 + const shouldRedirect = localStorage.getItem('shouldRedirect'); + if (shouldRedirect === 'true' && location.pathname !== '/') { + navigate('/', { replace: true }); + localStorage.removeItem('shouldRedirect'); + } + + return () => { + window.removeEventListener('beforeunload', handleBeforeUnload); + window.removeEventListener('popstate', handlePopState); + }; + }, [navigate, location.pathname]); + + return null; +}; + +export default BrowserNavigationGuard; diff --git a/client/src/layouts/GameHeader.tsx b/client/src/layouts/GameHeader.tsx new file mode 100644 index 00000000..58926c02 --- /dev/null +++ b/client/src/layouts/GameHeader.tsx @@ -0,0 +1,19 @@ +import { Logo } from '@/components/ui/Logo'; +import { useNavigationModalStore } from '@/stores/navigationModal.store'; + +const GameHeader = () => { + const { actions } = useNavigationModalStore(); + + return ( +
+ +
+ ); +}; + +export default GameHeader; diff --git a/client/src/layouts/GameLayout.tsx b/client/src/layouts/GameLayout.tsx index e8f263bf..05eba4c8 100644 --- a/client/src/layouts/GameLayout.tsx +++ b/client/src/layouts/GameLayout.tsx @@ -1,8 +1,10 @@ import { Outlet } from 'react-router-dom'; import { Chat } from '@/components/chat/Chat'; +import { NavigationModal } from '@/components/modal/NavigationModal'; import { PlayerCardList } from '@/components/player/PlayerCardList'; -import { Logo } from '@/components/ui/Logo'; import { useGameSocket } from '@/hooks/socket/useGameSocket'; +import BrowserNavigationGuard from '@/layouts/BrowserNavigationGuard'; +import GameHeader from '@/layouts/GameHeader'; import { cn } from '@/utils/cn'; const GameLayout = () => { @@ -21,65 +23,67 @@ const GameLayout = () => { } return ( -
- {/* 상단 헤더 */} -
- -
+ <> + + +
+ {/* 상단 헤더 */} + -
-
- {/* 플레이어 정보 영역 */} - + {/* 플레이어 정보 영역 */} + - {/* 중앙 영역 */} -
- -
+ {/* 중앙 영역 */} +
+ +
- {/* 채팅 영역 */} - -
-
-
+ {/* 채팅 영역 */} + +
+ +
+ ); }; diff --git a/client/src/stores/navigationModal.store.ts b/client/src/stores/navigationModal.store.ts new file mode 100644 index 00000000..89dcd444 --- /dev/null +++ b/client/src/stores/navigationModal.store.ts @@ -0,0 +1,17 @@ +import { create } from 'zustand'; + +interface NavigationModalStore { + isOpen: boolean; + actions: { + openModal: () => void; + closeModal: () => void; + }; +} + +export const useNavigationModalStore = create((set) => ({ + isOpen: false, + actions: { + openModal: () => set({ isOpen: true }), + closeModal: () => set({ isOpen: false }), + }, +})); From cf7062db9c566c188aacd3e193ab701617d88812 Mon Sep 17 00:00:00 2001 From: Taeyeon Yoon Date: Thu, 28 Nov 2024 11:42:53 +0900 Subject: [PATCH 20/33] style: Add scroll css to index.css (#149) From cc49a6c45a5e85bfaf77d3fc28d1f2c30d04a18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 12:02:16 +0900 Subject: [PATCH 21/33] refactor: Change docker build strategy to Docker Hub --- .github/workflows/client-ci-cd.yml | 6 +++--- .github/workflows/server-ci-cd.yml | 7 +++---- Dockerfile.nestjs => Dockerfile.api | 0 Dockerfile.nginx | 8 +++++++- docker-compose.yml | 11 ++--------- 5 files changed, 15 insertions(+), 17 deletions(-) rename Dockerfile.nestjs => Dockerfile.api (100%) diff --git a/.github/workflows/client-ci-cd.yml b/.github/workflows/client-ci-cd.yml index 683f205f..44fdd5c0 100644 --- a/.github/workflows/client-ci-cd.yml +++ b/.github/workflows/client-ci-cd.yml @@ -73,7 +73,7 @@ jobs: username: mira key: ${{ secrets.SSH_PRIVATE_KEY }} script: | - docker pull ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-nginx:latest - cd /home/mira/web30-stop-troublepainter - docker compose up -d nginx \ No newline at end of file + + DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }} docker compose pull nginx + DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }} docker compose up -d nginx \ No newline at end of file diff --git a/.github/workflows/server-ci-cd.yml b/.github/workflows/server-ci-cd.yml index 3661bb33..d6e6af0a 100644 --- a/.github/workflows/server-ci-cd.yml +++ b/.github/workflows/server-ci-cd.yml @@ -58,7 +58,7 @@ jobs: uses: docker/build-push-action@v5 with: context: . - file: ./Dockerfile.nestjs + file: ./ push: true tags: ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-api:latest build-args: | @@ -74,7 +74,6 @@ jobs: username: mira key: ${{ secrets.SSH_PRIVATE_KEY }} script: | - docker pull ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-api:latest - cd /home/mira/web30-stop-troublepainter - docker compose up -d api \ No newline at end of file + DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }} docker compose pull api + DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }} docker compose up -d api \ No newline at end of file diff --git a/Dockerfile.nestjs b/Dockerfile.api similarity index 100% rename from Dockerfile.nestjs rename to Dockerfile.api diff --git a/Dockerfile.nginx b/Dockerfile.nginx index f29b0c40..55efa50a 100644 --- a/Dockerfile.nginx +++ b/Dockerfile.nginx @@ -4,12 +4,18 @@ RUN corepack enable && corepack prepare pnpm@9.12.3 --activate WORKDIR /app +COPY pnpm-workspace.yaml package.json pnpm-lock.yaml ./ +COPY core/package.json ./core/ +COPY client/package.json ./client/ + +RUN pnpm install --frozen-lockfile + COPY . . ARG VITE_API_URL ARG VITE_SOCKET_URL -RUN if [ -z "$VITE_API_URL" ]; then echo "VITE_API_URL is empty" && exit 1; fi && if [ -z "$VITE_SOCKET_URL" ]; then echo "VITE_SOCKET_URL is empty" && exit 1; fi && echo "VITE_API_URL=$VITE_API_URL" >> client/.env && echo "VITE_SOCKET_URL=$VITE_SOCKET_URL" >> client/.env && pnpm install --frozen-lockfile && pnpm build +RUN echo "VITE_API_URL=$VITE_API_URL" > client/.env && echo "VITE_SOCKET_URL=$VITE_SOCKET_URL" >> client/.env && pnpm --filter @troublepainter/core build && pnpm --filter client build FROM nginx:alpine diff --git a/docker-compose.yml b/docker-compose.yml index c83ed84d..bc23d238 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,6 @@ services: api: - build: - context: . - dockerfile: Dockerfile.nestjs + image: ${DOCKERHUB_USERNAME}/troublepainter-api:latest container_name: troublepainter_api environment: - NODE_ENV=production @@ -15,12 +13,7 @@ services: restart: unless-stopped nginx: - build: - context: . - dockerfile: Dockerfile.nginx - args: - VITE_API_URL: ${VITE_API_URL} - VITE_SOCKET_URL: ${VITE_SOCKET_URL} + image: ${DOCKERHUB_USERNAME}/troublepainter-nginx:latest container_name: troublepainter_nginx volumes: - /etc/letsencrypt:/etc/letsencrypt From e0aa3d9b833ab04e47c25c6cdb1f697c1818fa5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 12:07:02 +0900 Subject: [PATCH 22/33] fix: Correct Dockerfile path in server CI/CD workflow --- .github/workflows/server-ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/server-ci-cd.yml b/.github/workflows/server-ci-cd.yml index d6e6af0a..9097365f 100644 --- a/.github/workflows/server-ci-cd.yml +++ b/.github/workflows/server-ci-cd.yml @@ -58,7 +58,7 @@ jobs: uses: docker/build-push-action@v5 with: context: . - file: ./ + file: ./Dockerfile.api push: true tags: ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-api:latest build-args: | From 67d9c6192bda1448d39f6679e4e5472ef183e638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 12:24:39 +0900 Subject: [PATCH 23/33] fix: add DOCKERHUB_USERNAME env variable for docker compose --- .github/workflows/client-ci-cd.yml | 6 +++--- .github/workflows/server-ci-cd.yml | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/client-ci-cd.yml b/.github/workflows/client-ci-cd.yml index 44fdd5c0..1751f96b 100644 --- a/.github/workflows/client-ci-cd.yml +++ b/.github/workflows/client-ci-cd.yml @@ -74,6 +74,6 @@ jobs: key: ${{ secrets.SSH_PRIVATE_KEY }} script: | cd /home/mira/web30-stop-troublepainter - - DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }} docker compose pull nginx - DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }} docker compose up -d nginx \ No newline at end of file + export DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }} + docker compose pull nginx + docker compose up -d nginx \ No newline at end of file diff --git a/.github/workflows/server-ci-cd.yml b/.github/workflows/server-ci-cd.yml index 9097365f..eebc1f39 100644 --- a/.github/workflows/server-ci-cd.yml +++ b/.github/workflows/server-ci-cd.yml @@ -75,5 +75,6 @@ jobs: key: ${{ secrets.SSH_PRIVATE_KEY }} script: | cd /home/mira/web30-stop-troublepainter - DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }} docker compose pull api - DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }} docker compose up -d api \ No newline at end of file + export DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }} + docker compose pull api + docker compose up -d api \ No newline at end of file From af7f893e26f364c5347480ebca7213e4d02fac76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 12:36:01 +0900 Subject: [PATCH 24/33] fix: Update command to directly pull images --- .github/workflows/client-ci-cd.yml | 2 +- .github/workflows/server-ci-cd.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/client-ci-cd.yml b/.github/workflows/client-ci-cd.yml index 1751f96b..f097dbec 100644 --- a/.github/workflows/client-ci-cd.yml +++ b/.github/workflows/client-ci-cd.yml @@ -75,5 +75,5 @@ jobs: script: | cd /home/mira/web30-stop-troublepainter export DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }} - docker compose pull nginx + docker pull ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-nginx:latest docker compose up -d nginx \ No newline at end of file diff --git a/.github/workflows/server-ci-cd.yml b/.github/workflows/server-ci-cd.yml index eebc1f39..a69b65b7 100644 --- a/.github/workflows/server-ci-cd.yml +++ b/.github/workflows/server-ci-cd.yml @@ -76,5 +76,5 @@ jobs: script: | cd /home/mira/web30-stop-troublepainter export DOCKERHUB_USERNAME=${{ secrets.DOCKERHUB_USERNAME }} - docker compose pull api + docker pull ${{ secrets.DOCKERHUB_USERNAME }}/troublepainter-api:latest docker compose up -d api \ No newline at end of file From 02b1a4cb1b117697f4eb53bfef134f8fee9c66be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 13:16:31 +0900 Subject: [PATCH 25/33] fix: Update Nginx configuration to prevent duplicate API paths --- .github/workflows/client-ci-cd.yml | 1 + nginx.conf | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/client-ci-cd.yml b/.github/workflows/client-ci-cd.yml index f097dbec..c1e9fb86 100644 --- a/.github/workflows/client-ci-cd.yml +++ b/.github/workflows/client-ci-cd.yml @@ -7,6 +7,7 @@ on: - 'client/**' - 'core/**' - '.github/workflows/client-ci-cd.yml' + - 'nginx.conf' jobs: ci: diff --git a/nginx.conf b/nginx.conf index 37ea4d11..d38140b7 100644 --- a/nginx.conf +++ b/nginx.conf @@ -20,7 +20,7 @@ server { } location /api { - proxy_pass http://api:3000; + proxy_pass http://api:3000/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -29,7 +29,7 @@ server { } location /socket.io { - proxy_pass http://api:3000; + proxy_pass http://api:3000/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; From 5bc723c695197f4cc1bf5b52ca62c3400bacd49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 13:38:27 +0900 Subject: [PATCH 26/33] fix: Resolve API request path duplication issue in Nginx and client setup --- nginx.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nginx.conf b/nginx.conf index d38140b7..d2962d63 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,7 +1,7 @@ server { listen 80; server_name www.troublepainter.site; - return 301 https://$server_name$request_uri; + return 301 https://www.troublepainter.site$request_uri; } server { listen 443 ssl; @@ -20,7 +20,7 @@ server { } location /api { - proxy_pass http://api:3000/; + proxy_pass http://api:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; @@ -29,7 +29,7 @@ server { } location /socket.io { - proxy_pass http://api:3000/; + proxy_pass http://api:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; From 60de6f1ac708706da8fb83ee78b6de8ba6921d62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 13:51:16 +0900 Subject: [PATCH 27/33] feat: Add debugging code to log API request URL --- client/src/api/api.config.ts | 2 +- nginx.conf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/api/api.config.ts b/client/src/api/api.config.ts index 7a989b8b..23d36593 100644 --- a/client/src/api/api.config.ts +++ b/client/src/api/api.config.ts @@ -92,7 +92,7 @@ export class ApiError extends Error { * }; */ export async function fetchApi(endpoint: string, options?: RequestInit): Promise { - console.log(import.meta.env.VITE_API_URL); + console.log(`${API_CONFIG.BASE_URL}${endpoint}`); const response = await fetch(`${API_CONFIG.BASE_URL}${endpoint}`, { ...API_CONFIG.OPTIONS, diff --git a/nginx.conf b/nginx.conf index d2962d63..37ea4d11 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,7 +1,7 @@ server { listen 80; server_name www.troublepainter.site; - return 301 https://www.troublepainter.site$request_uri; + return 301 https://$server_name$request_uri; } server { listen 443 ssl; From b59718766ed50639d7837cef9be458b8b77fe3ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 14:02:05 +0900 Subject: [PATCH 28/33] refactor: Fix duplicate URL issue in Nginx proxy configuration --- client/src/api/api.config.ts | 2 +- nginx.conf | 4 ++-- server/src/main.ts | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/client/src/api/api.config.ts b/client/src/api/api.config.ts index 23d36593..35d43695 100644 --- a/client/src/api/api.config.ts +++ b/client/src/api/api.config.ts @@ -6,7 +6,7 @@ export const API_CONFIG = { BASE_URL, ENDPOINTS: { GAME: { - CREATE_ROOM: '/api/game/rooms', + CREATE_ROOM: '/game/rooms', }, }, OPTIONS: { diff --git a/nginx.conf b/nginx.conf index 37ea4d11..e1094b71 100644 --- a/nginx.conf +++ b/nginx.conf @@ -19,8 +19,8 @@ server { try_files $uri $uri/ /index.html; } - location /api { - proxy_pass http://api:3000; + location /api/ { + proxy_pass http://api:3000/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; diff --git a/server/src/main.ts b/server/src/main.ts index 95c970b3..554e1873 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -5,8 +5,6 @@ import { IoAdapter } from '@nestjs/platform-socket.io'; async function bootstrap() { const app = await NestFactory.create(AppModule); - app.setGlobalPrefix('api'); - app.enableCors({ origin: '*', methods: '*', From 0617ffbf66498421ea1a2cdd4f2e2bd9c821b9fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 14:14:19 +0900 Subject: [PATCH 29/33] refactor: Fix duplicate URL issue in Nginx proxy configuration --- client/src/api/api.config.ts | 4 ++-- nginx.conf | 4 ++-- server/src/main.ts | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/client/src/api/api.config.ts b/client/src/api/api.config.ts index 35d43695..b9577211 100644 --- a/client/src/api/api.config.ts +++ b/client/src/api/api.config.ts @@ -6,7 +6,7 @@ export const API_CONFIG = { BASE_URL, ENDPOINTS: { GAME: { - CREATE_ROOM: '/game/rooms', + CREATE_ROOM: '/api/game/rooms', }, }, OPTIONS: { @@ -94,7 +94,7 @@ export class ApiError extends Error { export async function fetchApi(endpoint: string, options?: RequestInit): Promise { console.log(`${API_CONFIG.BASE_URL}${endpoint}`); - const response = await fetch(`${API_CONFIG.BASE_URL}${endpoint}`, { + const response = await fetch(`${endpoint}`, { ...API_CONFIG.OPTIONS, ...options, headers: { diff --git a/nginx.conf b/nginx.conf index e1094b71..37ea4d11 100644 --- a/nginx.conf +++ b/nginx.conf @@ -19,8 +19,8 @@ server { try_files $uri $uri/ /index.html; } - location /api/ { - proxy_pass http://api:3000/; + location /api { + proxy_pass http://api:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; diff --git a/server/src/main.ts b/server/src/main.ts index 554e1873..95c970b3 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -5,6 +5,8 @@ import { IoAdapter } from '@nestjs/platform-socket.io'; async function bootstrap() { const app = await NestFactory.create(AppModule); + app.setGlobalPrefix('api'); + app.enableCors({ origin: '*', methods: '*', From 6797c164cb8a4bc7a8c2a6687a54ca0d7192d4d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 14:22:32 +0900 Subject: [PATCH 30/33] refactor: Fix duplicate URL issue in Nginx proxy configuration --- server/src/game/game.controller.ts | 2 +- server/src/main.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/server/src/game/game.controller.ts b/server/src/game/game.controller.ts index 80dd8b2f..6c3a604a 100644 --- a/server/src/game/game.controller.ts +++ b/server/src/game/game.controller.ts @@ -1,7 +1,7 @@ import { Controller, Post } from '@nestjs/common'; import { GameService } from './game.service'; -@Controller('game') +@Controller('/api/game') export class GameController { constructor(private readonly gameService: GameService) {} diff --git a/server/src/main.ts b/server/src/main.ts index 95c970b3..554e1873 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -5,8 +5,6 @@ import { IoAdapter } from '@nestjs/platform-socket.io'; async function bootstrap() { const app = await NestFactory.create(AppModule); - app.setGlobalPrefix('api'); - app.enableCors({ origin: '*', methods: '*', From 158a2dc16381519f34b799ed473ccbdf9efc4495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 14:31:10 +0900 Subject: [PATCH 31/33] refactor: Fix duplicate URL issue in Nginx proxy configuration --- server/src/game/game.controller.ts | 2 +- server/src/main.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/server/src/game/game.controller.ts b/server/src/game/game.controller.ts index 6c3a604a..80dd8b2f 100644 --- a/server/src/game/game.controller.ts +++ b/server/src/game/game.controller.ts @@ -1,7 +1,7 @@ import { Controller, Post } from '@nestjs/common'; import { GameService } from './game.service'; -@Controller('/api/game') +@Controller('game') export class GameController { constructor(private readonly gameService: GameService) {} diff --git a/server/src/main.ts b/server/src/main.ts index 554e1873..95c970b3 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -5,6 +5,8 @@ import { IoAdapter } from '@nestjs/platform-socket.io'; async function bootstrap() { const app = await NestFactory.create(AppModule); + app.setGlobalPrefix('api'); + app.enableCors({ origin: '*', methods: '*', From d64e97eea92c1e1f2e3d7b14959497056bf32637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 14:47:00 +0900 Subject: [PATCH 32/33] refactor: Fix socket URL issue in Nginx proxy configuration --- client/src/api/api.config.ts | 2 -- client/src/stores/socket/socket.config.ts | 1 + nginx.conf | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/client/src/api/api.config.ts b/client/src/api/api.config.ts index b9577211..f5eeeb2f 100644 --- a/client/src/api/api.config.ts +++ b/client/src/api/api.config.ts @@ -92,8 +92,6 @@ export class ApiError extends Error { * }; */ export async function fetchApi(endpoint: string, options?: RequestInit): Promise { - console.log(`${API_CONFIG.BASE_URL}${endpoint}`); - const response = await fetch(`${endpoint}`, { ...API_CONFIG.OPTIONS, ...options, diff --git a/client/src/stores/socket/socket.config.ts b/client/src/stores/socket/socket.config.ts index 87b5ef3e..d44257f9 100644 --- a/client/src/stores/socket/socket.config.ts +++ b/client/src/stores/socket/socket.config.ts @@ -114,6 +114,7 @@ type SocketCreator = (auth?: SocketAuth) => T; */ const createSocket = (namespace: SocketNamespace, auth?: SocketAuth): T => { const options = auth ? { ...SOCKET_CONFIG.BASE_OPTIONS, auth } : SOCKET_CONFIG.BASE_OPTIONS; + console.log(`${SOCKET_CONFIG.URL}${SOCKET_CONFIG.PATHS[namespace]}`); return io(`${SOCKET_CONFIG.URL}${SOCKET_CONFIG.PATHS[namespace]}`, options) as T; }; diff --git a/nginx.conf b/nginx.conf index 37ea4d11..d70000a6 100644 --- a/nginx.conf +++ b/nginx.conf @@ -29,7 +29,7 @@ server { } location /socket.io { - proxy_pass http://api:3000; + proxy_pass http://api:3000/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; From 931952cac242a2662962418edaa3f91a91408d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=AF=B8=EB=9D=BC?= Date: Thu, 28 Nov 2024 14:51:58 +0900 Subject: [PATCH 33/33] refactor: Fix socket URL issue in Nginx proxy configuration --- client/src/stores/socket/socket.config.ts | 2 +- nginx.conf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/stores/socket/socket.config.ts b/client/src/stores/socket/socket.config.ts index d44257f9..4dd445eb 100644 --- a/client/src/stores/socket/socket.config.ts +++ b/client/src/stores/socket/socket.config.ts @@ -86,7 +86,7 @@ export const SOCKET_CONFIG = { /** 네임스페이스별 경로 */ PATHS: { [SocketNamespace.GAME]: '/socket.io/game', - [SocketNamespace.DRAWING]: 'socket.io/drawing', + [SocketNamespace.DRAWING]: '/socket.io/drawing', [SocketNamespace.CHAT]: '/socket.io/chat', }, } as const; diff --git a/nginx.conf b/nginx.conf index d70000a6..37ea4d11 100644 --- a/nginx.conf +++ b/nginx.conf @@ -29,7 +29,7 @@ server { } location /socket.io { - proxy_pass http://api:3000/; + proxy_pass http://api:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";