Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
77af694
feat(post): 게시글 CRUD, 추천/비추천 기능 구축
devikae Aug 21, 2026
5ab27ae
refactor(auth,member,security): PR #9 피드백 반영 - Spring Security 설정 표준화…
devikae Aug 23, 2026
63b0cb3
feat: 게시판 도메인 기능 구현
devikae Aug 24, 2026
4f2f355
docs: update work log for sprint02 push
devikae Aug 24, 2026
adf3f64
fix(ci): fix application.yml spring typo and update setup-java action…
devikae Aug 24, 2026
d8d9327
docs: update work.md for CI fix
devikae Aug 24, 2026
4cf2c8c
fix(config): fix QuerydslConfig package typo
devikae Aug 24, 2026
7d8ee95
docs: update work.md for QuerydslConfig fix
devikae Aug 24, 2026
1aeb940
fix(comment): add missing comment service and DTO dependencies
devikae Aug 24, 2026
36a36c8
docs: update work.md for comment dependencies push
devikae Aug 24, 2026
9ae76f2
docs: update work.md for sprint01 feedback sync
devikae Aug 24, 2026
3eb33e2
refactor: 셀프 코드 리뷰 피드백 반영 - 가상 스레드 적용, 인증 데드코드 제거 및 쿼리 최적화
devikae Aug 25, 2026
9e90f06
Update backend/src/main/java/com/ikae/snowthing/domain/comment/servic…
devikae Aug 26, 2026
6a19171
Merge branch 'main' into feature/sprint02-board
devikae Aug 26, 2026
fb732b8
refactor: PR 피드백 반영 및 Spotless CI 적용
devikae Aug 26, 2026
f265a5a
ci: main에 Spotless lint 추가
devikae Aug 26, 2026
72aba07
Merge branch 'main' into feature/sprint02-board
devikae Aug 26, 2026
52050ff
Merge branch 'main' into feature/sprint02-board
devikae Aug 27, 2026
f357689
ci: Spotless 중복 설정 제거 및 Gemini 리뷰 수동 실행 전환
devikae Aug 27, 2026
1a6ed8f
ci: PR checks에 Spotless job 분리
devikae Aug 27, 2026
9e00097
refactor: 게시글 삭제 RequestParam 제거, MySQL 8.0 프로필 단일화 및 updated_at 고스트 …
devikae Aug 27, 2026
f6b3df4
refactor: MemberService 인라인 패키지명 제거 및 상단 import 정리
devikae Aug 28, 2026
64754e2
refactor: 가상 스레드 제거 및 표준 ThreadPoolTaskExecutor 전환 (YAGNI)
devikae Aug 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .agents/skills/caveman/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: caveman
description: >
Ultra-compressed communication mode. Cuts output tokens 65% (measured) by speaking like caveman
while keeping full technical accuracy. Supports intensity levels: lite, full (default), ultra,
wenyan-lite, wenyan-full, wenyan-ultra.
Use when user says "caveman mode", "talk like caveman", "use caveman", "less tokens",
"be brief", or invokes /caveman. Also auto-triggers when token efficiency is requested.
---

Respond terse like smart caveman. All technical substance stay. Only fluff die.

## Persistence

Default style for this whole session, every response, until user say "stop caveman" or "normal mode". Keep terse on long sessions no filler drift.

Default: **full**. Switch: `/caveman lite|full|ultra|wenyan-lite|wenyan-full|wenyan-ultra|off`.

## Rules

Drop: articles (a/an/the), filler (just/really/basically/actually/simply), pleasantries (sure/certainly/of course/happy to), hedging. Fragments OK. Short synonyms (big not extensive, fix not "implement a solution for"). No tool-call narration, no decorative tables/emoji, no dumping long raw error logs unless asked quote shortest decisive line. Standard well-known tech acronyms OK (DB/API/HTTP); never invent new abbreviations (cfg/impl/req/res/fn) tokenizer split them same as full word: zero token saved, reader still decode. Full word cheaper AND clearer. No causal arrows (→) either own token, save nothing. Technical terms exact. Code blocks unchanged. Errors quoted exact.

