Capacity
{[
diff --git a/apps/sn/docs/작업내용/SN-도시침수지도-정보제공포털-목록보기/001-fe-SN-도시침수지도-정보제공포털-목록보기-통합구현기록.md b/apps/sn/docs/작업내용/SN-도시침수지도-정보제공포털-목록보기/001-fe-SN-도시침수지도-정보제공포털-목록보기-통합구현기록.md
index e695d60c5..b5c9824e9 100644
--- a/apps/sn/docs/작업내용/SN-도시침수지도-정보제공포털-목록보기/001-fe-SN-도시침수지도-정보제공포털-목록보기-통합구현기록.md
+++ b/apps/sn/docs/작업내용/SN-도시침수지도-정보제공포털-목록보기/001-fe-SN-도시침수지도-정보제공포털-목록보기-통합구현기록.md
@@ -52,7 +52,7 @@
| 행 선택 지도 이동 | 기존 그룹 범위 이동 유지 |
| 일반 지도 통신 | 빈도 부모 3개 TileWMS |
| 빈도 제한 | 부모 `flterSql`을 WMS `CQL_FILTER`로 전달 |
-| 침수심도 스타일 | 자식 5건 기반 동적 SLD |
+| 침수심도 스타일 | GeoServer 레이어 기본 스타일(2026-10-16부터, 11절). 이전에는 자식 5건 기반 동적 SLD |
| 범례 | 숨겨진 자식 설정의 기존 색상·명칭 유지 |
| 100년 빈도 | 화면 및 WMS 전환 대상에서 제외 |
| 기존 다른 레이어 | 기존 WFS 경로 유지 |
@@ -88,3 +88,16 @@
- 운영에서 행 선택 후 그룹 extent API가 `ST_Envelope` 스키마 해석 오류로 실패해 지도 이동이 중단된 원인을 백엔드 SQL에서 보완했다.
- 기존 시군구·침수빈도 그룹 범위 이동 계약과 화면 동작은 유지한다.
- 재배포 후 목록 행 클릭, 지도 중심 이동, 선택 빈도 WMS 표출을 회귀 확인한다.
+
+## 11. 2026-10-16 WMS SLD_BODY 제거
+
+- 근거: `COMMON_DOCS_ROOT/작업계획/SN-도시침수지도-정보제공포털-목록보기/003-de-SN-도시침수지도-WMS502-SLD_BODY제거-작업계획.md` (SFR-011-008·009, 화면설계서 24·28쪽 SN_MN010205·SN_MN010206)
+- 운영에서 `SLD_BODY`가 포함된 WMS 요청이 nginx 502로 실패해, 침수심도 스타일을 GeoServer 레이어 기본 스타일로 옮기고 요청에서 `SLD_BODY`를 뺐다.
+- `gis.layer.js`
+ - `getWmsLayer()`에서 도시침수지도 `SLD_BODY` 생성 분기와 `gis.wms-sld.js` import를 제거했다.
+ - `STYLES=''`(레이어 기본 스타일), 빈도 `CQL_FILTER`, `drawOrdr`, `minViewSize`는 그대로다.
+- `gis.wms-sld.js`: 삭제했다(사용처가 `gis.layer.js` 하나뿐).
+- 범례(`water-depth.tsx`)는 기존처럼 숨겨진 자식 5건의 DB 색상을 쓴다. GeoServer 기본 스타일이 제공 SLD(`tb_ms_flood_dngr_map_depth.sld`)로 교체되어야 지도 색과 범례가 일치한다.
+- 검증: 남은 참조 없음, `git diff --check`·ESLint 통과, 개발 GeoServer 동일 파라미터 요청 HTTP 200 PNG.
+- 미수행: 사용자 개발 서버 실행 중이라 `business_components`·`sn` 빌드 보류, 로그인 필요로 브라우저 Network 확인 보류.
+- 롤백: `gis.layer.js`의 SLD 분기와 `gis.wms-sld.js`를 복원한다.
diff --git a/packages/common/business_components/src/ui/map/lib/gis.layer.js b/packages/common/business_components/src/ui/map/lib/gis.layer.js
index b6935c383..8baf58bb9 100644
--- a/packages/common/business_components/src/ui/map/lib/gis.layer.js
+++ b/packages/common/business_components/src/ui/map/lib/gis.layer.js
@@ -21,11 +21,6 @@ import Tile from 'ol/layer/Tile.js';
import TileWMS from 'ol/source/TileWMS.js';
import gisCore from './gis.core.js';
import { showBusinessUserMessage } from '../../../lib/user-message';
-import {
- buildFloodDngrSldBody,
- FLOOD_DNGR_MAP_LAYER_TYPE,
- getFloodDngrSldSettings,
-} from './gis.wms-sld.js';
/**
* GisApp.layer
@@ -195,19 +190,12 @@ GisOlLayer.prototype = {
params['FORMAT'] = 'image/png';
params['TRANSPARENT'] = true;
params['TILED'] = true;
+ // 빈 값이면 GeoServer 레이어의 기본 스타일(Default Style)로 그린다.
+ // 도시침수지도(tb_ms_flood_dngr_map)의 침수심도 색상도 GeoServer에 등록한 기본 스타일을 사용하며,
+ // 긴 SLD_BODY를 URL에 싣지 않아 운영 프록시의 헤더 크기 초과(502)를 피한다.
params['STYLES'] = '';
if (filter) params['CQL_FILTER'] = filter;
- if (lyrTyNm === FLOOD_DNGR_MAP_LAYER_TYPE) {
- const sldSettings = getFloodDngrSldSettings(GisApp.layerCode, options?.id);
- const sldBody = buildFloodDngrSldBody(lyrTyNm, sldSettings);
- if (!sldBody) {
- console.warn('[GisApp] 도시침수지도 WMS SLD 생성에 필요한 침수심도 설정 5건이 유효하지 않습니다.', options);
- return null;
- }
- params['SLD_BODY'] = sldBody;
- }
-
const wmsLayer = new Tile({
...layerOptions,
id: layerOptions?.id,
diff --git a/packages/common/business_components/src/ui/map/lib/gis.wms-sld.js b/packages/common/business_components/src/ui/map/lib/gis.wms-sld.js
deleted file mode 100644
index 131378ae0..000000000
--- a/packages/common/business_components/src/ui/map/lib/gis.wms-sld.js
+++ /dev/null
@@ -1,103 +0,0 @@
-const FLOOD_DNGR_MAP_LAYER_TYPE = 'tb_ms_flood_dngr_map';
-const FLOOD_DEPTH_ATTRIBUTE = 'sbmrg_dpthl_cd';
-const FLOOD_DEPTH_CODES = ['N330', 'N331', 'N332', 'N333', 'N334'];
-
-const escapeXml = (value) => String(value ?? '')
- .replaceAll('&', '&')
- .replaceAll('<', '<')
- .replaceAll('>', '>')
- .replaceAll('"', '"')
- .replaceAll("'", ''');
-
-const toHex = (value) => Math.round(value).toString(16).padStart(2, '0');
-
-const parseCssColor = (value) => {
- const normalized = String(value ?? '').trim();
- const rgbaMatch = normalized.match(/^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(0(?:\.\d+)?|1(?:\.0+)?))?\s*\)$/i);
- if (rgbaMatch) {
- const red = Number(rgbaMatch[1]);
- const green = Number(rgbaMatch[2]);
- const blue = Number(rgbaMatch[3]);
- const opacity = rgbaMatch[4] == null ? 1 : Number(rgbaMatch[4]);
- if ([red, green, blue].some((channel) => channel < 0 || channel > 255) || opacity < 0 || opacity > 1) {
- return null;
- }
- return {
- hex: `#${toHex(red)}${toHex(green)}${toHex(blue)}`,
- opacity,
- };
- }
-
- const hexMatch = normalized.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
- if (!hexMatch) return null;
- const rawHex = hexMatch[1].length === 3
- ? hexMatch[1].split('').map((character) => character + character).join('')
- : hexMatch[1];
- return {
- hex: `#${rawHex.toLowerCase()}`,
- opacity: 1,
- };
-};
-
-const getFloodDepthCode = (filterSql) => {
- const match = String(filterSql ?? '').match(/\bsbmrg_dpthl_cd\s*=\s*'([^']+)'/i);
- const depthCode = match?.[1]?.trim();
- return FLOOD_DEPTH_CODES.includes(depthCode) ? depthCode : null;
-};
-
-const getLineWidth = (value) => {
- const lineWidth = Number(value);
- return Number.isFinite(lineWidth) && lineWidth >= 0 && lineWidth <= 20 ? lineWidth : null;
-};
-
-/**
- * 빈도 부모 레이어 바로 아래에 있는 침수심도 설정만 선별한다.
- * 부모는 WMS 요청을 담당하고, 반환된 자식 5건은 SLD 규칙의 필터와 색상 원본으로 사용한다.
- */
-export const getFloodDngrSldSettings = (layerCode, parentLayerId) => Object.values(layerCode ?? {})
- .filter((layerSetting) => (
- String(layerSetting?.upperLyrSn ?? '') === String(parentLayerId ?? '')
- && layerSetting?.lyrTyNm === FLOOD_DNGR_MAP_LAYER_TYPE
- ))
- .sort((left, right) => Number(left?.sortOrdr ?? 0) - Number(right?.sortOrdr ?? 0));
-
-/**
- * DB의 침수심도 필터와 RGBA 스타일을 GeoServer가 해석할 수 있는 SLD 1.0 XML로 변환한다.
- * 다섯 침수심도 코드나 색상값 중 하나라도 유효하지 않으면 잘못된 기본 스타일 표출을 막기 위해 null을 반환한다.
- */
-export const buildFloodDngrSldBody = (layerName, layerSettings) => {
- if (!Array.isArray(layerSettings) || layerSettings.length !== FLOOD_DEPTH_CODES.length) return null;
-
- const settingsByDepthCode = new Map();
- for (const layerSetting of layerSettings) {
- const depthCode = getFloodDepthCode(layerSetting?.flterSql);
- if (depthCode && !settingsByDepthCode.has(depthCode)) {
- settingsByDepthCode.set(depthCode, layerSetting);
- }
- }
-
- if (settingsByDepthCode.size !== FLOOD_DEPTH_CODES.length) return null;
-
- const rules = [];
- for (const depthCode of FLOOD_DEPTH_CODES) {
- const layerSetting = settingsByDepthCode.get(depthCode);
- const fillColor = parseCssColor(layerSetting?.polgnColor);
- const strokeColor = parseCssColor(layerSetting?.lnColor);
- const lineWidth = getLineWidth(layerSetting?.lnWdth);
- if (!fillColor || !strokeColor || lineWidth == null) return null;
-
- rules.push(
- `${escapeXml(depthCode)}${escapeXml(layerSetting?.lyrNm || depthCode)}`
- + `${FLOOD_DEPTH_ATTRIBUTE}${escapeXml(depthCode)}`
- + `${fillColor.hex}${fillColor.opacity}`
- + `${strokeColor.hex}${strokeColor.opacity}${lineWidth}`
- );
- }
-
- return ``
- + ``
- + `${escapeXml(layerName)}${rules.join('')}`
- + ``;
-};
-
-export { FLOOD_DNGR_MAP_LAYER_TYPE };