소스 정보
- 저장소
- dallay/profiletailors.com
- 최근 소스 활동
- 2026년 7월 29일 12:44
- 감지된 SKILL.md 언어
- 영어
- 스타
- 1
- 포크
- 0
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/dallay/profiletailors.com --skill vue명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Use when writing Playwright tests, fixing flaky tests, debugging failures, implementing Page Object Model, configuring CI/CD, optimizing performance, mocking APIs, handling authentication or OAuth, testing accessibility (axe-core), file uploads/downloads, date/time mocking, WebSockets, geolocation, permissions, multi-tab/popup flows, mobile/responsive layouts, touch gestures, GraphQL, error handling, offline mode, multi-user collaboration, third-party services (payments, email verification), console error monitoring, global setup/teardown, test annotations (skip, fixme, slow), test tags (@smoke, @fast, @critical, filtering with --grep), project dependencies, security testing (XSS, CSRF, auth), performance budgets (Web Vitals, Lighthouse), iframes, component testing, canvas/WebGL, service workers/PWA, test coverage, i18n/localization, Electron apps, or browser extension testing. Covers E2E, component, API, visual, accessibility, security, Electron, and extension testing.
Use when creating features, domain models, use cases, or organizing backend code with Hexagonal Architecture (Ports and Adapters) and CQRS.
Use when bootstrapping a new Spring Boot 4 backend from Spring Initializr, choosing Kotlin + WebFlux + Gradle defaults, defining a hexagonal package-by-feature structure, and wiring local development services for a reactive stack.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | vue |
| description | Use when working with .vue files, composables, Pinia stores, or form validation. |
| allowed-tools | Read, Edit, Write, Glob, Grep, Bash |
| metadata | {"author":"profiletailors","version":"1.0"} |
Conventions for Vue 3 development with Composition API, TypeScript, and the profiletailors component ecosystem.
.vue components@profiletailors/ui component libraryThis project follows a component maintainability standard that defines layering, composable extraction, component decomposition, type contracts, and code quality checks.
Read the full guide at:
.agents/skills/frontend-platform/vue/references/vue-component-maintainability.md
Key rules enforced by this standard:
<script setup> exceeds ~80 lines or contains computed/watch logicany, withDefaults for optional propsALWAYS use <script setup lang="ts">:
<script setup lang="ts">
// 1. Imports
import {computed, ref} from 'vue';
import {useUserStore} from '@/stores/user';
// 2. Type definitions
type Props = {
title: string;
count?: number;
isActive?: boolean;
};
// 3. Props with defaults
const props = withDefaults(defineProps<Props>(), {
count: 0,
isActive: false,
});
// 4. Emits with types
const emit = defineEmits<{
(e: 'update', value: number): void;
(e: 'close'): void;
}>();
// 5. Composables and stores
const userStore = useUserStore();
// 6. Reactive state
const localCount = ref(props.count);
// 7. Computed properties
const doubled = computed(() => localCount.value * 2);
// 8. Methods
const increment = () => {
localCount.value++;
emit('update', localCount.value);
};
</script>
<template>
<div class="card">
<h2>{{ title }}</h2>
<p>Count: {{ localCount }} (Doubled: {{ doubled }})</p>
<button @click="increment">Increment</button>
</div>
</template>
<style scoped>
.card {
padding: var(--space-4);
}
</style>
ALWAYS type state, getters, and actions:
// stores/user.ts
import {defineStore} from 'pinia';
import {api, isAxiosError} from '@/api';
import {toast} from 'vue-sonner';
type User = {
id: string;
name: string;
email: string;
};
type UserState = {
currentUser: User | null;
isLoading: boolean;
error: string | null;
};
export const useUserStore = defineStore('user', {
state: (): UserState => ({
currentUser: null,
isLoading: false,
error: null,
}),
getters: {
isAuthenticated: (state): boolean => state.currentUser !== null,
userInitials: (state): string => {
if (!state.currentUser) return '';
state..
.()
.( n[])
.();
},
},
: {
(: ): <> {
. = ;
. = ;
{
response = api.(id);
. = response.;
} (e) {
error = e ? e : ();
message = (e) && e.?.?.
? e...
: error. || ;
. = message;
toast.(, {: message});
} {
. = ;
}
},
(): {
. = ;
},
},
});
Return reactive values, prefix with use:
// composables/useCounter.ts
import {ref, computed, type Ref, type ComputedRef} from 'vue';
type UseCounterReturn = {
count: Ref<number>;
doubled: ComputedRef<number>;
increment: () => void;
decrement: () => void;
reset: () => void;
};
export const useCounter = (initial = 0): UseCounterReturn => {
const count = ref(initial);
const doubled = computed(() => count.value * 2);
const increment = () => count.value++;
const decrement = () => count.value--;
const reset = () => count.value = initial;
return {count, doubled, increment, decrement, reset};
};
CRITICAL: Manual validation on blur, NOT automatic:
<script setup lang="ts">
import {useForm} from 'vee-validate';
import {toTypedSchema} from '@vee-validate/zod';
import {z} from 'zod';
import {
FormField,
FormItem,
FormLabel,
FormControl,
FormMessage,
Input,
Button,
} from '@profiletailors/ui';
const schema = z.object({
email: z.string().email('Invalid email format'),
password: z.string().min(8, 'Must be at least 8 characters'),
});
type FormData = z.infer<typeof schema>;
const {handleSubmit, validateField, resetForm} = useForm<FormData>({
validationSchema: toTypedSchema(schema),
validateOnMount: false, // ✅ CRITICAL: Don't validate on mount
});
const onSubmit = handleSubmit((values) => {
console.log('Form submitted:', values);
});
</script>
<template>
<form @submit="onSubmit">
<FormField v-slot="{ componentField }" name="email">
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<!-- ✅ Manual validation on blur -->
<Input
type="email"
v-bind="componentField"
@blur="validateField('email')"
/>
</FormControl>
<FormMessage/>
</FormItem>
</FormField>
<Button type="submit">Submit</Button>
</form>
</template>
| Scenario | Approach |
|---|---|
| Parent → Child | Props |
| Child → Parent | emit() |
| Sibling/Distant | Pinia store |
| Provide/Inject | Rarely, for deeply nested |
NEVER use global event buses.
Use Shadcn-Vue components from @profiletailors/ui:
<script setup lang="ts">
import {Button, Card, CardHeader, CardTitle, CardContent} from '@profiletailors/ui';
</script>
<template>
<Card>
<CardHeader>
<CardTitle>Dashboard</CardTitle>
</CardHeader>
<CardContent>
<Button variant="default" @click="handleAction">
Take Action
</Button>
</CardContent>
</Card>
</template>
<script setup lang="ts">
import {onUnmounted, shallowRef} from 'vue';
// ✅ Use shallowRef for large objects that don't need deep reactivity
const largeData = shallowRef<LargeObject | null>(null);
// ✅ Clean up side effects
const intervalId = setInterval(() => {
// polling logic
}, 5000);
onUnmounted(() => {
clearInterval(intervalId);
});
</script>
<template>
<!-- ✅ v-once for truly static content -->
<footer v-once>
<p>© 2024 CVIX</p>
</footer>
<!-- ✅ v-memo for expensive lists -->
<div v-for="item in items" :key="item.id" v-memo="[item.id, item.updated]">
{{ item.name }}
</div>
</template>
❌ Options API - Always use Composition API with <script setup>
❌ any type - Always provide proper TypeScript types
❌ Mutating props - Props are read-only, emit events instead
❌ Global event bus - Use Pinia for cross-component state
❌ validate-on-blur prop - Use manual validateField() on @blur
❌ Field injection - Use constructor pattern in stores
<script setup lang="ts">
import {useI18n} from 'vue-i18n';
const {t} = useI18n();
</script>
<template>
<h1>{{ t('dashboard.title') }}</h1>
<p>{{ t('dashboard.welcome', { name: user.name }) }}</p>
</template>
# Development
pnpm --filter @profiletailors/webapp dev
# Testing
pnpm --filter @profiletailors/webapp vitest run
pnpm --filter @profiletailors/webapp vitest --watch
# Type checking
pnpm --filter @profiletailors/webapp vue-tsc --noEmit
# Linting
pnpm --filter @profiletailors/webapp lint