원클릭으로
component-api-scaffolding
Create new React components, API routes, SWR hooks, and context providers following repo patterns.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Create new React components, API routes, SWR hooks, and context providers following repo patterns.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Migrate from Next.js 15 to Next.js 16 and handle breaking changes
Configure Content Security Policy and security headers for the portfolio
Deploy Next.js to Cloudflare Workers using OpenNext adapter
Manage the canary token honeypot system for detecting security scanning
Write, debug, and optimize GROQ queries for Sanity CMS in this portfolio
Advanced TypeScript patterns and type safety as used in this portfolio
| name | component-api-scaffolding |
| description | Create new React components, API routes, SWR hooks, and context providers following repo patterns. |
Location: src/components/ui/
'use client';
import { useState } from 'react';
interface MyComponentProps {
title: string;
onAction: () => void;
}
export function MyComponent({ title, onAction }: Readonly<MyComponentProps>) {
const [state, setState] = useState('');
return (
<div className="rounded-xl border border-border-light dark:border-border-dark bg-white dark:bg-card-bg-dark p-5">
<h3 className="text-sm font-semibold text-text-primary-light dark:text-text-primary-dark">
{title}
</h3>
<button
type="button"
onClick={onAction}
className="mt-3 inline-flex items-center gap-2 rounded-lg bg-accent-pink px-4 py-2 text-sm font-medium text-white hover:bg-accent-pink-hover dark:hover:bg-accent-pink-hover-dark transition-colors"
>
Action
</button>
</div>
);
}
Component conventions:
PascalCase.tsx (e.g., MyComponent.tsx)export function MyComponent)interface with Readonly<> wrapper-light / -dark suffix pairsaria-label, role, semantic HTML'use client' at topLocation: src/components/sections/
'use client';
import { useCmsContent } from '@/hooks/useCmsContent';
export function MySection() {
const { profile } = useCmsContent();
return (
<section className="py-16 sm:py-20" id="my-section">
<div className="mx-auto max-w-6xl px-4 sm:px-6">
<h2 className="text-2xl font-bold text-text-primary-light dark:text-text-primary-dark">
Section Title
</h2>
{/* Content */}
</div>
</section>
);
}
Section conventions:
src/components/sections/id for navigationmax-w-6xl mx-auto px-4 sm:px-6 containerpy-16 sm:py-20useCmsContent() hookLocation: src/app/api/<route>/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
try {
// Logic here
return NextResponse.json({ data: result });
} catch (error) {
console.error('[API Error]', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
export async function POST(request: NextRequest) {
try {
const body = await request.json();
// Validate body
// Process
return NextResponse.json({ success: true }, { status: 201 });
} catch (error) {
console.error('[API Error]', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
API route conventions:
route.ts (not page.ts)GET, POST, PUT, DELETE)[API Name] for easy filteringNextResponse.json()Location: src/hooks/
import useSWR from 'swr';
const fetcher = (url: string) => fetch(url).then((res) => res.json());
export function useMyData() {
const { data, error, isLoading } = useSWR('/api/my-data', fetcher, {
revalidateOnFocus: true,
revalidateOnReconnect: true,
dedupingInterval: 60000,
});
return {
data: data ?? null,
error: error ?? null,
isLoading,
};
}
SWR conventions:
use<Name>.ts (e.g., useProjects.ts)?? null)dedupingInterval to prevent excessive requestsSWRConfig in tests for isolationLocation: src/hooks/ (for small state) or src/contexts/ (for complex state)
'use client';
import { createContext, useCallback, useContext, useMemo, useState } from 'react';
type MyContextValue = {
value: string;
setValue: (v: string) => void;
};
const MyContext = createContext<MyContextValue | null>(null);
export function MyProvider({ children }: { children: React.ReactNode }) {
const [value, setValue] = useState('');
const contextValue = useMemo(() => ({ value, setValue }), [value]);
return (
<MyContext.Provider value={contextValue}>
{children}
</MyContext.Provider>
);
}
export function useMyContext() {
const context = useContext(MyContext);
if (!context) throw new Error('useMyContext must be used within MyProvider');
return context;
}
Location: src/components/ui/
Modals use the base <Modal> component:
'use client';
import { Modal } from './Modal';
interface MyModalProps {
open: boolean;
onClose: () => void;
}
export function MyModal({ open, onClose }: Readonly<MyModalProps>) {
return (
<Modal open={open} onClose={onClose} title="My Modal">
<div className="px-5 py-6">
{/* Modal content */}
</div>
</Modal>
);
}
Modal conventions:
src/hooks/useModal.tsx (add to ModalName type)ModalProvider componentfullScreen prop for content-heavy modalstitle for accessibilityLocation: src/app/<route>/page.tsx
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Page Title | PP Namias',
description: 'Page description',
};
export default function MyPage() {
return (
<main>
{/* Page content */}
</main>
);
}
Page conventions:
metadata for SEO<main> as root element'use client' or use dynamic importsrc/
components/
ui/ # Reusable UI components (Button, Modal, Card)
sections/ # Page sections (Hero, Projects, Contact)
layout/ # Layout components (Header, Footer, Navigation)
hooks/ # Custom React hooks
contexts/ # React context providers
lib/ # Utilities, constants, helpers
app/ # Next.js App Router pages and API routes
__tests__/ # Test files (mirrors src/ structure)
| Type | Convention | Example |
|---|---|---|
| Component file | PascalCase | ContactModal.tsx |
| Hook file | camelCase, use prefix | useCmsContent.ts |
| Utility file | camelCase | buildEmailLinks.ts |
| Constant file | camelCase | constants.ts |
| Type file | camelCase | types.ts |
| Test file | *.test.tsx | ContactModal.test.tsx |
| API route | route.ts | src/app/api/chat/route.ts |
'use client' on components that use hooks<div onClick> instead of <button onClick> (accessibility)Readonly<>useModal.tsxnpx tsc --noEmit)npm run lint)