Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .gemini/styleguide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# 스타일 가이드

작업 정책과 코드 스타일의 정본은 [AGENTS.md](../AGENTS.md)입니다. 상세 관례는 [코드 관례](../docs/guides/code-conventions.md)를 확인합니다.
26 changes: 26 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Stology Frontend 작업 안내

이 문서는 AI 작업 정책의 정본입니다. 상세 기술·환경·기능 사실은 여기서 복제하지 않고 [문서 인덱스](docs/README.md)에 둡니다.

## 작업 전 읽기 순서

1. [문서 인덱스](docs/README.md)와 변경 대상의 온보딩/기능 문서를 읽습니다.
2. 변경 대상 소스와 설정을 다시 확인합니다. 문서보다 현재 코드·설정이 사실의 기준입니다.
3. 변경 범위에 맞는 [코드 관례](docs/guides/code-conventions.md)와 [PR 검토](docs/guides/pr-review.md)를 확인합니다.

## 현재 구조 지도

- 애플리케이션 조립과 라우팅은 `src/app`, 화면은 `src/pages`, 공용 코드와 UI는 `src/shared`에 있습니다.
- 기능별 상세와 탐색 경로는 [기능 온보딩](docs/onboarding/domain/README.md)을 기준으로 합니다.
- React 함수 컴포넌트와 hooks를 사용하고, 스타일은 Tailwind CSS를 우선합니다.
- 서버 상태는 TanStack Query, 클라이언트/UI 상태는 Zustand, 검증이 필요한 폼은 React Hook Form과 Zod를 사용합니다.

## 작업 규칙

- 화면·컴포넌트는 PascalCase, hook은 camelCase, 유틸리티와 기타 파일은 snake_case를 사용합니다.
- 일반 함수는 function 선언을, 컴포넌트는 화살표 함수를 사용하고 메인 컴포넌트를 파일 상단에 둡니다. Props interface를 명시합니다.
- 공용화 전 기능 로컬 컴포넌트를 우선하며, 합의 없이 CSS-in-JS를 도입하지 않습니다.
- 화면 변경 시 loading, empty, error, permission, disabled, 종료된 스터디의 읽기 전용 상태를 검토합니다.
- AI는 Concept 후보만 제안하며 팀 검토를 거쳐 활성화됩니다. 질문은 Q&A에서 별도로 관리하며 Concept로 자동 변환하지 않습니다.
- 코드·설정 변경 시 영향을 받는 온보딩·기능·가이드 문서도 함께 갱신합니다.
- 되돌리기 어려운 실제 결정만 [ADR](docs/adr/README.md)로 기록합니다.
3 changes: 3 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Claude 안내

작업 정책의 정본은 [AGENTS.md](AGENTS.md)입니다. 시작점은 [문서 인덱스](docs/README.md)이며, 변경 대상은 [기능 지도](docs/onboarding/domain/README.md)와 [가이드](docs/guides/README.md)에서 찾아 확인합니다.
3 changes: 3 additions & 0 deletions GEMINI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Gemini 안내

작업 정책의 정본은 [AGENTS.md](AGENTS.md)입니다. 시작점은 [문서 인덱스](docs/README.md)이며, 변경 대상은 [기능 지도](docs/onboarding/domain/README.md)와 [가이드](docs/guides/README.md)에서 찾아 확인합니다.
27 changes: 27 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Stology Frontend 문서

현재 코드와 설정을 탐색하기 위한 인덱스입니다. 정책 정본은 루트의 [AGENTS.md](../AGENTS.md)이며, 상세 사실은 아래 소유 문서에서 관리합니다.

## 권장 읽기 경로

1. 처음 참여하거나 실행 환경을 확인할 때: [온보딩](onboarding/README.md)
2. 기능 변경 전: [기능 지도](onboarding/domain/README.md)와 해당 문서
- [인증·초대](onboarding/domain/auth.md)
- [홈](onboarding/domain/home.md)
- [스터디](onboarding/domain/study.md)
- [AI 후보 검토](onboarding/domain/review.md)
3. 구현·검토 시: [가이드](guides/README.md)
4. 되돌리기 어려운 결정을 기록할 때: [ADR 안내](adr/README.md)

