NestJS 기반의 IoT 디바이스 및 온도 측정 로그 관리 API
이 프로젝트는 IoT 온도 측정 디바이스를 관리하고 온도 로그 데이터를 수집, 저장, 분석하는 백엔드 API입니다. Clean Architecture와 Domain-Driven Design 원칙을 따르며, 엔터프라이즈급 애플리케이션 구조를 갖추고 있습니다.
- 디바이스 그룹 등록 (시리얼 번호 기반)
- 디바이스 그룹 목록 조회
- 디바이스 그룹별 통계 (평균, 최소, 최대 온도, MKT)
- 디바이스 등록 (그룹별 연결)
- 디바이스 조회
- 디바이스별 온도 통계
- 온도 데이터 기록 (16진수 형식 지원)
- 디바이스별 온도 로그 조회
- Mean Kinetic Temperature (MKT) 계산
- SELECT FOR UPDATE를 이용한 row-level locking
- 동시 등록 방지 메커니즘
- 트랜잭션 기반 데이터 무결성 보장
- NestJS v11 - Progressive Node.js framework
- TypeScript - Type-safe development
- PostgreSQL - Production database
- Sequelize ORM - Database abstraction layer
- sequelize-typescript - TypeScript decorators for Sequelize
- class-validator - DTO validation
- class-transformer - Object transformation
- Joi - Configuration validation
- Jest - Unit & E2E testing framework
- Supertest - HTTP assertion library
- SQLite - In-memory database for tests
- Winston - Logging
- Swagger - API documentation
- Terminus - Health checks
프로젝트는 엄격한 레이어 분리와 의존성 역전 원칙을 따릅니다:
src/
├── {feature}/
│ ├── presentation/ # Controllers, DTOs (API Layer)
│ ├── application/ # Services, Use Cases (Business Logic)
│ ├── domain/ # Domain Models, Interfaces
│ └── infra/ # Repository Implementations, Entities
├── common/ # Shared utilities, exceptions, config
└── database/ # Database configuration
presentation → application → domain ← infra
- Domain Layer: 비즈니스 로직의 핵심, 다른 레이어에 의존하지 않음
- Infrastructure Layer: Domain 인터페이스를 구현
- Application Layer: Use case 조율 및 비즈니스 로직 실행
- Presentation Layer: HTTP 요청/응답 처리
.env 파일을 프로젝트 루트에 생성:
# Database DB_HOST=localhost DB_PORT=5432 DB_USER=your_username DB_PASS=your_password DB_NAME=measurement_db # Application NODE_ENV=development PORT=3000
npm install
# 개발 모드 npm run start:dev # 프로덕션 빌드 npm run build npm run start:prod # 디버그 모드 npm run start:debug
디바이스 그룹 등록
{
"deviceGroupSerial": "GROUP-001"
}전체 디바이스 그룹 목록 조회
디바이스 그룹 통계 조회
- Query Parameters:
groupSerial: 그룹 시리얼 번호start: 시작 날짜 (YYYY-MM-DD)end: 종료 날짜 (YYYY-MM-DD)
디바이스 등록
{
"serialNumber": "DEVICE-001",
"deviceGroupSerial": "GROUP-001"
}디바이스 목록 조회 (그룹별 필터링 가능)
디바이스별 온도 통계 조회
온도 데이터 기록
{
"serialNumber": "DEVICE-001",
"interval": 60,
"temperatures": "00FA00FB00FC",
"registered_at": "2024年01月01日T12:00:00Z"
}디바이스별 온도 로그 조회
# 전체 테스트 실행 npm run test # Watch 모드 npm run test:watch # 커버리지 확인 npm run test:cov
npm run test:e2e
test/
├── {feature}/
│ ├── presentation/ # Controller tests
│ ├── application/ # Service tests
│ └── infra/ # Repository tests
├── config/ # Test configuration
└── concurrency/ # Concurrency tests
중요:
- Unit/E2E 테스트는 SQLite in-memory 데이터베이스 사용
- Concurrency 테스트는 PostgreSQL 필요 (SQLite의 트랜잭션 제한으로 인해)
id(PK, AUTO_INCREMENT)serial_number(UNIQUE)created_at
id(PK, AUTO_INCREMENT)serial_number(UNIQUE)device_group_id(FK → device_groups.id)created_at
id(PK, AUTO_INCREMENT)device_id(FK → devices.id)temperature(DECIMAL)recorded_atcreated_at
Production 환경(PostgreSQL)에서는 SELECT ... FOR UPDATE를 사용하여 동시 등록을 방지합니다:
// DeviceGroup 등록 시 await this.repository.findBySerial(serial, { lock: true, transaction });
이를 통해:
- Race condition 방지
- 중복 등록 차단
- 데이터 무결성 보장
npm run lint
npm run format
온도 데이터의 평균 동역학 온도를 계산하여 제공합니다.
공식:
MKT = (ΔH/R) / ln(Σ(e^(ΔH/RTi))/n) - 273.15
- ΔH (Activation Energy): 83,144 J/mol
- R (Gas Constant): 8.314 J/(mol·K)
16진수 형식의 온도 데이터를 signed 16-bit integer로 변환하여 처리합니다.
예시:
"00FA00FB00FC" → [25.0, 25.1, 25.2]°C
모든 쓰기 작업은 트랜잭션 내에서 실행되어 ACID 속성을 보장합니다.
UNLICENSED