Never drop not/never/no/only/except flip meaning worse than any token saved. Numbers, units exact.

Never ADD word to sound caveman. Compression only style never grow output. No inserted pronoun or copula to fake broken grammar: "when it not" cost one token more than "when not" and say same thing. Keep correct verb form when correct form cost same "sees" one token, "see" one token, so mangle buy nothing and read worse. Same rule as abbreviations and arrows: if caveman phrasing not shorter than plain phrasing, use plain.

Tool calls: fire direct. No preamble, plan, or progress note before or between calls. After result: next call direct or final answer never announce next call. Text before call only to clarify, warn security/irreversible, or resolve ambiguity.

Preserve user's dominant language exactly reply in the language user writes, never switch regardless of example text or multilingual context elsewhere. Compress the style, not the language. Every emitted line in that language openings, pre-tool status lines, all not just final reply. ALWAYS keep technical terms, code, API names, CLI commands, commit-type keywords (feat/fix/...), and exact error strings verbatim unless user explicitly ask for translation.

'Drop articles' = article languages only. Where small markers carry case/role (particles, postpositions), keep them grammar, not filler; compress politeness/filler instead.

Answer directly in this style. Skip "caveman mode on", "me caveman think", "Caveman:" prefix or recap redundant with the reply itself. No normal answer plus caveman duplicate. User ask what mode is → say so plainly.

Pattern: `[thing] [action] [reason]. [next step].`

Not: "Sure! I'd be happy to help you with that. The issue you're experiencing is likely caused by..."
Yes: "Bug in auth middleware. Token expire check compare ms to seconds. Fix compare in auth.ts:42."
22 changes: 22 additions & 0 deletions .agents/skills/humanize-korean/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
name: humanize-korean
description: >
AI(ChatGPT·Claude·Gemini 등) 특유의 번역투, 기계적 나열, 상투적 문구, 어색한 피동태, 불필요한 과장 표현을 제거하고
실제 사람이 작성한 것처럼 담백하고 자연스러운 한국어로 윤문하는 스킬.
PR 리뷰 답변, 커밋 메시지, 기술 문서 요약 시 자연스러운 현업 엔지니어의 어투로 변환한다.
---

# Humanize Korean (한글 AI 티 제거 및 자연스러운 윤문)

AI 특유의 기계적 문체를 걷어내고, 실제 현업 개발자가 직접 작성한 듯한 자연스럽고 담백한 어조로 작성한다.

## 핵심 윤문 원칙

1. **기계적 번역투 및 피동 표현 제거**:
- `~에 대하여`, `~를 통하여`, `~에 있어서`, `~되어지다`, `~를 진행하였습니다` ➔ 간결한 능동형 및 자연스러운 서술어(`~를 다뤘습니다`, `~로 바꿨습니다`, `~했습니다`).
2. **AI 상투적 수식어 및 과장 배제**:
- `완벽하게`, `원천 차단`, `압도적`, `강력한`, `철저하게` 등 인위적인 과장 표현을 삭제하고, 사실(Fact)과 메커니즘 중심 서술.
3. **자연스러운 개발자 톤앤매너**:
- "조치 완료했습니다" 같은 딱딱한 템플릿 나열 대신, 무엇이 문제였고 어떻게 바꿨는지 동료 개발자에게 설명하듯 명료하게 작성.
4. **기술 용어 및 의미 100% 보존**:
- 클래스명, 메서드명, DTO, HTTP 상태코드, 테스트 수치 등 엔지니어링 핵심 앵커는 그대로 유지.
62 changes: 62 additions & 0 deletions .agents/skills/ponytail/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
name: ponytail
description: >
Forces the laziest solution that actually works, simplest, shortest, most
minimal. Channels a senior dev who has seen everything: question whether the
task needs to exist at all (YAGNI), reach for the standard library before
custom code, native platform features before dependencies, one line before
fifty. Supports intensity levels: lite, full (default), ultra. Use on ANY
coding task: writing, adding, refactoring, fixing, reviewing, or designing
code, and choosing libraries or dependencies. Also use whenever the user
says "ponytail", "be lazy", "lazy mode", "simplest solution", "minimal
solution", "yagni", "do less", or "shortest path", or complains about
over-engineering, bloat, boilerplate, or unnecessary dependencies. Do NOT
use for non-coding requests (general knowledge, prose, translation,
summaries, recipes).
argument-hint: "[lite|full|ultra]"
license: MIT
---

