Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions backend/src/schemas/simulation_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,36 @@ def _warn_unknown_business_type(cls, v: str) -> str:
sorted(_BUSINESS_TYPE_ALLOWED),
)
return v

@field_validator("target_district", "target_districts", mode="before")
@classmethod
def _validate_dong_code_format(cls, v):
"""target_district / target_districts 입력 검증.

사용자가 dong_code 형식 (8자리 숫자) 으로 입력 시 행정동 형식 강제 검증.
한글 동명 (예: '서교동') 입력은 통과 — dong_resolver 가 후속 매핑.
법정동 10자리 코드 입력 시 reject (잘못된 컬럼 적재 차단).
"""
if v is None or v == "":
return v
# list 입력 처리
if isinstance(v, list):
return [cls._check_single(d) for d in v]
return cls._check_single(v)

@staticmethod
def _check_single(value: str) -> str:
"""단일 동 입력값 검증 — 숫자 형식이면 8자리 강제, 한글이면 통과."""
if not value or not isinstance(value, str):
return value
s = value.strip()
# 숫자 입력 (dong_code 직접 입력 케이스) — 8자리 강제
if s.isdigit():
if len(s) != 8:
raise ValueError(
f"dong_code 형식 오류: {value!r} (행정동 8자리 숫자 기대, "
"10자리 법정동 또는 잘못된 형식이면 한글 동명 또는 8자리 행정동 코드 사용)"
)
return s
# 한글 동명 — dong_resolver 가 후속 매핑 (validator 통과)
return s
40 changes: 40 additions & 0 deletions backend/src/services/dong_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,46 @@ def resolve_dong_code_or_default(
return resolve_dong_code(dong_name, db_url=db_url, default=fallback) or fallback


def validate_dong_code(code: str | None, *, strict: bool = True) -> str | None:
"""행정동 dong_code 8자리 숫자 형식 검증.

Args:
code: 검증 대상 코드. None / "" 은 None 반환.
strict: True 면 형식 위반 시 ValueError raise. False 면 None 반환 (silent skip).

Returns:
검증 통과 시 trim 된 8자리 코드. 실패 시 None (strict=False) 또는 ValueError.

Raises:
ValueError (strict=True): 8자리 숫자 아니면 raise.

예외:
- 마포 행정동 코드: '11440***' (8자, 숫자) — 통과
- 법정동 코드 (10자): 거부 (잘못된 컬럼 적재 차단)
- 빈 값 / None: None 반환

사용처:
- 새 ETL/사용자 입력 검증 — varchar(10/15/text) 컬럼이라 길이 통과해도
행정동 컬럼 적재 시 SoT 가정 위반.
- SimulationInput Pydantic validator
- ORM 적재 직전 sanity check
"""
if code is None:
return None
s = str(code).strip()
if not s:
return None
if len(s) == 8 and s.isdigit():
return s
if strict:
raise ValueError(
f"invalid dong_code format: {code!r} (행정동 8자리 숫자 기대, "
"법정동 10자리 또는 잘못된 형식이면 별 컬럼/테이블 사용)"
)
logger.warning(f"[validate_dong_code] 잘못된 dong_code 형식: {code!r} — None 반환 (silent)")
return None


def resolve_dong_name(dong_code: str, db_url: str | None = None) -> str | None:
"""동코드 → 동이름 변환.

Expand Down
15 changes: 15 additions & 0 deletions docs/retrospective/2026-05-05.md
Original file line number Diff line number Diff line change
Expand Up @@ -534,3 +534,18 @@
```

---

## 12:19:50 세션 완료

### 변경 파일
- backend/src/agents/legal/categories.py
- docs/retrospective/2026-05-05.md

### diff 요약
```
backend/src/agents/legal/categories.py | 18 +++++++++---------
docs/retrospective/2026-05-05.md | 9 +++++++++
2 files changed, 18 insertions(+), 9 deletions(-)
```

---
Loading