AgentSkillsCN

Nextjs Architecture

Next.js 架构

SKILL.md

Next.js 16 Architecture Patterns

Project Structure (App Router)

code
app/
├── (auth)/                    # Route group - public auth pages
│   ├── login/page.tsx
│   ├── register/
│   │   ├── owner/page.tsx
│   │   └── client/page.tsx
│   └── layout.tsx             # Auth layout (no navbar)
├── (owner)/                   # Route group - owner dashboard
│   ├── dashboard/page.tsx
│   ├── clientes/page.tsx
│   ├── servicios/page.tsx
│   ├── empleados/page.tsx
│   ├── agenda/page.tsx
│   ├── recompensas/page.tsx
│   ├── reportes/page.tsx
│   ├── configuracion/page.tsx
│   └── layout.tsx             # Owner layout (sidebar + navbar)
├── (client)/                  # Route group - client app
│   ├── dashboard/page.tsx
│   ├── reservas/page.tsx
│   ├── recompensas/page.tsx
│   ├── historial/page.tsx
│   ├── perfil/page.tsx
│   └── layout.tsx             # Client layout (bottom nav)
├── api/                       # API Routes
│   ├── auth/
│   │   ├── login/route.ts
│   │   ├── register-owner/route.ts
│   │   └── register-client/route.ts
│   └── establish/[estId]/     # Dynamic routes per establishment
│       ├── clients/route.ts
│       ├── services/route.ts
│       └── appointments/route.ts
├── layout.tsx                 # Root layout
├── page.tsx                   # Home page
├── loading.tsx                # Global loading
├── error.tsx                  # Global error
└── not-found.tsx              # 404 page

components/
├── auth/                      # Auth-related components
├── owner/                     # Owner dashboard components
├── client/                    # Client app components
├── common/                    # Shared components (Navbar, Sidebar)
└── ui/                        # Base UI components (Button, Card, Input)

lib/
├── firebase/
│   ├── client.ts              # Firebase client SDK init
│   ├── admin.ts               # Firebase Admin SDK init
│   └── firestore/             # Firestore CRUD functions
├── auth/
│   ├── session.ts             # Session management
│   └── middleware.ts          # Auth middleware helpers
├── validators/                # Input validation functions
└── utils/                     # Utility functions

types/                         # TypeScript interfaces
hooks/                         # Custom React hooks
context/                       # React Context providers

Server Components vs Client Components

Server Components (Default)

  • No 'use client' directive needed
  • Can be async functions
  • Can directly access databases, file system
  • Cannot use hooks, event handlers, browser APIs
tsx
// app/(owner)/clientes/page.tsx - Server Component
import { getClients } from '@/lib/firebase/firestore/clients'

export default async function ClientesPage() {
  const clients = await getClients()

  return (
    <div>
      <h1>Clientes</h1>
      <ClientList clients={clients} />
    </div>
  )
}

Client Components

  • Must have 'use client' at top
  • Can use hooks (useState, useEffect)
  • Can handle events (onClick, onChange)
  • Can access browser APIs
tsx
'use client'
// components/owner/ClientList.tsx - Client Component

import { useState } from 'react'

export function ClientList({ clients }: { clients: Client[] }) {
  const [search, setSearch] = useState('')

  const filtered = clients.filter(c =>
    c.name.toLowerCase().includes(search.toLowerCase())
  )

  return (
    <div>
      <input
        value={search}
        onChange={(e) => setSearch(e.target.value)}
        placeholder="Buscar cliente..."
      />
      {filtered.map(client => (
        <ClientCard key={client.id} client={client} />
      ))}
    </div>
  )
}

Route Groups

Route groups (groupName) organize routes without affecting URL:

code
app/(auth)/login/page.tsx     → /login
app/(owner)/dashboard/page.tsx → /dashboard
app/(client)/reservas/page.tsx → /reservas

Each group can have its own layout:

tsx
// app/(owner)/layout.tsx
export default function OwnerLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="flex">
      <Sidebar />
      <main className="flex-1">{children}</main>
    </div>
  )
}

Dynamic Routes

tsx
// app/api/establish/[estId]/clients/route.ts
export async function GET(
  request: Request,
  { params }: { params: Promise<{ estId: string }> }
) {
  const { estId } = await params
  const clients = await getClientsByEstablishment(estId)
  return Response.json(clients)
}

Layouts

tsx
// app/layout.tsx - Root Layout
import { Geist } from 'next/font/google'
import './globals.css'

const geist = Geist({ subsets: ['latin'] })

export const metadata = {
  title: 'Loyalty App',
  description: 'Sistema de puntos y reservas',
}

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="es">
      <body className={geist.className}>{children}</body>
    </html>
  )
}

Loading States

tsx
// app/(owner)/clientes/loading.tsx
export default function Loading() {
  return (
    <div className="animate-pulse">
      <div className="h-8 bg-gray-200 rounded w-1/4 mb-4" />
      <div className="space-y-3">
        {[...Array(5)].map((_, i) => (
          <div key={i} className="h-16 bg-gray-200 rounded" />
        ))}
      </div>
    </div>
  )
}

Error Handling

tsx
'use client'
// app/(owner)/clientes/error.tsx

export default function Error({
  error,
  reset,
}: {
  error: Error
  reset: () => void
}) {
  return (
    <div className="p-4 text-center">
      <h2 className="text-xl font-bold text-red-600">Algo salió mal</h2>
      <p className="text-gray-600 mt-2">{error.message}</p>
      <button
        onClick={reset}
        className="mt-4 px-4 py-2 bg-blue-500 text-white rounded"
      >
        Intentar de nuevo
      </button>
    </div>
  )
}

Metadata & SEO

tsx
// app/(owner)/clientes/page.tsx
import { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'Clientes | Loyalty',
  description: 'Gestiona tus clientes',
}

export default function ClientesPage() {
  // ...
}

Naming Conventions

TypeConventionExample
Pagespage.tsxapp/(owner)/clientes/page.tsx
Layoutslayout.tsxapp/(owner)/layout.tsx
Loadingloading.tsxapp/(owner)/clientes/loading.tsx
Errorerror.tsxapp/(owner)/clientes/error.tsx
API Routesroute.tsapp/api/clients/route.ts
ComponentsPascalCaseClientCard.tsx
HookscamelCase with useuseClients.ts
UtilscamelCaseformatDate.ts