nextjs-fullstack
npx skills add https://github.com/saccoai/agent-skills --skill nextjs-fullstack
Agent 安装分布
Skill 文档
This skill codifies an opinionated fullstack Next.js stack for building production web applications. It defines architecture patterns, file conventions, and best practices to ensure consistency across projects.
Use when: starting a new project, onboarding a developer to the stack, or reviewing code for pattern compliance.
The Stack
| Layer | Technology | Version | Purpose |
|---|---|---|---|
| Framework | Next.js | 16+ | App Router, RSC, Server Actions |
| Language | TypeScript | 5.x | Strict mode enabled |
| Styling | Tailwind CSS | v4 | Utility-first, CSS variables |
| Components | shadcn/ui | latest | Copy-paste primitives, Radix-based |
| Auth | Better Auth | latest | Email/password, OAuth, sessions |
| Database | Drizzle ORM | latest | Type-safe SQL, migrations |
| DB Provider | PostgreSQL | (via Neon/Supabase/local) | Production database |
| Animations | Framer Motion | latest | LazyMotion + m for tree-shaking |
| Forms | React Hook Form + Zod | latest | Validation, Server Actions |
| Nodemailer | latest | Transactional emails | |
| Hosting | Vercel | â | Auto-deploy, edge functions |
Project Structure
src/
âââ app/
â âââ (auth)/ # Auth route group
â â âââ login/page.tsx
â â âââ register/page.tsx
â â âââ layout.tsx # Auth layout (centered, minimal)
â âââ (dashboard)/ # Protected route group
â â âââ dashboard/page.tsx
â â âââ layout.tsx # Dashboard layout (sidebar)
â âââ (marketing)/ # Public route group
â â âââ page.tsx # Homepage
â â âââ about/page.tsx
â â âââ layout.tsx # Marketing layout (header + footer)
â âââ api/
â â âââ auth/[...all]/route.ts # Better Auth handler
â â âââ webhooks/ # External webhooks
â âââ layout.tsx # Root layout (providers, fonts, metadata)
â âââ globals.css # Tailwind imports, CSS variables
â âââ sitemap.ts # Dynamic sitemap
â âââ robots.ts # Robots config
âââ components/
â âââ ui/ # shadcn/ui components (don't edit)
â âââ layout/ # Header, footer, sidebar, nav
â âââ forms/ # Form components with validation
â âââ sections/ # Page section components
âââ data/ # Static content data (TypeScript)
âââ lib/
â âââ auth.ts # Better Auth client instance
â âââ auth-server.ts # Better Auth server instance
â âââ db/
â â âââ index.ts # Drizzle client
â â âââ schema.ts # Database schema
â â âââ migrations/ # SQL migrations
â âââ utils.ts # cn() and shared utilities
â âââ validations/ # Zod schemas (shared client + server)
âââ hooks/ # Custom React hooks
âââ types/ # TypeScript type definitions
âââ actions/ # Server Actions
âââ auth.ts
âââ {resource}.ts
Architecture Patterns
Server Components by Default
Every component is a Server Component unless it needs interactivity:
// src/app/page.tsx â Server Component (default)
import { db } from "@/lib/db";
export default async function HomePage() {
const posts = await db.query.posts.findMany();
return <PostList posts={posts} />;
}
Add "use client" only for:
- Event handlers (onClick, onChange, onSubmit)
- useState, useEffect, useRef
- Browser APIs (window, document)
- Third-party client libraries
Server Actions for Mutations
Use Server Actions instead of API routes for data mutations:
// src/actions/contact.ts
"use server";
import { z } from "zod";
import { contactSchema } from "@/lib/validations/contact";
export async function submitContact(formData: FormData) {
const parsed = contactSchema.safeParse({
name: formData.get("name"),
email: formData.get("email"),
message: formData.get("message"),
});
if (!parsed.success) {
return { error: parsed.error.flatten().fieldErrors };
}
// Send email, save to DB, etc.
return { success: true };
}
API Routes Only For
- Webhooks from external services
- Auth handlers (Better Auth)
- Public APIs consumed by third parties
- File uploads
Route Groups for Layout Separation
(marketing)/ â public pages with header/footer
(auth)/ â login/register with minimal centered layout
(dashboard)/ â protected pages with sidebar, requires auth
Metadata Pattern
Every page exports metadata. For "use client" pages, use a sibling layout:
// src/app/about/page.tsx (Server Component)
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "About",
description: "About our company",
};
export default function AboutPage() { ... }
// src/app/contact/layout.tsx (for client pages)
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Contact",
description: "Get in touch",
};
export default function Layout({ children }: { children: React.ReactNode }) {
return children;
}
Authentication Pattern (Better Auth)
// src/lib/auth-server.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/lib/db";
export const auth = betterAuth({
database: drizzleAdapter(db),
emailAndPassword: { enabled: true },
// ... providers
});
// src/lib/auth.ts (client)
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient();
Database Pattern (Drizzle ORM)
// src/lib/db/schema.ts
import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
export const posts = pgTable("posts", {
id: uuid("id").primaryKey().defaultRandom(),
title: text("title").notNull(),
content: text("content"),
createdAt: timestamp("created_at").defaultNow(),
});
// src/lib/db/index.ts
import { drizzle } from "drizzle-orm/neon-http";
import { neon } from "@neondatabase/serverless";
import * as schema from "./schema";
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql, { schema });
Validation Pattern (Zod â Shared Client + Server)
// src/lib/validations/contact.ts
import { z } from "zod";
export const contactSchema = z.object({
name: z.string().min(2, "Name is required"),
email: z.string().email("Invalid email"),
message: z.string().min(10, "Message too short"),
});
export type ContactInput = z.infer<typeof contactSchema>;
Used in both Server Actions (server-side validation) and React Hook Form (client-side validation).
Animation Pattern (Framer Motion â Tree-Shakeable)
// src/components/sections/animated-section.tsx
"use client";
import { LazyMotion, domAnimation, m } from "framer-motion";
export function AnimatedSection({ children }: { children: React.ReactNode }) {
return (
<LazyMotion features={domAnimation}>
<m.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 0.5 }}
>
{children}
</m.div>
</LazyMotion>
);
}
Always use LazyMotion + m (not motion) for smaller bundles.
Tailwind CSS v4 Setup
/* src/app/globals.css */
@import "tailwindcss";
@theme {
--color-primary: #8e375c;
--color-primary-dark: #6d2847;
--font-heading: "Playfair Display", serif;
--font-body: "Inter", sans-serif;
}
Naming Conventions
| Item | Convention | Example |
|---|---|---|
| Files | kebab-case | page-hero.tsx |
| Components | PascalCase | PageHero |
| Hooks | camelCase with use prefix |
useAuth |
| Server Actions | camelCase verb | submitContact |
| Zod schemas | camelCase + Schema suffix |
contactSchema |
| DB tables | snake_case (plural) | blog_posts |
| DB columns | snake_case | created_at |
| CSS variables | kebab-case with -- prefix |
--color-primary |
| Env vars | SCREAMING_SNAKE_CASE | DATABASE_URL |
Common Commands
# Development
npm run dev # Start dev server
npm run build # Production build
npm run lint # ESLint
# Database
npx drizzle-kit generate # Generate migration from schema changes
npx drizzle-kit migrate # Apply migrations
npx drizzle-kit studio # Open Drizzle Studio (DB browser)
# shadcn/ui
npx shadcn@latest add button # Add a component
# Deployment
npx vercel # Deploy preview
npx vercel --prod # Deploy production
Environment Variables Template
# Database
DATABASE_URL=postgresql://user:pass@host:5432/dbname
# Auth
BETTER_AUTH_SECRET=generate-a-random-string
BETTER_AUTH_URL=http://localhost:3000
# Email
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=user@example.com
SMTP_PASS=your-password
SMTP_FROM=noreply@example.com
# Optional
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
Agent Team Integration
This skill is used by the designer teammate in the website-refactor workflow to ensure consistent architecture. It can also be loaded by any teammate that needs to understand the project’s patterns.
Anti-Patterns (Don’t Do This)
- API routes for internal mutations â Use Server Actions instead
"use client"on pages â Keep pages as Server Components; extract client parts into child components- Importing
motiondirectly â Always useLazyMotion+mfor tree-shaking - Raw SQL â Use Drizzle ORM for type-safe queries
anytypes â TypeScript strict mode is enabled; type everything- Inline styles â Use Tailwind classes
.envin git â Only.env.exampleis committed