티스토리 뷰
SaaS 운영 자동화 최종편
사용량 기반 빌링 · 에러 모니터링 · Sentry · Slack 알림 · Observability 구축하기
(NestJS + Next.js + K8s + Cloudflare + Terraform 기반 실서비스 운영편)
이제 우리는 개발·배포·AI 기능·결제·구독 모델까지
“상품으로서의 SaaS” 를 모두 만들었다.
그러나 진짜 운영은 지금부터다.
서버는 절대 우리가 보는 동안만 문제가 생기지 않는다.
사용자는 새벽 3시에 에러를 터뜨리고,
Stripe 결제 실패는 주말에 몰려오며,
로그는 알아서 쌓이지 않는다.
이번 글은 실제 스타트업에서 반드시 구축해야 하는 운영 자동화 체계를 정리한다:
🧭 이번 글에서 완성되는 운영 체계
기능 목적
| 📡 Sentry 에러 모니터링 | 실시간 서버/프론트 에러 감지 |
| 🔔 Slack 알림 | 장애 즉시 알림 |
| 📊 Prometheus + Grafana | CPU, 메모리, RPS, Latency 모니터링 |
| 📝 구조적 로그(JSON Logging) | 오류 상황 분석 |
| 💰 사용량 기반 Billing | AI 호출량 기반 결제 기능 |
| 🧹 Cron 기반 유지작업 | 매일 사용량 리셋, 오래된 로그 삭제 |
| 🚦 API Rate-Limit | 악의적 트래픽 방지 |
| 🔁 Circuit Breaker | 외부 API 문제 시 서버 전체 장애 방지 |
이 글을 끝내고 나면, 당신의 서비스는
“혼자서도 회사급 운영 시스템” 을 가지게 된다.
1️⃣ Sentry 도입 — 백엔드/프론트 에러를 실시간 수집
Sentry는 스타트업 99%가 쓰는 운영 필수 툴이다.
에러가 발생하면 자동으로 Slack과 메일로 날아온다.
NestJS Sentry 설치
npm install @sentry/node @sentry/tracing
초기화
main.ts
import * as Sentry from '@sentry/node';
import { nodeProfilingIntegration } from "@sentry/profiling-node";
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
integrations: [
nodeProfilingIntegration(),
],
tracesSampleRate: 1.0,
profilesSampleRate: 1.0,
});
Next.js Sentry 설정
npm install @sentry/nextjs
프로젝트 루트:
npx @sentry/wizard
자동으로:
- pages/app 에러 추적
- API route 에러 캡처
- sourcemap 업로드
가 적용된다.
2️⃣ Slack 알림 — Sentry + 서버 장애 알림
Slack Incoming Webhook 생성
환경변수:
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxxx
NestJS Slack 서비스
@Injectable()
export class SlackService {
async notify(message: string) {
await fetch(process.env.SLACK_WEBHOOK_URL!, {
method: 'POST',
body: JSON.stringify({ text: message }),
});
}
}
장애 발생 시 호출
errorHandler.ts
if (statusCode >= 500) {
slackService.notify(`🚨 서버 오류 발생: ${err.message}`);
}
3️⃣ Prometheus + Grafana 로 Observability 구축
운영하려면 최소한 알아야 한다:
- CPU / 메모리 / 디스크
- API 요청 수
- 평균 응답시간
- 에러율
- RPS(Requests per second)
Kubernetes 환경에서 보통 아래 조합을 사용한다:
구성 설명
| Prometheus | 메트릭 수집 |
| Grafana | 대시보드 시각화 |
| Prometheus Operator | 설치 자동화 |
NestJS에서 Prometheus 메트릭 제공
npm install prom-client
import { Injectable } from '@nestjs/common';
import { Counter, Registry } from 'prom-client';
@Injectable()
export class MetricsService {
private registry = new Registry();
private requestCount = new Counter({
name: 'http_requests_total',
help: '전체 API 요청 수',
});
getMetrics() {
return this.registry.metrics();
}
increment() {
this.requestCount.inc();
}
}
Metrics 엔드포인트
@Get('/metrics')
getMetrics() {
return this.metricsService.getMetrics();
}
Prometheus가 자동으로 긁어간다.
4️⃣ 구조적 로그(JSON Logging) — 로그를 데이터처럼 다루기
개발자들 대부분이 초반에 하루 종일 삽질하는 부분: 로그가 흐트러짐.
운영 로그는 무조건 JSON이어야 한다.
NestJS Logger 패치
npm install pino pino-pretty nestjs-pino
main.ts
import { Logger } from 'nestjs-pino';
app.useLogger(app.get(Logger));
모든 요청·응답·에러가 JSON 형태로 기록된다:
{
"msg": "Request completed",
"method": "GET",
"path": "/posts",
"status": 200,
"responseTime": 34
}
이제 Loki/Grafana/CloudWatch로 전송 가능.
5️⃣ 사용량 기반 Billing (AI 호출량 기반 결제)
우리는 이미 Stripe 구독 모델을 만들어두었다.
이제 여기에 사용량 기반 결제를 추가해볼 수 있다.
예시:
AI 요청 초과 → 추가 과금
AI 호출 기록 테이블
model AiUsage {
id Int @id @default(autoincrement())
userId Int
count Int @default(1)
createdAt DateTime @default(now())
}
요청 시마다 기록 남기기
AiRateLimitGuard에서 추가:
await this.prisma.aiUsage.create({
data: { userId: user.id },
});
Stripe 사용량 리포트 업로드
await stripe.subscriptionItems.createUsageRecord(
subscriptionItemId,
{
quantity: 1,
action: "increment",
}
);
이제 Stripe가 자동으로 과금한다.
6️⃣ Cron 작업 — 매일 00시 AI 사용량 초기화
NestJS Schedule 패키지
npm install @nestjs/schedule
app.module.ts
imports: [ScheduleModule.forRoot()]
Reset Service
@Cron('0 0 * * *') // 매일 00:00
async resetAiLimits() {
await this.prisma.user.updateMany({
data: { ai_limit: 5 },
where: { plan: 'FREE' },
});
await this.prisma.user.updateMany({
data: { ai_limit: 200 },
where: { plan: 'PRO' },
});
}
7️⃣ API Rate Limit — 악성 요청 방어
npm install express-rate-limit
main.ts
app.use(
rateLimit({
windowMs: 60 * 1000,
max: 100, // IP당 1분 100요청 제한
})
);
8️⃣ Circuit Breaker — 외부 API 장애로 전체 서버가 죽는 걸 방지
LLM API 오류가 전체 API를 다운시키지 않도록.
npm install opossum
const breaker = new CircuitBreaker(
() => openai.chat.completions.create(...),
{ timeout: 5000, errorThresholdPercentage: 50 }
);
OpenAI 문제가 생기면 자동으로 fallback 실행.
🔥 최종 운영 아키텍처
┌──────────────────────────────┐
│ Next.js Frontend │
│ (Cloudflare Pages + Sentry) │
└───────────────┬──────────────┘
│
▼
┌──────────────────────────────┐
│ NestJS Backend │
│ JWT Auth / Stripe Billing │
│ AI / RAG / VectorDB │
│ Prometheus Metrics / Logging │
│ Sentry Error Tracking │
└───────────────┬──────────────┘
│
▼
┌──────────────────────────────┐
│ Kubernetes Cluster │
│ Auto Restart / Autoscaling │
│ Grafana / Prometheus / Loki │
└──────────────────────────────┘
✅ 이번 편 요약
기능 구축 여부
| Sentry 에러 모니터링 | ✔️ |
| Slack 장애 알림 | ✔️ |
| Prometheus 메트릭 | ✔️ |
| Grafana 대시보드 | ✔️ |
| JSON 구조 로그 | ✔️ |
| AI 사용량 Billing | ✔️ |
| AI RateLimit | ✔️ |
| Cron 스케줄러 | ✔️ |
| Circuit Breaker | ✔️ |
이제 단순한 프로젝트가 아니라
실서비스급 운영 능력을 갖춘 SaaS가 완성되었다.
🔮 다음 글 예고
이제 모든 흐름이 완성됐으니,
다음 편에서는 “전체 프로젝트 구조를 아키텍처 문서로 정리하기” 를 다룬다.
실제 회사에서 “기술 문서 / 아키텍처 문서 / 운영 문서 / 장애 대응 문서”를 어떻게 작성하는지
샘플과 함께 정리한다.
즉,
프로젝트의 모든 구성요소를 문서화하는 실무 편 으로 넘어간다.
SaaS운영, Stripe사용량과금, Prometheus, Grafana, Loki, Sentry, Slack알림, NestJS, Next.js, 운영자동화, Observability, DevOps
'study > 백엔드' 카테고리의 다른 글
| 👥 SaaS 팀 온보딩(Onboarding) 가이드 완성편 (0) | 2025.12.12 |
|---|---|
| 📘 SaaS 프로젝트 기술 문서(Architecture Document) 완성편 (0) | 2025.12.11 |
| Stripe 구독(Subscription) + 사용자 인증(Auth) + AI 기능 제한까지 (0) | 2025.12.05 |
| 실서비스급 NestJS + Next.js 프로젝트에 AI 기능 붙이기 (0) | 2025.12.01 |
| Terraform + GitOps(ArgoCD)로 “전체 인프라를 코드로 관리”하기 (0) | 2025.11.25 |
- Total
- Today
- Yesterday
- JAX
- Prisma
- Next.js
- rag
- flax
- 압박면접
- kotlin
- node.js
- 쿠버네티스
- NestJS
- nextJS
- 웹개발
- JWT
- Docker
- Redis
- 프론트엔드개발
- fastapi
- llm
- 개발블로그
- SEO최적화
- 딥러닝
- Python
- REACT
- Express
- seo 최적화 10개
- PostgreSQL
- CI/CD
- DevOps
- ai철학
- 백엔드개발
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 | 31 |

