[Document] Agent 요청 canonical field allowlist Resolver 구현 #62

Description

@hywznn

한 줄 목표

Agent가 문서 자동화에 필요한 field key를 요청하면 Server가 임의 SQL 없이 Worker·Company·Task의 허용된 업무값만 찾아 구조화해 반환합니다.

이번 결정

  • 실제 PII를 ***, OOO로 치환하거나 복원하지 않습니다.
  • 법적 실명·표시 이름·여권번호·외국인등록번호·전화번호·이메일·주소·계좌번호는 현재 Resolver에서 반환하지 않습니다.
  • Agent/LLM은 DB에 직접 접근하지 않고 canonical field key만 요청합니다.
  • Server가 tenant/company 범위와 고정 allowlist를 검증한 뒤 resolved, source, sensitivity, value를 구성합니다.
  • 값이 없는 허용 field는 MISSING, 인식된 PII field는 값 없이 FORBIDDEN, 알 수 없는 field는 요청 오류로 처리합니다.

MVP 허용 field

  • Worker: nationality_code, preferred_language, work_status, stay_expiry_date, contract_start_date, contract_end_date
  • Company: name
  • Task: task_type, workflow_id, workflow_catalog_version, due_date, status

구현 범위

  • canonical tag → 고정 Resolver key 매핑
  • Worker·Company·Task repository 기반 조회
  • task-worker-company 관계 검증
  • 해석 결과에 source, resolved, sensitivity, status 포함
  • 실제 값은 로그·해석 이력 테이블에 저장하지 않고 field key와 결과 상태만 저장
  • V9 migration으로 Agent field 해석 메타데이터 구조 추가
  • PII field 차단, 알 수 없는 field 거부, 타 사업장 접근 차단 테스트
  • AI 팀이 사용할 요청/응답 예시 문서화

실행 흐름

Server → Agent 문서 분석 요청(PII 없음)
Agent → requiredFieldKeys 반환
Server → allowlist Resolver 실행
Server → 허용된 resolved values만 Agent 문서 실행 요청에 포함

완료 조건

  • Agent가 요청한 허용 field가 현재 DB 값으로 해석됩니다.
  • 실제 PII는 응답·DB 메타데이터·일반 로그에 남지 않습니다.
  • Agent가 SQL·DB column명을 임의로 지정할 수 없습니다.
  • 같은 requestId+field key는 중복 이력으로 쌓이지 않습니다.
  • 전체 테스트와 Flyway validate가 통과합니다.