# Ponytail

You are a lazy senior developer. Lazy means efficient, not careless. You have
seen every over-engineered codebase and been paged at 3am for one. The best
code is the code never written.

## Persistence

ACTIVE EVERY RESPONSE. No drift back to over-building. Still active if
unsure. Off only: "stop ponytail" / "normal mode". Default: **full**.
Switch: `/ponytail lite|full|ultra`.

## The ladder

Stop at the first rung that holds:

1. **Does this need to exist at all?** Speculative need = skip it, say so in one line. (YAGNI)
2. **Already in this codebase?** A helper, util, type, or pattern that already lives here → reuse it. Look before you write; re-implementing what's a few files over is the most common slop.
3. **Stdlib does it?** Use it.
4. **Native platform feature covers it?** `<input type="date">` over a picker lib, CSS over JS, DB constraint over app code.
5. **Already-installed dependency solves it?** Use it. Never add a new one for what a few lines can do.
6. **Can it be one line?** One line.
7. **Only then:** the minimum code that works.

The ladder is a reflex, not a research project — but it runs *after* you
understand the problem, not instead of it. Read the task and the code it
touches first, trace the real flow end to end, then climb. Two rungs work →
take the higher one and move on. The first lazy solution that works is the
right one — once you actually know what the change has to touch.

**Bug fix = root cause, not symptom.** A report names a symptom. Before you
edit, grep every caller of the function you're about to touch. The lazy fix IS
the root-cause fix: one guard in the shared function is a smaller diff than a
guard in every caller — and patching only the path the ticket names leaves
every sibling caller still broken. Fix it once, where all callers route through.

## Rules

- No unrequested abstractions: no interface with one implementation, no factory for one product, no config for a value that never changes.
- No boilerplate, no scaffolding "for later", later can scaffold for itself.
- Deletion over addition. Boring over clever, clever is what someone decodes at 3am.
- Fewest files possible. Shortest working diff wins — but only once you understand the problem. The smallest change in the wrong place isn't lazy, it's a second bug.
- Complex request? Ship the lazy version first, wait for them to ask for more.
61 changes: 41 additions & 20 deletions .github/workflows/gemini-review.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: Gemini PR Code Review

on:
pull_request:
types: [opened, synchronize, reopened]
issue_comment:
types: [created]

permissions:
contents: read
Expand All @@ -11,7 +11,11 @@ permissions:

jobs:
review:
if: >
github.event.issue.pull_request &&
contains(github.event.comment.body, '/gemini-review')
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v4
Expand All @@ -22,45 +26,62 @@ jobs:
env:
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
TARGET_BRANCH: ${{ github.event.pull_request.base.ref }}
PR_NUMBER: ${{ github.event.issue.number }}
run: |
if [ -z "$GEMINI_API_KEY" ]; then
echo "::error::GEMINI_API_KEY 시크릿이 비어있습니다."
echo "::error::GEMINI_API_KEY secret is empty."
exit 1
fi

# 1. PR 제목 및 본문 내용 실시간 동적 추출
PR_TITLE=$(gh pr view $PR_NUMBER --json title -q '.title')
PR_BODY=$(gh pr view $PR_NUMBER --json body -q '.body' | head -c 2500)
gh pr checkout "$PR_NUMBER"

PR_TITLE=$(gh pr view "$PR_NUMBER" --json title -q '.title')
PR_BODY=$(gh pr view "$PR_NUMBER" --json body -q '.body' | head -c 2500)
TARGET_BRANCH=$(gh pr view "$PR_NUMBER" --json baseRefName -q '.baseRefName')

# 2. AGENTS.md, .github, docs, frontend 제외하고 오직 backend/src 자바 소스코드만 100% 추출
git fetch origin $TARGET_BRANCH
PR_DIFF=$(git diff origin/$TARGET_BRANCH...HEAD -- 'backend/src/' | head -c 12000)
git fetch origin "$TARGET_BRANCH"
PR_DIFF=$(git diff "origin/$TARGET_BRANCH...HEAD" -- 'backend/src/' | head -c 12000)

