콘텐츠로 이동

내 작업 공간 창

원천 · framework/evomind/web/workflow-project-evo-service기준 · 릴리스 v0.12.0커밋 · 2e32c6cc파일 · docs/operations/workspace-user-window.md기준선 · 2026-11-12

사용자가 계정 메뉴에서 내 작업 공간 을 열어 전체 사용량과 프로젝트(복제)·대화 worktree·파일을 보고, 필요 없는 항목을 지우거나 전체를 초기화한다. 파일은 읽기 전용으로만 본다 — 편집·업로드·다운로드는 이 창에 없다(의 나머지). 실행기는 workspace-runner.md 의 /v1/files/{list,read,delete}·/v1/usage·/v1/workspace/reset 을 쓴다. 관리자가 남의 공간을 보는 화면은 workspace-admin.md 다.

조건 설명
WORKSPACE_ENABLED=true 기능이 꺼져 있으면 계정 메뉴에 내 작업 공간 항목 자체가 나오지 않는다.
WORKSPACE_RUNNER_URL·WORKSPACE_RUNNER_TOKEN 실행기 주소·서비스 토큰. 없으면 기능이 꺼진 것으로 본다.
그 사용자의 workspace 기능 권한 PermissionService.isFeatureAllowed(username, Feature.WORKSPACE). 없으면 403.
로컬 계정의 활성 상태·GitLab 토큰 WorkspaceService.availableFor — 비활성이거나 토큰·호스트가 없으면 메뉴를 숨긴다.

GET /api/workspace/self/status 는 위 조건을 모두 만족할 때 enabled:true 와 실행 인증 상태(GitLab 계정·만료·경고)를 돌려준다. 사이드바는 이 값을 미리 받아 메뉴를 보일지 정하고, 창을 열 때 다시 받아 만료된 토큰을 반영한다.

모든 경로는 로그인 사용자의 홈 기준 상대 경로다. 서버는 로그인 사용자의 runner 번호로만 부르고, runner 는 그 사용자의 홈 밖을 커널 수준(os.Root)에서 거절한다 — 다른 사용자의 공간은 조회·삭제 어느 쪽으로도 드러나지 않는다. 권한이 없으면 403, 기능·runner 가 꺼져 있으면 503, 실행 중 삭제·초기화는 409, runner 호출 실패는 502 다.

