회의방 목록의 진행자(소유자) 표기를 별 아이콘+이름에서 UserAvatar(프로필
이미지/실루엣)+이름으로 변경 — 프로젝트·업무 화면의 사람 표기 방식과 일치.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- nginx Permissions-Policy: 운영에서 camera/microphone 을 self 에 허용
(기존 microphone=()/camera=() 가 LiveKit 장치 접근을 차단하던 문제 수정)
- 회의 로비 빈 상태/검색결과 없음을 공용 EmptyState 로 통일(내 업무·프로젝트 화면과 동일)
- 미구현인 공유 링크 안내 문구 제거(lede)
- 프리조인 "카메라·마이크 권한이 없습니다" 문구 제거
- 회의실 상단 노란색 권한 안내 배너(room-err) 제거 + 관련 prop/이벤트 정리
- 회의방 이름에 한글 허용(백엔드 DTO 2종 + 프론트 검증 정규식/문구, 공백·특수문자는 계속 차단)
- 멤버 초대 등급 셀렉트(DropdownSelect block) 라벨 좌측 정렬(버튼 기본 가운데정렬 상속 수정)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
디자인 시안(프로토타입)을 실제 Vue 컴포넌트로 이식하고, 코드·로직·보안
검토에서 도출한 항목을 반영한다.
UI 개편
- 컴포넌트 분리: MeetingLobby/CreateForm/Prejoin/Room/SidePanel/PeopleList/
Chat/ControlBar/ParticipantTile/QualityBars/MeetingIcon
- 로비: 검색 툴바 + "새 회의 만들기" 모달(BaseModal) + 방 목록(삭제=휴지통)
- 프리조인: 실제 카메라/마이크 미리보기 + 초기 on/off, 실제 프로필 아바타
- 회의실: 축소 스테이지 + 썸네일 그리드(한 페이지 50명) + 페이지네이션,
말하는 사람 하이라이트/연결 품질 막대
- 채팅: 데이터 채널 실제 구현(Shift+Enter 줄바꿈, 실제 프로필 아바타)
디자인 시스템 정합
- rem 단위/토큰 정렬, 공용 .btn/.form-*/.search/BaseModal/UserAvatar 재사용
- 회의실 다크 캔버스 토큰(--d-*, --d-red/green/amber/accent-soft) 추가
화질/성능
- 스테이지=고화질, 나머지=저화질 구독(setVideoQuality)
- 타일 backdrop-filter 제거 + 발화/품질 이벤트 전체 리렌더 제거(버벅임 완화)
코드·로직·보안 검토 반영
- 채팅 표시 이름은 서명 토큰의 name/identity 만 신뢰(클라이언트 name 사칭 차단)
- promote 는 보낸 사람 metadata role=host 일 때만 적용(인가)
- 원격 오디오를 룸 레벨에서 전원 재생(페이지 밖 참여자 무음 수정)
- 타일 언마운트 시 트랙 detach(누수 방지)
- 마이크/카메라 토글 실패 시 상태 롤백
- 입장 토큰 TTL 1h → 12h(장시간 회의 재연결 안정성)
- 채팅 길이 상한(MAX_CHAT_LENGTH)
- 토큰 metadata 에 avatarUrl 포함(참여자/채팅 아바타)
기타
- 임시 명세/디자인 참고 파일 제거
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
암묵적 방 생성을 명시적 방 관리로 확장한다. (기능 완성 + 임시 UI)
백엔드
- meeting_rooms 에 scheduled_at(예약), allowed_user_ids(참여 허용 allow-list) 추가 + 마이그레이션
- GET /meetings/rooms(목록: 접근 가능/진행자 여부 포함)
- POST /meetings/rooms(생성: name+예약+허용멤버, 생성자=진행자, 이름 중복 409)
- DELETE /meetings/rooms/:id(진행자만, 아니면 403)
- 토큰 발급 시 참여 제한 enforcement: 비허용자는 AUTH_003(403).
방이 없으면 자동 생성(공개)으로 직접 링크 입장은 유지.
프론트
- useMeeting: listRooms/createRoom/removeRoom + types/meeting.ts
- MeetingPage 로비: 방 목록(입장/삭제) + 생성 폼(예약시각·참여 제한 멤버 피커, useUser 검색 재사용) + 빠른 입장
- 화상회의_화면명세.md 단계 4 반영(범위/로비/데이터 계약/엔드포인트)
권한 모델은 기존 결정대로 "누구나 생성=진행자" 유지(전역 admin 없음).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
진행자/승격 참여자 큰 화면 + 썸네일 + 페이지네이션 + 화면 승격을 구현한다.
(레이아웃은 임시 — UI 는 추후 개편 예정. 데이터/로직만 확정.)
- useLiveKitRoom: featuredIdentity 상태 + promote(identity) 추가.
진행자가 데이터 채널로 승격을 브로드캐스트 → RoomEvent.DataReceived 로 전원 동기화.
- MeetingPage:
· stage(featured: 승격>진행자>첫 참여자) 큰 화면 + 나머지 썸네일
· 진행자에게만 썸네일 "크게"(승격) 버튼
· 썸네일 페이지네이션(페이지당 12명) — 현재 페이지만 렌더 →
adaptiveStream 이 안 보이는 참여자 미디어 자동 미구독(대역폭 절약)
- 화상회의_화면명세.md: 단계 2~3 반영(범위/화면 구성/데이터 계약 갱신)
백엔드 변경 없음(승격은 클라이언트 데이터 채널).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
방을 처음 만든 사용자를 진행자로 보고, 역할별로 LiveKit 권한을 차등 부여한다.
백엔드
- meeting_rooms 엔티티/마이그레이션: 방 이름(고유)→진행자(host) 보관
- 토큰 발급 시 역할 결정: 방이 없으면 생성자=진행자, 있으면 생성자 일치로 판정
(동시 생성 경쟁은 name unique 충돌 후 재조회로 처리)
- grant 차등: 진행자 roomAdmin+발행/구독, 일반 발행/구독
- 역할을 토큰 metadata({"role":...})에 실어 다른 참여자도 진행자 식별
- 응답에 role 추가
프론트
- useMeeting: role 반환
- ParticipantTile: metadata 파싱 → 진행자 타일에 "진행자" 배지
- MeetingPage: 본인이 진행자면 헤더에 역할 칩 표시
방 목록/예약/참여 제한 UI 는 단계 4 로 분리.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
LiveKit(SFU)에 미디어 전송을 위임하고, 앱은 입장 토큰 발급 + 회의 화면만
담당하는 구조로 단계 1(기본 연결)을 구현한다.
백엔드
- meeting 모듈: POST /api/meetings/token (JWT 인증)
livekit-server-sdk 로 입장 JWT 발급(identity=userId, name, grants:
roomJoin/publish/subscribe/publishData, TTL 1h). 단계 2에서 역할별 분기 예정.
프론트
- useMeeting(토큰 발급), useLiveKitRoom(연결/참여자/컨트롤 상태)
- ParticipantTile(카메라/마이크 트랙 attach, 본인 거울·음소거, 이니셜 플레이스홀더)
- MeetingPage(로비 + 영상 그리드), 라우트 /meeting/:room?, 사이드바 네비 추가
- VITE_LIVEKIT_URL 주입(build arg + dev 런타임 env)
인프라/설정
- 개발 미디어 서버는 LiveKit Cloud 사용(로컬 self-host 는 WSL2/Docker Desktop
WebRTC 네트워킹 제약으로 제외). env 만으로 운영 전환 가능.
- livekit/livekit.yaml 은 단계 6 셀프호스팅 참고용으로 보관.
- 화상회의_화면명세.md: 현재 화면 기능/구조/데이터 계약 문서(UI 개편 참고).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AI 추천이 문서 내용을 반영하지 못해도(추출 실패·미지원 형식) 추천은
정상 응답되어 사용자가 인지할 수 없던 문제를 해소한다. 문서 목록에
반영 상태 배지를 노출한다.
- ProjectAttachmentResponse.aiStatus 추가(ready/failed/unsupported)
· ready: 추출 성공(반영 가능) · failed: 지원 형식이나 추출 실패
· unsupported: 미지원 형식(이미지·xlsx·ppt·zip 등)
- isExtractableType + deriveAiStatus 로 상태 산출
(추출 본문은 응답에 노출하지 않고 상태 판별에만 사용)
- listFiles 에서 extracted_text 를 명시적으로 선택(select:false 우회)
- 공용 AttachmentAiBadge 컴포넌트 추가 → 프로젝트 상세·설정 문서 목록에 적용
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
프로젝트에 문서 파일을 첨부할 수 있도록 추가(업무 첨부 인프라·업로드 설정 재사용).
백엔드:
- ProjectAttachment 엔티티 + 마이그레이션(project_attachments)
- 업로드(관리자)/삭제(관리자)/다운로드(멤버) 엔드포인트, 멀터 디스크 저장
- 프로젝트 상세 응답에 attachments 포함
프론트:
- 생성 화면: 파일 staged 후 생성 직후 업로드
- 편집(설정) 화면: 기존 문서 목록 + 추가/삭제(즉시), 폼 미저장 보존
- 프로젝트 상세: 문서 목록(다운로드 전용)
- useProject.uploadFile/removeFile, ApiProjectAttachment 타입
권한: 업로드/삭제=관리자, 조회/다운로드=멤버. 형식/용량은 업무 첨부와 동일(25MB).
런타임 검증: 업로드·목록·다운로드·삭제 + 비관리자 403 확인.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
일정 CRUD 시 참석자에게 인앱 알림 발송(기존 NotificationService + SSE 재사용).
- 생성: 참석자로 지정된 사용자에게 schedule.invited (전 직원 일정은 개별 알림 생략)
- 수정: 신규 참석자 → schedule.invited, 기존 참석자 → schedule.updated
- 삭제: 참석자에게 schedule.removed (삭제 전 참석자 확보)
- 행위자 본인은 자동 제외, payload(actorName/eventTitle/start), 클릭 시 /schedule 이동
- NotificationType(백/프론트) 3종 추가 + notification.store 렌더 케이스
런타임 검증: 지정/수정/삭제 알림이 참석자에게만 정상 도달.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 사이드바 nav 순서: 일정 → 내 업무 → 프로젝트
- 기본 진입을 /schedule 로: 루트 redirect, 로그인 후 이동, 로그인 상태에서
로그인/가입 진입 가드, 소셜 로그인(구글/카카오) 콜백
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- '내 일정' 토글 추가(참석자 기준: 전 직원 또는 참석자에 본인 포함). 주간/월간 공통
- 월간 '+N' 클릭 시 그날 전체 일정 팝오버(Teleport, 바깥클릭/ESC 닫기, 클릭→상세)
- 일정/카테고리 모달 필수 입력 표기(*) — 제목·유형·시작일·종료일·시간·참석자, 카테고리 이름
(.form-label .req 전역 스타일 추가)
- 참석자 필수화(폼 검증: 전 직원 또는 1명 이상)
- 월간 일정바 두께 소폭 증가
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
카테고리가 없을 때 안내 문구를 상단에 작게 두지 않고, 본문(min-height:100%)과
.tl-empty(flex:1)로 표 영역 전체 높이를 채워 중앙 배치.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 새 일정 모달 placeholder 를 프로젝트 기존 톤("~을 입력하세요/선택하세요")으로 통일
- 참석자 등록을 업무 생성의 담당자 등록과 동일한 콤보(검색 입력+후보 드롭다운+선택 칩)로 개편
('전 직원'은 드롭다운 항목/단일 칩으로 처리)
- 아바타 스택+오버플로(+N)+팝오버 목록을 공용 AvatarStack 으로 추출,
일정 상세 참석자 + 업무 상세 담당자 카드에 적용(담당자 팝오버에 역할 표시)
- 사용처가 사라진 ScheduleAvatar 삭제(UserAvatar/AvatarStack 으로 일원화)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
세션이 짧게 유지되고 '로그인 유지'가 동작하지 않던 문제 수정.
원인1(프론트): 401 자동 refresh 가 '/auth/' 포함 URL을 모두 제외해,
부트스트랩 /auth/me 가 access 만료(15분)로 401 이어도 refresh 를 시도하지 않아
새로고침/재방문 시 로그아웃됨.
- useApi 인터셉터: refresh-재시도 제외 대상을 /auth/refresh·/auth/login 으로만 한정
→ /auth/me 등은 access 만료 시 refresh 후 재시도되어 세션 복원
원인2(백엔드): keepLogin 값이 무시되어 쿠키 영속 여부에 반영되지 않음.
- RefreshSession 에 persistent 플래그 추가(마이그레이션, default true)
- 로그인 시 keepLogin 저장, refresh 회전 시에도 그대로 유지
- setAuthCookies: persistent=true 면 maxAge(영속), false 면 세션 쿠키
- 소셜 로그인은 체크박스가 없어 영속(true) 기본
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 보고서 모달: '전체' 탭 제거(기본=항목 있는 첫 분류), 상태 드롭다운 크기 축소,
푸터 배경을 다른 모달(.bm-foot)과 동일한 #fafbfc 로 통일
- 일정 화면: 콘텐츠 영역 상하좌우 여백 1.5rem 통일, 툴바 가로 여백 정렬 +
전역 .toolbar 의 margin-bottom 상속 차단(상단 여분 마진 제거)
- 일정 하위 컴포넌트 px→rem 일괄 변환(보더 width·box-shadow 는 px 유지),
ScheduleAvatar 도 size 를 rem 렌더 → '전 직원' 표식과 아바타 크기 정합 유지
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
todo 표기가 화면마다 '할 일'(taskStatusLabel) vs '대기'(ProjectDetail 배지)로
갈리던 불일치 해소. SSOT(format.taskStatusLabel)를 '대기' 로 통일하고
ProjectDetailPage 의 자체 STATUS_LABEL 제거 → taskStatusLabel 사용.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
StatusSelect 와 업무 상세에 각각 중복 정의되던 WORK_STATUS_META/ORDER 를
shared/constants/workStatus.ts 단일 소스로 추출(값 동일, 표시 변화 없음).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ScheduleAvatar 가 복제하던 이미지/실루엣 렌더링을 제거하고, 공용 UserAvatar 를
size(px)로 감싸는 얇은 래퍼로 전환. 아바타 표시 로직을 UserAvatar 단일 소스로 통일
(.sa 클래스는 상세 패널 스택 CSS 훅으로 유지, 사용처 변경 없음).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
목록 로딩·빈 상태 박스(state-msg/feed-state/list-empty)를 전역 .empty-state
카드 스타일 + EmptyState 컴포넌트로 통일. 5개 페이지(프로젝트 목록/상세,
내 업무, 활동, 멤버)의 중복 박스 CSS 제거.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
목록 페이지네이션 '더보기' 버튼 마크업/문구를 LoadMore 로 추출(전역 .load-more 사용).
- 프로젝트 목록/상세, 내 업무, 프로젝트 활동 4곳 적용
- 활동 화면의 비표준 .more-row/.more-btn 제거하고 표준 .load-more 로 통일
('더 보기' → '더보기' 문구도 통일)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3개 페이지(활동/프로젝트 상세/멤버)에 반복되던 .segmented 버튼 마크업을
options 기반 SegmentedTabs 로 추출(전역 .segmented 스타일은 그대로 사용).
수량(.n) 표기는 option.count 로 처리.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DropdownSelect·StatusSelect 에 중복되던 fixed 위치 계산·open 토글·
바깥클릭/ESC/스크롤 닫기 로직을 useDropdownMenu 훅으로 추출.
- composables/useDropdownMenu.ts 신설 (align/matchWidth/gap/esc 옵션)
- DropdownSelect, StatusSelect 가 훅을 사용하도록 정리
- 절대배치 메뉴(일정 멀티셀렉트/유형필터/참석자 스택)는 Phase 0 useClickOutside 로 이미 공유
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- components/common/BaseModal.vue 신설: backdrop+헤더(제목/닫기)+본문/푸터 슬롯,
Teleport·ESC·바깥클릭 닫기 내장. 전역 .modal* 와 충돌 없게 bm- 접두 클래스 사용
- relay.css 에 .form-field/-label/-row/-input/-textarea/-select(+wrap/chev) 표준 추가
- 일정·카테고리 모달을 BaseModal + .form-* 로 전환(중복 모달/필드 CSS 제거,
푸터 버튼은 전역 .mbtn 사용)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 툴바 '오늘' 버튼 제거, 컨트롤 간격을 전역 .toolbar(0.625rem)와 통일
- 타임라인 레인 hover 편집/삭제 버튼 제거(카테고리 관리는 유형 필터에서)
- 유형 필터 버튼을 기존 DropdownSelect pill 디자인으로 통일 + 수량 뱃지 제거
- '새 일정' 버튼의 스코프 .btn 재정의 제거 → 전역 .btn primary 표준 사용
- 일정/카테고리 모달을 사이트 폼 모달 규격(rem + 멤버 초대 모달)으로 재정렬,
라벨 좌측정렬, 취소/저장 버튼을 전역 .mbtn 으로 통일
- 참석자 아바타를 공용 UserAvatar 방식(이미지/실루엣)으로 교체,
'전 직원' 표식 크기를 아바타와 동일(20px)하게 고정(루트 14px rem 보정)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
상단 nav 독립 메뉴 '일정' — 주간 타임라인(간트형) 캘린더.
카테고리=레인, 일정=막대(다중일 지원), 우측 상세 패널, 일정/카테고리 CRUD.
백엔드(Schedule 모듈):
- ScheduleCategory/ScheduleEvent 엔티티 + 참석자(다대다) + 작성자
- 카테고리/일정 CRUD, 기간 겹침 조회, 참석자 풀(전사 사용자)
- 기본 카테고리 12종 onModuleInit 멱등 시드
- 인증 사용자 누구나 관리(전역 일정, 글로벌 관리자 개념 없음)
- 운영 마이그레이션(AddSchedule) 추가, @nestjs/schedule 임포트는 CronModule 로 alias
프론트:
- /schedule 라우트 + 사이드바 nav 항목
- 주간 네비(이전/다음/오늘), 유형 필터·카테고리 관리 드롭다운
- 타임라인/상세 패널/일정 모달/카테고리 모달(hue 슬라이더)/참석자 멀티셀렉트
- schedule.store + useSchedule + scheduleDate 유틸
런타임 검증: dev 부팅·시드(12건)·라우트 매핑 정상, 인증 게이트(401),
일정 생성/조회/수정/삭제 + 참석자/전직원/다중일 스모크 전부 정상.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
활발한 프로젝트/업무에서 활동이 한 번에 전부 내려와 렌더링되던 문제 보완.
- 업무 상세 활동 탭: 최신 100건으로 조회 상한 추가(기존 무제한)
- 프로젝트 활동 피드: 200건 통째 조회 → 오프셋 페이지네이션 전환
- 컨트롤러 page/size 쿼리 지원, 서비스 findAndCount
- 프론트 스토어 누적 + hasMore/loadMore, 활동 페이지 "더 보기" 버튼
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
보고 제출 시 알림만 보내고 활동(activity)에는 적재되지 않아
프로젝트 활동 피드·업무 활동 탭에 표시되지 않던 누락을 보완.
- ActivityType/ApiActivityType 에 task.checkpoint_reported 추가
- submitCheckpointReport 에서 activity.record 호출
- 프론트 활동 렌더링 케이스(프로젝트 피드/업무 탭) 추가
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
보고 완료 상태에서 배지 클릭으로만 열리던 것을 명확히 — 배지 오른쪽에 보고서 아이콘 버튼 추가, 아이콘 클릭 시 보고 모달 오픈(열람 권한자만). 배지는 상태 표시 전용으로 변경.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
시안(진행 상태 보고서/받은 진행 보고) 기준으로 두 모달 전면 개편:
- 전체 탭 + 카테고리 탭(색상 dot·건수), 전체 탭에서 카테고리별 그룹 헤더로 묶음
- 작성(작업자): 항목별 상태색 드롭다운(StatusSelect, body Teleport), 보고 메모, 하단 상태 요약(대기/진행/완료 N)
- 열람(지시자·담당자): '진행 보고 도착' 태그 + 보고자 아바타/이름/점검일·시각, 읽기전용 상태 배지, 보고자 메모 박스
- 신규 StatusSelect 컴포넌트 추가, 기존 cp-modal/ws-* 스타일 정리, 미사용 DropdownSelect import 제거
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 상세 우측 상단 액션(수정 버튼 + 더보기 메뉴) 전체를 isIssuer 일 때만 노출
- 더보기 메뉴에서 업무 복제·링크 복사 제거, 업무 삭제만 유지
- 편집 화면(/edit) 진입을 지시자 본인만 허용(그 외 상세로 리다이렉트). 생성 모드는 기존대로 관리자만
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
보고서 작성 모달의 취소/보내기 버튼을 커스텀 소형 버튼 → 전역 .btn / .btn primary(height 2.25rem)로 교체해 다른 화면과 크기 통일.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DropdownSelect 메뉴를 absolute → body Teleport + fixed 위치 계산으로 변경.
스크롤/overflow 컨테이너(보고 모달 등) 안에서도 메뉴가 잘리지 않음(스크롤·리사이즈 시 닫힘).
보고 열람/작성 모달 max-height 를 calc(100vh - 3rem) 로 확대.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
인라인 보고서 폼 제거 → '보고서 작성' 클릭 시 모달로 띄움.
모달 내 항목은 필수/관리/보안/부가 탭으로 구분해 항목별 상태를 선택하고 메모와 함께 전송.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
보고 '내용' 열람을 지시자 + 해당 업무 담당자로 제한:
- 백엔드 buildDetail: viewerId 기준으로 권한 없으면 checkpointReports 를 빈 배열로 응답(findOne 에 현재 사용자 전달). 점검일에는 reported 플래그를 두어 상태는 전원 공유
- 프론트: checkpointState 는 reported 플래그 기준, '보고 완료' 클릭(모달)은 지시자·담당자만. 그 외는 비클릭 상태 배지
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>