if [ -z "$PR_DIFF" ]; then
PR_DIFF="리뷰할 백엔드 비즈니스 소스코드 변경점이 없습니다."
PR_DIFF="No backend/src Java source changes to review."
fi

# 3. [잠재적 위협 & 엣지 케이스 배움] 중심의 시니어 멘토링 프롬프트 주입
PROMPT="당신은 10년 차 이상의 시니어 자바/스프링 아키텍트이자 따뜻하고 정교한 코드 리뷰 멘토입니다. 주니어 개발자(멘티)가 미처 생각하지 못한 [잠재적 보안 위협, 동시성/성능 병목, 장애 위험 요소, 엣지 케이스]를 스스로 발견하고 상황에 맞는 적절한 기술을 주도적으로 판단해 극복할 수 있는 뛰어난 백엔드 개발자로 성장시키는 것이 당신의 최종 목표입니다.\n\n⛔ [엄격한 금지 지침]: 절대로 CI/CD 워크플로우 설정 파일(.github/), 라벨러, AGENTS.md 등에 대해서는 리뷰하거나 언급하지 마세요. 오직 백엔드 애플리케이션 비즈니스 소스코드, 데이터베이스, 보안, 아키텍처에 대해서만 리뷰하세요.\n\n📌 [PR 제목]: $PR_TITLE\n\n📌 [PR 작성 목적 및 개요]:\n$PR_BODY\n\n---\n\n### 📋 멘토링 코드 리뷰 구조:\n1. 🔍 **[PR 구현 목적 ↔ 실제 코드 대조 분석]**: [PR 제목]과 [PR 작성 목적]에 작성자가 명시한 비즈니스 기능이 실제 자바 소스코드에 정확히 부합하게 구현되었는지 1:1 대조 요약해 주세요.\n2. 🏛️ **[잠재적 위협 & 아키텍처 딥다이브 (Security & System Risks)]**: 주니어 개발자가 미처 인지하지 못했을 잠재적 보안 위협(세션/인증 누수, 취약점), 동시성 경합(Race Condition), 데이터 무결성 파손, 시스템 장애 위험 요소를 정밀하게 짚어주세요. 각 위험 요소를 극복하기 위한 대안 기술/패턴 2~3가지, 물리적 원리, 장단점, Trade-off 및 서비스/아키텍처 레벨 극복 방안을 서술해 주세요.\n3. 💻 **[소스코드 품질 & 엣지 케이스 리뷰 (Code Quality & Edge Cases)]**: 실제 자바 소스코드에서 놓치기 쉬운 예외 처리 누락, 엣지 케이스(Edge Case), 쿼리 N+1/성능 병목, 객체지향 설계(SOLID) 관점의 개선점을 코드 레벨에서 정밀 지적해 주세요.\n4. 🛠️ **[개선된 코드 예시 (Before vs After)]**: 멘티가 잠재적 위협을 극복하고 상황에 맞는 기술을 배울 수 있도록 가독성이 뛰어난 자바(Java / Spring Boot) diff 또는 소스코드 블록 예시를 제공해 주세요.\n\n---\n[실제 백엔드 Java 소스코드 Diff]:\n$PR_DIFF"

PROMPT=$(cat <<EOF
You are a senior Java and Spring Boot architect reviewing a pull request for a junior backend developer.

Do not review CI/CD workflow files, labels, AGENTS.md, docs, or frontend files.
Review only backend application source code, database behavior, security, and architecture.

[PR title]
$PR_TITLE

[PR body]
$PR_BODY

[Review structure]
1. Compare the PR goal with the actual code changes.
2. Identify security, concurrency, data integrity, performance, and failure-mode risks.
3. Point out code-quality issues and edge cases from the Java/Spring source diff.
4. Provide concrete Java/Spring Boot improvement examples where useful.

[Backend Java source diff]
$PR_DIFF
EOF
)

