ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

๋ฐ˜์‘ํ˜•

๐Ÿ“Œ NestJS ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ: ๊ธฐ์ดˆ๋ถ€ํ„ฐ ์‹ค์ „๊นŒ์ง€

19. NestJS ์‹ค์‹œ๊ฐ„ SaaS ๋ฐฑ์—”๋“œ ์„ค๊ณ„ (GraphQL + WebSocket)

SaaS ๋ฐฑ์—”๋“œ์—์„œ๋Š” ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๊ฐ€ ์ค‘์š”ํ•œ ์š”์†Œ์ž…๋‹ˆ๋‹ค.
ํŠนํžˆ ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ, ๋Œ€์‹œ๋ณด๋“œ ์—…๋ฐ์ดํŠธ, ์ฑ„ํŒ…, ์‹ค์‹œ๊ฐ„ ํ˜‘์—… ๊ธฐ๋Šฅ ๋“ฑ์—์„œ WebSocket๊ณผ GraphQL์„ ํ™œ์šฉํ•œ ํšจ์œจ์ ์ธ ๊ตฌํ˜„์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
์ด๋ฒˆ ๊ธ€์—์„œ๋Š” NestJS์—์„œ GraphQL + WebSocket์„ ํ™œ์šฉํ•˜์—ฌ ์‹ค์‹œ๊ฐ„ SaaS ๋ฐฑ์—”๋“œ๋ฅผ ์„ค๊ณ„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค. ๐Ÿš€


19.1 SaaS์—์„œ ์‹ค์‹œ๊ฐ„ ๊ธฐ๋Šฅ์ด ์ค‘์š”ํ•œ ์ด์œ 

โœ… ์‹ค์‹œ๊ฐ„ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ SaaS ์‚ฌ๋ก€

โœ” ์‹ค์‹œ๊ฐ„ ๋Œ€์‹œ๋ณด๋“œ → ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ์ฆ‰์‹œ ๋ฐ˜์˜
โœ” ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ(Notification) → ์œ ์ €์˜ ํ–‰๋™์— ๋”ฐ๋ฅธ ์ฆ‰๊ฐ์ ์ธ ํ”ผ๋“œ๋ฐฑ
โœ” ์ฑ„ํŒ… ๋ฐ ํ˜‘์—… → ๋‹ค์ค‘ ์‚ฌ์šฉ์ž ๊ฐ„ ์‹ค์‹œ๊ฐ„ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜

๐Ÿ’ก GraphQL Subscriptions + WebSocket์„ ์กฐํ•ฉํ•˜๋ฉด ํšจ์œจ์ ์ธ ์‹ค์‹œ๊ฐ„ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ๊ฐ€๋Šฅ


19.2 NestJS์—์„œ GraphQL + WebSocket ์„ค์ •

โœ… 1) GraphQL Subscriptions ํŒจํ‚ค์ง€ ์„ค์น˜

npm install @nestjs/graphql apollo-server-express graphql-ws

โœ… 2) GraphQL Subscriptions ํ™œ์„ฑํ™”

๋ฐ˜์‘ํ˜•

๐Ÿ“‚ app.module.ts

import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { PubSub } from 'graphql-subscriptions';

@Module({
  imports: [
    GraphQLModule.forRoot({
      autoSchemaFile: true,
      subscriptions: {
        'graphql-ws': true, // WebSocket ์‚ฌ์šฉ ์„ค์ •
      },
    }),
  ],
  providers: [{ provide: 'PUB_SUB', useValue: new PubSub() }],
})
export class AppModule {}

โœ… subscriptions ์˜ต์…˜์„ graphql-ws๋กœ ์„ค์ •ํ•˜๋ฉด WebSocket ๊ธฐ๋ฐ˜์˜ GraphQL Subscriptions ํ™œ์„ฑํ™”


19.3 ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ ๊ธฐ๋Šฅ ๊ตฌํ˜„ (GraphQL Subscriptions ์‚ฌ์šฉ)

โœ… 1) ์ด๋ฒคํŠธ ๋ฐœํ–‰ (PubSub ์‚ฌ์šฉ)

๐Ÿ“‚ notifications.resolver.ts

import { Resolver, Mutation, Subscription } from '@nestjs/graphql';
import { PubSub } from 'graphql-subscriptions';

@Resolver()
export class NotificationsResolver {
  constructor(private readonly pubSub: PubSub) {}

  @Mutation(() => String)
  async sendNotification() {
    const message = '์ƒˆ๋กœ์šด ์•Œ๋ฆผ์ด ๋„์ฐฉํ–ˆ์Šต๋‹ˆ๋‹ค!';
    await this.pubSub.publish('NOTIFICATION_ADDED', { notificationAdded: message });
    return '์•Œ๋ฆผ ์ „์†ก ์™„๋ฃŒ';
  }

  @Subscription(() => String, {
    resolve: (payload) => payload.notificationAdded,
  })
  notificationAdded() {
    return this.pubSub.asyncIterator('NOTIFICATION_ADDED');
  }
}

โœ… 2) GraphQL Subscription ์š”์ฒญ ์˜ˆ์ œ

