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
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,3 @@ gh-pages
*.sw?

.claude
docs
112 changes: 112 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# AGENTS.md

이 문서는 LinKU에서 작업하는 코딩 에이전트를 위한 빠른 진입점입니다.
설계, 동작, 배포, 협업 규칙이 관련된 작업이라면 이 문서를 먼저 읽고,
이후 `docs/ARCHITECTURE.md`와 `docs/CONTRIBUTING.md`를 확인하세요.

## 프로젝트 개요

LinKU는 건국대학교 학생을 위한 Manifest V3 Chrome Extension입니다.
팝업 UI에서 학교 및 학생 서비스 링크, 공지, todo, banner, template 편집과
공유, 도서관 좌석 현황, QR 생성 같은 Labs 기능을 제공합니다.

이 저장소는 프론트엔드 확장 프로그램 코드만 포함합니다. LinKU backend와의
통신은 `VITE_API_BASE_URL`을 기준으로 이루어지며, 학교 및 외부 사이트 접근은
`public/manifest.json`의 `host_permissions`가 제어합니다.

## 읽는 순서

1. `README.md`: 제품 소개와 기본 실행 명령을 확인합니다.
2. `docs/ARCHITECTURE.md`: 런타임 구조, 소스 지도, 데이터 흐름을 파악합니다.
3. `docs/CONTRIBUTING.md`: 브랜치, PR, 검증, 릴리즈 규칙을 확인합니다.
4. 위 문맥을 이해한 뒤 관련 source file을 읽습니다.

## 런타임 구성

- Popup UI: `index.html` -> `src/main.tsx` -> `src/routes.tsx`
- Root app shell: `src/App.tsx`
- Background service worker: `src/background/index.ts`
- OAuth handler: `src/background/handlers/oauth.ts`
- Extension manifest: `public/manifest.json`

현재 구조에는 content script가 없습니다. `public/manifest.json`이 변경되지 않는
한 페이지 주입 기능이 존재한다고 가정하지 마세요.

## 공통 명령

```bash
pnpm install
pnpm run dev
pnpm run build:local
pnpm run lint
```

Chrome에서 확장 프로그램을 검증하기 전에는 `pnpm run build:local`을 실행하고,
생성된 `dist/` 디렉터리를 `chrome://extensions`에서 Developer Mode로
로드하세요.

`pnpm run dev`는 React UI 반복 작업에는 유용하지만, `chrome.identity`,
`chrome.storage`, `chrome.action`, service worker 동작은 빌드된 확장 프로그램
환경에서 검증해야 합니다.

## 변경 규칙

- `public/manifest.json`의 extension version을 직접 수정하지 마세요.
운영 workflow가 `scripts/updateVersion.js`를 통해 version을 올립니다.
- Chrome permission을 추가하거나 넓힐 때는 해당 permission이 왜 필요한지
문서화하세요.
- `host_permissions`는 보안상 민감한 영역입니다. 가능한 한 넓은 패턴보다
구체적인 domain을 사용하세요.
- access token, refresh token, auth code, private user data를 로그로 남기지
마세요.
- `README.md`는 제품 소개와 빠른 시작 중심으로 유지하세요. 협업 및 기술
세부사항은 `docs/` 아래에 둡니다.
- 이미 working tree에 존재하는 사용자 변경사항을 보존하세요. 편집 전
`git status`를 확인하세요.

## 소스 책임 지도

- `src/components/Tabs/`: popup tab 기능.
- `src/components/Editor/`: template editor control과 canvas.
- `src/pages/`: route 단위 page.
- `src/layouts/`: route layout wrapper.
- `src/contexts/`: React Context 기반 상태 container.
- `src/hooks/`: feature 단위 hook.
- `src/apis/`: LinKU backend API wrapper.
- `src/apis/external/`: 학교 또는 외부 서비스 연동.
- `src/background/`: Manifest V3 service worker와 message handling.
- `src/utils/`: storage, auth, analytics, template, Chrome helper utility.
- `src/types/`: 공유 TypeScript data contract.
- `src/constants/`: link list 같은 정적 app data.

## 주의 영역

- `public/manifest.json`: permission, entrypoint, Chrome Web Store 심사에
직접 영향을 줍니다.
- `scripts/updateVersion.js`: release automation과 version bump에 관여합니다.
- `.github/workflows/`: Chrome Web Store upload, GitHub Pages, release 흐름을
제어합니다.
- `src/background/handlers/oauth.ts`: auth flow와 token handling을 담당합니다.
- `src/apis/client.ts`: auth interceptor, backend response parsing,
silent reauth를 담당합니다.
- `src/apis/external/`: third-party 또는 school page markup에 의존하는 parsing
logic이 있습니다.
- `src/utils/templateStorage.ts`: local draft persistence와 migration risk가
있습니다.

## 검증 기준

code change라면 최소한 다음 명령을 실행하세요.

```bash
pnpm run build:local
```

