<?php
// 권한 분석 — 선택한 메뉴/액션 기준으로 효과권한(EFFECTIVE) 분석
$CURRENT_SECTION = 'permission';
include '../inc/header.php';
?>
    <div class="container" style="max-width:1280px; margin-top:24px;">
        <div class="card shadow-sm">
            <div class="card-header d-flex flex-wrap gap-2 align-items-center">
                <strong>권한 분석</strong>
                <select class="form-select form-select-sm" id="actionSelect" style="width:160px;">
                    <option value="read">읽기(read)</option>
                    <option value="create">쓰기(create)</option>
                    <option value="update">수정(update)</option>
                    <option value="delete">삭제(delete)</option>
                    <option value="approve">결재(approve)</option>
                </select>
                <input class="form-control form-control-sm" id="keyword" placeholder="사용자/부서/역할 검색" style="width:260px;">
                <button class="btn btn-sm btn-outline-secondary" id="btnRecalc">권한 재계산</button>
                <div class="ms-auto d-flex gap-2">
                    <button class="btn btn-sm btn-outline-success" id="btnExport">CSV 내보내기</button>
                </div>
            </div>

            <div class="card-body">
                <div class="row g-3">
                    <!-- 좌: 메뉴 트리 -->
                    <div class="col-md-5">
                        <div class="border rounded p-2">
                            <div class="d-flex align-items-center justify-content-between mb-2">
                                <div class="small text-muted">분석 메뉴</div>
                                <div class="input-group input-group-sm" style="max-width:280px;">
                                    <input type="text" class="form-control" id="menuSearch" placeholder="메뉴/코드 검색">
                                    <button class="btn btn-outline-secondary" id="btnMenuSearch">검색</button>
                                    <button class="btn btn-outline-secondary" id="btnMenuReset">초기화</button>
                                </div>
                                <!-- (기존) 메뉴 검색 input-group 바로 뒤에 추가 -->
                                <div class="form-check form-check-sm ms-2">
                                    <input class="form-check-input" type="checkbox" id="highlightAllowed">
                                    <label class="form-check-label small" for="highlightAllowed">접근가능</label>
                                </div>
                            </div>
                            <div class="table-responsive" style="max-height:64vh; overflow:auto;">
                                <table class="table table-sm align-middle" id="menuTable">
                                    <thead class="table-light">
                                    <tr>
                                        <th style="width:60%;">메뉴</th>
                                        <th>코드</th>
                                    </tr>
                                    </thead>
                                    <tbody><!-- PermissionMenu로 렌더 --></tbody>
                                </table>
                            </div>
                        </div>
                    </div>

                    <!-- 우: 분석 결과 -->
                    <div class="col-md-7">
                        <div class="border rounded p-2">
                            <div class="d-flex align-items-center justify-content-between mb-2">
                                <div>
                                    <div class="small text-muted">선택 메뉴</div>
                                    <div id="selMenuTitle" class="fw-semibold">-</div>
                                </div>
                                <div class="small text-muted">
                                    결론 규칙: <code>ALLOW = 부서 OR 역할 OR (개인 ALLOW)</code> → <code>개인 DENY 최우선</code>
                                </div>
                            </div>

                            <ul class="nav nav-pills mb-2" role="tablist">
                                <li class="nav-item"><button class="nav-link active" data-bs-toggle="tab" data-bs-target="#tabAllow">접근 가능</button></li>
                                <li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tabDeny">접근 불가</button></li>
                                <li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tabWhy">근거/상세</button></li>
                                <!-- 탭 버튼들 (기존 3개 뒤에 추가) -->
                                <li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tabUser">사용자 역추적</button></li>
                            </ul>
                            <div class="tab-content">
                                <!-- 접근 가능 -->
                                <div class="tab-pane fade show active" id="tabAllow">
                                    <div class="table-responsive" style="max-height:28vh; overflow:auto;">
                                        <table class="table table-sm align-middle" id="tblAllow">
                                            <thead class="table-light">
                                            <tr><th style="width:30%;">사용자</th><th>부서</th><th>역할</th><th>개인모드</th><th>최종</th></tr>
                                            </thead>
                                            <tbody></tbody>
                                        </table>
                                    </div>
                                </div>
                                <!-- 접근 불가 -->
                                <div class="tab-pane fade" id="tabDeny">
                                    <div class="table-responsive" style="max-height:28vh; overflow:auto;">
                                        <table class="table table-sm align-middle" id="tblDeny">
                                            <thead class="table-light">
                                            <tr><th style="width:30%;">사용자</th><th>부서</th><th>역할</th><th>개인모드</th><th>사유</th></tr>
                                            </thead>
                                            <tbody></tbody>
                                        </table>
                                    </div>
                                </div>
                                <!-- 근거/상세 -->
                                <div class="tab-pane fade" id="tabWhy">
                                    <div class="table-responsive" style="max-height:28vh; overflow:auto;">
                                        <table class="table table-sm align-middle" id="tblWhy">
                                            <thead class="table-light">
                                            <tr><th style="width:24%;">사용자</th><th>부서 허용</th><th>역할 허용</th><th>개인 허용</th><th>개인 DENY</th><th>최종</th></tr>
                                            </thead>
                                            <tbody></tbody>
                                        </table>
                                    </div>
                                    <div class="small text-muted">* “개인 DENY”가 하나라도 있으면 최종 DENY (최우선)</div>
                                </div>
                                <!-- 탭 콘텐츠 (아래 블록을 기존 tab-content 맨 아래에 추가) -->
                                <div class="tab-pane fade" id="tabUser">
                                    <div class="d-flex flex-wrap gap-2 align-items-center mb-2">
                                        <select class="form-select form-select-sm" id="userTraceSelect" style="width:260px;">
                                            <!-- 샘플: USERS 배열과 동일하게 -->
                                            <option value="101">권혁성(kevin)</option>
                                            <option value="102">김슬기(sally)</option>
                                            <option value="103">이민수(minsu)</option>
                                        </select>
                                        <select class="form-select form-select-sm" id="userTraceAction" style="width:160px;">
                                            <option value="read">읽기(read)</option>
                                            <option value="create">쓰기(create)</option>
                                            <option value="update">수정(update)</option>
                                            <option value="delete">삭제(delete)</option>
                                            <option value="approve">결재(approve)</option>
                                        </select>
                                        <div class="form-check ms-2">
                                            <input class="form-check-input" type="checkbox" id="onlyAllow">
                                            <label class="form-check-label" for="onlyAllow">ALLOW만 보기</label>
                                        </div>
                                        <div class="ms-auto d-flex gap-2">
                                            <button class="btn btn-sm btn-outline-secondary" id="btnTraceExport">CSV</button>
                                        </div>
                                    </div>

                                    <div class="table-responsive" style="max-height:50vh; overflow:auto;">
                                        <table class="table table-sm align-middle" id="tblUserTrace">
                                            <thead class="table-light">
                                            <tr>
                                                <th style="width:40%;">메뉴</th>
                                                <th>코드</th>
                                                <th class="text-center">최종</th>
                                                <th class="text-center">부서</th>
                                                <th class="text-center">역할</th>
                                                <th class="text-center">개인 ALLOW</th>
                                                <th class="text-center">개인 DENY</th>
                                            </tr>
                                            </thead>
                                            <tbody></tbody>
                                        </table>
                                    </div>
                                </div>
                            </div>

                        </div>
                    </div>
                </div> <!-- row -->
            </div>
        </div>
    </div>

    <style>
        .menu-name { font-size:14px; font-weight:500; }
        .menu-url  { color:#6c757d; font-size:12px;}
        .indent    { font-family: ui-monospace, Menlo, Consolas, monospace; color:#6c757d; }
        #menuTable tbody tr.active { background: #eef3ff; }
        .badge-inherit{ background:#6c757d; }
        .badge-allow{ background:#0d6efd; }
        .badge-deny{ background:#dc3545; }
        /* ALLOW 행은 왼쪽 라인 + 은은한 배경, DENY는 살짝 흐리게 */
        #menuTable tbody tr.allow-row {
            background: #f3f8ff;
            border-left: 4px solid #0d6efd;
        }
        #menuTable tbody tr.deny-dim {
            opacity: .45;
        }
    </style>

    <script src="/tenant/assets/js/permission_menu.js"></script>
    <script>
        // ================== 샘플 데이터 (실전: AJAX로 교체) ==================
        const MENU_DATA = [
            {id:1,parent_id:null,title:'대시보드',code:'dashboard',path:'/tenant/member/dashboard.php',source:'system'},
            {id:2,parent_id:null,title:'수주',code:'order',path:null,source:'system'},
            {id:21,parent_id:2,title:'수주 관리',code:'order.manage',path:'/tenant/order/manage.php',source:'system'},
            {id:22,parent_id:2,title:'수주 등록/수정',code:'order.edit',path:'/tenant/order/edit.php',source:'system'},
            {id:3,parent_id:null,title:'생산',code:'production',path:null,source:'system'},
            {id:31,parent_id:3,title:'작업 지시',code:'production.wi',path:'/tenant/production/work_instruction.php',source:'workflow'},
            {id:32,parent_id:3,title:'스크린 작업',code:'production.screen',path:'/tenant/production/screen_work.php',source:'workflow'},
            {id:5,parent_id:null,title:'게시판',code:'board',path:null,source:'system'},
            {id:51,parent_id:5,title:'공지사항',code:'board.notice',path:'/tenant/board/notice_list.php',source:'board'},
        ];
        const TENANT_USE = {dashboard:true, order:true,'order.manage':true,'order.edit':false,
            production:true,'production.wi':true,'production.screen':true,
            board:true,'board.notice':true};

        // 조직/역할/유저 샘플
        const DEPARTMENTS = [{id:201,name:'개발팀'},{id:202,name:'영업팀'}];
        const ROLES = [{id:301,name:'최고관리자'},{id:302,name:'일반관리자'},{id:303,name:'직원'}];
        const USERS = [
            {id:101, name:'권혁성', uid:'kevin',  dept_id:201, role_ids:[301,302]},
            {id:102, name:'김슬기', uid:'sally',  dept_id:201, role_ids:[303]},
            {id:103, name:'이민수', uid:'minsu',  dept_id:202, role_ids:[303]},
        ];

        // 부서/역할 권한 정의(샘플) — 실제는 DB에서 로드
        const DEPT_PERMS = {
            // dept_id: { code: {read,create,update,delete,approve} }
            201: { 'order.manage': {read:true,create:true,update:true,delete:false,approve:false},
                'production.wi':{read:true,create:true,update:false,delete:false,approve:false},
                'dashboard':    {read:true,create:false,update:false,delete:false,approve:false},
                'board.notice': {read:true,create:false,update:false,delete:false,approve:false} },
            202: { 'order.manage': {read:true,create:false,update:false,delete:false,approve:false},
                'dashboard':    {read:true,create:false,update:false,delete:false,approve:false} }
        };
        const ROLE_PERMS = {
            // role_id: { code: {...} }
            301: { 'order.manage':{read:true,create:true,update:true,delete:true,approve:true},
                'production':  {read:true,create:false,update:false,delete:false,approve:false} },
            302: { 'production.wi':{read:true,create:true,update:true,delete:false,approve:false} },
            303: { 'board.notice':{read:true,create:true,update:true,delete:false,approve:false} }
        };

        // 개인 예외(샘플)
        // 모드: 사용자별 전역 모드 (INHERIT/ALLOW/DENY)
        const USER_MODE = { 101:'ALLOW', 102:'INHERIT', 103:'DENY' };
        // 개인 허용(ALLOW 모드일 때만 의미) — user_id: { code: {...} }
        const USER_PERMS = {
            101: { 'production.screen': {read:true,create:true,update:false,delete:false,approve:false} }
        };
        // 개인 DENY(선택사항: 메뉴별 차단) — user_id: Set(menu_code)
        const USER_DENY = {
            102: new Set(['order.manage']) // 예: 상속으로 되더라도 이 메뉴만 차단
        };

        // ================== 공통 트리 세팅 + 좌측 메뉴 렌더 ==================
        PermissionMenu.setData(MENU_DATA, TENANT_USE);

        function renderMenuList(){
            const rows = PermissionMenu.buildRows((node)=>{
                return `<td class="text-muted">${node.code}</td>`;
            });
            document.querySelector('#menuTable tbody').innerHTML = rows;
        }
        renderMenuList();

        let selectedMenuCode = null;
        function selectFirstMenuIfNeeded(){
            if (!selectedMenuCode){
                const first = document.querySelector('#menuTable tbody tr');
                if (first){ first.classList.add('active'); selectedMenuCode = first.dataset.code; updateSelectedInfo(); runAnalyze(); }
            }
        }
        function updateSelectedInfo(){
            const tr = document.querySelector('#menuTable tbody tr.active');
            const title = tr ? tr.querySelector('td:first-child').innerText.trim() : '-';
            document.querySelector('#selMenuTitle').innerText = title;
        }

        // 메뉴 선택
        document.querySelector('#menuTable').addEventListener('click', (e)=>{
            const tr = e.target.closest('tr'); if(!tr) return;
            document.querySelectorAll('#menuTable tbody tr').forEach(x=> x.classList.remove('active'));
            tr.classList.add('active');
            selectedMenuCode = tr.dataset.code;
            updateSelectedInfo();
            runAnalyze();
        });

        // 메뉴 검색
        document.querySelector('#btnMenuSearch').addEventListener('click', ()=>{
            const q = document.querySelector('#menuSearch').value.trim().toLowerCase();
            document.querySelectorAll('#menuTable tbody tr').forEach(tr=>{
                const name = tr.querySelector('td:first-child').innerText.toLowerCase();
                const code = tr.dataset.code.toLowerCase();
                tr.style.display = (q==='' || name.includes(q) || code.includes(q)) ? '' : 'none';
            });
        });
        document.querySelector('#btnMenuReset').addEventListener('click', ()=>{
            document.querySelector('#menuSearch').value=''; document.querySelectorAll('#menuTable tbody tr').forEach(tr=> tr.style.display='');
        });

        // ================== 분석 로직 ==================
        function hasDeptAllow(userId, code, action){
            const user = USERS.find(u=>u.id==userId); if(!user) return false;
            const map = DEPT_PERMS[user.dept_id]||{};
            return !!(map[code] && map[code][action]);
        }
        function hasRoleAllow(userId, code, action){
            const user = USERS.find(u=>u.id==userId); if(!user) return false;
            return user.role_ids.some(rid => !!(ROLE_PERMS[rid] && ROLE_PERMS[rid][code] && ROLE_PERMS[rid][code][action]));
        }
        function hasUserAllow(userId, code, action){
            const mode = USER_MODE[userId] || 'INHERIT';
            if (mode!=='ALLOW') return false;
            const up = USER_PERMS[userId]||{};
            return !!(up[code] && up[code][action]);
        }
        function hasUserDeny(userId, code){
            // 전역 DENY 우선
            if ((USER_MODE[userId]||'INHERIT')==='DENY') return true;
            // 메뉴별 DENY
            return !!(USER_DENY[userId] && USER_DENY[userId].has(code));
        }
        function effective(userId, code, action){
            // 개인 DENY 최우선
            if (hasUserDeny(userId, code)) return {allow:false, reason:'개인 DENY'};
            const allow = hasDeptAllow(userId, code, action) || hasRoleAllow(userId, code, action) || hasUserAllow(userId, code, action);
            return {allow, reason: allow?'ALLOW':'NO MATCH'};
        }

        function runAnalyze(){
            if (!selectedMenuCode){ selectFirstMenuIfNeeded(); return; }
            const action = document.querySelector('#actionSelect').value;
            const kw = document.querySelector('#keyword').value.trim().toLowerCase();

            const rowsAllow=[], rowsDeny=[], rowsWhy=[];
            USERS.forEach(u=>{
                const name = `${u.name}(${u.uid})`;
                if (kw && !name.toLowerCase().includes(kw)) return;

                const dept = (DEPARTMENTS.find(d=>d.id===u.dept_id)||{}).name || '-';
                const roleNames = u.role_ids.map(id => (ROLES.find(r=>r.id===id)||{}).name).filter(Boolean).join(', ') || '-';
                const mode = USER_MODE[u.id] || 'INHERIT';

                const deptOk = hasDeptAllow(u.id, selectedMenuCode, action);
                const roleOk = hasRoleAllow(u.id, selectedMenuCode, action);
                const userOk = hasUserAllow(u.id, selectedMenuCode, action);
                const uDeny  = hasUserDeny(u.id, selectedMenuCode);

                const eff = effective(u.id, selectedMenuCode, action);

                const modeBadge = mode==='INHERIT' ? '<span class="badge badge-inherit">INHERIT</span>' :
                    mode==='ALLOW'   ? '<span class="badge badge-allow">ALLOW</span>' :
                        '<span class="badge badge-deny">DENY</span>';

                const finalBadge = eff.allow ? '<span class="badge bg-primary">ALLOW</span>' :
                    '<span class="badge bg-danger">DENY</span>';

                // WHY 표
                rowsWhy.push(`<tr>
      <td>${name}</td>
      <td>${deptOk?'Y':''}</td>
      <td>${roleOk?'Y':''}</td>
      <td>${userOk?'Y':''}</td>
      <td>${uDeny?'Y':''}</td>
      <td>${eff.allow? 'ALLOW':'DENY'}</td>
    </tr>`);

                if (eff.allow){
                    rowsAllow.push(`<tr>
        <td>${name}</td><td>${dept}</td><td>${roleNames}</td><td>${modeBadge}</td><td>${finalBadge}</td>
      </tr>`);
                } else {
                    const reason = uDeny ? '개인 DENY' : '권한 없음';
                    rowsDeny.push(`<tr>
        <td>${name}</td><td>${dept}</td><td>${roleNames}</td><td>${modeBadge}</td><td>${reason}</td>
      </tr>`);
                }
            });

            document.querySelector('#tblAllow tbody').innerHTML = rowsAllow.join('') || `<tr><td colspan="5" class="text-center text-muted">해당 없음</td></tr>`;
            document.querySelector('#tblDeny  tbody').innerHTML = rowsDeny.join('')  || `<tr><td colspan="5" class="text-center text-muted">해당 없음</td></tr>`;
            document.querySelector('#tblWhy   tbody').innerHTML = rowsWhy.join('')   || `<tr><td colspan="6" class="text-center text-muted">해당 없음</td></tr>`;
        }

        // 액션/검색/재계산
        document.querySelector('#actionSelect').addEventListener('change', runAnalyze);
        document.querySelector('#keyword').addEventListener('keyup', (e)=>{ if(e.key==='Enter') runAnalyze(); });
        document.querySelector('#btnRecalc').addEventListener('click', runAnalyze);

        // CSV 내보내기(접근 가능 탭 기준 + WHY 탭 함께)
        document.querySelector('#btnExport').addEventListener('click', ()=>{
            const rows = [['tab','user','dept','roles','mode','final','dept_allow','role_allow','user_allow','user_deny']];
            USERS.forEach(u=>{
                const dept = (DEPARTMENTS.find(d=>d.id===u.dept_id)||{}).name || '-';
                const roleNames = u.role_ids.map(id => (ROLES.find(r=>r.id===id)||{}).name).filter(Boolean).join('|') || '-';
                const mode = USER_MODE[u.id] || 'INHERIT';
                const a = document.querySelector('#actionSelect').value;
                const code = selectedMenuCode || '';
                const deptOk = hasDeptAllow(u.id, code, a);
                const roleOk = hasRoleAllow(u.id, code, a);
                const userOk = hasUserAllow(u.id, code, a);
                const uDeny  = hasUserDeny(u.id, code);
                const eff = effective(u.id, code, a);
                rows.push(['result', `${u.name}(${u.uid})`, dept, roleNames, mode, eff.allow?'ALLOW':'DENY', deptOk?'Y':'', roleOk?'Y':'', userOk?'Y':'', uDeny?'Y':'']);
            });
            const csv = rows.map(r=> r.map(x=> `"${String(x).replace(/"/g,'""')}"`).join(',')).join('\n');
            const blob = new Blob([csv], {type:'text/csv;charset=utf-8;'});
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a'); a.href = url; a.download = 'permission_analysis.csv'; a.click();
            URL.revokeObjectURL(url);
        });

        // 최초 선택/분석
        selectFirstMenuIfNeeded();

        // ---------- 사용자 역추적 ----------
        function traceEffectiveForUser(userId, code, action){
            // anlyze 탭에서 쓰던 로직 재사용
            const deptOk = hasDeptAllow(userId, code, action);
            const roleOk = hasRoleAllow(userId, code, action);
            const userOk = hasUserAllow(userId, code, action);
            const uDeny  = hasUserDeny(userId, code);
            const allow  = !uDeny && (deptOk || roleOk || userOk);
            return {allow, deptOk, roleOk, userOk, uDeny};
        }

        function renderUserTrace(){
            const userId = parseInt(document.getElementById('userTraceSelect').value,10);
            const action = document.getElementById('userTraceAction').value;
            const onlyAllow = document.getElementById('onlyAllow').checked;

            const rows = [];
            // PermissionMenu.activeCodes() 순회해서 메뉴별 결과 뽑기
            const { maps } = PermissionMenu;
            const codes = PermissionMenu.activeCodes();
            const { byCode } = maps();

            codes.forEach(code=>{
                const node = byCode[code];
                if (!node) return;
                const r = traceEffectiveForUser(userId, code, action);
                if (onlyAllow && !r.allow) return;

                const finalBadge = r.allow ? '<span class="badge bg-primary">ALLOW</span>'
                    : '<span class="badge bg-danger">DENY</span>';
                rows.push(`
      <tr>
        <td><span class="menu-name">${node.title}</span>
            ${node.source==='workflow' ? '<span class="badge bg-warning text-dark ms-1">workflow</span>':''}
            ${node.source==='board' ? '<span class="badge bg-success ms-1">board</span>':''}
            ${node.path? `<span class="menu-url ms-2 text-muted">${node.path}</span>`:''}
        </td>
        <td class="text-muted">${node.code}</td>
        <td class="text-center">${finalBadge}</td>
        <td class="text-center">${r.deptOk?'Y':''}</td>
        <td class="text-center">${r.roleOk?'Y':''}</td>
        <td class="text-center">${r.userOk?'Y':''}</td>
        <td class="text-center">${r.uDeny?'Y':''}</td>
      </tr>
    `);
            });

            const tbody = document.querySelector('#tblUserTrace tbody');
            tbody.innerHTML = rows.join('') || `<tr><td colspan="7" class="text-center text-muted">해당 없음</td></tr>`;
        }

        // 이벤트 바인딩
        ['userTraceSelect','userTraceAction','onlyAllow'].forEach(id=>{
            const el = document.getElementById(id);
            if (el) el.addEventListener('change', renderUserTrace);
        });

        // CSV 내보내기
        document.getElementById('btnTraceExport').addEventListener('click', ()=>{
            const userId = parseInt(document.getElementById('userTraceSelect').value,10);
            const action = document.getElementById('userTraceAction').value;

            const user = USERS.find(u=>u.id===userId);
            const rows = [['menu','code','final','dept','role','user_allow','user_deny','action',`user:${user?.name||''}(${user?.uid||''})`]];

            const { maps } = PermissionMenu; const { byCode } = maps();
            PermissionMenu.activeCodes().forEach(code=>{
                const node = byCode[code]; if (!node) return;
                const r = traceEffectiveForUser(userId, code, action);
                rows.push([
                    node.title, code, r.allow?'ALLOW':'DENY',
                    r.deptOk?'Y':'', r.roleOk?'Y':'', r.userOk?'Y':'', r.uDeny?'Y':'', action
                ]);
            });

            const csv = rows.map(r=> r.map(x=>`"${String(x).replace(/"/g,'""')}"`).join(',')).join('\n');
            const blob = new Blob([csv], {type:'text/csv;charset=utf-8;'});
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a'); a.href = url; a.download = 'user_trace.csv'; a.click();
            URL.revokeObjectURL(url);
        });

        // 처음 들어오면 한 번 렌더
        renderUserTrace();


        // 좌측 트리에 허용 하이라이트 적용
        function updateMenuHighlight() {
            const chk = document.getElementById('highlightAllowed');
            const userSel = document.getElementById('userTraceSelect');
            const actSel  = document.getElementById('userTraceAction');
            if (!chk || !userSel || !actSel) return;

            const on = chk.checked;
            const userId = parseInt(userSel.value, 10);
            const action = actSel.value;

            document.querySelectorAll('#menuTable tbody tr').forEach(tr=>{
                tr.classList.remove('allow-row','deny-dim');
                if (!on) return; // 꺼져 있으면 리셋만

                const code = tr.dataset.code;
                // analyze 탭에서 쓰던 판단식 재사용
                const r = effective(userId, code, action); // {allow:boolean}
                if (r.allow) tr.classList.add('allow-row');
                else tr.classList.add('deny-dim');
            });
        }

        // 탭/선택 변경 시 갱신
        ['highlightAllowed','userTraceSelect','userTraceAction'].forEach(id=>{
            const el = document.getElementById(id);
            if (el) el.addEventListener('change', updateMenuHighlight);
        });

        // 최초 렌더/재렌더 후에도 호출
        document.addEventListener('DOMContentLoaded', updateMenuHighlight);

        // 좌측 메뉴 다시 그릴 때도 호출 (이미 있는 렌더 뒤쪽에 한 줄만 추가)
        const _origRenderMenuList = renderMenuList;
        renderMenuList = function() {
            _origRenderMenuList();
            updateMenuHighlight();
        };

        // 사용자 역추적 테이블 재계산 후에도 한 번 더 (이미 만든 함수 끝에 한 줄 추가)
        const _origRenderUserTrace = renderUserTrace;
        renderUserTrace = function() {
            _origRenderUserTrace();
            updateMenuHighlight();
        };
    </script>

<?php include '../inc/footer.php'; ?>
