28 KiB
NEW Web Configurator — Architecture Document
Version 3.0 | 2026-06-20 — reflects app v1.11.10 (Network Apply Engine + Wi-Fi AP + Firmware OTA) Supersedes: v2.2 (2026-05-28), v2.1 (2026-05-26), v2.0 (2026-05-22), v1.1 (2026-02-19), v1.0 (2026-02-12)
1. Overview
The NEW Web Configurator is a browser-based configuration tool for the Telechips TCC8030 IoT device. It is a Python-stdlib HTTP server plus a vanilla ES-module SPA (no build step), and it replaced a heavier legacy Java/Spring configurator (~436 MB → ~15–30 MB resident).
It reads and writes the device's board_config SQLite store. That store is
also used by two other programs on the device — the legacy Java app and the
dpworldapp data-processing binary — which makes storage ownership a
central concern of this document (see §6).
2. System Context
Three independent programs run on the device and all touch the same SQLite DB:
graph LR
Operator["운영자<br/>(브라우저)"]
Operator -->|":9090 직접"| WebCfg
Operator -->|":80 → nginx"| JavaApp
subgraph Device["IoT Device — TCC8030 (192.168.55.x)"]
WebCfg["Python Web Configurator<br/>systemd: web-configurator.service<br/>:9090"]
JavaApp["레거시 Java app-runner<br/>:8080 (nginx :80 프록시)"]
dpworld["dpworldapp<br/>CAN/Modbus/OPC-UA 데이터 처리"]
DB[("SQLite<br/>~/db/dynamic_data.db")]
WebCfg -->|R/W| DB
JavaApp -->|R/W| DB
dpworld -->|R/W| DB
end
- Python Web Configurator — this project. systemd-managed service on port 9090, reached directly (no reverse proxy in front of it).
- Legacy Java app-runner — a separate, still-running legacy app on 8080,
fronted by nginx on :80. Not part of this project, but it shares
board_config— see §6. - dpworldapp — the core data-processing binary. Reads config from
board_config, writes events toevent_history.
The original design docs assumed "nginx :80 → Python :8080". The actual device deployment is the layout above (Python direct on :9090, systemd- managed). See
DEPLOY.mdfor the deployment runbook.
위 3개 프로그램 외에 사용자의 별도 프로젝트 Super_Relay도 같은
board_config에 일부 키(security_config·transport_config)를 기록한다 — 소유권 상세는 §6.2.
3. Component Architecture
graph TB
subgraph Frontend["프론트엔드 — Vanilla ES-module SPA (빌드 없음)"]
AppJS["app.js — 라우팅·초기화·Save/Import/Export"]
ApiJS["api.js — REST 클라이언트"]
StateJS["state.js — 상태관리, flat↔nested 변환"]
ViewMode["view-mode.js — Two Faces (User/Advanced 토글)"]
Pages["pages/ — ~18 페이지<br/>(home·wifi·wifi-ap·ethernet·io·<br/>can·modbus·opcua·register·log·<br/>firmware·net-apply·…)"]
Shared["validator·utils·toast·constants·<br/>country-codes·components/"]
AppJS --> Pages --> ApiJS
AppJS --> ViewMode
Pages --> StateJS
Pages --> Shared
end
subgraph Backend["백엔드 — Python stdlib"]
Server["server.py — HTTP 라우팅·CORS·정적파일·진입점"]
DBMgr["db_manager.py — 3-tier SQLite 접근 레이어"]
Validator["config_validator.py — 서버측 검증·정규화"]
LogMgr["log_manager.py — 로그 관리·자동압축 데몬"]
KernelLog["kernel_log.py — 커널 로그 번들 (.tar.gz)"]
Status["system_status.py — Home 대시보드 상태 집계"]
Bundle["support_bundle.py — 진단 zip 생성"]
NetPkg["network/ — Network Apply Engine + Wi-Fi AP"]
FwPkg["firmware/ — Firmware OTA (TCP 8990)"]
Server --> DBMgr
Server --> Validator
Server --> LogMgr
Server --> KernelLog
Server --> Status
Server --> Bundle
Server --> NetPkg
Server --> FwPkg
end
ApiJS -->|HTTP REST| Server
3.1 Backend modules (src/*.py)
| 모듈 | 책임 |
|---|---|
server.py |
stdlib ThreadedHTTPServer + ConfigHandler. 모든 GET/POST 라우팅, 정적파일 서빙, 앱 진입점(main()) |
db_manager.py |
3-tier 설정 저장 레이어 — board_config 읽기/쓰기는 전부 이곳을 거침 |
config_validator.py |
device/protocol config 검증·정규화 (None 제거, 비활성 프로토콜 매핑 처리) |
log_manager.py |
dpworldapp 앱 로그(/opt/log/dpworldapp) 목록·다운로드 아카이브·수동/자동 압축·정리·통계, 그리고 5분 자동압축 데몬 |
kernel_log.py |
(v1.1.0) 커널 로그 번들 빌더 — systemd 저널을 journalctl로 텍스트 export + /opt/log 평문 커널 로그(kernel-follow.log/wifi-focus.log/boot-history/pstore) 사본 + 매니페스트 → .tar.gz 한 파일. journald 디렉터리(/opt/log/journal/)는 읽기 전용 (텍스트 export 방식). 시작 시 sweep_stale_temp_dirs()로 잔여 임시디렉터리 정리 |
system_status.py |
Home 대시보드용 디바이스 헬스 스냅샷 집계. v1.0.x 기본(core_app·communication·network·system) + (v1.2.0) hardware_modules (GNSS FW + WiFi FW, /lib/firmware/amss.bin의 QC_IMAGE_VERSION_STRING 토큰 + dpworldapp 로그의 [GNSS FW VER : ...]) + (v1.2.1) chunk-boundary 안전 line-iter 스캐너로 교체 (FWVE 16KB tail 누락 버그 fix) + (v1.3.0) dpworldapp_status (7개 startup phase tracker + 5개 result 상태 [healthy/starting/hung/failed/unknown] + 6개 runtime config 필드 equipment·protocol+endpoint·can_input/type/speed·speed_data·odo_speed.source·odo_dir.source). 모든 신규 필드는 module-level cache + threading.Lock로 lazy-load (서비스 재시작 전까지 영구 캐시) |
support_bundle.py |
진단 zip 생성 (상태 + 마스킹된 config + 최신 로그 + OS 진단) — "빠른 스냅샷" 용도. 전체 커널 저널이 필요하면 kernel_log.py의 별도 번들 사용 |
config_validator.py |
device/protocol config 검증·정규화 (None 제거, 비활성 프로토콜 매핑 처리) — dpworldapp 가 기대하는 JSON 형식 보장 |
enum_normalizer.py |
enum 값의 case-only 입력 정규화("ON"→"on"). 의미 추측은 의도적 제외 |
dpworldapp_enums.py |
device/protocol enum 허용집합 — 배포 바이너리 검증 계약과 일치. validator 가 reject 판정에 사용 |
dpworldapp_telemetry.py |
(v1.5.5) dpworldapp telemetry 스트림(TCP 8989) 파서 — connect→헤더 frame parse→disconnect 의 stateless query 로 정적 정보(firmware version/MAC/IP) 수집 |
migrations.py |
기동 시 1회 실행 마이그레이션 — schema_meta 테이블로 게이트(board_config 경합 회피). CanSpeed Integer 정합 등 |
3.1.1 src/network/ — Network Apply Engine + Wi-Fi AP (v1.6.0~)
웹에서 입력한 네트워크 22항목을 dpworldapp 파일 계약과 byte-exact 로 렌더해 즉시 적용·검증·롤백하고, 상시 watchdog 로 자가복구한다. Wi-Fi AP(소프트 AP, ap0) 서브시스템도 같은 패키지에 있다.
| 모듈 | 책임 |
|---|---|
apply_engine.py |
apply 상태머신(STAGING→APPLYING→VERIFYING→CONFIRM_WAIT→COMMITTED). 단일 in-flight, DB-first 쓰기, confirm TTL(90s) 타이머, 크래시 복구, country split-apply(비country 즉시 / country deferred) |
netmodel.py |
22항목 집합 — DB device_config ↔ intent ↔ persist JSON 매핑 + dpworldapp 네트워크-필드 비교 정합 의미론 |
renderer.py |
intent → dpworldapp byte-호환 파일 렌더(캡처 golden 과 1바이트도 안 틀리게) |
validator.py |
§5.2 hard rule — SSID/PSK 바이트 길이·security·IPv4 등 dpworldapp 파서 한계 위반 차단 |
snapshot.py |
apply 전 백업 + manifest 해시 검증 + 롤백 복원(last-known-good) |
verifier.py |
사후 검증(존재→carrier→주소·라우트→wpa_state→gateway ping). carrier 없음 = "config staged" WARN |
watchdog.py |
상시 감시·자가복구(30s 틱, 히스테리시스·cooldown·시간당 한도). 적용본(network_config.json) 기준 |
journal.py |
JSONL 네트워크 이벤트 저널(5MB×3 로테이션, psk/password 마스킹) + forensic 번들 |
net_routes.py |
/api/network/* 라우트 글루(서버 독립적·dict in/out) |
ap_engine.py |
Wi-Fi AP apply 오케스트레이션 — hostapd/udhcpd conf 렌더 + dpworld-ap-apply.service 트리거 + 상태 persist. SCC(STA 채널 추종)·marker kill-switch |
ap_model.py |
ap_config DB 키 ↔ 정규화 intent (별도 board_config 키, device_config 무관) |
ap_renderer.py |
intent → hostapd-ap0.conf / udhcpd-ap0.conf 렌더(WPA2-PSK) |
ap_validator.py |
AP 필드 hard rule(SSID/PSK/채널/country) |
ap_routes.py |
/api/network/ap/* 라우트 글루. status 응답에서 ap_passphrase 제거(미인증 API) |
상세는 §5 API 표(Network Apply) 및 Wi-Fi AP는
wifi-ap-guide.md참조.
3.1.2 src/firmware/ — Firmware OTA (v1.5.0 Phase 4a~)
dpworldapp 의 FW-MMI 채널(TCP 8990)로 펌웨어 컴포넌트를 staging→flash 하는 OTA 서브시스템. 플래시 전 config 백업, 재부팅 후 복원 검사까지 오케스트레이션한다.
| 모듈 | 책임 |
|---|---|
fw_controller.py |
상태머신·8단계 phase stepper(upload·verify·preflight·backup·flash·commit·reboot·config) + 컴포넌트별 진행률. FirmwareController 단일 인스턴스, thread-safe |
staging.py |
업로드 ZIP 추출·컴포넌트 식별(.rom/.img/.ext4/.dtb)·sha256·free-space 확인 |
protocol.py |
dpworldapp FW-MMI 와이어 프로토콜(3바이트 signature + 8바이트 LE size + payload, ACK SUCCESS/FW_FAIL) |
fw_client.py |
TCP 8990 wire client — 컴포넌트 전송 + ACK 분류 + 진행 콜백 |
config_safety.py |
플래시 전 device_config/protocol_config 백업, 재부팅 후 factory-default reseed 감지 → 원자적 복원(단일 BEGIN IMMEDIATE 트랜잭션) |
fw_routes.py |
/api/firmware/* 라우트 글루 — 스트리밍 ZIP 업로드(디스크 /opt 버퍼, tmpfs 금지) |
상세는
firmware-ota-guide.md참조.
3.2 Frontend (src/static/js/)
- Core:
app.js(라우팅·초기화·저장),api.js(fetch 래퍼),state.js(상태·flat↔nested 변환),view-mode.js(Two Faces — User 기본 / Advanced 토글, body 클래스로.user-only/.advanced-only구동) - Shared:
validator.js,utils.js(escapeHtml),toast.js,constants.js(기본값 +APP_VERSION),country-codes.js(WiFi 국가코드) components/:crud-table.js,ip-input.jspages/(~18개):home(Dashboard),wifi,wifi-ap,ssid,ethernet,network/server-setting,general-settings,io/sensor-io,can/can-bus,modbus,opcua,register,log,firmware(OTA),net-apply(Apply & Status — Advanced 전용)- Two Faces (v1.8.0): 기본 User 보기(운영자용 간소 동선)와 Advanced 보기(네트워크 Apply & Status 등 고급 기능)를 토글한다.
net-apply같은 Advanced 전용 페이지는 User 모드에서 nav 숨김 + 라우트 가드로 이중 차단
4. Data Flow
4.1 설정 조회 / 저장
sequenceDiagram
participant B as Browser
participant P as Python Web Configurator
participant D as SQLite DB
B->>P: GET /setting/get-device
P->>D: SELECT device_config, log_config
P-->>B: 200 — 두 키를 병합한 단일 JSON
B->>P: POST /setting/device {JSON}
P->>P: 검증 · None 제거 · 로그설정 분리
P->>D: device_config 저장 (로그설정 제외)
P->>D: log_config 저장 (로그설정 4개)
P-->>B: 200 success
로그 설정 분리(v1.0.2): 클라이언트는 변함없이 하나의 device config를 주고받지만,
server.py가 저장 시 로그 자동압축/정리 설정 4개를log_config키로 떼어내고, 조회 시 다시 합쳐서 내려준다. 이유는 §6.3.
4.2 로그 자동압축 데몬
main()이 백그라운드 데몬 스레드를 띄운다. 5분마다:
log_config에서log_auto_compress/log_auto_cleanup확인- 켜져 있으면 — 비활성(active 아님) 로그를
<로그명>.<mtime>.tar.gz로 압축, 오래된 압축 아카이브를 임계치까지 정리
5. API Contract
기존 Java 앱과 호환되는 /setting/* 엔드포인트 + 신규 /api/* 엔드포인트.
| Method | Path | 핸들러 | 용도 |
|---|---|---|---|
GET |
/setting/get-device |
_handle_get_device |
device + log config 조회(병합) |
GET |
/setting/get-protocol |
_handle_get_protocol |
protocol config 조회 |
GET |
/setting/log-files |
_handle_get_log_files |
로그 파일 목록 |
GET |
/setting/log-stats |
_handle_get_log_stats |
로그 디스크 사용량 통계 |
GET |
/setting/kernel-bundle |
_handle_get_kernel_bundle |
(v1.1.0) 커널 로그 번들 .tar.gz 즉석 생성·스트리밍 (journalctl 텍스트 export + 평문 커널 로그 + boot-history + pstore + manifest) |
GET |
/api/health |
_handle_health |
서버 헬스(uptime·DB 백엔드) |
GET |
/api/mac |
_handle_get_mac |
WiFi MAC (장비 식별) |
GET |
/api/system-status |
_handle_system_status |
Home 대시보드 종합 상태. 응답: core_app·communication·network·system (v1.0.x) + hardware_modules (v1.2.0, GNSS FW + WiFi FW) + dpworldapp_status (v1.3.0, 7 phases + result + runtime config). 모두 top-level key, 후방 호환 |
GET |
/api/support-bundle |
_handle_support_bundle |
진단 zip 다운로드 |
POST |
/setting/device |
_handle_post_device |
device config 저장(로그설정 분리) |
POST |
/setting/protocol |
_handle_post_protocol |
protocol config 저장 |
POST |
/setting/log-download |
_handle_post_log_download |
선택 로그 tar.gz 다운로드 |
POST |
/setting/log-compress |
_handle_post_log_compress |
수동 압축 |
POST |
/setting/log-delete |
_handle_post_log_delete |
선택 로그 삭제 |
POST |
/api/action/test-connections |
_handle_test_connections |
설정된 서버 TCP 연결 테스트 |
POST |
/api/action/restart-dpworldapp |
_handle_restart_dpworldapp |
dpworldapp 재시작 |
Firmware OTA (v1.5.0 Phase 4a) — 상세 firmware-ota-guide.md
| Method | Path | 용도 |
|---|---|---|
GET |
/api/firmware/status |
OTA 상태 스냅샷(phase stepper + 컴포넌트 진행률 + slot) |
POST |
/api/firmware/preflight |
플래시 전 게이트 체크리스트(staging·여유공간·FW 포트·DB·slot) |
POST |
/api/firmware/upload |
펌웨어 ZIP 스트리밍 업로드 → staging(/opt 버퍼) |
POST |
/api/firmware/flash |
staged 컴포넌트 플래시 시작(백그라운드 워커) |
POST |
/api/firmware/restore-check |
재부팅 후 config reseed 감지 → 복원 + dpworldapp 재시작 |
Network Apply (v1.6.0) — 상세 per-subsystem 가이드
| Method | Path | 용도 |
|---|---|---|
GET |
/api/network/state |
현재 적용 상태머신 스냅샷 |
GET |
/api/network/drift |
DB ↔ network_config.json 22항목 미적용 drift 카운트(경량) |
GET |
/api/network/apply/status (?id=) |
특정 apply 진행 상태 |
GET |
/api/network/journal (?limit=) |
네트워크 이벤트 저널 tail |
GET |
/api/network/config |
watchdog 등 효과적 net_config 조회 |
POST |
/api/network/apply |
22항목 적용 시작(즉시 적용 + confirm 대기) |
POST |
/api/network/apply/confirm |
적용 확정(미확정 시 TTL 만료 → 자동 롤백) |
POST |
/api/network/rollback |
last-known-good 롤백 |
POST |
/api/network/config |
watchdog kill-switch 등 net_config 쓰기 |
Wi-Fi AP (v1.11.x) — 상세 wifi-ap-guide.md
| Method | Path | 용도 |
|---|---|---|
GET |
/api/network/ap/status |
AP 라이브 상태(ap_passphrase 제거됨) |
POST |
/api/network/ap/config |
ap_config 저장(필드 화이트리스트 merge) |
POST |
/api/network/ap/apply |
AP bring-up/down 적용(또는 dry_run) |
네트워크/AP 서브시스템 import 실패 시(예: Windows dev box) 해당 라우트는 503 으로 fail-soft.
OPTIONS는 CORS preflight(204). 알 수 없는 /api/·/setting/ 경로는 404(SPA 폴백 마스킹 방지, v1.5.0). 그 외 GET은 SPA 정적파일 폴백.
6. Database — board_config 소유권 ⭐
~/db/dynamic_data.db는 세 프로그램이 공유한다. 이 절은 무엇이 누구
소유인지 명확히 한다 — 잘못 건드리면 다른 앱의 데이터가 깨진다.
6.1 테이블
CREATE TABLE board_config (key TEXT PRIMARY KEY NOT NULL, value TEXT NOT NULL);
CREATE TABLE event_history (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT NOT NULL);
board_config— Key-Value 설정 저장소. Python 이 쓰는 키는 5개 (db_manager.ALLOWED_KEYS), 그 외 다른 프로그램 소유 키도 같은 테이블에 공존event_history— 이벤트 큐. dpworldapp이 WRITE, Web Configurator는 건드리지 않음
6.2 board_config 키별 소유권 — 우리 / Java / dpworldapp
| key | 쓰기 주체 | 소유 구분 |
|---|---|---|
device_config |
Python Web Configurator + 레거시 Java 앱 | ⚠️ 공유(경합) |
protocol_config |
Python Web Configurator + 레거시 Java 앱 | ⚠️ 공유 계약 |
log_config |
Python Web Configurator | 🟦 우리 (v1.0.2 신설) |
net_config |
Python Web Configurator | 🟦 우리 (v1.6.0 — watchdog 등 Network Apply 설정) |
ap_config |
Python Web Configurator | 🟦 우리 (v1.11.x — Wi-Fi AP 설정) |
security_config |
Super_Relay 프로젝트 | 🟧 타 프로젝트 |
transport_config |
Super_Relay 프로젝트 | 🟧 타 프로젝트 |
- 🟦 우리(Python Web Configurator)가 쓰는 것 — Python의
db_manager.ALLOWED_KEYS는{device_config, protocol_config, log_config, net_config, ap_config}(5개). Python 은 이 5개만 쓴다.device_config·protocol_config는 dpworldapp/Java 와의 공유 계약 (Java schema 그대로 — [board_config 키 ownership 정책]),log_config·net_config·ap_config는 Python 전용(Java/dpworldapp 가 읽지 않음). Python 전용 키를 별도로 둔 이유는 §6.3. - 🟧 다른 프로젝트(Super_Relay)가 쓰는 것 —
security_config,transport_config. 사용자의 별도 프로젝트 Super_Relay (c:/Development/Super_Relay)가 자체config_bridge.py로 같은board_config테이블에 기록한다 — 릴레이 전송 설정 (transport_config:relay_enabled/type/base_url;security_config: Bearer 인증 토큰). NEW Web Configurator는 이 두 키를 읽지도 쓰지도 않으며, 레거시 Java 앱과도 무관하다. (2026-05-22 검증: DB의 JSON 내용 + Super_Relay 프로젝트 grep으로 확인.) event_history— dpworldapp 소유.
6.3 ⚠️ device_config는 공유 행 — 그래서 log_config가 생겼다
device_config는 Python Web Configurator와 레거시 Java 앱이 둘 다 쓴다.
Java 앱이 자기 데이터 모델로 device_config를 저장하면 Java가 모르는
Python 전용 필드가 통째로 사라진다.
이 때문에 로그 자동압축/정리 설정(log_auto_compress, log_auto_cleanup,
log_cleanup_max_files, log_cleanup_max_size_mb)이 실제로 날아갔고
자동압축 데몬이 조용히 멈췄다. 해결(v1.0.2): 이 4개를 Java가 안 건드리는
별도 log_config 키로 분리. board_config 키 소유권은 db_manager.ALLOWED_KEYS를 참고.
원칙: 앞으로 추가하는 Python 전용 설정은
device_config/protocol_config에 넣지 말 것. Java/dpworldapp 가 덮어쓴다. 별도 키를 만들고db_manager.ALLOWED_KEYS에 등록한다 —log_config(v1.0.2)·net_config(v1.6.0)·ap_config(v1.11.x)가 이 패턴이다.
6.4 db_manager 3-tier 백엔드
db_manager.py는 환경에 따라 백엔드를 자동 선택한다: ① Python sqlite3
모듈(기본), ② sqlite3 CLI(subprocess), ③ JSON 파일 폴백(임시용). save_config은
"database is locked" 시 신선한 커넥션으로 재시도한다(v1.0.1).
7. Directory Structure
NEW_Web_Configurator/
├── src/ ← 애플리케이션 (배포 단위)
│ ├── server.py ← 진입점, HTTP 서버
│ ├── db_manager.py ← SQLite 3-tier 접근
│ ├── config_validator.py ← 서버 검증
│ ├── enum_normalizer.py ← enum case-only 정규화
│ ├── dpworldapp_enums.py ← enum 허용집합 (device 계약)
│ ├── dpworldapp_telemetry.py ← TCP 8989 telemetry 파서
│ ├── migrations.py ← 기동 시 1회 마이그레이션
│ ├── log_manager.py ← 로그 관리 + 자동압축 데몬
│ ├── kernel_log.py ← 커널 로그 번들
│ ├── system_status.py ← 대시보드 상태 집계
│ ├── support_bundle.py ← 진단 zip
│ ├── network/ ← Network Apply Engine + Wi-Fi AP
│ │ ├── apply_engine·netmodel·renderer·validator
│ │ ├── snapshot·verifier·watchdog·journal·net_routes
│ │ └── ap_engine·ap_model·ap_renderer·ap_validator·ap_routes
│ ├── firmware/ ← Firmware OTA (TCP 8990)
│ │ └── fw_controller·fw_client·protocol·staging·config_safety·fw_routes
│ └── static/
│ ├── index.html
│ ├── css/style.css
│ ├── img/dp-world-logo.svg
│ └── js/ app·api·state·view-mode·validator·utils·toast·constants·country-codes
│ ├── components/ crud-table·ip-input
│ └── pages/ home·wifi·wifi-ap·ssid·ethernet·io·can·modbus·
│ opcua·register·log·firmware·net-apply· … (~18)
├── deploy/ ← systemd 유닛 + AP/network apply 셸 스크립트
├── tests/ ← pytest(~1557) + node/jsdom(~392) 스위트
├── scripts/deploy.ps1 ← 버전 태그 기반 디바이스 배포 스크립트
├── docs/ ← 문서 (본 문서, wifi-ap-guide, firmware-ota-guide, specs/, …)
├── CHANGELOG.md README.md .gitignore
디바이스 배포 위치:
/usr/lib/web-configurator/src/(systemd가 구동, port 9090).deploy/의 systemd 유닛·셸 스크립트는 rootfs/lib/systemd등에 설치되며 flash 마다 wipe 된다(§10 caveat,wifi-ap-guide.md참조).
8. Versioning & Deployment
- 버전 체계:
vMAJOR.MINOR.PATCH시맨틱 버전. 단일 소스 =APP_VERSION(src/static/js/constants.js), 사이드바 표시. 현재 v1.11.10. - 릴리스:
APP_VERSION갱신 →CHANGELOG.md항목 → 커밋 →git tag vX.Y.Z. - 배포:
scripts/deploy.ps1 <device-ip>— 버전 태그 검사 →src/아카이브 전송 → 장비 백업 → 스왑 →DEPLOYED_VERSION기록 → systemd 재시작 → 검증. 절차·롤백 상세는DEPLOY.md.
9. 기술 제약사항
| 항목 | 제약 | 대응 |
|---|---|---|
| Python | stdlib만 (pip 없음) | http.server·sqlite3·json·tarfile 등 |
| 메모리 | 목표 경량 | 레거시 Java ~436MB → Python ~15–30MB |
| 빌드 도구 | Node/npm 없음 | Vanilla ES-module JS (빌드 불필요) |
| 공유 DB | Java 앱·dpworldapp과 SQLite 공유 | §6 소유권 규칙 준수, 별도 키 분리 |
| 디바이스 구동 | systemd web-configurator.service :9090 |
DEPLOY.md 참고 |
10. 보안 고려사항
| 현재 상태 | 비고 |
|---|---|
| 인증 없음 | HTTP API(:9090)는 현재 완전 미인증 — 17개 mutation endpoint + wildcard CORS. 이것이 문서화된 threat boundary(폐쇄 LAN 단일 운영자 전제). 운영자 로그인은 설계 완료·구현 백로그 상태. |
| CORS 전체 허용 | 의도된 설계 (IoT LAN 전용) |
| HTTP only | TLS 미구현. 운영자 로그인 spec 의 known-limitation(평문) 참조 |
| SQL Injection | db_manager가 키 화이트리스트(ALLOWED_KEYS)로 방어 |
| XSS | 출력은 escapeHtml 경유 |
| Support bundle | config 내 WiFi 비밀번호 마스킹 후 포함 |
| API 응답 마스킹 | AP status/apply(dry_run) 응답에서 ap_passphrase 제거. /api/health 는 db path/pid 미노출 |
| Wi-Fi AP 접근 게이트 | v1.11.7 이후 AP INPUT 전면 개방(SSH 포함) — WPA2 PSK 가 게이트. FORWARD 차단으로 PLC/업링크 격리(wifi-ap-guide.md) |
이전 메커니즘 제거됨: 과거 문서가 언급하던 systemd
WEB_AUTH_USER/PASS(옵션 Basic 인증) 및WEB_SSL_CERT/KEY(옵션 HTTPS) 환경변수 인증은 현재 코드/유닛에 존재하지 않는다. 인증 방향은 위의 operator-login 설계로 대체되었다(아직 미구현).
11. 변경 이력
| 일자 | 버전 | 변경 |
|---|---|---|
| 2026-02-12 | doc v1.0 | 초기 작성 |
| 2026-02-19 | doc v1.1 | 디렉터리·보안·건강상태 섹션 |
| 2026-05-22 | doc v2.0 | 앱 v1.0.2 기준 전면 갱신 — 실제 배포 구조(systemd :9090), 6개 백엔드 모듈·9개 페이지, 전체 API 라우트, §6 board_config 소유권(우리/Java/Super_Relay/dpworldapp 구분), log_config 분리, 버전관리·배포 섹션 |
| 2026-05-26 | doc v2.1 | 앱 v1.1.0 — Kernel Log Bundle 기능 — 신규 모듈 kernel_log.py (§3.1), 신규 엔드포인트 GET /setting/kernel-bundle (§5). /opt/log/journal/은 journald 소유로 읽기 전용 처리(텍스트 export). 임시작업 디렉터리는 /opt 디스크에 (메모리 제약 장비에서 /tmp tmpfs 회피). DB 스키마·소유권 변경 없음 |
| 2026-05-28 | doc v2.2 | 앱 v1.2.0 → v1.2.1 → v1.3.0 누적 반영. v1.2.0 Hardware Modules 카드 — Home 대시보드에 GNSS·WiFi 펌웨어 버전 표시 (amss.bin QC_IMAGE_VERSION_STRING 추출 + dpworldapp 로그 [GNSS FW VER] 스캔), /api/system-status에 hardware_modules 키 추가. v1.2.1 scanner 견고화 — 64KB chunk-boundary silent miss + 10MB cap 두 결함을 line-iter 기반으로 일괄 해결, locale-independent ISO date 파싱. v1.3.0 dpworldapp Status Tracker — 7 startup phase (FRAM→Steady) + 5 result 상태 + 6 runtime config 필드, /api/system-status에 dpworldapp_status 키 추가. 모두 module-level cache + threading.Lock. §3.1 system_status.py 책임 갱신, §5 payload key 목록 갱신. DB 스키마·소유권 변경 없음 |
| 2026-06-20 | doc v3.0 | 앱 v1.11.10 전면 동기화 (v1.4~v1.11 누적). 신규 백엔드 서브시스템 2종 — src/network/(Network Apply Engine v1.6.0 + Wi-Fi AP v1.11.x)·src/firmware/(Firmware OTA v1.5.0 Phase 4a) 및 신규 src/*.py(enum_normalizer·dpworldapp_enums·dpworldapp_telemetry·migrations) §3.1 추가. §5 API 표에 firmware/network/AP 엔드포인트 추가. §6 ALLOWED_KEYS 5키로 정정(net_config·ap_config Python 전용). §3.2 프론트 ~18 페이지 + Two Faces(User/Advanced). §7 디렉터리 트리 갱신. §10 보안 — 제거된 WEB_AUTH_USER/PASS/WEB_SSL 언급 삭제, API 미인증=문서화된 threat boundary 명시 + operator-login 설계(백로그) 링크. 신규 가이드 [wifi-ap-guide.md]·[firmware-ota-guide.md] 분리 |
관련 문서:
DEPLOY.md(배포·버전 런북) ·CHANGELOG.md(릴리스 변경 이력)