# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. # slack-notifier Gitea/Notion webhook 알림을 담당자에게 Slack 개인 DM으로 중계하는 **Go(Gin)** 서버. 워크스페이스 규칙은 상위 [../CLAUDE.md](../CLAUDE.md) 참고. ## 스택 / 실행 - **Go 1.26 (Gin)** — 버전은 mise로 관리(`mise use go@1.26`) - 관리 UI: 표준 `html/template` + HTMX (Node 빌드 불필요), 템플릿은 `go:embed`로 바이너리에 포함 - 명령은 `Makefile`에 정리되어 있음(환경은 명령어로 분기, `APP_ENV`에 의존 안 함): - `make run-dev` / `make run-prod` — `go run . -env {dev,prod}` (dev=text·debug·콘솔, prod=JSON·info·`logs/app.log`) - `make test` (`go test ./...`) · `make vet` · `make fmt`(`gofmt -w .`) - `make build`(현재 OS) · `make build-linux ARCH=arm64|amd64`(EC2 배포용 정적 바이너리, 기본 arm64/Graviton) - 단일 테스트: `go test ./internal/gitea -run TestName -v` (테스트는 현재 `internal/gitea`에만 있음) - 헬스체크 `GET /health`, 관리 페이지 `http://localhost:8000/admin/mappings` - 배포: `docker compose up --build`(distroless, host:6000→컨테이너:8000) 또는 `deploy/`의 systemd+Caddy. 외부 접근은 HTTPS 필요. ## 구조 ``` main.go # 조립: config → mapping/slack/notion → server.Run internal/ config/ config.go # env 설정 (.env, godotenv) + 환경/로그 기본값 logging/ logging.go # log/slog 환경별 설정 + Gin 액세스로그 미들웨어 security/ security.go # HMAC-SHA256 서명 검증 (Gitea/Notion 공용) slack/ slack.go # users.lookupByEmail + chat.postMessage(DM), email 캐시 notify/ notify.go # Notification 모델 + Block Kit 헬퍼 mapping/ mapping.go # 수동 매핑 스토어 (data/mappings.json, thread-safe) gitea/ gitea.go(+test)# Gitea 이벤트 → 담당자 이메일/로그인 + 메시지 notion/ notion.go # Notion 이벤트 → 페이지 People 속성 → 이메일 server/ server.go # Gin 엔진, 라우트, deliver() webhooks.go # POST /webhooks/{gitea,notion} admin.go # /admin/mappings (GET/POST/DELETE, HTMX) templates/ # mappings.html (embed) data/mappings.json # 런타임 매핑 데이터 (gitignore) deploy/ # 비-Docker 배포: slack-notifier.service(systemd) + Caddyfile(HTTPS 리버스 프록시) + run.sh ``` ## 핵심 동작 - 담당자 해석 순서: **수동 매핑(이메일→, 로그인→)** 우선, 없으면 원래 이메일 그대로 → Slack 조회. - 못 찾으면 `DEFAULT_SLACK_CHANNEL` fallback, 그것도 없으면 skip(로그만). - 모든 webhook은 raw body 기준 HMAC-SHA256 검증. secret 미설정 시 검증 skip(개발용, WARN 로그). - Notion은 최초 구독 시 받은 `verification_token`을 로그에서 확인해 `.env`에 넣어야 정상 검증됨. - 관리 페이지에서 추가/삭제한 매핑은 즉시 `data/mappings.json`에 저장. - 환경은 **실행 명령어 `-env` 플래그로 분기**(`go run . -env prod`). 값은 `dev`|`prod`(긴 형태 development/production도 정규화됨). 미지정 시 `APP_ENV` → `dev` 순 fallback. - 환경별 `.env` 로드: `.env.{env}.local` → `.env.{env}` → `.env`(앞이 우선). 예: `.env.dev`, `.env.prod`. - 로깅은 `log/slog` 표준 라이브러리. 환경별로 결정: - `dev` → text 포맷 + debug 레벨 + Gin debug 모드, **콘솔(IDE)만 출력** - `prod` → JSON 포맷 + info 레벨 + Gin release 모드, **`logs/app.log` 파일로 추출**(+ stdout) - `LOG_LEVEL`/`LOG_FORMAT`/`LOG_FILE`로 개별 오버라이드. 코드에선 `slog.Info/Warn/Error` 사용(표준 `log` 금지). - `LOG_FILE` 지정 시 부모 디렉터리는 자동 생성, stdout과 파일에 동시 기록. dev 기본값은 빈 값(콘솔만). - 파일은 **날짜별로 회전**됨: `LOG_FILE=logs/app.log` → 실제 기록은 `logs/app-YYYY-MM-DD.log`. 날짜가 바뀌면 새 파일 생성, `LOG_RETENTION_DAYS`(기본 7)일치만 보존하고 초과분 자동 삭제. 구현은 `internal/logging/rotate.go`(표준 라이브러리만, 외부 회전 의존성 없음). ## 작업 시 주의 - 이벤트별 "담당자" 로직은 제품 정책에 가까움. 새 이벤트/대상 규칙은 `internal/gitea`·`internal/notion`의 `BuildNotifications`에 추가하고, 가능하면 테스트(`*_test.go`)도 같이. - 메시지는 한국어 + Block Kit(`notify.SimpleBlocks`). - 비밀값(`SLACK_BOT_TOKEN`, secret, Notion 토큰)은 `.env`로만 관리, 커밋 금지(`.gitignore` 확인). - 저사양 타겟이므로 무거운 의존성 추가 자제. 라우터는 Gin, 그 외는 표준 라이브러리 위주.