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
6 changes: 0 additions & 6 deletions .env

This file was deleted.

13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Firebase Client SDK
# These values are exposed to the browser by Next.js.
NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
NEXT_PUBLIC_FIREBASE_APP_ID=

# Spring Backend
# Leave empty in Firebase Hosting builds so /api/** uses firebase.json rewrites.
# Set this only for local direct-to-Cloud-Run testing.
NEXT_PUBLIC_BACKEND_API_BASE_URL=
11 changes: 11 additions & 0 deletions .env.production
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Firebase Client SDK
# These values are exposed to the browser by Next.js.
NEXT_PUBLIC_FIREBASE_API_KEY=AIzaSyABxF3nO6fVtgk-RQEwE5eYK5GKEt8diEI
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=ajou-project-cafd9.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=ajou-project-cafd9
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=ajou-project-cafd9.firebasestorage.app
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=926871086070
NEXT_PUBLIC_FIREBASE_APP_ID=1:926871086070:web:9a01bad8170cb172f15dd7

# Keep empty in Firebase Hosting builds so /api/** uses firebase.json rewrites.
NEXT_PUBLIC_BACKEND_API_BASE_URL=
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ out
.vercel
dist
dist-ssr
.env
.env.*.local
*.local
*.tsbuildinfo

# Editor directories and files
.vscode/*
Expand Down
61 changes: 33 additions & 28 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pnpm lint
- 앱 개발 기준은 `Next.js App Router`다.
- Firebase Hosting은 유지하되, 배포는 `out/` 정적 산출물을 기준으로 한다.
- 공개 페이지는 `SSG`, 로그인 이후 내부 페이지는 `CSR`을 기본 전략으로 삼는다.
- `src/app`는 라우팅과 레이아웃을 담당하고, 실제 화면 구현은 `src/views`에 둔다.
- `src/app`는 라우팅과 레이아웃을 담당하고, 실제 화면 구현은 `src/screens`에 둔다.
- Vite 앱 엔트리(`src/main.tsx`, `index.html`)와 레거시 App 엔트리(`src/app/index.tsx`)는 더 이상 사용하지 않는다.

새로 합류한 팀원은 "Next.js로 실행하지만 모든 페이지를 SSR로 만드는 프로젝트는 아니다"라고 이해하면 가장 덜 헷갈린다.
Expand Down Expand Up @@ -90,16 +90,13 @@ aim-frontend/
│ │ ├─ page.tsx # 기본 라우트
│ │ └─ globals.css # 전역 스타일 진입점
│ │
│ ├─ views/ # 화면 레이어 (기존 pages 레이어 대체)
│ ├─ widgets/ # 위젯 레이어 (큰 UI 블록)
│ ├─ features/ # 기능 레이어
│ ├─ entities/ # 엔티티 레이어
│ ├─ api/ # 백엔드/외부 API 클라이언트
│ ├─ lib/ # 앱 유스케이스와 공통 로직
│ ├─ screens/ # 화면 구현 (기존 pages 레이어 대체)
│ └─ shared/ # 공유 레이어
│ ├─ ui/ # 재사용 가능한 UI 컴포넌트
│ ├─ assets/ # 전역 에셋 (images, icons, fonts)
│ ├─ config/ # 설정 (firebase.ts)
│ ├─ api/ # API 클라이언트
│ ├─ lib/ # 유틸리티 함수
│ └─ types/ # 공통 타입 정의
├─ docs/ # 문서
Expand Down Expand Up @@ -138,9 +135,11 @@ aim-frontend/
- 라우트 공통 레이아웃/metadata:
- `src/app/**/layout.tsx`
- 실제 화면 구현:
- `src/views/**`
- 큰 화면 블록 조합:
- `src/widgets/**`
- `src/screens/**`
- 백엔드/외부 API 호출:
- `src/api/**`
- Firebase 로그인 흐름, 세션 생성, 화면과 API 사이의 유스케이스:
- `src/lib/**`
- 재사용 UI:
- `src/shared/ui/**`
- 전역 스타일 진입:
Expand All @@ -153,31 +152,36 @@ aim-frontend/
- `/login` 라우트 파일:
- `src/app/(auth)/login/page.tsx`
- 로그인 화면 구현:
- `src/views/login/index.tsx`
- `src/screens/login/index.tsx`

---

## 아키텍처

### FSD (Feature-Sliced Design)
### 레이어 기준

레이어 의존 방향은 **단방향**입니다. 하위 레이어는 상위 레이어를 import할 수 없습니다.
현재 구조는 FSD를 엄격히 적용하기보다, Next.js App Router에 맞춘 컴팩트한 레이어 구조를 사용합니다. 의존 방향은 **단방향**입니다.

```
app → viewswidgetsfeatures → entities → shared
app → screenslibapi → shared
```
Comment on lines 165 to 167
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language to the fenced code block to satisfy markdown lint.

The fence at Line 165 should declare a language (e.g., text) to avoid MD040 warnings.

Suggested fix
-```
+```text
 app → screens → lib → api → shared
</details>

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.22.1)</summary>

[warning] 165-165: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @docs/CONTRIBUTING.md around lines 165 - 167, The fenced code block
containing the path string "app → screens → lib → api → shared" lacks a language
tag; update the opening fence from totext so the block reads text followed by the path and the closing to satisfy markdown lint (MD040).


</details>

<!-- fingerprinting:phantom:poseidon:hawk:6cf36a1a-0c8b-4fc2-93ba-4e43bb0f31d4 -->

<!-- d98c2f50 -->

<!-- This is an auto-generated comment by CodeRabbit -->


- `@/` alias를 사용해 절대 경로로 import
- Next.js App Router와 충돌하지 않도록 화면 레이어는 `src/views`를 사용
- 각 슬라이스는 `index.ts`(public API)를 통해서만 export
- `src/app`은 URL, layout, metadata 같은 라우팅 책임만 갖는다.
- `src/screens`는 라우트가 렌더링하는 화면 조합을 담당한다.
- `src/lib`는 로그인, 세션 생성처럼 화면과 API 사이의 앱 로직을 담당한다.
- `src/api`는 fetch, 요청/응답 타입, 외부 API 호출만 담당한다.
- `src/shared`는 UI, config, asset처럼 도메인과 무관한 공통 자원만 둔다.

```ts
// 올바른 import
import { Button } from '@/shared/ui/button'
import { AuthFeature } from '@/features/auth'
import { signInWithGoogle } from '@/lib/auth'
import { loginWithBackend } from '@/api/auth'

// 잘못된 import (하위에서 상위 참조 금지)
// shared에서 features import 불가
// 잘못된 import
// api에서 screens/lib import 금지
// shared에서 api/lib/screens import 금지
```

### 인프라 구조
Expand Down Expand Up @@ -224,7 +228,7 @@ git checkout -b fix/header-layout
Next.js 전환 작업이나 구조 변경이 포함되면 아래 항목을 함께 확인합니다.

- 새 라우트가 `src/app` 기준으로 추가되었는가
- 라우트 파일이 화면 구현까지 전부 떠안지 않고, 필요한 경우 `src/views`를 조합하는가
- 라우트 파일이 화면 구현까지 전부 떠안지 않고, 필요한 경우 `src/screens`를 조합하는가
- SEO 대상 페이지인지, CSR 유지 페이지인지 분류했는가
- 공개 SEO 페이지라면 `SSG` 가능한 구조인지 먼저 검토했는가
- `use client`가 꼭 필요한 곳에만 선언되었는가
Expand All @@ -236,7 +240,7 @@ Next.js 전환 작업이나 구조 변경이 포함되면 아래 항목을 함

- `CSR 페이지`라고 해서 Vite를 다시 쓰는 것은 아니다.
- Next.js 안에서도 Client Component 기반으로 충분히 구현할 수 있다.
- `src/app/page.tsx`는 라우트 파일이고, `src/views/**`는 화면 구현 파일이다.
- `src/app/page.tsx`는 라우트 파일이고, `src/screens/**`는 화면 구현 파일이다.
- 라우트 정의와 화면 구현을 분리하는 것이 현재 기준이다.
- `pnpm build` 결과물은 `.next`만 보는 것이 아니라 최종적으로 `out/` 배포를 염두에 둔다.
- `/`는 지금 정적 export 환경을 고려해 클라이언트에서 `/login`으로 이동한다.
Expand Down Expand Up @@ -296,10 +300,10 @@ enum ButtonVariant { Primary = "primary" }
// 1. 외부 라이브러리
import { useState } from 'react'

// 2. 내부 alias (FSD 레이어 순서)
// 2. 내부 alias (레이어 순서)
import { auth } from '@/shared/config/firebase'
import { UserEntity } from '@/entities/user'
import { AuthFeature } from '@/features/auth'
import { loginWithBackend } from '@/api/auth'
import { signInWithGoogle } from '@/lib/auth'

// 3. 상대 경로
import { getButtonClasses } from './button.utils'
Expand Down Expand Up @@ -375,19 +379,19 @@ export const Loading: Story = {

### 화면 개발 패턴

현재 프로젝트에서는 "라우트 파일은 얇게, 화면 구현은 views로" 가져가는 것을 권장합니다.
현재 프로젝트에서는 "라우트 파일은 얇게, 화면 구현은 screens로" 가져가는 것을 권장합니다.

```tsx
// src/app/(auth)/login/page.tsx
import { LoginPage } from "@/views"
import { LoginPage } from "@/screens"

export default function LoginRoute() {
return <LoginPage />
}
```

```tsx
// src/views/login/index.tsx
// src/screens/login/index.tsx
"use client"

export function LoginPage() {
Expand Down Expand Up @@ -451,14 +455,15 @@ function LikeButton() {

## API 호출 가이드

현재 저장소에는 공통 API 클라이언트 레이어가 아직 없다. API 연동이 시작되면 `src/shared/api` 또는 `src/shared/lib/api` 하위에 공통 fetch/HTTP 래퍼를 두고 일관되게 사용하는 것을 기본 정책으로 한다.
API 클라이언트는 `src/api` 하위에 둔다. 백엔드 API, Google People API처럼 네트워크 요청 자체와 요청/응답 타입은 이 레이어에 모으고, 화면 흐름과 세션 생성 로직은 `src/lib`에서 조합한다.

권장 원칙:

- 서버 컴포넌트에서 우선적으로 데이터 패칭
- 인증 헤더/토큰 주입 로직 중앙화
- 에러 처리와 응답 파싱 로직 공통화
- 브라우저 전용 상호작용만 Client Component에서 처리
- `src/api`는 `src/screens`나 `src/lib`를 import하지 않는다.

### Next.js 기준 권장 방식

Expand Down
11 changes: 10 additions & 1 deletion firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,16 @@
},
"hosting": {
"public": "out",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"]
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "/api/**",
"run": {
"serviceId": "aim-be-prod",
"region": "us-central1"
}
}
]
},
"storage": {
"rules": "storage.rules"
Expand Down
Loading