Skip to content

Commit 0510f2a

Browse files
committed
[#31] docs: code agent
1 parent 0cef070 commit 0510f2a

File tree

2 files changed

+340
-0
lines changed

2 files changed

+340
-0
lines changed

AGENTS.md

Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
Spring Boot 3.5.3 backend application implementing Clean Architecture with JWT authentication. This is the "Gamchi API" project.
7+
8+
## Development Commands
9+
10+
### Build and Run
11+
```bash
12+
# Build the project
13+
./gradlew build
14+
15+
# Run tests
16+
./gradlew test
17+
18+
# Run a specific test class
19+
./gradlew test --tests com.nexters.teamace.auth.presentation.AuthControllerTest
20+
21+
# Run a specific test method
22+
./gradlew test --tests "com.nexters.teamace.auth.presentation.AuthControllerTest.login_success"
23+
24+
# Clean and build
25+
./gradlew clean build
26+
27+
# Run the application
28+
./gradlew bootRun
29+
```
30+
31+
### Docker & Database
32+
```bash
33+
# Start MySQL database (required for application)
34+
docker-compose up -d db
35+
36+
# Stop database
37+
docker-compose down
38+
39+
# View database logs
40+
docker-compose logs -f db
41+
```
42+
43+
### Testing
44+
```bash
45+
# Run all tests (includes unit, integration, and E2E tests)
46+
./gradlew test
47+
48+
# Run only integration tests
49+
./gradlew test --tests "*UseCaseIntegrationTest"
50+
51+
# Run only E2E tests
52+
./gradlew test --tests "*E2ETest"
53+
54+
# Run tests with Testcontainers (automatically starts MySQL container)
55+
./gradlew test --tests "*E2ETest"
56+
```
57+
58+
### Code Quality
59+
```bash
60+
# Apply code formatting (automatically runs before compile)
61+
./gradlew spotlessApply
62+
63+
# Check code formatting without applying
64+
./gradlew spotlessCheck
65+
```
66+
67+
### API Documentation
68+
```bash
69+
# Generate OpenAPI documentation
70+
./gradlew openapi3
71+
72+
# Output: build/api-spec/openapi3.yaml
73+
```
74+
75+
### Database Migration (Flyway)
76+
77+
#### 새 마이그레이션 만들기
78+
1. `src/main/resources/db/migration/` 폴더에 새 파일 생성
79+
2. 파일명 형식: `V{번호}__{설명}.sql`
80+
3. 예시: `V2__Add_user_email_column.sql`, `V3__Create_chat_room_table.sql`
81+
82+
#### 주요 명령어
83+
```bash
84+
# 마이그레이션 검증하기 (PR 올리기 전에 실행)
85+
./scripts/validate-migration-files.sh
86+
87+
# 마이그레이션 실행 (앱 시작할 때 자동으로 됨)
88+
./gradlew flywayMigrate
89+
90+
# 마이그레이션 상태 확인
91+
./gradlew flywayInfo
92+
93+
# SQL 문법 검증
94+
./gradlew flywayValidate
95+
```
96+
97+
## Architecture Overview
98+
99+
### Clean Architecture Layers
100+
The project follows Clean Architecture with unidirectional dependencies:
101+
```
102+
presentation → application → domain ← infrastructure
103+
104+
config
105+
```
106+
107+
### Key Architectural Decisions
108+
109+
1. **Dependency Inversion**: Application layer depends on interfaces, not implementations
110+
- Example: `TokenService` interface in application layer, `JwtTokenProvider` implementation in infrastructure
111+
112+
2. **Command/Result Pattern**: Application services use Command objects for input and Result objects for output
113+
- Prevents application layer from depending on presentation DTOs
114+
- Example: `LoginCommand``AuthService``LoginResult`
115+
116+
3. **Configuration Properties**: Using record types with constructor binding
117+
- Example: `JwtProperties` as a record with `@ConfigurationProperties`
118+
- Requires `@ConfigurationPropertiesScan` on main application class
119+
120+
4. **Security Architecture**:
121+
- Stateless authentication (JWT) with access/refresh token pattern
122+
- Custom error handling through `SecurityErrorHandler`
123+
- JWT filter processes tokens before Spring Security authentication
124+
125+
5. **AI Integration Architecture**:
126+
- Spring AI framework with custom Gemini adapter
127+
- Conversation domain manages AI interaction patterns
128+
- External prompt templates for maintainable AI responses
129+
- Context-aware conversation management
130+
131+
6. **Testing Architecture**:
132+
- Three-tier testing: Unit → Integration → E2E
133+
- Testcontainers for database integration testing
134+
- Fixture Monkey for realistic test data generation
135+
- REST Docs for automated API documentation
136+
137+
### Bounded Context Architecture
138+
The project is organized into bounded contexts following Domain-Driven Design:
139+
140+
- **auth**: Authentication and authorization
141+
- **user**: User management and domain logic
142+
- **conversation**: AI-powered conversation system with Gemini integration
143+
- **chat**: Chat room functionality
144+
- **common**: Shared utilities and infrastructure
145+
146+
Each bounded context follows Clean Architecture layers with strict dependency rules.
147+
148+
### Authentication Flow
149+
1. **Login**: `POST /api/v1/auth/login` with username (password-less for current implementation)
150+
2. **Token Generation**: `AuthService` creates access and refresh tokens via `TokenService`
151+
3. **Response**: Returns both tokens in `LoginResponse`
152+
4. **API Access**: Subsequent requests include `Authorization: Bearer {accessToken}` header
153+
5. **Token Validation**: `JwtAuthenticationFilter` validates tokens and sets `SecurityContext`
154+
6. **Token Refresh**: Use refresh token to get new access token when expired
155+
156+
### Conversation System Architecture
157+
1. **Domain Models**: `ConversationScript` defines conversation structure and types
158+
2. **Service Layer**: `ConversationService` orchestrates conversation flow
159+
3. **AI Integration**: `ConversationClient` interface with Gemini implementation
160+
4. **Context Management**: `ConversationContext` maintains conversation state
161+
5. **Prompt Management**: External prompt files loaded from resources
162+
6. **Response Processing**: Structured responses based on conversation type
163+
164+
### Testing Strategy
165+
166+
#### Controller Tests
167+
- **Base Class**: `ControllerTest` with `@WebMvcTest` and security configurations
168+
- **Authentication**: `@WithMockCustomUser` annotation for authenticated endpoints
169+
- **Mocking**: `@MockitoBean` for services to isolate controller logic
170+
- **Documentation**: REST Docs integration with `@AutoConfigureRestDocs`
171+
- **JSON Handling**: ObjectMapper and JsonPath utilities for response parsing
172+
173+
#### Integration Tests
174+
- **Base Class**: `UseCaseIntegrationTest` for service layer testing
175+
- **Configuration**: `@SpringBootTest(webEnvironment = NONE)` for non-web tests
176+
- **Real Beans**: No mocking - tests actual Spring bean interactions
177+
- **Assertions**: BDD-style using `BDDAssertions.then()` with `extracting()`
178+
179+
#### E2E Tests
180+
- **Base Class**: `E2ETest` with full Spring Boot context
181+
- **Database**: Testcontainers for MySQL integration
182+
- **HTTP Client**: REST Assured for API testing
183+
- **Test Data**: Fixture Monkey for generating realistic test data
184+
185+
#### Test Data Generation
186+
- **Fixture Monkey**: Generates realistic test objects with minimal configuration
187+
- **Custom Factories**: Domain-specific object creation patterns
188+
- **Database Population**: Automated test data setup for integration tests
189+
190+
##### Describe-Context-It Pattern
191+
This pattern focuses on describing the behavior of code through test cases. While it shares a similar philosophy with the well-known BDD pattern Given-When-Then, it has subtle differences. Describe-Context-It is more suitable for describing behaviors in detail with the test subject as the protagonist, rather than merely describing situations.
192+
193+
| Keyword | Description |
194+
|---------|-------------|
195+
| **Describe** | Specifies the test subject. Names the class or method being tested. |
196+
| **Context** | Describes the circumstances in which the test subject is placed. Explains the parameters to be input to the method being tested. |
197+
| **It** | Describes the behavior of the test subject. Explains what the test subject method returns. |
198+
199+
Writing Guidelines:
200+
- Context statements must start with **with** or **when**
201+
- It statements should be simple, like "It returns true" or "It responses 404"
202+
- Use Fixture Monkey for generating test data: `fixture.giveMeOne(User.class)`
203+
- Use BDD assertions with `extracting()` for multiple field validation
204+
- Mock external dependencies like AI services in unit tests
205+
206+
Example structure:
207+
```java
208+
@Nested
209+
@DisplayName("createUser")
210+
class Describe_createUser {
211+
@Nested
212+
@DisplayName("when valid username and nickname are provided")
213+
class Context_with_valid_username_and_nickname {
214+
@Test
215+
@DisplayName("it returns user with generated id")
216+
void it_returns_user_with_generated_id() {
217+
// Given
218+
CreateUserCommand command = fixture.giveMeOne(CreateUserCommand.class);
219+
220+
// When
221+
CreateUserResult result = userService.createUser(command);
222+
223+
// Then - BDD assertions with extracting()
224+
then(result)
225+
.extracting("id", "username", "nickname")
226+
.containsExactly(result.id(), command.username(), command.nickname());
227+
}
228+
}
229+
}
230+
```
231+
232+
## Important Configuration
233+
234+
### Environment Variables
235+
```yaml
236+
# Database
237+
DB_HOST: localhost
238+
DB_USERNAME: root
239+
DB_PASSWORD: 1234
240+
241+
# JWT Authentication
242+
JWT_SECRET: base64-encoded-secret-key
243+
JWT_ACCESS_TOKEN_VALIDITY: 3600000 # 1 hour in milliseconds
244+
JWT_REFRESH_TOKEN_VALIDITY: 604800000 # 7 days in milliseconds
245+
246+
# AI Integration
247+
GEMINI_API_KEY: your-gemini-api-key
248+
OPENAI_API_KEY: fake-key # Required but unused (Spring AI constraint)
249+
```
250+
251+
### Database Configuration
252+
- **Database**: MySQL 8.x with utf8mb4 charset
253+
- **Migration**: Flyway with validation enabled
254+
- **Connection Pool**: HikariCP (Spring Boot default)
255+
- **SQL Logging**: P6Spy with formatted output for development
256+
257+
### AI Configuration
258+
- **Primary Model**: Google Gemini 2.0 Flash
259+
- **Framework**: Spring AI with custom Gemini integration
260+
- **Conversation Types**: Emotion analysis, message generation
261+
- **Prompt Management**: External prompt files in resources/prompts/
262+
263+
### Monitoring Configuration
264+
- **Actuator**: Health, metrics, and Prometheus endpoints
265+
- **Metrics**: Micrometer with Prometheus registry
266+
- **Endpoints**: `/actuator/health`, `/actuator/metrics`, `/actuator/prometheus`
267+
268+
### Security Configuration
269+
- **Authentication**: JWT-based with access/refresh token pattern
270+
- **Session Management**: STATELESS (no server-side sessions)
271+
- **CSRF**: Disabled for REST API
272+
- **CORS**: Configured for cross-origin requests
273+
- **Public Endpoints**: `/api/v1/auth/**`, `/docs/**`, `/swagger-ui/**`, `/actuator/**`
274+
- **Protected Endpoints**: All other endpoints require valid JWT
275+
- **Error Handling**: `SecurityErrorHandler` for authentication/authorization errors
276+
- **Filter Chain**: Custom `JwtAuthenticationFilter` validates tokens before Spring Security
277+
- **Test Configuration**: `@ConditionalOnWebApplication` prevents security loading in non-web tests
278+
279+
## Common Development Patterns
280+
281+
### Adding a New Domain
282+
1. Create package structure: `domain/application/infrastructure/presentation`
283+
2. Define domain interfaces in domain layer
284+
3. Implement interfaces in infrastructure layer
285+
4. Use dependency injection with constructor parameters
286+
5. Follow Command/Result pattern for application services
287+
288+
### Adding New Endpoints
289+
1. Create Request/Response DTOs in presentation layer
290+
2. Create Command/Result objects in application layer
291+
3. Implement business logic in application service
292+
4. Add controller method with proper validation
293+
5. Write controller tests extending `ControllerTest`
294+
6. Add integration tests extending `UseCaseIntegrationTest`
295+
7. Consider E2E tests extending `E2ETest` for critical flows
296+
297+
### Working with AI Features
298+
1. Define conversation types in `ConversationType` enum
299+
2. Create prompt templates in `src/main/resources/prompts/`
300+
3. Implement conversation logic in `ConversationService`
301+
4. Use `ConversationClient` for AI model interactions
302+
5. Test with mocked AI responses using `@MockitoBean`
303+
304+
### Database Development
305+
1. Create new migration files following `V{number}__{description}.sql` pattern
306+
2. Run `./scripts/validate-migration-files.sh` before committing
307+
3. Use `./gradlew flywayInfo` to check migration status
308+
4. Domain entities go in domain layer, JPA entities in infrastructure
309+
5. Repository interfaces in domain, implementations in infrastructure
310+
311+
### Error Handling
312+
- Use `CustomException` with appropriate `ErrorType`
313+
- Global exception handling via `GlobalExceptionHandler`
314+
- Security exceptions handled by `SecurityErrorHandler`
315+
316+
## Database Migration Guidelines
317+
318+
### Migration File Naming Convention
319+
- Format: `V{version}__{description}.sql`
320+
- Version: Sequential numbers (V1, V2, V3, etc.)
321+
- Description: Use underscores for spaces, be descriptive
322+
- Examples:
323+
- `V1__Create_user_schema.sql`
324+
- `V2__Add_user_email_column.sql`
325+
- `V3__Create_chat_room_participants_table.sql`
326+
327+
### Migration Best Practices
328+
1. **Never modify existing migrations** - Create new migrations instead
329+
2. **Use descriptive names** - Make it clear what the migration does
330+
3. **Test migrations** - Always test against a copy of production data
331+
4. **Backward compatibility** - Consider rollback scenarios
332+
5. **Small incremental changes** - Avoid large, complex migrations
333+
6. **Sequential versioning** - Use V1, V2, V3... for simple and clear ordering
334+
7. **자동 검증** - PR 올릴 때 GitHub에서 자동으로 파일 이름과 SQL 문법을 확인해줍니다
335+
336+
### Migration Location
337+
- All migration files must be placed in: `src/main/resources/db/migration/`
338+
- Flyway automatically runs migrations on application startup
339+
- Migrations are executed in version order

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
See @AGENTS.md for guidelines.

0 commit comments

Comments
 (0)