[Document][P0] 문서 상세 조회·상태 표현·HWP/HWPX 업로드 보완 #80

Description

@chaeliki

배경

fowoco/client PR #174, #228에서 fowoco/server의 통합 문서함 API(#13)를
실제 화면에 연동하며 발견된 문제들을 정리합니다.

1. GET /documents 응답에 version 필드 누락

PATCH /workers/{workerId}/documents/{documentId}는 expected_version이
필수인데, GET /documents 응답(DocumentItemResponse)에 이 값이 없어
DocumentDetailPage의 확인/반려 버튼이 실제 연동이 안 되고 있습니다.
WorkerDocument 도메인엔 이미 version이 있어 응답 DTO
노출만 하면 해결됩니다.

2. 단건 조회 API 부재

GET /documents/{documentId}가 없어서, 프론트가 전체 목록을 받아
worker_document_id로 직접 찾는 방식으로 우회하고 있습니다.

3. HWP/HWPX 업로드 지원 추가

POST /files가 image/jpeg·png·webp, application/pdf만 허용합니다.
HWP/HWPX 업로드가 실제로 필요하므로 지원을 추가합니다.

참고

완료 조건

  • DocumentItemResponse에 version 필드 추가
  • GET /documents/{documentId} 단건 조회 API 신설
  • HWP/HWPX MIME 타입을 ALLOWED_MIME_TYPES에 추가

2026-08-04 · PWF3 문서함 보완 원칙

단건 응답은 화면이 목록 전체를 다시 받지 않아도 검토·반려를 수행할 수 있도록 다음 값을 함께 반환합니다.

  • version: 수정 충돌을 막는 expectedVersion의 기준값
  • Worker·Task 참조와 문서 유형
  • 제출 상태와 만료일
  • 연결된 파일의 ID·표시 파일명·MIME·크기·검사 상태

서로 다른 상태를 하나의 status에 섞지 않습니다.

상태소유 모델
파일 검사 상태StoredFile.scanStatus
근로자 서류 제출 상태WorkerDocument — enum·DB 제약 변경은 #60 소유
유효·만료 판단서류 만료일을 기준으로 Server가 계산
업무 준비도기존 GET /tasks/{taskId}/document-readiness가 계산

HWP/HWPX 허용 시 확장자만 믿지 않고 MIME·크기·파일 시그니처 정책과 다운로드 권한을 함께 검증합니다.

Activity

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

Metadata

Metadata

Assignees

Labels