## 기존 참고 문서

- [백엔드 데이터베이스 스키마](backend-database-schema.md): 프론트엔드 더미데이터의 엔티티 관계 참고
- [디자인 토큰](design-tokens.md)
- [Hermes 권한 확인](hermes-permission-check.md)

## 문서 소유권

- 온보딩은 실행 환경과 현재 구조의 사실을 설명합니다.
- 기능 문서는 각 화면의 현재 모델과 탐색 경로를 설명합니다.
- 가이드는 코드·문서 갱신 및 검토 기준을 제공합니다.
- ADR은 미래의 실제 결정을 기록하는 형식만 제공합니다. 기존 구현의 의도를 소급해 확정하지 않습니다.
23 changes: 23 additions & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Architecture Decision Records

ADR은 이미 코드에 존재하는 구조의 의도를 추측하는 문서가 아니라, 앞으로 내리는 되돌리기 어려운 기술 결정을 기록하는 문서입니다.

## 기록 대상

- 여러 기능에 영향을 주는 상태 관리, 라우팅, API 계층의 변경
- 기존 공개 동작이나 데이터 계약과 호환되지 않는 결정
- 장기간 유지할 라이브러리 또는 아키텍처 선택

단순 리팩터링, 버그 수정, 현재 코드 설명은 ADR 대상이 아닙니다.

## 파일 형식

확정된 결정은 `YYYY-MM-DD-short-title.md`로 추가하고 다음을 기록합니다.

1. 상태와 결정일
2. 문제와 제약
3. 검토한 선택지
4. 선택한 결정과 근거
5. 영향과 후속 작업

결정 전 초안은 PR 또는 이슈에서 논의하며, 합의되지 않은 추정을 ADR로 확정하지 않습니다.
217 changes: 217 additions & 0 deletions docs/backend-database-schema.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
# 백엔드 데이터베이스 스키마