subscription {
  notificationAdded
}

โœ… ํด๋ผ์ด์–ธํŠธ๊ฐ€ Subscription์„ ๊ตฌ๋…ํ•˜๊ณ  ์žˆ์œผ๋ฉด, Mutation ๋ฐœ์ƒ ์‹œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ


19.4 NestJS WebSocket์œผ๋กœ ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ… ๊ตฌํ˜„

โœ… 1) WebSocket ๋ชจ๋“ˆ ์„ค์น˜

npm install @nestjs/websockets @nestjs/platform-socket.io

โœ… 2) WebSocket Gateway ์ƒ์„ฑ

๐Ÿ“‚ chat.gateway.ts

import { WebSocketGateway, WebSocketServer, SubscribeMessage, MessageBody } from '@nestjs/websockets';
import { Server } from 'socket.io';

@WebSocketGateway({ cors: true })
export class ChatGateway {
  @WebSocketServer()
  server: Server;

  @SubscribeMessage('chatMessage')
  handleMessage(@MessageBody() message: string): void {
    this.server.emit('chatMessage', message);
  }
}

โœ… 3) ํ”„๋ก ํŠธ์—”๋“œ WebSocket ํด๋ผ์ด์–ธํŠธ ์˜ˆ์ œ


  const socket = io('http://localhost:3000');
  
  socket.emit('chatMessage', '์•ˆ๋…•ํ•˜์„ธ์š”!');
  
  socket.on('chatMessage', (msg) => {
    console.log('๋ฐ›์€ ๋ฉ”์‹œ์ง€:', msg);
  });

๐Ÿ’ก NestJS WebSocket Gateway๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฑ„ํŒ…, ์‹ค์‹œ๊ฐ„ ํ˜‘์—… ๊ธฐ๋Šฅ์„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


19.5 ์‹ค์‹œ๊ฐ„ SaaS ์‹œ์Šคํ…œ ์„ค๊ณ„ ์‹œ ๊ณ ๋ คํ•  ์ 

โœ” Connection ๊ด€๋ฆฌ → WebSocket์˜ ์ƒํƒœ ์œ ์ง€ ๋ฐ ์„ธ์…˜ ์ฒ˜๋ฆฌ ํ•„์š”
โœ” ๋ณด์•ˆ ๋ฐ ์ธ์ฆ → JWT ํ† ํฐ ๊ธฐ๋ฐ˜ ์ธ์ฆ์œผ๋กœ ๋ณด์•ˆ ๊ฐ•ํ™”
โœ” ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ → WebSocket ์‚ฌ์šฉ ์‹œ Redis PubSub ๋˜๋Š” Kafka ํ™œ์šฉ
โœ” ๊ณ ๊ฐ๋ณ„ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ๋ถ„๋ฆฌ → ๋ฉ€ํ‹ฐ ํ…Œ๋„Œ์‹œ ํ™˜๊ฒฝ์—์„œ tenantId ๊ธฐ๋ฐ˜์˜ ํ•„ํ„ฐ๋ง ํ•„์š”


19.6 ๊ฒฐ๋ก : NestJS๋กœ ๊ฐ•๋ ฅํ•œ ์‹ค์‹œ๊ฐ„ SaaS ๋ฐฑ์—”๋“œ ๊ตฌ์ถ•ํ•˜๊ธฐ

โœ… GraphQL Subscriptions๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‹ค์‹œ๊ฐ„ ๋Œ€์‹œ๋ณด๋“œ, ์•Œ๋ฆผ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ๊ฐ€๋Šฅ
โœ… WebSocket Gateway๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ… ๋ฐ ํ˜‘์—… ์„œ๋น„์Šค ๊ฐ€๋Šฅ
โœ… ๋ฉ€ํ‹ฐ ํ…Œ๋„Œ์‹œ ํ™˜๊ฒฝ์—์„œ ๊ฐ ํ…Œ๋„ŒํŠธ๋ณ„ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆฌ๋ฐ ์ „๋žต ํ•„์š”

๋‹ค์Œ ๊ธ€์—์„œ๋Š” NestJS์—์„œ AI/ML ๋ชจ๋ธ์„ ํ™œ์šฉํ•˜์—ฌ SaaS ์„œ๋น„์Šค์— ์ธ๊ณต์ง€๋Šฅ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค! ๐Ÿš€


๐Ÿ” ๋‹ค์Œ ๊ธ€ ์˜ˆ๊ณ : NestJS AI/ML ์—ฐ๋™ํ•˜์—ฌ SaaS ๊ธฐ๋Šฅ ํ™•์žฅ

๐Ÿ“Œ ๋‹ค์Œ ํŽธ: 20. NestJS์—์„œ AI/ML ์—ฐ๋™ ์‹ค์ „ ๊ฐ€์ด๋“œ

 

โ€ป ์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค.
๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
Total
Today
Yesterday
๋งํฌ
ยซ   2025/04   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
๊ธ€ ๋ณด๊ด€ํ•จ
๋ฐ˜์‘ํ˜•