TypeScript, React hooks, shared utilities, CI/lint configuration을 수정했다면
`pnpm run lint`도 실행하세요. 기존 lint issue 때문에 실패한다면 최종 보고에
명확히 적고, 관련 없는 실패를 숨기지 마세요.

UI 또는 확장 프로그램 동작을 변경했다면 `dist/`를 Chrome에 직접 로드해 관련
popup 흐름을 검증하세요. OAuth, storage, badge, service-worker 변경은 Vite
dev mode와 실제 extension runtime이 다르므로 브라우저 검증이 필요합니다.

259 changes: 259 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
# 아키텍처

이 문서는 LinKU가 런타임에서 어떻게 구성되는지, 그리고 어느 위치를 어떻게
수정해야 안전한지 설명합니다.

## 시스템 개요

LinKU는 Vite, React, TypeScript, Tailwind CSS로 만든 Manifest V3 Chrome
Extension입니다. 확장 프로그램은 두 개의 런타임 영역을 가집니다.

- `index.html`에서 렌더링되는 Popup UI.
- `src/background/index.ts`에서 빌드되는 Background service worker.

현재 프로젝트에는 content script가 없습니다. 확장 프로그램은 임의의 web page에
UI나 logic을 주입하지 않습니다. 대부분의 user interaction은 popup 내부에서
일어납니다.

## Backend 의존성

LinKU는 frontend-only extension이 아닙니다. auth, template sync, posted
template, icons, alerts 같은 backend 연동 기능은 `VITE_API_BASE_URL`이
올바르게 설정되어야 동작합니다.

로컬 개발 환경에서 `VITE_API_BASE_URL`이 없거나 placeholder 값으로 남아
있다면, 다음 기능은 정상적으로 동작하지 않을 수 있습니다.

- Google OAuth login
- template sync와 posted-template API
- icons API
- alerts subscription API
- `src/apis/` 아래 LinKU backend를 호출하는 기타 기능

## 빌드 모델

`vite.config.ts`는 extension mode에서 multi-entry build를 설정합니다.

- `index.html`은 popup entry가 됩니다.
- `src/background/index.ts`는 `background/index.js`가 됩니다.

`gh-pages` mode에서는 build output이 `gh-pages/`로 바뀌고, static hosting을
위해 banner asset이 복사됩니다. extension build의 output directory는
`dist/`입니다.

중요한 script:

```bash
pnpm run dev
pnpm run build:local
pnpm run build
pnpm run watch:local
pnpm run build:gh-pages
```

`pnpm run build`는 build 전에 manifest patch version을 증가시킵니다. local
validation에서 version bump를 원하지 않는다면 `pnpm run build:local`을
사용하세요.

## 런타임 진입점

Popup UI 흐름:

```text
index.html
-> src/main.tsx
-> src/routes.tsx
-> src/App.tsx
-> route pages and layouts
```

Background worker 흐름:

```text
public/manifest.json
-> background.service_worker: background/index.js
-> src/background/index.ts
-> src/background/handlers/oauth.ts
```

popup은 React Router의 hash routing을 사용합니다. Chrome extension popup
page는 일반적인 server-backed web route처럼 동작하지 않기 때문에 hash routing을
사용합니다.

## 라우트

route는 `src/routes.tsx`에 정의되어 있습니다.

- `/`: `MainLayout` 안의 main popup page.
- `/editor`: 새 template editor.
- `/editor/:templateId`: 기존 template editor.
- `/templates`: owned/local template list.
- `/gallery`: public posted-template gallery.
- `*`: not found page.

`src/App.tsx`는 root error boundary, global providers, page-view analytics,
toast rendering을 제공합니다.

## 소스 구조

```text
src/
apis/ LinKU backend API wrapper
apis/external/ 학교 또는 외부 서비스 integration
assets/ local image와 SVG asset
background/ Manifest V3 service worker code
components/ feature component와 UI primitive
constants/ 정적 app data
contexts/ React Context 상태 container
hooks/ reusable React hook
layouts/ route layout wrapper
pages/ route 단위 screen
types/ 공유 TypeScript contract
utils/ storage, auth, analytics, template, Chrome helper
```

## 주요 기능 영역

기본 popup 기능:

- Link groups: `src/components/Tabs/LinkGroup.tsx`
- Banners: `src/components/Tabs/ImageCarousel.tsx`
- Todo list: `src/components/Tabs/TodoList/`
- Alerts: `src/components/Tabs/Alerts/`
- Labs: `src/components/Labs/`

Template system 구성:

- Editor page: `src/pages/EditorPage.tsx`
- Template list: `src/pages/TemplateListPage.tsx`
- Public gallery: `src/pages/GalleryPage.tsx`
- Editor state: `src/contexts/EditorContext.tsx`
- Editor UI: `src/components/Editor/`
- Local template persistence: `src/utils/templateStorage.ts`
- Template helper: `src/utils/template.ts`

Auth 및 account 관련 UI:

