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
32 changes: 32 additions & 0 deletions .github/workflows/deploy-nest-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Deployment Nestjs server (Dev)

on:
push:
branches: [development]

jobs:
build-and-deploy:
name: Build and Deploy to EC2
runs-on: [self-hosted, nest-dev]

steps:
- name: Checkout source code
uses: actions/checkout@v3
- name: install dependencies
run: |
corepack enable
yarn install

- name: Run Docker Compose
env:
DATABASE_HOST_DEV: ${{ secrets.DATABASE_HOST_DEV }}
DATABASE_USERNAME_DEV: ${{ secrets.DATABASE_USERNAME_DEV }}
DATABASE_PASSWORD_DEV: ${{ secrets.DATABASE_PASSWORD_DEV }}
DATABASE_ROOT_PASSWORD_DEV: ${{ secrets.DATABASE_ROOT_PASSWORD_DEV }}
REDIS_HOST_DEV: ${{ secrets.REDIS_HOST_DEV }}

run: |
yarn types:build
docker system prune -f
docker compose -f ./compose.server.dev.yaml down || true
docker compose -f ./compose.server.dev.yaml up -d --build
32 changes: 32 additions & 0 deletions .github/workflows/deploy-nest-prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Deployment Nestjs server (Prod)

on:
push:
branches: [main]

jobs:
build-and-deploy:
name: Build and Deploy to EC2
runs-on: [self-hosted, nest-prod]

steps:
- name: Checkout source code
uses: actions/checkout@v3
- name: install dependencies
run: |
corepack enable
yarn install

- name: Run Docker Compose
env:
DATABASE_HOST_PROD: ${{ secrets.DATABASE_HOST_PROD }}
DATABASE_USERNAME_PROD: ${{ secrets.DATABASE_USERNAME_PROD }}
DATABASE_PASSWORD_PROD: ${{ secrets.DATABASE_PASSWORD_PROD }}
DATABASE_ROOT_PASSWORD_PROD: ${{ secrets.DATABASE_ROOT_PASSWORD_PROD }}
REDIS_HOST_PROD: ${{ secrets.REDIS_HOST_PROD }}

run: |
yarn types:build
docker system prune -f
docker compose -f ./compose.server.prod.yaml down || true
docker compose -f ./compose.server.prod.yaml up -d --build
41 changes: 41 additions & 0 deletions .github/workflows/pr-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Claude PR Review
on:
pull_request:
types: [opened, synchronize]
branches: [development]

jobs:
review:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
id-token: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1

- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
track_progress: true
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}

Please review this pull request with a focus on:
- Code quality and best practices
- Potential bugs or issues
- Security implications
- Performance considerations

NOTE: The PR branch is already checked out in the current working directory.
NOTE: write your review in Korean.

Use `gh pr comment` for top-level feedback.
Use `mcp__github_inline_comment__create_inline_comment` to highlight specific code issues.
Only post GitHub comments - don't submit review text as messages.

