Skip to content

Commit 3332b35

Browse files
authored
Write skills and agents with quality focus (#989)
1 parent 427ba97 commit 3332b35

File tree

10 files changed

+295
-0
lines changed

10 files changed

+295
-0
lines changed

.claude/agents/code-reviewer.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
name: code-reviewer
3+
description: Expert code reviewer for quality, performance, and maintainability. Use PROACTIVELY after writing or modifying code to ensure standards are met before committing.
4+
tools: Read, Grep, Glob, Bash
5+
model: sonnet
6+
---
7+
8+
Senior code reviewer for programming.in.th (Next.js 15, React 19, TypeScript, Prisma).
9+
10+
**Process**: `git diff --name-only``git diff` → read files → review
11+
12+
**Review for**:
13+
- **Performance**: Server Components (avoid unnecessary `'use client'`), selective Prisma fields, no N+1, pagination, caching
14+
- **Types**: No `any`, Zod validation for APIs, proper error handling
15+
- **Patterns**: Follows codebase conventions, focused functions, clear naming
16+
17+
**Key patterns**:
18+
- Prisma: Always `select`, import from `@/lib/prisma`
19+
- Auth: `getServerUser()` from `@/lib/session`, check `user.admin`
20+
- APIs: Zod schemas, consistent errors (400/401/403/404/500)
21+
- Components: Tailwind, `dark:` variants, accessibility
22+
23+
**Output**: Issues by severity (Critical/Warning/Suggestion) with `file:line` and fixes. Verdict: **APPROVED** / **CHANGES REQUESTED**
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
name: security-reviewer
3+
description: Security specialist for identifying vulnerabilities, auth issues, and data exposure risks. Use PROACTIVELY when reviewing API routes, auth logic, file handling, or user input processing.
4+
tools: Read, Grep, Glob, Bash
5+
model: sonnet
6+
---
7+
8+
Security specialist for programming.in.th (auth, code submissions, file storage).
9+
10+
**Process**: `git diff` for changes OR grep for security patterns → analyze → remediate
11+
12+
**Check for**:
13+
- **Auth**: `getServerUser()` on protected routes, `user.admin` for admin routes
14+
- **Validation**: Zod `safeParse()` for all input, no internal details in errors
15+
- **Injection**: Prisma parameterized queries, no user input in commands/paths
16+
- **Data exposure**: Selective fields only, no secrets in responses/logs
17+
- **Files**: Presigned S3 URLs, validate types/sizes, sanitize paths
18+
19+
**Search for secrets**:
20+
```bash
21+
grep -rE "(password|secret|key|token)\s*[:=]" --include="*.ts"
22+
```
23+
24+
**Required patterns**:
25+
```typescript
26+
const user = await getServerUser()
27+
if (!user) return Response.json({ error: 'Unauthorized' }, { status: 401 })
28+
29+
const result = Schema.safeParse(input)
30+
if (!result.success) return Response.json({ error: 'Invalid' }, { status: 400 })
31+
```
32+
33+
**Output**: Findings by severity (Critical/High/Medium/Low) with risk, evidence, fix. Verdict: **SECURE** / **ISSUES FOUND** / **CRITICAL**

.claude/commands/perf.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
description: Analyze a component or page for performance issues
3+
allowed-tools: Read, Glob, Grep, Bash
4+
argument-hint: "<file-path>"
5+
---
6+
7+
Analyze `$1` for:
8+
- **React**: Unnecessary `'use client'`? Missing memoization? Re-render issues?
9+
- **Data**: Selective fields? N+1 queries? Pagination? Caching (ISR/SWR)?
10+
- **Bundle**: Optimized imports? Next.js `<Image>`?
11+
12+
Report issues by severity (Critical/Warning) with specific fixes.

.claude/commands/review.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
description: Review code changes for quality, performance, and maintainability
3+
allowed-tools: Bash, Read, Glob, Grep
4+
argument-hint: "[file-path or --staged]"
5+
---
6+
7+
1. Get changes: `git diff` (or `git diff --cached` for staged, or read specific file)
8+
2. Review for:
9+
- **Performance**: Server Components, selective queries, no N+1, caching
10+
- **Types**: No `any`, proper Zod validation
11+
- **Security**: Auth checks, input validation, no secrets
12+
- **Patterns**: Follows codebase conventions
13+
3. Report issues and verdict: **APPROVED** / **CHANGES REQUESTED**

.claude/commands/verify.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
description: Run all verification checks (types, lint, tests) - the "No Regression" check
3+
allowed-tools: Bash, Read, Glob, Grep
4+
---
5+
6+
Run in sequence, stop on failure:
7+
1. `pnpm check-types`
8+
2. `pnpm lint`
9+
3. `pnpm test`
10+
11+
Report **PASS/FAIL** with error details if any.

.claude/settings.json

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"$schema": "https://json.schemastore.org/claude-code-settings.json",
3+
"permissions": {
4+
"allow": [
5+
"Bash(pnpm:*)",
6+
"Bash(npm:*)",
7+
"Bash(npx:*)",
8+
"Bash(git status:*)",
9+
"Bash(git diff:*)",
10+
"Bash(git log:*)",
11+
"Bash(git branch:*)",
12+
"Bash(git show:*)",
13+
"Read",
14+
"Glob",
15+
"Grep",
16+
"Skill"
17+
]
18+
},
19+
"hooks": {
20+
"PostToolUse": [
21+
{
22+
"matcher": "Edit|Write|MultiEdit",
23+
"hooks": [
24+
{
25+
"type": "command",
26+
"command": "bash -c 'FILE=\"$CLAUDE_TOOL_ARG_file_path\"; if [[ \"$FILE\" == *.ts || \"$FILE\" == *.tsx ]]; then echo \"[Hook] TypeScript file modified: $FILE\"; fi'"
27+
}
28+
]
29+
}
30+
],
31+
"Stop": [
32+
{
33+
"matcher": "",
34+
"hooks": [
35+
{
36+
"type": "command",
37+
"command": "bash -c 'cd \"$(git rev-parse --show-toplevel)\" && if git diff --name-only HEAD 2>/dev/null | grep -qE \"\\.(ts|tsx)$\"; then echo \"[Reminder] TypeScript files changed. Consider running: pnpm check-types && pnpm lint && pnpm test\"; fi'"
38+
}
39+
]
40+
}
41+
]
42+
}
43+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
name: api-development
3+
description: Use when creating or modifying Elysia API routes. Ensures proper validation with t schema, auth guards, error handling, and performance patterns.
4+
allowed-tools: Read, Edit, Write, Glob, Grep, Bash
5+
---
6+
7+
API routes use [Elysia](https://elysiajs.com) with TypeBox validation:
8+
9+
```typescript
10+
import { Elysia, t } from 'elysia'
11+
import { prisma } from '@/lib/prisma'
12+
13+
const app = new Elysia()
14+
.get('/tasks/:id', async ({ params, query, status }) => {
15+
const limit = query.limit ?? 10
16+
const task = await prisma.task.findUnique({
17+
where: { id: params.id },
18+
select: { id: true, title: true }
19+
})
20+
if (!task) return status(404, { error: 'Not found' })
21+
return task
22+
}, {
23+
params: t.Object({ id: t.String() }),
24+
query: t.Object({ limit: t.Optional(t.Numeric()) })
25+
})
26+
.post('/tasks', async ({ body, status }) => {
27+
const task = await prisma.task.create({ data: body })
28+
return status(201, task)
29+
}, {
30+
body: t.Object({
31+
title: t.String({ minLength: 1 }),
32+
fullScore: t.Number({ minimum: 0 })
33+
})
34+
})
35+
```
36+
37+
**Auth guard pattern**:
38+
```typescript
39+
.derive(async ({ headers, status }) => {
40+
const user = await getUser(headers.authorization)
41+
if (!user) return status(401, { error: 'Unauthorized' })
42+
return { user }
43+
})
44+
.get('/admin', ({ user, status }) => {
45+
if (!user.admin) return status(403, { error: 'Forbidden' })
46+
return 'admin only'
47+
})
48+
```
49+
50+
**Checklist**: `t.Object` validation, auth derive/guard, selective Prisma fields, pagination, `status()` for errors.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
name: component-development
3+
description: Use when creating or modifying React components. Ensures proper Server/Client component patterns, performance optimization, and accessibility.
4+
allowed-tools: Read, Edit, Write, Glob, Grep
5+
---
6+
7+
Components in `src/components/`. Default to Server Components.
8+
9+
```tsx
10+
// Server Component (default) - no directive needed
11+
export function TaskCard({ task }: { task: Task }) {
12+
return <div className="p-4 dark:bg-gray-800">{task.title}</div>
13+
}
14+
15+
// Client Component - only for interactivity
16+
'use client'
17+
import { useState } from 'react'
18+
export function Toggle() {
19+
const [on, setOn] = useState(false)
20+
return <button onClick={() => setOn(!on)}>{on ? 'On' : 'Off'}</button>
21+
}
22+
```
23+
24+
**When to use `'use client'`**: onClick/onSubmit, useState/useEffect, browser APIs.
25+
26+
**Performance**: Push `'use client'` to smallest component, use `memo()` for expensive renders, Next.js `<Image>`.
27+
28+
**Accessibility**: Labels for inputs, ARIA attributes, keyboard nav for custom elements.
29+
30+
**Styling**: Tailwind only, `dark:` variants, custom colors: `prog-primary-500`.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
name: database-changes
3+
description: Use when modifying Prisma schema or database queries. Ensures proper migrations, type safety, and query performance.
4+
allowed-tools: Read, Edit, Write, Glob, Grep, Bash
5+
---
6+
7+
Schema at `prisma/schema.prisma`. Always import from `@/lib/prisma`.
8+
9+
**Schema changes**:
10+
```bash
11+
# Edit schema, then:
12+
pnpm prisma migrate dev --name descriptive_name
13+
pnpm check-types
14+
```
15+
16+
**Query patterns**:
17+
```typescript
18+
// Always select specific fields
19+
const tasks = await prisma.task.findMany({
20+
where: { private: false },
21+
select: { id: true, title: true },
22+
take: 10, skip: 0 // Always paginate
23+
})
24+
25+
// Avoid N+1 - use include or batch queries
26+
const tasks = await prisma.task.findMany({ include: { tags: true } })
27+
// OR
28+
const submissions = await prisma.submission.findMany({
29+
where: { taskId: { in: taskIds } }
30+
})
31+
```
32+
33+
**Indexes**: Add `@@index([field])` for WHERE/ORDER BY columns.
34+
35+
**Models**: User, Task, Submission, Assessment, Category, Tag, Bookmark.

CLAUDE.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# programming.in.th
2+
3+
Next.js 15 + React 19 + TypeScript + Prisma competitive programming platform.
4+
5+
## Core Principles
6+
7+
1. **Performance**: Server Components by default, selective Prisma fields, ISR/SWR caching
8+
2. **No Regression**: Run `pnpm check-types && pnpm lint && pnpm test` before commits
9+
3. **Maintainability**: Follow existing patterns, strict TypeScript, Zod validation
10+
11+
## Key Patterns
12+
13+
```tsx
14+
// Server Component (default) - direct Prisma
15+
const tasks = await prisma.task.findMany({
16+
where: { private: false },
17+
select: { id: true, title: true } // Always select specific fields
18+
})
19+
20+
// Client Component - only when needed
21+
'use client' // forms, useState, useEffect, browser APIs
22+
23+
// API Routes - always validate with Zod
24+
const result = Schema.safeParse(input)
25+
if (!result.success) return Response.json({ error: 'Invalid' }, { status: 400 })
26+
27+
// Auth - use getServerUser() from @/lib/session
28+
// Prisma - import from @/lib/prisma (singleton)
29+
```
30+
31+
## Commands
32+
33+
```bash
34+
pnpm dev # Dev server (Turbopack)
35+
pnpm check-types # TypeScript check
36+
pnpm lint # ESLint
37+
pnpm test # Vitest
38+
```
39+
40+
## Gotchas
41+
42+
- Prisma: Always `@/lib/prisma`, always use `select`
43+
- Auth: `getServerUser()` for server-side, check `user.admin` for admin routes
44+
- Files: Presigned S3 URLs only, sanitize paths
45+
- Dark mode: `dark:` Tailwind variants

0 commit comments

Comments
 (0)