- OAuth popup/background bridge: `src/utils/oauth.ts`
- Background OAuth handler: `src/background/handlers/oauth.ts`
- API auth interceptor: `src/apis/client.ts`
- Email verification dialog: `src/components/EmailVerificationDialog.tsx`
- Settings dialog: `src/components/SettingsDialog.tsx`

## Popup과 Background 통신

popup은 `chrome.runtime.sendMessage`를 사용해 background service worker와
통신합니다.

message type과 guard는 `src/background/types.ts`에 있습니다.

background worker가 처리하는 일:

- Google login request.
- Silent reauth request.
- Extension install/update event.
- Badge count initialization.
- `chrome.storage.local` 변경에 따른 badge count update.

OAuth는 background worker에 있습니다. `chrome.identity.launchWebAuthFlow`는
일반 browser page flow가 아니라 extension API로 다뤄야 하기 때문입니다.

## Backend API 흐름

중앙 HTTP client는 `src/apis/client.ts`입니다.

주요 책임:

- `VITE_API_BASE_URL`에서 backend URL을 구성합니다.
- `chrome.storage.local`의 bearer token을 request에 붙입니다.
- backend response envelope을 parsing합니다.
- token-expired backend code `5004`를 감지합니다.
- background worker에 silent reauth를 요청합니다.
- silent reauth 성공 후 original request를 한 번 retry합니다.
- hard auth failure에서 `auth:unauthorized`를 dispatch합니다.

feature-specific API module은 fetch behavior를 중복 구현하지 말고 이 client를
사용해야 합니다.

## Storage 모델

현재 storage는 두 browser storage system으로 나뉘어 있습니다.

- `chrome.storage.local`: auth token, user profile state, settings, custom
todo, library token, badge count.
- `localStorage`: `src/utils/templateStorage.ts`를 통한 template draft와 local
template persistence.

이 분리는 과거 설계의 결과입니다. template local persistence flow를 직접
수정하는 경우가 아니라면, 새 extension-wide state는 `chrome.storage.local`을
우선 사용하세요.

stored data shape를 바꿀 때는 기존 user의 migration behavior를 고려해야
합니다. LinKU는 실제 user에게 배포되는 extension이므로 가능한 한 backward
compatible해야 합니다.

## 인증

Google OAuth flow는 backend-mediated flow입니다.

1. popup이 background worker에 login 시작을 요청합니다.
2. background worker가 extension redirect URI를 계산합니다.
3. background worker가 `chrome.identity.launchWebAuthFlow`로 backend Google
OAuth URL을 엽니다.
4. backend가 auth code를 포함해 redirect합니다.
5. background worker가 backend를 통해 code를 token으로 교환합니다.
6. token은 `chrome.storage.local`에 저장됩니다.
7. popup/API state가 auth success 또는 failure에 반응합니다.

auth code, access token, refresh token, full token response를 로그로 남기지
마세요.

## 외부 연동

`src/apis/external/`에는 이 repository가 소유하지 않는 integration이 있습니다.
예시는 eCampus, library, banners, RSS, HTML parsing입니다.

이 module들은 external service의 response shape 또는 DOM structure가 바뀌면
깨질 수 있습니다. 이 영역의 변경은 PR에 manual verification notes를 포함해야
합니다.

## UI 시스템

UI는 다음을 사용합니다.

- Styling에는 Tailwind CSS를 사용합니다.
- `src/components/ui/` 아래에는 shadcn-style Radix wrapper가 있습니다.
- Icon에는 `lucide-react`를 사용합니다.
- Toast notification에는 `sonner`를 사용합니다.
- Editor drag behavior에는 `@dnd-kit/*`를 사용합니다.
- Carousel behavior에는 `embla-carousel`을 사용합니다.

새 component library를 도입하기보다 existing UI primitive와 local pattern을
우선 사용하세요.

## CI와 배포

GitHub Actions workflow는 `.github/workflows/`에 있습니다.

- `pr-build-check.yml`: PR에서 local production-like build check를 실행합니다.
- `upload-chrome-extension-draft.yml`: main에서 Chrome Web Store draft를
upload합니다.
- `create-release.yml`: GitHub Release를 만들고 built zip을 첨부합니다.
- `deploy-gh-pages.yml`: static assets/pages를 `gh-pages`에 deploy합니다.

main branch는 release-sensitive합니다. versioning과 deployment behavior는
의도적으로 변경하고 PR에 문서화해야 합니다.

## 알려진 기술 부채

- lint는 설정되어 있지만 현재 PR CI에서 강제하지 않습니다.
- test framework 또는 automated browser extension test suite가 없습니다.
- `README.md`는 product-focused 문서이며, 깊은 협업 문서는 `docs/` 아래에
있습니다.
- 일부 production code에 diagnostic logging이 남아 있습니다.
- `public/manifest.json`에는 broad host permissions가 포함되어 있습니다.
- template persistence는 `localStorage`를 사용하고, 다른 extension state는
`chrome.storage.local`을 사용합니다.

이 항목들은 별도 cleanup PR로 다루기 좋습니다. unrelated feature work에 섞지
마세요.
Loading
Loading