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
15 changes: 15 additions & 0 deletions .github/workflows/review-assign.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: Review Assign

on:
pull_request:
types: [opened, ready_for_review]

jobs:
assign:
runs-on: ubuntu-latest
steps:
- uses: hkusu/review-assign-action@v1
with:
assignees: ${{ github.actor }}
# 팀원 GitHub 아이디가 정해지면 콤마로 구분해 채운다 (예: reviewers: alice, bob)
reviewers: "xeoxxn, jjunh33, tnals0924, sangrae2325, leegain1"
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ dist-ssr
*.sw?

.env
.docs/plans
docs/plans
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@wanteddev:registry=https://npm.pkg.github.com/
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ React + TypeScript + Vite 기반 프론트엔드.
- 요청받은 범위만 수정한다. 인접 코드 개선·리팩토링은 임의로 하지 않는다.
- 테스트 코드는 지시하는 사람이 명시적으로 요청하지 않는 이상 작성하지 않는다.

## 코딩 컨벤션

자세한 내용은 `docs/conventions/coding-style.md` 참고. TypeScript strict, 네이밍, 폴더 구조, import 순서, Biome lint/format 규칙을 다룬다.

## Git 컨벤션

자세한 내용은 `docs/conventions/git-convention.md` 참고.
Expand Down
87 changes: 18 additions & 69 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,76 +1,25 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)

## React Compiler

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
# stream-client

```js
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
국민대학교 소프트웨어융합대학 통합 플랫폼 'STREAM' 프론트엔드 (React + TypeScript + Vite).

// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
## 개발 환경

// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
- Node: `.nvmrc` 참고 (`nvm use`)
- 패키지 매니저: [pnpm](https://pnpm.io/) — Corepack으로 관리한다 (`corepack enable` 후 `pnpm install`만 실행하면 `packageManager` 필드에 고정된 버전이 자동으로 쓰인다)

```bash
corepack enable
pnpm install
pnpm dev
```

You can also install [eslint-plugin-react-x](https://npmx.dev/package/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://npmx.dev/package/eslint-plugin-react-dom) for React-specific lint rules:

```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
## 스크립트

export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])

