Skip to content

7.1.0

Latest

Choose a tag to compare

@HeuJung HeuJung released this 10 Oct 11:08

Security

  • 모듈·플러그인·템플릿 설치 창에서 함께 설치할 의존 확장·번들 언어팩을 고르면, 본 확장의 설치 권한만으로 다른 종류의 확장까지 설치·활성화되던 문제를 막았습니다. 이제 항목마다 그 종류의 설치·활성화 권한(언어팩은 설치·관리 권한)을 확인해 권한이 없는 항목의 체크박스를 잠그고 「권한 없음」을 안내하며, 서버도 아무것도 설치하지 않고 거부합니다.
  • 역할 관리에서 사용 여부를 끈 역할의 권한이 계속 유효하던 문제를 고쳤습니다. 이제 꺼진 역할로 받은 권한·메뉴 접근은 즉시 판정에서 빠지고(비회원 역할도 같음), 역할 폼에 「끄면 이 역할로 받은 권한이 즉시 회수됩니다」를 안내합니다. 최고관리자 역할은 끄면 모든 운영자가 관리 화면을 잃으므로 끌 수 없게 잠갔습니다.
  • 회원 삭제 권한을 가진 운영자가 회원 목록에서 자기 계정을 지울 수 있던 문제를 막았습니다. 본인 행의 [삭제]는 잠기고 이유를 안내하며, 서버도 거부합니다. 탈퇴는 마이페이지에서 합니다.
  • 대시보드 시스템 경고의 [복구]·[닫기]가 처리 권한이 없는 운영자에게도 열려 있던 문제를 고쳤습니다. 경고마다 처리 권한을 함께 내려 버튼을 잠그고 「권한이 있는 관리자에게 요청하세요」를 보입니다. 자동 비활성 확장의 복구·닫기는 그 확장 종류의 활성화 권한을 요구합니다(전에는 모듈·템플릿도 플러그인 활성화 권한으로 판정).
  • 화면 정의의 컴포넌트 권한 표시가 모달 안·표 셀 안 컴포넌트에서는 걸러지지 않던 문제와, 레이아웃 미리보기가 권한 표시를 거르지 않던 문제를 고쳤습니다.
  • 비회원이 여러 권한을 요구하는 경로에서 하나만 가져도 통과하던 판정을 회원과 같게(모두 필요) 맞췄습니다.
  • 운영 모드에서 레이아웃·확장 조각·커스텀 다국어 관리(저장·미리보기·판본 복원)가 데이터베이스 오류 같은 내부 오류로 실패하면 응답에 원래 오류 문장(SQL·DB 이름 등)이 그대로 실리던 문제를 막았습니다. 이제 일반 안내만 보여 주고 원문은 서버 로그에 남깁니다.
  • 운영 모드에서 모듈·플러그인·템플릿의 설치·활성화·비활성화·제거·업데이트가 데이터베이스 오류로 실패하면 관리자 화면 안내에 원래 오류 문장(실행한 SQL, 데이터베이스 호스트·포트·이름)이 그대로 보이던 문제를 수정했습니다. 이제 「서버 내부 오류가 발생했습니다. 자세한 내용은 서버 로그를 확인하세요.」로 안내하고 원래 오류는 서버 로그에 남깁니다. 디버그 모드와 확장이 직접 알리는 사유는 종전대로 보입니다.
  • 연락처 변경 본인인증 정책이 켜져 있어도 회원이 마이페이지 > 내 정보 수정에서 휴대폰·전화번호·이메일을 인증 없이 바꿀 수 있던 문제를 수정했습니다. 이제 연락처 칸이 실제로 바뀔 때 본인인증을 요구하고, 같은 값을 다시 저장하거나 닉네임처럼 다른 항목만 바꿀 때는 요구하지 않습니다. 관리자가 회원 정보를 고치는 경우는 종전처럼 대상이 아닙니다.
  • 비밀번호를 바꾸면 다른 기기의 로그인이 풀립니다. 본인이 바꾸면 지금 쓰는 기기만 남고, 메일로 재설정하거나 관리자가 비밀번호를 정해 주면 모든 기기가 로그아웃됩니다 — 비밀번호를 바꿔도 이미 빼앗긴 로그인이 그대로 살아 있던 경로입니다.
  • 관리자가 회원 수정 화면에서 자기 비밀번호를 바꿀 때 현재 비밀번호를 확인합니다. 자리를 비운 사이 열린 관리자 화면으로 비밀번호를 바꿔 계정을 가져갈 수 있던 경로입니다.
  • 관리자가 정해 준 비밀번호(회원 등록·다른 회원의 비밀번호 변경)는 그 회원이 다음 로그인 때 직접 바꿔야 로그인이 끝납니다(임시 비밀번호 강제 변경).
  • 정보 수정 API(PUT /api/me·PUT /api/user/profile)로 비밀번호를 함께 바꿀 때도 비밀번호 변경 전용 화면과 같은 본인인증 정책이 걸리고, 현재 비밀번호 원문이 서버 로그와 작업 대기열에 남지 않습니다.
  • 확장·코어 저장소에서 요청값으로 만든 경로가 상위 폴더로 거슬러 올라가, 파일 하나를 지우려던 요청이 다른 확장의 저장소까지 통째로 지울 수 있던 문제를 막았습니다. 저장 경로에 ..·.·절대경로·역슬래시·인코딩된 구분자(%2e·%2f·%5c)·빈 경로 조각이 섞이면 저장소가 요청을 거부하고, 저장소 최상위·확장 최상위 폴더는 폴더 삭제 요청으로 지워지지 않습니다(카테고리 폴더 전체 삭제는 종전대로 됩니다). 거부된 시도는 보안 로그에 남습니다. (KISA 측에서 제보해주셨습니다 — KVE-2026-2349)
  • 모듈·플러그인·첨부·공개(public) 저장소 디스크가 상대경로 이동(..)을 아예 받지 않는 방식(local-safe)으로 바뀌었습니다. 위의 경로 검사가 뚫리더라도 파일 시스템에 닿기 전에 한 번 더 막힙니다. 표준 local 디스크 설정(read-only·prefix 포함)을 그대로 따르며, 이 두 설정에 필요한 패키지가 없으면 무시하지 않고 설정 오류로 알립니다. 이 디스크들을 서명 URL 서빙(serve)으로 바꾸려면 표준 local 드라이버로 되돌려야 합니다.
  • 관리자 로그인 주소의 복귀 경로(?redirect=)에 javascript: 주소나 외부 주소를 넣은 링크로 관리자가 로그인하면, 로그인 직후 그 주소가 관리자 화면에서 그대로 실행되거나 외부 사이트로 이동하던 문제를 수정했습니다. (KISA 측에서 제보해주셨습니다 — KVE-2026-2348)
    • 이제 같은 탭 이동은 사이트 안의 경로만 허용하고, 그 밖의 주소는 첫 화면(관리자 로그인은 관리자 첫 화면)으로 보냅니다. 사용자 로그인·주문 로그인·본인인증 화면의 복귀 주소, 화면 이동 동작, 로그인 후 복귀 경로 판정이 모두 같은 기준을 따릅니다.
    • 화면에 그려지는 링크·폼 제출 주소에 실행 스킴(javascript:·vbscript:·data:)이 들어오면 무해한 값으로 바뀌며, 정상 외부 링크·메일·전화 링크는 그대로입니다. 검색엔진용 화면도 같은 기준을 따릅니다.
  • 레이아웃 화면 정의의 표현식이 이벤트가 일어난 화면 요소를 거쳐 브라우저 창에 닿아, 로그인 토큰을 읽거나 외부로 요청을 보낼 수 있던 문제를 수정했습니다. (KISA 측에서 제보해주셨습니다 — KVE-2026-2350)
    • 이벤트·오류·콜백 값은 이제 화면 정의가 실제로 쓰는 값(입력값·체크 여부·선택 항목·파일 등)만 복사해 전달하며, 표현식은 화면 요소·브라우저 창·저장소 같은 브라우저 객체를 다룰 수 없고 순수 계산 함수만 호출할 수 있습니다.
    • 레이아웃을 저장할 때도 이런 표현식과 실행 스킴 주소를 어느 위치에 있든 거부하며, 미리보기 만들기도 저장과 같은 검사를 거칩니다.
    • 화면 정의의 API 호출 동작은 로그인 토큰을 사이트 안의 주소로 보낼 때만 싣고, 레이아웃을 저장할 때 이동·호출 대상의 외부 주소는 화면 정의의 어느 위치에 있든 거부합니다 — 레이아웃 편집 권한만 있는 계정이 관리자 토큰을 외부로 보내게 할 수 있던 경로입니다.
    • 외부 주소에서 온 "본인인증 필요"·"로그인 만료" 응답도 더 이상 따르지 않습니다 — 그 응답이 지정한 주소로 로그인 토큰을 보내거나, 토큰을 갱신해 같은 외부 주소로 다시 요청하던 경로였습니다.
    • 기본 제공 관리자·사용자 테마의 언어 선택·로그아웃·프로필 사진 올리기·본인인증 시작도 사이트 안의 주소로 보낼 때만 로그인 토큰을 싣고, 로그아웃 뒤에는 사이트 안의 주소로만 이동합니다.
  • 첨부파일 이름만 이미지로 바꾼 파일(예: 내용이 SVG 인 evil.png)이 업로드되고, 누구나 여는 첨부 주소에서 그 안의 스크립트가 사이트 주소로 실행되던 문제를 막았습니다. 위임받은 관리자가 이런 파일을 올려 두고 최고관리자가 링크를 열면 로그인 정보가 새어 나갈 수 있었습니다. (KISA 측에서 제보해주셨습니다 — KVE-2026-2366)
    • 이제 업로드할 때 파일 이름뿐 아니라 파일 내용도 허용 형식인지 확인해, 내용이 맞지 않으면 「파일 내용이 허용된 형식과 일치하지 않습니다」로 거부합니다. 원래 일반 텍스트인 md·log·csv·tsv 파일과 eps 파일은 허용 확장자에 들어 있으면 그대로 올라가고, 0바이트 파일은 「빈 파일(0바이트)은 올릴 수 없습니다」로 거부합니다.
    • 첨부·게시판·페이지·상품·에디터 이미지·레이아웃 배경 이미지를 내보낼 때는 스크립트를 담을 수 없는 일반 이미지(JPG·PNG·GIF·WebP 등)만 화면에 바로 보여 주고, SVG 등 그 밖의 파일은 내려받기로 처리하며 브라우저가 파일 형식을 추측하지 못하게 했습니다. 이미 올라가 있던 SVG 첨부도 같은 방식으로 내려받기로 바뀝니다.
  • 로그인 없이 부르는 템플릿 라우트·다국어 주소에 ?v= 숫자만 바꿔 계속 요청하면 서버 캐시가 요청마다 새로 쌓여(다국어는 건당 수백 KB) 저장 공간을 고갈시킬 수 있던 문제를 막았습니다. (KISA 측에서 제보해주셨습니다 — KVE-2026-2336)
    • 서버 캐시는 이제 주소의 ?v= 값과 무관하게 현재 사이트 버전 하나로만 만들고, 존재하지 않는 템플릿에 대한 오류 결과는 캐시에 남기지 않습니다.
    • 로그인 없이 부르는 템플릿 라우트·설정·다국어·컴포넌트와 레이아웃 응답에 방문자(IP)별 요청 횟수 제한(기본 분당 600회)을 걸었습니다. 화면을 그리는 JS/CSS 번들·정적 자산·이미지 파일은 제한하지 않습니다.
    • 리버스 프록시·CDN 뒤에서 운영하면서 TRUSTED_PROXIES 를 지정하지 않으면 모든 방문자가 한 IP 로 집계되어 방문자가 몰릴 때 화면이 뜨지 않을 수 있으니 반드시 지정하고, 한 IP 뒤에 사용자가 많은 환경(사내망·공유 IP)에서는 .env 의 THROTTLE_PUBLIC 으로 한도를 올리세요.
    • 확장 캐시 버전은 같은 초 안에 두 번 올려도 반드시 새 값이 되도록 바꿔, 설정을 연달아 바꿨을 때 이전 캐시가 남지 않습니다.
  • 남의 이메일로 틀린 비밀번호를 몇 번 보내는 것만으로 그 계정을 잠가, 로그인 시도 제한을 계정 주인이 로그인하지 못하게 하는 수단으로 쓸 수 있던 문제를 보완했습니다. 잠긴 사용자가 「비밀번호 찾기」로 재설정을 마치면 잠금(무기한 잠금 포함)이 바로 풀리고, 로그인 화면의 잠김 안내에 이 방법을 함께 알립니다. 관리자가 한 명뿐인 사이트에서 그 관리자가 잠겨도 스스로 복구할 수 있습니다. 재설정으로 풀린 잠금은 활동 로그에 「비밀번호 재설정으로 계정 잠금 해제」로 남습니다. (KISA 측에서 제보해주셨습니다 — KVE-2026-2332)
  • 로그인 시도 제한을 켜 두어도 실패 횟수가 세지지 않아 계정 잠금이 걸리지 않던 문제를 수정했습니다. 로그인 실패·성공 처리가 백그라운드 작업으로 미뤄져, 기본 설치처럼 작업 처리기(큐 워커)를 따로 띄우지 않은 사이트에서는 몇 번을 틀려도 잠기지 않았고, 처리기가 있어도 처리가 밀리는 동안의 시도는 막지 못했습니다. 이제 실패 횟수와 잠금은 로그인 요청 안에서 바로 반영됩니다.
  • 회원 본인용 활동 기록 조회 응답이 접속 IP 를 함께 내보내던 것을 관리자 전용 정보 기준에 맞춰 비워서 보냅니다. 접속 IP 는 관리자 활동 로그 화면에서 종전대로 볼 수 있습니다.
  • 일부 응답(활동 로그 행위자, 메뉴 작성자, 알림 발송 이력, 회원 정보)에 볼 권한이 없는 사람에게도 회원 이메일이 실리던 문제를 수정했습니다. 이메일은 관리자 화면 응답과 본인 정보 조회에만 실리고, 그 밖에는 칸은 두되 값을 비웁니다.
  • 검색엔진용 화면이 요청의 Host 헤더를 믿어 생기던 세 가지 문제를 막았습니다. (KISA 측에서 제보해주셨습니다 — KVE-2026-2333·KVE-2026-2334·KVE-2026-2335)
    • Host 헤더만 바꾼 요청으로 대표 주소(canonical·og:url·다국어 주소·이미지 주소)가 다른 주소로 박힌 화면을 한 번 만들면, 그 화면이 저장돼 이후 검색엔진과 방문자에게 그대로 나가던 문제를 수정했습니다. 이제 검색엔진용 화면의 절대 주소와 ?locale= 정리용 리다이렉트 주소는 모두 APP_URL 을 기준으로 만들고, 저장된 화면은 사이트 주소별로 구분됩니다. 이 업데이트를 적용하면 기존에 저장된 검색엔진용 화면은 한 번씩 새로 만들어집니다.
    • 검색엔진용 화면을 채우는 내부 데이터 호출이 Host 헤더가 가리키는 곳으로 나가, 서버가 공격자가 고른 호스트·포트로 요청을 보내고 그 응답을 화면에 싣던 문제를 수정했습니다. 내부 호출은 이제 APP_URL 로만 나가며, 리다이렉트도 사이트 주소 안에서만 따릅니다. 꺼져 있던 인증서 검증을 되살렸고, APP_URL 이 서버 자신(127.0.0.1)을 가리키는 경우에만 검증을 생략합니다.
    • 요청 하나가 내부 호출 여러 건을 낳는 검색엔진용 화면 만들기가 한꺼번에 몰리면 서버 처리 능력이 고갈될 수 있던 문제를 완화했습니다. 동시에 만들 수 있는 화면 수를 사이트 전체에서 제한하고(기본 4, G7_SEO_MAX_CONCURRENT_RENDERS), 넘친 요청은 오류가 아니라 일반 화면을 받습니다. 방문자별 분당 한도의 집계가 동시 요청에서 실제보다 적게 세던 문제도 바로잡았고, 내부 호출 제한 시간을 2초로 줄였습니다(G7_SEO_DATASOURCE_TIMEOUT).
    • 주소 뒤에 ?_escaped_fragment_= 만 붙이면 브라우저 종류와 무관하게 검색엔진용 화면이 만들어지던 경로를 없앴습니다. 구글이 2015년에 폐기한 방식이라 현재 검색엔진의 수집에는 영향이 없습니다. 검색엔진용 화면을 직접 확인하려면 검색엔진 User-Agent 로 요청하세요.
    • 운영 환경에서는 요청 Host 가 APP_URL 의 도메인(하위 도메인 포함)이 아니면 요청을 받지 않습니다. APP_URL 이 실제 사이트 주소와 같은지 확인하세요. APP_URL 의 www 짝(www.example.com ↔ example.com)은 따로 적지 않아도 받아 사이트 주소로 301 이동합니다(맨 앞 www. 한 단계만, IP 주소·localhost 제외). 그 밖의 다른 도메인으로도 같은 사이트를 서빙한다면 .env 의 TRUSTED_HOSTS 에 콤마로 나열하고, 업데이트 직후 사이트가 열리지 않으면 TRUSTED_HOSTS_ENABLED=false 로 임시 해제한 뒤 주소를 맞추세요.
  • 웹 설치 마법사가 진행되는 동안 다른 브라우저에서 설치 설정을 바꿔, 관리자 계정을 자기 것으로 만들거나 기존 DB 테이블 삭제를 예약할 수 있던 문제를 막았습니다. (KISA 측에서 제보해주셨습니다 — KVE-2026-2430·KVE-2026-2432)
    • 이제 설치 마법사 3단계(설치 정보 입력)를 처음 통과한 브라우저만 그 설치를 이어갈 수 있습니다. 설정 저장·확장 선택·설치 시작·중단·초기화·설치 마무리는 그 브라우저에서 보낸 요청만 받고, 다른 브라우저로 접속하면 「다른 세션에서 진행 중인 설치」 화면만 보입니다. 설치 진행 상황 조회는 종전대로 막지 않습니다.
    • 설치 도중 브라우저를 닫아 이어갈 수 없게 되면, 3단계를 통과할 때 화면에 표시된 복구 토큰으로 다른 브라우저에서 이어갈 수 있습니다. 토큰은 한 번 쓰면 바뀌고, 틀린 토큰을 여러 번 입력하면 15분 동안 잠깁니다. 토큰을 잃어버렸다면 서버에서 storage/installer-state.json 을 지우고 처음부터 설치합니다.
    • DB 연결 테스트에 실패한 기록이 통과로 취급되던 문제와, 연결 테스트를 통과한 뒤 연결 설정을 바꿔 제출해도 받아들이던 문제를 수정했습니다. 3단계 입력 오류가 번역 문구 대신 내부 키로 표시되던 문제도 함께 고쳤습니다.
    • 기존 테이블 삭제는 연결 테스트 화면에서 동의했고 그때 확인한 테이블 목록이 그대로일 때만 수행합니다. 조건이 맞지 않으면 삭제하지 않고 설치를 진행하며 설치 로그에 경고를 남깁니다.
    • 설치가 끝난 뒤에도 .env 를 읽지 못해 설치 마무리·설치 상태 API 가 닫히지 않던 문제를 수정했습니다. 배포 .env 에 들어 있는 주석 형식 때문에 완료 여부를 판정하지 못했습니다.
    • 운영 서버에서 설치할 때는 설치하는 동안 /install 경로를 설치자 IP 나 관리망에서만 열어 두기를 권장합니다. 설정 예는 설치 가이드(INSTALL.md)의 「설치 마법사 보안」을 참고하세요.
  • 회원 목록에서 본인만 보도록 제한된 위임 관리자(기본 제공 「매니저」 역할)가 최근 가입 회원·회원 검색(uuid 지정)·회원 통계 화면으로는 다른 회원의 이름·이메일·휴대전화와 전체 회원 수를 볼 수 있던 문제를 수정했습니다. 이제 이 경로들은 모두 회원 목록과 같은 조회 범위를 따르고, 범위 밖 회원을 uuid 로 찾으면 「없음」으로 답합니다. 관리자 대시보드의 회원 수 카드와 회원 통계의 언어별 분포도 같은 범위로 셉니다. 전체 권한을 가진 관리자에게는 달라지는 것이 없습니다. (KISA 측에서 제보해주셨습니다 — KVE-2026-2368)
  • 발송 이력에서 본인이 보내거나 받은 알림만 보도록 제한된 위임 관리자가 관리자 대시보드의 「최근 알림」 카드로는 다른 회원의 알림(비밀번호 재설정 안내 등)까지 볼 수 있던 문제를 수정했습니다. 이제 이 카드도 발송 이력 목록과 같은 범위를 따르며, 「같은 역할 회원」 범위로 준 권한도 전체로 넓어지지 않고 그 범위로 좁혀집니다. 권한을 「본인만」으로 설정했는데 실제로는 어디서도 좁혀지지 않는 조합이 있으면, 권한 초기화·코어 업데이트 때 로그에 경고로 남깁니다. (KISA 측에서 제보해주셨습니다 — KVE-2026-2374)
  • 작업 처리기(큐)를 데이터베이스로 쓰는 사이트에서, 회원가입 때 입력한 비밀번호와 관리자가 회원을 추가하거나 회원 비밀번호를 바꿀 때 입력한 비밀번호의 원문이 뒤처리 작업마다 작업 대기 표(처리에 실패하면 실패 작업 표)에 사본으로 남던 문제를 수정했습니다. 가입 완료 훅(core.auth.after_register)의 가입 데이터(registration_data), 가입 동의 기록 훅(core.auth.record_consents)의 가입 데이터, 회원 추가·수정 완료 훅(core.user.after_create·core.user.after_update)의 원본 데이터에서 비밀번호와 비밀번호 확인 값을 뺍니다. 확장 개발자 영향 — 이 데이터에서 비밀번호를 읽던 구독자는 더 이상 받지 못합니다(기본 제공 확장 중에는 없습니다).
  • 본인인증·결제 결과를 돌려보낼 주소와 메일 링크를 요청의 Host 헤더로 만들던 문제를 고쳤습니다. 신뢰 호스트 검사는 사이트 주소의 하위 도메인이나 다른 포트로 들어온 요청을 막지 않아, 그런 주소로 접속한 화면에서 본인인증을 시작하면 인증을 마친 뒤의 이동 주소와 검증 토큰이 그 주소로 전달될 수 있었습니다. (KISA 측에서 제보해주셨습니다 — KVE-2026-2433·KVE-2026-2435)
    • 이제 본인인증 표준 콜백의 복귀 주소는 사이트 주소와 같은 출처일 때만 따르고, 메일 본인인증 링크·사이트맵 주소·검색엔진용 화면의 이동 주소·프로필 사진 주소는 항상 사이트 주소로 만듭니다.
    • 화면이 본인인증 뒤 원래 요청을 다시 보낼 때는 사이트 안의 주소일 때만 인증 정보와 검증 토큰을 싣습니다.
    • 화면 정의의 「새 창 열기」 동작은 외부 주소를 https 일 때만 열고 열린 창이 원래 화면을 조작하지 못하게 하며, 사이트 전역 요청 헤더는 사이트 안의 주소로 보낼 때만 붙습니다.

