# 내 개발 환경 설정
- 계획서와 답변은 항상 한글로
- 테스트 및 검증은 내가 직접 수동으로 할것임.

## 공통 코딩 규약
- 모든 코드에 상세한 주석 포함
- 함수명은 카멜케이스 사용
- 오류 처리는 try-catch 블록 사용



# 프로젝트 개발 지침 및 주의사항

해당 프로젝트의 안정성과 데이터 일관성을 유지하기 위해 다음 지침을 반드시 준수하시기 바랍니다.

## ⚠️ 절대 주의 사항 (Critical)
* **PHP 직접 호출 금지:** 테스트나 디버깅 목적으로 서버 내의 PHP 파일을 직접 호출하여 실행하는 행위를 **절대 금지**합니다. 모든 비즈니스 로직 검증은 정해진 아키텍처 가이드라인에 따라 진행하십시오.

---

## 🗄️ 데이터베이스 참조 가이드
모든 데이터베이스 관련 작업(스키마 확인, 쿼리 작성, 데이터 구조 설계 등)은 아래의 최신 SQL 덤프 파일을 기준으로 합니다.

* **참조 경로:** `Y:\dorothy\go\REF\musago-db.sql`
* **주요 확인 내용:**
    * `musago` 데이터베이스의 테이블 스키마 및 데이터 타입
    * 인덱스(Index) 및 외래 키(Foreign Key) 설정
    * 기본 데이터 삽입 구조
# musago DB 비즈니스 로직 정리

## 1. tblCompany — 회사 계층 구조

| 컬럼 | 설명 |
|---|---|
| `compCd` | 해당 회사의 고유 코드 |
| `gCompCd` | 본점 회사 코드 (Group Company Code) |

### 본점 vs 지점 판별 규칙

```
gCompCd == 9999  →  본점 (자기 자신이 본점)
gCompCd != 9999  →  지점 (gCompCd 값이 소속된 본점의 compCd)
```

### 예시

```
compCd=100, gCompCd=9999  →  100번 회사는 본점
compCd=101, gCompCd=100   →  101번 회사는 지점, 본점은 100번
```

---

## 2. tblWorker — 근로자의 소속 회사 확인

`tblWorker.gCompCd` → `tblCompany.compCd` 로 조인하여 본점/지점 여부 확인

### 예시

| tblWorker.gCompCd | tblCompany (compCd=해당값) | 해석 |
|---|---|---|
| 100 | gCompCd=9999 | 근로자는 본점(100) 소속 |
| 101 | gCompCd=100 | 근로자는 지점(101) 소속, 본점은 100번 |

---

## 3. tblDevice — 장치의 본점/지점 할당 관계

| 컬럼 | 설명 |
|---|---|
| `gCompCd` | 장치를 소유한 본점 코드 |
| `sCompCd` | 장치가 실제 할당된 회사 코드 (Sub Company Code) |

### 본점 장치 vs 지점 할당 장치 판별 규칙

```
sCompCd == 0           →  본점 장치 (미할당)
sCompCd == gCompCd     →  본점 장치 (본점이 직접 사용)
sCompCd != gCompCd     →  지점 할당 장치 (sCompCd가 할당된 지점의 compCd)
```

### 예시

| 시리얼 | gCompCd | sCompCd | 해석 |
|---|---|---|---|
| 1004 | 100 | 0 | 본점(100) 장치, 미할당 |
| 1004 | 100 | 100 | 본점(100) 장치, 본점이 직접 사용 |
| 1004 | 100 | 101 | 본점(100) 소유, 지점(101)에 할당됨 |

> **지점 확인 경로:** `tblDevice.sCompCd` → `tblCompany.compCd` 조회 → 해당 row의 `gCompCd`가 본점 코드

---

## 4. 전체 관계 요약

```
tblCompany (compCd=100, gCompCd=9999)  ← 본점
    └─ tblCompany (compCd=101, gCompCd=100)  ← 지점
    └─ tblWorker (gCompCd=100 or 101)        ← 근로자
    └─ tblDevice (gCompCd=100)               ← 장치 소유
            └─ sCompCd=0 or 100  → 본점 사용
            └─ sCompCd=101       → 지점 할당
```

---

# 안전신호등 (SigLight) 개발 내역

## 관련 파일
- `musago/apiSigLight.php` — 안전신호등 API (신규 생성)
- `common/libMiscFunc.php` — do_update_siglight_* 함수 추가됨

---

## tblSigLightDev — 기기 정보 테이블

