auth-dev
Dev-mode authentication tooling — seed dev users and quick sign-in buttons for each role. Use this skill when the user says "setup dev auth", "add dev login", "setup dev users", "seed test users", or "dev sign-in".
What this skill does
# Dev Authentication Tooling Adds one-click dev sign-in buttons directly on the login screen, a development-only `/dev` console page, and an API endpoint that seeds dev users into the database. Users are auto-seeded when the login page loads. Everything is gated behind `NODE_ENV !== 'production'` so none of this code runs in production builds. ## What Gets Created 1. **`src/app/api/dev/seed/route.ts`** — Seeds dev users via better-auth internal API + Drizzle role patch 2. **`src/components/auth/dev-login-panel.tsx`** — One-click sign-in buttons shown below the login form (auto-seeds on mount) 3. **`src/app/(auth)/sign-in/page.tsx`** — Updated to include DevLoginPanel in development 4. **`src/app/dev/layout.tsx`** — Dev-only layout guard (returns 404 in production) 5. **`src/app/dev/page.tsx`** — Dev console with seed button + quick sign-in cards ## Prerequisites - `auth` skill fully applied (auth config, database schema, auth client) - Database running and schema pushed (`bunx drizzle-kit push`) - Dev server running (`bun run dev`) ## Dev Users | Role | Email | Password | |--------|--------------------|------------| | admin | <[email protected]> | Admin123! | | member | <[email protected]> | Member123! | ## Setup Steps ### 1. Create Dev Layout Guard (`src/app/dev/layout.tsx`) ```tsx import { notFound } from "next/navigation"; export default function DevLayout({ children }: { children: React.ReactNode }) { if (process.env.NODE_ENV === "production") { notFound(); } return ( <div className="min-h-screen bg-zinc-950 text-zinc-100"> <div className="mx-auto max-w-xl px-4 py-12"> <div className="mb-8 rounded-lg border border-amber-500/30 bg-amber-500/10 px-4 py-3 text-sm text-amber-400"> Development only — this page is not available in production. </div> {children} </div> </div> ); } ``` ### 2. Create Dev Console Page (`src/app/dev/page.tsx`) ```tsx "use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { signIn, signOut, useSession } from "@/lib/auth-client"; const DEV_USERS = [ { email: "[email protected]", password: "Admin123!", name: "Admin User", role: "admin" }, { email: "[email protected]", password: "Member123!", name: "Member User", role: "member" }, ] as const; export default function DevPage() { const router = useRouter(); const { data: session, isPending } = useSession(); const [seeding, setSeeding] = useState(false); const [seedResult, setSeedResult] = useState<string | null>(null); const [signingIn, setSigningIn] = useState<string | null>(null); const handleSeed = async () => { setSeeding(true); setSeedResult(null); try { const res = await fetch("/api/dev/seed", { method: "POST" }); const data = await res.json(); if (res.ok) { setSeedResult(`Seeded ${data.results.length} users: ${data.results.map((r: { email: string; status: string }) => `${r.email} (${r.status})`).join(", ")}`); } else { setSeedResult(`Error: ${data.error}`); } } catch (err) { setSeedResult(`Network error: ${err instanceof Error ? err.message : "unknown"}`); } finally { setSeeding(false); } }; const handleSignIn = async (email: string, password: string) => { setSigningIn(email); try { const result = await signIn.email({ email, password }); if (result.error) { setSeedResult(`Sign-in failed for ${email}: ${result.error.message ?? "unknown error"} — try seeding first.`); } else { router.push("/"); router.refresh(); } } finally { setSigningIn(null); } }; const handleSignOut = async () => { await signOut(); router.refresh(); }; return ( <div className="space-y-8"> <div> <h1 className="text-2xl font-bold">Dev Console</h1> <p className="mt-1 text-sm text-zinc-400">Quick authentication for development</p> </div> {/* Current session */} <div className="rounded-xl border border-zinc-800 bg-zinc-900 p-5"> <h2 className="mb-3 text-sm font-medium uppercase tracking-wider text-zinc-500">Current Session</h2> {isPending ? ( <div className="h-5 w-32 animate-pulse rounded bg-zinc-800" /> ) : session ? ( <div className="flex items-center justify-between"> <div> <p className="font-medium">{session.user.name}</p> <p className="text-sm text-zinc-400">{session.user.email}</p> </div> <button type="button" onClick={handleSignOut} className="rounded-lg border border-zinc-700 px-3 py-1.5 text-sm hover:bg-zinc-800" > Sign Out </button> </div> ) : ( <p className="text-sm text-zinc-500">Not signed in</p> )} </div> {/* Seed */} <div className="rounded-xl border border-zinc-800 bg-zinc-900 p-5"> <div className="flex items-center justify-between"> <div> <h2 className="text-sm font-medium uppercase tracking-wider text-zinc-500">Database Seed</h2> <p className="mt-1 text-sm text-zinc-400">Create dev users in the database</p> </div> <button type="button" onClick={handleSeed} disabled={seeding} className="rounded-lg bg-amber-600 px-4 py-2 text-sm font-medium text-white hover:bg-amber-500 disabled:opacity-50" > {seeding ? "Seeding..." : "Seed Users"} </button> </div> {seedResult && ( <p className="mt-3 rounded-lg bg-zinc-800 px-3 py-2 text-sm text-zinc-300">{seedResult}</p> )} </div> {/* Quick sign-in cards */} <div> <h2 className="mb-4 text-sm font-medium uppercase tracking-wider text-zinc-500">Quick Sign In</h2> <div className="grid gap-4"> {DEV_USERS.map((devUser) => ( <div key={devUser.email} className="flex items-center justify-between rounded-xl border border-zinc-800 bg-zinc-900 p-5" > <div> <p className="font-medium">{devUser.name}</p> <p className="text-sm text-zinc-400">{devUser.email}</p> <span className="mt-1 inline-block rounded-full bg-zinc-800 px-2.5 py-0.5 text-xs text-zinc-300"> {devUser.role} </span> </div> <button type="button" onClick={() => handleSignIn(devUser.email, devUser.password)} disabled={signingIn === devUser.email} className="rounded-lg bg-zinc-100 px-4 py-2 text-sm font-medium text-zinc-900 hover:bg-white disabled:opacity-50" > {signingIn === devUser.email ? "Signing in..." : "Sign In"} </button> </div> ))} </div> </div> </div> ); } ``` ### 3. Create Seed API Route (`src/app/api/dev/seed/route.ts`) > Uses better-auth's internal `signUpEmail` API so password hashing is handled automatically — no need for manual scrypt. Falls back gracefully if users already exist. ```typescript import { NextResponse } from "next/server"; const DEV_USERS = [ { email: "[email protected]", password: "Admin123!", name: "Admin User", role: "admin" }, { email: "[email protected]", password: "Member123!", name: "Member User", role: "member" }, ] as const; export async function POST() { if (process.env.NODE_ENV === "production") { return NextResponse.json({ error: "Not available in production" }, { status: 404 }); } const { auth } = await import("@/lib/auth"); const { db } = await import("@/lib/db"); const { user } = await import("@/lib/db/schema/auth"); const { eq } = await import("drizzle-orm"); const results: { email:
Related in Code Review
gstack
IncludedFast headless browser for QA testing and site dogfooding. Navigate pages, interact with elements, verify state, diff before/after, take annotated screenshots, test responsive layouts, forms, uploads, dialogs, and capture bug evidence. Use when asked to open or test a site, verify a deployment, dogfood a user flow, or file a bug with screenshots. (gstack)
startup-due-diligence
IncludedLegal due diligence review for seed-stage and Series A startups (US, Delaware C-Corp focus). Supports both investor and founder perspectives. Capabilities include: (1) Interactive document review and issue spotting; (2) Document request list generation; (3) Cap table and SAFE/convertible note analysis; (4) Red flag identification with severity ratings; (5) Diligence report generation. TRIGGERS: due diligence, DD, startup investment, cap table review, Series A, seed round, investor diligence, legal review startup, SAFE analysis, convertible note, 409A, founder vesting.
interview-master
IncludedThis skill should be used when the user asks to "generate interview questions", "prepare for interview", "optimize resume", "conduct mock interview", "analyze git commits for resume", "generate resume from code", "review my resume", or mentions interview preparation, career assistance, or extracting project experience from git history. Provides comprehensive interview and career development guidance for both job seekers and interviewers.
fix-issue
IncludedFixes GitHub issues using parallel analysis agents for root cause investigation, code exploration, and regression detection. Reads issue context from gh CLI, searches codebase and memory for related patterns, generates a fix with tests, and links the resolution back to the issue via PR. Includes prevention analysis to avoid recurrence. Use when debugging errors, resolving regressions, fixing bugs, or triaging issues.
sf-apex
IncludedGenerates and reviews Salesforce Apex code with 150-point scoring. TRIGGER when: user writes, reviews, or fixes Apex classes, triggers, test classes, batch/queueable/schedulable jobs, or touches .cls/.trigger files. DO NOT TRIGGER when: LWC JavaScript (use sf-lwc), Flow XML (use sf-flow), SOQL-only queries (use sf-soql), or non-Salesforce code.
swift-development
IncludedComprehensive Swift development for building, testing, and deploying iOS/macOS applications. Use when Claude needs to: (1) Build Swift packages or Xcode projects from command line, (2) Run tests with XCTest or Swift Testing framework, (3) Manage iOS simulators with simctl, (4) Handle code signing, provisioning profiles, and app distribution, (5) Format or lint Swift code with SwiftFormat/SwiftLint, (6) Work with Swift Package Manager (SPM), (7) Implement Swift 6 concurrency patterns (async/await, actors, Sendable), (8) Create SwiftUI views with MVVM architecture, (9) Set up Core Data or SwiftData persistence, or any other Swift/iOS/macOS development tasks.