# 오늘의 날씨 `Open-Meteo → /v1/local/weather → useLiveWeather → WeatherSection` 관측값은 기존 API를 사용하며 브라우저에서 10분마다 갱신한다. 조회 실패 시 마지막 관측값과 관측 시각을 유지한다. 날씨 문구는 API 요청마다 생성하지 않는다. **API 키 없음** — Open-Meteo 는 키 발급 없이 쓰는 무료 공개 엔드포인트다(`services/external/open_meteo.py`). ## Open-Meteo 응답 → 내부 스냅샷 `GET https://api.open-meteo.com/v1/forecast?latitude=&longitude=¤t=temperature_2m,weather_code,wind_speed_10m&timezone=auto` 원본 `current` 블록(`temperature_2m`·`weather_code`·`wind_speed_10m`·`time`)을 어댑터가 `{temperature, weather_code, wind_speed, observed_at, timezone, latitude, longitude}`로 정규화한다(`open_meteo.py:fetch_current_weather`). `weather_code`는 WMO 표준 정수 코드 그대로 저장·전달되고, 하늘 상태 문구로 바꾸는 건 아래 두 곳뿐이다 — **반드시 같은 표여야 한다** (하이드레이션 전엔 백엔드 값, 후엔 브라우저 값을 쓰는데 표가 다르면 같은 날씨인데 문구가 바뀐다): - 서버: `site_payload._WEATHER_CONDITION_BY_CODE` (조회는 `_weather_condition()`) — 프리렌더 스냅샷에 쓰인다. - 브라우저: `use-live-weather.ts:WEATHER_CONDITION_BY_CODE` (조회는 `condition()`) — 10분마다 재조회할 때 쓰인다. 둘 다 **코드마다 고유 라벨**을 반환하는 딕셔너리 조회다(구간 검사가 아니다) — 코드 하나가 분류 하나에 정확히 대응하므로 "51~57 은 다 이슬비" 식으로 뭉치지 않는다. | 코드 | WMO 의미(영어) | 분류(=조건 라벨) | |---|---|---| | 0 | Clear sky | 맑음 | | 1 | Mainly clear | 대체로 맑음 | | 2 | Partly cloudy | 구름 조금 | | 3 | Overcast | 흐림 | | 45 | Fog | 안개 | | 48 | Depositing rime fog | 착빙성 안개 | | 51 | Drizzle: Light intensity | 가벼운 이슬비 | | 53 | Drizzle: Moderate intensity | 보통 이슬비 | | 55 | Drizzle: Dense intensity | 강한 이슬비 | | 56 | Freezing Drizzle: Light intensity | 가벼운 착빙성 이슬비 | | 57 | Freezing Drizzle: Dense intensity | 강한 착빙성 이슬비 | | 61 | Rain: Slight intensity | 약한 비 | | 63 | Rain: Moderate intensity | 보통 비 | | 65 | Rain: Heavy intensity | 강한 비 | | 66 | Freezing Rain: Light intensity | 약한 착빙성 비 | | 67 | Freezing Rain: Heavy intensity | 강한 착빙성 비 | | 71 | Snow fall: Slight intensity | 약한 눈 | | 73 | Snow fall: Moderate intensity | 보통 눈 | | 75 | Snow fall: Heavy intensity | 강한 눈 | | 77 | Snow grains | 싸라기눈 | | 80 | Rain showers: Slight | 약한 소나기 | | 81 | Rain showers: Moderate | 보통 소나기 | | 82 | Rain showers: Violent | 강한 소나기 | | 85 | Snow showers: Slight | 약한 소나기눈 | | 86 | Snow showers: Heavy | 강한 소나기눈 | | 95 | Thunderstorm: Slight or moderate | 뇌우 | | 96 | Thunderstorm with slight hail | 약한 우박 뇌우 | | 99 | Thunderstorm with heavy hail | 강한 우박 뇌우 | 이 28개가 Open-Meteo `weather_code`의 전체 정의 값이다 — 표에 없는 값(파싱 실패 포함)만 안전하게 `흐림`으로 떨어진다(실제로는 도달하지 않는 방어 분기). `weatherMood()`(`derive.ts`)는 위 28종을 화면 배경 그림용으로 다시 4종(맑음/흐림/비/눈)으로 뭉친다 — 정규식 기반이라 새 분류를 추가해도 대개 자동으로 걸린다(예: "가벼운 착빙성 이슬비"는 `/비|우|소나기/` 패턴에 "비"가 들어 있어 `비`로 걸리고, "약한 소나기눈"은 `/눈|설/` 이 먼저 걸려 `눈`이 된다 — 검사 순서가 그래서 중요하다). `WeatherSection`의 `skyKey`는 노트에 그 조건 키가 실제로 있으면(`notes?.noteSets?.[condition]`) 그 조건 그대로 쓰고, 없으면(옛 payload 등) `mood`로 내려간다 — 화이트리스트를 따로 유지하지 않는 일반화된 조회다. `weather_notes.json → weather_notes.py → site_payload._weather → noteSets/tempNoteSets` 하늘 28종(위 표의 "분류" 열 전체)·기온 5구간에 각 5문구를 싣는다(28×5+5×5=165줄, 전부 고유해야 순환이 막히지 않는다). 첫 렌더는 첫 문장으로 고정해 하이드레이션을 맞추고, 브라우저에서는 무작위 시작 후 20초마다 하늘·기온 두 줄을 한 타이머로 같이 골라 한 바퀴 안에서 중복 없이 순환한다(`useWeatherNotes`). 기온 구간은 기존 `weatherBand`의 30·25·20·10도다. **세분화 원칙**: 강도(약/보통/강)만 다른 코드도 문구를 따로 쓴다 — 약한 비는 "우산 하나면 충분", 강한 비는 "이동을 미루라"처럼 안내 자체가 달라지기 때문이다. 착빙성(어는 비/이슬비)은 안개·비·이슬비와 별도로 갈랐다 — 노면 결빙이라는, 세기와는 다른 축의 위험이라 "도로가 얼어붙을 수 있으니" 식의 안전 안내가 필요하다(2026-09-18). 목업 README 2.3의 순환 계약을 제품으로 옮겼다. 군산 전용 시설·장소를 다른 사업장에 복사하지 않도록 기본 문구는 장소·시설·영업시간을 주장하지 않는 공통 안내로 구성한다. **LLM 생성이 아니다.** 지역별 장소 추천을 자동 생성하는 작업은 포함하지 않았다. 목업의 수기 문구·산출물은 변경하지 않는다. 옛 단일 `note`·`notes`·`tempNotes` payload도 계속 지원한다. 이미 발행된 사이트는 재발행해야 반영된다.