Added

로그인·비밀번호·접근 제한

  • 템플릿 엔진이 로그인의 비밀번호 변경 단계를 처리합니다(engine-v1.77.0). 비밀번호가 만료됐거나 관리자가 정해 준 비밀번호면 로그인·인증번호 확인 응답이 토큰 대신 변경 단계를 돌려주는데, 화면은 새 액션 loginPasswordChange(새 비밀번호로 로그인 완료)·loginPasswordChangePostpone(「다음에 변경」)으로 로그인을 끝냅니다. 레이아웃 편집기의 액션 목록에도 두 액션이 보입니다. 휴면이 풀린 로그인의 「휴면 상태가 해제되었습니다」 안내도 로그인 동작이 화면까지 전달해 관리자·사용자 로그인, 2단계 인증, 비밀번호 변경 단계 모두에서 뜹니다.
  • 비밀번호 정책을 추가했습니다(환경설정 > 보안). 모두 기본 꺼짐이며 운영자가 켭니다. 가입·변경 화면이 실제 정책대로 안내하도록 작성·재사용 규칙은 화면 설정 값으로 함께 내보냅니다(만료·IP 제한·2단계 인증 등 다른 보안 설정은 내보내지 않습니다).
    • 작성 규칙: 영문·숫자·특수문자 중 2종류 이상, 아이디(이메일 앞부분) 포함 금지, 같은 문자 연속 반복 금지, 연속 문자(1234·abcd·qwer) 금지(글자 수 3~6). 가입·재설정·변경·관리자 등록/수정에 똑같이 적용됩니다.
    • 재사용 금지: 최근 N개(1~10, 지금 비밀번호 포함)는 다시 쓸 수 없습니다. 관리자를 포함한 전 회원에게 적용되고, 관리자가 다른 회원에게 정해 주는 비밀번호는 검사하지 않습니다. 재사용 여부는 재설정 링크나 현재 비밀번호가 맞을 때만 판정하므로, 그 오류로 남의 비밀번호를 맞혀 볼 수 없습니다.
    • 만료: 사용 기간(30~730일)이 지나면 로그인할 때 새 비밀번호를 정해야 합니다. 「변경해야 로그인」 또는 「다음에 변경 허용(N일 뒤 다시 안내)」을 고르고, 적용 범위를 전체 회원·관리자만·지정한 역할·회원만으로 정하며, 역할 수정·회원 등록/수정 화면에서 따름·적용·제외를 고를 수 있습니다(회원 > 역할 > 사이트 순, 역할끼리 다르면 적용). 기간은 기능을 켠 날부터 계산하므로 켜자마자 전원이 만료되지 않습니다.
    • 매일 새벽 만료 N일 전 안내와 만료 알림(메일·사이트 알림)을 보내고, 「변경해야 로그인」이면 만료일에 그 회원의 로그인을 풀어 다음 로그인 때 변경 단계로 안내합니다. 한 번에 보낼 안내 수 상한(기본 1000명)을 두어 만료가 가까운 순서로 나눠 보냅니다. 보안 탭에서 대상 수·명단을 보고 「지금 실행」할 수 있습니다(만료 기능이 켜져 있을 때만 — 꺼진 채 실행하면 안내와 달리 로그인 때 변경을 요구하지 않으므로 거절합니다).
    • 로그인 변경 단계: 비밀번호·2단계 인증을 통과한 뒤 비밀번호를 바꿔야 하면 토큰 대신 변경 단계를 돌려주는 API(POST /api/auth/login/password-change·/postpone, 관리자 POST /api/auth/admin/login/password-change·/postpone)를 추가했습니다. 휴면 회원도 변경을 마치면 휴면이 풀립니다.
    • 알림 정의 2종(비밀번호 만료 사전 안내·비밀번호 만료), 활동 로그(비밀번호 변경·변경 연기·만료 로그인 해제), 확장용 훅(core.auth.password_change_recorded·password_change_required·password_change_postponed·password_expiry_notice·password_expired 등), 배치 명령 auth:process-password-expiry 를 추가했습니다.
  • 로그인 2단계 인증을 인증 앱(OTP)으로 받을 수 있습니다. 종전에는 2단계 인증을 켜면
    인증번호가 이메일로만 왔습니다. 이제 인증 앱을 쓰는 플러그인을 설치하면 앱이 만든 6자리
    코드로 로그인할 수 있고, 아직 앱을 등록하지 않은 사람은 종전처럼 이메일로 받습니다 —
    앱을 등록하지 않았다는 이유로 로그인이 막히지 않습니다.
    인증 앱으로 받는 화면에서는 "인증번호를 보냈습니다" 대신 앱 코드를 입력하라고 안내합니다.
  • 2단계 인증을 관리자에게만 요구할 수 있습니다. 환경설정 > 보안에서 적용 범위를
    「전체 회원」과 「관리자만」 중에 고릅니다. 종전에 2단계 인증을 켜 두셨다면 그대로
    「전체 회원」으로 동작합니다.
  • 관리자 영역을 허용한 IP 에서만 열 수 있습니다. 환경설정 > 보안 > 접근 제한에서 관리자
    화면·관리자 API(확장 관리 화면 포함)·관리자 로그인에 접근할 수 있는 IP·대역(CIDR)을 정합니다.
    특정 경로만 따로 막는 규칙도 둘 수 있습니다 — 위에서부터 처음 맞는 규칙 하나만 적용됩니다.
    기본은 꺼져 있습니다.
    • 허용 범위 밖에서 들어오면 접속 IP 를 보여 주는 403 화면(또는 403 응답)을 받고, 그 사실이
      활동 로그에 시스템 기록으로 남습니다.
    • 저장하면 지금 접속한 관리자 자신이 막히는 설정은 저장되지 않고 이유를 알려 줍니다. 그래도
      잠겼다면 서버에서 php artisan security:ip-restriction --disable 로 끌 수 있습니다(목록과
      규칙은 남깁니다). 개발 대시보드에도 점검·해제 버튼이 있습니다.
    • 결제 승인·입금 통보·웹훅·본인인증 결과처럼 외부 서버가 보내는 요청은 규칙에 걸리지 않습니다.
      확장은 core.security.ip_restriction_exempt_paths 훅으로 자기 수신 경로를 더할 수 있습니다.
    • 리버스 프록시 뒤에서 신뢰 프록시를 설정하지 않았다면 설정 화면이 경고합니다 — 그 상태에서는
      모든 방문자가 프록시 주소 하나로 보여 IP 제한이 제대로 동작하지 않습니다.

회원·역할·메뉴

  • 관리자 회원 목록이 계정 상태·권한 그룹·관리자 여부·계정 잠금·가입일·최근 로그인·휴면 전환일·상태 변경일(탈퇴/차단)·언어·국가·이메일 인증·본인인증 12가지 조건으로 회원을 거릅니다. 검색 대상도 닉네임·휴대폰/전화·회원번호/고유ID·관리자 메모까지 7가지로 늘었고, 검색어의 %·_ 는 글자 그대로 찾습니다. 계정 상태·언어·국가 열로도 정렬됩니다(종전에는 이 머리글을 누르면 오류가 났습니다). 필터에 쓰는 칸에 인덱스 6개를 더했습니다.
  • 회원 상세·본인 프로필 응답에 국가 이름(country_name)을 싣습니다 — 다시 보이게 한 국가 항목이 「US」 같은 코드 대신 이름으로 나옵니다.
  • 모듈·플러그인이 관리자 회원 목록에 자기 필터를 더할 수 있습니다 — 화면의 ext_filters[] 값 칸과 훅 core.user.filter_list_params·core.user.list_query_extensions·core.user.list_validation_attributes 를 새로 두었습니다(기존 core.user.list_validation_rules 와 함께 씁니다).
  • 역할 편집 화면에 「접근 가능 메뉴」 카드를 추가했습니다. 역할 하나에 관리자 메뉴 여러 개를 한 번에 체크해 저장할 수 있습니다 — 예전에는 메뉴 관리에서 메뉴를 하나씩 열어 역할을 골라야 했습니다. 하위 메뉴를 고르면 상위 메뉴도 함께 체크되고, 상위 메뉴를 빼면 하위 메뉴도 함께 빠집니다. 관리자 역할은 모든 메뉴에 항상 접근하므로 잠겨 있고, 메뉴 수정 권한이 없는 운영자에게는 읽기 전용으로 보입니다. 역할 복제로 만든 역할은 원본의 메뉴 구성을 그대로 이어받습니다.
  • 메뉴 관리 화면에 「여러 개 선택」 모드를 추가했습니다. 메뉴 여러 개를 체크한 뒤 역할을 한꺼번에 추가하거나 뺄 수 있고, 적용 전에 상·하위 메뉴가 함께 처리되는 수를 확인 창에서 먼저 보여 줍니다. API 는 PATCH /api/admin/menus/bulk-roles 입니다.
  • 메뉴 관리 목록의 메뉴마다 그 메뉴에 부여된 역할을 이름 배지로 보입니다(3개까지, 나머지는 「외 n개」, 전체는 마우스를 올리면 보입니다). 목록 응답에는 메뉴마다 역할 ID(role_ids)만 실어, 하위 메뉴의 역할 정보를 목록에서 덜어낸 최적화는 그대로 유지합니다.
  • 회원 목록의 선택 일괄 작업에 「역할 추가」「역할 제거」를 추가했습니다. 고른 회원들에게 역할을 한 번에 주거나 뺄 수 있고, 최고관리자·관리 범위 밖 회원·마지막 관리자(본인)와, 빼고 나면 역할이 하나도 남지 않는 회원은 건너뛰고 그 사유를 결과로 보여 줍니다. 내가 부여할 수 없는 권한이 담긴 역할이 하나라도 섞이면 아무것도 바꾸지 않고 거부합니다. API 는 PATCH /api/admin/users/bulk-roles 이며, 회원마다 활동 로그(user.bulk_roles)가 남습니다.
  • 확장이 관리자 역할 목록 조회(GET /api/admin/roles)에 조회 조건을 더할 수 있도록 검증 규칙 필터 core.role.list_validation_rules 를 추가했습니다(다른 목록 조회와 같은 방식).
  • 확장 개발자용 훅 core.menu.before_bulk_update_roles·core.menu.after_bulk_update_roles·core.user.before_bulk_update_roles·core.user.after_bulk_update_roles 를 추가했습니다. 역할 폼의 메뉴 저장과 메뉴 일괄 변경도 메뉴마다 core.menu.after_sync_roles 를 발화해, 메뉴 단건 수정과 같은 활동 로그·사용자 수정 기록이 남습니다.

활동 로그

  • 활동 로그(접속기록) 보관 기간을 정할 수 있습니다(환경설정 > 보안, 365~3650일, 기본 365일). 개인정보의 안전성 확보조치 기준의 접속기록 보관(1년, 회원 5만 명 이상·고유식별/민감정보 처리 시 2년)에 맞춰 늘릴 수 있고, 법정 최소보다 짧게는 저장되지 않습니다. 역할 정의·권한 구성·회원 역할 변경 기록은 이 값과 관계없이 최소 3년 보관합니다(권한 부여·변경 내역 3년 보관).
  • 관리자가 회원 등록·수정 화면에서 회원의 역할을 바꾸면 활동 로그에 「역할 변경」이 붙은 역할·뺀 역할과 함께 남습니다 — 종전에는 회원 정보 수정 로그에 묻혀 누가 언제 권한을 줬는지 따로 볼 수 없었습니다. 역할을 그대로 두고 저장하면 남지 않습니다. 확장 개발자용 훅 core.user.after_update_roles 를 추가했습니다(일괄 변경 훅 core.user.after_bulk_update_roles 의 짝).

개인정보 보유기간·휴면 계정

  • 보유기간이 지난 개인정보를 자동으로 파기할 수 있습니다. 환경설정 > 개인정보에서 켭니다.
    기본은 꺼져 있고, 켜면 매일 새벽 배치가 대상을 처리합니다.
    • 코어가 기본으로 다루는 것은 탈퇴 회원의 잔여 정보입니다. 탈퇴할 때는 분쟁 대응을 위해
      이름·이메일의 원값이 접미사 형태로 남는데, 정한 보유기간이 지나면 연락처·주소·자기소개와
      본인인증 식별자까지 실제로 지웁니다. 이름은 「탈퇴회원」, 이메일은 식별할 수 없는 형태로
      바뀌며 되돌릴 수 없습니다.
    • 화면의 뱃지가 지금 처리 대상이 몇 명인지 보여 줍니다. 꺼져 있어도 저장된 보유기간으로
      세어 보여 주므로 켜기 전에 규모를 확인할 수 있고, 그 숫자는 실제 처리 건수와 같은 기준으로 셉니다.
    • 뱃지 옆 **「대상 보기」**를 누르면 처리될 회원 명단(이름·이메일·탈퇴일)이 창으로 열립니다.
      한 번에 20명씩 보이고 아래로 스크롤하면 이어서 불러오며, 이름을 누르면 회원 상세가 새 탭으로
      열립니다. 명단에는 개인정보가 그대로 나오므로 회원 조회 권한까지 있는 관리자에게만 이 버튼이
      보입니다(설정 조회 권한만 있으면 건수만 보입니다). 회원 조회 권한을 「본인만」·「같은 역할만」으로
      좁혀 위임받은 관리자도 건수만 봅니다 — 명단은 전체 회원에서 모은 것이라 회원 목록보다 넓게 보이게
      되기 때문입니다.
    • 모듈·플러그인은 core.privacy.retention_handlers 훅으로 자기 도메인(주문·게시물 등)의
      보유기간 처리를 더할 수 있습니다. 처리기가 대상 명단과 명단 권한을 함께 내놓으면 그 확장의 설정
      화면에도 같은 「대상 보기」 창이 코어 수정 없이 붙습니다 — 계약은 개발자 문서 「개인정보 보유기간
      처리」에 있습니다. 한 확장이 실패해도 다른 도메인의 처리는 계속됩니다 —
      확장이 등록한 처리기가 이름조차 돌려주지 못하고 멈춰도 그 하나만 건너뛰고 나머지는 계속합니다.
    • 번들 이커머스·게시판이 이 훅으로 종결 주문과 게시물 작성 IP·비회원 작성자 정보의
      보유기간 처리를 더합니다. 각 모듈 환경설정에서 따로 켭니다(기본 꺼짐).
    • --handler= 처럼 처리기 이름을 빈 값으로 주면 이제 실행하지 않고 오류로 끝납니다.
      예전에는 빈 값이 「전체 실행」으로 해석되어, 한 도메인만 돌리려던 명령이 모든 도메인의
      파기로 번질 수 있었습니다. 전체를 돌리려면 옵션을 빼면 됩니다.
    • 서버에서는 php artisan privacy:process-retention --dry-run 으로 미리 볼 수 있습니다.
      개발 대시보드에도 미리보기·실행 버튼이 있습니다.
  • 오래 접속하지 않은 회원을 휴면으로 돌릴 수 있습니다. 환경설정 > 개인정보에서 켭니다.
    기본은 꺼져 있습니다.
    • 안내를 먼저 보냅니다. 전환 예정일 며칠 전에 「휴면 전환 예정」 안내가 이메일과 사이트
      알림으로 나가고, 그 기간이 지난 뒤에 실제로 전환됩니다. 기능을 처음 켠 날 이미 오래
      미접속인 회원이 그날 바로 휴면이 되는 일은 없습니다.
    • 로그인하면 곧바로 풀립니다. 별도 신청 절차가 없고, 풀렸다는 안내가 화면에 뜹니다.
      휴면 동안에는 서비스 이용이 제한되며, 이미 받아 둔 인증 토큰으로도 이용할 수 없습니다.
    • 미접속 기간은 로그인 시각만이 아니라 앱·토큰으로 접속한 시각까지 함께 봅니다. 토큰
      유지시간을 무한으로 둔 사이트에서 매일 쓰는 회원이 휴면으로 넘어가지 않게 하기 위함입니다.
    • 휴면 상태가 오래 이어진 계정을 탈퇴 처리하도록 따로 켤 수 있습니다. 이때도 탈퇴 예정
      안내를 먼저 보내며, 관리자 계정은 자동 탈퇴 대상에서 제외됩니다.
    • 회원 상태에 「휴면」이 추가되어 회원 목록·상세의 상태 표시와 상태 변경에서 함께 쓰입니다.
      휴면 전환·해제·탈퇴는 활동 로그에 남습니다.
    • 휴면으로 전환된 뒤에도 알림이 한 번 더 갑니다. 전환 예정 안내·전환 완료 안내·탈퇴 예정
      안내 세 가지가 이메일과 사이트 알림으로 나가며, 문구는 알림 설정에서 고칠 수 있습니다.
    • 화면에서도 네 단계(사전 안내·휴면 전환·탈퇴 예고·자동 탈퇴)의 대상 인원이 기능이 꺼져 있어도
      보이고, 단계마다 「대상 보기」로 그 회원 명단을 열 수 있습니다(범위 제한 없는 회원 조회 권한 필요).
      자동 탈퇴를 켜지 않았어도 켜면 탈퇴될 인원을 미리 봅니다. 명단의 「마지막 활동일」도 판정과 같이
      앱·토큰으로 접속한 시각까지 함께 봅니다.
    • 서버에서는 php artisan privacy:process-dormant --dry-run 으로 단계별 대상 건수를 볼 수
      있습니다. 개발 대시보드에도 버튼이 있습니다.
  • 개인정보 조치를 관리자가 화면에서 즉시 실행할 수 있습니다. 새벽 배치를 기다리지 않고
    환경설정 > 개인정보의 탈퇴 잔여정보 파기와 휴면 네 단계(사전 안내·휴면 전환·탈퇴 예고·탈퇴 처리)를
    카드의 「지금 실행」으로 한 번 돌립니다. 확장의 보유기간·통지 설정 화면에도 같은 버튼이 붙으며,
    어느 화면이든 조치 대상이 대상마다 한 줄로 정리되어, 이름·대상 건수 옆에 그 대상의
    「대상 보기」·「지금 실행」과 마지막 실행 결과가 함께 있습니다.
    • 자동 실행을 꺼 둔 채로도 돌릴 수 있습니다. 저장된 기간·방식으로 이번 한 번만 처리하므로,
      매일 자동으로 돌리지 않고 필요할 때만 손으로 처리하는 운영이 가능합니다.
    • 누르면 확인 창이 지금 처리될 건수와 처리 방식(익명화·삭제 등)을 다시 세어 보여 주고, 되돌릴
      수 없다는 경고 뒤에 실행합니다. 저장하지 않은 설정 변경이 있으면 버튼이 막힙니다.
    • 실행은 큐에 접수되어 차례로 처리되고, 카드에 「처리 대기·처리 중」이 떴다가 끝나면
      「마지막 직권 실행: 일시 · 실행자 · N건 처리」(실패하면 사유)로 바뀝니다. 대상 건수도 처리된 만큼
      다시 셉니다. 큐 워커가 돌아야 처리되며, 워커가 멈춰 6시간 넘게 끝나지 않은 접수는 실패로 정리됩니다.
    • 같은 대상에 접수된 작업이 끝나기 전에는 다시 실행할 수 없습니다. 보유기간 파기·휴면은 새벽 배치와도
      겹치지 않습니다 — 배치가 처리 중이면 작업이 기다렸다 이어서 돌고, 직권 실행이 처리 중이면 배치가 그 대상을
      건너뜁니다. 연간 통지는 회원별로 접수를 직렬화하므로 정기 발송과 겹쳐도 같은 회원에게 두 번 가지 않습니다.
    • 휴면 전환·탈퇴 단계는 확인 창에서 **「대기기간 생략」**을 고를 수 있습니다(기본 해제). 생략하면
      안내를 받지 못했거나 안내 후 기간이 지나지 않은 회원도 기간만 지났으면 바로 처리합니다 — 법이
      요구하는 사전 안내를 건너뛰는 선택이라 운영자 책임 아래에서만 씁니다. 관리자 계정은 이때도 탈퇴되지
      않습니다.
    • 실행 권한은 설정 수정 + 그 도메인 수정 권한(범위 제한 없이)입니다 — 회원 파기는 회원 수정, 주문
      처리는 주문 수정(삭제 방식이면 주문 삭제까지) 권한이 함께 있어야 버튼이 보입니다.
    • 접수와 완료·실패는 활동 로그에 남습니다(실행자·대상·처리 건수·대기기간 생략 여부).
    • 확장은 보유기간 처리기만 등록하면 이 버튼이 따라옵니다. 처리기가 아닌 조치는
      core.privacy.manual_run_targets 훅으로 더합니다 — 계약은 개발자 문서 「개인정보 보유기간 처리」의
      「관리자 직권 실행」에 있습니다.
  • 개인정보 통지에 확장별 처리 내역을 기여하는 core.privacy.notice_sections 계약을 추가했습니다. 알림 데이터의 context.channels로 발행자가 선택한 채널만 발송할 수 있습니다.