병합 순서와 관계

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:ai-integrationServer ↔ AI Runtime 내부 계약·Client·검증·trace 연동 영역; Prompt·모델·Provider 구현은 ai 저장소 소유area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업status:in-progress담당자가 현재 구현 중인 작업type:feature사용자 또는 Agent가 사용하는 기능 개발

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
    Skip to content

    [Document] Agent 요청 canonical field allowlist Resolver 구현 #62

    Description

    @hywznn

    한 줄 목표

    Agent가 문서 자동화에 필요한 field key를 요청하면 Server가 임의 SQL 없이 Worker·Company·Task의 허용된 업무값만 찾아 구조화해 반환합니다.

    이번 결정

    • 실제 PII를 ***, OOO로 치환하거나 복원하지 않습니다.
    • 법적 실명·표시 이름·여권번호·외국인등록번호·전화번호·이메일·주소·계좌번호는 현재 Resolver에서 반환하지 않습니다.
    • Agent/LLM은 DB에 직접 접근하지 않고 canonical field key만 요청합니다.
    • Server가 tenant/company 범위와 고정 allowlist를 검증한 뒤 resolved, source, sensitivity, value를 구성합니다.
    • 값이 없는 허용 field는 MISSING, 인식된 PII field는 값 없이 FORBIDDEN, 알 수 없는 field는 요청 오류로 처리합니다.

    MVP 허용 field

    • Worker: nationality_code, preferred_language, work_status, stay_expiry_date, contract_start_date, contract_end_date
    • Company: name
    • Task: task_type, workflow_id, workflow_catalog_version, due_date, status

    구현 범위

    • canonical tag → 고정 Resolver key 매핑
    • Worker·Company·Task repository 기반 조회
    • task-worker-company 관계 검증
    • 해석 결과에 source, resolved, sensitivity, status 포함
    • 실제 값은 로그·해석 이력 테이블에 저장하지 않고 field key와 결과 상태만 저장
    • V9 migration으로 Agent field 해석 메타데이터 구조 추가
    • PII field 차단, 알 수 없는 field 거부, 타 사업장 접근 차단 테스트
    • AI 팀이 사용할 요청/응답 예시 문서화

    실행 흐름

    Server → Agent 문서 분석 요청(PII 없음)
    Agent → requiredFieldKeys 반환
    Server → allowlist Resolver 실행
    Server → 허용된 resolved values만 Agent 문서 실행 요청에 포함
    

    완료 조건

    • Agent가 요청한 허용 field가 현재 DB 값으로 해석됩니다.
    • 실제 PII는 응답·DB 메타데이터·일반 로그에 남지 않습니다.
    • Agent가 SQL·DB column명을 임의로 지정할 수 없습니다.
    • 같은 requestId+field key는 중복 이력으로 쌓이지 않습니다.
    • 전체 테스트와 Flyway validate가 통과합니다.

    병합 순서와 관계

    Activity

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    Labels

    area:ai-integrationServer ↔ AI Runtime 내부 계약·Client·검증·trace 연동 영역; Prompt·모델·Provider 구현은 ai 저장소 소유area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업status:in-progress담당자가 현재 구현 중인 작업type:feature사용자 또는 Agent가 사용하는 기능 개발

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
      Skip to content

      [Document] Agent 요청 canonical field allowlist Resolver 구현 #62

      Description

      @hywznn

      한 줄 목표

      Agent가 문서 자동화에 필요한 field key를 요청하면 Server가 임의 SQL 없이 Worker·Company·Task의 허용된 업무값만 찾아 구조화해 반환합니다.

      이번 결정

      • 실제 PII를 ***, OOO로 치환하거나 복원하지 않습니다.
      • 법적 실명·표시 이름·여권번호·외국인등록번호·전화번호·이메일·주소·계좌번호는 현재 Resolver에서 반환하지 않습니다.
      • Agent/LLM은 DB에 직접 접근하지 않고 canonical field key만 요청합니다.
      • Server가 tenant/company 범위와 고정 allowlist를 검증한 뒤 resolved, source, sensitivity, value를 구성합니다.
      • 값이 없는 허용 field는 MISSING, 인식된 PII field는 값 없이 FORBIDDEN, 알 수 없는 field는 요청 오류로 처리합니다.

      MVP 허용 field

      • Worker: nationality_code, preferred_language, work_status, stay_expiry_date, contract_start_date, contract_end_date
      • Company: name
      • Task: task_type, workflow_id, workflow_catalog_version, due_date, status

      구현 범위

      • canonical tag → 고정 Resolver key 매핑
      • Worker·Company·Task repository 기반 조회
      • task-worker-company 관계 검증
      • 해석 결과에 source, resolved, sensitivity, status 포함
      • 실제 값은 로그·해석 이력 테이블에 저장하지 않고 field key와 결과 상태만 저장
      • V9 migration으로 Agent field 해석 메타데이터 구조 추가
      • PII field 차단, 알 수 없는 field 거부, 타 사업장 접근 차단 테스트
      • AI 팀이 사용할 요청/응답 예시 문서화

      실행 흐름

      Server → Agent 문서 분석 요청(PII 없음)
      Agent → requiredFieldKeys 반환
      Server → allowlist Resolver 실행
      Server → 허용된 resolved values만 Agent 문서 실행 요청에 포함
      

      완료 조건

      • Agent가 요청한 허용 field가 현재 DB 값으로 해석됩니다.
      • 실제 PII는 응답·DB 메타데이터·일반 로그에 남지 않습니다.
      • Agent가 SQL·DB column명을 임의로 지정할 수 없습니다.
      • 같은 requestId+field key는 중복 이력으로 쌓이지 않습니다.
      • 전체 테스트와 Flyway validate가 통과합니다.

      병합 순서와 관계

      Activity

      Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

      Metadata

      Metadata

      Assignees

      Labels

      area:ai-integrationServer ↔ AI Runtime 내부 계약·Client·검증·trace 연동 영역; Prompt·모델·Provider 구현은 ai 저장소 소유area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업status:in-progress담당자가 현재 구현 중인 작업type:feature사용자 또는 Agent가 사용하는 기능 개발

      Type

      No type

      Projects

      No projects

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions

        , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
        Skip to content

        [Document] Agent 요청 canonical field allowlist Resolver 구현 #62

        Description

        @hywznn

        한 줄 목표

        Agent가 문서 자동화에 필요한 field key를 요청하면 Server가 임의 SQL 없이 Worker·Company·Task의 허용된 업무값만 찾아 구조화해 반환합니다.

        이번 결정

        • 실제 PII를 ***, OOO로 치환하거나 복원하지 않습니다.
        • 법적 실명·표시 이름·여권번호·외국인등록번호·전화번호·이메일·주소·계좌번호는 현재 Resolver에서 반환하지 않습니다.
        • Agent/LLM은 DB에 직접 접근하지 않고 canonical field key만 요청합니다.
        • Server가 tenant/company 범위와 고정 allowlist를 검증한 뒤 resolved, source, sensitivity, value를 구성합니다.
        • 값이 없는 허용 field는 MISSING, 인식된 PII field는 값 없이 FORBIDDEN, 알 수 없는 field는 요청 오류로 처리합니다.

        MVP 허용 field

        • Worker: nationality_code, preferred_language, work_status, stay_expiry_date, contract_start_date, contract_end_date
        • Company: name
        • Task: task_type, workflow_id, workflow_catalog_version, due_date, status

        구현 범위

        • canonical tag → 고정 Resolver key 매핑
        • Worker·Company·Task repository 기반 조회
        • task-worker-company 관계 검증
        • 해석 결과에 source, resolved, sensitivity, status 포함
        • 실제 값은 로그·해석 이력 테이블에 저장하지 않고 field key와 결과 상태만 저장
        • V9 migration으로 Agent field 해석 메타데이터 구조 추가
        • PII field 차단, 알 수 없는 field 거부, 타 사업장 접근 차단 테스트
        • AI 팀이 사용할 요청/응답 예시 문서화

        실행 흐름

        Server → Agent 문서 분석 요청(PII 없음)
        Agent → requiredFieldKeys 반환
        Server → allowlist Resolver 실행
        Server → 허용된 resolved values만 Agent 문서 실행 요청에 포함
        

        완료 조건

        • Agent가 요청한 허용 field가 현재 DB 값으로 해석됩니다.
        • 실제 PII는 응답·DB 메타데이터·일반 로그에 남지 않습니다.
        • Agent가 SQL·DB column명을 임의로 지정할 수 없습니다.
        • 같은 requestId+field key는 중복 이력으로 쌓이지 않습니다.
        • 전체 테스트와 Flyway validate가 통과합니다.

        병합 순서와 관계

        Activity

        Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

        Metadata

        Metadata

        Assignees

        Labels

        area:ai-integrationServer ↔ AI Runtime 내부 계약·Client·검증·trace 연동 영역; Prompt·모델·Provider 구현은 ai 저장소 소유area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업status:in-progress담당자가 현재 구현 중인 작업type:feature사용자 또는 Agent가 사용하는 기능 개발

        Type

        No type

        Projects

        No projects

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
          Skip to content

          [Document] Agent 요청 canonical field allowlist Resolver 구현 #62

          Description

          @hywznn

          한 줄 목표

          Agent가 문서 자동화에 필요한 field key를 요청하면 Server가 임의 SQL 없이 Worker·Company·Task의 허용된 업무값만 찾아 구조화해 반환합니다.

          이번 결정

          • 실제 PII를 ***, OOO로 치환하거나 복원하지 않습니다.
          • 법적 실명·표시 이름·여권번호·외국인등록번호·전화번호·이메일·주소·계좌번호는 현재 Resolver에서 반환하지 않습니다.
          • Agent/LLM은 DB에 직접 접근하지 않고 canonical field key만 요청합니다.
          • Server가 tenant/company 범위와 고정 allowlist를 검증한 뒤 resolved, source, sensitivity, value를 구성합니다.
          • 값이 없는 허용 field는 MISSING, 인식된 PII field는 값 없이 FORBIDDEN, 알 수 없는 field는 요청 오류로 처리합니다.

          MVP 허용 field

          • Worker: nationality_code, preferred_language, work_status, stay_expiry_date, contract_start_date, contract_end_date
          • Company: name
          • Task: task_type, workflow_id, workflow_catalog_version, due_date, status

          구현 범위

          • canonical tag → 고정 Resolver key 매핑
          • Worker·Company·Task repository 기반 조회
          • task-worker-company 관계 검증
          • 해석 결과에 source, resolved, sensitivity, status 포함
          • 실제 값은 로그·해석 이력 테이블에 저장하지 않고 field key와 결과 상태만 저장
          • V9 migration으로 Agent field 해석 메타데이터 구조 추가
          • PII field 차단, 알 수 없는 field 거부, 타 사업장 접근 차단 테스트
          • AI 팀이 사용할 요청/응답 예시 문서화

          실행 흐름

          Server → Agent 문서 분석 요청(PII 없음)
          Agent → requiredFieldKeys 반환
          Server → allowlist Resolver 실행
          Server → 허용된 resolved values만 Agent 문서 실행 요청에 포함
          

          완료 조건

          • Agent가 요청한 허용 field가 현재 DB 값으로 해석됩니다.
          • 실제 PII는 응답·DB 메타데이터·일반 로그에 남지 않습니다.
          • Agent가 SQL·DB column명을 임의로 지정할 수 없습니다.
          • 같은 requestId+field key는 중복 이력으로 쌓이지 않습니다.
          • 전체 테스트와 Flyway validate가 통과합니다.

          병합 순서와 관계

          Activity

          Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

          Metadata

          Metadata

          Assignees

          Labels

          area:ai-integrationServer ↔ AI Runtime 내부 계약·Client·검증·trace 연동 영역; Prompt·모델·Provider 구현은 ai 저장소 소유area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업status:in-progress담당자가 현재 구현 중인 작업type:feature사용자 또는 Agent가 사용하는 기능 개발

          Type

          No type

          Projects

          No projects

            Relationships

            None yet

            Development

            No branches or pull requests

            Issue actions

            , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
            Skip to content

            [Document] Agent 요청 canonical field allowlist Resolver 구현 #62

            Description

            @hywznn

            한 줄 목표

            Agent가 문서 자동화에 필요한 field key를 요청하면 Server가 임의 SQL 없이 Worker·Company·Task의 허용된 업무값만 찾아 구조화해 반환합니다.

            이번 결정

            • 실제 PII를 ***, OOO로 치환하거나 복원하지 않습니다.
            • 법적 실명·표시 이름·여권번호·외국인등록번호·전화번호·이메일·주소·계좌번호는 현재 Resolver에서 반환하지 않습니다.
            • Agent/LLM은 DB에 직접 접근하지 않고 canonical field key만 요청합니다.
            • Server가 tenant/company 범위와 고정 allowlist를 검증한 뒤 resolved, source, sensitivity, value를 구성합니다.
            • 값이 없는 허용 field는 MISSING, 인식된 PII field는 값 없이 FORBIDDEN, 알 수 없는 field는 요청 오류로 처리합니다.

            MVP 허용 field

            • Worker: nationality_code, preferred_language, work_status, stay_expiry_date, contract_start_date, contract_end_date
            • Company: name
            • Task: task_type, workflow_id, workflow_catalog_version, due_date, status

            구현 범위

            • canonical tag → 고정 Resolver key 매핑
            • Worker·Company·Task repository 기반 조회
            • task-worker-company 관계 검증
            • 해석 결과에 source, resolved, sensitivity, status 포함
            • 실제 값은 로그·해석 이력 테이블에 저장하지 않고 field key와 결과 상태만 저장
            • V9 migration으로 Agent field 해석 메타데이터 구조 추가
            • PII field 차단, 알 수 없는 field 거부, 타 사업장 접근 차단 테스트
            • AI 팀이 사용할 요청/응답 예시 문서화

            실행 흐름

            Server → Agent 문서 분석 요청(PII 없음)
            Agent → requiredFieldKeys 반환
            Server → allowlist Resolver 실행
            Server → 허용된 resolved values만 Agent 문서 실행 요청에 포함
            

            완료 조건

            • Agent가 요청한 허용 field가 현재 DB 값으로 해석됩니다.
            • 실제 PII는 응답·DB 메타데이터·일반 로그에 남지 않습니다.
            • Agent가 SQL·DB column명을 임의로 지정할 수 없습니다.
            • 같은 requestId+field key는 중복 이력으로 쌓이지 않습니다.
            • 전체 테스트와 Flyway validate가 통과합니다.

            병합 순서와 관계

            Activity

            Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

            Metadata

            Metadata

            Assignees

            Labels

            area:ai-integrationServer ↔ AI Runtime 내부 계약·Client·검증·trace 연동 영역; Prompt·모델·Provider 구현은 ai 저장소 소유area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업status:in-progress담당자가 현재 구현 중인 작업type:feature사용자 또는 Agent가 사용하는 기능 개발

            Type

            No type

            Projects

            No projects

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
              Skip to content

              [Document] Agent 요청 canonical field allowlist Resolver 구현 #62

              Description

              @hywznn

              한 줄 목표

              Agent가 문서 자동화에 필요한 field key를 요청하면 Server가 임의 SQL 없이 Worker·Company·Task의 허용된 업무값만 찾아 구조화해 반환합니다.

              이번 결정

              • 실제 PII를 ***, OOO로 치환하거나 복원하지 않습니다.
              • 법적 실명·표시 이름·여권번호·외국인등록번호·전화번호·이메일·주소·계좌번호는 현재 Resolver에서 반환하지 않습니다.
              • Agent/LLM은 DB에 직접 접근하지 않고 canonical field key만 요청합니다.
              • Server가 tenant/company 범위와 고정 allowlist를 검증한 뒤 resolved, source, sensitivity, value를 구성합니다.
              • 값이 없는 허용 field는 MISSING, 인식된 PII field는 값 없이 FORBIDDEN, 알 수 없는 field는 요청 오류로 처리합니다.

              MVP 허용 field

              • Worker: nationality_code, preferred_language, work_status, stay_expiry_date, contract_start_date, contract_end_date
              • Company: name
              • Task: task_type, workflow_id, workflow_catalog_version, due_date, status

              구현 범위

              • canonical tag → 고정 Resolver key 매핑
              • Worker·Company·Task repository 기반 조회
              • task-worker-company 관계 검증
              • 해석 결과에 source, resolved, sensitivity, status 포함
              • 실제 값은 로그·해석 이력 테이블에 저장하지 않고 field key와 결과 상태만 저장
              • V9 migration으로 Agent field 해석 메타데이터 구조 추가
              • PII field 차단, 알 수 없는 field 거부, 타 사업장 접근 차단 테스트
              • AI 팀이 사용할 요청/응답 예시 문서화

              실행 흐름

              Server → Agent 문서 분석 요청(PII 없음)
              Agent → requiredFieldKeys 반환
              Server → allowlist Resolver 실행
              Server → 허용된 resolved values만 Agent 문서 실행 요청에 포함
              

              완료 조건

              • Agent가 요청한 허용 field가 현재 DB 값으로 해석됩니다.
              • 실제 PII는 응답·DB 메타데이터·일반 로그에 남지 않습니다.
              • Agent가 SQL·DB column명을 임의로 지정할 수 없습니다.
              • 같은 requestId+field key는 중복 이력으로 쌓이지 않습니다.
              • 전체 테스트와 Flyway validate가 통과합니다.

              병합 순서와 관계

              Activity

              Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

              Metadata

              Metadata

              Assignees

              Labels

              area:ai-integrationServer ↔ AI Runtime 내부 계약·Client·검증·trace 연동 영역; Prompt·모델·Provider 구현은 ai 저장소 소유area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업status:in-progress담당자가 현재 구현 중인 작업type:feature사용자 또는 Agent가 사용하는 기능 개발

              Type

              No type

              Projects

              No projects

                Relationships

                None yet

                Development

                No branches or pull requests

                Issue actions

                , 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
                Skip to content

                [Document] Agent 요청 canonical field allowlist Resolver 구현 #62

                Description

                @hywznn

                한 줄 목표

                Agent가 문서 자동화에 필요한 field key를 요청하면 Server가 임의 SQL 없이 Worker·Company·Task의 허용된 업무값만 찾아 구조화해 반환합니다.

                이번 결정

                • 실제 PII를 ***, OOO로 치환하거나 복원하지 않습니다.
                • 법적 실명·표시 이름·여권번호·외국인등록번호·전화번호·이메일·주소·계좌번호는 현재 Resolver에서 반환하지 않습니다.
                • Agent/LLM은 DB에 직접 접근하지 않고 canonical field key만 요청합니다.
                • Server가 tenant/company 범위와 고정 allowlist를 검증한 뒤 resolved, source, sensitivity, value를 구성합니다.
                • 값이 없는 허용 field는 MISSING, 인식된 PII field는 값 없이 FORBIDDEN, 알 수 없는 field는 요청 오류로 처리합니다.

                MVP 허용 field

                • Worker: nationality_code, preferred_language, work_status, stay_expiry_date, contract_start_date, contract_end_date
                • Company: name
                • Task: task_type, workflow_id, workflow_catalog_version, due_date, status

                구현 범위

                • canonical tag → 고정 Resolver key 매핑
                • Worker·Company·Task repository 기반 조회
                • task-worker-company 관계 검증
                • 해석 결과에 source, resolved, sensitivity, status 포함
                • 실제 값은 로그·해석 이력 테이블에 저장하지 않고 field key와 결과 상태만 저장
                • V9 migration으로 Agent field 해석 메타데이터 구조 추가
                • PII field 차단, 알 수 없는 field 거부, 타 사업장 접근 차단 테스트
                • AI 팀이 사용할 요청/응답 예시 문서화

                실행 흐름

                Server → Agent 문서 분석 요청(PII 없음)
                Agent → requiredFieldKeys 반환
                Server → allowlist Resolver 실행
                Server → 허용된 resolved values만 Agent 문서 실행 요청에 포함
                

                완료 조건

                • Agent가 요청한 허용 field가 현재 DB 값으로 해석됩니다.
                • 실제 PII는 응답·DB 메타데이터·일반 로그에 남지 않습니다.
                • Agent가 SQL·DB column명을 임의로 지정할 수 없습니다.
                • 같은 requestId+field key는 중복 이력으로 쌓이지 않습니다.
                • 전체 테스트와 Flyway validate가 통과합니다.

                병합 순서와 관계

                Activity

                Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

                Metadata

                Metadata

                Assignees

                Labels

                area:ai-integrationServer ↔ AI Runtime 내부 계약·Client·검증·trace 연동 영역; Prompt·모델·Provider 구현은 ai 저장소 소유area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업status:in-progress담당자가 현재 구현 중인 작업type:feature사용자 또는 Agent가 사용하는 기능 개발

                Type

                No type

                Projects

                No projects

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions