42 Commits

Author SHA1 Message Date
13e95f4ace feat(rails): GIT_RAW_ALLOWED_HOSTS env 로 파일 프록시 allowlist 외부화
- 기존에는 git.nabomhalang.co.kr 한 곳만 하드코딩되어 있었음
- GIT_RAW_ALLOWED_HOSTS=comma,separated,hosts 로 여러 호스트 지원
- 기본값은 기존과 동일 (git.nabomhalang.co.kr) — 행동 변화 없음
- hanarang-rails v0.1.3 의 외부 배포 친화 패키지와 세트
2026-04-10 21:52:11 +09:00
9a99a8a33c feat(rails): MD 파일 클릭해서 뷰어 모달로 내용 보기
- backend: /api/rails/file-content 프록시 (Gitea host allowlist)
- frontend: FileViewerModal — 마크다운/코드 렌더링, front matter 파싱
- drawer: FileRow 클릭 핸들러 + 호버 효과
  - .md 로그는 resultJson에서 직접 표시
  - 추출된 코드 파일은 rawUrlBase로 백엔드 프록시 페치
2026-04-10 21:09:38 +09:00
a7cb728602 feat(dashboard): SIEM log + escalations + office collaboration lines
B - SIEM 로그 + 경보:
- backend/rails: GET /api/rails/transitions (filter by pipelineId, eventType)
- backend/rails: GET /api/rails/escalations (filter by resolved)
- frontend/app/rails/log/page.tsx — 결정론적 이벤트 스트림
    필터: pipelineId / eventType / 초기화
    timestamp / event badge / pipeline pill / state transition / 클릭 → 필터링
    이벤트 타입별 색상 (REQUEST_CHANGES=주황, ERROR=빨강, 등)
- frontend/app/rails/escalations/page.tsx — 경보 카드 뷰
    탭: 전체 / 미해결 / 해결됨
    카드: reason, category 태그, attempts, stage, 시간
    context snapshot 펼침 (JSON pretty)
- sidebar: 로그 / 경보 메뉴 추가

C - Office collaboration lines:
- OfficeFloor 의 4자매 책상 위에 SVG overlay
- harang→narang→narang→darang→darang→erang 흐름선
- active stage 가 있으면 점선 애니메이션 (flowDash keyframe)
- 비활성 시 흐릿한 정적 점선
- 화살표 마커로 방향 표시
2026-04-10 18:28:07 +09:00
5ec1287792 feat(rails): node detail drawer — click any sub-task to inspect
Backend:
- rails.service.ts: getSubTaskDetail(id) - calls rails GET /api/sub-tasks/:id
- rails.controller.ts: GET /api/rails/sub-tasks/:id

Frontend:
- components/rails/SubTaskDetailDrawer.tsx — slide-in drawer
    Header: role badge, title, close button (ESC)
    Body: state/agent/model/duration/complexity grid,
          description, error, result JSON
          children list
          event log timeline (color-coded by event type)
- components/rails/SubTaskTree.tsx: clickable Node, hover state, onSelectNode prop
- app/rails/page.tsx: detailNodeId state, drawer mount
- app/office/page.tsx: same drawer wired to its sub-tree