방문자 동의

  • 방문자 동의 공개 계약을 추가했습니다. 쿠키·추적 동의를 관리하는 확장(예: GDPR 플러그인)이 무엇이든, 다른 확장과 코어는 같은 방법으로 「이 방문자가 무엇에 동의했는가」를 물을 수 있습니다. 브라우저에서는 전역 상태 _global.consent(contractVersion·status·categories·needsRenewal·policyVersion)와 G7Core.consent.getSnapshot()·refresh()·subscribe(), 레이아웃의 refreshConsent 동작과 consent:changed 컴포넌트 이벤트로 읽고, 서버에서는 GET /api/consent 로 묻습니다. 로그인·로그아웃하면 스냅샷을 비우고 다시 조회하며, 그 사이에 도착한 이전 응답은 반영하지 않습니다. 판단할 수 없으면 unknown 으로 두어 동의하지 않은 것으로 다루게 했고, 회원 번호·게스트 식별자는 응답에 싣지 않습니다. 동의를 관리하는 확장은 ConsentProviderInterface 를 구현해 core.consent.registered_providers 필터로 등록하고, 동의가 바뀌면 core.consent.changed 액션으로 알립니다. 방문자 통계도 이 계약으로 동의를 판정하며, 동의 관리 확장을 고르지 못한 상태면 통계 설정의 「동의 출처」가 「제공자 선택 필요」로 표시됩니다. (#129 @glitter-gim 님께서 건의해주셨습니다.)
  • 관리자 > 환경설정 > 개인정보 탭 맨 위에 「동의 관리 제공자」 카드를 추가했습니다. 동의 관리 확장이 둘 이상이면 여기서 하나를 고르고, 비워 두면 하나뿐일 때 자동으로 그것을 씁니다. 둘 이상인데 고르지 않았거나 고른 확장이 비활성화되면 카드가 경고를 띄우고, 고르기 전까지 모든 방문자의 동의는 「확인 불가」로 처리되어 외부 스크립트와 방문자 통계가 멈춥니다.

방문자 통계

  • 코어가 방문자 통계를 직접 모읍니다. 외부 분석 도구 없이 동작하고 방문 데이터는 사이트 안에만
    남습니다. 방문·페이지뷰·유입 경로·브라우저와 기기·지역·사이트 내부 검색어·내려받은 파일·외부 링크
    클릭이 기록되고, 봇 방문은 사람 방문과 섞이지 않게 따로 셉니다.
    개인정보 수집 수준은 세 모드(IP 저장 / 동의 연동 / 익명) 중에 고릅니다. IP 마스킹 정도,
    추적 거부(DNT) 존중, 유입 주소 익명화, 회원 번호 가명화를 각각 켜고 끌 수 있습니다. 익명 모드의
    방문자 구분값은 날마다 바뀌는 해시라 어제와 오늘을 이어 붙일 수 없습니다 — 그래서 재방문은 셀 수
    없습니다. 익명으로 도는 동안에는 수집 실패 기록에도 IP 를 남기지 않습니다. 동의 연동을 골랐는데 동의를 확인할 곳이 없으면 아무것도 모으지 않는 대신 익명 모드로
    내려가고, 그 사실을 화면이 알립니다. 쿠키 동의 관리 플러그인이 켜진 사이트에서는
    방문자가 동의하기 전에는 브라우저에 식별 쿠키를 남길 수 없으므로, 「IP 저장」 모드라도 분석·기능
    쿠키에 모두 동의하기 전의 방문자는 익명으로 모으고 동의한 방문자만 IP·방문자 쿠키로 모읍니다.
    그러지 않으면 한 사람의 이동이 방문 여러 건으로 흩어져 방문자 수가 부풀고 이탈률이 100% 로 보입니다.
    자바스크립트가 막힌 방문자도 세도록 서버 쪽 기록을 함께 두었고, 같은 페이지가 두 번 세어지지
    않도록 브라우저가 보낸 것과 하나로 합칩니다. 브라우저가 미리 그려 둔 화면은 실제로 열렸을 때 세고,
    너무 긴 제목·주소는 보내기 전에 줄여 방문 기록이 통째로 버려지지 않게 합니다. 수집이 실패해도 방문자가 보던 화면은 영향을 받지
    않으며, 무엇이 왜 빠졌는지는 진단용 기록에 남습니다.
    업데이트 직후부터 「IP 저장」 모드로 수집이 시작되며 설정에서 언제든 끌 수 있습니다.
  • 관리자 화면에 방문자 통계가 생겼습니다 — 오늘·어제·최대·전체 방문자와 추이, 인기 페이지, 유입
    경로, 브라우저·기기·지역, 내부 검색어, 요일과 시간대 이용 패턴, 실시간 접속자, 봇 방문을 화면 열넷에서
    봅니다. 기간은 프리셋이나 날짜로 고르고 그 선택이 주소에 남아 화면을 옮기거나 링크를 나눠도 같은
    기간이 열리며, 기간을 여러 번 바꿔 본 뒤 뒤로 가기로 직전 기간에 돌아갑니다. 관리자 대시보드에는 오늘·어제·최대·전체와 최근 이레 추이를 담은 카드가 붙고,
    사용자 홈 맨 아래에는 방문자 카운터를 켤 수 있습니다(끄면 숫자를 내려보내지 않습니다).
  • 방문자 통계에서 어느 글에서 왔는지까지 봅니다. 유입 경로의 「유입 사이트」에서 도메인 줄을 누르면
    그 도메인에서 들어온 실제 주소가 방문 수 순으로 펼쳐지고, 방문자 상세의 방문마다 전체 유입 주소가
    붙어 CSV 에도 함께 나갑니다(유입 URL 익명화를 켠 기간의 방문은 저장 시점에 도메인까지만 남습니다).
    방문자 목록은 로그인 회원을 번호가 아니라 이름으로 보여 주고, 이름을 누르면 회원 정보를 새 창으로
    열거나 그 회원의 방문만 골라 볼 수 있습니다.
  • 관리자 화면의 재집계 진행률이 실시간으로 움직입니다. 집계가 진행률을 갱신할 때마다 관리자 채널로
    방송하고, 실시간 서버(Reverb)가 없는 사이트는 진단 화면이 2초마다 물어보는 방식으로 같은 값을 봅니다.
  • 방문자 통계의 모든 시각은 사이트 표준시 기준으로 나옵니다 — 집계 경계가 사이트 자정이므로
    「오늘」의 숫자와 목록의 날짜가 같은 하루를 가리킵니다. 보는 사람의 시간대가 사이트와 다르면 통계
    화면이 그 사실을 함께 알립니다.
  • 방문과 사이트 내부 검색은 작업 처리기(queue:work) 없이 요청 안에서 바로 기록됩니다. 브라우저
    신호는 화면 그리기를 기다리게 하지 않고 서버 쪽 기록은 응답을 보낸 뒤에 돌아 방문자가 기다리는
    시간은 늘지 않습니다. 집계·익명화처럼 오래 걸리는 일만 작업 처리기가 맡습니다.
  • 방문자 상세·정보주체 요청·수집 진단은 보여 주는 주소가 마스킹된 값인지 함께 알립니다. 현재
    접속자 목록은 회원 이름과 회원 화면으로 가는 길을 보여 주고, 방문자 상세의 단건 CSV 파일 이름에는
    조회 기간이 들어가 같은 사람을 두 기간으로 받아도 앞 파일을 덮지 않습니다. 다른 집계가 돌고 있어
    재집계가 건너뛰어지면 화면이 그 사실을 그대로 알립니다.
  • 관리자 메뉴에 방문자 통계가 대시보드 다음 자리로 들어갑니다. 그에 맞춰 기존 코어 메뉴의 순서가
    한 칸씩 밀립니다(관리자 화면에서 순서를 직접 바꿔 둔 메뉴는 그대로 둡니다).
  • 방문자 통계에 회원가입과 로그인이 전환으로 기록됩니다. 관리자 「검색어·다운로드·전환」 화면의
    전환 탭에서 방문이 가입·로그인으로 이어진 횟수를 봅니다(가입은 방문자당 한 번, 로그인은 방문당 한 번).
  • 확장을 「데이터도 삭제」로 제거하면 그 확장이 방문자 통계에 남긴 전환과 집계도 함께 지워지고,
    수집 진단의 실행 이력에 그 정리가 남습니다. 데이터를 남기고 제거하거나 끄기만 하면 과거 수치는
    그대로이고, 그 확장의 분류 기준은 검색어·다운로드·전환 › 확장별 분류 탭에서 「꺼진 확장」으로 계속 볼 수 있습니다.
  • 확장 개발자용: 방문자 통계에 확장이 기여하는 지점이 열렸습니다. 모듈·플러그인은 진입 클래스의
    getAnalyticsGoals()·getAnalyticsDimensions() 로 전환(목표)과 분류 기준을 먼저 선언하고,
    선언한 것만 기록됩니다(선언 밖의 값은 버리고 수집 진단에 사유를 남깁니다). 서버에서 전환을 남기는
    ConversionRecorderInterface, 판정표(검색엔진·캠페인·추적 파라미터·브라우저 판정)와 방문 제외
    규칙을 보태는 필터, 정보주체 삭제·내보내기·전체 삭제·소급 익명화에 확장 데이터가 함께 참여하는
    필터(삭제는 코어와 같은 트랜잭션), 하루 집계에 확장 행을 얹는 훅, CSV 열·진단·실시간·저장소 현황
    출력에 붙는 필터, 통계 화면 열한 곳의 레이아웃 확장 지점을 제공합니다. 이 밖에 방문자의 동의 여부를
    답하는 자리, 비콘 검증 규칙을 넓히는 자리, 적재 결과를 지켜보는 자리도 훅으로 있습니다. 수집 중에
    도는 확장 훅·필터가 오류를 내도 방문은 코어 기본값으로 그대로 기록되고, 수집 진단 「최근 적재
    실패」에 「리스너 예외」로 어느 훅인지 남습니다. 확장이 집계에 얹은 행 하나(너무 긴 분류 기준 이름·같은 라벨 중복)가 그날
    집계를 멈추지도 않습니다. 브라우저에서 넣은 분류 값은 그 화면의 비콘에만 실립니다. 잘못 선언해 버려진 목표·분류 기준은 그 사유가 수집 진단 화면 맨 위에 보이고, 데이터를 남기고
    제거한 확장의 통계는 php artisan analytics:purge-extension {module|plugin} {식별자} --confirm 으로 나중에
    지울 수 있습니다. 번들 확장 가운데 전환·분류 기준을 선언하는 것은 아직 없고, 동의 관리 플러그인만 방문자의
    동의 여부를 답하는 자리를 씁니다(그 플러그인은 이미 이 코어 버전을 요구합니다).
  • 모아 둔 방문 기록이 숫자로 정리됩니다. 시간·일·리포트별 집계가 매시(오늘치 다시 계산)와
    매일(어제치 확정) 자동으로 돌고, 관리자 화면은 원장이 아니라 이 집계를 읽습니다 — 몇 달치가 쌓여도
    화면이 느려지지 않고, 보존 기간이 지나 원장을 지워도 과거 숫자는 그대로 남습니다. 집계 규칙이 바뀌면
    지난 기간을 다시 계산할 수 있습니다.
  • 관리자 API 로 오늘·어제·최대·전체 방문자와 추이, 인기 페이지·유입 경로·브라우저와 기기·지역·
    검색어·내려받은 파일·외부 링크, 요일과 시간대 이용 패턴, 현재 접속자, 봇 방문
    을 조회합니다.
    기간은 프리셋(오늘·어제·7일·30일·90일·이번 달·지난달·올해)이나 날짜로 고르고, 「관리자 제외」·
    「회원 제외」를 켜면 그 방문이 합계에서 빠집니다. 상위 목록 표와 추이·방문자 활동은 CSV 로 내려받아 엑셀에서 바로
    열 수 있습니다
    (한글이 깨지지 않습니다). 봇 방문은 「어느 봇이 얼마나」에 더해 최근 요청 50건을
    함께 보여, 어떤 주소를 언제 긁어 갔는지 보고 차단 여부를 판단할 수 있습니다. 입력이 잘못되면 오류 문구가
    필드 키 대신 항목 이름(「종료일」·「원장 보존」 등)으로 나옵니다 — 환경설정의 방문자 통계 탭에서 저장할 때도 같습니다.
  • 권한이 셋으로 갈립니다. 통계 조회는 숫자만, 통계 설정은 설정 저장·집계 실행·데이터 삭제까지,
    방문자 개인정보 열람은 개별 방문자의 기록과 IP 까지 봅니다. 조회 권한만 준 계정에는 현재 접속자
    목록이 보이되 그 IP 는 비어서 나옵니다.
  • 보존 기간이 지난 기록이 자동으로 정리됩니다. 방문·액션·전환은 보존일(기본 90일)이 지나면
    지워지고, 시간 단위 집계·봇 기록·실패 기록은 각자의 보존일을 따릅니다. 일 단위 집계와 주소·제목
    사전은 지우지 않으므로 과거 통계는 남습니다. 보존일을 7일보다 짧게 줄일 수는 없습니다.
  • 기록이 너무 많이 쌓이면 알려 줍니다. 방문·액션이 운영자가 정한 한계를 넘으면 메일·알림함으로
    하루 한 번 알리고, 관리자 대시보드에도 보존 설정으로 가는 안내가 뜹니다. 집계가 실패했을 때도
    같은 방식으로 알립니다.
  • 주간·월간 방문 요약 메일을 켤 수 있습니다(기본 꺼짐). 지난 기간의 방문·방문자·페이지뷰와
    증감, 인기 페이지·유입처가 담깁니다.
  • 수집이 안 되는 이유를 진단 화면 하나에서 봅니다 — 큐 워커가 멈췄는지, 프록시 설정이 없어
    방문자 주소가 하나로 뭉치는지, 집계가 밀렸는지, 무엇이 왜 제외됐는지, 지역 조회·실시간 푸시·
    차단 목록이 준비됐는지.
  • 개인정보 수집 수준을 더 엄격하게 바꾸면 이미 쌓인 기록에도 소급 적용할지 물어봅니다. 방문자
    주소를 가리거나 해시로 바꾸고, 유입 주소는 도메인까지만 남기며, 회원 번호는 가명으로 바꿉니다.
    집계는 건드리지 않습니다.
  • 정보주체 요청에 답할 수 있습니다. IP·회원 번호·방문자 키로 그 사람의 방문을 찾아 목록으로
    보고, 활동 내역을 JSON 파일로 내려받아 요청한 사람에게 그대로 건네고, 지울 수 있습니다.
    지우는 것은 방문 기록뿐이고 집계는 남습니다.
    기록 전체를 지우는 길도 있습니다(되돌릴 수 없어 확인을 거칩니다).
  • 운영자가 자기 브라우저를 통계에서 뺄 수 있습니다 — 사이트를 손보는 동안 자기 방문이 인기
    페이지 1위가 되지 않습니다.
  • 사용자 화면이 읽을 공개 방문자 요약(오늘·어제·최대·전체)이 생겼습니다. 끌 수 있고, 개인을
    가리키는 값은 나가지 않습니다.
  • 스케줄러(cron)가 없어도 방문자 통계가 최신 숫자를 보여 줍니다. 관리자가 통계 화면(개요·페이지·유입·환경·지역·
    행동·요일·시간대·봇, 대시보드 방문자 카드)을 열거나 새로고침하면 마지막 집계가 1분 넘게 지났을 때 그 자리에서
    오늘치를 다시 집계합니다. 여러 관리자가 동시에 열어도 1분에 한 번만 돌고, 오늘 방문이 상한(기본 50,000건)을 넘으면
    요청 안에서는 집계하지 않습니다. 설정 「방문자 통계 → 보존 → 집계」에서 끄거나 상한을 바꿀 수 있습니다.
  • 스케줄러가 멈춘 동안 확정되지 않은 날을 자동으로 확정합니다. 매일 확정 실행과 화면 열 때 집계가 보존기간
    안에서 밀린 날을 최근 날부터 최대 7일 확정합니다.
  • 모든 집계 화면의 기간 줄에 「마지막 집계 22:07 · …」가 보이고, 문제가 있으면 상단에 알립니다. 스케줄러가
    2시간 넘게 돌지 않았으면 「어제 확정·정리·메일 보고서가 멈춘다」는 안내를, 화면 열 때 집계를 끈 채 집계가 멈췄거나
    오늘 방문이 상한을 넘어 집계하지 않았으면 경고와 「지금 집계」 버튼(설정 권한 계정)을 띄웁니다. 수집 진단의 집계
    카드에도 스케줄러 마지막 실행과 「스케줄러 미가동」 표시가 생겼습니다.
  • 리포트 목록의 각 줄에서 그 항목의 날짜별 추이를 볼 수 있습니다. 줄 끝 그래프 아이콘을 누르면 기간 동안의 방문·
    조회 추이가 창으로 뜹니다(92일까지 일, 그 뒤 주 단위).
  • 개요 추이에 신규·재방문 선이 더해지고 품질 줄에 신규·재방문 카드가 생겼습니다. 범례를 눌러 선을 켜고 끕니다.
    익명 모드처럼 구분할 수 없는 기간은 「구분할 수 없습니다」로 표시합니다. 추이 CSV 에도 두 열이 붙습니다.
  • 새 리포트 다섯 가지 — 유입 경로 「캠페인 매체」, 검색어·다운로드·전환 「검색 탭」·「이벤트」, 페이지 「체류시간
    구간」·「본 페이지 수 구간」. 구간 경계는 설정에서 바꿀 수 있고 바꾼 뒤 집계부터 적용됩니다.

알림

  • 관리자 화면에 회원 알림함이 생겼습니다. 회원이 받은 알림이 지금 어떤 상태인지 —
    남아 있는지, 읽었는지 — 를 전 회원 범위로 보고 지울 수 있습니다. 「알림이 안 왔다」는
    문의를 받으면 발송 기록만 보고 짐작하던 것을, 회원 화면에 실제로 무엇이 남아 있는지로
    확인합니다. 수신자·제목·본문으로 각각 찾을 수 있고, 읽음/안 읽음과 수신 기간으로 좁힙니다.
  • 회원 상세에 「알림함」 탭이 생겼습니다. 그 회원의 총 알림 수와 안 읽은 수를 보여 주고,
    누르면 그 회원으로 좁힌 알림함 목록으로 넘어갑니다.
  • 확장이 회원 알림함 목록에 조건을 더할 때 그 조건의 이름도 붙일 수 있습니다. 훅 core.member_notification.index_validation_attributes 를 새로 두었고(기존 core.member_notification.index_validation_rules 와 함께 씁니다), 잘못된 조회 값의 안내 문구가 내부 키 대신 「검색 대상」 같은 항목 이름으로 나옵니다.
  • 확장이 만드는 알림 설정 화면이 여러 발송 수단을 한 화면에서 다룰 수 있습니다. 종전에는 알림 목록이 한 번에 한 수단의 문구만 내려 주어, 수단을 바꿔 볼 때마다 화면을 다시 불러야 했습니다. 이제 켜 둔 수단 전부의 문구를 한 번에 받아 한 목록에 보여줄 수 있습니다. 기존 화면의 동작과 응답 크기는 그대로입니다.
  • 알림을 받는 사람마다 내용을 다르게 만들 수 있는 확장 지점이 생겼습니다. 같은 알림이라도 운영자에게는 관리자 화면 주소를, 고객에게는 내 주문 화면 주소를 보내는 식으로 확장이 값을 바꿀 수 있습니다. 이 지점을 쓰는 확장이 없으면 동작은 종전과 같습니다.
  • 알림 템플릿의 역할 수신자를 여러 개 지정할 수 있습니다. 종전에는 역할을 하나만 고를 수 있어 「최고관리자 + 고객센터」처럼 두 역할이 함께 받아야 하는 알림은 같은 알림을 나눠 만들거나 포기해야 했습니다. 이미 저장해 둔 한 개짜리 설정은 그대로 동작합니다.
  • 수신자 규칙의 「관련 사용자」를 그 알림이 제공하는 관계 중에서 고릅니다(상품 문의 답변 알림의 「문의 작성자」, 댓글 알림의 「게시글 작성자」 등). 선택지와 알림 목록은 관계를 이름으로 보이며, 확장은 그 이름을 언어 파일(messages.notification_relations)에 둡니다. 종전에는 관계 이름을 글자로 직접 적어야 했고, 잘못 적어도 저장은 되며 발송 시점에 아무에게도 가지 않는 것으로만 드러났습니다. 관계를 제공하지 않는 알림에서는 이 선택지가 표시되지 않습니다.
  • 알림 본문 편집기가 채널에 맞춰 열립니다. 메일은 서식 편집기로, 사이트내 알림은 평문 입력으로 열리며, 문자·알림톡처럼 채널을 제공하는 확장이 자기 입력 양식을 두는 채널에서는 그 양식만 표시됩니다. 종전에는 모든 채널이 같은 평문 입력이라 메일에 서식을 넣으려면 HTML 을 손으로 적어야 했고, 같은 내용을 사이트내 알림에 넣으면 태그가 글자 그대로 보였습니다.

본인인증

  • 본인인증 정책별 문구를 추가·삭제하는 API(POST·DELETE /api/admin/notification-definitions/{id})와, 링크 방식 본인인증의 결과를 인증을 시작한 화면이 받아 가는 POST /api/identity/challenges/{id}/claim(일회용 claim_secret, 파라미터 확장 훅 core.identity.claim_validation_rules)을 추가했습니다.

확장 관리

  • 관리자 모듈·플러그인·템플릿·언어팩 관리 화면에 갤러리(바둑판) 보기가 생겼습니다. 기본 보기이며
    목록 보기로 바꾸면 그 선택이 브라우저에 기억되고, 네 화면이 같은 선택을 함께 씁니다. 화면이 넓을수록
    한 줄에 더 많은 카드가 놓입니다.
  • 확장과 언어팩이 자기 아이콘을 함께 담을 수 있습니다. 패키지 안 assets/icon.svg 를 두거나
    설정 파일에 icon 항목을 적으면 됩니다. 종전에는 관리자 모듈·플러그인·템플릿·언어팩 관리 화면이
    모두 종류별 기본 그림만 보여 주어 어느 확장인지 그림으로 구분되지 않았습니다. 아이콘은 목록·상세와
    설치·업데이트·삭제 확인 창, 그리고 설치 마법사에 표시되고, 언어팩은 대상 확장의 아이콘에 언어 표시를
    얹어 보여 줍니다.
    아이콘을 넣지 않은 확장은 종전처럼 종류별 기본 그림으로 표시됩니다.
  • 수동 설치 미리보기가 패키지 안 아이콘의 규격(정사각·크기·안전성)을 검사해 알려 줍니다.
    규격에 맞지 않아도 설치는 막지 않으며, 그 확장은 종류별 기본 그림으로 표시됩니다.
  • php artisan template:uninstall 에 --force(확인 없이 제거)와 --delete-data(「데이터도 삭제」를 고른 것으로 제거) 옵션을
    추가했습니다. 모듈·플러그인 제거 명령과 같은 옵션입니다.
  • 모듈·플러그인·템플릿을 업데이트할 때 새 버전이 요구하는 의존 확장이 없거나 꺼져 있거나 버전이 모자라면 경고합니다. 업데이트는
    그대로 진행하고, 업데이트 완료 안내(관리자 화면)와 명령행·번들 일괄 업데이트 출력에 「단, 의존 확장이 요구 조건에 못 미칩니다 — …」가
    붙습니다. 종전에는 의존성을 설치할 때만 검사해, 예를 들어 이커머스를 옛 버전으로 둔 채 결제 플러그인만 업데이트해도 아무 안내가 없었습니다.
    번들 확장 일괄 업데이트는 같은 종류 안에서도 의존하는 확장을 뒤에 업데이트합니다.

레이아웃 마크업 형식

  • 화면 레이아웃을 HTML 에 가까운 마크업 형식(.g7.html)으로 작성할 수 있습니다. 여닫는 태그로 화면 구조가 눈에 그대로 드러나고, 화면 곳곳에 설명 주석을 남길 수 있습니다. 기본 제공되는 모든 화면이 이 포맷으로 함께 제공됩니다. 플러그인 설정 화면도 .g7.html 소스만으로 열립니다.
  • 기존 JSON 레이아웃은 그대로 유효합니다. .g7.html 은 짝이 되는 JSON 과 항상 같은 결과로 변환되므로 화면 동작이 달라지지 않으며, JSON 만 쓰던 환경도 종전과 동일하게 동작합니다.
  • 소스 파일을 저장·설치하는 시점에 문법과 구조를 검증해, 지원되지 않는 표기나 잘못된 중첩을 화면에 반영되기 전에 알려줍니다.
  • JSON 레이아웃과 .g7.html 을 서로 바꾸는 명령을 추가했습니다. php artisan layout:compile 은 JSON 을 .g7.html 로 바꾸고, php artisan layout:decompile 은 .g7.html 을 JSON 으로 바꾸며(--sync 로 짝 JSON 갱신, --check 로 짝 JSON 이 최신인지 확인), 두 명령 모두 변환 결과가 원본과 같은지 왕복으로 검증합니다.
  • 관리자 레이아웃 코드 편집기가 화면을 HTML(.g7.html) 형식으로 열고 저장합니다. 저장소에는 종전대로 JSON 만 두며, 열 때 변환하고(GET …?with_markup=1) 저장·미리보기 때 컴파일합니다(format=markup). 저장 없이 변환만 하는 POST …/markup-compile 이 추가되어 편집 중 문법 오류를 줄 단위로 알려 줍니다.
  • 레이아웃 코드 편집기의 검사 경고·보안 검사 오류가 문제가 있는 줄·칸을 함께 보여 주고, 그 항목을 누르면 코드 편집기가 그 줄로 이동합니다. 한 이벤트에 기다렸다 실행하는 동작(debounce)과 바로 실행하는 동작을 섞어 적으면 기다리는 동작도 입력할 때마다 실행된다고 경고하고, 조건 분기(<when>·<case>)·순서 실행(<sequence>)·결과 처리(onSuccess 등) 안쪽 액션에 적은 debounce 는 적용되지 않으므로 「감싸는 바깥 액션에 다세요」로 알립니다. 휴대폰 폭에서는 파일 설명·수정일·안내를 접어 두어 코드 칸을 넓게 쓰고, [파일 정보 펼치기]로 엽니다.
  • 마크업의 인라인 팝업 창에 이름을 적을 수 있습니다(<modal name="…">). 설치가 팝업 조각을 화면 안에 펼칠 때 남기는 이름이라, 편집기로 연 설치본을 다시 마크업으로 되돌릴 때 이 자리가 필요했습니다.
  • 마크업의 외부 스크립트 선언에 사람이 읽는 이름을 적을 수 있습니다(<script src="…" id="…" label="$t:…">). 스크립트를 끝내 불러오지 못했을 때 안내가 그 이름(없으면 「화면 기능 스크립트」)으로 나오며, 스크립트 식별자는 화면에 보이지 않습니다.
  • 마크업에서 화면 안에 펼쳐진 조각의 이름을 적을 수 있습니다(data-layout-name="…"). 팝업 창은 그 본문에 <data-source> 를 얹어 창이 열릴 때 받을 것을 적습니다. 설치가 조각을 화면 안에 펼치며 남기는 두 자리라, 편집기로 연 설치본을 다시 마크업으로 되돌릴 때 필요했습니다.
  • 설치된 화면과 조각 전체가 편집기에서 열고 저장할 수 있는 상태인지 점검하는 php artisan layout:check-installed 를 추가했습니다. 조각 등록 누락·중복·잘못된 템플릿 등록도 함께 보고합니다.
  • 7.0 에서 만든 JSON 레이아웃 확장에 찾을 수 없는 조각 참조가 있어도 설치·활성화·업데이트를 막지 않고 그 자리를 비운 채 등록합니다. 관리자 화면은 확장을 켜거나 템플릿을 설치할 때 빠진 조각 참조 건수를 경고 알림으로 보여 주고, 어느 파일의 어느 조각이 빠졌는지는 서버 로그, 명령 출력, php artisan layout:check-installed 의 「JSON 조각 참조 누락」 표로 알려 줍니다. .g7.html 레이아웃의 같은 문제는 종전대로 오류로 알립니다.
  • 레이아웃 편집기에서 편집 중인 템플릿의 컴포넌트 목록에 없는 컴포넌트를 이미 담고 있는 화면·조각도 저장할 수 있습니다(7.0 이 다른 템플릿용으로 함께 등록해 둔 조각 등). 이미 있던 컴포넌트는 "이 템플릿에서는 그려지지 않을 수 있다" 는 경고로 알리고, 새로 적은 목록 밖 컴포넌트는 종전대로 오류로 막습니다.
  • 7.0 에서 올린 사이트는 7.1.0 업데이트 때 확장 조각을 조각 파일 이름 기준으로 옮겨 둡니다. 템플릿이 덮어쓴 조각을 고쳐 둔 내용이 첫 업데이트에서 사라지거나 같은 조각이 화면에 두 번 나타나지 않게 하려는 것이며, 어느 조각이었는지 정할 수 없는 고친 조각은 그대로 두고 업데이트 기록에 남깁니다.

레이아웃 파일 관리 API

  • 관리자 화면에서 레이아웃 파일을 만들고, 이름을 바꾸고, 지울 수 있습니다
    (POST …/layouts · PATCH …/layouts/{name}/rename · DELETE …/layouts/{name}).
    종전에는 이 세 가지를 하려면 데이터베이스를 직접 열어야 했습니다.
    • 삭제는 되돌릴 수 있게 남겨 둡니다. 다만 다른 화면이 그 파일을 쓰고 있으면 막고, 무엇이
      쓰고 있는지(상속·조각 참조) 목록으로 알려 줍니다. 참조를 자동으로 고쳐 주지는 않습니다 —
      화면 정의 안의 표현식까지 건드리면 되돌릴 수 없는 손상이 되기 때문입니다.
    • 확장이 제공한 원본은 지우거나 이름을 바꿀 수 없습니다. 지우면 그 확장이 깨집니다.
    • 이름변경은 같은 행을 옮기므로 판본 이력이 그대로 이어집니다.
  • 레이아웃 본문 검색이 추가됐습니다(GET …/layouts/search). 검색 대상은 저장된 JSON 이 아니라
    편집기가 보여 주는 .g7.html 마크업이라, 결과의 줄 번호가 편집기의 줄 번호와 같습니다.
    변환 결과는 저장 번호를 키로 캐시하므로 저장할 때 그 파일만 자동으로 새로 계산됩니다.
  • 확장의 사용자 추가 자산(custom/)에 이름변경과 검색이 추가됐습니다
    (POST …/custom-assets/rename · GET …/custom-assets/search). 이름변경은 대상 자리에 파일이
    이미 있으면 덮어쓰지 않고 막으며, 확장자를 바꾸는 이름변경도 막습니다 — 그 파일이 더 이상
    실리지 않게 되는데 화면에는 그대로 보이기 때문입니다.

레이아웃 편집기

  • 관리자 코드 편집기에서 저장하지 않은 편집분이 사라지던 경로 세 곳을 막았습니다. 편집기를 두 탭에
    띄웠을 때 한쪽이 다른 쪽 초안을 지우던 문제, 지워진 파일의 편집분이 빈 화면과 «요청한 리소스를 찾을 수
    없습니다» 로만 나타나던 문제, 며칠 전 초안이 복원 배너에 영원히 쌓이던 문제입니다. 지워진 파일의
    편집분은 이제 읽기 전용으로 보여 주고 새 이름으로 살릴 수 있습니다.
  • 화면 편집기 요소 속성 창의 [동작] 탭에 「검색어를 입력하면」이 추가되었습니다. 검색해서 고르는 선택 항목에 입력한 글자로 목록을 불러오는 동작을 붙일 수 있습니다.
  • 화면 편집기 [동작] 탭에서 한 칸에 기다렸다 실행하는 동작(debounce)과 바로 실행하는 동작을 함께 넣으면 그 칸에 경고를 보여 줍니다. 바로 실행하는 동작이 돌 때마다 기다리던 동작도 곧바로 실행되기 때문입니다(동작 방식은 그대로입니다).
  • 화면 편집기 [동작] 탭에서 값을 그대로 넘기는 부품(검색 드롭다운·태그 선택·필터 묶음 등)의 「값이 바뀌면」 칸 위에, 바뀐 값을 동작 값 칸에서 {{$args[0]}}(필터 묶음은 {{$args[1]}})로 읽는다는 안내를 보입니다.
  • 이미 저장된 레이아웃을 강화된 보안 검사로 다시 훑는 php artisan layout:audit-expressions 를 추가했습니다. 레이아웃·확장 조각·버전 이력·미리보기와 레이아웃 파일을 검사해 위반 위치만 알려 주고 값은 바꾸지 않습니다(위반이 있으면 종료 코드 1). 개발 대시보드에도 버튼이 있습니다.

템플릿 엔진

  • 화면 이동 액션 navigate 의 주소만 바꾸는 이동(replace: true)에 refetch_data_sources 를 줄 수 있습니다(engine-v1.79.0). 적은 데이터 소스만 다시 받고, 생략하면 종전처럼 자동으로 받는 데이터 소스를 전부 다시 받습니다. 설정 폼과 목록이 한 화면에 있을 때 목록의 검색, 필터, 쪽 넘김이 고친 설정 칸을 저장된 값으로 되돌리지 않게 하는 데 씁니다. 레이아웃 편집기의 「다른 페이지로 이동」 폼에도 같은 칸이 있습니다.
  • 언어 전환 인계 G7Core.locale.handoff(isSwitching(), stash(), take())를 추가했습니다(engine-v1.79.0). 언어를 바꾸면 같은 화면을 새로 그리므로, 컴포넌트 안에만 있는 저장 전 상태(업로더가 고른 대기 파일 등)를 전환 전에 맡기고 새로 그린 뒤 되찾는 데 씁니다.
  • G7Core.locale.change(locale, { persist: false }) 로 언어를 바꾸면서 로그인 회원의 언어 저장을 건너뛸 수 있습니다(engine-v1.79.0). 회원 언어를 직접 저장한 화면이 저장 요청을 두 번 보내지 않게 할 때 씁니다.
  • 화면 동작에 "상위로 전파하지 않음" 을 지정할 수 있습니다. 목록의 각 행 전체가 눌리는 구조에서 행 안의 토글이나 버튼만 반응시켜야 할 때 쓰며, 이 지정이 없던 동안에는 행 안의 컨트롤을 눌러도 행 선택이 함께 일어났습니다.

다국어

  • 일본어처럼 코어에 국가 이름이 없는 언어도 언어팩이 국가 이름을 채울 수 있습니다. 코어 언어팩에 국가 코드별 이름 파일(countries.php)을 두면 회원 정보와 방문자 통계의 국가 이름이 그 언어로 나옵니다. 함께 배포되는 일본어 언어팩이 지원 국가 48개의 이름을 채웁니다.

설치·개발 도구

  • 설치 완료 화면이 예약 작업(cron) 등록 명령을 안내합니다. 등록하지 않으면 무엇이 멈추는지도 함께 적습니다.
  • 개발용 E2E 정리 명령(playwright:cleanup)을 추가했습니다. 테스트 토큰 발급(playwright:issue-token)이 남긴 테스트 역할·계정과, 예전 발급이 지어낸 권한 행(이름이 식별자 그대로인 코어 소유 권한 중 테스트 역할 말고는 쓰는 곳이 없는 것)을 지웁니다. 사람이 읽는 이름을 가진 권한과 일반 역할이 쓰는 권한은 남깁니다.

확장 개발자

  • 확장 매니페스트에 state_contracts(다른 확장이 읽으라고 내놓는 전역 상태의 이름·모양·쓰기 허용 주체)와 integrations(있으면 연동되고 없어도 동작하는 확장 목록)를 선언할 수 있습니다. 같은 전역 상태 이름을 두 확장이 소유하려 하면 설치·활성화가 막히고 메시지에 소유자가 나오며, 브라우저에서는 G7Core.stateContracts.get()·list()·ownerOf() 로 읽습니다. 관리자 확장 정보 창은 「함께 쓰면 연동되는 확장」과 그 설치 상태를 보여 줍니다.
  • 확장 개발자용 훅 목록과 호환 규칙을 추가했습니다. 코어가 발화하는 훅 전체를 docs/extension/hook-catalog.md 에서 볼 수
    있고(기본 제공 확장의 훅은 각 확장의 확장 지점 문서), 공개 훅의 이름·인자 모양은 마이너 버전에서 바꾸지 않는다는 규칙을
    docs/extension/hooks.md 에 적었습니다 — 바꿔야 하면 새 훅을 더하고 옛 훅은 사용 중단으로 두었다가 메이저 버전에서만 뺍니다.
  • 확장이 화면의 목록(표의 열, 탭 등) 중 한 항목만 고칠 수 있습니다. 종전에는 목록 전체를 다시 적어 넣는 방법뿐이었는데, 그렇게 적어 둔 목록은 만든 시점에 고정되어 나중에 그누보드가 항목을 더해도 확장의 옛 목록이 그것을 덮어 화면에서 지웠습니다. 이제 바꿀 항목만 지목하면 나머지는 그대로 남습니다.
  • 여러 확장이 화면의 같은 자리에 나란히 무언가를 더할 수 있습니다. 종전에는 나중에 적용되는 확장이 앞의 것을 덮어써 하나만 남았고, 그래서 확장끼리 서로의 몫을 대신 그려 주는 우회가 필요했습니다(그 확장이 설치되지 않은 상점에서는 어긋났습니다). 이제 각 확장이 자기 것만 더하면 되고, 새 확장이 추가돼도 기존 확장을 고칠 필요가 없습니다.
  • 레이아웃 확장점을 목록 표의 칸 안(DataGrid·CardGrid 셀 템플릿, 확장 행·하위 행 템플릿)에도 둘 수 있습니다. 지금까지는 칸 안에 둔 확장점이 채워지지 않아, 확장이 한 칸에 표시 하나를 덧붙이려면 표의 컬럼 전체를 복사해 덮어야 했고 그 사본 때문에 원래 표의 개선이 화면에서 사라지곤 했습니다. 개발자 문서 「레이아웃 확장」의 「셀 템플릿 안의 확장점」에 쓰는 법이 있습니다.
  • 확장 개발자 문서(훅)에 회원 수정 화면의 확장 필드 저장 계약(검증 규칙 필터 → core.user.filter_update_data → core.user.after_update)과 누락돼 있던 core.user.update_profile_validation_rules 를 추가했습니다. 확장이 회원 수정 폼에 칸을 얹을 때 별도 저장 API 를 두지 않고 코어 회원 저장 요청 한 번으로 함께 저장하는 방법입니다.
  • 검색 봇용 화면을 만들 때 서버가 자기 자신에게 보내는 데이터 요청에 앱 키로 서명한 표식 헤더(X-G7-Seo-Render)를 붙입니다. 확장은 App\Seo\SeoRenderRequest::matches() 로 이 요청을 알아보고 조회수 같은 열람 집계에서 뺄 수 있습니다.
  • 확장은 공개 API 응답의 회원 이메일 노출 기준(ExposesMemberContact)을 그대로 쓸 수 있습니다.
  • 확장이 리다이렉트·콜백·메일 링크에 쓸 절대 주소를 사이트 주소 기준으로 만드는 기능(App\Support\SiteUrl)을 추가했습니다. 요청의 Host 헤더를 따르는 url()·redirect('/…') 대신 이것을 씁니다. 사용법은 개발 문서 「절대 URL 은 사이트 주소로 만든다」에 있습니다.

Changed

로그인·비밀번호

  • 로그인 응답에 비밀번호 변경 단계가 생겨, 로그인 화면이 「2단계 인증이 아니면 로그인 성공」 으로 판정하면 변경 단계 응답(토큰 없음)을 성공으로 오판합니다. 직접 만든 로그인 화면은 response.password_change_required 를 먼저 확인하세요(작성 규칙: 프론트엔드 인증 문서 「비밀번호 변경 요구 로그인」). 템플릿 엔진의 AuthManager.completeTwoFactor() 는 종전대로 사용자를 돌려주고, 비밀번호 변경 단계가 오면 로그인하지 않은 채 오류를 냅니다 — 그 단계까지 다루려면 completeTwoFactorSession() 을 씁니다.
  • 로그인 실패 횟수를 환경설정 > 보안의 「로그인 시도 횟수 초과시 차단 시간」 안에 이어진 실패만 세도록 바꿨습니다. 종전에는 실패 횟수가 시간이 지나도 줄지 않아, 며칠에 걸친 드문 오타가 쌓여 계정이 잠길 수 있었습니다. 차단 시간을 0(무기한)으로 둔 사이트는 종전처럼 기간 없이 셉니다.

활동 로그

  • 비밀번호 변경 활동 로그가 경로별로 남습니다 — 종전에는 본인 변경·관리자 지정까지 전부 「비밀번호 재설정」으로 적혔습니다. 메일 재설정은 그대로 「비밀번호 재설정」, 그 밖은 「비밀번호 변경(본인·관리자 지정·로그인 시)」이며 관리자가 정한 경우 행위자가 관리자로 남습니다.
  • 활동 로그 자동 파기(activity-log:prune, 매일 04:45)가 환경설정 > 보안 「활동 로그 보관 기간」을 따릅니다 — 종전에는 1년 고정이었습니다. --days 로 직접 기간을 줘도 법정 최소 365일 안의 기록은 지우지 않고, 권한·역할 변경 기록은 그 값과 관계없이 최소 3년 남깁니다. 확장 훅 core.activity_log.before_prune·after_prune 의 일수 인자는 실제로 적용한 일수입니다.

다국어

  • 다국어 입력에서 반드시 채워야 하는 언어가 보는 사람의 언어가 아니라 사이트 기본 언어(환경설정 「기본 언어」)로 바뀌었습니다. 영어로 관리 화면을 보는 관리자가 만든 내용을 한국어 관리자가 이어 고칠 때 「ko 언어의 값은 필수입니다」로 저장되지 않던 일이 없어지고, 누가 어떤 언어로 보든 같은 칸이 필수입니다. 다국어 필수 검증 규칙을 쓰는 확장 기능에도 같은 기준이 적용됩니다.

알림

  • 편집 창을 열고 아무것도 바꾸지 않은 채 저장하면 더 이상 「수정됨」으로 기록되지 않고, 한 칸만 고쳐 저장하면 그 칸만 「수정됨」으로 기록됩니다(본인인증 정책·알림 템플릿). 종전에는 본인인증 정책에서 유예 시간 한 칸만 고쳐도 모든 칸이 「수정됨」으로 고정됐습니다.
    종전에는 이렇게 남은 표시 때문에 새 버전의 문구 교정이 들어오지 않고 「기본」 표시가 사라졌습니다. 업그레이드하면 이미 남은 거짓 표시를 정리합니다.
  • 문자·알림톡 같은 알림 채널을 추가하는 확장이 게시판·쇼핑몰 같은 도메인 이름을 몰라도 되게 바뀌었습니다. 채널 확장은 코어 훅 core.notification.channels 하나에 답하고, 코어가 모든 도메인의 알림에 그 채널을 후보로 올린 뒤 도메인 훅({도메인}.notification.channels)이 자기 설정으로 좁힙니다. 지금까지는 채널 확장이 코어 인증·게시판·쇼핑몰을 이름으로 골라 구독해, 목록에 없는 새 모듈의 알림에는 문자 채널이 붙지 않았습니다. 확장이 활성 채널을 화면에 보여 줄 때도 같은 코어 진입점을 씁니다. 알림 설정에서 켜고 끈 결과와 발송 동작은 그대로입니다.
  • 알림 채널 확장이 알림 설정 화면에 보일 채널별 템플릿을 넣을 때도 코어 훅 하나(core.notification.filter_seed_definitions)에 답합니다. 코어와 모든 모듈·플러그인의 알림 정의를 설치·업데이트 때 저장하기 직전 이 훅을 한 번 거치며, 정의마다 소유자(코어·모듈·플러그인과 식별자)가 함께 실립니다. 지금까지는 채널 확장이 게시판·쇼핑몰의 알림 저장 훅을 이름으로 골라 구독해, 새 모듈의 알림에는 문자·알림톡 템플릿이 생기지 않았습니다. 도메인별 알림 저장 훅(seed.{확장}.notifications.translations)은 언어팩 번역 병합용으로 그대로 발행되며, 새 훅은 그 번역이 병합된 뒤에 발행됩니다. 채널 확장이 켜질 때 이미 설치된 모듈·플러그인의 알림 정의만 다시 저장하는 코어 기능(resyncActiveModuleNotificationDefinitions / resyncActivePluginNotificationDefinitions)도 추가했습니다 — 권한·메뉴는 건드리지 않고, 운영자가 고친 알림 내용은 그대로 둡니다.
  • 알림에 수신 전화번호를 싣는 표준 키가 생겼습니다. 비회원처럼 받는 사람 정보에 전화번호가 없는 알림은, 알림을 보내는 확장이 알림 데이터에 코어 표준 키로 번호를 싣고 문자 채널은 그 키만 읽습니다. 확장 개발자 문서(훅)의 「수신 전화번호 표준 키」에 쓰는 법이 있습니다.
  • 역할 기반 알림 수신자를 모을 때 권한 정보를 필요한 항목만 읽습니다.

본인인증

  • 본인인증 메일 문구를 「환경설정 > 알림 설정」에서 관리합니다. 회원가입·비밀번호 찾기·정보 변경·중요 작업 확인·관리자 2단계 인증
    메일의 제목과 본문이 알림 설정의 분류 「본인인증」 카드로 옮겨졌습니다. 다른 알림처럼 편집·켜고 끄기·기본값 복원을 하고, 운영자가
    등록한 본인인증 정책에는 [정책별 문구 추가]로 전용 문구를 붙이거나 지울 수 있습니다. 「환경설정 > 본인인증 > 메시지」에는 그 화면으로
    가는 안내만 남습니다. 업데이트하면 기존 문구가 그대로 옮겨지고, 직접 고친 문구도 유지됩니다.
  • 알림 설정의 메일 채널을 끄면 본인인증 메일도 보내지 않습니다. 종전에는 메일 채널을 꺼도 인증번호 메일만은 나갔습니다. 이제
    인증번호를 보낼 수 없으면 「발송하지 못했다」고 안내하며, 메일을 끄고 저장할 때 「본인인증·관리자 2단계 인증 메일도 멈추고, 인증 앱을
    등록하지 않은 관리자는 로그인할 수 없게 된다」는 확인 창이 뜹니다. 실수로 끈 채 로그인할 수 없게 되었다면 서버의
    storage/app/settings/notifications.json 에서 mail 채널의 is_active 를 true 로 고치고 php artisan cache:clear 를 실행하면 다시 보냅니다.
  • 본인인증 메일도 발송 이력(알림 발송 로그)에 남습니다. 이력을 보는 관리자가 남의 인증을 가로채지 못하도록 인증번호와 인증 링크는
    ****** 로 가려 저장합니다.
  • 관리자 2단계 인증 메일이 공통 문구 대신 「로그인 인증번호 안내」 전용 문구로 나갑니다.
  • 알림 정의 목록 API(GET /api/admin/notification-definitions)가 분류 필터 category(general·identity)를 받고, 각 항목에 category 를 싣습니다.
  • 본인인증 시작 API(POST /api/identity/challenges)가 policy_key(428 응답이 알려 준 정책 키)를 받아, 그 정책이 켜져 있고 목적이 맞을 때
    정책별 문구로 보냅니다. 메일 링크가 여는 /identity/verify 화면은 번들 사용자 템플릿에 있으므로, 다른 사용자 템플릿은 같은 주소의 화면을
    두어야 합니다(docs/backend/api/identity.md).
  • 본인인증 요청이 기한을 넘겨 만료로 정리될 때 core.identity.challenge_expired 를 요청마다 발화합니다(종전에는 선언만 있었습니다).
  • 본인인증 프로바이더 목록의 수정 가능 여부를 실제 저장 권한(환경설정 수정)으로 판정합니다.

확장 관리·업데이트

  • PHP 의존성 패키지를 최신 안정 버전으로 갱신했습니다 (Laravel 12.69.3, Reverb 1.12, Scout 11.9, Monolog 3.12, Carbon 3.14, Symfony 7.4.20 등 — 메이저 상승 없음). 의존성이 PHP 8.2 에서 동작하는 판으로만 고정되도록 잠금 기준 PHP 버전을 8.2 로 두었고(이 때문에 개발 도구 Pint 는 PHP 8.2 호환 판 1.30 으로 고정), Composer 를 실행할 수 없는 환경을 위한 코어와 이커머스 모듈의 vendor-bundle.zip 도 같은 구성으로 다시 만들었습니다. 7.0.x 에서 올릴 때 코어 업데이트가 vendor/ 를 새 구성으로 교체합니다.
  • 7.0.x 에서 올리는 사이트는 7.0.x → 7.1.0 업그레이드 안내를 먼저 읽으세요. 코어 업데이트 뒤 묻는
    번들 확장 일괄 업데이트는 반드시 승인해야 하며, 건너뛰었거나 일부가 실패했을 때의 조치(php artisan hooks:cache,
    php artisan language-pack:update … --force, 개별 업데이트 순서)와 APP_URL·신뢰 호스트 확인을 안내합니다.
  • 7.0.x 에서 코어를 올릴 때 업데이트 단계에서 코어 역할·권한·메뉴 선언을 한 번 더 동기화해, 7.1.0 에서 생긴 권한(일반 회원의 내 정보·활동 기록,
    관리자 「방문자 통계」·「회원 알림함」 등)이 기존 역할에 연결됩니다. 운영자가 고친 역할 이름·메뉴 설정은 그대로 둡니다.
  • 확장을 「수정 유지」로 업데이트하면 이제 고친 화면을 통째로 두지 않고, 고친 부분은 그대로 두고 손대지 않은 부분에는 새 버전의 변경을 넣습니다.
    같은 곳을 운영자와 새 버전이 모두 고쳤으면 운영자 것을 남깁니다. 업데이트 완료 알림에 「새 버전 변경 N곳 자동 반영, 겹친 M곳은 운영자 것 유지」가
    붙고, 활동 로그의 업데이트 행을 펼치면 화면마다 결과가 보이며, 명령어로 업데이트하면 결과 표가 나옵니다. 모듈·플러그인이 끼워 넣는 조각을
    고친 경우에도 같습니다. 업데이트 전 「수정한 레이아웃」 목록에도 고친 조각이 함께 나옵니다.
  • 확장 업데이트 명령어(module:update·plugin:update·template:update·번들 일괄 업데이트)의 터미널 안내 문구와 설치·업데이트·제거 진행 문구가
    한국어로 고정돼 있던 것을 번역 키로 옮겼습니다(extensions.commands.update.*·extensions.commands.bundled_update.*·extensions.progress.*). 영어 환경에서는 영어로 나옵니다.
  • 레이아웃 편집기와 관리 화면이 실제로 설치된 확장·템플릿 파일만 읽습니다. 종전에는 설치본에 파일(컴포넌트 정의·라우트·레이아웃·다국어·편집기 빌드·CSS, 모듈·플러그인 컴포넌트 정의, SEO 기본 설정)이 없으면 코어에 함께 들어 있는 배포 원본을 대신 읽어, 사이트에서 돌아가는 것과 다른 내용이 편집기에 보일 수 있었습니다. 이제 설치본에 필요한 파일이 없으면 「설치본에 파일이 없습니다. 해당 템플릿을 다시 업데이트하세요」 안내를 보여 주고, 없어도 되는 파일(다국어·CSS·SEO 기본 설정 등)은 없는 것으로 처리합니다. 편집기 자산 응답의 manifest_source 필드는 늘 설치본을 가리키게 되어 제거했습니다.
  • 언어팩 관리의 내장 번역(한국어·영어) 목록이 설치된 확장의 설치본에서 만들어집니다. 종전에는 코어에 함께 들어 있는 배포 원본을 훑어, 설치하지 않은 동봉 확장이 목록에 나오고 마켓·업로드로 설치한 확장은 빠졌으며, 버전·경로도 실제로 쓰이는 파일과 다를 수 있었습니다. 이제 설치 경로와 상관없이 설치된 확장만, 사이트가 실제로 읽는 번역 파일 기준으로 표시됩니다.
  • 설치된 확장의 라이선스 보기가 설치본만 읽습니다. 종전에는 설치본에 파일이 없으면 배포 원본의 라이선스를 대신 보여 주었습니다. 이제 설치본에 없으면 파일을 찾을 수 없다는 안내로 처리하고, 배포 원본·업로드 대기본은 아직 설치하지 않은 확장을 보여 줄 때만 읽습니다.
  • 모듈·플러그인 설정 폴더 정리 기능이 확장 저장소 전체가 아니라 설정 폴더만 지웁니다. 확장 저장소의 최상위 폴더는 이제 어떤 삭제 요청으로도 지워지지 않습니다.
  • 환경설정 정보 탭의 [업데이트 확인]을 환경설정 조회 권한으로도 쓸 수 있습니다(전에는 수정 권한이 필요해 읽기 전용 관리자가 누르면 거부됐습니다).

화면 정의·레이아웃

  • 화면 정의의 redirect 동작(같은 탭에서 통째로 이동)이 사이트 안의 경로로만 이동합니다. 외부 주소를 받으면 첫 화면으로 보내므로, 외부 인증 페이지로 같은 탭 이동이 필요한 본인인증 제공자는 당분간 새 창 방식이나 자체 이동 처리를 써야 합니다.
  • 화면 정의의 표현식에 전달되는 이벤트($event)·오류(error)·콜백 인자($args)가 원본 브라우저 객체가 아니라 값 사본입니다. $event.target.value·checked·files·selectedOptions·dataset, 폼 제출 시 이름 있는 입력칸($event.target.검색칸이름.value)은 종전대로 읽히지만, 화면 요소의 메서드 호출이나 요소를 거친 탐색은 더 이상 되지 않습니다. 확장의 동작 처리기는 종전대로 원본 이벤트를 받습니다.
  • 레이아웃 저장의 외부 주소 검사가 입력창 안내 문구(placeholder)·링크(href) prop 과 액션 요청 본문(params.body)의 http(s) 웹 주소를
    허용합니다. 이 자리라도 실행 스킴(javascript: 등)·프로토콜 상대 주소(//host)·ftp: 는 막고, 자원을 불러오는 prop(src 등)과 액션의
    이동·요청 대상은 종전대로 외부 주소를 막습니다. 확장 조각이 끼워 넣는 컴포넌트·prop 덧씌우기(injections[])도 이제 같은 규칙으로
    검사합니다(종전에는 조각 저장에서 그림 주소 등의 외부 주소가 그대로 저장됐습니다).
  • 레이아웃 편집기의 확인·입력 창(나가기·템플릿 전환·초기화, 커스텀 자산 삭제·이름변경, 버전 복원, 다국어 키·이미지 삭제 등)이 브라우저 기본 창 대신 편집기와 같은 모양의 창으로 열립니다. 단추 이름이 하는 일을 말하고(「변경 사항 버리기」·「편집 계속」 등), 되돌릴 수 없는 확인은 처음 초점이 [취소]에 있으며, Esc·Tab 과 화면 낭독기로 쓸 수 있습니다.
  • 계산값(computed)이 많은 화면에서 글자를 입력할 때 멈칫하던 문제를 줄였습니다. 같은 표현식을 매번 다시 해석하지 않고, 계산값은 같은 상태를 쓰는 화면 조각마다
    한 번만 계산해 나눠 씁니다. 계산값은 앞에 정의된 다른 계산값을 바로 참조할 수 있습니다. 표시되는 값은 그대로입니다(engine-v1.74.0). (#140 @lyg-kaban 님께서 제보해주셨습니다.)
  • 사이트 기본 시간대(환경설정 > 일반 > 시간대)를 화면 설정 값(_global.settings.general.timezone)으로 내보냅니다. 관리자 화면의 빠른 기간 버튼과 방문자 통계 기간이 「오늘」을 브라우저가 아니라 계정·사이트 시간대로 정하는 데 씁니다. 민감 정보가 아니며, 사이트 주소·관리자 이메일·언어는 종전대로 내보내지 않습니다.

사이트 주소·API

  • 사이트 주소가 아닌 주소(하위 도메인·다른 포트 등)로 들어온 화면 요청은 사이트 주소의 같은 경로로 이동합니다(301). API·결제/본인인증 콜백·사이트맵·설치 화면은 대상이 아닙니다. 리버스 프록시가 내부 이름을 Host 로 넘기는 구성처럼 이동이 반복되면 .env 에 CANONICAL_HOST_REDIRECT=false 를 넣어 끌 수 있습니다.
  • API 주소(/api/…)의 입력 검증 오류는 요청의 Accept 헤더와 관계없이 JSON(422)으로 응답합니다. 종전에는 Accept 헤더 없이 부르면 직전 화면 주소로 이동하는 응답을 돌려줄 수 있었습니다.
  • 파일 크기 표시(size_formatted)가 소수 둘째 자리까지 나오고, 1GB 이상은 GB 로 표시합니다. 예: 12.1 KB 가 12.06 KB 로, 1024 MB 가 1 GB 로 바뀝니다. 이 문자열을 해석하던 연동은 바이트 값 size 를 쓰세요.
  • 대시보드 시스템 알림 API 는 「시스템 알림」 권한, 시스템 리소스 API 는 「시스템 리소스」 권한을 요구합니다(전에는 둘 다 대시보드 조회 권한). 화면의 시스템 알림 블록과 같은 권한입니다.

확장 개발자 영향

  • 확장 개발자 영향 — 확장 생명주기 직전 훅(core.{modules,plugins}.before_install·before_activate·before_deactivate·
    before_update·before_uninstall, 템플릿은 before_version_update 포함)을 이제 Manager 가 한 번 발화해, Artisan 커맨드로
    작업할 때도 발화합니다(종전에는 어드민 화면에서만). 인자는 종전과 같습니다. 직전 훅 구독자가 예외를 던져 작업을 막으면
    이제 커맨드로 하는 설치·활성화·업데이트·제거도 같이 막힙니다.
    템플릿 활성화 데이터 필터(core.templates.filter_activate_data)도 활성화 직전 훅 뒤에 한 번 돌며, 커맨드로 활성화할 때도 돕니다.
  • 확장 개발자 영향 — TemplateManagerInterface::uninstallTemplate() 에 네 번째 선택 인자 bool $deleteData = false 가
    더해졌습니다. 이 인터페이스를 직접 구현한 클래스는 시그니처를 맞춰야 합니다(인터페이스를 부르기만 하는 코드는 그대로 동작합니다).
  • 확장 개발자 영향 — 날짜(Carbon) 값을 담은 훅 인자가 큐로 넘어가도 날짜로 되살아납니다. 종전에는 큐로 실행되는 구독자가
    그 자리에 null 을 받았습니다.
  • 플러그인 정보의 permissions 가 모듈과 같은 권한 분류 목록으로 바뀌었습니다(종전에는 권한 선언 전체를 담은 {name, description, categories} 객체). 관리자 플러그인 정보 창에서 권한을 등록하는 플러그인(GDPR 등)의 「권한」 구획이 비어 보이던 것이 이 때문이었습니다. 같은 모양이 플러그인 상세·설치·활성화 응답과 훅 core.plugins.after_install·after_activate·after_update 의 정보 인자($info)에도 실립니다 — $info['permissions']['categories'] 를 읽던 확장은 $info['permissions'] 를 분류 목록으로 읽도록 바꿔야 합니다.
  • 모듈·플러그인·템플릿 관리자 클래스를 직접 new 로 만드는 코드는 생성자 인자 2개를 더 넘겨야 합니다(컨테이너로 받으면 변경 없음).

개발·운영 도구

  • 개발·관리용 명령과 샘플 데이터가 특정 확장·템플릿 이름을 적어 두지 않습니다.
    • json:convert-unicode 는 변환 대상을 DB 의 전문 검색(FULLTEXT) 인덱스 컬럼에서 찾습니다. 종전에는 쇼핑몰·게시판·페이지
      테이블 8개를 적어 두어, 다른 확장의 검색 컬럼은 변환되지 않았습니다.
    • layout:add-permissions 를 제거했습니다. 권한은 이미 각 레이아웃 소스에 들어 있고, 명령이 들고 있던 옛 권한 표를
      그대로 적용하면 인증 앱 등록 화면처럼 일부러 권한을 두지 않은 화면이 일반 관리자에게 막혔습니다.
    • E2E 시드 명령 playwright:seed-layout 은 활성 템플릿에 시드 화면을 깔고, 인증 앱 자격증명 심기는 그 플러그인의
      playwright:seed-totp 로 옮겼습니다. playwright:seed-two-factor 의 테스트 계정 정리는 운영자 삭제와 같은 경로를
      타서 각 확장이 자기 데이터를 치웁니다.
    • 샘플 시더(--sample)가 관리자 템플릿 행을 지우고 가짜 행으로 바꿔 넣던 동작을 없앴습니다. 샘플 활동 로그는 실제로
      설치된 확장을 대상으로 만들고, 확장이 남긴 활동 로그는 지우지 않습니다.
  • 개발용 E2E 토큰 발급 명령(playwright:issue-token)이 DB 에 없는 권한 식별자를 받으면 권한 행을 지어내지 않고, 없는 식별자를 알리며 실패 코드로 끝납니다(계정·역할·토큰도 만들지 않습니다). 관리자 권한 트리에 식별자 그대로인 가짜 권한이 쌓이던 원인입니다. 게시판별 권한은 그 게시판을 만든 뒤에만 받을 수 있습니다.

Deprecated

  • LayoutExtensionService::getModifiedExtensionsBySource() 를 사용 중단 예정으로 표시했습니다. 코어 안에서 더 쓰이지 않으며 다음 메이저에서 제거할
    예정이니, 확장이 고친 조각 목록이 필요하면 hasModifiedLayouts() 결과의 kind: extension 항목을 쓰세요.
  • 확장 생명주기 구훅 core.{modules,plugins,templates}.installed·activated·updated(식별자 1개만 전달)를 사용 중단 예정으로
    표시했습니다. 지금은 종전대로 발화하지만 다음 메이저에서 제거할 예정이니, 새 구독은 정규 훅 after_install·after_activate·
    after_update(템플릿은 after_version_update)를 쓰세요.
  • 사용 중단 예정인 훅과 공개 배포본에서 한 번도 발화한 적이 없는 훅 이름(core.auth.register, 단수형 core.module.* 등)의
    대체 이름을 docs/extension/hooks.md 의 「사용 중단 훅」 표에 정리했습니다. 새 구독은 대체 이름을 쓰세요.
  • core.templates.after_list·core.menu.after_update_order 는 인자 모양이 호출 경로마다 달라, 모양이 하나로 정해진 새 훅
    core.templates.after_list_paginated·core.menu.after_update_order_flat 을 함께 발화합니다. 옛 훅은 종전대로 발화합니다.
  • 확장의 본인인증 메시지 선언 getIdentityMessages() — 본인인증 문구는 getNotificationDefinitions() 에 category => 'identity' 로 선언합니다.
    아직 구현한 확장은 설치·업데이트 때 알림 정의로 바꿔 등록합니다(docs/backend/identity-messages.md).
  • 훅 core.identity.message.before_send·after_send·send_failed·resolve_failed — 계속 발화합니다. 대체 훅은 docs/extension/hooks.md 「사용 중단 훅」.
    인자에서 template_id·rendered(렌더된 제목·본문)가 빠지고 definition_id 는 알림 정의 ID 가 됐습니다. 메일 채널이 꺼져 건너뛴 발송도
    send_failed 로 알립니다(delivery_status = skipped). 렌더된 내용이 필요하면 core.notification.before_channel_send 를 구독하세요.
  • 본인인증 메시지 관리 훅 23종(core.identity.message_definition.*·core.identity.message_template.*·core.identity.filter_default_message_definitions) —
    알림 설정에서 본인인증 문구를 추가·수정·삭제·켜고 끄기·복원할 때 새 알림 훅과 함께 계속 발화합니다. 인자는 알림 정의·템플릿입니다. 대체 훅은 같은 문서.

Removed

  • 본인인증 메시지 전용 관리 API /api/admin/identity/messages/* 11개와 권한 「본인인증 메시지 조회·수정」(core.admin.identity.messages.read·update)을
    없앴습니다. 알림 설정 권한(core.settings.read·update)으로 같은 일을 합니다. 업데이트하면 두 권한은 역할에서 빠집니다.
  • 본인인증 메시지 테이블(identity_message_definitions·identity_message_templates)과 설정 키 core.identity_messages — 업데이트 때 내용을 알림 정의로
    옮긴 뒤 지웁니다. 옮긴 건수가 맞지 않으면 지우지 않고 업데이트를 멈춥니다.
  • 쓰이지 않던 코어 메일 테이블 mail_templates·mail_send_logs 를 지웁니다(새로 설치하면 만들지 않습니다).
  • 번역 필터 seed.identity_messages.translations 는 더 발화하지 않습니다 — 본인인증 문구 번역은 seed.notifications.translations 로 옵니다.
  • 메일 외 채널로 본인인증 메시지를 보낼 때 발화하던 필터 core.identity.message.send_{채널} 은 더 발화하지 않습니다 — 채널 발송은
    core.notification.before_channel_send·after_channel_send 로 구독합니다.

Fixed

확장 설치·활성화·관리

  • Artisan 커맨드로 확장을 설치·활성화·업데이트·제거하면 어드민 화면에서 할 때 뒤따르던 처리가 빠지던 문제를 수정했습니다.
    큐 워커가 재시작되지 않아 새 코드가 반영되지 않았고, 활동 로그가 남지 않았고, 확장의 번역 문구가 언어팩에 반영되지 않았습니다.
    이제 어드민 화면·커맨드·코어 업그레이드의 번들 일괄 업데이트·ZIP/URL 로 올린 확장 설치 모두 같은 처리를 한 번씩 거치며,
    모듈·플러그인은 설치·활성화 때도 큐 워커를 재시작합니다. 커맨드로 한 작업은 활동 로그 행위자 칸에 「시스템(CLI)」로 보입니다.
    파일을 직접 올려 배포한다면 배포 뒤 php artisan hooks:cache 를 실행하세요. (#138 @lyg-kaban 님께서 제보해주셨습니다.)
  • 켜진 확장이 의존하는 모듈·플러그인을 제거할 수 있던 문제를 수정했습니다. 의존 확장을 켠 채 모듈을 강제로 끄고 제거하면, 의존 확장이
    필요한 모듈 없이 켜진 채 남았습니다. 이제 제거를 거부하고 어떤 확장 때문인지 알려 줍니다. 확장이 서로를 의존하는지 판정하는 조회가
    한 번도 의존을 찾지 못하던 결함도 함께 고쳐, 모듈·플러그인을 끌 때 「이 확장에 의존하는 확장이 있습니다」 경고가 이제 실제로 뜹니다.
    모듈 비활성화 경고 문구도 의존하는 것이 템플릿뿐인 것처럼 「활성 템플릿이 있습니다」라고 하던 것을 「활성화된 확장이 있습니다」로 바로잡았습니다.
    명령행(module:deactivate)도 의존하는 템플릿만이 아니라 모듈·플러그인까지 목록으로 보여 줍니다.
  • 확장 상세 창의 「변경 내역」이 CHANGELOG 항목 밑에 들여써 이어 쓴 둘째 줄부터를 버려 문장이 중간에 잘리던 문제를 고쳤습니다. 이어 쓴 줄은 앞 항목에 이어 붙고, 중첩 항목·빈 줄 뒤 문단·코드 블록·소제목·CRLF 파일도 같은 기준으로 읽습니다. 모듈·플러그인·템플릿·언어팩 상세와 코어 업데이트 안내가 모두 같은 파서를 씁니다.
  • 플러그인을 끄거나 삭제해도 그 플러그인의 화면(설정 화면 등)이 남아 있던 문제를 수정했습니다. 끄면 숨기고 다시 켜면 되살리며, 삭제하면 지웁니다. 같은 식별자의 모듈 화면이 대신 숨겨질 수 있던 문제도 함께 고쳤고, 7.1.0 으로 업데이트할 때 이미 삭제된 플러그인이 남긴 화면을 정리합니다.
  • 코어에 함께 들어 있는 모듈이나 플러그인을 ZIP 파일 또는 GitHub 주소로 설치하면, 설치는 끝났는데 서버 오류가 표시되던 문제를 수정했습니다.
  • 모듈이나 플러그인을 켤 때 레이아웃 파일 검사에서 실패하면 오류가 표시되면서도 목록에는 「활성」으로 바뀌고 화면은 하나도 등록되지 않던 문제를 수정했습니다. 이제 검사에 실패하면 상태가 바뀌지 않습니다.
  • 레이아웃 검증에 실패했을 때 안내 첫 줄에 번역되지 않은 원문 키나 :error 가 그대로 보이고, 플러그인의 실패가 「모듈」로 표기되던 문제를 수정했습니다.
  • 템플릿 목록에서 템플릿이 기대는 모듈의 이름이 비어 있으면 카드 목록 전체가 그려지지 않고 「컴포넌트 로드 실패」가 나던 문제를 수정했습니다.
    이름이 비면 식별자를 보여 줍니다.
  • 모듈·플러그인·템플릿 제거가 실패하면 안내 문구 앞에 「… 제거에 실패했습니다:」가 두 번 붙어 나오던 문제를 수정했습니다.
    템플릿은 실패 사유 앞에 :error 가 글자 그대로 끼어 나오던 것도 함께 고쳤습니다.
  • 언어팩 관리에서 쪽 이동이 되지 않던 문제를 수정했습니다. 「보호된 언어팩 제외」를 풀어 63건이 잡히는데도 쪽 단추가 1번 하나만 나와 2쪽 이후를 볼 수 없었습니다. 목록 API 가 쪽 정보를 다른 자리에 담아 화면이 마지막 쪽 수를 읽지 못한 탓으로, 아래 「총 N개 · 1-10 표시」 는 정상이라 눈으로는 모순돼 보였습니다.
  • 코어 요구 버전을 만족하지 못하는 확장(모듈·플러그인·템플릿)의 설치·활성 버튼이 눌리는 상태로 보였지만 거절되던 문제를 수정했습니다. 확장 목록 응답이 현재 코어 버전 충족 여부를 함께 알려 줍니다.
  • 설치·삭제·업데이트가 진행 중인 템플릿도 활성화·삭제 요청이 받아들여지던 문제를 수정했습니다. 모듈·플러그인과 같이 진행 중인 작업이 끝날 때까지 거절합니다.
  • 템플릿 관리 화면은 사용 중인 템플릿의 스위치와 삭제를 잠그지만, 같은 요청을 직접 보내면 받아들여 관리자용 또는 사용자용 템플릿이 하나도 활성화되지 않은 상태가 될 수 있던 문제를 수정했습니다. 유형별 마지막 활성 템플릿의 비활성화·삭제는 거절되며, 템플릿을 바꾸려면 같은 유형의 다른 템플릿을 활성화합니다.
  • 템플릿 설치·활성화·비활성화·삭제·레이아웃 갱신이 실패했을 때 안내 문구에 원인 대신 :error 가 그대로 보이던 문제를 수정했습니다. 코어 업데이트 확인에서 GitHub 가 릴리스 정보 없이 응답했을 때의 실패 사유와, 모듈·플러그인·템플릿 설치 실패의 대체 문구도 자리표시자 없이 실제 값을 보여 줍니다. 또 모듈·플러그인·템플릿의 활성화·비활성화·삭제·업데이트 확인·레이아웃 갱신이 거절될 때 안내 문구 앞말(「…에 실패했습니다:」)이 두 번 붙던 문제도 함께 고쳤습니다.
  • 관리자 로그인 사용자 응답(GET /api/admin/auth/user)이 본인의 최고관리자 여부(is_super)를 함께 줍니다. 모듈·플러그인·템플릿 목록의 「숨김 항목 포함」 체크는 최고관리자에게만 보이도록 되어 있었지만 이 값을 받지 못해 누구에게도 나타나지 않았습니다. 남의 계정이 담기는 회원 목록 응답에는 싣지 않습니다.
  • 모듈·플러그인·템플릿 목록 응답이 확장마다 코어 요구 버전을 싣지 않아, 매니페스트가 지금 코어를 만족하지 못해도 코어 호환(core_compatible)이 늘 참으로 내려가던 문제를 수정했습니다. 설치 버튼·켜기 스위치가 잠기지 않아 누른 뒤에야 코어 버전 불일치(422)로 거절됐습니다.
  • 모듈·플러그인·템플릿 목록의 「숨김 항목 포함」(include_hidden)을 최고관리자가 아닌 관리자에게도 적용하던 문제를 고쳤습니다. 체크 값이 주소에 실리면서, 최고관리자가 공유한 주소로 들어온 다른 관리자에게 숨김 확장이 보이고 그것을 끌 체크박스는 보이지 않았습니다. 이제 최고관리자가 아니면 서버가 이 값을 무시합니다.
  • 확장 의존성 목록이 이름이 빈 문자열인 의존 확장을 빈 이름 그대로 내려보내던 문제를 수정했습니다. 이름이 비면 식별자를 이름으로 줍니다.
  • 모듈 목록 응답의 활성 모듈 수(meta.active_modules)가 활성 모듈이 있어도 늘 0 이던 문제를 수정했습니다.
  • 모듈·플러그인·템플릿 목록 응답에 업데이트할 새 버전의 코어 요구 정보가 없어, 새 버전이 지금 코어보다 높은 코어를 요구해도 업데이트 창에 경고가 뜨지 않고 [업데이트]를 누른 뒤에야 실패하던 문제를 고쳤습니다. 이제 업데이트가 있는 확장은 목록 응답에 그 버전의 코어 요구 버전·호환 여부·현재 코어 버전(required_core_version·is_compatible·current_core_version)을 함께 싣습니다.
  • 모듈·플러그인을 끌 때 뜨는 「비활성화 경고」 창에서 의존하는 모듈·플러그인의 버전이 비어 「v」 만 보이던 문제를 고쳤습니다.
  • 모듈·플러그인·템플릿을 껐다가 다시 켜면 저장된 이름·설명의 한국어·영어 값이 지워져, 다른 확장의 설치 창 의존 목록 등에 이름 대신 식별자가 보이던 문제를 고쳤습니다. 확장에 내장된 언어팩이 함께 꺼져도 확장 자신의 이름·설명은 지우지 않습니다.
  • 모듈 목록에서 검색 결과가 0건이면 권한이 있어도 [수동 설치]·[업데이트 확인]이 잠기던 문제를 고쳤습니다.
  • 플러그인 카드 [설정]이 활성화 권한으로 잠기던 것을 설정 저장 권한으로 바로잡았고, 카드 [언어팩 관리]는 언어팩 조회 권한이 없으면 잠급니다.

확장 업데이트·고친 화면 보존

  • 7.0.x 에서 7.1.0 으로 업데이트하면 7.1.0 에서 지운 번들 확장 파일이 남아, 뒤이은 확장 업데이트가 옛 화면 조각·레이아웃을 다시 등록하던 문제를 수정했습니다(결제 플러그인의 옛 주문 목록 조각이 관리자 주문 목록 표를 덮어 「클레임」 열이 사라짐).
    업데이트가 7.0.x 배포본과 내용이 같은 남은 번들 파일만 지우고, 내용을 고친 파일은 남긴 채 업그레이드 로그에 알립니다. 결제 플러그인(KG이니시스·NHN KCP·나이스페이먼츠)도 업데이트 때 옛 조각 파일과 등록을 정리합니다.
  • 모듈·플러그인·템플릿을 켜거나, 사용자 템플릿을 바꾸거나, 다른 확장을 켤 때 레이아웃 편집기로 고친 화면과 조각이 원본으로 돌아가던 문제를 수정했습니다.
    원본으로 되돌리려면 편집기의 「레이아웃 갱신」을 쓰세요.
  • 「수정 유지」로 업데이트해도 모듈·플러그인이 끼워 넣는 조각을 고친 내용이 지워지던 문제, 새 버전에서 빠진 화면을 고쳐 두었는데 모듈·플러그인
    업데이트가 그 화면을 지우던 문제를 수정했습니다.
  • 꺼 둔 템플릿을 업데이트한 뒤 켜면 새 버전의 화면 변경이 들어오지 않던 문제를 수정했습니다.
  • 확장 업데이트 때 운영자가 고친 역할 이름·설명이 원래대로 돌아가고, 꺼 둔 확장 역할과 메뉴가 다시 켜지고, 다른 상위로 옮긴 메뉴가 원위치로
    돌아가던 문제를 수정했습니다. 메뉴를 한 번 끌어 순서를 바꾸면 모든 메뉴가 「수정됨」으로 기록돼 새 버전의 순서 변경이 들어오지 않던 문제도 고쳤습니다.
  • 확장 업데이트가 운영자가 고친 알림 템플릿·본인인증 메시지 템플릿의 「기본」 표시를 되살려 「원래대로」 버튼이 숨던 문제를 수정했습니다.
  • 모듈·플러그인·템플릿 업데이트가 새 버전을 기록한 뒤 레이아웃 갱신에서 실패하면 파일은 이전 버전으로 돌아가는데 관리자 화면에는 새 버전이
    설치된 것으로 표시되고 「업데이트 없음」으로 판정돼 다시 시도할 수 없던 문제를 수정했습니다. 이제 버전·업데이트 표시도 업데이트 전으로 돌아갑니다.
  • 템플릿을 새 버전으로 업데이트해도 그 템플릿의 번역 문구가 언어팩에 반영되지 않고, 템플릿 정보를 수정할 때 언어팩 버전이 늘
    1.0.0 으로 기록되던 문제를 수정했습니다.
  • 확장 업데이트 창의 확인 버튼을 빠르게 두 번 누르면 업데이트가 두 번 수행되던 문제를 수정했습니다. 같은 확장의 업데이트는 한 번에
    하나만 수행하고(관리자 화면·커맨드 공통), 겹친 요청은 「업데이트가 이미 진행 중입니다」 안내로 끝납니다.
  • 업데이트할 것이 없는 확장을 업데이트하면 「… 버전으로 업데이트되었습니다」라고 답하던 문제를 수정했습니다. 이제 「업데이트할 내용이
    없습니다」라고 답하고, 업데이트 창의 완료 안내도 서버가 보낸 문구를 그대로 보여 줍니다.
  • 코어 업데이트로 훅 구독이 바뀐 사이트에서, 업데이트 직후 옛 구독으로 만든 훅 캐시가 쓰여 회원가입·비밀번호 찾기·역할 변경 같은
    활동 로그가 빠질 수 있던 문제를 수정했습니다. 훅 캐시에 형식과 만든 코어 버전을 함께 기록하고, 이 표시가 없거나(7.0.x 가 만든 캐시)
    지금 코어 버전과 다르면 그 캐시를 쓰지 않고 리스너를 직접 찾아 등록합니다. 그래서 7.0.x 에서 올리면서 번들 확장 일괄 업데이트를
    건너뛰었거나 실패한 사이트도 옛 구독이 남지 않습니다(php artisan hooks:cache 를 한 번 실행하면 캐시를 다시 씁니다).
    7.1.0 이후의 코어 업데이트는 마지막에 새 프로세스로 hooks:cache 를 한 번 더 실행하고(번들 확장 일괄 업데이트를 했으면 그 뒤에 다시,
    업그레이드 단계가 새 프로세스 재실행을 요청해 멈춘 경우에도), 실패하면 업데이트를 되돌리지 않고 직접 실행할 명령을 알려 줍니다.
  • 사용 중인 템플릿을 업데이트한 뒤, 템플릿 새 버전에 생긴 자리에 붙는 모듈·플러그인 화면 조각이 빠지던 문제를 수정했습니다. 번들 확장 일괄
    업데이트는 모듈 → 플러그인 → 템플릿 순서라, 플러그인이 조각을 등록할 때는 템플릿이 아직 옛 버전이어서 붙을 자리가 없었습니다(예: 결제
    플러그인의 주문 상세 가상계좌 입금 안내·영수증·에스크로 표시가 다른 확장을 켜거나 업데이트하기 전까지 보이지 않음). 이제 사용 중인
    템플릿을 업데이트하면 켜져 있는 모듈·플러그인의 조각을 다시 등록합니다. 운영자가 고친 조각은 그대로 둡니다.
  • 관리자가 고친 확장 조각이 다른 확장을 켜거나 업데이트할 때 원본으로 되돌아가던 문제와, 7.0.11 에서 고친 조각이 업데이트
    (수정본 유지 선택) 뒤 사라지던 문제를 수정했습니다. 업데이트의 「수정본 유지」 선택은 이제 그 확장 자신의 조각에도 적용됩니다.
  • 모듈·플러그인을 업데이트한 직후, 새 버전에서 추가된 기능 연결(훅)이 반영되지 않아 그 기능이 동작하지 않던 문제를 고쳤습니다(예: 인증 앱 플러그인 업데이트 뒤 관리자 회원 상세의 인증 앱 카드가 「권한 없음」으로 보임). 관리자 화면의 [업데이트]와 명령행 업데이트 모두 해당합니다.
  • 확장의 공개 릴리스가 코어와 함께 배포된 판보다 옛 버전이면, 관리자 화면과 module:update·plugin:update·template:update 가 「사용 가능한
    업데이트가 없습니다」로 끝나던 문제를 수정했습니다. 이제 공개 릴리스와 함께 배포된 판 중 높은 버전을 업데이트 대상으로 봅니다. 명령의
    --source=bundled(함께 배포된 판만)·--source=github(공개 릴리스만) 지정도 업데이트 확인 단계부터 지킵니다.
  • 모듈·플러그인 업데이트가 실패해 이전 버전으로 되돌린 뒤, 새 버전에만 있는 기능 연결이 확장 캐시에 남아 사이트 전체가 오류(500)를 내던
    문제를 수정했습니다(예: 이커머스를 올리지 않은 채 결제 플러그인을 업데이트해 중단된 경우). 이제 되돌린 뒤 확장 캐시를 이전 버전 기준으로
    다시 만듭니다. 업데이트 명령이 실패 원인과 무관하게 「백업에서 이전 버전이 복원되었습니다」라고 안내하던 것도, 실제 결과(되돌림·되돌리지
    못함·새 버전 유지·변경 없음)를 알리도록 고쳤습니다.

언어팩

  • 언어팩 관리에서 모듈·플러그인·템플릿·코어에 내장된(보호) 언어팩이 「sirsoft-template-sirsoft-admin_basic-en」 같은 내부 식별자로만 보이던 문제를 수정했습니다. 「게시판 내장 언어팩 (English)」처럼 대상과 언어로 이름을 붙입니다.
  • 확장 설치 창의 「함께 설치할 언어팩」에서, 이미 설치되어 켜져 있는 의존 확장의 언어팩이 늘 꺼진 채 잠겨 있어 함께 설치할 수 없던 문제를 고쳤습니다.
  • 모듈·플러그인·템플릿 설치 창에서 함께 고른 그 확장 자신의 언어팩(예: 일본어)이 「대상이 비활성 상태」로 늘 설치되지 않던 문제를 고쳤습니다. 설치 직후 확장은 꺼져 있으므로, 이제 그 언어팩은 꺼진 채 설치되고 확장을 켤 때 함께 켜집니다. 언어팩 관리 화면에서도 설치돼 있으나 꺼진 확장의 언어팩을 설치할 수 있습니다(꺼진 채 설치되며, 켜는 것은 그 확장을 켠 뒤 합니다). 설치되지 않은 확장의 언어팩은 종전처럼 설치할 수 없고, 사용자가 직접 끈 언어팩은 확장을 켜도 그대로 둡니다.
  • 모듈·플러그인 언어팩(예: GDPR 일본어 팩)을 비활성화해도 그 팩이 넣은 메뉴·역할·권한 이름과 알림 이름·제목·본문의 그 언어 문구가 남던 문제를 고쳤습니다. 이제 비활성화하면 확장 이름·설명과 함께 걷히고, 다시 활성화하면 다시 채워집니다. 운영자가 직접 고친 문구는 그대로 둡니다.
  • 언어팩 수동 설치에서 5~10MB 압축 파일은 설치는 되는데 미리보기만 거절되고, 일반 파일 형식으로 올라간 zip 은 반대로 미리보기만 통과하던 문제를 수정했습니다. 이제 미리보기와 설치가 같은 기준(10MB, zip)으로 검사합니다.
  • 언어팩을 업데이트하면 꺼 둔 언어팩이 「설치됨」으로 바뀌어, 대상 확장을 다시 켤 때 함께 켤 언어팩 목록에서 빠지던 문제를 수정했습니다.
    확장이 켜지기를 기다리던 언어팩(꺼진 확장에 설치한 언어팩)도 업데이트 뒤 그 표시를 잃어 확장을 켜도 함께 켜지지 않았습니다. 이제
    업데이트 전 상태를 그대로 둡니다. 번들 확장 일괄 업데이트로 일본어 언어팩을 한꺼번에 올릴 때도 같습니다.
  • 플러그인을 업데이트하거나 다시 켜면 그 플러그인의 관리자 메뉴 이름이 언어팩 번역(예: 일본어) 없이 기본 문구로 돌아가던 문제를 수정했습니다.
    모듈 메뉴와 같이 켜져 있는 언어팩의 메뉴 이름을 함께 반영합니다.
  • 번들 확장 일괄 업데이트로 모듈과 언어팩을 함께 올리면, 모듈이 새로 넣은 데이터(예: 쇼핑몰의 새 클레임 사유)의 언어팩 번역(일본어 이름 등)이
    비어 있던 문제를 수정했습니다. 언어팩을 켜는 과정의 데이터 번역 재적용이 갓 업데이트된 모듈의 새 기능을 불러오지 못해 실패하고 있었습니다.
    이제 일괄 업데이트는 확장을 올린 뒤 언어팩 단계를 새로 시작한 작업에서 진행합니다. 이미 올린 사이트는 php artisan language-pack:update <언어팩> --force 로 다시 적용하면 채워집니다.
  • GitHub 저장소 주소가 있는 언어팩의 설치·업데이트 확인이 늘 실패하던 문제를 수정했습니다. 이제 업데이트 확인은 공개 릴리스와 코어에 함께
    배포된 판 중 높은 버전을 대상으로 보고(모듈·플러그인·템플릿과 같은 규칙), 업데이트도 그 출처에서 받습니다.

레이아웃·확장 조각

  • 저장할 때 검증이 화면 정의의 항목 순서를 임의로 바꾸던 문제를 수정했습니다. 순서가 뜻을 갖는 목록(주소 패턴별 헤더 등)에서는 우선순위가 달라질 수 있었고, 판본 이력의 변경 요약도 실제 편집과 무관하게 커졌습니다.
  • 같은 확장이 같은 화면에 조각을 둘 보내면 뒤 조각이 앞 조각을 덮어쓰던 문제를 수정했습니다. 이커머스의 회원 결제 통화 칸이 배송 국가 칸에 덮여 관리자 회원 수정 화면과 회원가입 화면에 보이지 않았습니다. 조각마다 파일 이름으로 된 식별자(fragment_key)를 두어 구분합니다.
  • 확장 조각이 붙을 자리가 없는 템플릿에도 무조건 등록되어 사용자 템플릿에 관리자 화면용 조각이 쌓이던 문제를 수정했습니다. 모듈 화면을 겨냥한 조각의 대상 판정도 모듈 접두 이름을 인식하도록 고쳤습니다. 확장을 켜거나 업데이트하면 다른 확장의 조각도 다시 살펴, 나중에 설치된 화면을 겨냥한 조각이 빠지지 않습니다.
  • 확장 기능이 화면에 끼워 넣는 조각에 적어 둔 개발자용 설명이 방문자에게 전달되는 화면 구성 데이터에 그대로 실려 나가던 문제를 수정했습니다. 화면 본문의 설명은 이미 제거되고 있었으나 끼워 넣는 조각은 그 처리 뒤에 합쳐져 빠져나가고 있었으며, 이제 두 경로 모두 제거됩니다. 화면 조각(공통 창 등)에 붙은 개발자용 설명문도 함께 제거됩니다.
  • 화면의 일부 조각을 불러오지 못했을 때 아무 알림 없이 그 부분만 조용히 사라지던 문제를 수정했습니다. 조각 파일이 없거나 내용이 깨졌거나 서로를 순환 참조하는 경우가 여기에 해당하며, 설치는 성공한 것처럼 끝나 화면 일부가 흔적 없이 빈 채로 남았습니다. 이제 이런 경우 그 자리는 비운 채 등록하되, 어떤 조각을 왜 불러오지 못했는지 관리자 화면의 경고 알림과 서버 로그·명령 출력으로 알려 줍니다.
  • CSS 를 선언하지 않은 템플릿을 쓰면 모든 화면이 없는 템플릿 CSS 파일(css/components.css)을 요청해 실패 요청과 콘솔 오류가 남던 문제를 고쳤습니다. 이제 사용자·관리자 화면 모두 템플릿 정보 파일(template.json)의 assets.css 에 선언했고 실제로 있는 CSS 만 링크합니다.
  • 레이아웃 응답에서 원본이 빈 객체({})인 화면 상태 초기값·액션 인자·데이터 대체값이 빈 배열([])로 바뀌어 전달되던 문제를 수정했습니다. 이제 원본 그대로 {} 로 전달되어, 키-값으로 쓰는 화면 상태(예: 게시판 환경설정의 알림 펼침 상태)가 배열로 시작하지 않습니다.

레이아웃 편집기

  • 관리자 템플릿 레이아웃 편집기의 「미리보기」가 사용자 화면 주소(/preview/{token})로 열려, 관리자 템플릿 레이아웃이 활성 사용자 템플릿의 컴포넌트·다국어로 그려지던 문제를 고쳤습니다. 미리보기 생성 응답의 preview_url 이 템플릿 종류에 맞춰 관리자 템플릿은 /admin/preview/{token}, 사용자 템플릿은 /preview/{token} 을 돌려줍니다(레이아웃 파일·레이아웃 확장 조각 미리보기 모두).
  • 화면 편집기 [동작] 탭에서 검색 드롭다운·태그 선택·아이콘 선택·필터 묶음·수량 선택·서식 편집기의 「값이 바뀌면」 칸에 붙인 동작이 저장은 되지만 화면에서 실행되지 않던 문제를 수정했습니다.
  • 레이아웃 편집기의 커스텀 자산 창에서 파일 본문을 모두 지우고 저장하면 「content 필드는 문자열이어야 합니다.」로 저장되지 않던 문제를 수정했습니다. CSS 를 통째로 비우는 저장이 가능해졌고, 본문 없이 보낸 요청은 종전대로 거절합니다.
  • 레이아웃 편집기의 커스텀 자산 창에서 글꼴·이미지처럼 본문을 편집할 수 없는 파일을 고르면 「이 형식(:extension)은…」처럼 확장자 자리에 자리 이름이 그대로 보이던 문제를 고쳤습니다. 이제 woff2 처럼 실제 확장자가 표시됩니다.
  • 레이아웃 편집기 「커스텀 자산」 창을 Esc 나 바깥 클릭으로 닫으면 저장하지 않은 편집을 묻지 않고 닫혀 쓰던 내용이 사라지던 문제를 고쳤습니다(engine-v1.76.0).
  • 레이아웃 편집기에서 미리보기 기기를 모바일·태블릿으로 바꿔도 카드·표의 칸과 펼친 행, 화면 폭에 따라 바뀌는 스타일, 셀 안 일부 문구가 실제 브라우저 창 기준으로 그려지던 문제를 고쳤습니다. 이제 미리보기 안의 모든 요소가 고른 기기 폭과 콘텐츠 언어를 따르고, 편집 중에는 셀·슬롯 안 버튼의 동작이 실행되지 않습니다. 테마의 CSS 가 어떤 방식으로 작성됐든(일반 CSS·Bootstrap·Tailwind 등) 화면 폭 조건과 화면 폭 단위가 미리보기 폭으로 판정되며, 편집기를 벗어나면 원래대로 돌아갑니다. 관리자 헤더 통화 선택처럼 다른 위치로 옮겨 그려지는 요소도 편집 캔버스에서 고를 수 있습니다. (#141 @glitter-gim 님께서 제보해주셨습니다.)
  • 레이아웃 편집기 미리보기에서 본문 편집기(CKEditor)가 「편집기를 불러오지 못했습니다」 안내와 함께 임시 입력창으로 바뀌던 문제를 수정했습니다. 미리보기와 편집기 플러그인이 같은 편집기 파일을 각자 불러와 두 번 실행되던 것을 한 번만 실행되게 했고, 환경설정 「에셋 파일 서빙 방식」이 확장자 없는 방식인 사이트에서 미리보기만 그 파일을 찾지 못하던 문제도 함께 고쳤습니다.
  • 레이아웃 편집기에서 창을 편집할 때, 창을 연 화면의 값을 읽는 창(장바구니 옵션 변경, 구매 불가 안내, 주문 일괄변경 확인 등)이 상품과 목록 없이 빈 채로 그려지던 문제를 수정했습니다.
  • 레이아웃 편집기에서 여러 확장이 같은 이름으로 쓰는 창(삭제 확인·직권 실행·본인인증 정책 편집 등)을 편집하면, 「화면 상태」 고르개에 다른 확장의 창 상태가 같은 이름으로 겹쳐 보이고 다른 화면의 표본이 적용되던 문제를 수정했습니다. 이제 창을 연 화면을 만든 확장(또는 템플릿)의 상태를 씁니다.
  • 레이아웃 편집기에서 콘텐츠 언어를 바꿔도 조건에 따라 고르는 문구(창 아래 [삭제] 버튼, 「현재 활성」 같은 상태 배지)만 한국어로 남던 문제를 수정했습니다.
  • 확장자가 붙은 주소를 웹서버가 먼저 가로채는 서버(「에셋 파일 서빙 방식」이 확장자 없는 방식)에서 정적 게시를 쓰지 않으면, 관리자 화면의 코드 편집기가 늘 일반 입력창으로 표시되던 문제를 수정했습니다.
  • 관리자 화면 5개(모듈·플러그인·템플릿·언어팩 목록, 환경설정)를 레이아웃 편집기로 열어 아무것도 바꾸지 않고 저장해도 「HTTPS 프로토콜 URL은
    허용되지 않습니다」(422)로 막히던 문제를 수정했습니다. 입력창 안내 문구·링크·요청 본문 예시의 외부 주소 때문이었습니다.
  • 레이아웃 편집기에서 반복 항목 편집에 들어가면 고른 화면 상태가 기본으로 풀리던 문제를
    수정했습니다. 상태 고르개가 사라지고 화면이 기본 상태로 돌아가, 고른 상태에서만 보이는 반복 항목은
    편집 대상 자체가 캔버스에서 사라졌습니다. 이제 반복 항목 편집 중에도 그 화면에서 고른 상태를 이어 가고,
    다른 화면을 열면 그 화면의 기본 상태로 열립니다.
  • 레이아웃 편집기의 미리보기 화면에서도 같은 설명이 그대로 전달되던 문제를 함께 수정했습니다. 미리보기는 주소만 알면 열람할 수 있어 편집 중인 내용의 설명까지 노출될 수 있었습니다.
  • 레이아웃 편집기에서 화면을 저장할 때 화면에 적어 둔 설명이 아무 안내 없이 사라지던 문제를 수정했습니다. 저장 검사가 그 항목을 받지 않아 조용히 버려지고 있었습니다.
  • 레이아웃 편집기에서 다른 화면을 물려받아 제목이나 초기값만 바꾸는 화면을 저장하면 거부되던 문제를 수정했습니다. 물려받은 화면은 구성 요소를 다시 적지 않아도 되는데도 저장 검사가 이를 요구하고 있었습니다.
  • 레이아웃 편집기에서 본인인증·알림·마이페이지·검색 등 일부 화면을 저장할 때 "허용되지 않은 API 주소" 로 거부되던 문제를 수정했습니다. 검사 기준을 실제로 제공 중인 주소 목록에서 직접 확인하도록 바꿔, 앞으로 새 주소가 추가되어도 같은 문제가 생기지 않습니다.
  • 확장 기능이 기존 화면에 끼워 넣는 조각을 저장할 때, 끼워 넣을 위치 목록 없이 팝업창만 제공하는 조각이 저장되지 않던 문제를 수정했습니다. 팝업창·데이터·스크립트·초기 동작 중 하나만 갖춘 조각도 정상적으로 동작하며 실제로 그렇게 쓰이고 있었는데, 화면 편집기로 저장할 때만 거부되던 상태였습니다. 저장이 막히던 안내 문구도 실제 기준에 맞게 다듬었습니다.
  • 레이아웃을 다른 곳에서 먼저 저장해 저장이 충돌할 때 뜨는 안내 문구에 내부 자원 표기(테이블 이름과 번호)가 함께 보이던 문제를 고쳤습니다.

템플릿 엔진·화면 동작

  • G7Core.state.subscribe() 가 문서대로 해제 함수를 돌려줍니다. 지금까지는 아무것도 돌려주지 않아 화면을 떠나도 구독이 남았고, 같은 화면을 오갈 때마다 리스너가 쌓였습니다. AuthManager.on() 도 해제 함수를 돌려주고 off()·getState() 가 생겼으며, 로그인 상태에서 비로그인으로 바뀔 때 authStateChange 를 한 번 냅니다.
  • 관리자 화면의 창이 Esc 키로 닫히지 않던 문제를 고쳤습니다(engine-v1.77.1) — 컴포넌트가 이벤트 없이 부른 액션 핸들러가 오류로 멈추던 것을, 액션 종류에 맞는 대체 이벤트로 실행하도록 바꿨습니다.
  • 환경설정의 알림 설정 탭처럼 폼과 목록이 함께 있는 화면에서 채널 사용 여부를 바꾼 뒤(저장 전) 알림 하나를 켜거나 끄면, 바꾼 채널은 화면에 그대로인데 저장 버튼이 꺼져 저장할 수 없던 문제를 고쳤습니다(engine-v1.77.2) — 입력 중인 폼과 무관한 목록을 다시 불러올 때는 「저장하지 않은 변경」 표시를 지우지 않습니다.
  • 관리자 모듈·플러그인 목록에서 의존성 경고 창으로 강제 활성화한 뒤 「언어팩 다시 켜기」 창을 닫으면, 이미 끝난 강제 활성 창이 빈 목록으로 다시 나타나던 문제를 고쳤습니다. 한 동작 안에서 창을 닫고 바로 다른 창을 여는 모든 화면에 해당합니다.
  • 버튼 동작이 여러 단계로 이어질 때(상태 변경 → 다음 단계) 조건 분기형($switch) 계산값과 고정 문자열 계산값(마이페이지의 현재 탭 등)이 상태 변경 직후 사라지던 문제를 수정했습니다(engine-v1.74.0).
  • 글자를 친 직후(0.3초 안)에 저장을 누르면 마지막으로 친 내용이 빠진 채 저장되던 문제를 수정했습니다. 저장은 성공으로 표시되고 응답도 정상이라 화면만 보고는 알 수 없었습니다. 입력 반영이 잠시 미뤄지는 구조를 쓰는 모든 화면에 해당하며(코드 편집기·옵션 입력 등), 이제 저장 동작이 미뤄진 입력을 반영한 뒤의 값을 읽습니다.
  • 본인인증에서 외부 제공자로 나가야 할 때 아무 일도 일어나지 않던 문제를 수정했습니다. 화면 정의가 쓰던 이동 방식이 엔진에 구현돼 있지 않았고, 오류도 기록도 남지 않았습니다.
  • 관리자에서 메뉴로 한 목록 화면에서 다른 목록 화면으로 이동하면(예: 주문 목록에서 쿠폰 목록으로) 도착한 목록에 체크박스와 작업 열만 남고 데이터 열이 사라지던 문제를 수정했습니다. 이전 화면의 표시 설정이 새 화면에 섞여 들어가던 것으로, 목록의 열 표시를 한 번도 바꾸지 않은 브라우저(시크릿 창 등)에서 나타났고 새로고침하면 정상으로 돌아왔습니다. 이제 새로고침 없이도 새 화면의 열이 그대로 그려집니다.
  • 관리자 화면의 저장 버튼을 빠르게 두 번 누르면 같은 저장 요청이 두 번 나가던 문제를 수정했습니다. 폼 저장이 끝나기 전에 다시 누른 것은 무시합니다.
  • 언어를 바꾸면 작성 중이던 입력(제목, 고른 첨부 파일 등)이 사라지던 문제를 고쳤습니다. 이제 언어를 바꿔도 저장하지 않은 입력은 그대로 남습니다. 탭을 열 때 받아 둔 목록이 언어를 바꾼 뒤에도 이전 언어 문구로 남던 것도 새 언어로 다시 받습니다.
  • 같은 화면 틀을 쓰는 두 화면(게시판 「수정」과 「등록」, 게시글 「수정」과 「작성」 등)을 오가면 앞 화면에서 입력한 값이 뒤 화면 입력칸에 남던 문제를 고쳤습니다. 게시글 「작성」에서는 직전에 수정하던 글의 번호가 저장 요청에 함께 실리기도 했습니다.
  • 환경설정에서 다른 탭을 눌렀다가 곧바로 원래 탭으로 돌아와 입력하면, 늦게 도착한 설정 응답이 방금 입력한 값을 말없이 덮어쓰던 문제를 고쳤습니다.
    • 설정과 목록이 한 탭에 있는 화면(본인인증 정책 등)에서 목록의 검색, 필터, 쪽 넘김이 고친 설정 칸을 저장된 값으로 되돌리던 문제도 함께 고쳤습니다.
  • 권한이 없는 화면으로 이동하면 오류 화면 뒤에서 브라우저 콘솔 오류가 수백 건 쌓이고, 그 오류 화면에서 브라우저 뒤로 가기를 해도 이전 화면이 다시 그려지지 않던 문제를 고쳤습니다.
  • 로그인하지 않고 여는 화면이 주소에 없는 조건 값(쪽 번호 등)을 page=undefined 처럼 글자 그대로 보내 서버가 요청을 거절(422)하던 문제를 고쳤습니다. 이제 값이 없는 조건은 보내지 않습니다.
  • 화면 전환 중 보이는 로딩 뼈대(스켈레톤)를 화면 읽기 프로그램이 화면 언어와 상관없이 「Loading...」으로 읽고, 같은 로딩 안내를 두 번 읽던 문제를 고쳤습니다. 이제 화면 언어의 로딩 문구로 한 번만 읽습니다.
  • G7Core.modal.isOpen()·getStack() 이 창이 열려 있어도 늘 false·빈 목록을 돌려주던 문제를 고쳤습니다(engine-v1.75.2).

다국어·문구

  • 영어·일본어 관리자 화면의 알림 템플릿 편집 창에서 「사용 가능한 변수」 설명이 「— 수신자 이름」 처럼 한국어로만 보이던 문제를 수정했습니다. 코어 알림의 변수 설명이 화면 언어로 나옵니다. 언어 파일에 설명이 없는 변수(외부 확장이 새로 선언한 변수 등)는 선언한 문구를 그대로 보입니다.
  • 영어 화면에서 개수가 1일 때도 「1 posts」「1 comments」「Total 1 items」처럼 복수형으로 표시되던 문제를 수정했습니다. 번역 문구가 개수에 따라 단수·복수 꼴을 고르며(검색엔진 봇 화면도 같음), 확장 개발자는 번역 파일에 키_one 같은 단수 문구를 더하는 것만으로 같은 처리를 쓸 수 있습니다.
  • 영어 화면에서 「Activate 1 user(s).」「1 item(s) selected」「Showing 1-1 of 1 users」「within 1 days」처럼 「(s)」를 붙여 쓰거나 수와 맞지 않던 확인 창·선택 개수·안내 문구(화면 편집기·관리자·사용자 화면)를 개수에 맞는 단수·복수 꼴로 표시하도록 수정했습니다.
  • 영어 화면에서 서버가 보내는 안내 문구가 개수가 1이어도 「Too many requests. Please try again in 1 second(s).」「1 user(s) status updated successfully.」처럼 「(s)」를 붙여 나오던 문제를 수정했습니다(로그인 시도 제한·계정 잠금 안내, 회원 일괄 상태 변경, 플러그인 레이아웃 검증 실패, 템플릿 설치·삭제·캐시 정리와 검색 색인 재구축 콘솔 출력). 1이면 단수, 0·2 이상이면 복수로 나옵니다. 확장도 서버 문구의 영어 값을 단수|복수 로 적고 치환값에 count 를 넘기면 같은 처리를 씁니다.
  • 영어 화면에서 서버가 보내는 문구 중 「(s)」 없이 늘 복수로 적혀 있던 것이 개수가 1이어도 「1 results found.」「Users status bulk updated (1 items)」「1 layouts deleted」「SEO cache statistics for the last 1 days」「The tags field must have at least 1 items.」처럼 나오던 문제를 수정했습니다(통합 검색 결과 안내, 활동 로그, 모듈·플러그인 설치·활성화·비활성화·삭제·목록·캐시 정리, SEO 캐시와 검색 색인 점검 콘솔 출력, 개수·글자 수·용량·자릿수 제한 입력 검증 오류). 1이면 단수로 나옵니다.
  • 입력 오류가 두 개 이상인 폼을 저장하면 한국어 화면의 오류 안내가 「… (and 1 more error)」처럼 영어 꼬리로 끝나던 문제를 수정했습니다. 이제 「… (외 1개 오류)」로 나옵니다.
  • 한국어 검증 안내에서 값·이름 뒤의 조사가 맞지 않거나 괄호 조사로 나오던 문제(「1000를 초과하면 안 됩니다」, 「선택한 tab이(가) 올바르지 않습니다」)를 고쳤습니다. 이제 「1000 이하여야 합니다」, 「선택한 tab 값이 올바르지 않습니다」처럼 값에 조사가 붙지 않는 문장으로 안내합니다.
  • 모듈·플러그인·템플릿 관리 안내와 오류 문구가 「모듈 "sirsoft-board"을(를) 찾을 수 없습니다.」, 「플러그인 "sirsoft-gdpr"이(가) 설치되지 않았습니다.」처럼 영문 이름 뒤에 괄호 조사를 붙여 나오던 문제를 수정했습니다. 이제 「"sirsoft-board" 모듈을 찾을 수 없습니다.」처럼 조사가 이름에 붙지 않는 문장으로 나옵니다. 코어 버전 호환성 안내도 같은 방식으로 바꿨습니다.
  • 레이아웃 편집기와 화면 스크립트 안내 문구가 「편집기을(를) 불러오지 못했습니다.」, 「sirsoft-board 이(가) 주입함」, 「page_title은(는) 이미 추가한 변수입니다.」처럼 괄호 조사를 붙여 나오던 문제를 수정했습니다. 이제 「편집기 불러오기에 실패했습니다.」, 「주입: sirsoft-board」, 「이미 추가한 변수입니다: page_title」처럼 나옵니다.
  • 여러 언어로 적는 입력칸(메뉴·역할·권한 이름, 알림 제목·본문, 게시판 이름 등)에서 필수 언어(사이트 기본 언어)의 값을 비웠을 때의 오류 문구가 어느 칸의 어느 언어인지 알려 주도록 바뀌었습니다.
    • 종전에는 「The en language value is required.」·「ko 언어의 값은 필수입니다.」처럼 언어 코드만 나왔고, 이제 「게시판 이름의 한국어(ko) 값은 필수입니다.」·「알림 본문의 한국어(ko) 값은 필수입니다.」처럼 나옵니다.
    • 화면 이름이 정해지지 않은 칸은 내부 필드 이름(name 등)을 내보이지 않고 「한국어(ko) 값은 필수입니다.」처럼 언어만 알립니다.
  • 권한이 없거나 없는 화면을 열 때 나오는 오류 화면의 제목·「새로고침」 단추가 언어와 무관하게 한국어였고, 본문에 개발자용 원문(「Failed to fetch layout: 403 Forbidden」)이 보이던 문제를 수정했습니다. 화면 언어로 「이 화면을 볼 권한이 없습니다.」 처럼 안내합니다. 레이아웃 편집기를 불러오지 못했을 때의 오류 화면 제목과 안내도 화면 언어로 나옵니다.
  • 언어를 바꾸거나 고른 언어로 사이트를 열어도 문서 언어(<html lang>)가 처음 받은 언어로 남아, 화면 읽기 프로그램·번역 제안이 다른 언어로 읽던 문제를 고쳤습니다.
  • 다른 기기에서 언어를 바꾼 회원이 로그인하면 화면 문구와 서버가 보내는 문구(필수 언어 안내, 확장 목록 이름 등)가 서로 다른 언어로 섞이던 문제를 고쳤습니다. 이제 로그인 상태에서는 화면을 열거나 새로 고칠 때 회원이 설정한 언어로 맞춥니다. 사이트가 지원하지 않는 언어면 그대로 둡니다.
  • 회원 언어가 지금 화면 언어와 다른 회원이 로그인하면 로그인 직후 브라우저 콘솔에 오류가 수십 건 나고 일부 화면 기능이 초기화되지 않던 문제를 고쳤습니다.

회원·역할·메뉴

  • 관리자 회원 목록에서 검색어로 「0」 한 글자만 넣으면 조건이 무시되어 전체 회원이 나오던 문제를 고쳤습니다.
  • 회원 상태 라벨에서 「가입대기」가 원문 키로 보이던 것을 고쳤습니다. 상태 값은 있었지만
    라벨 문구가 빠져 있어 화면에 user.status.pending_verification 이 그대로 나왔습니다.
  • 회원 검색 결과가 검색어와 맞는 목록인지 화면이 알 수 있게 됐습니다. 회원 검색 응답이 그
    목록을 만든 검색어를 함께 싣습니다(meta.keyword). 자동완성은 글자를 칠 때마다 요청을 내는데
    응답이 오는 순서는 보장되지 않아, 한 글자가 불러온 큰 목록이 가장 늦게 도착하면 화면이 그것을
    방금 친 검색어의 결과로 착각했습니다 — 이제 응답이 스스로 어느 검색어의 것인지 말하므로 화면이
    가려낼 수 있습니다. (이 값을 쓰는 화면 수정은 이커머스 모듈 CHANGELOG 에 있습니다.)
  • 역할 관리에서 코어·확장이 만든 역할의 「삭제」와, 슈퍼 관리자가 아닌 운영자에게 그 역할의 「수정」·사용 여부 스위치가 눌리는 상태로 보였지만 저장하면 거절되던 문제를 수정했습니다. 역할 목록·상세 응답의 조작 가능 여부가 서버의 역할 보호 판정과 같은 기준을 따릅니다.
  • 슈퍼 관리자가 아닌 운영자가 슈퍼 관리자 회원의 수정 화면을 열 수 있었지만 저장하면 거절되던 문제를 수정했습니다. 회원 상세와 회원 목록 응답의 수정·역할 부여 가능 여부가 모두 등급 보호 판정을 반영합니다(목록 행에서는 이 판정이 빠져 수정 버튼이 켜져 있었습니다).
  • 회원 생성 권한만 있고 역할 부여 권한이 없는 운영자가 회원을 등록하면 역할 칸이 잠긴 채 「역할을 하나 이상 선택해주세요」로 항상 실패하던 문제를 수정했습니다. 역할을 고르지 않으면 기본 역할(일반 사용자)로 등록됩니다.
  • 회원 일괄 상태 변경(활성·비활성·차단·탈퇴)에서 슈퍼 관리자나 관리 범위 밖 회원이 제외되어도 결과에 실패 건수·사유가 실리지 않아 전원 처리된 것처럼 보이던 문제를 수정했습니다.
  • 로그인 사용자 응답(GET /api/auth/user)과 관리자 회원 상세·목록 응답에서, 불러오지 않은 관계 값(modules_count·consents·terms_consent·privacy_consent 등 9개)이 키를 빼는 대신 빈 객체 {} 로 나가던 문제를 수정했습니다. 이제 해당 키가 응답에 없습니다.
  • 메뉴 관리에서 메뉴의 역할을 모두 빼고 저장하면 그 메뉴가 관리자를 포함한 모든 사람의 사이드바에서 사라지고, 상세 화면에는 오히려 「모든 역할」 로 표시되던 문제를 수정했습니다. 이제 메뉴를 저장할 때 관리자 역할은 항상 남고, 역할이 하나도 없는 메뉴는 「지정된 역할 없음」 으로 표시되고, 메뉴 수정 권한을 전체 범위로 가진 관리자의 메뉴 관리 목록에 「역할 없음」으로 나와 편집 저장으로 복구할 수 있습니다(범위가 제한된 운영자의 목록은 달라지지 않습니다). 이미 관리자 역할이 빠져 있던 메뉴에는 7.1.0 업그레이드가 관리자 역할을 다시 붙입니다.
  • 메뉴가 지정된 역할이라도 메뉴 관리 조회 권한(core.menus.read)이 없으면 그 역할만 가진 운영자의 관리자 사이드바가 통째로 비던 문제를 수정했습니다(개인정보 운영자·게시판 관리자처럼 메뉴가 지정된 확장 역할 포함). 사이드바 메뉴(GET /api/admin/menus/active)는 관리자 화면에 들어올 수 있으면 받으며, 응답은 내 역할에 지정된 메뉴로만 좁혀집니다. 메뉴 관리 화면의 목록·상세는 종전대로 메뉴 조회 권한이 필요합니다.
  • 관리자 회원 검색(GET /api/admin/users/search — 회원 자동완성)의 검색어 %·_ 가 와일드카드로 쓰여, % 한 글자만 쳐도 볼 수 있는 회원 전체가 나오던 문제를 고쳤습니다. 회원 목록 검색과 같이 글자 그대로 찾습니다.
  • 내 정보 응답에 언어 코드만 실려 사용자 화면 내 정보의 언어 칸이 ko 처럼 코드로 보이던 문제를 고쳤습니다. 언어 이름(language_label)을 함께 싣습니다.
  • 언어를 일본어로 고른 회원의 언어 칸(관리자 회원 목록·상세)이 user.language.ja 같은 번역 키로 보이던 문제를 고쳤습니다. 이름 번역이 없는 언어는 코드 그대로 보입니다.
  • 사용자 API 의 내 정보 조회·수정과 활동 기록 조회(GET·PUT /api/user/profile, GET /api/user/profile/activity-log)가 모든 회원에게 「권한이 없습니다」(403)로 거절되던 문제를 고쳤습니다. 이 주소들이 요구하는 권한(내 정보 조회·내 정보 수정)이 권한 목록에 없었습니다. 이제 두 권한이 「일반 사용자」 역할에 기본으로 들어가고, 이미 설치된 사이트는 코어 업데이트 때 함께 추가됩니다. 운영자가 역할 편집에서 빼면 그 역할의 회원은 종전처럼 거절됩니다.
  • 비활성·차단·탈퇴·가입대기·휴면 상태 회원이 이미 로그인해 둔 기기로 마이페이지를 열면 화면이 비어 보이고 머리글이 로그아웃 상태로 보여, 마이페이지에 마련된 계정 상태 배지와 안내(예: 「계정이 차단 상태입니다. 관리자에게 문의하세요.」)가 실제로는 보일 수 없던 문제를 고쳤습니다. 이제 그 회원의 역할에 「내 정보 조회」 권한이 있으면 본인 정보 조회만 허용해 상태 배지와 안내가 보입니다. 정보 수정·비밀번호 확인·탈퇴 같은 쓰기와 그 밖의 기능은 종전처럼 상태 사유와 함께 거절되고, 이 상태의 회원이 새로 로그인할 수 없는 것도 그대로입니다.
  • 역할 편집 화면의 권한 목록에서 사용자용 알림·내 정보·본인인증 같은 권한 묶음이 정해진 순서가 아니라 섞여 보이던 문제를 수정했습니다.

로그인·본인인증

  • 로그인이 풀린 채 로그인 화면을 열면 주소에 로그인 화면 자신이 돌아갈 곳으로 붙어, 로그인을 마친 뒤 다시 로그인 화면에 떨어지던 문제를 고쳤습니다(관리자 로그인 포함). 이제 로그인·회원가입·비밀번호 찾기·재설정 화면은 돌아갈 곳으로 삼지 않고, 로그인 화면이 이미 돌아갈 곳을 갖고 있으면 그곳으로 이어 갑니다.
  • 토큰이 만료된 채 화면을 열면 로그인 화면으로 옮겨지기 직전 「요청을 보내지 못했습니다. 네트워크 연결을 확인…」 토스트가 뜨던 문제를 고쳤습니다. 로그인이 필요한 데이터를 비회원으로 열었을 때도 같은 토스트 대신 로그인 화면(돌아올 곳 포함)으로 옮겨집니다.
  • 확인 링크로 보내는 본인인증(비밀번호 재설정 등)은 링크를 연 쪽에서만 확인이 끝나, 인증을 시작한 화면이 그 결과를 받지 못해 다음 단계로 넘어가지 못하던 문제를 수정했습니다. 이제 인증을 시작한 화면이 확인 결과를 받아 이어 가며, 링크는 다른 기기에서 열어도 됩니다.
  • 본인인증의 인증번호 확인 요청 횟수 제한이 같은 방문자의 다른 공개 API 호출과 횟수를 함께 세고 있어, 2단계 인증 화면을 몇 번 오간 뒤 인증번호 확인이 「요청이 너무 많습니다」로 막히던 문제를 수정했습니다. 본인인증의 요청·확인·취소·상태 조회·콜백이 각각 자기 횟수만 세도록 분리했습니다.
  • 본인확인 코드를 보내지 못하면 그 자리에서 알려줍니다. 전까지는 발송이 실패해도 화면이
    「전송된 6자리 코드를 입력해주세요」와 남은 시간 카운트다운을 띄워, 오지 않을 코드를 기다리다
    만료를 맞았습니다. 메일·SMS 장애로 코드가 나가지 못하면 이제 「인증 코드를 보내지 못했습니다.
    잠시 후 다시 시도하시거나 다른 인증 수단을 이용해주세요.」로 즉시 안내합니다.
  • 본인인증이 필요한 동작에서 인증 화면으로 넘어가 인증을 마쳐도 원래 화면으로 돌아가지 않던 문제를 고쳤습니다.

알림

  • 알림이 아무에게도 가지 않은 경우가 아무 흔적 없이 사라지던 문제를 수정했습니다. 수신자 규칙으로 받을 사람을 찾지 못했거나 비회원의 이메일이 비어 있으면, 이제 발송 이력에 「건너뜀」으로 사유와 적용된 수신자 규칙이 「관련 사용자(게시글 작성자) — 이벤트 유발자 제외」처럼 읽을 수 있는 이름으로 함께 남습니다. 종전에는 운영자가 "왜 안 왔는지" 를 확인할 방법이 없었습니다.
  • 수신자 규칙을 여러 개 둔 알림에서 「알림을 일으킨 사람 제외」가 그 규칙뿐 아니라 전체 수신자에게 적용되던 문제를 수정했습니다. 예를 들어 「운영자(본인 제외) + 주문자」로 설정한 알림에서 주문자 본인이 조작하면 주문자에게도 알림이 가지 않았습니다. 이제 제외는 그 설정이 붙은 규칙에만 적용됩니다.
  • 알림을 일으킨 회원의 계정이 삭제된 경우, 주문 등에 남은 연락처로 대신 보내지 않고 발송 이력에 「알림 대상 회원의 계정이 삭제되어 발송하지 않았습니다」를 남깁니다.
  • 탈퇴한 회원에게 메일·SMS·알림톡이 더 이상 발송되지 않습니다. 탈퇴 시 연락처가 익명화되므로
    그 주소로 보내면 받을 사람이 없고 바운스만 쌓였습니다. 이제 바깥 채널은 건너뛰고, 발송 이력에
    「탈퇴한 회원이라 바깥 채널로는 발송하지 않았습니다」 사유가 함께 남아 운영자가 왜 안 나갔는지
    화면에서 확인할 수 있습니다. 알림함(사이트 내 알림)은 그대로 쌓여 탈퇴 전후 이력이 끊기지 않습니다.
  • 큐 워커가 알림 수신 권한을 작업마다 새로 판정합니다. 권한 판정 결과가 워커 수명 내내 남아, 역할을
    바꾼 뒤에도 워커를 재시작하기 전까지 이전 권한 기준으로 알림이 나갔습니다.
  • 백그라운드 작업(큐)에서 만든 알림의 링크가 http://localhost 로 나가던 문제를 고쳤습니다.
  • 알림 설정의 [기본값 복원]이 문자·알림톡처럼 채널 확장이 덧붙인 템플릿에서 언어팩 번역(일본어 등)을 지우던 문제를 수정했습니다. 이제 복원해도 설치 때와 같은 언어가 남습니다.
  • 알림 템플릿의 역할·회원 수신자 값을 목록이 아닌 키가 붙은 묶음으로 보내면 그대로 저장되던 문제를 막았습니다. 이제 저장 단계에서 사유와 함께 거절합니다. 수신자 칸 검증 안내가 「recipients.0.relation」 같은 내부 키 대신 「관련 사용자 관계」·「수신자 값」 같은 항목 이름으로 나옵니다.
  • 알림 템플릿의 값을 바꿨다가 원래 값으로 되돌려 저장해도 「운영자가 수정한 항목」 으로 남아, 이후 확장 업데이트의 기본값이 그 항목에 반영되지 않던 문제를 고쳤습니다.
  • 회원 알림 목록 응답에 읽음·삭제 권한 값을 함께 내려, 마이페이지 알림함과 헤더 알림 센터가 권한이 없는 회원에게 [모두 읽음]·삭제 버튼을 잠급니다.

활동 로그

  • 활동 로그 API 가 회원이 없는 로그(시스템 작업)의 user 를 회원처럼 보이는 모양으로 내보내 화면이 회원 메뉴를 그리던
    문제를 수정했습니다. 이제 이런 로그의 user 는 uuid 가 null 이고 name 에 「시스템」·「시스템(CLI)」 같은 행위자 라벨이 담깁니다.
  • 어드민 화면에서 템플릿을 「데이터도 삭제」로 제거해도 활동 로그에는 데이터를 남긴 제거로 기록되던 문제를 수정했습니다.
  • 작업 처리기(큐 워커)가 회원이 한 작업 다음에 시스템 작업을 처리하면, 시스템 작업의 활동 로그 행위자가 앞 회원으로 기록되던 문제를 수정했습니다.
  • 회원 가입·비밀번호 찾기 요청·비밀번호 변경이 활동 로그에 남지 않던 문제를 수정했습니다. 활동 로그가 실제로 발화하지 않는 이름을
    구독하고 있었습니다. 비밀번호 변경은 이제 변경한 사람(관리자가 바꿨으면 관리자)을 행위자로 남깁니다.
  • 활동 로그 다국어 전환 마이그레이션이 중간에 멈춘 뒤 다시 실행하면 매번 실패하던 문제를 고쳤습니다.
  • 활동 로그에서 일반 회원의 로그인·로그아웃도 「관리자 로그인」·「관리자 로그아웃」으로 보이던 문제를 고쳤습니다. 이제 관리자 로그인·로그아웃만 그렇게 표시되고, 이전에 쌓인 기록은 「로그인」·「로그아웃」으로 보입니다.
  • 회원 일괄 상태 변경에서 최고관리자·관리 범위 밖이라 제외된 회원에게도 활동 로그에 「상태 변경」 기록이 남던 문제를 고쳤습니다. 이제 실제로 바뀐 회원만 기록되고, 일괄 탈퇴는 탈퇴가 끝난 회원만 기록됩니다(훅 sirsoft-core.user.after_bulk_update 의 첫 인자도 실제로 바뀐 회원 목록입니다).
  • 모듈·플러그인의 관리자 화면에서 한 작업(예: 회원의 인증 앱 강제 해제)이 활동 로그에 「사용자」 유형으로 남던 문제를 고쳤습니다. 이제 IP 접근 제한이 관리자 영역으로 보는 주소(관리자 화면·관리자 API·확장의 관리자 API·관리자 로그인)에서 남는 활동 로그는 모두 「관리자」 유형으로 분류됩니다. 관리자 로그인 기록도 「관리자」 유형으로 남습니다.

관리자 화면·환경설정

  • 환경설정 > SEO 탭에서 고른 기본 공유 이미지가 저장되지 않던 문제를 고쳤습니다. 저장 버튼이 그 업로더에 「지금 올리라」는 신호를 보내지 않아, 새 이미지를 골라 저장해도 업로드 요청이 없고 설정이 빈 채로 남았습니다(오류 표시도 없었습니다).
  • 비밀번호 최소 길이를 바꿔도 안내 문구가 늘 「최소 8자」로 나오던 문제를 고쳤습니다 — 설정한 길이가 그대로 안내됩니다.
  • 환경설정 › 보안에서 저장한 비밀번호 최소 길이가 숫자가 아닌 문자열("10")로 저장되던 문제를 고쳤습니다 — 다른 비밀번호 정책 숫자 값과 같이 정수로 저장됩니다.
  • 환경설정 › 보안에서 인증 토큰 유지시간을 0(무한대)으로 입력해 저장하면 「0(무한대) 또는 30~3600분 사이여야 합니다」 오류로 저장되지 않던 문제를 고쳤습니다. 인증 토큰 유지시간·로그인 시도 횟수·잠금 시간을 고쳐 저장하면 문자열로 저장되던 것도 정수로 저장됩니다.
  • 환경설정 저장 오류 문구에 화면 라벨 대신 내부 필드 이름이 나오던 문제를 수정했습니다(예: "seo.bot_user_agents.0" → "봇 User-Agent 목록"). 탭 묶음·목록 항목·알림 채널 항목이 대상입니다.
  • .env 우선 모드에서 .env 로 지정한 비밀값(웹소켓 앱 시크릿·Mailgun 시크릿·AWS 키 등)이 화면에서 빈 칸으로 전달되어 드라이버·메일 설정 저장과 테스트 메일 발송이 「필수 항목」 오류로 실패하던 문제를 수정했습니다. .env 가 정한 값은 요청에서 요구하지 않으며, 테스트 메일은 .env 값으로 발송합니다.
  • 환경설정 SEO 의 사이트맵 생성 시각에 형식만 맞는 없는 시각(99:99·24:00 등)이 저장돼 예약 작업 목록이 열리지 않던 문제를 고쳤습니다. 이제 00:00~23:59 만 저장됩니다.
  • 모듈·플러그인을 켜거나 꺼도 관리자 대시보드 통계가 실시간으로 갱신되지 않던 문제를 수정했습니다.
  • 회원이 스스로 가입해도 관리자 대시보드의 회원 통계가 실시간으로 갱신되지 않던 문제를 수정했습니다.
  • 관리자 목록 화면이 화면에 그리지 않는 데이터까지 읽어 오던 문제를 고쳤습니다. 건수 배지처럼 집계 값을 함께 표시하는 목록(주문·상품·리뷰·게시글 등)에서 이 현상이 나타났으며, 목록이 실제로 사용하는 항목만 읽도록 바로잡아 데이터가 많은 사이트일수록 목록이 빠르게 열립니다.
  • 스케줄 목록의 등록일, 스케줄 실행 이력의 시작일 조건과 회원 통계의 「오늘 가입」 이 날짜를 UTC 하루로 잘라, 화면에 보이는 날짜와 다른 하루로 걸러지거나 세던 문제를 고쳤습니다. 이제 보는 사람의 시간대 하루로 거릅니다.
  • 권한이 좁은 운영자가 관리자 화면을 열 때 같은 「해당 권한이 없습니다.」 알림이 화면 공통 데이터마다 여러 장 겹쳐 뜨던 문제를 수정했습니다. 같은 알림은 잠깐 사이에 한 장만 뜹니다.
  • 권한 없는 운영자에게 쓰기 동작이 열려 있던 관리자 화면을 잠갔습니다 — 플러그인 설정 화면(응답에 저장 권한을 실어 읽기 전용 지원), 스케줄 목록의 등록·일괄 변경·행 선택·행 토글, 헤더 알림 센터의 모두 읽음·삭제와 닫을 때 자동 읽음 처리, 환경설정 SEO 탭 입력 13칸, 레이아웃 편집기 판본 복원, 회원 등록 화면(등록 권한 없으면 진입 거부), 메뉴 관리에서 주소로 수정 화면에 바로 들어가는 경우, 활동 로그 행 선택.

예약 작업

  • 예약 작업 관리와 실행 이력 창에서도 같은 이유로 쪽 이동이 죽어 있던 것을 함께 수정했습니다. 목록 위 「총 N개」 가 항상 0으로 보이던 것도 같은 원인이었습니다. 예약 작업이 한 쪽(20건)을 넘는 사이트에서만 드러나던 문제입니다.
  • 스케줄 목록의 빠른 기간(오늘·일주일 등)이 UTC 날짜로 계산돼 한국 시간 오전 9시 전에는 「오늘」 이 어제로 채워지던 문제를 고쳤습니다.
  • 예약 작업 목록에서 등록 시각이 같은 작업이 한 쪽(20건)을 넘으면 2쪽이 1쪽의 작업을 다시 보여 주고 일부 작업은 어느 쪽에도 나오지 않던 문제를 수정했습니다. 확장 설치가 작업을 같은 초에 여러 개 등록할 때 드러났습니다.
  • 예약 작업 실행 이력 창이 이력이 있어도 「실행 이력이 없습니다」만 보이던 문제를 수정했습니다. 회차별 정상 출력·오류 출력과 실행자도 함께 보이고, 이력이 여러 쪽이면 쪽 이동이 됩니다. 실행 이력 목록 API 응답에 output·error_output 이 포함됩니다.

검색엔진용 화면

  • 확장을 끄거나 제거해도 검색엔진용 화면 캐시에 그 확장이 그리던 내용이 남던 문제를 수정했습니다.
  • 검색엔진용 화면의 제목(<title>)이 인기 게시글·게시판 목록 화면에서 「그누보드7 | 그누보드7」처럼 사이트 이름만 두 번 나가고, 회원 프로필·회원 작성글 화면에서는 화면 제목 없이 사이트 이름만 나가던 문제를 수정했습니다. 이제 「인기 게시글 | 그누보드7」·「사용자 프로필 | 그누보드7」 처럼 나갑니다.
    • 게시판 목록의 기본 제목 틀({site_name})처럼 사이트 이름만 담은 제목은 화면 정보가 없는 것으로 보고 화면 제목으로 넘기며, 다른 제목이 없으면 라우트에 적힌 화면 제목(meta.title)을 씁니다. 공유 미리보기 제목(og:title)도 같은 화면 제목을 쓰고, 첫 화면은 종전대로 사이트 이름만 나갑니다.
    • 적용 뒤 php artisan seo:clear 로 저장된 검색엔진용 화면을 비우면 바로 반영됩니다.

설치·코어 업데이트

  • 업데이트 도중 데이터베이스 변경이 중단됐을 때, 다시 실행하면 이어서 정상 진행됩니다. 종전에는 일부 변경만 적용된 상태에서 멈추면 재실행이 "이미 존재하는 항목" 오류로 계속 실패해 운영자가 직접 손대지 않고는 업데이트를 마칠 수 없었습니다.
  • 중단된 설치를 「재시도」로 이어서 진행할 때, 기존 데이터베이스를 지우는 선택을 하면 그 전에 이미 설치된 확장이 빠진 채 설치가 끝나던 문제를 수정했습니다. 빠진 확장에 기대는 템플릿 설치가 「필수 의존성이 충족되지 않았습니다」로 실패해 설치를 마칠 수 없었습니다. 이제 데이터베이스를 지울 때 함께 사라지는 항목은 모두 다시 설치됩니다.
  • Windows 에서 폴더에 읽기 전용 속성이 걸려 설치가 막힌 경우, 안내대로 권한 명령을 실행해도 같은 실패 화면이 반복되던 문제를 수정했습니다. 읽기 전용은 접근 권한이 아니라 파일 속성이라 권한 명령으로는 해제되지 않습니다. 이제 이 경우를 따로 알아보고 폴더와 그 안쪽 파일·하위 폴더까지 속성을 해제하는 명령을 함께 안내합니다. 압축을 풀거나 백업을 복원한 뒤에 흔히 생깁니다.
  • 설치를 마친 직후 주소 연결 정보(라우트 캐시)가 만들어지지 않던 문제를 수정했습니다. 설치 마지막에 설정 캐시는 만들면서 주소 연결 정보만 빠져 있었고, 사이트는 매 요청마다 이를 다시 읽느라 느린 상태로 시작했습니다. 겉으로는 정상 동작해 알아채기 어려웠고, 확장을 하나라도 설치하거나 변경하면 그때 만들어져 그 뒤로는 드러나지 않았습니다. 이제 설치 마지막 단계에서 함께 만들어집니다.
  • 설치 마법사의 사이트 주소 기본값이 리버스 프록시 뒤에서 내부 주소나 http 로 채워지던 문제를 고쳤습니다. 이제 운영자가 실제로 보고 있는 주소로 채웁니다.
  • 설치가 끝난 사이트에서 php artisan db:seed --sample 이 관리자 계정 환경변수가 없다는 오류로 멈춰 샘플 회원을 만들 수 없던 문제를
    수정했습니다. 관리자 시더는 이제 최고관리자가 이미 있거나 설치 환경변수가 없으면 안내만 하고 건너뛰며, 기존 회원을 지우지 않습니다.
    설치 마법사의 첫 관리자 생성은 종전과 같습니다.
  • php artisan db:seed --sample 이 레이아웃 버전 샘플을 만들다 데이터 형식 오류로 멈춰 뒤의 샘플(활동 로그 등)이 만들어지지 않던 문제를
    수정했습니다. 레이아웃 버전 샘플은 이제 기존 편집 이력을 지우지 않고 그 뒤 번호로 붙으며, 다시 실행하면 샘플만 새로 만듭니다.
  • php artisan db:seed --sample 이 코어 활동 로그 샘플을 만들면서 기존 활동 로그를 모두 지우던 문제를 수정했습니다. 이제 샘플로 만든
    로그에만 표시를 남기고, 다시 실행할 때는 그 샘플 로그만 새로 만듭니다. 실제 활동 기록은 그대로 둡니다.

개발 도구

  • php artisan ext:docgen 이 만드는 확장 개발자 문서의 「전역 진입점」 판정이 고쳐졌습니다. 핸들러 등록 메서드를 변수로 떼어 부르는 확장을 「엔트리 없음」으로 적어 재등록 전역 누락이 묻혔고, 템플릿의 window.G7TemplateHandlers 를 「미노출」로 거짓 경고했습니다. 이제 재등록 전역이 없으면 경고를 쓰고, 화살표 함수로 선언한 initPlugin 도 진입점으로 인정합니다. 자기 test:run 스크립트가 없는 확장의 Vitest 실행 명령은 저장소 루트 기준으로 안내합니다.
  • 개발 환경 전용 php artisan api:docgen --seed 가 만든 샘플(권한·메뉴·역할·사용자·알림·스케줄 등)을 개발 DB 에 남겨, 「API 문서 샘플 권한」이 실제 권한처럼 역할에 배정되던 문제를 고쳤습니다. 이제 실행이 끝나면 만든 샘플을 모두 지우고, 이전 실행이 남긴 것도 다음 실행 때 지웁니다.