2026-08-15 PulseUp 작업일지입니다. 오늘은 7건의 작업을 진행했습니다.
모니터 이미지 저장 — 운영 URL 검증 실패 수정
현상/기능
- 이미지는 올라갔는데 저장 시 "이미지 URL 형식이 올바르지 않습니다"
작업
- 운영 `VITE_API_URL=/api` 이면 origin이 빈 값이 되어 `/uploads/...`만 남고, 저장 검증이 `http(s)://`만 허용해 막혔다. 상대경로일 때 `window.location.origin`을 쓰고, `/uploads`도 유효한 형식으로 받는다
- **Web** · `utils/`
배포 후 이미지 업로드 — nginx `/uploads` 프록시 정리
현상/기능
- 서버에서 가져온 pulsebox.conf에 필요한 부분만 추가/수정하고 불필요 부분은 삭제
작업
- `alias`+`try_files/uploads` 블록을 API(3002) `proxy_pass`로 바꿨다. 443에 `client_max_body_size 80m`을 넣고, IP 테스트용 8080 서버 블록은 삭제했다. Certbot HTTP→HTTPS 블록은 유지했다
- **서버** · · `uploads/electron-logs/.../pulsebox.conf`
ANT+ 슬롯 — 숫자·연결/해제 표시 지연 단축
현상/기능
- 슬롯 숫자·표시·enable/disable 상태 변화가 느리다
작업
- 무수신 판정을 20초에서 5초로, 점검 주기를 5초에서 1초로 줄였다. 연결 이벤트에서 카드를 바로 만들고, 카드 CSS transition을 제거했다. 지점 기기명은 매니저 생성 시 미리 불러 첫 표시가 늦지 않게 했다
ANT+ 슬롯 — 전원 ON 직후 DeviceID만으로 즉시 배정
현상/기능
- 심박기기를 켰을 때 슬롯이 더 빨리 나오게
작업
- `heart-rate-modules/`
- 신규 기기는 유효 HR(20~250)을 기다리지 않고 DeviceID 첫 패킷에서 빈 슬롯을 붙인다. BPM·서버 저장은 기존처럼 유효 HR만 반영한다
심박 저장 최적화 2단계 — 전용 풀·전역 슬롯·인덱스 정리
현상/기능
- 서버/DB 2단계 진행
작업
- 심박 UPSERT 는 기본 풀과 분리한 전용 풀(기본 6연결)로 보낸다. 다지점 동시 쓰기는 전역 슬롯(기본 4개, 3초 대기 후 429)으로 제한한다. 단일 문장 UPSERT 에서 명시적 트랜잭션과 `created_at` 갱신을 뺐다. 모듈은 풀/슬롯을 각각 분리했다
- `heart_rate_data` 에서 중복 보조 인덱스 6개(`idx_user_id`, `idx_workout_history_master_id`, `idx_device_id`, `idx_zone`, `idx_timestamp`, `idx_slot_number`)를 제거한다. UPSERT 유니크와 조회용 복합 인덱스 2개만 남긴다. 90일 이전 행을 지우는 `sp_PurgeHeartRateData` 를 추가하되 자동 실행은 하지 않는다. UUID PK 교체는 테이블 복사 락이 커서 이번엔 보류
- **API** · `lib/`(신규) · `lib/`(신규) · `services/` · `routes/` · `lib/`
- **DB** · `migrations/20260815_heart_rate_data_write_indexes.sql` · `_v2-schema.sql`
리모컨 심박 진단 — 정상 격자 표본을 업로드 대기로 오인하던 문구 수정
현상/기능
- 리모컨에 "심박 업로드 대기 데이터가 있습니다. 네트워크와 로그인 세션 상태를 확인하세요." 가 뜬다
작업
- `getHeartRateDiagnostics`
- 5초 격자에 잠시 쌓인 `bufferCount` 와 빈 큐 파일(`queue.exists`)을 실패 대기로 보고 있었다. 실제 실패 큐 줄 수 또는 연속 업로드 실패가 있을 때만 그 문구를 낸다. 당시 로그는 POST 성공·큐 0줄이라 오탐이었다
심박계 매칭 — 기기명으로 Electron 연결, 화면은 기기 ID
현상/기능
- Electron 과는 기기명을 연결시키고, electron-app 표시는 기기 ID 로 해 달라. 지점 보유 심박계는 `PULS-084` / `HW9 10084` 형식이다
작업
- 배정 테이블의 기기명 끝 숫자(`HW9 10084` → `10084`)로 Electron `ant-10084`/`HR-10084` 를 같은 기기로 본다. 저장 `device_id` 는 지점 등록 ID(`PULS-084`)를 써서 참가자 조인과 맞춘다. 못 찾으면 기존처럼 운동 소유자로 저장한다
- (신규)
- 지점 심박계 목록을 받아 기기명 끝 숫자로 ANT ID 를 연결한다. 화면 카드와 저장 payload 모두 등록 기기 ID(`PULS-084`)를 쓰고, 카탈로그에 없을 때만 `HR-10084` 를 쓴다. 표시 포맷터는 `PULS-084` 를 자르지 않는다
- **API** · `lib/`(신규) · `services/`