area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업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][P0] 문서 상세 조회·상태 표현·HWP/HWPX 업로드 보완 #80

    Description

    @chaeliki

    배경

    fowoco/client PR #174, #228에서 fowoco/server의 통합 문서함 API(#13)를
    실제 화면에 연동하며 발견된 문제들을 정리합니다.

    1. GET /documents 응답에 version 필드 누락

    PATCH /workers/{workerId}/documents/{documentId}는 expected_version이
    필수인데, GET /documents 응답(DocumentItemResponse)에 이 값이 없어
    DocumentDetailPage의 확인/반려 버튼이 실제 연동이 안 되고 있습니다.
    WorkerDocument 도메인엔 이미 version이 있어 응답 DTO
    노출만 하면 해결됩니다.

    2. 단건 조회 API 부재

    GET /documents/{documentId}가 없어서, 프론트가 전체 목록을 받아
    worker_document_id로 직접 찾는 방식으로 우회하고 있습니다.

    3. HWP/HWPX 업로드 지원 추가

    POST /files가 image/jpeg·png·webp, application/pdf만 허용합니다.
    HWP/HWPX 업로드가 실제로 필요하므로 지원을 추가합니다.

    참고

    완료 조건

    • DocumentItemResponse에 version 필드 추가
    • GET /documents/{documentId} 단건 조회 API 신설
    • HWP/HWPX MIME 타입을 ALLOWED_MIME_TYPES에 추가

    2026-08-04 · PWF3 문서함 보완 원칙

    단건 응답은 화면이 목록 전체를 다시 받지 않아도 검토·반려를 수행할 수 있도록 다음 값을 함께 반환합니다.

    • version: 수정 충돌을 막는 expectedVersion의 기준값
    • Worker·Task 참조와 문서 유형
    • 제출 상태와 만료일
    • 연결된 파일의 ID·표시 파일명·MIME·크기·검사 상태

    서로 다른 상태를 하나의 status에 섞지 않습니다.

    상태소유 모델
    파일 검사 상태StoredFile.scanStatus
    근로자 서류 제출 상태WorkerDocument — enum·DB 제약 변경은 #60 소유
    유효·만료 판단서류 만료일을 기준으로 Server가 계산
    업무 준비도기존 GET /tasks/{taskId}/document-readiness가 계산

    HWP/HWPX 허용 시 확장자만 믿지 않고 MIME·크기·파일 시그니처 정책과 다운로드 권한을 함께 검증합니다.

    Activity

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

    Metadata

    Metadata

    Assignees

    Labels

    area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업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][P0] 문서 상세 조회·상태 표현·HWP/HWPX 업로드 보완 #80

      Description

      @chaeliki

      배경

      fowoco/client PR #174, #228에서 fowoco/server의 통합 문서함 API(#13)를
      실제 화면에 연동하며 발견된 문제들을 정리합니다.

      1. GET /documents 응답에 version 필드 누락

      PATCH /workers/{workerId}/documents/{documentId}는 expected_version이
      필수인데, GET /documents 응답(DocumentItemResponse)에 이 값이 없어
      DocumentDetailPage의 확인/반려 버튼이 실제 연동이 안 되고 있습니다.
      WorkerDocument 도메인엔 이미 version이 있어 응답 DTO
      노출만 하면 해결됩니다.

      2. 단건 조회 API 부재

      GET /documents/{documentId}가 없어서, 프론트가 전체 목록을 받아
      worker_document_id로 직접 찾는 방식으로 우회하고 있습니다.

      3. HWP/HWPX 업로드 지원 추가

      POST /files가 image/jpeg·png·webp, application/pdf만 허용합니다.
      HWP/HWPX 업로드가 실제로 필요하므로 지원을 추가합니다.

      참고

      완료 조건

      • DocumentItemResponse에 version 필드 추가
      • GET /documents/{documentId} 단건 조회 API 신설
      • HWP/HWPX MIME 타입을 ALLOWED_MIME_TYPES에 추가

      2026-08-04 · PWF3 문서함 보완 원칙

      단건 응답은 화면이 목록 전체를 다시 받지 않아도 검토·반려를 수행할 수 있도록 다음 값을 함께 반환합니다.

      • version: 수정 충돌을 막는 expectedVersion의 기준값
      • Worker·Task 참조와 문서 유형
      • 제출 상태와 만료일
      • 연결된 파일의 ID·표시 파일명·MIME·크기·검사 상태

      서로 다른 상태를 하나의 status에 섞지 않습니다.

      상태소유 모델
      파일 검사 상태StoredFile.scanStatus
      근로자 서류 제출 상태WorkerDocument — enum·DB 제약 변경은 #60 소유
      유효·만료 판단서류 만료일을 기준으로 Server가 계산
      업무 준비도기존 GET /tasks/{taskId}/document-readiness가 계산

      HWP/HWPX 허용 시 확장자만 믿지 않고 MIME·크기·파일 시그니처 정책과 다운로드 권한을 함께 검증합니다.

      Activity

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

      Metadata

      Metadata

      Assignees

      Labels

      area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업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][P0] 문서 상세 조회·상태 표현·HWP/HWPX 업로드 보완 #80

        Description

        @chaeliki

        배경

        fowoco/client PR #174, #228에서 fowoco/server의 통합 문서함 API(#13)를
        실제 화면에 연동하며 발견된 문제들을 정리합니다.

        1. GET /documents 응답에 version 필드 누락

        PATCH /workers/{workerId}/documents/{documentId}는 expected_version이
        필수인데, GET /documents 응답(DocumentItemResponse)에 이 값이 없어
        DocumentDetailPage의 확인/반려 버튼이 실제 연동이 안 되고 있습니다.
        WorkerDocument 도메인엔 이미 version이 있어 응답 DTO
        노출만 하면 해결됩니다.

        2. 단건 조회 API 부재

        GET /documents/{documentId}가 없어서, 프론트가 전체 목록을 받아
        worker_document_id로 직접 찾는 방식으로 우회하고 있습니다.

        3. HWP/HWPX 업로드 지원 추가

        POST /files가 image/jpeg·png·webp, application/pdf만 허용합니다.
        HWP/HWPX 업로드가 실제로 필요하므로 지원을 추가합니다.

        참고

        완료 조건

        • DocumentItemResponse에 version 필드 추가
        • GET /documents/{documentId} 단건 조회 API 신설
        • HWP/HWPX MIME 타입을 ALLOWED_MIME_TYPES에 추가

        2026-08-04 · PWF3 문서함 보완 원칙

        단건 응답은 화면이 목록 전체를 다시 받지 않아도 검토·반려를 수행할 수 있도록 다음 값을 함께 반환합니다.

        • version: 수정 충돌을 막는 expectedVersion의 기준값
        • Worker·Task 참조와 문서 유형
        • 제출 상태와 만료일
        • 연결된 파일의 ID·표시 파일명·MIME·크기·검사 상태

        서로 다른 상태를 하나의 status에 섞지 않습니다.

        상태소유 모델
        파일 검사 상태StoredFile.scanStatus
        근로자 서류 제출 상태WorkerDocument — enum·DB 제약 변경은 #60 소유
        유효·만료 판단서류 만료일을 기준으로 Server가 계산
        업무 준비도기존 GET /tasks/{taskId}/document-readiness가 계산

        HWP/HWPX 허용 시 확장자만 믿지 않고 MIME·크기·파일 시그니처 정책과 다운로드 권한을 함께 검증합니다.

        Activity

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

        Metadata

        Metadata

        Assignees

        Labels

        area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업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][P0] 문서 상세 조회·상태 표현·HWP/HWPX 업로드 보완 #80

          Description

          @chaeliki

          배경

          fowoco/client PR #174, #228에서 fowoco/server의 통합 문서함 API(#13)를
          실제 화면에 연동하며 발견된 문제들을 정리합니다.

          1. GET /documents 응답에 version 필드 누락

          PATCH /workers/{workerId}/documents/{documentId}는 expected_version이
          필수인데, GET /documents 응답(DocumentItemResponse)에 이 값이 없어
          DocumentDetailPage의 확인/반려 버튼이 실제 연동이 안 되고 있습니다.
          WorkerDocument 도메인엔 이미 version이 있어 응답 DTO
          노출만 하면 해결됩니다.

          2. 단건 조회 API 부재

          GET /documents/{documentId}가 없어서, 프론트가 전체 목록을 받아
          worker_document_id로 직접 찾는 방식으로 우회하고 있습니다.

          3. HWP/HWPX 업로드 지원 추가

          POST /files가 image/jpeg·png·webp, application/pdf만 허용합니다.
          HWP/HWPX 업로드가 실제로 필요하므로 지원을 추가합니다.

          참고

          완료 조건

          • DocumentItemResponse에 version 필드 추가
          • GET /documents/{documentId} 단건 조회 API 신설
          • HWP/HWPX MIME 타입을 ALLOWED_MIME_TYPES에 추가

          2026-08-04 · PWF3 문서함 보완 원칙

          단건 응답은 화면이 목록 전체를 다시 받지 않아도 검토·반려를 수행할 수 있도록 다음 값을 함께 반환합니다.

          • version: 수정 충돌을 막는 expectedVersion의 기준값
          • Worker·Task 참조와 문서 유형
          • 제출 상태와 만료일
          • 연결된 파일의 ID·표시 파일명·MIME·크기·검사 상태

          서로 다른 상태를 하나의 status에 섞지 않습니다.

          상태소유 모델
          파일 검사 상태StoredFile.scanStatus
          근로자 서류 제출 상태WorkerDocument — enum·DB 제약 변경은 #60 소유
          유효·만료 판단서류 만료일을 기준으로 Server가 계산
          업무 준비도기존 GET /tasks/{taskId}/document-readiness가 계산

          HWP/HWPX 허용 시 확장자만 믿지 않고 MIME·크기·파일 시그니처 정책과 다운로드 권한을 함께 검증합니다.

          Activity

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

          Metadata

          Metadata

          Assignees

          Labels

          area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업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][P0] 문서 상세 조회·상태 표현·HWP/HWPX 업로드 보완 #80

            Description

            @chaeliki

            배경

            fowoco/client PR #174, #228에서 fowoco/server의 통합 문서함 API(#13)를
            실제 화면에 연동하며 발견된 문제들을 정리합니다.

            1. GET /documents 응답에 version 필드 누락

            PATCH /workers/{workerId}/documents/{documentId}는 expected_version이
            필수인데, GET /documents 응답(DocumentItemResponse)에 이 값이 없어
            DocumentDetailPage의 확인/반려 버튼이 실제 연동이 안 되고 있습니다.
            WorkerDocument 도메인엔 이미 version이 있어 응답 DTO
            노출만 하면 해결됩니다.

            2. 단건 조회 API 부재

            GET /documents/{documentId}가 없어서, 프론트가 전체 목록을 받아
            worker_document_id로 직접 찾는 방식으로 우회하고 있습니다.

            3. HWP/HWPX 업로드 지원 추가

            POST /files가 image/jpeg·png·webp, application/pdf만 허용합니다.
            HWP/HWPX 업로드가 실제로 필요하므로 지원을 추가합니다.

            참고

            완료 조건

            • DocumentItemResponse에 version 필드 추가
            • GET /documents/{documentId} 단건 조회 API 신설
            • HWP/HWPX MIME 타입을 ALLOWED_MIME_TYPES에 추가

            2026-08-04 · PWF3 문서함 보완 원칙

            단건 응답은 화면이 목록 전체를 다시 받지 않아도 검토·반려를 수행할 수 있도록 다음 값을 함께 반환합니다.

            • version: 수정 충돌을 막는 expectedVersion의 기준값
            • Worker·Task 참조와 문서 유형
            • 제출 상태와 만료일
            • 연결된 파일의 ID·표시 파일명·MIME·크기·검사 상태

            서로 다른 상태를 하나의 status에 섞지 않습니다.

            상태소유 모델
            파일 검사 상태StoredFile.scanStatus
            근로자 서류 제출 상태WorkerDocument — enum·DB 제약 변경은 #60 소유
            유효·만료 판단서류 만료일을 기준으로 Server가 계산
            업무 준비도기존 GET /tasks/{taskId}/document-readiness가 계산

            HWP/HWPX 허용 시 확장자만 믿지 않고 MIME·크기·파일 시그니처 정책과 다운로드 권한을 함께 검증합니다.

            Activity

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

            Metadata

            Metadata

            Assignees

            Labels

            area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업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][P0] 문서 상세 조회·상태 표현·HWP/HWPX 업로드 보완 #80

              Description

              @chaeliki

              배경

              fowoco/client PR #174, #228에서 fowoco/server의 통합 문서함 API(#13)를
              실제 화면에 연동하며 발견된 문제들을 정리합니다.

              1. GET /documents 응답에 version 필드 누락

              PATCH /workers/{workerId}/documents/{documentId}는 expected_version이
              필수인데, GET /documents 응답(DocumentItemResponse)에 이 값이 없어
              DocumentDetailPage의 확인/반려 버튼이 실제 연동이 안 되고 있습니다.
              WorkerDocument 도메인엔 이미 version이 있어 응답 DTO
              노출만 하면 해결됩니다.

              2. 단건 조회 API 부재

              GET /documents/{documentId}가 없어서, 프론트가 전체 목록을 받아
              worker_document_id로 직접 찾는 방식으로 우회하고 있습니다.

              3. HWP/HWPX 업로드 지원 추가

              POST /files가 image/jpeg·png·webp, application/pdf만 허용합니다.
              HWP/HWPX 업로드가 실제로 필요하므로 지원을 추가합니다.

              참고

              완료 조건

              • DocumentItemResponse에 version 필드 추가
              • GET /documents/{documentId} 단건 조회 API 신설
              • HWP/HWPX MIME 타입을 ALLOWED_MIME_TYPES에 추가

              2026-08-04 · PWF3 문서함 보완 원칙

              단건 응답은 화면이 목록 전체를 다시 받지 않아도 검토·반려를 수행할 수 있도록 다음 값을 함께 반환합니다.

              • version: 수정 충돌을 막는 expectedVersion의 기준값
              • Worker·Task 참조와 문서 유형
              • 제출 상태와 만료일
              • 연결된 파일의 ID·표시 파일명·MIME·크기·검사 상태

              서로 다른 상태를 하나의 status에 섞지 않습니다.

              상태소유 모델
              파일 검사 상태StoredFile.scanStatus
              근로자 서류 제출 상태WorkerDocument — enum·DB 제약 변경은 #60 소유
              유효·만료 판단서류 만료일을 기준으로 Server가 계산
              업무 준비도기존 GET /tasks/{taskId}/document-readiness가 계산

              HWP/HWPX 허용 시 확장자만 믿지 않고 MIME·크기·파일 시그니처 정책과 다운로드 권한을 함께 검증합니다.

              Activity

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

              Metadata

              Metadata

              Assignees

              Labels

              area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업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][P0] 문서 상세 조회·상태 표현·HWP/HWPX 업로드 보완 #80

                Description

                @chaeliki

                배경

                fowoco/client PR #174, #228에서 fowoco/server의 통합 문서함 API(#13)를
                실제 화면에 연동하며 발견된 문제들을 정리합니다.

                1. GET /documents 응답에 version 필드 누락

                PATCH /workers/{workerId}/documents/{documentId}는 expected_version이
                필수인데, GET /documents 응답(DocumentItemResponse)에 이 값이 없어
                DocumentDetailPage의 확인/반려 버튼이 실제 연동이 안 되고 있습니다.
                WorkerDocument 도메인엔 이미 version이 있어 응답 DTO
                노출만 하면 해결됩니다.

                2. 단건 조회 API 부재

                GET /documents/{documentId}가 없어서, 프론트가 전체 목록을 받아
                worker_document_id로 직접 찾는 방식으로 우회하고 있습니다.

                3. HWP/HWPX 업로드 지원 추가

                POST /files가 image/jpeg·png·webp, application/pdf만 허용합니다.
                HWP/HWPX 업로드가 실제로 필요하므로 지원을 추가합니다.

                참고

                완료 조건

                • DocumentItemResponse에 version 필드 추가
                • GET /documents/{documentId} 단건 조회 API 신설
                • HWP/HWPX MIME 타입을 ALLOWED_MIME_TYPES에 추가

                2026-08-04 · PWF3 문서함 보완 원칙

                단건 응답은 화면이 목록 전체를 다시 받지 않아도 검토·반려를 수행할 수 있도록 다음 값을 함께 반환합니다.

                • version: 수정 충돌을 막는 expectedVersion의 기준값
                • Worker·Task 참조와 문서 유형
                • 제출 상태와 만료일
                • 연결된 파일의 ID·표시 파일명·MIME·크기·검사 상태

                서로 다른 상태를 하나의 status에 섞지 않습니다.

                상태소유 모델
                파일 검사 상태StoredFile.scanStatus
                근로자 서류 제출 상태WorkerDocument — enum·DB 제약 변경은 #60 소유
                유효·만료 판단서류 만료일을 기준으로 Server가 계산
                업무 준비도기존 GET /tasks/{taskId}/document-readiness가 계산

                HWP/HWPX 허용 시 확장자만 믿지 않고 MIME·크기·파일 시그니처 정책과 다운로드 권한을 함께 검증합니다.

                Activity

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

                Metadata

                Metadata

                Assignees

                Labels

                area:serverSpring Boot API·도메인·DB·tenant·Task Workflow 영역; Prompt·모델·Provider 구현 제외priority:P0MVP 진행을 막는 최우선 핵심 작업security:privacy개인정보·접근권한·토큰·보안 영향이 있는 작업type:feature사용자 또는 Agent가 사용하는 기능 개발

                Type

                No type

                Projects

                No projects

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions