feat: add verification methodology and writing plans skills

This commit is contained in:
duthaho
2025-11-29 23:23:04 +07:00
parent 96d9217c31
commit 3c224790f9
80 changed files with 30860 additions and 0 deletions
@@ -0,0 +1,245 @@
---
title: Django
description: Django ORM, views, and REST framework patterns
---
The Django skill provides expertise in Django web framework including ORM, class-based views, and Django REST Framework.
## When Activated
- Python web applications
- Admin interfaces
- Django REST Framework APIs
- Working with Django projects
## Core Patterns
### Models
```python
from django.db import models
class User(models.Model):
email = models.EmailField(unique=True)
name = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_at']
indexes = [
models.Index(fields=['email']),
]
def __str__(self):
return self.email
```
### Views (Class-based)
```python
from django.views.generic import ListView, DetailView, CreateView
class UserListView(ListView):
model = User
template_name = 'users/list.html'
context_object_name = 'users'
paginate_by = 20
class UserDetailView(DetailView):
model = User
template_name = 'users/detail.html'
context_object_name = 'user'
class UserCreateView(CreateView):
model = User
fields = ['email', 'name']
template_name = 'users/create.html'
success_url = '/users/'
```
### Django REST Framework
```python
from rest_framework import serializers, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'email', 'name', 'created_at']
read_only_fields = ['created_at']
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
@action(detail=True, methods=['post'])
def activate(self, request, pk=None):
user = self.get_object()
user.is_active = True
user.save()
return Response({'status': 'activated'})
```
### URLs
```python
from django.urls import path, include
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('users', UserViewSet)
urlpatterns = [
path('api/', include(router.urls)),
path('users/', UserListView.as_view(), name='user-list'),
path('users/<int:pk>/', UserDetailView.as_view(), name='user-detail'),
]
```
## Best Practices
1. **Use class-based views for standard CRUD**
2. **Define model methods for business logic**
3. **Use serializers for validation**
4. **Add proper permissions**
5. **Use select_related/prefetch_related for queries**
## Common Pitfalls
### N+1 Queries
```python
# ❌ BAD: N+1 query problem
users = User.objects.all()
for user in users:
print(user.profile.bio) # Separate query for each user
# ✅ GOOD: Use select_related
users = User.objects.select_related('profile').all()
for user in users:
print(user.profile.bio) # Single query
```
### Missing Migrations
```python
# ❌ BAD: Forgetting migrations
# After changing models, forgetting to:
python manage.py makemigrations
python manage.py migrate
# ✅ GOOD: Always create and run migrations
python manage.py makemigrations
python manage.py migrate
```
### No Validation
```python
# ❌ BAD: Direct model creation
user = User.objects.create(email=request.POST['email'])
# ✅ GOOD: Use serializer for validation
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save()
else:
return Response(serializer.errors, status=400)
```
## Advanced Patterns
### Custom Managers
```python
class ActiveUserManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(is_active=True)
class User(models.Model):
# ...
objects = models.Manager()
active = ActiveUserManager()
# Usage
all_users = User.objects.all()
active_users = User.active.all()
```
### Signals
```python
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
```
### Permissions
```python
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.owner == request.user
class UserViewSet(viewsets.ModelViewSet):
permission_classes = [IsOwnerOrReadOnly]
# ...
```
### Pagination
```python
from rest_framework.pagination import PageNumberPagination
class StandardResultsSetPagination(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
max_page_size = 100
class UserViewSet(viewsets.ModelViewSet):
pagination_class = StandardResultsSetPagination
# ...
```
## Testing
```python
from django.test import TestCase
from rest_framework.test import APITestCase
class UserModelTest(TestCase):
def test_create_user(self):
user = User.objects.create(
email='test@example.com',
name='Test User'
)
self.assertEqual(user.email, 'test@example.com')
class UserAPITest(APITestCase):
def test_list_users(self):
response = self.client.get('/api/users/')
self.assertEqual(response.status_code, 200)
def test_create_user(self):
data = {'email': 'new@example.com', 'name': 'New User'}
response = self.client.post('/api/users/', data)
self.assertEqual(response.status_code, 201)
```
## Related Skills
- [Python](/claudekit/skills/languages/python) - Python language
- [PostgreSQL](/claudekit/skills/databases/postgresql) - Database
- [pytest](/claudekit/skills/testing/pytest) - Testing
- [OpenAPI](/claudekit/skills/api/openapi) - API documentation
@@ -0,0 +1,283 @@
---
title: FastAPI
description: FastAPI async patterns, Pydantic validation, and OpenAPI documentation
---
The FastAPI skill provides expertise in building REST APIs with Python, async patterns, Pydantic validation, and automatic OpenAPI documentation.
## When Activated
- Building REST APIs with Python
- Async web applications
- OpenAPI/Swagger documentation needed
- Working with FastAPI framework
## Core Patterns
### Route Definition
```python
from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel
app = FastAPI()
class UserCreate(BaseModel):
email: str
name: str
class UserResponse(BaseModel):
id: int
email: str
name: str
@app.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user: UserCreate):
# Create user logic
return UserResponse(id=1, **user.model_dump())
@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
user = await get_user_by_id(user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
```
### Dependency Injection
```python
from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession
async def get_db() -> AsyncGenerator[AsyncSession, None]:
async with async_session_maker() as session:
yield session
@app.get("/users")
async def list_users(db: AsyncSession = Depends(get_db)):
result = await db.execute(select(User))
return result.scalars().all()
```
### Router Organization
```python
from fastapi import APIRouter
router = APIRouter(prefix="/users", tags=["users"])
@router.get("/")
async def list_users():
pass
@router.post("/")
async def create_user(user: UserCreate):
pass
# In main.py
app.include_router(router)
```
### Request Validation
```python
from pydantic import BaseModel, EmailStr, Field
class UserCreate(BaseModel):
email: EmailStr
name: str = Field(min_length=1, max_length=100)
age: int = Field(ge=0, le=150)
class Config:
json_schema_extra = {
"example": {
"email": "user@example.com",
"name": "John Doe",
"age": 30
}
}
```
### Error Handling
```python
from fastapi import HTTPException, status
from fastapi.responses import JSONResponse
class UserNotFoundError(Exception):
pass
@app.exception_handler(UserNotFoundError)
async def user_not_found_handler(request, exc):
return JSONResponse(
status_code=status.HTTP_404_NOT_FOUND,
content={"detail": "User not found"}
)
@app.get("/users/{user_id}")
async def get_user(user_id: int):
user = await find_user(user_id)
if not user:
raise UserNotFoundError()
return user
```
### Background Tasks
```python
from fastapi import BackgroundTasks
def send_email(email: str, message: str):
# Send email logic
pass
@app.post("/users")
async def create_user(
user: UserCreate,
background_tasks: BackgroundTasks
):
new_user = await create_user_in_db(user)
background_tasks.add_task(send_email, user.email, "Welcome!")
return new_user
```
## Best Practices
1. **Use Pydantic models for request/response validation**
2. **Organize routes with APIRouter**
3. **Use dependency injection for services**
4. **Return proper HTTP status codes**
5. **Add OpenAPI descriptions and examples**
## Common Pitfalls
### Blocking I/O in Async
```python
# ❌ BAD: Blocking call in async function
@app.get("/users")
async def list_users():
users = blocking_db_call() # Blocks event loop
return users
# ✅ GOOD: Use async libraries
@app.get("/users")
async def list_users(db: AsyncSession = Depends(get_db)):
result = await db.execute(select(User))
return result.scalars().all()
```
### Missing Response Models
```python
# ❌ BAD: No response model
@app.get("/users/{user_id}")
async def get_user(user_id: int):
return await get_user_by_id(user_id)
# ✅ GOOD: Define response model
@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
return await get_user_by_id(user_id)
```
### Not Using HTTPException
```python
# ❌ BAD: Returning error dict
@app.get("/users/{user_id}")
async def get_user(user_id: int):
user = await find_user(user_id)
if not user:
return {"error": "Not found"} # Returns 200!
return user
# ✅ GOOD: Raise HTTPException
@app.get("/users/{user_id}")
async def get_user(user_id: int):
user = await find_user(user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
```
## Advanced Patterns
### Middleware
```python
from fastapi import Request
import time
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
```
### Authentication
```python
from fastapi import Security, HTTPException
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
security = HTTPBearer()
async def get_current_user(
credentials: HTTPAuthorizationCredentials = Security(security)
) -> User:
token = credentials.credentials
user = await verify_token(token)
if not user:
raise HTTPException(status_code=401, detail="Invalid token")
return user
@app.get("/profile")
async def get_profile(current_user: User = Depends(get_current_user)):
return current_user
```
### CORS
```python
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["https://example.com"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
```
## Testing
```python
from fastapi.testclient import TestClient
client = TestClient(app)
def test_create_user():
response = client.post(
"/users",
json={"email": "test@example.com", "name": "Test"}
)
assert response.status_code == 201
assert response.json()["email"] == "test@example.com"
def test_get_nonexistent_user():
response = client.get("/users/999")
assert response.status_code == 404
```
## Related Skills
- [Python](/claudekit/skills/languages/python) - Python language
- [Pydantic](/claudekit/skills/languages/python) - Data validation
- [PostgreSQL](/claudekit/skills/databases/postgresql) - Database
- [pytest](/claudekit/skills/testing/pytest) - Testing
@@ -0,0 +1,404 @@
---
title: Next.js
description: Next.js App Router, Server Components, and full-stack patterns
---
The Next.js skill provides expertise in Next.js with App Router, Server Components, Server Actions, and full-stack development patterns.
## When Activated
- React applications with SSR/SSG
- Full-stack applications
- App Router patterns
- Working in `app/` directory
## Core Patterns
### App Router Structure
```
app/
├── layout.tsx # Root layout
├── page.tsx # Home page
├── loading.tsx # Loading UI
├── error.tsx # Error UI
├── api/
│ └── users/
│ └── route.ts # API route
└── users/
├── page.tsx # Users page
└── [id]/
└── page.tsx # User detail
```
### Server Components
```tsx
// app/users/page.tsx - Server Component (default)
async function UsersPage() {
const users = await db.users.findMany();
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
```
### Client Components
```tsx
'use client';
import { useState } from 'react';
export function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}
```
### API Routes
```typescript
// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function GET() {
const users = await db.users.findMany();
return NextResponse.json(users);
}
export async function POST(request: NextRequest) {
const data = await request.json();
const user = await db.users.create({ data });
return NextResponse.json(user, { status: 201 });
}
```
### Server Actions
```tsx
// app/actions.ts
'use server';
export async function createUser(formData: FormData) {
const name = formData.get('name') as string;
await db.users.create({ data: { name } });
revalidatePath('/users');
}
// app/users/new/page.tsx
import { createUser } from '@/app/actions';
export default function NewUserPage() {
return (
<form action={createUser}>
<input name="name" required />
<button type="submit">Create</button>
</form>
);
}
```
### Dynamic Routes
```tsx
// app/users/[id]/page.tsx
interface PageProps {
params: { id: string };
}
export default async function UserPage({ params }: PageProps) {
const user = await db.users.findUnique({
where: { id: params.id }
});
if (!user) {
notFound();
}
return <div>{user.name}</div>;
}
```
### Layouts
```tsx
// app/layout.tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<nav>{/* Navigation */}</nav>
<main>{children}</main>
<footer>{/* Footer */}</footer>
</body>
</html>
);
}
```
## Best Practices
1. **Use Server Components by default**
2. **Add 'use client' only when needed**
3. **Colocate data fetching with components**
4. **Use loading.tsx for suspense boundaries**
5. **Implement proper error boundaries**
## Common Pitfalls
### Using Hooks in Server Components
```tsx
// ❌ BAD: Hooks in Server Component
export default async function Page() {
const [state, setState] = useState(0); // Error!
return <div>{state}</div>;
}
// ✅ GOOD: Mark as Client Component
'use client';
export default function Page() {
const [state, setState] = useState(0);
return <div>{state}</div>;
}
```
### Large Client Bundles
```tsx
// ❌ BAD: Entire page as Client Component
'use client';
export default function Page() {
const [count, setCount] = useState(0);
const data = await fetchData(); // Can't use await in Client Component
return (
<div>
<HeavyComponent />
<button onClick={() => setCount(c => c + 1)}>{count}</button>
</div>
);
}
// ✅ GOOD: Extract interactive parts only
export default async function Page() {
const data = await fetchData(); // Server Component can await
return (
<div>
<HeavyComponent data={data} /> {/* Server Component */}
<Counter /> {/* Small Client Component */}
</div>
);
}
// Counter.tsx
'use client';
export function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
```
### Missing Loading States
```tsx
// ❌ BAD: No loading state
export default async function Page() {
const data = await slowFetch();
return <div>{data}</div>;
}
// ✅ GOOD: Add loading.tsx
// app/page.tsx
export default async function Page() {
const data = await slowFetch();
return <div>{data}</div>;
}
// app/loading.tsx
export default function Loading() {
return <div>Loading...</div>;
}
```
### Not Revalidating After Mutations
```tsx
// ❌ BAD: No revalidation
'use server';
export async function createUser(data: FormData) {
await db.users.create({ data: getData(data) });
// Page still shows old data
}
// ✅ GOOD: Revalidate path
'use server';
export async function createUser(data: FormData) {
await db.users.create({ data: getData(data) });
revalidatePath('/users');
redirect('/users');
}
```
## Data Fetching Patterns
### Parallel Data Fetching
```tsx
export default async function Page() {
// Fetch in parallel
const [users, posts] = await Promise.all([
fetchUsers(),
fetchPosts(),
]);
return (
<div>
<UserList users={users} />
<PostList posts={posts} />
</div>
);
}
```
### Sequential Data Fetching
```tsx
export default async function UserPage({ params }: { params: { id: string } }) {
const user = await fetchUser(params.id);
const posts = await fetchUserPosts(user.id); // Depends on user
return (
<div>
<h1>{user.name}</h1>
<PostList posts={posts} />
</div>
);
}
```
### Streaming with Suspense
```tsx
import { Suspense } from 'react';
export default function Page() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<Skeleton />}>
<SlowComponent />
</Suspense>
<FastComponent />
</div>
);
}
async function SlowComponent() {
const data = await slowFetch();
return <div>{data}</div>;
}
```
## Caching and Revalidation
### Time-Based Revalidation
```tsx
// Revalidate every hour
export const revalidate = 3600;
export default async function Page() {
const data = await fetch('https://api.example.com/data', {
next: { revalidate: 3600 }
});
return <div>{JSON.stringify(data)}</div>;
}
```
### On-Demand Revalidation
```tsx
// app/actions.ts
'use server';
import { revalidatePath, revalidateTag } from 'next/cache';
export async function createPost(data: FormData) {
await db.posts.create({ data: getData(data) });
revalidatePath('/posts');
// or
revalidateTag('posts');
}
```
## Metadata
```tsx
import { Metadata } from 'next';
export const metadata: Metadata = {
title: 'User Profile',
description: 'View user profile information',
};
export default function Page() {
return <div>Profile</div>;
}
// Dynamic metadata
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const user = await fetchUser(params.id);
return {
title: `${user.name}'s Profile`,
description: `Profile page for ${user.name}`,
};
}
```
## Integration with Other Skills
### With React
See [React skill](/claudekit/skills/frameworks/react) for component patterns and hooks.
### With TypeScript
Full TypeScript integration:
```tsx
import { NextRequest, NextResponse } from 'next/server';
export async function GET(
request: NextRequest,
{ params }: { params: { id: string } }
): Promise<NextResponse> {
const user = await fetchUser(params.id);
return NextResponse.json(user);
}
```
## Related Skills
- [React](/claudekit/skills/frameworks/react) - Component patterns
- [TypeScript](/claudekit/skills/languages/typescript) - Type safety
- [Tailwind CSS](/claudekit/skills/frontend/tailwind) - Styling
- [PostgreSQL](/claudekit/skills/databases/postgresql) - Database
@@ -0,0 +1,287 @@
---
title: React
description: React component patterns, hooks, and state management
---
The React skill provides expertise in React component patterns, hooks, context, and modern React best practices.
## When Activated
- Building React components
- Using React hooks
- Component state management
- Working with `.jsx` or `.tsx` files containing React
## Core Patterns
### Functional Components
```tsx
interface UserCardProps {
user: User;
onSelect?: (user: User) => void;
}
export function UserCard({ user, onSelect }: UserCardProps) {
return (
<div className="card" onClick={() => onSelect?.(user)}>
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
);
}
```
### Hooks
```tsx
// useState
const [count, setCount] = useState(0);
// useEffect
useEffect(() => {
const subscription = subscribe();
return () => subscription.unsubscribe();
}, [dependency]);
// useMemo
const expensive = useMemo(() => compute(data), [data]);
// useCallback
const handleClick = useCallback(() => {
doSomething(id);
}, [id]);
```
### Custom Hooks
```tsx
function useUser(id: string) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
fetchUser(id)
.then(setUser)
.finally(() => setLoading(false));
}, [id]);
return { user, loading };
}
// Usage
function UserProfile({ userId }: { userId: string }) {
const { user, loading } = useUser(userId);
if (loading) return <div>Loading...</div>;
if (!user) return <div>User not found</div>;
return <div>{user.name}</div>;
}
```
### Context Pattern
```tsx
const UserContext = createContext<User | null>(null);
export function UserProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null);
return (
<UserContext.Provider value={user}>
{children}
</UserContext.Provider>
);
}
export function useUser() {
const context = useContext(UserContext);
if (!context) throw new Error('useUser must be within UserProvider');
return context;
}
```
## Best Practices
1. **Keep components small and focused**
2. **Use TypeScript for props**
3. **Memoize expensive computations**
4. **Clean up effects properly**
5. **Lift state up when needed**
## Common Pitfalls
### Missing Dependencies in Hooks
```tsx
// ❌ BAD: Missing dependency
useEffect(() => {
fetchData(userId);
}, []); // userId not in dependencies
// ✅ GOOD: All dependencies included
useEffect(() => {
fetchData(userId);
}, [userId]);
```
### State Updates on Unmounted Components
```tsx
// ❌ BAD: No cleanup
useEffect(() => {
fetchUser(id).then(setUser);
}, [id]);
// ✅ GOOD: Cleanup function
useEffect(() => {
let cancelled = false;
fetchUser(id).then(user => {
if (!cancelled) setUser(user);
});
return () => {
cancelled = true;
};
}, [id]);
```
### Prop Drilling
```tsx
// ❌ BAD: Passing props through many levels
<App>
<Layout user={user}>
<Header user={user}>
<UserMenu user={user} />
</Header>
</Layout>
</App>
// ✅ GOOD: Use context
<UserProvider value={user}>
<App>
<Layout>
<Header>
<UserMenu /> {/* Gets user from context */}
</Header>
</Layout>
</App>
</UserProvider>
```
### Not Memoizing Callbacks
```tsx
// ❌ BAD: New function every render
<Child onUpdate={(data) => handleUpdate(id, data)} />
// ✅ GOOD: Memoized callback
const handleUpdate = useCallback((data) => {
updateData(id, data);
}, [id]);
<Child onUpdate={handleUpdate} />
```
## Component Patterns
### Compound Components
```tsx
function Tabs({ children }: { children: ReactNode }) {
const [activeTab, setActiveTab] = useState(0);
return (
<TabsContext.Provider value={{ activeTab, setActiveTab }}>
{children}
</TabsContext.Provider>
);
}
Tabs.List = function TabsList({ children }: { children: ReactNode }) {
return <div className="tabs-list">{children}</div>;
};
Tabs.Tab = function Tab({ index, children }: { index: number; children: ReactNode }) {
const { activeTab, setActiveTab } = useTabsContext();
return (
<button
className={activeTab === index ? 'active' : ''}
onClick={() => setActiveTab(index)}
>
{children}
</button>
);
};
// Usage
<Tabs>
<Tabs.List>
<Tabs.Tab index={0}>Tab 1</Tabs.Tab>
<Tabs.Tab index={1}>Tab 2</Tabs.Tab>
</Tabs.List>
</Tabs>
```
### Render Props
```tsx
interface DataLoaderProps<T> {
url: string;
children: (data: T | null, loading: boolean) => ReactNode;
}
function DataLoader<T>({ url, children }: DataLoaderProps<T>) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(setData)
.finally(() => setLoading(false));
}, [url]);
return <>{children(data, loading)}</>;
}
// Usage
<DataLoader<User> url="/api/user">
{(user, loading) => (
loading ? <Spinner /> : <UserProfile user={user} />
)}
</DataLoader>
```
## Integration with Frameworks
### With Next.js
See [Next.js skill](/claudekit/skills/frameworks/nextjs) for server components and App Router patterns.
### With Testing
```tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
it('should increment count on click', async () => {
render(<Counter />);
const button = screen.getByRole('button', { name: /increment/i });
await userEvent.click(button);
expect(screen.getByText('Count: 1')).toBeInTheDocument();
});
```
## Related Skills
- [TypeScript](/claudekit/skills/languages/typescript) - Type safety
- [Next.js](/claudekit/skills/frameworks/nextjs) - Full-stack React
- [Tailwind CSS](/claudekit/skills/frontend/tailwind) - Styling
- [vitest](/claudekit/skills/testing/vitest) - Testing