```sql
CREATE TABLE `tblSigLightDev` (
    `serialNo`      VARCHAR(20)     NOT NULL DEFAULT '',
    `gCompCd`       INT             NOT NULL DEFAULT 0,
    `devNm`         VARCHAR(64)     NOT NULL DEFAULT '',
    `bdaddr`        VARCHAR(32)     NOT NULL DEFAULT '',
    `operMode`      VARCHAR(16)     NOT NULL DEFAULT 'auto',
    `fcmEnF`        CHAR(1)         NOT NULL DEFAULT 'Y',
    `eventYN`       CHAR(1)         NOT NULL DEFAULT 'N',
    `flagYN`        CHAR(1)         NOT NULL DEFAULT 'Y',
    `lat`           VARCHAR(256)    NOT NULL DEFAULT '',  -- AES 암호화 (키: serialNo)
    `lng`           VARCHAR(256)    NOT NULL DEFAULT '',  -- AES 암호화 (키: serialNo)
    `loc`           VARCHAR(512)    NOT NULL DEFAULT '',  -- AES 암호화 (키: 'a')
    `locImgNm`      VARCHAR(128)    NOT NULL DEFAULT '',
    `regDate`       DATETIME        NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `issueDate`     DATETIME        NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`serialNo`),
    INDEX `idx_gcomp` (`gCompCd`),
    INDEX `idx_flag`  (`gCompCd`, `flagYN`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='안전신호등 기기 정보';
```

---

## tblSigLightEvent — 이벤트 이력 테이블

```sql
CREATE TABLE `tblSigLightEvent` (
    `seqNo`         BIGINT          NOT NULL AUTO_INCREMENT,
    `gCompCd`       INT             NOT NULL DEFAULT 0,
    `serialNo`      VARCHAR(20)     NOT NULL DEFAULT '',
    `devNm`         VARCHAR(64)     NOT NULL DEFAULT '',
    `ecode`         VARCHAR(32)     NOT NULL DEFAULT 'def',
    `sts`           VARCHAR(16)     NOT NULL DEFAULT '00000000',
    `lightColor`    VARCHAR(16)     NOT NULL DEFAULT 'green',  -- 'red'|'yellow'|'green'
    `lightRed`      TINYINT(1)      NOT NULL DEFAULT 0,
    `lightYellow`   TINYINT(1)      NOT NULL DEFAULT 0,
    `lightGreen`    TINYINT(1)      NOT NULL DEFAULT 0,
    `operMode`      VARCHAR(16)     NOT NULL DEFAULT 'auto',
    `fcmEnF`        CHAR(1)         NOT NULL DEFAULT 'Y',
    `batt`          VARCHAR(16)     NOT NULL DEFAULT '0',  -- 배터리 전압 (예: '3.44')
    `lat`           VARCHAR(256)    NOT NULL DEFAULT '',  -- AES 암호화 (키: serialNo)
    `lng`           VARCHAR(256)    NOT NULL DEFAULT '',  -- AES 암호화 (키: serialNo)
    `loc`           VARCHAR(512)    NOT NULL DEFAULT '',  -- AES 암호화 (키: 'a')
    `stDate`        DATE            NOT NULL DEFAULT '2000-01-01',
    `stTime`        TINYINT         NOT NULL DEFAULT 0,
    `regDate`       DATETIME        NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`seqNo`),
    INDEX `idx_gcomp_date`  (`gCompCd`, `stDate`),
    INDEX `idx_serial_date` (`serialNo`, `stDate`),
    INDEX `idx_stdate`      (`stDate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='안전신호등 이벤트 이력';
```

---

## apiSigLight.php 구조

| cmd | opt | 설명 |
|-----|-----|------|
| `update` | `dev-info` | 기기명 + 위치(lat/lng/loc) + locImgNm 수정 |
| `update` | `dev-name` | 기기명만 수정 |
| `update` | `dev-loc` | 위치(lat/lng/loc) + locImgNm 수정 |
| `update` | `fcm-enf` | FCM 알림 여부 수정 |
| `get` | `list` | gCompCd 기준 기기 목록 + 최신 이벤트 조인 |
| `get` | `each-detail-pack` | 기기별 상세 (미구현) |

### get - list 쿼리 패턴
- `tblSigLightDev` 기준으로 `flagYN = 'Y'` 인 기기 조회
- `tblSigLightEvent` 에서 `MAX(seqNo)` 기준 최신 이벤트 LEFT JOIN
- lat/lng 복호화: `AES_DECRYPT(UNHEX(D.lat), D.serialNo)`
- loc 복호화: `CAST(AES_DECRYPT(UNHEX(D.loc), 'a') AS CHAR)`

---

## libMiscFunc.php 추가 함수

```
do_update_siglight_dev_info($db_conn, $serialNo, $devNm, $loc, $lat, $lng, $locImgNm)
do_update_siglight_dev_name($db_conn, $serialNo, $devNm)
do_update_siglight_dev_loc($db_conn, $serialNo, $lat, $lng, $loc, $locImgNm)
do_update_siglight_fcm_enf($db_conn, $serialNo, $EnF)
```

## 암호화 규칙 (프로젝트 공통)

| 컬럼 | 암호화 키 | 복호화 |
|------|-----------|--------|
| lat, lng | serialNo | `AES_DECRYPT(UNHEX(lat), serialNo)` |
| loc (위치 문자열) | `'a'` | `CAST(AES_DECRYPT(UNHEX(loc), 'a') AS CHAR)` |
