ARCHITECTURE · STACK

내부를 들여다 볼 수 있게.

디바이스에서 사용자 화면까지, CellOps의 데이터가 어떻게 흐르고 어떤 기술이 동작하는지 그대로 보여드립니다. 영업자료의 그림이 아니라 실제 배포된 구조입니다.

01

배터리 셀에서 운영자 알림까지 — 전체 경로

데이터의 한살이

BMS 디바이스펌웨어 + 토큰Ingest APINext.js /api/v1/telemetry알람 엔진lib/alarms · 인라인 + 워커TimescaleDB하이퍼테이블 + 연속 집계Telegram 봇cellops_alert_bot대시보드브라우저 (PWA)HTTPS · Bearer평가INSERTsendMessageSSR · 자동 갱신+ offline 워커 (1분 주기) · 폴링 fallback
  1. 01

    수집 (Edge)

    BMS 펌웨어가 5초마다 팩 상태, 60초마다 셀 단위 데이터를 batch로 POST 합니다.

  2. 02

    인증

    Authorization: Bearer <token> 헤더로 디바이스 식별. 토큰은 회전 가능, 회전 즉시 이전 토큰 무효화.

  3. 03

    검증 + 저장

    Zod 스키마로 모양 검증 후 TimescaleDB 하이퍼테이블에 INSERT. 미지의 팩 라벨은 조용히 스킵.

  4. 04

    룰 평가

    같은 요청 흐름 안에서 SOC·온도·셀 편차 임계 평가. OPEN 알람 중복 차단 + 정상 복귀 시 자동 RESOLVED.

  5. 05

    알림

    신규 알람은 텔레그램 봇으로 즉시 발송. 운영자 + 해당 고객사만 받습니다 (그룹 채팅 가능).

  6. 06

    표시 / 자동 갱신

    대시보드 15초, 디바이스 상세 10초 주기 server component re-fetch — 화면이 살아 움직입니다.

02

각 박스가 실제로 무슨 일을 하는가

구성요소

Edge · BMS 펌웨어

HTTPS POSTBearer TokenBatch (≤ 100 샘플)

디바이스가 직접 클라우드로 push. 게이트웨이·MQTT 브로커 없이 단순화. 시연 단계에서는 cellops-sim PM2 워커가 8대를 흉내.

Ingest API

Next.js Route HandlerZod 검증Prisma createMany

단일/배치 양쪽 지원. 알 수 없는 팩 라벨은 조용히 무시 → 펌웨어 마이그레이션 도중에도 안전.

Database

PostgreSQL 17TimescaleDBContinuous aggregates

TelemetryPack/Cell은 하이퍼테이블. 1분·1시간 집계는 백그라운드로 자동 계산. 알람·사용자·사이트 등 메타는 일반 테이블.

Alarm Engine

lib/alarms.tsTelemetry hook (인라인)1분 주기 워커

low_soc · high_temp · cell_imbalance · offline 4종. 정상 복귀 시 자동 RESOLVED, 같은 종류는 1건만 OPEN.

Notification

Telegram Bot APIWebhook + Polling fallbackPer-event recipient matrix

DuckDNS NS 불안정 대응으로 폴링 백업 항상 가동. 운영자 + 해당 사이트 소유 고객만 수신.

Frontend

Next.js 16 + React 19App Router (RSC)recharts · Tailwind v4

대부분 server component. AutoRefresh 컴포넌트가 router.refresh()를 주기 호출 → 데이터 살아 움직임.

Auth · Session

bcryptjsjose JWT (HS256)HttpOnly cookie 'co_session'

ADMIN / CUSTOMER 두 역할. 모든 admin API 호출에 역할 게이트. 토큰 회전·자동 정상화 가능.

Worker

tsxPM2 cellops-workerOffline detection 1m

텔레메트리가 안 오면 알람을 못 만드니까 별도 워커가 디바이스를 sweep. 텔레그램 폴링도 같은 프로세스에서 처리.

Infrastructure

Ubuntu + DockerPM2 (web/worker/sim)Nginx + Let's Encrypt

DNS-01 챌린지로 SSL 발급 (DuckDNS NS 불안정 우회). 트래픽은 HTTPS 강제, internal 5435 PG는 127.0.0.1 바인딩.

