-
Notifications
You must be signed in to change notification settings - Fork 39
feat: migrate from NextAuth.js v4 to Auth.js v5 #988
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
iammarkps
wants to merge
4
commits into
main
Choose a base branch
from
claude/migrate-to-authjs-v5-KsJ1u
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
70ea752
feat: migrate from NextAuth.js v4 to Auth.js v5
claude 3332b35
Write skills and agents with quality focus (#989)
iammarkps 6541948
Merge branch 'pr-988-review' into claude/review-pr-988-sDhky
claude aae5ad1
fix: Address Auth.js v5 migration critical issues
claude File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| --- | ||
| name: code-reviewer | ||
| description: Expert code reviewer for quality, performance, and maintainability. Use PROACTIVELY after writing or modifying code to ensure standards are met before committing. | ||
| tools: Read, Grep, Glob, Bash | ||
| model: sonnet | ||
| --- | ||
|
|
||
| Senior code reviewer for programming.in.th (Next.js 15, React 19, TypeScript, Prisma). | ||
|
|
||
| **Process**: `git diff --name-only` → `git diff` → read files → review | ||
|
|
||
| **Review for**: | ||
| - **Performance**: Server Components (avoid unnecessary `'use client'`), selective Prisma fields, no N+1, pagination, caching | ||
| - **Types**: No `any`, Zod validation for APIs, proper error handling | ||
| - **Patterns**: Follows codebase conventions, focused functions, clear naming | ||
|
|
||
| **Key patterns**: | ||
| - Prisma: Always `select`, import from `@/lib/prisma` | ||
| - Auth: `getServerUser()` from `@/lib/session`, check `user.admin` | ||
| - APIs: Zod schemas, consistent errors (400/401/403/404/500) | ||
| - Components: Tailwind, `dark:` variants, accessibility | ||
|
|
||
| **Output**: Issues by severity (Critical/Warning/Suggestion) with `file:line` and fixes. Verdict: **APPROVED** / **CHANGES REQUESTED** |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| --- | ||
| name: security-reviewer | ||
| 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. | ||
| tools: Read, Grep, Glob, Bash | ||
| model: sonnet | ||
| --- | ||
|
|
||
| Security specialist for programming.in.th (auth, code submissions, file storage). | ||
|
|
||
| **Process**: `git diff` for changes OR grep for security patterns → analyze → remediate | ||
|
|
||
| **Check for**: | ||
| - **Auth**: `getServerUser()` on protected routes, `user.admin` for admin routes | ||
| - **Validation**: Zod `safeParse()` for all input, no internal details in errors | ||
| - **Injection**: Prisma parameterized queries, no user input in commands/paths | ||
| - **Data exposure**: Selective fields only, no secrets in responses/logs | ||
| - **Files**: Presigned S3 URLs, validate types/sizes, sanitize paths | ||
|
|
||
| **Search for secrets**: | ||
| ```bash | ||
| grep -rE "(password|secret|key|token)\s*[:=]" --include="*.ts" | ||
| ``` | ||
|
|
||
| **Required patterns**: | ||
| ```typescript | ||
| const user = await getServerUser() | ||
| if (!user) return Response.json({ error: 'Unauthorized' }, { status: 401 }) | ||
|
|
||
| const result = Schema.safeParse(input) | ||
| if (!result.success) return Response.json({ error: 'Invalid' }, { status: 400 }) | ||
| ``` | ||
|
|
||
| **Output**: Findings by severity (Critical/High/Medium/Low) with risk, evidence, fix. Verdict: **SECURE** / **ISSUES FOUND** / **CRITICAL** |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| --- | ||
| description: Analyze a component or page for performance issues | ||
| allowed-tools: Read, Glob, Grep, Bash | ||
| argument-hint: "<file-path>" | ||
| --- | ||
|
|
||
| Analyze `$1` for: | ||
| - **React**: Unnecessary `'use client'`? Missing memoization? Re-render issues? | ||
| - **Data**: Selective fields? N+1 queries? Pagination? Caching (ISR/SWR)? | ||
| - **Bundle**: Optimized imports? Next.js `<Image>`? | ||
|
|
||
| Report issues by severity (Critical/Warning) with specific fixes. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| --- | ||
| description: Review code changes for quality, performance, and maintainability | ||
| allowed-tools: Bash, Read, Glob, Grep | ||
| argument-hint: "[file-path or --staged]" | ||
| --- | ||
|
|
||
| 1. Get changes: `git diff` (or `git diff --cached` for staged, or read specific file) | ||
| 2. Review for: | ||
| - **Performance**: Server Components, selective queries, no N+1, caching | ||
| - **Types**: No `any`, proper Zod validation | ||
| - **Security**: Auth checks, input validation, no secrets | ||
| - **Patterns**: Follows codebase conventions | ||
| 3. Report issues and verdict: **APPROVED** / **CHANGES REQUESTED** |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| --- | ||
| description: Run all verification checks (types, lint, tests) - the "No Regression" check | ||
| allowed-tools: Bash, Read, Glob, Grep | ||
| --- | ||
|
|
||
| Run in sequence, stop on failure: | ||
| 1. `pnpm check-types` | ||
| 2. `pnpm lint` | ||
| 3. `pnpm test` | ||
|
|
||
| Report **PASS/FAIL** with error details if any. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| { | ||
| "$schema": "https://json.schemastore.org/claude-code-settings.json", | ||
| "permissions": { | ||
| "allow": [ | ||
| "Bash(pnpm:*)", | ||
| "Bash(npm:*)", | ||
| "Bash(npx:*)", | ||
| "Bash(git status:*)", | ||
| "Bash(git diff:*)", | ||
| "Bash(git log:*)", | ||
| "Bash(git branch:*)", | ||
| "Bash(git show:*)", | ||
| "Read", | ||
| "Glob", | ||
| "Grep", | ||
| "Skill" | ||
| ] | ||
| }, | ||
| "hooks": { | ||
| "PostToolUse": [ | ||
| { | ||
| "matcher": "Edit|Write|MultiEdit", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "bash -c 'FILE=\"$CLAUDE_TOOL_ARG_file_path\"; if [[ \"$FILE\" == *.ts || \"$FILE\" == *.tsx ]]; then echo \"[Hook] TypeScript file modified: $FILE\"; fi'" | ||
| } | ||
| ] | ||
| } | ||
| ], | ||
| "Stop": [ | ||
| { | ||
| "matcher": "", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "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'" | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| --- | ||
| name: api-development | ||
| description: Use when creating or modifying Elysia API routes. Ensures proper validation with t schema, auth guards, error handling, and performance patterns. | ||
| allowed-tools: Read, Edit, Write, Glob, Grep, Bash | ||
| --- | ||
|
|
||
| API routes use [Elysia](https://elysiajs.com) with TypeBox validation: | ||
|
|
||
| ```typescript | ||
| import { Elysia, t } from 'elysia' | ||
| import { prisma } from '@/lib/prisma' | ||
|
|
||
| const app = new Elysia() | ||
| .get('/tasks/:id', async ({ params, query, status }) => { | ||
| const limit = query.limit ?? 10 | ||
| const task = await prisma.task.findUnique({ | ||
| where: { id: params.id }, | ||
| select: { id: true, title: true } | ||
| }) | ||
| if (!task) return status(404, { error: 'Not found' }) | ||
| return task | ||
| }, { | ||
| params: t.Object({ id: t.String() }), | ||
| query: t.Object({ limit: t.Optional(t.Numeric()) }) | ||
| }) | ||
| .post('/tasks', async ({ body, status }) => { | ||
| const task = await prisma.task.create({ data: body }) | ||
| return status(201, task) | ||
| }, { | ||
| body: t.Object({ | ||
| title: t.String({ minLength: 1 }), | ||
| fullScore: t.Number({ minimum: 0 }) | ||
| }) | ||
| }) | ||
| ``` | ||
|
|
||
| **Auth guard pattern**: | ||
| ```typescript | ||
| .derive(async ({ headers, status }) => { | ||
| const user = await getUser(headers.authorization) | ||
| if (!user) return status(401, { error: 'Unauthorized' }) | ||
| return { user } | ||
| }) | ||
| .get('/admin', ({ user, status }) => { | ||
| if (!user.admin) return status(403, { error: 'Forbidden' }) | ||
| return 'admin only' | ||
| }) | ||
| ``` | ||
|
|
||
| **Checklist**: `t.Object` validation, auth derive/guard, selective Prisma fields, pagination, `status()` for errors. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| --- | ||
| name: component-development | ||
| description: Use when creating or modifying React components. Ensures proper Server/Client component patterns, performance optimization, and accessibility. | ||
| allowed-tools: Read, Edit, Write, Glob, Grep | ||
| --- | ||
|
|
||
| Components in `src/components/`. Default to Server Components. | ||
|
|
||
| ```tsx | ||
| // Server Component (default) - no directive needed | ||
| export function TaskCard({ task }: { task: Task }) { | ||
| return <div className="p-4 dark:bg-gray-800">{task.title}</div> | ||
| } | ||
|
|
||
| // Client Component - only for interactivity | ||
| 'use client' | ||
| import { useState } from 'react' | ||
| export function Toggle() { | ||
| const [on, setOn] = useState(false) | ||
| return <button onClick={() => setOn(!on)}>{on ? 'On' : 'Off'}</button> | ||
| } | ||
| ``` | ||
|
|
||
| **When to use `'use client'`**: onClick/onSubmit, useState/useEffect, browser APIs. | ||
|
|
||
| **Performance**: Push `'use client'` to smallest component, use `memo()` for expensive renders, Next.js `<Image>`. | ||
|
|
||
| **Accessibility**: Labels for inputs, ARIA attributes, keyboard nav for custom elements. | ||
|
|
||
| **Styling**: Tailwind only, `dark:` variants, custom colors: `prog-primary-500`. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| --- | ||
| name: database-changes | ||
| description: Use when modifying Prisma schema or database queries. Ensures proper migrations, type safety, and query performance. | ||
| allowed-tools: Read, Edit, Write, Glob, Grep, Bash | ||
| --- | ||
|
|
||
| Schema at `prisma/schema.prisma`. Always import from `@/lib/prisma`. | ||
|
|
||
| **Schema changes**: | ||
| ```bash | ||
| # Edit schema, then: | ||
| pnpm prisma migrate dev --name descriptive_name | ||
| pnpm check-types | ||
| ``` | ||
|
|
||
| **Query patterns**: | ||
| ```typescript | ||
| // Always select specific fields | ||
| const tasks = await prisma.task.findMany({ | ||
| where: { private: false }, | ||
| select: { id: true, title: true }, | ||
| take: 10, skip: 0 // Always paginate | ||
| }) | ||
|
|
||
| // Avoid N+1 - use include or batch queries | ||
| const tasks = await prisma.task.findMany({ include: { tags: true } }) | ||
| // OR | ||
| const submissions = await prisma.submission.findMany({ | ||
| where: { taskId: { in: taskIds } } | ||
| }) | ||
| ``` | ||
|
|
||
| **Indexes**: Add `@@index([field])` for WHERE/ORDER BY columns. | ||
|
|
||
| **Models**: User, Task, Submission, Assessment, Category, Tag, Bookmark. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| # programming.in.th | ||
|
|
||
| Next.js 15 + React 19 + TypeScript + Prisma competitive programming platform. | ||
|
|
||
| ## Core Principles | ||
|
|
||
| 1. **Performance**: Server Components by default, selective Prisma fields, ISR/SWR caching | ||
| 2. **No Regression**: Run `pnpm check-types && pnpm lint && pnpm test` before commits | ||
| 3. **Maintainability**: Follow existing patterns, strict TypeScript, Zod validation | ||
|
|
||
| ## Key Patterns | ||
|
|
||
| ```tsx | ||
| // Server Component (default) - direct Prisma | ||
| const tasks = await prisma.task.findMany({ | ||
| where: { private: false }, | ||
| select: { id: true, title: true } // Always select specific fields | ||
| }) | ||
|
|
||
| // Client Component - only when needed | ||
| 'use client' // forms, useState, useEffect, browser APIs | ||
|
|
||
| // API Routes - always validate with Zod | ||
| const result = Schema.safeParse(input) | ||
| if (!result.success) return Response.json({ error: 'Invalid' }, { status: 400 }) | ||
|
|
||
| // Auth - use getServerUser() from @/lib/session | ||
| // Prisma - import from @/lib/prisma (singleton) | ||
| ``` | ||
|
|
||
| ## Commands | ||
|
|
||
| ```bash | ||
| pnpm dev # Dev server (Turbopack) | ||
| pnpm check-types # TypeScript check | ||
| pnpm lint # ESLint | ||
| pnpm test # Vitest | ||
| ``` | ||
|
|
||
| ## Gotchas | ||
|
|
||
| - Prisma: Always `@/lib/prisma`, always use `select` | ||
| - Auth: `getServerUser()` for server-side, check `user.admin` for admin routes | ||
| - Files: Presigned S3 URLs only, sanitize paths | ||
| - Dark mode: `dark:` Tailwind variants |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: programming-in-th/programming.in.th
Length of output: 1097
🏁 Script executed:
Repository: programming-in-th/programming.in.th
Length of output: 2171
Replace Elysia/TypeBox examples with Next.js and Zod.
This documentation demonstrates Elysia with TypeBox validation, but the codebase uses Next.js App Router with Zod. The API routes (e.g.,
src/app/api/tasks/route.ts) parse input using Zod schemas (e.g.,TaskSchema.parse(await req.json())) and return errors via abadRequest()utility. Update the examples to match the actual tech stack, showing how to validate route inputs with Zod and return a 400 status code for invalid input.🤖 Prompt for AI Agents