You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
16 KiB

# BSP 통합 가이드 — Web Configurator v1.12.1
디바이스 이미지(Yocto/OE 등)에 포함하기 위한 **커밋 히스토리 없는 클린 스냅샷**입니다.
런타임 앱·systemd 유닛·샘플·문서와 optional nginx sample 설정만 들어 있고, 개발/내부 자료와 VCS 이력은 없습니다.
---
## 1. 런타임 구조
- **Python 3 애플리케이션, stdlib 전용** — pip·virtualenv·외부 패키지 없음.
- 실행 진입점: `python3 /usr/lib/web-configurator/src/server.py`
- 리슨 포트: **9090** (유닛의 `Environment=PORT=` 로 변경 가능)
- 앱은 기본적으로 `:9090`에서 직접 서비스됩니다. nginx `:80` reverse proxy는 optional이며, `deploy/nginx.conf`는 BSP가 필요할 때 쓰는 sample 설정입니다.
- 영속 상태 — **패키지에 없음**(런타임/다른 컴포넌트가 생성):
- DB: `/home/root/db/dynamic_data.db` (`DB_PATH`)
- 로그: `/opt/log/dpworldapp` (`LOG_DIR`)
> **nginx optional**: `scripts/deploy.ps1`는 nginx 설정을 설치하거나 수정하지 않습니다. BSP에서 `deploy/nginx.conf`를 사용할 때만 이미지 레이아웃에 맞게 설치하고, Python 앱 단독 프록시라면 `proxy_pass`를 `http://127.0.0.1:9090/` 로 맞추세요.
---
## 2. 설치 경로 (`do_install`)
| 소스 (이 패키지) | 디바이스 설치 위치 |
|---|---|
| `src/` | `${libdir}/web-configurator/src/` (`${libdir}` = `/usr/lib`) |
| `deploy/web-configurator.service` | `${systemd_system_unitdir}/` |
| `deploy/dpworld-*.service` | `${systemd_system_unitdir}/` (제품이 사용하는 유닛만) |
| `deploy/*.service.d/` | `${systemd_system_unitdir}/<unit>.service.d/` |
| `deploy/dpworld-*.sh` | 각 유닛의 `ExecStart=` 가 가리키는 경로 |
| `deploy/nginx.conf` | Optional nginx sample site config. BSP/firmware가 nginx를 별도로 소유하면 생략 가능 |
권장 전체 기능 설치 목록:
- 항상 설치: `src/`, `deploy/web-configurator.service`
Release v1.12.3 — 빈 디바이스 DB-init 안정화(fail-soft) + Wi-Fi AP DFS 채널 선택 v1.12.1 전달 이후의 v1.12.2·v1.12.3 변경을 함께 반영합니다. dpworldapp 공유 DB(device/protocol)·계약·원자적 쓰기 계약은 무변경. ■ v1.12.2 — 신규/빈 디바이스 DB-init 안정화 (fail-soft) 펌웨어 업데이트 직후 동기화 문제로 device_config/protocol_config 가 비어 있을 때, 웹이 그 값을 생성·덮어써 dpworldapp 의 시딩을 선점하는 문제를 차단. 협력사 DB-init fix(2ca0ac1)를 포함하되, 미초기화 시 예외를 던져 fresh device 를 중단시키던 부분을 fail-soft 로 대체(렌더는 적용, DB 쓰기만 skip). - db_manager: config_initialized(key) 단일 판정 신규 (존재 AND 비어있지 않은 dict; 빈 {} = 미초기화). - apply_engine: 미초기화 시 raise 제거 → 렌더/networkctl 은 적용하되 DB 미러 쓰기만 skip(journal warn). _write_db / _write_db_restore 동일 적용. _lkg_bookkeeping: all-absent baseline 의 LKG 승격 방지(fresh device). - server: 미초기화 응답 통일 — GET 204, POST 409 not_initialized(code 필드). - netmodel(F3): 비-dict / malformed WIFI_SSID 내성 — crash 대신 안전 degrade. - migrations: contract_canonical 을 device / protocol 로 분리, 각 키가 시딩될 때까지 독립 defer(seed-ordering). 기존 통합 플래그 하위호환 유지. - frontend(F2): device/protocolConfigAbsent 가드 — 로드 시 부재(204)였던 키를 Save All 로 생성하지 않도록 차단하고 안내 토스트 표시. ■ v1.12.3 — Wi-Fi AP 채널 선택 + 네트워크 즉시적용 검증 - ap_engine: DFS 인지 채널 선택 — STA 가 DFS/no-IR 5GHz(52–64·100–144)에 있어도 AP 가 맹목 추종하지 않고 비-DFS 채널 선택(2.4GHz STA 는 ch1–13 만 추종). parse_iw_link_beacon_int 추가 — MCC(AP≠STA 채널) 시 hostapd beacon_int 을 STA BSS 와 일치(QCA6490 &#34;STA/AP BI must match&#34;). AP 상태에 라디오-다운 사유(country_unset / channel_dfs / mcc_bi) 추가. - ap_renderer: render_hostapd 에 beacon_int 파라미터 추가(기본 100). - 즉시적용: 기존 systemctl start 방식 유지 — 디바이스 실측으로 재확인, 관련 내부 재작업 시도는 검토 후 원복(순변화 없음). ■ 기타 - api.js: 저장 실패 시 서버 errors 메시지를 사용자에게 노출. - 문서/버전: VERSION·constants.js → v1.12.3, RELEASE-NOTES §0, DELIVERABLE-MANIFEST, BSP-INTEGRATION 갱신. - MemoryMax 48M→128M(v1.11.16) 주석 정합화(fw_routes / watchdog / server).
1 month ago
- 네트워크 apply 사용 시 (**권장 = 직접 교체**): `deploy/dpworld-network-apply-hardened.sh` 의 내용을 **`/usr/bin/dpworld-network-apply.sh` 원본 이름으로 설치**(펌웨어 base 스크립트 교체). firmware-native base 유닛(`dpworld-network-apply.service`/`dpworld-network-seed.service`)이 그 경로를 호출하므로 자동 적용됨. **이 방식에서는 `20-hardened.conf` ExecStart override 드롭인은 설치하지 않습니다** (`scripts/deploy.ps1` 라이브 후적용 fallback 전용 — §7, `docs/firmware-boot-hardening.md`). 단, 온디맨드 apply 는 웹이 `systemctl start dpworld-network-apply.service` 로 호출하는데, boot-seed `Requires=` 가 seed(boot-only oneshot)를 `--boot` 모드로 재트리거합니다. seed 도 하드닝본이라 드롭인이 없어도 안전 통과하여 `systemctl start` 는 성공하지만(필수 아님), 그 불필요한 `seed --boot` 재실행을 회피하려면 **`10-ondemand.conf` 드롭인 베이킹을 권장**합니다(완화 overlay) — `deploy/dpworld-network-apply-ondemand.conf``/lib/systemd/system/dpworld-network-apply.service.d/10-ondemand.conf` 로 설치(§7, 아래 참고).
- Wi-Fi AP 사용 시: `deploy/dpworld-ap-apply.service`, `deploy/dpworld-ap-seed.service`, `deploy/dpworld-hostapd-ap0.service`, `deploy/dpworld-udhcpd-ap0.service`, `deploy/dpworld-ap-apply.sh`를 함께 설치
- 복구 유닛 사용 시: `deploy/dpworld-net-recover.service` 설치
- `*.sh``0755` 실행 권한으로 `/usr/bin/`에 설치
> 앱 코드 디렉토리 `/usr/lib/web-configurator` 는 `do_install` 이 이미지에 굽는 **read-only program code** 이므로 아래 쓰기 디렉토리 목록에 포함하지 않습니다.
쓰기 가능 런타임 디렉토리 생성 (recipe `do_install` / tmpfiles.d / 유닛의 `ExecStartPre` 중 택1):
```
/opt/log/dpworldapp /opt/fw_staging /opt/fw_upload
/opt/config_backups /home/root/db /home/root/network
```
---
## 3. 런타임 의존성 (`RDEPENDS`)
**stdlib 전용** — 앱이 import하는 python3 표준 모듈만 이미지에 포함하면 됩니다. (외부 패키지 없음)
OE의 모듈형 python3 기준 예시:
```
python3-core python3-sqlite3 python3-json python3-netserver python3-netclient
python3-compression python3-crypt python3-logging python3-datetime python3-threading
python3-shell python3-io python3-mime python3-stringold python3-ctypes
```
실제 import: `sqlite3, http(.server), socketserver, socket, urllib, json, gzip, tarfile,
zipfile, hashlib, subprocess, shlex, logging, datetime, ipaddress, mimetypes, struct,
tempfile, shutil, re, io, os, sys, time, copy, traceback` — 사용하는 OE python3 분할 패키지에 맞춰 확인하세요.
추가로 유닛이 런타임에 쓰는 시스템 패키지: nginx reverse proxy를 이미지에서 제공할 때만 `nginx`.
네트워크/AP 유닛 사용 시 `wpa-supplicant`, `hostapd`, `udhcpd`/`busybox`, `iproute2` 등.
---
## 4. systemd
```
SYSTEMD_SERVICE:${PN} = "web-configurator.service"
SYSTEMD_AUTO_ENABLE = "enable"
```
제품에서 필요한 `dpworld-*` 유닛(network-apply, Wi-Fi AP, recovery)을 추가하세요. 전체 기능 이미지에서는 보통 다음처럼 함께 등록합니다:
```
SYSTEMD_SERVICE:${PN} = "web-configurator.service \
dpworld-ap-seed.service \
dpworld-hostapd-ap0.service \
dpworld-udhcpd-ap0.service"
```
`dpworld-ap-apply.service``dpworld-net-recover.service`는 웹 설정기/watchdog이 on-demand로 `systemctl start` 하므로 `[Install]` 없이 설치만 하면 됩니다. `dpworld-network-apply.service`/`dpworld-network-seed.service`는 firmware-native base 유닛이며 `/usr/bin/dpworld-network-apply.sh` 를 호출합니다 — 본 패키지는 **그 base 스크립트를 하드닝본으로 교체**합니다(권장, §7). (펌웨어 원본을 교체할 수 없는 라이브 디바이스에서는 `.service.d` override 드롭인이 fallback.)
---
## 5. 샘플 레시피 — `web-configurator_1.12.1.bb`
```bitbake
SUMMARY = "DP World Smart Solutions — Web Configurator"
LICENSE = "CLOSED"
# 방법 A — 내부 git 서버의 태그 릴리스를 fetch (배포물이 repo 루트에 평탄 배치됨):
SRC_URI = "git://<internal-host>/<path>/NewWebConfigurator.git;branch=<branch>;protocol=ssh"
SRCREV = "<v1.12.1 sha 또는 tag>"
S = "${WORKDIR}/git"
# 방법 B — git archive 로 만든 스냅샷 tarball 사용:
# (git -C <repo> archive v1.12.1 | gzip > web-configurator-v1.12.1.tar.gz)
# SRC_URI = "file://web-configurator-v1.12.1.tar.gz"
# S = "${WORKDIR}"
inherit systemd
RDEPENDS:${PN} += "python3-core python3-sqlite3 python3-json python3-netserver \
python3-netclient python3-compression python3-crypt python3-logging \
python3-datetime python3-threading python3-shell python3-io \
python3-mime"
# Optional: add nginx only if this recipe installs/enables the nginx reverse proxy.
# RDEPENDS:${PN} += "nginx"
SYSTEMD_SERVICE:${PN} = "web-configurator.service"
SYSTEMD_AUTO_ENABLE = "enable"
do_install() {
# 애플리케이션 (read-only program code → ${libdir} = /usr/lib)
install -d ${D}${libdir}/web-configurator
cp -r ${S}/src ${D}${libdir}/web-configurator/
# systemd 유닛
install -d ${D}${systemd_system_unitdir}
install -m 0644 ${S}/deploy/web-configurator.service ${D}${systemd_system_unitdir}/
install -m 0644 ${S}/deploy/dpworld-ap-apply.service ${D}${systemd_system_unitdir}/
install -m 0644 ${S}/deploy/dpworld-ap-seed.service ${D}${systemd_system_unitdir}/
install -m 0644 ${S}/deploy/dpworld-hostapd-ap0.service ${D}${systemd_system_unitdir}/
install -m 0644 ${S}/deploy/dpworld-udhcpd-ap0.service ${D}${systemd_system_unitdir}/
install -m 0644 ${S}/deploy/dpworld-net-recover.service ${D}${systemd_system_unitdir}/
# 유닛 ExecStart 대상 스크립트
install -d ${D}${bindir}
install -m 0755 ${S}/deploy/dpworld-ap-apply.sh ${D}${bindir}/dpworld-ap-apply.sh
# 네트워크-적용 하드닝 (권장 = 직접 교체):
# 펌웨어 base 스크립트 /usr/bin/dpworld-network-apply.sh 를 하드닝본으로 교체한다.
# firmware-native 한 dpworld-network-apply.service / dpworld-network-seed.service 가
Release v1.12.3 — 빈 디바이스 DB-init 안정화(fail-soft) + Wi-Fi AP DFS 채널 선택 v1.12.1 전달 이후의 v1.12.2·v1.12.3 변경을 함께 반영합니다. dpworldapp 공유 DB(device/protocol)·계약·원자적 쓰기 계약은 무변경. ■ v1.12.2 — 신규/빈 디바이스 DB-init 안정화 (fail-soft) 펌웨어 업데이트 직후 동기화 문제로 device_config/protocol_config 가 비어 있을 때, 웹이 그 값을 생성·덮어써 dpworldapp 의 시딩을 선점하는 문제를 차단. 협력사 DB-init fix(2ca0ac1)를 포함하되, 미초기화 시 예외를 던져 fresh device 를 중단시키던 부분을 fail-soft 로 대체(렌더는 적용, DB 쓰기만 skip). - db_manager: config_initialized(key) 단일 판정 신규 (존재 AND 비어있지 않은 dict; 빈 {} = 미초기화). - apply_engine: 미초기화 시 raise 제거 → 렌더/networkctl 은 적용하되 DB 미러 쓰기만 skip(journal warn). _write_db / _write_db_restore 동일 적용. _lkg_bookkeeping: all-absent baseline 의 LKG 승격 방지(fresh device). - server: 미초기화 응답 통일 — GET 204, POST 409 not_initialized(code 필드). - netmodel(F3): 비-dict / malformed WIFI_SSID 내성 — crash 대신 안전 degrade. - migrations: contract_canonical 을 device / protocol 로 분리, 각 키가 시딩될 때까지 독립 defer(seed-ordering). 기존 통합 플래그 하위호환 유지. - frontend(F2): device/protocolConfigAbsent 가드 — 로드 시 부재(204)였던 키를 Save All 로 생성하지 않도록 차단하고 안내 토스트 표시. ■ v1.12.3 — Wi-Fi AP 채널 선택 + 네트워크 즉시적용 검증 - ap_engine: DFS 인지 채널 선택 — STA 가 DFS/no-IR 5GHz(52–64·100–144)에 있어도 AP 가 맹목 추종하지 않고 비-DFS 채널 선택(2.4GHz STA 는 ch1–13 만 추종). parse_iw_link_beacon_int 추가 — MCC(AP≠STA 채널) 시 hostapd beacon_int 을 STA BSS 와 일치(QCA6490 &#34;STA/AP BI must match&#34;). AP 상태에 라디오-다운 사유(country_unset / channel_dfs / mcc_bi) 추가. - ap_renderer: render_hostapd 에 beacon_int 파라미터 추가(기본 100). - 즉시적용: 기존 systemctl start 방식 유지 — 디바이스 실측으로 재확인, 관련 내부 재작업 시도는 검토 후 원복(순변화 없음). ■ 기타 - api.js: 저장 실패 시 서버 errors 메시지를 사용자에게 노출. - 문서/버전: VERSION·constants.js → v1.12.3, RELEASE-NOTES §0, DELIVERABLE-MANIFEST, BSP-INTEGRATION 갱신. - MemoryMax 48M→128M(v1.11.16) 주석 정합화(fw_routes / watchdog / server).
1 month ago
# 이 경로를 호출하므로 apply·--boot 모두 자동으로 하드닝 동작을 탄다.
# ExecStart를 바꾸는 20-hardened.conf override 드롭인은 설치하지 않는다(scripts/deploy.ps1 fallback 전용).
# (파일 소유권은 BSP에서 조정 — firmware recipe의 base 파일을 이 패키지가 덮어쓰도록
# bbappend 또는 recipe 우선순위로 정리. 자세히 docs/firmware-boot-hardening.md)
install -m 0755 ${S}/deploy/dpworld-network-apply-hardened.sh \
${D}${bindir}/dpworld-network-apply.sh
Release v1.12.3 — 빈 디바이스 DB-init 안정화(fail-soft) + Wi-Fi AP DFS 채널 선택 v1.12.1 전달 이후의 v1.12.2·v1.12.3 변경을 함께 반영합니다. dpworldapp 공유 DB(device/protocol)·계약·원자적 쓰기 계약은 무변경. ■ v1.12.2 — 신규/빈 디바이스 DB-init 안정화 (fail-soft) 펌웨어 업데이트 직후 동기화 문제로 device_config/protocol_config 가 비어 있을 때, 웹이 그 값을 생성·덮어써 dpworldapp 의 시딩을 선점하는 문제를 차단. 협력사 DB-init fix(2ca0ac1)를 포함하되, 미초기화 시 예외를 던져 fresh device 를 중단시키던 부분을 fail-soft 로 대체(렌더는 적용, DB 쓰기만 skip). - db_manager: config_initialized(key) 단일 판정 신규 (존재 AND 비어있지 않은 dict; 빈 {} = 미초기화). - apply_engine: 미초기화 시 raise 제거 → 렌더/networkctl 은 적용하되 DB 미러 쓰기만 skip(journal warn). _write_db / _write_db_restore 동일 적용. _lkg_bookkeeping: all-absent baseline 의 LKG 승격 방지(fresh device). - server: 미초기화 응답 통일 — GET 204, POST 409 not_initialized(code 필드). - netmodel(F3): 비-dict / malformed WIFI_SSID 내성 — crash 대신 안전 degrade. - migrations: contract_canonical 을 device / protocol 로 분리, 각 키가 시딩될 때까지 독립 defer(seed-ordering). 기존 통합 플래그 하위호환 유지. - frontend(F2): device/protocolConfigAbsent 가드 — 로드 시 부재(204)였던 키를 Save All 로 생성하지 않도록 차단하고 안내 토스트 표시. ■ v1.12.3 — Wi-Fi AP 채널 선택 + 네트워크 즉시적용 검증 - ap_engine: DFS 인지 채널 선택 — STA 가 DFS/no-IR 5GHz(52–64·100–144)에 있어도 AP 가 맹목 추종하지 않고 비-DFS 채널 선택(2.4GHz STA 는 ch1–13 만 추종). parse_iw_link_beacon_int 추가 — MCC(AP≠STA 채널) 시 hostapd beacon_int 을 STA BSS 와 일치(QCA6490 &#34;STA/AP BI must match&#34;). AP 상태에 라디오-다운 사유(country_unset / channel_dfs / mcc_bi) 추가. - ap_renderer: render_hostapd 에 beacon_int 파라미터 추가(기본 100). - 즉시적용: 기존 systemctl start 방식 유지 — 디바이스 실측으로 재확인, 관련 내부 재작업 시도는 검토 후 원복(순변화 없음). ■ 기타 - api.js: 저장 실패 시 서버 errors 메시지를 사용자에게 노출. - 문서/버전: VERSION·constants.js → v1.12.3, RELEASE-NOTES §0, DELIVERABLE-MANIFEST, BSP-INTEGRATION 갱신. - MemoryMax 48M→128M(v1.11.16) 주석 정합화(fw_routes / watchdog / server).
1 month ago
# 온디맨드 apply 드롭인 (권장 bake — OPTIONAL 완화, 필수 아님):
# web-configurator 가 systemctl start dpworld-network-apply.service 로 온디맨드 호출할 때
# boot-seed Requires= 가 seed(boot-only oneshot)를 --boot 로 재트리거한다. seed 도 하드닝본이라
# 이 드롭인이 없어도 안전 통과(systemctl start 성공)한다. 이 드롭인은 Requires= 를 비워 그
# 불필요한 seed --boot 재실행만 회피하는 완화 overlay 이다(결함 fix 아님).
install -d ${D}${systemd_system_unitdir}/dpworld-network-apply.service.d
install -m 0644 ${S}/deploy/dpworld-network-apply-ondemand.conf \
Release v1.12.3 — 빈 디바이스 DB-init 안정화(fail-soft) + Wi-Fi AP DFS 채널 선택 v1.12.1 전달 이후의 v1.12.2·v1.12.3 변경을 함께 반영합니다. dpworldapp 공유 DB(device/protocol)·계약·원자적 쓰기 계약은 무변경. ■ v1.12.2 — 신규/빈 디바이스 DB-init 안정화 (fail-soft) 펌웨어 업데이트 직후 동기화 문제로 device_config/protocol_config 가 비어 있을 때, 웹이 그 값을 생성·덮어써 dpworldapp 의 시딩을 선점하는 문제를 차단. 협력사 DB-init fix(2ca0ac1)를 포함하되, 미초기화 시 예외를 던져 fresh device 를 중단시키던 부분을 fail-soft 로 대체(렌더는 적용, DB 쓰기만 skip). - db_manager: config_initialized(key) 단일 판정 신규 (존재 AND 비어있지 않은 dict; 빈 {} = 미초기화). - apply_engine: 미초기화 시 raise 제거 → 렌더/networkctl 은 적용하되 DB 미러 쓰기만 skip(journal warn). _write_db / _write_db_restore 동일 적용. _lkg_bookkeeping: all-absent baseline 의 LKG 승격 방지(fresh device). - server: 미초기화 응답 통일 — GET 204, POST 409 not_initialized(code 필드). - netmodel(F3): 비-dict / malformed WIFI_SSID 내성 — crash 대신 안전 degrade. - migrations: contract_canonical 을 device / protocol 로 분리, 각 키가 시딩될 때까지 독립 defer(seed-ordering). 기존 통합 플래그 하위호환 유지. - frontend(F2): device/protocolConfigAbsent 가드 — 로드 시 부재(204)였던 키를 Save All 로 생성하지 않도록 차단하고 안내 토스트 표시. ■ v1.12.3 — Wi-Fi AP 채널 선택 + 네트워크 즉시적용 검증 - ap_engine: DFS 인지 채널 선택 — STA 가 DFS/no-IR 5GHz(52–64·100–144)에 있어도 AP 가 맹목 추종하지 않고 비-DFS 채널 선택(2.4GHz STA 는 ch1–13 만 추종). parse_iw_link_beacon_int 추가 — MCC(AP≠STA 채널) 시 hostapd beacon_int 을 STA BSS 와 일치(QCA6490 &#34;STA/AP BI must match&#34;). AP 상태에 라디오-다운 사유(country_unset / channel_dfs / mcc_bi) 추가. - ap_renderer: render_hostapd 에 beacon_int 파라미터 추가(기본 100). - 즉시적용: 기존 systemctl start 방식 유지 — 디바이스 실측으로 재확인, 관련 내부 재작업 시도는 검토 후 원복(순변화 없음). ■ 기타 - api.js: 저장 실패 시 서버 errors 메시지를 사용자에게 노출. - 문서/버전: VERSION·constants.js → v1.12.3, RELEASE-NOTES §0, DELIVERABLE-MANIFEST, BSP-INTEGRATION 갱신. - MemoryMax 48M→128M(v1.11.16) 주석 정합화(fw_routes / watchdog / server).
1 month ago
${D}${systemd_system_unitdir}/dpworld-network-apply.service.d/10-ondemand.conf
# Fallback (라이브 후적용 전용 — 베이킹 시 설치하지 않음):
# 펌웨어 원본을 교체할 수 없는 경우에만, 하드닝본을 원래 -hardened 이름으로 설치하고
# deploy/dpworld-network-{apply,seed}.service.d/20-hardened.conf 드롭인 2개로
# base 유닛의 ExecStart 를 override 한다.
# Optional nginx site config.
# scripts/deploy.ps1 does not use this file. Skip this block if firmware/BSP
# owns nginx, or if the device will access the app directly on :9090.
if [ -f ${S}/deploy/nginx.conf ]; then
install -d ${D}${sysconfdir}/nginx
install -m 0644 ${S}/deploy/nginx.conf ${D}${sysconfdir}/nginx/web-configurator.conf
fi
# 쓰기 가능 런타임 디렉토리
install -d ${D}/opt/log/dpworldapp ${D}/opt/fw_staging ${D}/opt/fw_upload \
${D}/opt/config_backups ${D}/home/root/db ${D}/home/root/network
}
FILES:${PN} += "${libdir}/web-configurator /opt/log ${systemd_system_unitdir} \
/opt/fw_staging /opt/fw_upload /opt/config_backups \
/home/root/db /home/root/network ${bindir}/dpworld-*.sh \
${sysconfdir}/nginx"
```
---
## 6. 부팅 후 동작 확인 (smoke test)
```sh
systemctl status web-configurator # active (running)
curl -fsS http://127.0.0.1:9090/ | head # 앱 응답
curl -fsS http://127.0.0.1/ | head # optional: nginx 경유 사용 시
```
---
## 7. firmware-native 전제 + 네트워크-적용 하드닝 통합
### firmware가 제공하는 것 (이 패키지에 **미포함**)
- **base 네트워크-적용 유닛** — `dpworld-network-apply.service`, `dpworld-network-seed.service`. 이 유닛들은 `/usr/bin/dpworld-network-apply.sh` 를 호출합니다(no-arg / `--boot`).
- **dpworldapp**(텔레메트리 바이너리), (전환기의 레거시 `app-runner`) — firmware-native.
- **nginx** — 제품 이미지가 `:80` reverse proxy를 제공할 때만. 앱을 `:9090`으로 직접 접근하면 불필요.
### 네트워크-적용 하드닝본 통합 — ① 직접 교체(권장) vs ② override(fallback)
펌웨어 base `/usr/bin/dpworld-network-apply.sh` 에는 WiFi country 변경 시 `modprobe -r wlan`
라이브 재로드 경로가 있어 QCA6490에서 PMU 워치독 재부팅 루프를 유발한 이력이 있습니다.
`deploy/dpworld-network-apply-hardened.sh` 가 이를 제거한 **완전 대체본**입니다.
Release v1.12.3 — 빈 디바이스 DB-init 안정화(fail-soft) + Wi-Fi AP DFS 채널 선택 v1.12.1 전달 이후의 v1.12.2·v1.12.3 변경을 함께 반영합니다. dpworldapp 공유 DB(device/protocol)·계약·원자적 쓰기 계약은 무변경. ■ v1.12.2 — 신규/빈 디바이스 DB-init 안정화 (fail-soft) 펌웨어 업데이트 직후 동기화 문제로 device_config/protocol_config 가 비어 있을 때, 웹이 그 값을 생성·덮어써 dpworldapp 의 시딩을 선점하는 문제를 차단. 협력사 DB-init fix(2ca0ac1)를 포함하되, 미초기화 시 예외를 던져 fresh device 를 중단시키던 부분을 fail-soft 로 대체(렌더는 적용, DB 쓰기만 skip). - db_manager: config_initialized(key) 단일 판정 신규 (존재 AND 비어있지 않은 dict; 빈 {} = 미초기화). - apply_engine: 미초기화 시 raise 제거 → 렌더/networkctl 은 적용하되 DB 미러 쓰기만 skip(journal warn). _write_db / _write_db_restore 동일 적용. _lkg_bookkeeping: all-absent baseline 의 LKG 승격 방지(fresh device). - server: 미초기화 응답 통일 — GET 204, POST 409 not_initialized(code 필드). - netmodel(F3): 비-dict / malformed WIFI_SSID 내성 — crash 대신 안전 degrade. - migrations: contract_canonical 을 device / protocol 로 분리, 각 키가 시딩될 때까지 독립 defer(seed-ordering). 기존 통합 플래그 하위호환 유지. - frontend(F2): device/protocolConfigAbsent 가드 — 로드 시 부재(204)였던 키를 Save All 로 생성하지 않도록 차단하고 안내 토스트 표시. ■ v1.12.3 — Wi-Fi AP 채널 선택 + 네트워크 즉시적용 검증 - ap_engine: DFS 인지 채널 선택 — STA 가 DFS/no-IR 5GHz(52–64·100–144)에 있어도 AP 가 맹목 추종하지 않고 비-DFS 채널 선택(2.4GHz STA 는 ch1–13 만 추종). parse_iw_link_beacon_int 추가 — MCC(AP≠STA 채널) 시 hostapd beacon_int 을 STA BSS 와 일치(QCA6490 &#34;STA/AP BI must match&#34;). AP 상태에 라디오-다운 사유(country_unset / channel_dfs / mcc_bi) 추가. - ap_renderer: render_hostapd 에 beacon_int 파라미터 추가(기본 100). - 즉시적용: 기존 systemctl start 방식 유지 — 디바이스 실측으로 재확인, 관련 내부 재작업 시도는 검토 후 원복(순변화 없음). ■ 기타 - api.js: 저장 실패 시 서버 errors 메시지를 사용자에게 노출. - 문서/버전: VERSION·constants.js → v1.12.3, RELEASE-NOTES §0, DELIVERABLE-MANIFEST, BSP-INTEGRATION 갱신. - MemoryMax 48M→128M(v1.11.16) 주석 정합화(fw_routes / watchdog / server).
1 month ago
> ★ **불변식(권장이 아니라 필수)**: canonical `/usr/bin/dpworld-network-apply.sh` 는 **반드시 하드닝본**이어야 합니다(①/② 중 하나로 보장). 웹의 온디맨드 apply(`systemctl start dpworld-network-apply.service`)는 이 경로 + `Requires=seed`(→ seed `--boot`)를 타므로, un-hardened 로 남기면 `modprobe -r wlan` → 부트루프가 재발합니다. 아래 표의 '권장'은 ①vs② **방식 선택**의 권장일 뿐, 하드닝 자체는 선택이 아닙니다(Codex Q1 잔여 리스크).
| | ① 직접 교체 (BSP 베이킹, **권장**) | ② override (라이브 후적용, fallback) |
|---|---|---|
| 대상 | 펌웨어 이미지를 빌드하는 협력사 | 이미 구워진 디바이스(우리 `deploy.ps1`) |
| 방법 | 하드닝본 내용을 **`/usr/bin/dpworld-network-apply.sh` 원본 이름**으로 설치(원본 교체) | 하드닝본을 `…-hardened.sh` 로 두고 `.service.d/20-hardened.conf` 드롭인 2개로 ExecStart 교체 |
Release v1.12.3 — 빈 디바이스 DB-init 안정화(fail-soft) + Wi-Fi AP DFS 채널 선택 v1.12.1 전달 이후의 v1.12.2·v1.12.3 변경을 함께 반영합니다. dpworldapp 공유 DB(device/protocol)·계약·원자적 쓰기 계약은 무변경. ■ v1.12.2 — 신규/빈 디바이스 DB-init 안정화 (fail-soft) 펌웨어 업데이트 직후 동기화 문제로 device_config/protocol_config 가 비어 있을 때, 웹이 그 값을 생성·덮어써 dpworldapp 의 시딩을 선점하는 문제를 차단. 협력사 DB-init fix(2ca0ac1)를 포함하되, 미초기화 시 예외를 던져 fresh device 를 중단시키던 부분을 fail-soft 로 대체(렌더는 적용, DB 쓰기만 skip). - db_manager: config_initialized(key) 단일 판정 신규 (존재 AND 비어있지 않은 dict; 빈 {} = 미초기화). - apply_engine: 미초기화 시 raise 제거 → 렌더/networkctl 은 적용하되 DB 미러 쓰기만 skip(journal warn). _write_db / _write_db_restore 동일 적용. _lkg_bookkeeping: all-absent baseline 의 LKG 승격 방지(fresh device). - server: 미초기화 응답 통일 — GET 204, POST 409 not_initialized(code 필드). - netmodel(F3): 비-dict / malformed WIFI_SSID 내성 — crash 대신 안전 degrade. - migrations: contract_canonical 을 device / protocol 로 분리, 각 키가 시딩될 때까지 독립 defer(seed-ordering). 기존 통합 플래그 하위호환 유지. - frontend(F2): device/protocolConfigAbsent 가드 — 로드 시 부재(204)였던 키를 Save All 로 생성하지 않도록 차단하고 안내 토스트 표시. ■ v1.12.3 — Wi-Fi AP 채널 선택 + 네트워크 즉시적용 검증 - ap_engine: DFS 인지 채널 선택 — STA 가 DFS/no-IR 5GHz(52–64·100–144)에 있어도 AP 가 맹목 추종하지 않고 비-DFS 채널 선택(2.4GHz STA 는 ch1–13 만 추종). parse_iw_link_beacon_int 추가 — MCC(AP≠STA 채널) 시 hostapd beacon_int 을 STA BSS 와 일치(QCA6490 &#34;STA/AP BI must match&#34;). AP 상태에 라디오-다운 사유(country_unset / channel_dfs / mcc_bi) 추가. - ap_renderer: render_hostapd 에 beacon_int 파라미터 추가(기본 100). - 즉시적용: 기존 systemctl start 방식 유지 — 디바이스 실측으로 재확인, 관련 내부 재작업 시도는 검토 후 원복(순변화 없음). ■ 기타 - api.js: 저장 실패 시 서버 errors 메시지를 사용자에게 노출. - 문서/버전: VERSION·constants.js → v1.12.3, RELEASE-NOTES §0, DELIVERABLE-MANIFEST, BSP-INTEGRATION 갱신. - MemoryMax 48M→128M(v1.11.16) 주석 정합화(fw_routes / watchdog / server).
1 month ago
| 드롭인 (하드닝) | **없음** (직접 교체는 ExecStart override 드롭인 불필요) | 20-hardened.conf 2개만 설치 |
| 드롭인 (온디맨드) | `10-ondemand.conf` **권장 bake** (완화 overlay·필수 아님 — `systemctl start` 는 없어도 성공, 불필요한 `seed --boot` 재트리거만 회피) | `10-ondemand.conf` **권장 bake** (동일) |
| 효과 | base 유닛이 그대로 하드닝 스크립트를 실행 | base 유닛의 ExecStart가 하드닝본으로 바뀜 |
Release v1.12.3 — 빈 디바이스 DB-init 안정화(fail-soft) + Wi-Fi AP DFS 채널 선택 v1.12.1 전달 이후의 v1.12.2·v1.12.3 변경을 함께 반영합니다. dpworldapp 공유 DB(device/protocol)·계약·원자적 쓰기 계약은 무변경. ■ v1.12.2 — 신규/빈 디바이스 DB-init 안정화 (fail-soft) 펌웨어 업데이트 직후 동기화 문제로 device_config/protocol_config 가 비어 있을 때, 웹이 그 값을 생성·덮어써 dpworldapp 의 시딩을 선점하는 문제를 차단. 협력사 DB-init fix(2ca0ac1)를 포함하되, 미초기화 시 예외를 던져 fresh device 를 중단시키던 부분을 fail-soft 로 대체(렌더는 적용, DB 쓰기만 skip). - db_manager: config_initialized(key) 단일 판정 신규 (존재 AND 비어있지 않은 dict; 빈 {} = 미초기화). - apply_engine: 미초기화 시 raise 제거 → 렌더/networkctl 은 적용하되 DB 미러 쓰기만 skip(journal warn). _write_db / _write_db_restore 동일 적용. _lkg_bookkeeping: all-absent baseline 의 LKG 승격 방지(fresh device). - server: 미초기화 응답 통일 — GET 204, POST 409 not_initialized(code 필드). - netmodel(F3): 비-dict / malformed WIFI_SSID 내성 — crash 대신 안전 degrade. - migrations: contract_canonical 을 device / protocol 로 분리, 각 키가 시딩될 때까지 독립 defer(seed-ordering). 기존 통합 플래그 하위호환 유지. - frontend(F2): device/protocolConfigAbsent 가드 — 로드 시 부재(204)였던 키를 Save All 로 생성하지 않도록 차단하고 안내 토스트 표시. ■ v1.12.3 — Wi-Fi AP 채널 선택 + 네트워크 즉시적용 검증 - ap_engine: DFS 인지 채널 선택 — STA 가 DFS/no-IR 5GHz(52–64·100–144)에 있어도 AP 가 맹목 추종하지 않고 비-DFS 채널 선택(2.4GHz STA 는 ch1–13 만 추종). parse_iw_link_beacon_int 추가 — MCC(AP≠STA 채널) 시 hostapd beacon_int 을 STA BSS 와 일치(QCA6490 &#34;STA/AP BI must match&#34;). AP 상태에 라디오-다운 사유(country_unset / channel_dfs / mcc_bi) 추가. - ap_renderer: render_hostapd 에 beacon_int 파라미터 추가(기본 100). - 즉시적용: 기존 systemctl start 방식 유지 — 디바이스 실측으로 재확인, 관련 내부 재작업 시도는 검토 후 원복(순변화 없음). ■ 기타 - api.js: 저장 실패 시 서버 errors 메시지를 사용자에게 노출. - 문서/버전: VERSION·constants.js → v1.12.3, RELEASE-NOTES §0, DELIVERABLE-MANIFEST, BSP-INTEGRATION 갱신. - MemoryMax 48M→128M(v1.11.16) 주석 정합화(fw_routes / watchdog / server).
1 month ago
> **온디맨드 드롭인 `10-ondemand.conf` (권장 bake — OPTIONAL 완화, 필수 아님)**: web-configurator/watchdog 는 온디맨드 네트워크 적용을 `systemctl start dpworld-network-apply.service` 로 호출합니다. 이 base 유닛은 `Requires=dpworld-network-seed.service`(boot-only oneshot)를 걸어 온디맨드 start 시 seed 를 `--boot` 로 재트리거하지만, seed 도 하드닝본이라 드롭인이 없어도 안전 통과합니다(systemctl start 성공, 'Dependency failed' 0). 이 드롭인은 `Requires=` 를 비워 그 불필요한 `seed --boot` 재실행만 회피하는 완화 overlay 입니다. `deploy/dpworld-network-apply-ondemand.conf` → `/lib/systemd/system/dpworld-network-apply.service.d/10-ondemand.conf` 로 설치(①·② 양쪽 모두 권장).
>
> **참고 (2026-07-01 .56 실측)**: 이 드롭인은 현재 .56 이미지에 미baked. 없어도 `systemctl start dpworld-network-apply.service` 는 성공함(Requires=seed 로 seed --boot 가 재트리거되나 seed 도 하드닝본이라 안전 통과). 다만 매 런타임 apply 마다 seed --boot 가 재실행되는 부수효과가 있어, 이 드롭인(또는 seed RemainAfterExit=yes) baking 이 권장됨.
절차 상세: `docs/firmware-boot-hardening.md` "펌웨어 베이킹 (BSP) — 원본 교체 방법".
### 이 패키지가 소유·제공하는 스크립트 (모두 포함됨)
| 스크립트 | 설치 위치(권장 ①) | 호출 주체 |
|---|---|---|
| `deploy/dpworld-ap-apply.sh` | `/usr/bin/dpworld-ap-apply.sh` | `dpworld-ap-apply.service`, `dpworld-ap-seed.service` |
| `deploy/dpworld-network-apply-hardened.sh` | `/usr/bin/dpworld-network-apply.sh` (원본 교체) | firmware-native `dpworld-network-apply.service` / `dpworld-network-seed.service` |
Release v1.12.3 — 빈 디바이스 DB-init 안정화(fail-soft) + Wi-Fi AP DFS 채널 선택 v1.12.1 전달 이후의 v1.12.2·v1.12.3 변경을 함께 반영합니다. dpworldapp 공유 DB(device/protocol)·계약·원자적 쓰기 계약은 무변경. ■ v1.12.2 — 신규/빈 디바이스 DB-init 안정화 (fail-soft) 펌웨어 업데이트 직후 동기화 문제로 device_config/protocol_config 가 비어 있을 때, 웹이 그 값을 생성·덮어써 dpworldapp 의 시딩을 선점하는 문제를 차단. 협력사 DB-init fix(2ca0ac1)를 포함하되, 미초기화 시 예외를 던져 fresh device 를 중단시키던 부분을 fail-soft 로 대체(렌더는 적용, DB 쓰기만 skip). - db_manager: config_initialized(key) 단일 판정 신규 (존재 AND 비어있지 않은 dict; 빈 {} = 미초기화). - apply_engine: 미초기화 시 raise 제거 → 렌더/networkctl 은 적용하되 DB 미러 쓰기만 skip(journal warn). _write_db / _write_db_restore 동일 적용. _lkg_bookkeeping: all-absent baseline 의 LKG 승격 방지(fresh device). - server: 미초기화 응답 통일 — GET 204, POST 409 not_initialized(code 필드). - netmodel(F3): 비-dict / malformed WIFI_SSID 내성 — crash 대신 안전 degrade. - migrations: contract_canonical 을 device / protocol 로 분리, 각 키가 시딩될 때까지 독립 defer(seed-ordering). 기존 통합 플래그 하위호환 유지. - frontend(F2): device/protocolConfigAbsent 가드 — 로드 시 부재(204)였던 키를 Save All 로 생성하지 않도록 차단하고 안내 토스트 표시. ■ v1.12.3 — Wi-Fi AP 채널 선택 + 네트워크 즉시적용 검증 - ap_engine: DFS 인지 채널 선택 — STA 가 DFS/no-IR 5GHz(52–64·100–144)에 있어도 AP 가 맹목 추종하지 않고 비-DFS 채널 선택(2.4GHz STA 는 ch1–13 만 추종). parse_iw_link_beacon_int 추가 — MCC(AP≠STA 채널) 시 hostapd beacon_int 을 STA BSS 와 일치(QCA6490 &#34;STA/AP BI must match&#34;). AP 상태에 라디오-다운 사유(country_unset / channel_dfs / mcc_bi) 추가. - ap_renderer: render_hostapd 에 beacon_int 파라미터 추가(기본 100). - 즉시적용: 기존 systemctl start 방식 유지 — 디바이스 실측으로 재확인, 관련 내부 재작업 시도는 검토 후 원복(순변화 없음). ■ 기타 - api.js: 저장 실패 시 서버 errors 메시지를 사용자에게 노출. - 문서/버전: VERSION·constants.js → v1.12.3, RELEASE-NOTES §0, DELIVERABLE-MANIFEST, BSP-INTEGRATION 갱신. - MemoryMax 48M→128M(v1.11.16) 주석 정합화(fw_routes / watchdog / server).
1 month ago
| `deploy/dpworld-network-apply-ondemand.conf` | `/lib/systemd/system/dpworld-network-apply.service.d/10-ondemand.conf` (권장 bake) | web-configurator/watchdog 온디맨드 `systemctl start dpworld-network-apply.service` |
> fallback(②) 사용 시에는 `…-hardened.sh` 이름으로 설치하고 `.service.d` 드롭인 2개(`deploy/dpworld-network-apply.service.d/`, `deploy/dpworld-network-seed.service.d/`)를 함께 둡니다.
### 웹 설정기 앱이 런타임에 호출하는 유닛
`server.py` 는 다음을 `systemctl start` 로 호출합니다:
`dpworld-network-apply.service`(firmware base 유닛 — 교체된 하드닝 스크립트 실행), `dpworld-ap-apply.service`, `dpworld-hostapd-ap0.service`, `dpworld-udhcpd-ap0.service`, `dpworld-net-recover.service`.
→ base 네트워크-적용 **유닛**(firmware-native)을 제외하면 모두 본 패키지에 포함됩니다.