03

배터리가 임계값을 넘긴 순간, 1초 안에 무슨 일이 일어나는가

요청 1건의 일생

T+0msBMS가 SOC=8.5% 측정. /api/v1/telemetry로 batch POST.
T+20ms토큰 검증·디바이스 조회·Zod 스키마 검증.
T+45msTelemetryPack 1행 + TelemetryCell 1행 INSERT (하이퍼테이블).
T+55msSOC < 15 임계 hit. 동일 kind OPEN 알람 없음 → 신규 생성.
T+80msAlarmEvent INSERT (severity=CRITICAL, kind=low_soc).
T+120ms수신자 매트릭스 조회 → 운영자 + 사이트 소유 고객 chat_id 집계.
T+250ms봇 sendMessage 호출. 그룹 채팅에 메시지 도착, NotificationLog 기록.
T+~15s다음 AutoRefresh 틱에서 대시보드 KPI '긴급 알람'이 빨강으로 점등.

전체 평균 지연 < 1초. 통신·네트워크 변동 포함 95-percentile 약 2–3초.

04

자산 계층 + 시계열 분리

데이터 모델

SiteidownerId →name, addressDeviceidsiteId →authToken, serialPackiddeviceId →cellCount, nominalKwh1:N1:NTelemetryPackts, packId (PK)voltageV, currentA …TimescaleDBTelemetryCellts, packId (PK)cellV[], cellT[]TimescaleDBAlarmEventdeviceId →kind, severityOPEN/ACK/RESOLVED시계열알람

Site

고객사 소유의 운영 현장. ownerId가 CUSTOMER user를 가리킴.

Device

사이트에 설치된 게이트웨이. authToken으로 인증. 1개 디바이스 = 1개 BMS.

Pack

디바이스가 관리하는 배터리 팩. cellCount·nominalKwh 보유.

TelemetryPack

팩 단위 시계열. 5초 간격. 하이퍼테이블, 7일 보존.

TelemetryCell

셀별 vector(float[]). 1분 간격. 하이퍼테이블, 30일 보존.

AlarmEvent

OPEN/ACKNOWLEDGED/RESOLVED 라이프사이클. 무한 보존.

PolicyConfig

singleton row. 알람 임계값·텔레그램 on/off. 어드민에서 즉시 튜닝.

NotificationLog

텔레그램 전송 결과. 실패도 기록 → 사고 후 원인 추적.

05

TimescaleDB 연속 집계로 raw·집계가 자동 계단형 보존

데이터 보존

Pack raw

7일

5초 간격 원본

Cell raw

30일

1분 간격 셀 벡터

1분 집계

1년

자동 continuous agg

1시간 집계

영구

자동 continuous agg

원본은 시간이 지나면 chunk 단위로 자동 삭제됩니다. 집계 테이블은 그대로 남아 장기 트렌드·연도별 비교에 사용됩니다.

06

버전까지 그대로

기술 스택

Runtime · 백엔드

  • Node.js20 LTS
  • Next.js16.2 (App Router)
  • React19
  • TypeScript5
  • Prisma6
  • Zod4

Database

  • PostgreSQL17
  • TimescaleDBlatest
  • HypertablesTelemetryPack/Cell
  • Continuous aggs1m · 1h

Frontend · UI

  • Tailwind CSSv4
  • Radix UIDialog/Tooltip 등
  • recharts3
  • lucide-reacticons
  • PWAmanifest + sw.js

Auth · 보안

  • bcryptjspassword hash
  • joseJWT HS256
  • HttpOnly cookieco_session
  • 역할 게이트ADMIN/CUSTOMER
  • HTTPSTLS 1.2/1.3

알림

  • Telegram Bot APIsendMessage
  • webhook기본
  • polling fallbackDuckDNS NS 대비
  • NotificationLog발송 로그

Infrastructure

  • Ubuntu22.04
  • DockerPG + TimescaleDB
  • PM2web/worker/sim
  • Nginxreverse proxy + HSTS
  • Let's EncryptDNS-01 (DuckDNS)

그림이 아니라 실제로 돌고 있습니다

데모 환경에서 8대의 디바이스가 지금도 데이터를 보내고 있습니다. 여기 설명한 흐름을 직접 보세요.