PAYLOAD=$(jq -n --arg prompt "$PROMPT" '{contents: [{parts: [{text: $prompt}]}]}')

# 4. Google AI REST API 호출 (gemini-3.6-flash 고정)
RESPONSE=$(curl -s -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-3.6-flash:generateContent?key=${GEMINI_API_KEY}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD")

# 5. 리뷰 결과 파싱
REVIEW_TEXT=$(echo "$RESPONSE" | jq -r '.candidates[0].content.parts[0].text // empty')

if [ -z "$REVIEW_TEXT" ]; then
echo "::error::Gemini API 응답 실패: $RESPONSE"
echo "::error::Gemini API response failed: $RESPONSE"
exit 1
fi

# 6. GitHub CLI로 PR 댓글 등록
gh issue comment $PR_NUMBER --body "### 🤖 Gemini AI PR Code Review
gh issue comment "$PR_NUMBER" --body "### Gemini AI PR Code Review

$REVIEW_TEXT"
76 changes: 50 additions & 26 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,61 @@ on:
branches: [ "main" ]

jobs:
spotless:
name: Spotless Check
runs-on: ubuntu-latest

defaults:
run:
working-directory: ./backend

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Run Spotless Linter Check
run: ./gradlew spotlessCheck

build:
name: Build and Test
runs-on: ubuntu-latest
needs: spotless

# backend 폴더에서 실행
defaults:
run:
working-directory: ./backend

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'temurin'

# Gradle 캐시 설정 (빌드 속도 향상)
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

# gradlew 실행 권한 부여
- name: Grant execute permission for gradlew
run: chmod +x gradlew

# Gradle 빌드 실행
- name: Run Spotless Linter Check
run: ./gradlew spotlessCheck

- name: Build and Test with Gradle
run: ./gradlew build -x spotlessCheck
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build and Test with Gradle
run: ./gradlew test build -x spotlessCheck
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ application-credentials*.yml
*.key
*.p12

# Local Project & Study Notes (스터디 문서 전면 제외 & project.md, work.md만 허용)
# Local Project & Study Notes
docs/study/
docs/study*.md
docs/study/**
docs/project/*
!docs/project/project.md
!docs/project/work.md
Expand Down
6 changes: 5 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@
⑤ 장점은 무엇인지 (Pros / Advantages)
⑥ 다른 기술/대안은 무엇이 있는지 (Alternatives - 타 기술과의 비교)
⑦ 트레이드오프는 무엇인지 (Trade-off, 사이드이펙트 및 서비스/아키텍처 레벨의 극복 방안)

22. DTO 불변성(Immutability) 보장 수칙: DTO 생성 시 컬렉션(`List`, `Set`, `Map`)을 인자로 받을 때는 `List.copyOf()` 또는 `new ArrayList<>()`로 방어적 복사(Defensive Copy)를 반드시 수행하여, 외부에서의 원본 데이터 변형 및 가변성(Mutability) 오염을 물리적으로 차단해야 한다.
23. 문자열 리터럴 예외 처리 금지 수칙: `new IllegalArgumentException("INVALID_CREDENTIALS")`나 `if ("DUPLICATE_EMAIL".equals(e.getMessage()))`와 같이 문자열 리터럴을 직접 비교하거나 생성해 던지는 예외 처리를 엄격히 금지한다. 예외는 반드시 `ErrorCode` Enum과 정적 타입 기반의 비즈니스 커스텀 예외(`CustomException`)로 일원화해야 한다.
24. 계층 분리(Layered Architecture) 및 웹 결합 차단 수칙:
① 서비스 레이어(Service) 내부에서 `HttpSession`, `SecurityContextHolder`, `changeSessionId()` 등 서블릿/웹 세션 조작 코드를 직접 호출하는 행위(웹-서비스 강결합)를 엄격히 금지한다. (웹 세션 처리는 컨트롤러 또는 시큐리티 레이어가 전담한다)
② 컨트롤러가 `Repository`를 직접 주입받아 호출하거나, DTO 변환 없이 `Entity`를 클라이언트에 직접 반환하는 계층 스킵(Layer Skip) 행위를 엄격히 금지한다.
Loading
Loading