```
# stream-client
| 명령 | 설명 |
| --- | --- |
| `pnpm dev` | 개발 서버 실행 |
| `pnpm build` | 타입체크 후 프로덕션 빌드 |
| `pnpm preview` | 빌드 결과 미리보기 |
| `pnpm lint` | Biome lint |
| `pnpm format` | Biome로 포맷 적용 |
| `pnpm check` | Biome lint + format 검증 |
141 changes: 141 additions & 0 deletions biome.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
{
"$schema": "https://biomejs.dev/schemas/2.5.11/schema.json",

"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},

"files": {
"ignoreUnknown": false,
"includes": [
"**",
"!**/dist",
"!**/build",
"!**/coverage",
"!**/node_modules",
"!**/pnpm-lock.yaml",
"!**/*.d.ts",
"!**/public"
]
},

"formatter": {
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 80,
"attributePosition": "auto",
"bracketSpacing": true,
"expand": "auto"
},

"css": {
"parser": {
// Tailwind CSS 4 지시어(@theme, @apply 등) 파싱 허용 — 없으면 index.css의 @theme 블록에서 파싱 에러가 난다
"tailwindDirectives": true
},
"linter": {
// Tailwind 전용 at-rule과 충돌하는 CSS 린터는 끈다
"enabled": false
}
},

"linter": {
"enabled": true,

"domains": {
"react": "recommended"
},

"rules": {
"preset": "recommended",

"nursery": {
// Tailwind 클래스 순서를 자동 정렬
"useSortedClasses": {
"level": "error",
"fix": "safe",
"options": {
"attributes": ["class", "className"],
"functions": ["clsx", "cva", "cn", "twMerge", "twJoin"]
}
}
},

"correctness": {
"noUnusedImports": {
"level": "error",
"fix": "safe"
},
"noUnusedVariables": {
"level": "warn",
"fix": "none"
},
"noUnusedFunctionParameters": {
"level": "warn",
"fix": "none"
},
"noUndeclaredVariables": "warn"
},

"suspicious": {
"noDebugger": "error",
"noConsole": {
"level": "warn",
"fix": "none",
"options": {
"allow": ["log", "info", "warn", "error"]
}
},
"noVar": "error",
"noExplicitAny": "warn"
},

"style": {
"useConst": "error"
},

"a11y": {
// 모달 백드롭·오버레이 등 div/span 클릭 핸들러 패턴에서 불필요한 경고 방지
"noStaticElementInteractions": "off",
"useKeyWithClickEvents": "off",
"noSvgWithoutTitle": "off"
}
}
},

"assist": {
"enabled": true,
"actions": {
"source": {
"organizeImports": "on"
}
}
},

"javascript": {
"formatter": {
"quoteStyle": "double",
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"trailingCommas": "all",
"semicolons": "always",
"arrowParentheses": "always",
"bracketSameLine": false,
"bracketSpacing": true,
"attributePosition": "auto",
"expand": "auto"
}
},

"json": {
"parser": {
"allowComments": true,
"allowTrailingCommas": true
}
}
}
48 changes: 48 additions & 0 deletions docs/conventions/coding-style.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Coding Style

> TypeScript/React 코드 작성 시 지키는 공통 컨벤션.

## TypeScript

- `strict: true`. `any` 금지 — 불가피하면 `unknown` + 좁히기.
- 컴포넌트 props·외부에 노출하는 함수는 타입을 명시한다. 내부 지역 변수는 추론에 맡긴다.
- **객체 형태(컴포넌트 Props 등)는 `interface`**, `type`이어야만 하는 것(유니온·유틸리티 조합·별칭·조건부 타입)만 `type`으로 쓴다.
- 근거: TS 공식 핸드북의 휴리스틱 — *"use `interface` until you need to use features from `type`"*.
- 참고: [Handbook — Type Aliases vs Interfaces](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces)

## 네이밍

- 컴포넌트 파일/이름: PascalCase (`UserCard.tsx`).
- 훅: `useXxx`. 일반 함수/변수: camelCase. 상수: `UPPER_SNAKE_CASE`.
- 불리언: `is` / `has` / `should` 접두사.
- 폴더: 도메인명 소문자 또는 kebab-case.

## 폴더 구조

- 기능 기반(feature-based) 구조를 쓴다. `app/`(라우팅 껍데기)·`components/ui/`(공용 UI)·`hooks/`·`lib/`·`utils/`·`constants/`는 실제로 내용이 생길 때 만든다 — 빈 폴더를 미리 만들지 않는다.
- 화면 단위 기능이 생기면 `features/<기능>/`, 여러 화면이 공유하는 서버 계약(API·쿼리·타입)이 생기면 `entities/<도메인>/`을 그때 도입한다.
- import는 절대경로 `@/`(`./src/*`)를 쓴다. 상대경로는 같은 기능 폴더 내부에서만.
- 그룹 순서: ① 외부 라이브러리 → ② `@/` → ③ 상대경로. 저장 시 Biome의 `organizeImports`가 자동 정렬한다.

## 에러 / 비동기

- async는 try/catch 또는 서버 상태 라이브러리(도입 시)의 에러 상태로 다룬다. **빈 catch 금지**.
- 사용자에게 보이는 메시지와 개발 로깅을 구분한다.

## 주석

- "왜"를 적는다. "무엇"은 코드로 드러나게 한다.
- 주변 코드의 주석 밀도·언어를 따른다. 불필요한 주석 금지.

## Lint · Format

- **Biome 단일 도구**로 lint + format + import 정리. ESLint/Prettier는 쓰지 않는다.
- `pnpm check` — 검증만 (커밋·PR 전).
- `pnpm check:fix` — 자동 수정 + 포맷.
- 설정·룰셋: `biome.jsonc` 참고.

## 금지

- `console.log` 커밋 금지 (디버깅 후 제거; `console.info`/`warn`/`error`는 허용 — `biome.jsonc`의 `noConsole` 참고).
- 주석 처리된 죽은 코드 커밋 금지.
- 동일 기능 중복 구현 금지 — 새로 만들기 전에 기존 코드부터 검색한다.
22 changes: 0 additions & 22 deletions eslint.config.js

This file was deleted.

13 changes: 13 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>stream-client</title>
<link rel="preconnect" href="https://cdn.jsdelivr.net" />
<link
rel="stylesheet"
as="style"
crossorigin
href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard-jp-dynamic-subset.min.css"
/>
<link
rel="stylesheet"
as="style"
crossorigin
href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard-dynamic-subset.min.css"
/>
</head>
<body>
<div id="root"></div>
Expand Down
Loading