오래 쓴 라벨에 완료 항목이 계속 쌓여 카드가 길어지는 문제를 해소한다.
- 목록 상단에 '완료 항목 숨기기' 토글 — 화면에서만 걸러내고 데이터는 유지
- 라벨 메뉴에 '완료 항목 N개 삭제' — 확인 후 일괄 삭제(DELETE labels/:id/done-items)
- 완료 항목이 없으면 두 진입점 모두 노출하지 않는다
- 숨김 상태에서도 진행 집계는 전체 기준을 유지한다
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 버튼의 반짝임 아이콘 제거, 문구를 'AI 추천' → '할 일 추천' 으로 변경
- 추천 모달 제목·aria-label 도 같은 문구로 통일
- 아이콘 제거로 쓰이지 않게 된 CSS 규칙 정리
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
할 일 기능 전반을 재검토해 사용자가 바로 겪는 문제를 고친다.
- 이름 수정 시 입력에 포커스를 주지 않아 타이핑도 blur 확정도 되지 않던 문제
- 한글 조합 중 Enter 가 미완성 문자열을 저장하던 문제(추가·수정 양쪽)
- 되돌릴 수 없는 할 일 삭제에 확인 다이얼로그 추가
- 추가 실패 시 입력이 사라지던 문제 — 성공했을 때만 비운다
- 수정 입력에 빠져 있던 maxlength 추가
- 체크 토글을 낙관적으로 반영하고 실패 시 되돌린다
- 같은 항목의 중복 요청을 막아 응답 역순 도착으로 인한 덮어쓰기 방지
- 편집 중인 행이 목록에서 사라지면 편집 상태를 정리
- 처리되지 않은 Promise 거부 제거
- 삭제 버튼이 키보드 포커스 시에도 보이도록 수정
- 업무에서 만든 라벨에 원본 업무 링크 표시(직접 만든 라벨은 표시하지 않음)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
담당자가 업무를 자기 할 일 목록으로 옮길 수 있게 한다. 항목 출처는 두 갈래이며
확정 모달은 하나를 공유한다.
- 체크리스트가 있으면 그 항목을 카테고리 순으로 복사(완료 항목은 기본 해제)
- 없고 본문만 있으면 AI 가 본문을 분석해 담당자 관점의 실행 단계를 제안
- 둘 다 비어 있으면 버튼을 비활성화
- todo_labels.source_task_id 추가 — 같은 업무로 다시 만들면 새 라벨 대신 병합
- 병합 시 판정 기준은 '보완 내용을 뗀 원문', 반려된 항목은 완료를 되돌린다
- 수정 요청된 항목은 보완 내용을 제목에 함께 담는다
- 라벨 이름은 '프로젝트 - 업무 제목', 길면 프로젝트명부터 줄인다
- AI 프롬프트는 근거 없는 항목을 만들지 않도록 개수 하한 없이 제약
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
목록의 "N월 N일 완료" 라벨이 완료 시각이 아니라 마감일(dueDate)을 쓰고 있어,
마감일을 지시 당일로 잡은 업무는 지시 날짜가 완료일처럼 보였다.
완료 시각을 저장하는 컬럼 자체가 없던 것이 원인이다.
- tasks.completed_at 추가 — done 진입 시 기록, 이탈 시 null(재승인 시 갱신)
- 목록/내 업무 응답에 completedAt 노출, taskDueInfo 가 이 값으로 라벨 생성
- 기존 완료 업무는 활동 로그(task.status_changed)의 시각으로 백필
- 백필 불가 건과 마감일 없는 완료 업무는 날짜 없이 "완료"만 표시
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
사용하지 않는 기능이라 헤더 버튼과 관련 로직을 모두 걷어낸다.
업무 생성 화면의 AI 할 일 추천(/ai/suggest-checklist)은 그대로 유지한다.
- 프론트: AgentChatPanel, ai.store, 헤더 버튼·패널 마킹, useAi 의 대화 함수와
types/ai 의 대화 타입 제거. 채팅 전용이던 shared/utils/markdown.ts 도 함께 삭제
- 백엔드: AiController(대화 5개 엔드포인트), AiConversation·AiMessage 엔티티,
SendMessageDto, AiService 의 채팅 로직 제거. AiModule 의 TaskModule 의존도 해제
- ai_conversations·ai_messages 테이블 삭제 마이그레이션 추가(down 은 초기 스키마 복원)
- 문서: api-contract 의 채팅 API 절 삭제, integration-progress 8-6 은 이력이라
삭제 대신 제거됨 표기
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
.page 의 max-width(67.5rem)와 가운데 정렬을 제거해 콘텐츠가 화면
전체 폭을 사용하도록 한다. 좌우 여백(1.5rem)은 그대로 유지한다.
프로젝트 생성·설정처럼 좁은 단이 필요한 폼 화면은 각 페이지에서
자체 max-width 를 유지한다.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
사이드바에 '할 일' 메뉴를 추가하고, 라벨 1개에 할 일 N개를 담는
개인 전용 체크리스트를 구현한다.
- todo_labels / todo_items 엔티티 + 마이그레이션 (소유자·라벨 CASCADE)
- 라벨·항목 CRUD API — 항목 변경 응답은 '변경된 라벨' 단위라 카드 하나만 갱신
- 모든 라벨·항목은 소유자 본인만 접근하며 타인 것은 존재를 숨김(404)
- 화면: 라벨 카드 세로 나열, 인라인 추가·수정, 완료 항목은 취소선 후 하단 정렬
- 기존 .list / .toolbar / BaseModal 등 공용 디자인 규격 사용
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
카테고리를 사내 공용(owner=null)과 개인 전용(owner=사용자)으로 나누고,
일정의 공개 범위를 소속 카테고리에서 파생시켜 두 종류가 섞이지 않게 한다.
- 조회: 사내 일정 + 본인 개인 일정만 반환, 타인의 개인 항목은 존재를 숨김
- 개인 일정은 소유자만 수정·삭제하며 참석자·알림을 사용하지 않음
- 사내 일정은 등록자만 수정·삭제하도록 제한
(등록자가 탈퇴한 기존 일정은 잠기지 않도록 예외 처리)
- 일정이 남은 사내 카테고리는 삭제를 막아 타인 일정 연쇄 삭제를 방지
- 툴바를 캘린더 선택(사내/개인 체크박스)과 '내 관련' 참석자 필터로 분리
- 일정·카테고리 작성 시 사내/개인 구분을 명시적으로 선택
- 기존 데이터는 전부 사내 공유(company)로 유지되는 마이그레이션 추가
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 공동 지시자(coIssuers): 업무에 공동 지시자를 지정해 원 지시자와 함께
완료 검토(승인/수정요청) 권한을 부여. 생성/수정 UI, 검토 권한 체크,
보고 열람, 승인요청·시작 알림 수신, '내가 지시한 업무' 목록에 포함.
- 검토자 표기(reviewedBy): 승인 완료/수정 요청 카드에 실제 검토를 수행한
사람(원 지시자 또는 공동 지시자)을 표기하도록 추적·노출.
- 마감 알림: 매일 오전 9시(KST) cron으로 미완료 업무의 마감 임박(24h 이내)
·초과를 담당자에게 1회 알림(task.due_soon/task.overdue). 발송 플래그로
중복 방지(다중 인스턴스 대비 원자적 선점), 마감 변경 시 초기화.
웹푸시·인앱 문구 동시 지원(커버리지 스펙 갱신).
DB: task_co_issuers 조인테이블, tasks.reviewed_by,
tasks.due_soon_notified_at/overdue_notified_at 마이그레이션 추가
(dev synchronize 자동, 운영 migrationsRun).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
프로젝트·회의 화면과 달리 드라이브의 빈/검색없음 상태 안내문이 페이지
정중앙에 떠 있던 문제를 수정한다. 목록 컨테이너(.dr-listwrap)의 중앙
정렬을 제거해 안내 카드가 다른 화면과 동일하게 상단에 폭을 꽉 채워
배치되며, 남는 아래 영역은 그대로 드래그-드롭 업로드 영역으로 유지된다.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
VAPID 섹션만 설명 주석을 배너 박스 안에 넣거나(dev) 배너 자체가
없어(prod) 다른 섹션과 어긋나던 것을, 다른 섹션과 동일하게
'배너(제목만) → 아래 설명 주석' 구조로 맞춘다. 값 변화 없음.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
드롭다운을 body 로 Teleport + fixed 위치로 띄워(DropdownSelect 와 동일 패턴)
모달의 overflow 에 잘리지 않게 한다. 입력창 기준 좌표를 계산하고 뷰포트
하단을 넘지 않도록 최대높이를 제한하며 스크롤/리사이즈 시 위치를 갱신한다.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
[신뢰성]
- SSE 재연결 시 fetchInitial 로 재동기화: 끊긴 사이 놓친 알림 복구 +
access 토큰 자동 refresh 로 만료 토큰 재연결 무한루프 해소
- 서비스워커 pushsubscriptionchange 처리로 구독 회전 시 자동 재등록
- 읽은 알림 90일 retention 정리 배치(@Cron)
- 웹푸시 다기기 병렬 발송(allSettled) + TTL/urgency 지정
- 알림 문구 SSOT 상호참조 주석 + web-push 커버리지 테스트 추가
[내용]
- 전 직원(allHands) 일정도 전 사용자에게 알림(생성/수정/삭제)
- task.file_attached 신규 타입: 파일 첨부 시 지시자·담당자 알림
- task.started 재개(수정요청 후) 문구 '재개/시작' 구분
- task.due_changed 푸시에 날짜/해제 상세 반영
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
검색바가 전체 너비로 늘어나던 오버라이드를 제거해 전역 고정폭(17.5rem)을
사용하고 버튼 그룹을 우측 정렬한다. 상단 안내문도 다른 목록 화면과 같은
한 줄 문구로 맞춘다.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
기존엔 받는 사람이 앱 화면을 보고 있으면(포커스) OS 토스트를 띄우지
않고 종 알림만 갱신했으나, 화면을 보고 있어도 토스트가 뜨도록 변경한다.
서비스워커의 중복 방지(열린 탭 있으면 표시 생략)는 그대로라 토스트는
여전히 1개다.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
프론트 Dockerfile이 VAPID 공개키 build arg 를 받지 못해 운영 빌드
번들에 키가 비어 "푸시 키 미설정" 으로 동작하던 문제를 수정한다.
다른 VITE_* 변수와 동일하게 ARG/ENV 를 선언해 빌드에 주입한다.
(dev 는 런타임 env 주입이라 영향 없었음)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
드라이브 브레드크럼이 커스텀 .dr-crumb/.dr-sep(› 구분자)로 따로
구현돼 프로젝트 화면(.crumb/.lnk/.sep, / 구분자)과 달랐던 것을
전역 시스템으로 맞춘다. 루트 링크도 goRoot 핸들러 대신 RouterLink 로 통일.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
드롭 오버레이가 목록 래퍼 안에 갇혀 빈 폴더에서는 안내 카드 한 장
높이만큼만 드롭 영역으로 보이던 문제를 개선한다. 페이지를 세로
플렉스로 만들고 목록 영역이 남는 높이를 모두 채우게 해, 파일이 적거나
비어 있어도 파일 영역 전체에 끌어다 놓을 수 있게 한다.
- .page: 세로 플렉스 + min-height(뷰포트 - 상단바)
- .dr-listwrap: flex 1 로 남는 공간 차지(+ min-height 하한)
- 빈 폴더/검색 결과 없음 안내문은 영역 중앙 정렬
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
프로젝트 활동 페이지에 인라인 중복 구현돼 있던 활동 피드(원형 아이콘+
아바타+본문+날짜그룹) 마크업·아이콘맵·스타일을 공용 ActivityFeed로
추출한다. 드라이브 '기록' 패널도 단색 점 목록에서 이 공용 컴포넌트로
교체해 다른 화면과 동일한 디자인 시스템을 쓰도록 통일한다.
- 신규 components/common/ActivityFeed.vue (모달 임베드용 bare 옵션 포함)
- ProjectActivityPage: 인라인 피드 제거 → ActivityFeed 사용
- drive.store: 감사 로그를 ProjectActivityDay[]로 변환(activityDays),
tone setting·repo/pencil 아이콘, escapeHtml로 XSS 방지
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
개인별 격리(owner 기준)를 제거해 로그인 사용자 전원이 하나의 공유
트리를 보고 관리하도록 전환한다. 수정/삭제는 전원 허용하며, 행위
추적을 위해 전역 감사 로그(drive_activities, GET /drive/activity)를
추가한다. 업로더 탈퇴 시 공유 파일이 사라지지 않도록 owner FK를
CASCADE에서 SET NULL로 변경한다.
- 백엔드: 접근 권한 해석 제거(단순 로더화), 업로드/이름변경/삭제
6지점에 감사 적재, DriveAuditService 신설, 운영 마이그레이션
1783200000000 추가
- 프론트: 목록 행에 업로더 표시, 툴바 '기록' 패널 추가
- 프로젝트 폴더 연동의 '본인 소유 폴더만' 제한 해제(공유 모델 일관성)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
연동 프로젝트 폴더의 파일 업로드/삭제와 폴더 삭제를 활동 피드에 기록하고,
파일 삭제를 소프트 삭제(status=deleted + deletedBy/deletedAt 묘비)로 전환해
누가·언제 지웠는지 추적할 수 있게 한다. 실제 객체는 즉시 영구 삭제(복구 제외).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ADD COLUMN IF NOT EXISTS, project_attachments 는 제약 이름 비의존 DROP TABLE IF EXISTS ... CASCADE 로 변경. 과거 synchronize 로 만들어진 운영 DB나 부분 적용 상태에서도 실패하지 않도록 함
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
drive_files 에 extracted_text/extract_status 추가, project_attachments 폐기(완전 대체). dev 는 synchronize, 운영은 이 마이그레이션으로 반영
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
프로젝트 직접 업로드(project_attachments) 폐기, AI 검토 문서를 드라이브 폴더 연동으로 전환. 폴더 연동 CRUD·연동 폴더 문서에서 텍스트 지연 추출(NCP 다운로드, xlsx 포함)·AI 추천 주입. 폴더 선택 피커 추가
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
NCP Object Storage(S3 호환) 기반 파일 업로드/폴더 관리 기능을 백엔드에 추가한다.
- 스토리지 계층(common/storage): presign 기반 업로드/다운로드 URL 발급 래퍼
- 드라이브 모듈: 폴더 CRUD, 파일 presign 업로드→complete→다운로드, 이름변경/삭제
- 엔티티 3종: drive_folders(폴더 트리), drive_files(객체 메타), project_folder_links(프로젝트 공유)
- 마이그레이션 AddDriveTables: 3개 테이블 + 인덱스/외래키 생성
- stale pending 파일 정리 @Cron(매시) 추가
- env/docker-compose: OBJECT_STORAGE_* 주입(비시크릿은 루트, ACCESS/SECRET 키는 backend env)
- 의존성: @aws-sdk/client-s3, @aws-sdk/s3-request-presigner 추가
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
방 식별을 이름이 아닌 불변 코드로 전환 — 이름을 바꿔도 링크·세션이 유지되고
초대 링크의 안정적 기준이 된다.
- 백엔드: meeting_rooms.code(고유·불변) 추가, name 고유 해제(표시용 라벨, 중복 허용).
마이그레이션 AddMeetingRoomCode(코드 백필+name 고유 인덱스 제거). 토큰 발급은
code 로 방 조회(자동 생성 제거 — 명시 생성된 방만 입장, 없으면 404). LiveKit 방=code.
createRoom 이 고유 코드 발급. MeetingRoomResponse 에 code 추가.
- 프론트: 입장/라우팅을 code 기준으로(/meeting/:code), 로비 입장은 방 객체 전달,
'초대 링크 복사' 버튼(코드 기반 URL) 추가. 생성 폼 이름 중복 검사 제거.
검증: 백엔드 build, 프론트 type-check·lint 통과.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
진행자(생성자)가 방의 이름·예약 시각·참여 제한(allow-list)을 수정할 수 있다.
- 백엔드: PATCH /meetings/rooms/:roomId (updateRoom, 진행자만, 이름 중복 검사).
UpdateMeetingRoomDto(생성과 동일 필드). MeetingRoomResponse 에 allowedUsers 추가
(진행자에게만 노출 — 편집 폼 사전 채움용). User repo 주입해 ID→PublicUser 해석.
- 프론트: useMeeting.updateRoom, 로비 각 방에 편집 버튼(진행자), MeetingCreateForm
를 편집 모드로 재사용(현재 값 프리필·중복검사 자기제외·저장 분기), MeetingIcon edit 추가.
검증: 백엔드 build, 프론트 type-check·lint 통과.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
스테이지(featured) 유저만 HIGH, 나머지 원격 참여자는 LOW 로 구독한다.
스테이지가 바뀔 때마다 강등된 참여자가 LOW 로 내려가도록 보장한다.
- adaptiveStream 비활성화: 화질이 "엘리먼트 크기"가 아니라 "스테이지 역할"로만
결정되도록(스테이지=HIGH 보장, 강등 반영 결정적). dynacast 는 유지.
- 화질 제어를 useLiveKitRoom 로 중앙화: featuredIdentity 변경·참여자/트랙 변동
시마다 전원 재적용. 기존 타일 리마운트 의존(레이스로 강등자가 HIGH 유지되던 버그) 제거.
- ParticipantTile 의 개별 setVideoQuality 제거(중복·레이스 원인), 영상 연결만 담당.
검증: type-check, lint 통과.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>