공용 수정 요청 메시지는 그대로 두고, 검토 모달에서 각 보완 항목 아래에
항목별 보완 내용을 개별 등록할 수 있게 하고 상세 화면에 함께 표시한다.
- 백엔드: ChecklistItem.reviewNote 컬럼 추가, ChecklistReviewDto.note 수용,
requestChanges 가 미완성 항목에 보완 내용 보관(완료/승인 시 비움), 상세 응답 동봉
- 프론트: 검토 모달 보완 항목 아래 보완 내용 textarea(개별), 상세 체크리스트
보완 항목 아래 보완 내용 표시. 공용 메시지 입력은 유지
- 테스트: 미완성 항목 보완 내용 보관·완료 항목 비움 검증(9 tests)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
업무가 '수정 요청됨(changes)' 상태일 때 상세 화면 체크리스트의
미완료 항목을 빨강 X(보완 필요)로 표시해 담당자가 보완 대상을 명확히 보게 한다.
- 완료 항목은 초록 체크, 보완 항목은 빨강 X + '보완 필요' 태그
- changes 상태가 아닐 때는 기존대로 체크/빈 박스 유지
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
지시자 검토 카드의 '승인하기' 버튼과 별도 승인 모달을 제거하고,
단일 '할 일 검토하기' 버튼이 검토 모달을 열도록 통합한다.
- 검토 카드 버튼을 '할 일 검토하기' 하나로 정리(승인하기 제거)
- 미사용이 된 승인 확인 모달·approveTask·showApprove 상태 제거
- 승인은 검토 모달에서 전 항목 완료 시 '승인 완료' 버튼으로 수행
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
시안(수정 요청 모달.html)을 반영해 모달 UI를 재구성한다.
- 헤더(그라데이션 배지·안내)·스크롤 본문·고정 푸터 구조로 변경
- 항목별 완료/보완을 세그먼트 토글(완료=초록 / 보완=빨강 좌측 바)로 표시,
카테고리 그룹·진행률 바·완료 카운트 동봉
- 보완 항목 수에 따라 안내 배너(warn/good)와 메시지 필수 여부가 전환
- 모든 항목 완료 시 버튼이 '승인 완료'(초록)로 바뀌어 곧바로 승인,
보완 항목이 있으면 '수정 요청 보내기 (N건)'(빨강)으로 메시지와 함께 반려
- 모달 진입 시 전 항목을 '완료'로 초기화(담당자가 완료를 주장하며 요청)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
지시자가 승인을 검토하며 수정 요청할 때, 단순 텍스트 입력에 더해
할 일 목록에서 어떤 항목이 완성/미완성인지 체크(✓)·X로 표시할 수 있게 한다.
- 백엔드: ApprovalChangesDto 에 항목별 검토 결과(checklist) 추가,
requestChanges 가 전달된 항목만 done 상태로 반영(미전달 항목은 보존)
- 프론트: 수정 요청 모달에 카테고리별 체크/X 토글 UI 추가, 검토 결과를
note 와 함께 전송
- 테스트: 전달된 항목만 완료 체크가 반영되는지 검증(9 tests)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
업무 지시(생성/편집)·상세 화면의 '해야 할 일'을 AI 추천과 동일한
4개 영역(필수/관리/보안/부가)으로 분류한다.
- 백엔드: ChecklistItem 에 category 컬럼(기본 '필수') 추가, 생성/동기화
DTO·서비스·응답에 category 반영
- 프론트: 생성/편집은 카테고리 탭 + 탭별 추가 입력, AI 추천 항목은
소속 영역으로 매핑해 일괄 추가, 상세는 카테고리별 그룹 표시
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Docker 만 사용하므로 standalone 안내를 정리:
- 프론트 env(.example): '단독 실행 시 주석 해제' 안내 + 주석 처리된 VITE 라인 제거
(VITE_ 값은 compose build arg 로만 주입됨)
- CLAUDE.md: '단독 실행 시 주석 예시 활성화' 규칙 삭제
- README: 사전요구사항/cp 명령/‘단독 실행’ 섹션/env 표의 standalone 문구 제거
(모바일은 compose 비대상이라 별도 실행 안내만 한 줄 유지)
- integration-progress: Redis 폴백 설명의 '단독 실행' 표현을 'REDIS_HOST 미설정 시'로 교정
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 죽은 설정 제거: GITEA_*/REPO_IMPORT_ADMIN_EMAIL (저장소·Gitea 기능 삭제됨)
- 섹션 헤더 스타일을 # === 블록으로 전 파일 통일(루트/백엔드/프론트)
- 루트: AI 섹션(AI_TIMEOUT_MS) 형식 통일 + production 파일에 누락됐던 AI 섹션 추가
- 백엔드: JWT/앱URL/OAuth/AI 4섹션으로 일관 정렬, production 에 누락됐던 URL/OAuth/AI 추가
- 프론트: 빌드 주입 변수 안내(VITE_API_BASE_URL·VITE_AI_TIMEOUT_MS) 명시
- 각 .env 와 .example 의 키·순서·주석을 동일하게(값만 실값/placeholder 차이)
(실제 .env.* 는 gitignore 라 미커밋 — 로컬에선 동일 구조로 함께 정리함)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
근본 원인: useApi 기본 axios timeout 이 10초인데 suggestChecklist 가 이를
덮어쓰지 않아, AI 생성이 10초를 넘으면(항목 제한 해제 후 ~10.5초로 일관 초과)
백엔드가 200 으로 완료해도 프론트가 먼저 끊어 '추천을 가져오지 못했습니다' 발생.
(백엔드 에러 로그가 없던 이유 — 백엔드는 성공했음)
suggestChecklist 호출에 timeout 60000(백엔드 abort 30초보다 길게) 지정.
런타임 측정: 백엔드 suggest 응답 10.48초/HTTP 200 확인.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 프롬프트의 '3~6개씩' 제한 제거 → 카테고리별로 필요한 만큼 제안
- parseSuggestions 의 카테고리당 15개 슬라이스 캡 제거(응답 길이는 max_tokens 가 자연 제한)
- 항목이 늘어 잘리지 않도록 suggest max_tokens 3072 → 4096
런타임 재현: 동일 입력에서 필수8·관리6·보안8·부가6(총 28개)로 더 풍부하게 반환.
백엔드 build/lint 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4개 카테고리(필수/관리/보안/부가) 구조화 JSON 응답이 max_tokens=1024 를
넘으면 중간에 잘려 JSON 파싱이 실패하고 '추천을 가져오지 못했습니다' 로 떴음.
- callClaude 에 maxTokens 파라미터 추가, suggestChecklist 는 3072 사용
- parseSuggestions 파싱 실패/빈 결과 시 원본 일부를 warn 로그로 남겨 진단 가능
런타임 재현: 동일 입력으로 필수5·관리5·보안5·부가4(총 19개) 정상 반환 확인.
백엔드 build/lint 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
백엔드:
- SUGGEST_SYSTEM_PROMPT 를 정확히 4개 카테고리(필수/관리/보안/부가 기능)로 고정
(parseSuggestions 가 빈 카테고리는 자동 제외)
프론트(시안 'AI 추천 모달.html' 반영):
- 그라데이션 헤더(배지 아이콘 + '자동 생성' 뱃지 + 분석 요약 서브타이틀)
- 카테고리별 색상 아이콘 dot + 개수 pill + 전체 추가/해제 토글
- 항목을 체크 토글로 '선택' 후 푸터의 'N개 업무에 추가'로 일괄 반영(기존 즉시추가 → 선택→커밋 모델)
- 이미 체크리스트에 있는 항목은 잠금(added) 표시
- 푸터: 선택 개수 + 취소/추가 버튼(.ai-btn — 페이지 .btn 과 분리)
검증: 백엔드 build/lint 0·8 tests, 프론트 type-check/lint/build 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AI 추천은 제목과 내용을 함께 분석하므로, 둘 중 하나라도 비면 해당 필드에
인라인 에러(빨강 테두리+메시지)를 표시하고 요청을 중단하도록 수정.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
기존: 제목 미입력 시 'AI 추천' 버튼 비활성화(canRequestAi)
변경: 제출 버튼과 동일 로직 — 버튼 상시 활성(분석 중 in-flight 만 disabled),
클릭 시 제목이 비어 있으면 titleError 로 인라인 안내(빨강 테두리+메시지) 후 중단.
사용 안 하게 된 canRequestAi computed 제거.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
borderless 제목 인풋에 has-error 시 빨간 테두리(+가로 패딩) 부여 —
에디터·담당자 필드와 일관. box-sizing:border-box 라 overflow 없음,
세로 패딩 유지로 레이아웃 점프 최소화.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 업무 내용(*)이 표기상 필수인데 검증이 없던 문제 → 필수로 강제
· 프론트: 인라인 검증(에디터 빨강 테두리 + '업무 내용을 입력해 주세요.'),
입력 시 즉시 해제
· 백엔드: CreateTaskDto.content 를 @ArrayNotEmpty 필수로(데이터 계약 일치)
- 제목 에러 표기 정리: 1.5rem 큰 placeholder 가 빨갛게 변하며 아래 메시지와
이중으로 강조되던 것을 제거 → 작은 인라인 메시지만 표시(차분하게)
검증: 백엔드 build/lint 0·8 tests, 프론트 type-check/lint/build 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
기존: 제목·담당자 미입력 시 '지시 보내기' 버튼이 비활성화(이유 안내 없음)
변경:
- 버튼 비활성화 해제(제출 중 중복 클릭 방지용 submitting 만 유지)
- 제출 시 validateForm 으로 검증 → 미입력 필드에 인라인 에러 표시
· 제목: 빨강 placeholder + '업무 제목을 입력해 주세요.'
· 담당자: combo 빨강 테두리 + '담당자를 1명 이상 지정해 주세요.'
- 해당 필드를 채우면 watch 로 에러 즉시 해제
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
기존: 체크리스트 아래에 인라인으로 펼쳐지던 AI 추천 패널
변경: Teleport 기반 중앙 모달(반투명 배경, 헤더 고정 + 본문 스크롤).
배경 클릭/× 로 닫기(분석 중에는 닫기 비활성). 추천 항목 추가 동작은 동일.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ProjectMemberService 의 notify payload 에 actorName 이 빠져 있어, 프론트
notification.store 가 actorName 부재 시 '누군가'로 폴백하던 문제.
세 member.* 알림(invited/role_changed/removed) payload 에 actorName 추가
(actingUserId 로 사용자명 조회하는 actorName 헬퍼 신설). 활동 피드는 actor
관계로 별도 해결되므로 영향 없음.
런타임 검증: 초대 시 수신자 알림 payload.actorName = 초대자 이름으로 채워짐.
백엔드 build/lint 0·8 tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
저장소 기능 제거 후 남은 '저장소' 표현을 프로젝트로 통일:
- 백엔드: activity/notification/task 주석·ApiResponse 문구, AI 시스템 프롬프트
(SUGGEST_SYSTEM_PROMPT 의 저장소→프로젝트, 무의미해진 'slug=영문이름' 지시 제거),
CONTEXT_REPO_LIMIT→CONTEXT_PROJECT_LIMIT(프로젝트 컨텍스트 한도)
- 프론트: 페이지/스토어 주석 및 TaskCreate/TaskDetail 의 사용자 노출 문구('저장소'→'프로젝트')
- 단, auth OAuth state 'store' 의미의 '저장소'(cookie-state/strategies)는 정당하여 유지
검증: 백엔드 build/lint 0·8 tests, 프론트 type-check/lint/build 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
복잡도를 줄이기 위해 저장소 연동 기능을 전부 제거하고 프로젝트를 단독 단위로 운영한다.
백엔드:
- modules/repo, modules/gitea 모듈 전체 삭제(엔티티/서비스/컨트롤러/DTO/역방향 동기화)
- app.module 에서 RepoModule 제거
- ProjectService: repoCount 집계·repoRepo·"미분류" 시스템 프로젝트(ensureUnassigned/
onApplicationBootstrap)·isSystem 게이트 전부 제거. ProjectResponse 에서 repoCount/isSystem 제거
- Project 엔티티 is_system 컬럼 제거(dev synchronize 가 DROP)
- ProjectModule forFeature 에서 Repo 제거
- Activity 타입 repo.linked/unlinked 제거
- env example 에서 Gitea/REPO_IMPORT 섹션 제거
프론트:
- ProjectReposPage, useRepo 삭제. ProjectTabs 의 '저장소' 탭·repoCount prop 제거
- 4개 페이지의 :repo-count 제거, 라우트 /projects/:id/repos 제거
- types/project·project.store·mock 에서 repoCount/isSystem·Repo 뷰 제거
- ProjectListPage 저장소수/시스템 배지·gitea CSS 제거, activity 의 repo.* 케이스 제거
- types/repo 는 공용 ApiMember 만 유지
- 잔여 '저장소'/Gitea 사용자 문구를 프로젝트로 정리
검증: 백엔드 build/lint 0·8 tests, 프론트 type-check/lint/build 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
세 겹의 제한을 모두 분당 1000회로 상향(테스트 중 429 회피):
- main.ts express-rate-limit: 15분 150회 → 1분 1000회
- 전역 ThrottlerModule: 분당 100회 → 1000회
- 라우트별 @Throttle(login/signup/resend/forgot/reset/ai): 3~20회 → 1000회
각 라우트 주석에 운영 권장값을 남겨 추후 복원/ env 화 용이.
운영 배포 전 적정값으로 되돌릴 것.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ProjectReposPage 가 .crumb .lnk(accent색)·.sep(여백) 를 로컬로 덮어써 다른 탭과
달라 보이던 것을 제거 → 전역 relay.css 의 crumb 스타일(text-2 링크·opacity 구분자)
을 따르도록 통일.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 필드 순서 변경: 표시 제목(name)을 최상단으로(기존 slug 가 최상단)
- 템플릿을 체크박스 → 기존 셀렉트 구조로 복원
(없음[빈 저장소] / {템플릿slug} 템플릿, 가용 시에만 옵션 노출)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 인증 링크(verify-email)의 리다이렉트 대상을 /login?verified → /email-verified?ok=1|0 으로 변경
- 신규 EmailVerifiedPage(/email-verified): 인증 완료/실패 표시 후 창 자동 닫기 시도.
브라우저가 사용자가 연 탭의 close 를 막을 수 있어 안내 문구 + 수동 로그인/가입 링크 병행
- SignupPage 인증 대기 화면에 '인증을 완료했어요 · 로그인하러 가기' 기본 버튼 추가
(다른 탭에서 인증을 마친 뒤 기존 화면에서 로그인 진입)
런타임 검증: 유효 토큰→/email-verified?ok=1·무효→ok=0, 인증 후 로그인 200, SPA 라우트 제공.
백엔드 build/lint 0, 프론트 type-check/lint/build 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 시안(비밀번호 찾기.html) 적용 — 좌측 브랜드 패널 + 우측 폼(로그인 화면과 동일 구조)
- 1단계 이메일 입력(뒤로가기 링크·재설정 링크 보내기) → 2단계 전송 완료
(메일 아이콘·수신 이메일 칩·스팸함 안내 박스·다시 보내기·로그인 복귀)
- 다시 보내기 시 동일 이메일 재요청 + '전송됨 ✓' 일시 피드백
- 시안의 '30분 유효'는 실제 백엔드 토큰 TTL(1시간)에 맞춰 표기
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 백엔드: 앱이 전역 프리픽스 /api 하위라 루트(/) 프로브가 404 → /api/health 프로브로 교정
- 공통: localhost 가 IPv6(::1)로 풀려 IPv4 전용 바인딩에 연결 실패하던 것을 127.0.0.1 고정
- 두 컨테이너가 정상 동작에도 unhealthy 로 표시되던 선존 버그(리팩터 무관)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 데이터 계층 신설: types/project·useProject·project.store (프로젝트 CRUD·페이지네이션)
- useTask/useMember/useActivity 경로를 /projects/:projectId/... 로 전환
- task·my-task·activity 타입/스토어 repoId/repoName → projectId/projectName
- 알림 store 라우팅·문구 프로젝트화, 활동 타입 repo.linked/unlinked·project.* 반영
- 라우팅 /projects/... 전면 교체, / → /projects 리다이렉트
- 페이지 rename Repo*→Project* (List/Create/Detail/Settings/Members/Activity)
- ProjectCreatePage: Gitea 저장소 폼 → 단순 프로젝트 생성 폼으로 재작성
- RepoHeader→ProjectHeader, RepoTabs→ProjectTabs, AppShell 네비 프로젝트화
- 죽은 파일 삭제: repo.store·useRepo·GiteaRepoBar
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
저장소=프로젝트 1:1 구조를 프로젝트 우선 + 프로젝트 1:N 저장소로 전환하는 리팩터의 기반.
기존 코드는 건드리지 않고 추가만 함(기존 저장소 기반 동작 유지).
- Project / ProjectMember 엔티티 (isSystem '미분류' 버킷, admin/member/owner)
- ProjectService: CRUD + 권한 헬퍼(assertProjectMember/Admin) + 부팅 시 '미분류' 시스템 프로젝트 보장
- ProjectMemberService: 초대/역할/제거 (활동·알림 배선은 Activity 이관 단계 TODO)
- /projects, /projects/:id/members 라우트, app.module 등록
- docs/project-refactor-plan.md (리팩터 SSOT)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
통짜 코드 전송 방식이 토큰 비효율·부정확해, 검색 기반(grep으로 좁힌 뒤 관련
스니펫만 판정) 방식으로 재설계하기 위해 일괄 제거. 추후 개선안으로 재작업 예정.
This reverts commit 85ae82f.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
업로드 API 가 기존 taskId 종속이라 막혀 있던 생성 화면 첨부를 2단계 제출로 해결.
선택한 파일을 메모리에 보유하다 업무 생성/수정 후 그 taskId 로 순차 업로드(베스트에포트,
실패 개수 안내). 수정 모드는 기존 첨부 표시·즉시 삭제 + 새 파일 업로드. 25MB 사전 필터.
백엔드 변경 없음(기존 업로드 엔드포인트 재사용).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- POST /ai/suggest-checklist — 저장소 표시제목/설명 + 업무 제목/내용을 Claude 에 보내
카테고리별(필수/추가/보안) 할 일 항목을 JSON 으로 받아 파싱(코드펜스/잡텍스트 방어, 빈 결과 502)
- AiSuggestController + SuggestChecklistDto + AiService.suggestChecklist/parseSuggestions
- 프론트: TaskCreatePage 액션바 "취소 / AI 추천 / 지시 보내기" + 체크리스트 추천 패널
(카테고리별 항목 클릭 추가·전체 추가·중복 스킵), useAi.suggestChecklist(silent)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 컨텍스트에 저장소 목록 추가(RepoService.findAll), slug 빼고 표시 제목만 노출
- AI 응답 마크다운 렌더링: shared/utils/markdown.ts (escapeHtml 후 신뢰 태그만 조립, 의존성 0, XSS 안전 — 굵게/목록/코드/제목/링크)
- 시스템 프롬프트: 간결·이모지/사과 남발 금지·과도한 존칭 지양·마크다운 사용·저장소는 표시제목으로 안내
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>