This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
- Install:
pnpm install(this repo uses pnpm, not npm/yarn — seepnpm-lock.yaml) - Dev server:
pnpm dev - Build:
pnpm build - Lint:
pnpm lint— runsoxlint . --fixtheneslint . --fix --cache; both auto-fix and mutate files - Format:
pnpm format—prettier --writeonsrc/only (not the whole repo) - No test suite exists in this repo yet.
- Vue 3
<script setup>, plain JavaScript (no TypeScript). Composition API with Pinia stores defined asdefineStore('name', () => { ... }). - Styling is 100% Tailwind utility classes in templates — no
<style>blocks, no SCSS. Design tokens live insrc/style.cssas Tailwind v4 CSS-first theme:@themedefines color tokens (primary-50~800green scale,grey-white/grey-30~500), and@utilitydefines typography tokens (text-head1/head2/head3/body1~4/caption, all Pretendard-based). Prefer these tokens; colors that don't match the scale still fall back to Tailwind arbitrary-value hex classes (e.g.text-[#737373]). - Global font is Pretendard (CDN import at the top of
src/style.css). Button.vue(src/shared/components/Button.vue) defaults torounded-[14px](variant:primary/outline/accent/danger); pass thepillprop for a fully-rounded button — currently only the login screen's Kakao/Google buttons use it.- Native
<select>can't be restyled once open, so any picker-style field (category, bank, etc.) is a hand-built inline dropdown — a toggle button plus an absolutely-positioned option list closed on outside click — not a real<select>. Seesrc/features/onboarding/components/JobFormModal.vuefor the pattern. - Path alias
@→src/(defined in bothvite.config.jsandjsconfig.json). - Feature code lives in
src/features/<name>/with a<Name>View.vueand an optional co-locatedstore.js. Shared code lives insrc/shared/(components/,components/icons/,api/,store/). - Icons are hand-authored, template-only SVG SFCs under
src/shared/components/icons/, usingstroke/fill="currentColor"so color is controlled via Tailwindtext-*classes on the consumer. - Auth-gated routes set
meta: { requiresAuth: true }on the parent layout route; a globalrouter.beforeEachinsrc/app/router/index.jschecksuseAuthStore().isAuthenticated.meta: { requiresOnboarding: true }gates onauthStore.user?.onboardingCompleted(populated byGET /auth/me), not a local flag — there's no explicit "mark onboarding complete" API, so the client just re-fetches/auth/meat the end of the onboarding flow and trusts whatever the server says.
useAuthStore().tryRefresh()(src/features/auth/store.js) and both login handlers inLoginView.vuefake a successful login only whenVITE_API_BASE_URLis empty (currently only.env.production, until a prod backend URL is set —pnpm devnow hits the real backend).refreshTokenis persisted tolocalStorage;accessTokenis memory-only and gets re-derived viaPOST /auth/refreshon boot (main.js) and on 401 (axiosInstance.js).- OAuth login is frontend-driven:
LoginView.vueredirects straight to Kakao/Google's own authorize URL (needsVITE_KAKAO_CLIENT_ID/VITE_GOOGLE_CLIENT_ID), the provider redirects back to/auth/callback?code=...&state=kakao|google, andAuthCallbackView.vueexchanges the code viaGET /api/auth/oauth/{provider}. This is not the Spring Security/oauth2/authorization/{provider}convention. pnpm lintruns two linters with--fix— it will silently rewrite files.- On horizontally-scrolling flex containers (
overflow-x-auto+flex),paddingon the container is ignored in some WebView contexts (confirmed in this app's own WebView, not reproducible in desktop Chrome). Use ashrink-0spacer element plus per-itemmargininstead — see the job-recommendation row insrc/features/home/HomeView.vue.
- Commit messages follow Conventional Commits (
feat:,fix:,chore:, etc.). - Never add a
Co-Authored-Bytrailer to commits in this repo. - Branch creation, issues, and PRs are managed by the user — don't create them unless explicitly asked.