경로 하는 일
GET /api/workspace/self/status 창을 보일 수 있는지·GitLab 인증 상태
GET /api/workspace/self/usage 전체 사용량 + 프로젝트·worktree 별 크기 + 묶인 대화 제목
POST /api/workspace/self/files/list {"path":"repos/group__proj"} — 폴더 목록(비우면 홈)
POST /api/workspace/self/files/read {"path":"…"} — 텍스트만 내용, 바이너리·256KiB 초과는 이유만
POST /api/workspace/self/impact {"path":"…"} — 지우기 전 영향(크기·묶인 대화·커밋하지 않은 변경·push 하지 않은 커밋)
POST /api/workspace/self/files/delete {"path":"…"} — 파일·폴더(재귀)·worktree·프로젝트 삭제
POST /api/workspace/self/reset 내 공간 전체 초기화(계정·토큰·에이전트 ID 등록은 유지)
{"bytes":3221225472,"files":120,"dirs":14,"links":0,"truncated":false,"limitBytes":10737418240,
"over":false,"groupsTruncated":false,
"projects":[{"folder":"group__proj","project":"group/proj","bytes":3000000000,"files":118,
"conversations":[{"conversationId":"…","title":"첫 대화"}]}],
"worktrees":[{"path":"work/<대화 id>/group__proj","project":"group/proj","folder":"group__proj",
"conversationId":"…","conversationTitle":"첫 대화","bytes":40000000,"files":2}]}
  • 실행기 usage.groups(프로젝트 clone·worktree 별 크기)를 대화 연결(conversation_workspaces)과 맞물려 이름·제목을 붙인다. 연결만 있고 파일이 없는 worktree 도 0 바이트로 보여 준다.
  • 프로젝트가 1000개를 넘으면 groupsTruncated:true(실행기가 크기 순 상위 1000개만 준다). 전체 합계는 그대로 정확하다.
  • 묶인 대화는 그 사용자의 대화만 조회한다(conversation_workspaces + conversations.user_id).
  • kind 는 project(repos/<폴더>) · worktree(work/<대화 id>/<폴더>) · conversation(work/<대화 id>) · item(그 밖의 파일·폴더).
  • 크기는 사용량 묶음에서 정확히 얻는다. 묶음에 없는 폴더는 세지 않으므로 sizeKnown:false(파일이면 목록에서 크기를 찾는다).
  • uncommitted·unpushed 는 그 폴더에서 서버가 만든 인자로 git status --porcelain=v1 과 git rev-list --count HEAD --not --remotes 를 실행해 센다. 그 사용자의 실행이 진행 중이면 알 수 없으므로 null 이고 busy:true 다. git 을 부를 수 없거나 저장소가 아니면 null(모름)이다.
  • 대화(conversation)를 지울 때는 그 아래 worktree 들의 수를 모두 더한다 — 하나라도 모르면 null.
  • delete 는 실행기 /v1/files/delete 를 그대로 부른다. 파일·폴더(재귀)·링크를 지우고, worktree 폴더면 git 등록 정보도 정리한다. 홈 자체와 최상위 관리 폴더(repos·work)는 실행기가 400 으로 거절한다.
  • 실행 중이면 409 이고 아무것도 지우지 않는다. 성공하면 사용량을 다시 세어 응답에 담는다(다시 세지 못하면 usage:null, 화면은 GET /usage 로 새로 고친다). 초기화 뒤에도 같은 규칙이다.
  • 사용량 — 상한(기본 10GiB) 대비 막대와 파일·폴더·링크 수. 넘으면 빨간 경고, 일부만 셌으면 그 사실을 함께 보여 준다.
  • 프로젝트·worktree — 크기·파일 수·묶인 대화 제목을 보여 주고 행마다 삭제 버튼이 있다.
  • 파일 — 홈부터 경로를 따라 내려가는 목록. 폴더는 눌러 들어가고 파일은 눌러 읽는다. 내용은 React 텍스트로만 그리므로 HTML·스크립트가 실행되지 않는다. 바이너리·큰 파일은 내용 대신 이유만, 심볼릭 링크·장치 등은 이름만 보여 준다.
  • 삭제 확인 — 파일·폴더·worktree·프로젝트 어느 쪽이든 확인 창을 거친다. 창에는 종류·지울 크기·영향받는 대화· 커밋하지 않은 변경·push 하지 않은 커밋 수가 나오고, 실행 중이면 경고가 함께 나온다(그래도 시도하면 409).
  • 전체 초기화 — 현재 사용량과 “저장하지 않았거나 push 하지 않은 변경이 모두 사라진다”는 경고를 담은 확인 창을 거친다. 계정·GitLab 토큰·에이전트 ID 등록은 남는다.
  • 키보드만으로 열고 조작할 수 있고(계정 메뉴 → 창, 포커스 트랩·Escape), 문구는 한국어·영어 i18n 키(workspace.self.*)다.
이벤트 남기는 것
workspace.delete 행위자·대상 username·kind·path(요약: repos/<폴더>·work/<대화 id>/<폴더> 까지만)·bytes·files. 그 아래 파일 이름·내용은 넣지 않는다.
workspace.reset 행위자·대상 username·bytes·files(초기화 전). 경로·파일 이름 없음.
터미널 창
cd backend && ./gradlew :app:test --tests '*WorkspaceSelfServiceTest'
cd frontend && npm run build && npm run check:a11y
cd runner && go test ./... # groups 계산·경로 묶음 시험
  • 서비스 시험: 권한 없음 403(실행기 호출 없음), 기능 꺼짐 503, 사용량 묶음 매핑(프로젝트·worktree·제목·0바이트 worktree), 경로 이탈 400, 바이너리 통과, 영향(크기·대화·git 수·busy), 삭제 409·감사 없음, 감사에 종류·크기만, 사용량 갱신 실패에도 삭제 성공 유지, 초기화 감사.