diff --git a/.env b/.env.common similarity index 59% rename from .env rename to .env.common index 4443478..ebe5ea8 100644 --- a/.env +++ b/.env.common @@ -1,28 +1,15 @@ -# PostgreSQL 설정 -PGHOST=bkdhome.p-e.kr -PGPORT=15454 -PGDATABASE=scheduler -PGUSER=baekyangdan -PGPASSWORD=qwas745478! -PG_DATABASE_URL=postgres://baekyangdan:qwas745478!@bkdhome.p-e.kr:5454/scheduler - -# Redis 설정 -RD_HOST=bkdhome.p-e.kr -RD_PORT=6779 -RD_URL=redis://bkdhome.p-e.kr:6779 - -# Express 서버 포트 -PORT=3000 - -# Gmail SMTP 설정 -GMAIL_USER=bkd.scheduler@gmail.com -GMAIL_PASS= # 앱 비밀번호 또는 OAuth2 토큰 -GMAIL_CLIENT_ID=688417162908-iqvnj4ceb8t1dkbjr70dtcafo27m8kqe.apps.googleusercontent.com -GMAIL_CLIENT_SECRET=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 -GMAIL_REFRESH_TOKEN=1//04P8ekVQmkdtnCgYIARAAGAQSNwF-L9IrqPOyH8oYB-mdjUqw9jGHienVLBTWFdiZgpRnPgFmYnAdbjnstd9RkRVeJErB0NRAwg4 - -# SMTP 추가 옵션 -SMTP_AUTH=true -SMTP_STARTTLS_ENABLE=true -SMTP_STARTTLS_REQUIRED=true -SMTP_AUTH_MECHANISMS=XOAUTH2 +# Nestjs 서버 포트 +PORT=3000 + +# Gmail SMTP 설정 +GMAIL_USER=bkd.scheduler@gmail.com +GMAIL_PASS= # 앱 비밀번호 또는 OAuth2 토큰 +GMAIL_CLIENT_ID=688417162908-iqvnj4ceb8t1dkbjr70dtcafo27m8kqe.apps.googleusercontent.com +GMAIL_CLIENT_SECRET=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 +GMAIL_REFRESH_TOKEN=1//04P8ekVQmkdtnCgYIARAAGAQSNwF-L9IrqPOyH8oYB-mdjUqw9jGHienVLBTWFdiZgpRnPgFmYnAdbjnstd9RkRVeJErB0NRAwg4 + +# SMTP 추가 옵션 +SMTP_AUTH=true +SMTP_STARTTLS_ENABLE=true +SMTP_STARTTLS_REQUIRED=true +SMTP_AUTH_MECHANISMS=XOAUTH2 diff --git a/.env.dev b/.env.dev new file mode 100644 index 0000000..d010852 --- /dev/null +++ b/.env.dev @@ -0,0 +1,12 @@ +# PostgreSQL 설정 +PGHOST=bkdhome.p-e.kr +PGPORT=15454 +PGDATABASE=scheduler +PGUSER=baekyangdan +PGPASSWORD=qwas745478! +PG_DATABASE_URL=postgres://baekyangdan:qwas745478!@bkdhome.p-e.kr:15454/scheduler + +# Redis 설정 +RD_HOST=bkdhome.p-e.kr +RD_PORT=6779 +RD_URL=redis://bkdhome.p-e.kr:16779 diff --git a/.env.local b/.env.local new file mode 100644 index 0000000..20bf4ec --- /dev/null +++ b/.env.local @@ -0,0 +1,12 @@ +# PostgreSQL 설정 +PGHOST=bkdhome.p-e.kr +PGPORT=15454 +PGDATABASE=scheduler +PGUSER=baekyangdan +PGPASSWORD=qwas745478! +PG_DATABASE_URL=postgres://192.168.219.107:5454/scheduler + +# Redis 설정 +RD_HOST=bkdhome.p-e.kr +RD_PORT=6779 +RD_URL=redis://192.168.219.107:6779 diff --git a/.env.prod b/.env.prod new file mode 100644 index 0000000..c83a9f1 --- /dev/null +++ b/.env.prod @@ -0,0 +1,12 @@ +# PostgreSQL 설정 +PGHOST=db +PGPORT=5454 +PGDATABASE=scheduler +PGUSER=baekyangdan +PGPASSWORD=qwas745478! +PG_DATABASE_URL=postgres://baekyangdan:qwas745478!@db:5454/scheduler + +# Redis 설정 +RD_HOST=redis +RD_PORT=6779 +RD_URL=redis://redis:6779 \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b6de400..465ed21 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,25 +19,24 @@ # stages: # List of stages for jobs, and their order of execution # - build -# cache: -# key: -# files: -# - package-lock.json -# paths: -# - node_modules/ +cache: + key: "${CI_COMMIT_REF_SLUG}" + paths: + - node_modules/ + - .yarn/cache/ -# build: # This job runs in the build stage, which runs first. -# stage: build -# tags: -# - local-runner -# before_script: -# script: -# - echo "Compiling the code..." -# - echo $DOCKER_VOLUME -# - echo $DOCKER_COMPOSE_VOLUME -# - npm install -# - npm run build -# - sudo cp -r $PWD/dist/. $DOCKER_VOLUME/scheduler/back/dist -# - sudo cp $PWD/package.json $DOCKER_VOLUME/scheduler/back/dist -# - docker compose -f $DOCKER_COMPOSE_VOLUME/scheduler/docker-compose.yaml up -d back -# - echo "Compile complete." \ No newline at end of file +build: # This job runs in the build stage, which runs first. + stage: build + tags: + - local-runner + before_script: + script: + - echo "Compiling the code..." + - echo $DOCKER_VOLUME + - echo $DOCKER_COMPOSE_VOLUME + - yarn install --immutable + - yarn build + - sudo cp -r $PWD/dist/. $DOCKER_VOLUME/scheduler/back/dist + - sudo cp $PWD/package.json $DOCKER_VOLUME/scheduler/back/dist + - docker compose -f $DOCKER_COMPOSE_VOLUME/scheduler/docker-compose.yaml up -d back + - echo "Compile complete." \ No newline at end of file diff --git a/package.json b/package.json index 92602d9..c482d6c 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,13 @@ "private": true, "license": "UNLICENSED", "scripts": { - "build": "nest build", + "build": "NODE_ENV=prod nest build", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "start": "nest start", - "start:dev": "nest start --watch", + "start:local": "NODE_ENV=local nest start --watch", + "start:dev": "NODE_ENV=dev nest start --watch", "start:debug": "nest start --debug --watch", - "start:prod": "node dist/main", + "start:prod": "NODE_ENV=prod node dist/main", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "test": "jest", "test:watch": "jest --watch", @@ -23,6 +24,7 @@ "@nestjs/class-transformer": "^0.4.0", "@nestjs/class-validator": "^0.13.4", "@nestjs/common": "^11.0.1", + "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.0.1", "@nestjs/platform-express": "^11.0.1", "bcrypt": "^6.0.0", diff --git a/src/app.module.ts b/src/app.module.ts index d2055ac..79a53e9 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -5,9 +5,10 @@ import { DbModule } from './db/db.module'; import { RedisModule } from './redis/redis.module'; import { AccountModule } from './modules/account/account.module'; import { MailerModule } from './util/mailer/mailer.module'; +import { AppConfigModule } from './config/config.module'; @Module({ - imports: [DbModule, RedisModule, MailerModule, AccountModule], + imports: [AppConfigModule, DbModule, RedisModule, MailerModule, AccountModule], controllers: [AppController], providers: [AppService], }) diff --git a/src/config/config.module.ts b/src/config/config.module.ts new file mode 100644 index 0000000..b401e15 --- /dev/null +++ b/src/config/config.module.ts @@ -0,0 +1,15 @@ +import { Module } from "@nestjs/common"; +import { ConfigModule } from '@nestjs/config'; + +@Module({ + imports: [ + ConfigModule.forRoot({ + isGlobal: true, + envFilePath: [ + '.env.common', + `.env.${process.env.NODE_ENV}` + ] + }) + ] +}) +export class AppConfigModule{} diff --git a/src/db/db.module.ts b/src/db/db.module.ts index a1f0703..362539d 100644 --- a/src/db/db.module.ts +++ b/src/db/db.module.ts @@ -1,20 +1,22 @@ import { Global, Module } from "@nestjs/common"; import { Pool } from "pg"; import { drizzle, NodePgDatabase } from "drizzle-orm/node-postgres"; +import { ConfigModule, ConfigService } from "@nestjs/config"; import * as schema from '../../drizzle/schema'; @Global() @Module({ + imports: [ConfigModule], providers: [ { provide: "DRIZZLE", - useFactory: (): NodePgDatabase => { + useFactory: (configService: ConfigService): NodePgDatabase => { const pool = new Pool({ - connectionString: process.env.PG_DATABASE_URL + connectionString: configService.get('PG_DATABASE_URL') }); - return drizzle(pool, { schema: schema }); - } + }, + inject: [ConfigService] } ], exports: ["DRIZZLE"] diff --git a/src/redis/redis.module.ts b/src/redis/redis.module.ts index 3ca63fd..c229fe0 100644 --- a/src/redis/redis.module.ts +++ b/src/redis/redis.module.ts @@ -1,4 +1,5 @@ import { Global, Module } from "@nestjs/common"; +import { ConfigModule, ConfigService } from "@nestjs/config"; import Redis from "ioredis"; @Global() @@ -6,12 +7,13 @@ import Redis from "ioredis"; providers: [ { provide: "REDIS", - useFactory: (): Redis => { + useFactory: (configService: ConfigService): Redis => { return new Redis({ - host: process.env.RD_HOST!, - port: Number(process.env.RD_PORT || 6779) + host: configService.get('RD_HOST')!, + port: configService.get('RD_PORT') }); - } + }, + inject: [ConfigService] }, ], exports: ["REDIS"] diff --git a/src/util/mailer/mailer.service.ts b/src/util/mailer/mailer.service.ts index 6145cca..7bb4b01 100644 --- a/src/util/mailer/mailer.service.ts +++ b/src/util/mailer/mailer.service.ts @@ -1,42 +1,54 @@ import { Injectable } from '@nestjs/common'; import nodemailer from 'nodemailer'; import { google } from 'googleapis'; +import { OAuth2Client } from 'google-auth-library'; import SMTPTransport from 'nodemailer/lib/smtp-transport'; +import { ConfigService } from '@nestjs/config'; @Injectable() export class MailerService { - private oauth2Client = new google.auth.OAuth2( - process.env.GMAIL_CLIENT_ID, - process.env.GMAIL_CLIENT_SECRET, - 'https://developers.google.com/oauthplayground' - ); + private oauth2Client: OAuth2Client; + private readonly gmailUser: string; + + constructor(private readonly configService: ConfigService) { + const clientId = this.configService.get('GMAIL_CLIENT_ID'); + const clientSecret = this.configService.get('GMAIL_CLIENT_SECRET'); + const refreshToken = this.configService.get('GMAIL_REFRESH_TOKEN'); + + this.gmailUser = this.configService.get('GMAIL_USER')!; + + this.oauth2Client = new google.auth.OAuth2( + clientId, + clientSecret, + 'https://developers.google.com/oauthplayground' + ); - constructor() { this.oauth2Client.setCredentials({ - refresh_token: process.env.GMAIL_REFRESH_TOKEN + refresh_token: refreshToken, }); } async sendMail(to: string, subject: string, html: string) { const accessToken = await this.oauth2Client.getAccessToken(); + const options: SMTPTransport.Options = { host: "smtp.gmail.com", port: 465, secure: true, auth: { type: "OAuth2", - user: process.env.GMAIL_USER, - clientId: process.env.GMAIL_CLIENT_ID, - clientSecret: process.env.GMAIL_CLIENT_SECRET, - refreshToken: process.env.GMAIL_REFRESH_TOKEN, - accessToken: accessToken?.token || '' + user: this.gmailUser, + clientId: this.configService.get('GMAIL_CLIENT_ID'), + clientSecret: this.configService.get('GMAIL_CLIENT_SECRET'), + refreshToken: this.configService.get('GMAIL_REFRESH_TOKEN'), + accessToken: accessToken?.token || '', } } const transporter = nodemailer.createTransport(options); return transporter.sendMail({ - from: `Scheduler ${process.env.GMAIL_USER}>`, + from: `Scheduler ${this.gmailUser}>`, to, subject, html