ESC key closes drawer. Backdrop click closes.
2026-04-10 17:59:16 +09:00
80598e7b58 feat(rails): integrate hanarang-rails orchestrator into dashboard
Backend:
- src/rails/rails.service.ts — HTTP client for rails API (read-only)
- src/rails/rails.controller.ts — REST under /api/rails/* (JwtGuard 보호)
    GET /pipelines, /pipelines/:id, /pipelines/:id/sub-tasks, /health
    POST /pipelines/start, /pipelines/:id/abort
- src/rails/rails.scheduler.ts — 2초마다 rails poll → EventEmitter2 broadcast
- src/rails/rails.module.ts — module + DI
- events.gateway.ts — rails.* 이벤트 핸들러 3종 (Socket.IO 'rails:*')
- app.module.ts — RailsModule 등록

Frontend:
- lib/useRailsSocket.ts — Socket.IO 훅 (rails:pipelines / pipeline:updated / subtasks)
- components/rails/PipelineList.tsx — 좌측 파이프라인 카드 목록
- components/rails/SubTaskTree.tsx — 우측 계층 트리 뷰
    role 별 색상 (manager/principal/lead/junior)
    state 별 dot + running pulse 애니메이션
    duration / model 표시
- app/rails/page.tsx — 라이브 대시보드 페이지
    좌: 파이프라인 목록 + Start 폼
    우: 선택된 파이프라인의 sub-task 트리
- components/common/Sidebar.tsx — '레일' 메뉴 추가

기존 hanarang-dashboard 의 UX/테마 그대로 재사용 (CSS variables).
인증은 기존 JwtGuard 그대로 적용.

검증: backend nest build ✓ | frontend next build ✓ (turbopack)

다음: Dev 서버에 배포 + 첫 라이브 파이프라인 구동 확인.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:30:11 +09:00
54535e7b5e fix: resolve 8 review/security issues (SPRINT-016 hotfix)
Security:
- JwtGuard + RoleGuard on all sisters endpoints
- Admin-only access for config/sessions/subagents/activity
- ThrottlerGuard on /auth/refresh
- HttpOnly SameSite cookies + CSRF (replaces localStorage)

Code Quality:
- Per-sister draft input (Record<SisterName, string>)
- crypto.randomUUID for optimistic message ids (dedupe ready)
- Polling disabled while WebSocket connected
- SVG keyboard accessibility (role/tabIndex/onKeyDown)
2026-04-09 08:51:28 +09:00
58843db298 fix: wire activity.logged event to WebSocket broadcast
Add @OnEvent('activity.logged') listener in EventsGateway to bridge
EventEmitter2 → WebSocket activity:new broadcast. Restores real-time
activity push without reintroducing circular dependency.
2026-04-08 14:14:01 +09:00
d8f2818e59 fix: break circular dependency between Events↔Sisters↔Activity
- Replace EventsGateway direct dependency in ActivityService with EventEmitter2
- ActivityModule no longer imports EventsModule (cycle broken)
- Register EventEmitterModule in AppModule
- Update activity.service.spec.ts to provide EventEmitter2
- SistersModule safely imports ActivityModule without creating a cycle

Dependency graph after fix:
  EventsModule → SistersModule → ActivityModule (leaf, no back-edge)
2026-04-08 14:07:19 +09:00
88547e9464 fix: wire office dashboard to runtime state 2026-04-08 13:49:26 +09:00
441f590989 fix: correct dashboard freshness wiring 2026-04-06 20:45:41 +09:00
6596090677 fix: tighten dashboard copy and freshness labels 2026-04-06 20:40:59 +09:00
a8ff05c96a fix: stabilize backend prisma and lint 2026-04-06 20:21:40 +09:00
90ab555915 fix: source dashboard ops from real logs 2026-04-06 20:04:20 +09:00
42f76d9f04 fix: add JWT_SECRET to backend/.env.example 2026-04-06 12:31:54 +09:00
20f1416ede feat: implement sprint 014 hermes renewal 2026-04-05 16:29:56 +09:00
671b13cdad fix: repair dashboard graph and task assignees 2026-04-05 13:31:50 +09:00
91e3165dd3 fix: restore dashboard mobile charts and project detail metadata 2026-04-05 09:28:06 +09:00
a40b6eda32 feat(sprint-013): 자매 관리/타임라인/선택 UX 정리
TASK-057: 자매 상세 설정 탭 제거 (개요/세션/활동/하네스/로그만 유지)
TASK-058: 관리 > 자매 관리 카드 이모지 제거, SisterAvatar 적용
TASK-059: 프로젝트 상세 이력 API/history 추가, Sprint + Hotfix timeline 표시
TASK-060: GlobalStyle에 user-select 정책 추가 (기본 none, 편집/로그/입력/코드만 text)

테스트 23/23 pass, FE 16 routes build 성공
2026-04-04 21:14:16 +09:00
ad0b489633 feat(sprint-012): 프로젝트 UI 재설계 + 자매 상세 탭 통합 + 대시보드 그래프
TASK-052: 프로젝트 목록 3구역 구조로 재배치 (avatar/name-desc | progress+sprint counts | status+updated)
TASK-053: 프로젝트 대표 avatar를 자매 프로필 사진으로 교체 (ownerSister 기반)
TASK-054: 자매 상세 탭에 세션/활동/하네스/로그 통합
TASK-055: 메인 대시보드에 실데이터 막대 그래프 2종 추가 (sister load, project progress)
TASK-056: 관리자 상단 탭에서 하네스 제거 (자매 상세로 이동)

테스트 23/23 pass, FE 16 routes build 성공
2026-04-04 20:54:45 +09:00
16660e5611 fix(hotfix-003): 자매 상세 hero 확대 + activity raw stderr 사용자 친화화
TASK-046: /sisters/[name] 상단 프로필 hero 재디자인, avatar 120px 확대
TASK-047: 개요 레이아웃 우선순위 재정렬 (hero → system summary → activity)
TASK-048: ActivityService sanitize 추가
  - stderr/bash command not found/raw 내부 오류 직접 노출 금지
  - 원격 노드 연결 실패 메시지 사용자 친화화

테스트 23/23 pass, FE 16 routes build 성공
2026-04-04 19:46:58 +09:00
3ce7169c21 fix(hotfix-002): Sprint task count/완료 수 파싱 보정
TASK-044: sprint 문서에서 실제 task heading/list 파싱
  - ### TASK-001: ...
  - - [ ] TASK-001 ...
  - - [x] TASK-001 ...
  - - TASK-001: ...
  - TASK-001: ...
  - 중복 taskId 방지
TASK-045: Sprint status done이면 task status 정보 없을 때 done fallback
  - parsed task를 DB Task 테이블 upsert
  - 프로젝트 상세의 태스크 수/완료 수 정상 반영 기반 마련

테스트 23/23 pass, FE 16 routes build 성공
2026-04-04 18:34:38 +09:00
b85ca55482 fix(sprint-011): 진행률 실제 계산 + Sprint status QA 기반 파싱 + 아바타 공통 컴포넌트
TASK-040: SprintSyncService .qa/SPRINT-XXX-review-*.md PASSED 여부로 status 결정
TASK-041: ProjectsService 진행률을 Sprint done수/전체Sprint수 기반으로 수정
TASK-042/043: SisterAvatar 공통 컴포넌트 생성, 대시보드/자매/상세 페이지 적용
  - onError 시 이니셜 fallback으로 전환 (숨기기 제거)
  - API_URL 기반 src 사용

테스트 23/23 pass, FE 16 routes build 성공
2026-04-04 17:43:51 +09:00
176cb51f8a feat(sprint-010): API Key 완전 제거 + JWT 전용 정리 + 죽은 코드 청소
TASK-036: admin/layout.tsx API Key UI 완전 제거
TASK-037: adminFetch JWT 전용 단순화 (api key fallback 제거)
TASK-038: ApiKeyStrategy, ApiKeyGuard, CompositeGuard 제거
  - api-key.strategy.ts, api-key.guard.ts 파일 삭제
  - 모든 컨트롤러 @UseGuards JwtGuard로 전환
  - AuthModule에서 ApiKey 관련 providers 제거
TASK-039: PUBLIC_PATHS에서 /register 제거, login FooterLink dead code 제거

테스트 23/23 pass, FE 16 routes build 성공
2026-04-04 17:24:32 +09:00
39c1cdd6f1 fix(sprint-009): B1 repoUrl trailing slash 정규화 + B2 status 파싱 범위 제한
B1: repoUrl.replace(/\/+$/, '').split('/').pop() — trailing slash 안전 처리
B2: parseSprintMd status를 'Status: value' 명시 라인만 파싱 (전체 본문 검색 제거)

테스트 23/23 pass
2026-04-04 17:11:23 +09:00
9135dc59f9 feat(sprint-009): 회원가입 제거 + Sprint 동기화 + 진행률 + 아바타 버그 수정
TASK-032: /register → /login redirect, register API/로직 제거
TASK-033: SprintSyncService(.plans/sprints/ 파싱), /api/projects/:id/sync-sprints, sync-all
TASK-034: 프로젝트 목록 SPRINT SYNC 버튼 추가, Gitea sync 시 Sprint 자동 동기화
TASK-035: 아바타 onError 처리, 캐시 실패 시 삭제 로직 추가

테스트 23/23 pass, FE 16 routes build 성공
2026-04-04 17:01:19 +09:00
ce4f39ced7 Merge pull request 'SPRINT-008: 실시간 자매 시스템 정보 + 설정 + 스켈레톤 UI (최종 Sprint)' (#4) from feature/sprint-008 into main 2026-04-04 16:40:51 +09:00
cc5c74d75a fix(sprint-008): B1 Settings키 필터링 + B2 SistersScheduler 중복 제거 + B3 반영
B1: saveAll()에서 DEFAULT_SETTINGS 키만 허용 (임의 키 삽입 차단)
B2: EventsScheduler가 이미 동일 역할 수행 — SistersScheduler 제거
B3: SistersScheduler 제거로 clearInterval 이슈 함께 해소

테스트 26/26 pass, build 성공
2026-04-04 16:37:47 +09:00
abef8576fe feat(sprint-008): 실시간 자매 정보/아바타/설정 DB 연동
- TASK-028: /api/sisters/:name/system 추가, 자매 페이지 uptime/cpu/memory/disk 실시간화
- TASK-029: /api/sisters/:name/avatar 추가, SSH avatar fetch + 5분 캐시 + SVG fallback
- TASK-030: SystemSettings 모델 + /api/admin/settings GET/PUT + FE settings DB 연동/토스트
- TASK-031 일부: 대시보드/자매/설정 스켈레톤 UI + 에러 fallback
- 30초 자매 상태 websocket 브로드캐스트 시작

테스트 26/26 pass, build 성공
2026-04-04 15:56:12 +09:00
ded66c5cb6 fix: CORS origin + EventsGateway getClientCount null safety 2026-04-04 06:50:17 +00:00
035ba96381 fix(sprint-007): B1 commits limit NaN clamp(1~100) 2026-04-04 15:40:08 +09:00
a942f4e62d feat(sprint-007): Gitea 연동 + 활동 로그 자동 기록
Sprint 006 non-blocking:
- N2: AuthContext 401 시 refresh token 자동 재발급
- N3: login 후 /me API로 실제 userId 조회
- N4: register refreshToken localStorage 저장

TASK-024: Gitea 동기화
- GiteaSyncService: syncRepos() (Project upsert + ActivityLog)
- POST /api/admin/gitea/sync + GET /api/admin/gitea/status
- GiteaSyncModule (CompositeGuard + @Roles('admin'))

TASK-025: Commit/Branch/PR API
- GiteaService 강화: getCommits, getBranches, getPulls
- GiteaCommit/GiteaBranch 인터페이스 추가
- GET /api/projects/:id/{commits,branches,pulls}

TASK-026: 프로젝트 FE
- /projects: GITEA SYNC 버튼 + sync 결과 표시
- /projects/[id]: Overview/Commits/Branches/PRs 탭

TASK-027: 활동 로그 자동 기록
- SistersService: 상태 변경 시 ActivityLog 자동 기록 (@Optional ActivityService)
- GiteaSyncService: sync 시 new_repo/sync_complete 로그
- /activities: 실제 API 연결 확인 (하드코딩 없음)

테스트 26/26 pass, FE 16 routes build 성공
2026-04-04 15:34:27 +09:00
nabomhalang
e0fd04b4f1 fix: API Key strategy returns admin role for RoleGuard compatibility 2026-04-04 06:23:44 +00:00
2089283386 fix(sprint-006): Critical 보안 이슈 5건 수정
B1(Critical): JWT_SECRET 'changeme' fallback 3곳 전부 제거
- auth.service.ts / auth.module.ts / events.module.ts: 미설정 시 throw
- events.gateway.ts: 미설정 시 client.disconnect()

B2(Critical): User.role 기본값 'admin' → 'viewer'
- Prisma schema @default('viewer')
- RoleGuard 신규 생성 (Roles 데코레이터)
- AdminController / CostsController @Roles('admin') 적용

B3: WebSocket JWT 실패/미제공 시 client.disconnect()
- 토큰 없으면 즉시 disconnect
- 토큰 있지만 검증 실패해도 disconnect
- FE useSocket: access token을 auth.token으로 전달

B4: refresh endpoint throw Error → BadRequestException (400)

B5: register Throttle 추가 (3회/분, 초대코드 brute-force 방지)
2026-04-04 06:23:44 +00:00
9a86d04731 feat(sprint-006): 버그 수정 3건 + JWT 인증 시스템
TASK-020 버그 수정:
- BUG-1: adminFetch Authorization 헤더 우선순위 수정 (JWT > API Key)
  하네스 저장 실패 에러 핸들링 개선 (401/non-ok 명시적 처리)
- BUG-2: /admin/logs useEffect 초기 로드 추가 (마운트 시 자동 조회)
- BUG-3: costs/record python3 → node/python3/jq fallback 체인

TASK-021 JWT BE:
- User 모델 추가 (Prisma schema)
- AuthService: register(초대코드 검증+bcrypt) / login / refresh / getMe
- JwtStrategy (passport-jwt), JwtGuard, CompositeGuard (JWT+API Key)
- AuthController: /api/auth/{register,login,refresh,me}
- ThrottlerModule: 로그인 5회/분 Rate limiting
- CompositeGuard로 AdminController, CostsController Guard 전환
- EventsGateway: Socket.IO handshake JWT 검증 추가
- 테스트 26/26 pass

TASK-022 FE:
- AuthContext (AuthProvider + useAuth)
- AppShell (AuthProvider + AuthGate 라우트 보호)
- /login 페이지 (터미널 UI)
- /register 페이지 (초대 코드 필드)
- Sidebar: 로그인 사용자명 + 로그아웃 버튼
- FE 16 routes build 성공
2026-04-04 06:23:44 +00:00
nabomhalang
23fd1ecb09 fix: export SistersService from SistersModule for EventsScheduler DI 2026-04-04 03:38:56 +00:00
914903466c feat(sprint-005): cost monitor + WebSocket realtime
Sprint 004 non-blocking:
- null byte 방지 (harness file write)

Sprint 005 본문:
- CostLog Prisma 모델 추가
- TASK-016: GET /api/admin/costs + POST /api/admin/costs/record/:name
  자매별/모델별/일별 토큰 + 예상 비용 (USD), 기간 필터(day/week/month)
- TASK-018: WebSocket Gateway (@WebSocketGateway /ws namespace)
  sisters:update, activity:new 브로드캐스트
  EventsScheduler: 30초 주기 자매 상태 체크 + 브로드캐스트
  ActivityService: 새 로그 생성 시 실시간 브로드캐스트
- TASK-017: /admin/costs 비용 대시보드 (BarChart + 요약 카드)
- 메인 대시보드 useSocket 훅 + 실시간 연결 상태 표시
- 테스트 22/22 pass, FE 12 routes build 성공
- NEXT_PUBLIC_WS_URL env (.env.local.example 업데이트)
2026-04-04 12:28:25 +09:00
fa33308fe4 fix(sprint-004): B1 DTO validation, B2 lines clamp, B3 CORS PUT
B1: UpdateHarnessDto @IsString @IsNotEmpty @MaxLength(50000) 추가
B2: getSisterLogs lines clamp(1~500)
B3: CORS methods에 PUT 추가
2026-04-04 12:18:14 +09:00
033c142c0e feat(sprint-004): admin features + API auth guard
Sprint 003 non-blocking 처리:
- API Key Guard (passport-http-bearer) + AuthModule
- Helmet 적용 (main.ts)
- SisterNamePipe - name 파라미터 Controller 검증
- lib/sisters.ts - formatLastSeen/sisterEmojis/sisterDisplayNames 공통 추출

Sprint 004 본문:
- TASK-012: POST /api/admin/sisters/:name/{restart,reset} (ApiKeyGuard 적용)
- TASK-013: GET/PUT /api/admin/harness/:name/:file (허용 파일 allowlist)
- TASK-015: GET /api/admin/logs/:name
- 관리자 전 API @UseGuards(ApiKeyGuard)
- TASK-014: /admin 자매 관리 (재시작/리셋 + ConfirmModal)
- TASK-014: /admin/harness 하네스 편집 (CodeEditor + 파일트리)
- TASK-015: /admin/logs 로그 뷰어 (LogTerminal + 검색/에러필터)
- /admin/repos 저장소 목록
- AdminLayout (API Key 로컬스토리지 저장)
- 테스트 22/22 pass, FE 11 routes build 성공
2026-04-04 12:11:06 +09:00
4015e5f22f feat(sprint-003): sister detail + org chart + settings viewer
Sprint 002 non-blocking:
- API_URL/POLL_INTERVAL lib/config.ts 공통 추출
- 폴링 간격 NEXT_PUBLIC_POLL_INTERVAL_MS env화

Sprint 003 본문:
- TASK-008: SisterDetailService (config/sessions/subagents/activity 조회)
- TASK-008: GET /api/sisters/:name/{config,sessions,subagents,activity}
- TASK-008: GET /api/org → 조직도 + 파이프라인 데이터
- TASK-009: /sisters 목록 페이지 (카드 클릭 → 상세 이동)
- TASK-009: /sisters/[name] 상세 페이지 (탭: 개요/설정/세션/서브에이전트)
- TASK-009: SisterCard → /sisters/:name 링크 연결
- TASK-010: /org 조직도 페이지 (OrgTree 컴포넌트, 호버 팝업)
- TASK-011: /settings 설정 뷰어 페이지 (자매 선택 드롭다운)
- 테스트 16/16 pass, FE build 성공 (7 routes)
2026-04-04 11:55:14 +09:00
0b23deca48 fix(sprint-002): CR-001 GiteaService graceful fallback, CR-002 DTO validation
CR-001: GiteaService constructor throw 제거
- 토큰 미설정 시 client=null + warn 로그로 graceful fallback
- isAvailable() 가드 추가, 모든 메서드 빈 배열/null 반환

CR-002: DTO class-validator 적용
- CreateSprintDto: @IsNumber @Min(1), @IsString
- UpdateTaskDto: @IsOptional @IsString @IsIn(VALID_STATUSES)
- main.ts: ValidationPipe({ whitelist, forbidNonWhitelisted, transform })
2026-04-04 11:43:35 +09:00
52732e88b9 feat(sprint-002): projects + task ledger + activity feed
Sprint 001 non-blocking 해결:
- N6: npm audit high 패키지 업데이트 (@nestjs/config, @nestjs/cli)
- S1: CORS origin 화이트리스트 (CORS_ORIGINS env)
- S3: DATABASE_URL 미설정 시 즉시 throw
- N2: SSH_KEY_PATH 미설정 시 즉시 throw (하드코딩 fallback 제거)
- N3: API 응답에서 내부 IP 제거
- N7: SshService 에러 메시지 마스킹 (IP 노출 차단)
- N4: theme.ts 색상 SisterCard/StatusBadge에 실제 적용
- N5: Sidebar-MainContent margin 연동 (SidebarContext)
- N9: LayoutShell Client 컴포넌트로 분리

Sprint 002 본문:
- TASK-004: GiteaService (org repo 목록, PR 조회)
- TASK-004: GET /api/projects → Gitea + DB 병합
- TASK-004: GET /api/projects/:id → 상세 + open PRs
- TASK-005: GET /api/projects/:id/tasks → Sprint/Task Ledger
- TASK-005: POST /api/projects/:id/sprints → Sprint 생성
- TASK-005: PATCH /api/tasks/:id → Task 상태 업데이트 + ActivityLog
- TASK-006: GET /api/activity, /api/projects/:id/activity
- TASK-007: /projects/[id] 상세 페이지 (SprintAccordion + TaskTable + 활동탭)
- TASK-007: 메인 대시보드에 프로젝트 섹션 + 활동 피드 추가
- 테스트 11/11 pass
2026-04-04 11:34:04 +09:00
79135f24b0 feat(sprint-001): backend Nest.js + Prisma7 adapter setup, frontend Next.js UI
- Backend: NestJS + Prisma 7 (MariaDB adapter) scaffold
  - PrismaService with @prisma/adapter-mariadb driver
  - SistersService: SSH 상태 체크 with graceful fallback
  - HealthController: GET /health
  - 시드 스크립트: 자매 4명 초기 데이터
  - 테스트 5/5 pass

- Frontend: Next.js 16 + styled-components
  - styled-components SSR registry (next.config 컴파일러)
  - 다크 테마 글로벌 스타일 + 테마 토큰
  - SisterCard: glassmorphism 상태 카드 (온라인 pulse 애니메이션)
  - StatusBadge: 상태 표시 컴포넌트
  - Sidebar: 접이식 네비게이션
  - 대시보드 메인 페이지 (API 미연결 시 mock 데이터 fallback)
  - build 성공 확인

- DB credential 이랑이 대기 중
2026-04-04 11:06:44 +09:00