claude_args: |
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)"
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export default function InterviewMainScreen() {
source={{
uri: `${process.env.EXPO_PUBLIC_CLIENT_URL}/interviews`,
}}
userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Adding a hardcoded user agent string can be problematic. It would be better to either dynamically generate this based on the platform or use a configuration value. This increases maintainability and avoids issues if the user agent needs to be updated in the future.

Consider using react-native-device-info to get the device's user agent.

Suggested change
userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"
userAgent={Platform.OS === 'ios' ? 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1' : 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36'}

javaScriptEnabled={true}
originWhitelist={["*"]}
injectedJavaScriptBeforeContentLoaded={runFirst}
Expand Down
1 change: 1 addition & 0 deletions apps/kokomen-native/src/screens/my/dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export default function DashboardScreen() {
<WebView
ref={webviewRef as any}
source={{ uri: `${process.env.EXPO_PUBLIC_CLIENT_URL}/dashboard` }}
userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Similar to the InterviewMainScreen, hardcoding the user agent string here is not ideal. Consider using a dynamic approach or a configuration value for better maintainability.

Suggested change
userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"
userAgent={Platform.OS === 'ios' ? 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1' : 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36'}

javaScriptEnabled={true}
originWhitelist={["*"]}
injectedJavaScriptBeforeContentLoaded={runFirst}
Expand Down
16 changes: 16 additions & 0 deletions apps/kokomen-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM node:22-alpine

WORKDIR /app

RUN corepack enable

COPY . .

RUN yarn install

WORKDIR /app/apps/kokomen-server

RUN yarn types:build

WORKDIR /app
CMD ["yarn", "server:start"]
28 changes: 0 additions & 28 deletions apps/kokomen-server/compose.dev.yml

This file was deleted.

40 changes: 40 additions & 0 deletions apps/kokomen-server/nginx/dev/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
worker_processes auto;

events {
worker_connections 1024;
}


http {
charset utf-8;

log_format main '$request_id $remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$request_time" '
'"$http_user_agent" "$http_x_forwarded_for" '
'"$ssl_protocol/$ssl_cipher" "$content_length" "$request_length"';
access_log /var/log/nginx/access.log main;

upstream kokomen-graphql-api-dev {
server kokomen-nest-server-dev:3000;
}

server {
listen 80;

set_real_ip_from 10.0.0.0/16;
set_real_ip_from 43.203.50.14;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

server_name api-dev.kokomen.kr localhost;
server_tokens off;

location /api/v3 {
proxy_pass http://kokomen-graphql-api-dev;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-RequestID $request_id;
}
}
}
41 changes: 41 additions & 0 deletions apps/kokomen-server/nginx/prod/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
worker_processes auto;

events {
worker_connections 1024;
}


http {
charset utf-8;

log_format main '$request_id $remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" "$request_time" '
'"$http_user_agent" "$http_x_forwarded_for" '
'"$ssl_protocol/$ssl_cipher" "$content_length" "$request_length"';
access_log /var/log/nginx/access.log main;

upstream kokomen-graphql-api-prod {
server kokomen-nest-server-prod:3000;
}

server {
listen 80;

set_real_ip_from 10.0.0.0/16;
set_real_ip_from 43.203.50.14;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

server_name api-dev.kokomen.kr localhost;
server_tokens off;

location /api/v3 {
proxy_pass http://kokomen-graphql-api-prod;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-RequestID $request_id;

}
}
}
19 changes: 12 additions & 7 deletions apps/kokomen-server/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,28 @@ import { RootQuestionModule } from "src/interview/modules/rootQuestion";
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: [`env.${process.env.NODE_ENV || "development"}.`, ".env"],
envFilePath: [`env.${process.env.NODE_ENV || "development"}`, ".env"],
load: [appConfig]
}),
TypeOrmModule.forRoot({
type: "mysql",
host: process.env.DB_HOST,
port: process.env.DB_PORT ? parseInt(process.env.DB_PORT, 10) : 3306,
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
host: process.env.DATABASE_HOST,
port: process.env.DATABASE_PORT
? parseInt(process.env.DATABASE_PORT, 10)
: 3306,
username: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE_DATABASE,
entities: [__dirname + "/**/domains/*.{ts,js}"]
}),
TypeOrmModule.forFeature([Member]),
GraphQLModule.forRoot({
driver: ApolloDriver,
graphiql: process.env.NODE_ENV === "development",
autoSchemaFile: true
autoSchemaFile: true,
path: "api/v3/graphql",
sortSchema: true,
introspection: true
}),
RedisModule,
CategoryModule,
Expand Down
7 changes: 6 additions & 1 deletion apps/kokomen-server/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ import { AppModule } from "./app.module";
async function bootstrap() {
const app = await NestFactory.create(AppModule);

app.setGlobalPrefix("api/v3");

app.enableCors({
origin: [
"http://localhost:3000",
"http://localhost:3001",
"http://local.kokomen.kr:3000",
"https://dev.kokomen.kr"
"https://dev.kokomen.kr",
"https://kokomen.kr",
"https://webview.kokomen.kr",
"https://webview-dev.kokomen.kr"
],
credentials: true,
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
Expand Down
13 changes: 7 additions & 6 deletions apps/kokomen-server/src/redis/redis.module.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
// src/redis/redis.module.ts
import { Module, Global } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import Redis from "ioredis";

@Global()
@Module({
providers: [
{
provide: "REDIS_CLIENT",
useFactory: (configService: ConfigService): Redis => {
useFactory: (): Redis => {
const redis = new Redis({
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Removing ConfigService and directly using process.env is a good move for simplifying the code and accessing environment variables directly. This reduces unnecessary dependencies.

      useFactory: (): Redis => {

host: configService.get("REDIS_HOST", "127.0.0.1"),
port: configService.get("REDIS_PORT", 6379),
password: configService.get("REDIS_PASSWORD", ""),
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT
? parseInt(process.env.REDIS_PORT, 10)
: 6379,
password: process.env.REDIS_PASSWORD || "",

enableReadyCheck: false,
lazyConnect: false,
Expand Down Expand Up @@ -45,7 +46,7 @@ import Redis from "ioredis";

return redis;
},
inject: [ConfigService]
inject: []
}
],
exports: ["REDIS_CLIENT"]
Expand Down
36 changes: 36 additions & 0 deletions compose.server.dev.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
services:
kokomen-nest-server-dev:
build:
context: .
dockerfile: ./apps/kokomen-server/Dockerfile
environment:
TZ: Asia/Seoul
NODE_ENV: development
DATABASE_HOST: ${DATABASE_HOST_DEV}
DATABASE_PORT: 3306
DATABASE_USERNAME: ${DATABASE_USERNAME_DEV}
DATABASE_PASSWORD: ${DATABASE_PASSWORD_DEV}
DATABASE_ROOT_PASSWORD: ${DATABASE_ROOT_PASSWORD_DEV}
DATABASE_DATABASE: kokomen-dev
REDIS_HOST: ${REDIS_HOST_DEV}
REDIS_PORT: 6379
PORT: 3000
container_name: kokomen-nest-server-dev
restart: on-failure:3
ports:
- "3000:3000"
- "3001:3001"

nginx:
image: nginx:alpine
container_name: kokomen-nest-nginx-dev
ports:
- "80:80"
- "443:443"
volumes:
- ./apps/kokomen-server/nginx/dev/nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- kokomen-nest-server-dev
restart: unless-stopped
environment:
TZ: Asia/Seoul
Loading
Loading