fix(sirsoft-gdpr): 쿠키 배너 노출 토글 안내 문구 및 필드 레이아웃 정정
banner_enabled(쿠키 배너 노출) 토글 안내가 "마이페이지 동의 관리 카드"까지 함께 켜지고 꺼지는 것처럼 서술되어 있었으나, 실제로는 카드가 이 토글과 무관하게 동의/철회 이력이 있는 회원에게 항상 노출된다(GDPR Art.7(3) 철회 대칭성 보장, mypage_privacy_tab.json 회귀 가드로 이미 고정된 설계). 문구만 실제 동작과 어긋나 있어 ko/en 양쪽 hint 및 관련 코드 주석을 바로잡았다. 문구 확인 과정에서 field_legal_entity_name / field_data_storage_location / field_banner_enabled / field_banner_position 4개 필드가 텍스트 스타일 전용 클래스(section-heading-md, grid 미정의)를 컨테이너로 잘못 사용해 안내 문구가 길어지면 입력/토글 컨트롤이 아래 줄로 밀려나던 기존 UI 결함도 함께 발견해 수정했다. 같은 파일의 field_privacy_policy_slug가 이미 쓰던 올바른 grid-3col-responsive 패턴으로 통일.
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
- 마이페이지 「쿠키 동의 관리」의 글자 크기·여백이 어긋나던 문제를 바로잡고, 동의한 항목에는 동의한 날짜를, 철회한 항목에는 철회한 날짜를 함께 표시합니다.
|
||||
- 「동의하지 않고 계속하기」를 눌러도 필수 쿠키가 「동의함」으로 기록되지 않도록 바로잡았습니다 — 필수 쿠키는 서비스 이용에 반드시 필요하여 동의 대상이 아닙니다.
|
||||
- 거부 시 안내 문구를 「동의하지 않고 계속합니다」로 바로잡았습니다 (이전에는 「동의가 저장되었습니다」로 잘못 표시).
|
||||
- 관리자 환경설정의 「쿠키 배너 노출」 안내 문구를 실제 동작에 맞게 바로잡았습니다 — 이 토글은 배너와 자동 차단만 제어하며, 마이페이지 「쿠키 동의 관리」 카드는 동의·철회 이력이 있는 회원에게 이 토글과 무관하게 항상 노출됩니다.
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -28,6 +29,7 @@
|
||||
- 관리자 환경설정의 「운영 주체 / 개인정보처리방침」 섹션 제목 영역이 다른 카드와 다르게 표시되던 문제를 바로잡았습니다.
|
||||
- 관리자 환경설정의 저장/취소 버튼을 다른 관리자 화면과 동일하게 화면 하단 고정 위치로 옮기고, 상단 탭 영역의 불필요한 구분선과 좌우 여백 어긋남을 바로잡았습니다.
|
||||
- 관리자 환경설정 「정책 버전 보기」에서 본문 페이지 링크를 클릭하면 페이지를 찾을 수 없던 문제를 바로잡았습니다.
|
||||
- 관리자 환경설정의 「운영 주체」·「쿠키 배너 노출」·「배너 위치」 필드에서 안내 문구가 길어질 때 입력·토글 컨트롤이 옆이 아닌 아래 줄로 밀려나던 문제를 바로잡았습니다.
|
||||
|
||||
## [1.0.1] - 2026-07-16
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ php artisan plugin:activate sirsoft-gdpr
|
||||
|
||||
| 항목 | 설명 |
|
||||
|------|------|
|
||||
| 쿠키 배너 노출 (`banner_enabled`) | 마스터 토글 — ON 시 배너 + 자동 차단 + 마이페이지 동의 관리 카드가 일괄 활성화됩니다. GDPR Art.6 "동의 전 처리 금지" 의 강제 메커니즘인 자동 차단을 단독 OFF 할 수 없도록 단일 토글로 통합되어 있습니다 |
|
||||
| 쿠키 배너 노출 (`banner_enabled`) | 마스터 토글 — ON 시 배너 + 자동 차단이 함께 활성화됩니다. GDPR Art.6 "동의 전 처리 금지" 의 강제 메커니즘인 자동 차단을 단독 OFF 할 수 없도록 단일 토글로 통합되어 있습니다. 마이페이지 동의 관리 카드는 이 토글과 무관하게 동의/철회 이력이 있는 회원에게 항상 노출됩니다 (Art.7(3) 철회 대칭성 보장) |
|
||||
| 배너 위치 (`banner_position`) | 하단 바 / 좌하단 팝업 / 우하단 팝업 / 중앙 모달 |
|
||||
|
||||
### 자동 차단 정책
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"version": "1.0.0",
|
||||
"description": "GDPR (일반 데이터 보호 규정) 플러그인 환경설정 기본값 및 프론트엔드 스키마. banner_enabled 가 GDPR 컴플라이언스 모드 단일 토글 — ON 시 배너 노출 + 동의 전 외부 추적 자동 차단 + 마이페이지 동의 관리 카드 일괄 활성."
|
||||
"description": "GDPR (일반 데이터 보호 규정) 플러그인 환경설정 기본값 및 프론트엔드 스키마. banner_enabled 가 GDPR 컴플라이언스 모드 단일 토글 — ON 시 배너 노출 + 동의 전 외부 추적 자동 차단이 함께 시작됨. 마이페이지 동의 관리 카드는 이 토글과 무관하게 동의/철회 이력이 있는 회원에게 항상 노출됨."
|
||||
},
|
||||
"frontend_schema": {
|
||||
"privacy_policy_slug": { "type": "string", "expose": true },
|
||||
|
||||
@@ -78,7 +78,7 @@ return [
|
||||
],
|
||||
'banner_enabled' => [
|
||||
'label' => 'Show Cookie Banner',
|
||||
'hint' => 'When enabled, the cookie consent banner, pre-consent auto-blocking, and the MyPage consent management card are activated together. (Auto-blocking is the enforcement mechanism for GDPR Art.6 "no processing before consent" and is unified into a single toggle to prevent operators from disabling it independently.)',
|
||||
'hint' => 'When enabled, the cookie consent banner and pre-consent auto-blocking are activated together. (Auto-blocking is the enforcement mechanism for GDPR Art.6 "no processing before consent" and is unified into a single toggle to prevent operators from disabling it independently.) The MyPage consent management card is independent of this toggle and always shows for members with consent/withdrawal history.',
|
||||
],
|
||||
'banner_position' => [
|
||||
'label' => 'Banner Position',
|
||||
|
||||
@@ -78,7 +78,7 @@ return [
|
||||
],
|
||||
'banner_enabled' => [
|
||||
'label' => '쿠키 배너 노출',
|
||||
'hint' => '활성 시 쿠키 동의 배너 노출 + 동의 전 외부 추적 자동 차단 + 마이페이지 동의 관리 카드가 일괄 활성됩니다. (GDPR Art.6 "동의 전 처리 금지" 의 강제 메커니즘인 차단을 분리 토글로 끄지 못하도록 단일 토글로 통합)',
|
||||
'hint' => '활성 시 쿠키 동의 배너 노출 + 동의 전 외부 추적 자동 차단이 함께 시작됩니다. (GDPR Art.6 "동의 전 처리 금지" 의 강제 메커니즘인 차단을 분리 토글로 끄지 못하도록 단일 토글로 통합) 마이페이지 동의 관리 카드는 이 토글과 무관하게 동의/철회 이력이 있는 회원에게 항상 노출됩니다.',
|
||||
],
|
||||
'banner_position' => [
|
||||
'label' => '배너 위치',
|
||||
|
||||
@@ -381,7 +381,9 @@ class Plugin extends AbstractPlugin
|
||||
'data_storage_location' => '',
|
||||
|
||||
// 쿠키 배너 + 자동 차단 (F-01 / F-02) — banner_enabled 단일 토글로 통합 제어.
|
||||
// ON 시 배너 노출 + 동의 전 외부 추적 자동 차단 + 마이페이지 동의 관리 카드 일괄 활성.
|
||||
// ON 시 배너 노출 + 동의 전 외부 추적 자동 차단이 함께 시작됨. 마이페이지 동의 관리
|
||||
// 카드는 이 토글과 무관 — GDPR Art.7(3) 철회 대칭성 보장을 위해 동의/철회 이력이
|
||||
// 있는 회원에게 배너 노출 여부와 무관하게 항상 노출된다 (resources/extensions/mypage_privacy_tab.json 참조).
|
||||
// 차단을 별도 토글로 제공하지 않는 이유: GDPR Art.6 "동의 전 처리 금지" 의 강제 메커니즘
|
||||
// 인 차단을 운영자가 단독 OFF 할 수 있으면 위반 조합 (배너 ON + 차단 OFF) 가능 → CNIL
|
||||
// Microsoft €60M / Amazon €35M / Google €100M 처벌 패턴과 동일. 단일 토글로 구조적 차단.
|
||||
@@ -492,15 +494,15 @@ class Plugin extends AbstractPlugin
|
||||
'required' => false,
|
||||
],
|
||||
|
||||
// 쿠키 배너 + 자동 차단 + 마이페이지 카드 단일 토글 (banner_enabled)
|
||||
// 쿠키 배너 + 자동 차단 단일 토글 (banner_enabled). 마이페이지 카드는 이 토글과 무관 (별도 절 참조).
|
||||
// 기본값 true — 플러그인 활성화 = 운영자의 GDPR 컴플라이언스 의사 표명.
|
||||
'banner_enabled' => [
|
||||
'type' => 'boolean',
|
||||
'default' => true,
|
||||
'label' => ['ko' => '쿠키 배너 노출', 'en' => 'Show Cookie Banner'],
|
||||
'hint' => [
|
||||
'ko' => 'ON 시 쿠키 동의 배너 노출 + 동의 전 외부 추적 자동 차단 + 마이페이지 동의 관리 카드 일괄 활성. 정책 슬러그·카테고리 설정 후 켜는 것을 권장.',
|
||||
'en' => 'When ON, the cookie consent banner, pre-consent auto-blocking, and the MyPage consent management card are activated together.',
|
||||
'ko' => 'ON 시 쿠키 동의 배너 노출 + 동의 전 외부 추적 자동 차단이 함께 시작됩니다. 정책 슬러그·카테고리 설정 후 켜는 것을 권장. 마이페이지 동의 관리 카드는 이 토글과 무관하게 동의/철회 이력이 있는 회원에게 항상 노출됩니다.',
|
||||
'en' => 'When ON, the cookie consent banner and pre-consent auto-blocking are activated together. The MyPage consent management card is independent of this toggle and always shows for members with consent/withdrawal history.',
|
||||
],
|
||||
'required' => false,
|
||||
],
|
||||
|
||||
+51
@@ -1,3 +1,4 @@
|
||||
// e2e:allow 이슈 #509 4번 — banner_enabled 안내 문구/주석 정정만 (레이아웃 구조·핸들러·바인딩 변경 없음, 브라우저 관찰 가능한 동작 변화 없음). Vitest 회귀(위 hint 문자열 검증)로 충분.
|
||||
/**
|
||||
* GDPR 플러그인 환경설정 레이아웃 구조 검증
|
||||
*
|
||||
@@ -15,6 +16,8 @@ import { describe, it, expect } from 'vitest';
|
||||
import layout from '../../../layouts/admin/plugin_settings.json';
|
||||
import publishModal from '../../../layouts/admin/partials/plugin_settings/_policy_version_publish_modal.json';
|
||||
import snapshotModal from '../../../layouts/admin/partials/_shared/_policy_version_snapshot_modal.json';
|
||||
import koLang from '../../../lang/ko.json';
|
||||
import enLang from '../../../lang/en.json';
|
||||
import { findById, type AnyNode } from './helpers';
|
||||
|
||||
describe('admin/plugin_settings.json — 3 카드 (operator / cookie_banner / auto_blocking_policy)', () => {
|
||||
@@ -121,7 +124,55 @@ describe('admin/plugin_settings.json — 3 카드 (operator / cookie_banner / au
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 이슈 #509 체크리스트 4번 회귀 테스트 — 라벨/hint + 컨트롤(Input/Toggle/Select) 2단
|
||||
* 배치 필드가 `section-heading-md`(텍스트 스타일 전용, grid 미정의) 를 컨테이너
|
||||
* className 으로 사용해 col-span-* 자식이 무효화되고 컨트롤이 아래 줄로 밀려나던
|
||||
* 결함. 코드베이스 표준은 `grid-3col-responsive`(grid grid-cols-1 lg:grid-cols-3
|
||||
* gap-4 items-start) — field_privacy_policy_slug 가 원래 이 클래스를 올바르게
|
||||
* 사용하고 있었다 (참조 패턴).
|
||||
*/
|
||||
describe('필드 2단 배치 컨테이너 — grid-3col-responsive 사용 (section-heading-md 오용 회귀 가드)', () => {
|
||||
it.each([
|
||||
'field_legal_entity_name',
|
||||
'field_data_storage_location',
|
||||
'field_banner_enabled',
|
||||
'field_banner_position',
|
||||
])('%s 컨테이너 className 이 grid-3col-responsive 를 포함한다', (fieldId) => {
|
||||
const field = findById(root, fieldId);
|
||||
const className = String((field?.props as { className?: string } | undefined)?.className ?? '');
|
||||
expect(className).toContain('grid-3col-responsive');
|
||||
});
|
||||
|
||||
it('section-heading-md 는 더 이상 필드 2단 배치 컨테이너로 오용되지 않는다 (텍스트 스타일 전용 클래스)', () => {
|
||||
const layoutJson = JSON.stringify(root);
|
||||
expect(layoutJson).not.toContain('"className":"section-heading-md"');
|
||||
});
|
||||
});
|
||||
|
||||
describe('card_cookie_banner', () => {
|
||||
/**
|
||||
* 이슈 #509 체크리스트 4번 회귀 테스트 — banner_enabled 안내 문구가 "마이페이지 동의
|
||||
* 관리 카드"까지 이 토글로 일괄 제어되는 것처럼 서술하던 결함. 실제로는 카드가
|
||||
* banner_enabled 와 무관하게 동의/철회 이력 존재 여부로만 판정된다
|
||||
* (mypage_privacy_tab.test.tsx "카드 표시 조건" 참조). 안내 문구를 실제 동작과
|
||||
* 불일치시키지 않도록 ko/en 양쪽 hint 를 고정한다.
|
||||
*/
|
||||
it('banner_enabled hint 는 마이페이지 카드가 이 토글과 무관하게 항상 노출됨을 명시한다 (ko/en)', () => {
|
||||
const koHint = (koLang as { settings?: { fields?: { banner_enabled?: { hint?: string } } } }).settings
|
||||
?.fields?.banner_enabled?.hint ?? '';
|
||||
const enHint = (enLang as { settings?: { fields?: { banner_enabled?: { hint?: string } } } }).settings
|
||||
?.fields?.banner_enabled?.hint ?? '';
|
||||
|
||||
expect(koHint).toContain('마이페이지');
|
||||
expect(koHint).toContain('무관');
|
||||
expect(koHint).not.toMatch(/마이페이지.*(함께|일괄).*(시작|활성)/);
|
||||
|
||||
expect(enHint).toContain('MyPage');
|
||||
expect(enHint).toContain('independent');
|
||||
expect(enHint).not.toMatch(/MyPage.*activated together/);
|
||||
});
|
||||
|
||||
it('banner_enabled (쿠키 배너 노출 단일 토글) / banner_position 포함. auto_blocking_enabled 별도 토글 제거됨', () => {
|
||||
const fields = findById(root, 'card_cookie_banner_fields');
|
||||
const serialized = JSON.stringify(fields);
|
||||
|
||||
@@ -9,10 +9,11 @@
|
||||
* (회원/게스트 통합 — 인증 불필요. 회원은 sanctum 토큰이 있으면 자동 적용)
|
||||
*
|
||||
* banner_enabled 가 단일 토글 (쿠키 배너 노출) — ON 시 배너 노출 + 동의 전 외부 추적
|
||||
* 자동 차단 + 마이페이지 동의 관리 카드 일괄 활성. 차단 별도 토글 없음 (위반 조합 구조적 차단).
|
||||
* 자동 차단이 함께 시작됨. 차단 별도 토글 없음 (위반 조합 구조적 차단).
|
||||
*
|
||||
* 마이페이지 동의 카드(F-04)는 GDPR Art.7(3) 대칭성 의무에 따라 회원에게 동의 데이터가 있을
|
||||
* 때만 노출 (빈 카드 노출 방지). 가드 조건은 `mypage_privacy_tab.json` 의 `if` 속성에 정의.
|
||||
* 마이페이지 동의 카드(F-04)는 banner_enabled 와 무관 — GDPR Art.7(3) 대칭성 의무(철회는
|
||||
* 동의만큼 쉬워야 함)에 따라 회원에게 동의 데이터가 있으면 배너 비활성 중에도 항상 노출
|
||||
* (빈 카드 노출만 방지). 가드 조건은 `mypage_privacy_tab.json` 의 `if` 속성에 정의.
|
||||
*
|
||||
* G7Core.api 가 로드된 환경에서는 G7Core.api.get() 사용 (auth/devtools/locale 헤더 자동),
|
||||
* 미로드 환경(부트 초기 등)에서는 fetch 로 fallback.
|
||||
@@ -23,7 +24,8 @@
|
||||
export interface GdprPublicSettings {
|
||||
cookie_policy_version: string;
|
||||
/**
|
||||
* 쿠키 배너 노출 단일 토글. ON 시 배너 + 자동 차단 + 마이페이지 카드 일괄 활성.
|
||||
* 쿠키 배너 노출 단일 토글. ON 시 배너 + 자동 차단이 함께 활성.
|
||||
* 마이페이지 동의 관리 카드는 이 값과 무관 (동의/철회 이력 존재 여부로만 판정).
|
||||
*/
|
||||
banner_enabled: boolean;
|
||||
/**
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
},
|
||||
"banner_enabled": {
|
||||
"label": "Show Cookie Banner",
|
||||
"hint": "When enabled, the cookie banner, pre-consent auto-blocking, and the MyPage consent management card are activated together."
|
||||
"hint": "When enabled, the cookie banner and pre-consent auto-blocking are activated together. The MyPage consent management card is independent of this toggle and always shows for members with consent/withdrawal history."
|
||||
},
|
||||
"banner_position": {
|
||||
"label": "Banner Position",
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
},
|
||||
"banner_enabled": {
|
||||
"label": "쿠키 배너 노출",
|
||||
"hint": "활성 시 쿠키 배너 노출, 동의 전 외부 추적 자동 차단, 마이페이지 동의 관리 카드가 함께 시작됩니다."
|
||||
"hint": "활성 시 쿠키 배너 노출과 동의 전 외부 추적 자동 차단이 함께 시작됩니다. 마이페이지 동의 관리 카드는 이 토글과 무관하게 동의/철회 이력이 있는 회원에게 항상 노출됩니다."
|
||||
},
|
||||
"banner_position": {
|
||||
"label": "배너 위치",
|
||||
|
||||
@@ -286,7 +286,7 @@
|
||||
"type": "basic",
|
||||
"name": "Div",
|
||||
"props": {
|
||||
"className": "section-heading-md"
|
||||
"className": "grid-3col-responsive"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -350,7 +350,7 @@
|
||||
"type": "basic",
|
||||
"name": "Div",
|
||||
"props": {
|
||||
"className": "section-heading-md"
|
||||
"className": "grid-3col-responsive"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -549,7 +549,7 @@
|
||||
"name": "Div",
|
||||
"comment": "v1.4.0: banner_display_mode Select → banner_enabled Toggle",
|
||||
"props": {
|
||||
"className": "section-heading-md"
|
||||
"className": "grid-3col-responsive"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -600,7 +600,7 @@
|
||||
"type": "basic",
|
||||
"name": "Div",
|
||||
"props": {
|
||||
"className": "section-heading-md"
|
||||
"className": "grid-3col-responsive"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -1578,7 +1578,7 @@
|
||||
"type": "basic",
|
||||
"name": "Div",
|
||||
"if": "{{!_local.form?.banner_enabled}}",
|
||||
"comment": "쿠키 배너 노출 (banner_enabled) OFF 시 안내 박스. ON 으로 전환하면 배너 + 자동 차단 + 마이페이지 카드가 일괄 활성됨",
|
||||
"comment": "쿠키 배너 노출 (banner_enabled) OFF 시 안내 박스. ON 으로 전환하면 배너 + 자동 차단이 함께 활성됨 (마이페이지 카드는 이 토글과 무관, 항상 노출)",
|
||||
"props": {
|
||||
"className": "bg-blue-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 border-l-4 border-l-blue-500 dark:border-l-blue-400 rounded-lg p-4 flex-center gap-2"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user