> 이 문서는 백엔드 저장 구조를 프론트엔드 더미데이터 설계에 활용하기 위한 동기화 사본입니다. 정본은 [Stology/BE의 데이터베이스 스키마](https://github.com/Stology/BE/blob/main/docs/onboarding/database-schema.md)이며 최초 반영은 [BE PR #39](https://github.com/Stology/BE/pull/39)에서 확인합니다.

이 문서는 현재 JPA 엔티티와 애플리케이션 설정을 기준으로 관계형 데이터베이스 구조를 정리합니다. 별도 DDL 또는 Flyway/Liquibase 마이그레이션은 없으며, 기본 설정은 MySQL dialect와 `ddl-auto: create`, 프로덕션 설정은 MySQL dialect와 `ddl-auto: update`를 사용합니다.

따라서 아래 내용은 **현재 코드에서 도출되는 Hibernate 매핑**입니다. 특히 프로덕션 데이터베이스에는 과거 `update` 실행으로 남은 컬럼·제약이 있을 수 있으므로 실제 운영 스키마의 완전한 사본으로 간주하지 않습니다.

## 프론트엔드 더미데이터 활용 기준

- 엔티티 간 식별자와 참조 관계를 유지해 서로 연결되는 fixture를 구성할 때 이 문서를 사용합니다.
- 현재 `src/shared/mocks/studies.ts`처럼 화면에 맞춘 mock은 DB 행을 그대로 복제하지 않고, TypeScript 타입과 실제 API 응답 계약에 맞는 view model로 변환합니다.
- DB의 snake case 컬럼명은 저장 구조 설명이며 프론트엔드 객체의 필드명 규칙을 대체하지 않습니다. API DTO가 확정되면 해당 계약을 우선합니다.
- `created_at`, `updated_at`, `deleted_at` 같은 공통 컬럼은 화면 시나리오에 필요한 경우에만 ISO 8601 문자열 등 API 표현 형식으로 포함합니다.
- `@Builder.Default`로 표시된 값은 DB DEFAULT가 아니므로, 원시 엔티티 형태의 fixture를 만들 때 필요한 값은 명시적으로 채웁니다.

## 이름과 타입 해석 기준

- `@Table`, `@Column(name = ...)`이 없는 엔티티·필드는 현재 Spring Boot/Hibernate naming strategy에 따라 snake case로 적었습니다. 예: `MemberStudy` → `member_study`, `socialUid` → `social_uid`.
- 모든 엔티티의 `id`는 `Long`이며 `IDENTITY` 방식의 기본 키입니다.
- 별도 길이 지정이 없는 `String`은 Hibernate의 기본 문자열 매핑을 사용합니다. `Report`의 일부 필드만 코드에서 `json` 또는 `text`로 명시합니다.
- 모든 엔티티는 `BaseEntity`를 상속하므로 `created_at`, `updated_at`, `deleted_at`을 공유합니다.
- `@JoinColumn`에 `nullable = false`가 없고 연관 필드도 `optional = false`가 아니므로 외래 키 컬럼의 NOT NULL 제약은 코드에 명시되어 있지 않습니다.
- `@Builder.Default`는 Lombok builder로 객체를 생성할 때의 Java 기본값이며 DB의 `DEFAULT` 제약이 아닙니다.

## 관계 개요

```mermaid
erDiagram
MEMBER ||--o{ TEMPLATE : uploads
MEMBER ||--o{ MEMBER_STUDY : joins
TEMPLATE ||--o{ TEMPLATE_NODE : contains
TEMPLATE ||--o{ STUDY : bases
STUDY ||--o{ MEMBER_STUDY : has
STUDY ||--o{ QUESTION : has
QUESTION ||--o{ QUESTION_IMAGE : has
QUESTION ||--o{ ANSWER : has
ANSWER ||--o{ ANSWER_IMAGE : has
STUDY ||--o{ REPORT : has
STUDY ||--o{ STUDY_NODE : has
STUDY_NODE ||--o{ NODE_CANDIDATE : receives
STUDY_MATERIAL ||--o{ NODE_CANDIDATE : produces
```

코드의 모든 연관은 단방향 `@ManyToOne(fetch = LAZY)`입니다. 반대 방향 컬렉션, cascade, orphan removal은 선언되어 있지 않습니다. 다이어그램의 `||--o{`는 참조 방향과 다대일 구조를 읽기 쉽게 표현한 것이며, 코드가 외래 키 컬럼에 NOT NULL을 명시한다는 의미는 아닙니다.

## 공통 컬럼

아래 컬럼은 13개 엔티티 테이블에 모두 포함됩니다.

| 컬럼 | Java 타입 | 매핑 및 의미 |
| ------------ | --------------- | ---------------------------------------------- |
| `created_at` | `LocalDateTime` | `@CreatedDate`, 수정 불가(`updatable = false`) |
| `updated_at` | `LocalDateTime` | `@LastModifiedDate` |
| `deleted_at` | `LocalDateTime` | soft delete 시각, 코드상 nullable |

## 회원

### `member`

| 컬럼 | Java 타입 | 키/제약 및 매핑 |
| ------------- | ------------ | ----------------------------------------- |
| `id` | `Long` | PK, identity |
| `name` | `String` | Bean Validation `@NotBlank` |
| `social_type` | `SocialType` | 문자열 enum, `@NotNull`; 현재 값: `KAKAO` |
| `social_uid` | `String` | Bean Validation `@NotBlank` |
| `email` | `String` | Bean Validation `@Email`, `@NotBlank` |

코드에는 `social_type`과 `social_uid` 조합을 조회하는 repository 메서드가 있지만, 해당 조합의 UNIQUE 제약이나 인덱스는 선언되어 있지 않습니다.

## 노드와 템플릿

### `template`

| 컬럼 | Java 타입 | 키/제약 및 매핑 |
| ------------- | --------- | ------------------- |
| `id` | `Long` | PK, identity |
| `uploader` | `Long` | FK → `member.id` |
| `name` | `String` | 별도 컬럼 제약 없음 |
| `description` | `String` | 별도 컬럼 제약 없음 |

### `template_node`

| 컬럼 | Java 타입 | 키/제약 및 매핑 |
| ------------- | --------- | ------------------ |
| `id` | `Long` | PK, identity |
| `template_id` | `Long` | FK → `template.id` |

### `study_node`

| 컬럼 | Java 타입 | 키/제약 및 매핑 |
| -------------- | --------- | --------------------------------------------------- |
| `id` | `Long` | PK, identity |
| `study_id` | `Long` | FK → `study.id` |
| `active_level` | `Integer` | builder 생성 기본값 `0`; DB DEFAULT는 선언되지 않음 |

### `study_material`

| 컬럼 | Java 타입 | 키/제약 및 매핑 |
| ---------- | --------- | ------------------- |
| `id` | `Long` | PK, identity |
| `file_url` | `String` | 별도 컬럼 제약 없음 |

### `node_candidate`

| 컬럼 | Java 타입 | 키/제약 및 매핑 |
| ------------------- | ---------------- | ------------------------------------------------------------------------------------ |
| `id` | `Long` | PK, identity |
| `study_material_id` | `Long` | FK → `study_material.id` |
| `study_node_id` | `Long` | FK → `study_node.id` |
| `state` | `CandidateState` | 문자열 enum; 현재 값: `ACCEPT`, `DECLINED`, `PENDING`; builder 생성 기본값 `PENDING` |
| `accept_count` | `Integer` | builder 생성 기본값 `0`; DB DEFAULT는 선언되지 않음 |

## 스터디

### `study`

| 컬럼 | Java 타입 | 키/제약 및 매핑 |
| ----------------- | --------- | ------------------------------------------------------ |
| `id` | `Long` | PK, identity |
| `template_id` | `Long` | FK → `template.id` |
| `name` | `String` | 별도 컬럼 제약 없음 |
| `description` | `String` | 별도 컬럼 제약 없음 |
| `invitation_link` | `String` | 별도 컬럼 제약 없음 |
| `reviewer_count` | `Integer` | 별도 컬럼 제약 없음 |
| `is_active` | `Boolean` | builder 생성 기본값 `true`; DB DEFAULT는 선언되지 않음 |
| `study_leader` | `String` | 별도 컬럼 제약 없음 |

### `member_study`

| 컬럼 | Java 타입 | 키/제약 및 매핑 |
| ----------- | --------- | ---------------- |
| `id` | `Long` | PK, identity |
| `member_id` | `Long` | FK → `member.id` |
| `study_id` | `Long` | FK → `study.id` |

`member_id`와 `study_id` 조합의 UNIQUE 제약은 선언되어 있지 않습니다.

### `question`

| 컬럼 | Java 타입 | 키/제약 및 매핑 |
| -------------- | --------- | --------------------------------------------------- |
| `id` | `Long` | PK, identity |
| `study_id` | `Long` | FK → `study.id` |
| `title` | `String` | 별도 컬럼 제약 없음 |
| `content` | `String` | 별도 컬럼 제약 없음 |
| `member_name` | `String` | 별도 컬럼 제약 없음 |
| `answer_count` | `Integer` | builder 생성 기본값 `0`; DB DEFAULT는 선언되지 않음 |
| `is_attached` | `Boolean` | 별도 컬럼 제약 없음 |

### `question_image`

| 컬럼 | Java 타입 | 키/제약 및 매핑 |
| ------------- | --------- | ------------------- |
| `id` | `Long` | PK, identity |
| `question_id` | `Long` | FK → `question.id` |
| `image_url` | `String` | 별도 컬럼 제약 없음 |

### `answer`

| 컬럼 | Java 타입 | 키/제약 및 매핑 |
| ------------- | --------- | ------------------- |
| `id` | `Long` | PK, identity |
| `question_id` | `Long` | FK → `question.id` |
| `content` | `String` | 별도 컬럼 제약 없음 |
| `member_name` | `String` | 별도 컬럼 제약 없음 |

### `answer_image`

| 컬럼 | Java 타입 | 키/제약 및 매핑 |
| ----------- | --------- | ------------------- |
| `id` | `Long` | PK, identity |
| `answer_id` | `Long` | FK → `answer.id` |
| `image_url` | `String` | 별도 컬럼 제약 없음 |

### `report`

| 컬럼 | Java 타입 | 키/제약 및 매핑 |
| --------------------------------- | --------- | --------------------------------------------------- |
| `id` | `Long` | PK, identity |
| `study_id` | `Long` | FK → `study.id` |
| `total_node_count` | `Integer` | builder 생성 기본값 `0`; DB DEFAULT는 선언되지 않음 |
| `new_active_node_count` | `Integer` | builder 생성 기본값 `0`; DB DEFAULT는 선언되지 않음 |
| `reinforced_node_count` | `Integer` | builder 생성 기본값 `0`; DB DEFAULT는 선언되지 않음 |
| `weekly_core_node_list` | `String` | MySQL `json`으로 명시 |
| `ai_review_content` | `String` | MySQL `text`로 명시 |
| `recommended_node_list` | `String` | MySQL `json`으로 명시 |
| `follow_up_content` | `String` | MySQL `text`로 명시 |
| `member_activity_statistics_list` | `String` | MySQL `json`으로 명시 |

JSON 컬럼의 Java 타입은 구조화된 객체가 아닌 `String`입니다. 코드에는 JSON 변환기나 구체적인 JSON 내부 스키마가 선언되어 있지 않습니다.

## 명시적으로 선언되지 않은 제약

현재 엔티티에는 다음 데이터베이스 제약이 선언되어 있지 않습니다.

- 기본 키 이외의 UNIQUE 제약
- 명시적 보조 인덱스
- 외래 키 컬럼의 NOT NULL
- 연관 삭제/갱신 cascade 규칙
- 문자열 길이, 숫자 범위, CHECK 제약
- DB 수준의 컬럼 기본값

Bean Validation의 `@NotBlank`, `@NotNull`, `@Email`은 `member` 엔티티 객체 검증에 사용되지만, 이 문서에서는 이를 명시적인 JPA `nullable = false`나 데이터베이스 CHECK 제약으로 간주하지 않습니다.

## 관계형 DB 밖의 저장 데이터

refresh token은 RDB 테이블이 아니라 Redis에 `refresh:{uid}` 키로 저장되며 TTL을 가집니다. 따라서 위 스키마와 테이블 목록에는 포함하지 않습니다.

## 백엔드 기준 소스

- [공통 필드](https://github.com/Stology/BE/blob/main/src/main/java/com/stology/be/global/entity/BaseEntity.java)
- [회원 엔티티](https://github.com/Stology/BE/blob/main/src/main/java/com/stology/be/domain/member/entity/Member.java)
- [노드·템플릿 엔티티](https://github.com/Stology/BE/tree/main/src/main/java/com/stology/be/domain/node/entity)
- [스터디 엔티티](https://github.com/Stology/BE/tree/main/src/main/java/com/stology/be/domain/study/entity)
- [기본 DB/JPA 설정](https://github.com/Stology/BE/blob/main/src/main/resources/application.yaml)
- [프로덕션 DB/JPA 설정](https://github.com/Stology/BE/blob/main/src/main/resources/application-prod.yaml)
6 changes: 6 additions & 0 deletions docs/guides/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# 구현·검토 가이드

- [코드 관례](code-conventions.md): 현재 배치와 구현 원칙
- [PR 검토](pr-review.md): 자동 검사와 사람 검토 기준

작업 정책은 [AGENTS.md](../../AGENTS.md), 현재 구조는 [온보딩](../onboarding/README.md)에서 확인합니다.
Loading
Loading