Application Architecture

Overview of the application structure and organization

Application Architecture

This document outlines the core architecture of the ShipKit application, built with Next.js 13+ App Router, TypeScript, and modern React patterns.

Core Technologies

  • Framework: Next.js 13+ with App Router
  • Language: TypeScript 5.x
  • Styling: Tailwind CSS with Shadcn/UI
  • Database: PostgreSQL with Drizzle ORM
  • CMS: Payload CMS and Builder.io
  • Authentication: NextAuth/AuthJS v5
  • Email: Resend
  • Package Manager: PNPM

App Router Structure

The application uses Next.js 13+ App Router, organized in the /src/app directory:

src/app/
├── (app)/           # App-specific routes (grouped)
│   ├── dashboard/   # User dashboard
│   ├── settings/    # User settings
│   └── profile/     # User profile
├── (auth)/          # Authentication routes (grouped)
│   ├── login/       # Login page
│   ├── register/    # Registration page
│   └── verify/      # Email verification
├── (marketing)/     # Marketing pages (grouped)
│   ├── pricing/     # Pricing page
│   ├── features/    # Features page
│   └── blog/        # Blog section
├── api/            # API routes
│   ├── auth/       # Auth endpoints
│   ├── trpc/       # tRPC router
│   └── webhooks/   # Webhook handlers
├── _components/    # App-wide components
└── docs/          # Documentation routes

Special Files

  • layout.tsx - Root layout with providers
  • not-found.tsx - Custom 404 page
  • error.tsx - Error boundary component
  • loading.tsx - Loading states
  • robots.ts - Search engine configuration
  • sitemap.ts - Dynamic sitemap
  • manifest.ts - PWA configuration

Component Organization

Components are organized by feature and responsibility:

src/components/
├── auth/         # Authentication components
│   ├── login-form.tsx
│   └── oauth-buttons.tsx
├── dashboard/    # Dashboard components
│   ├── activity-feed.tsx
│   └── stats-cards.tsx
├── marketing/    # Marketing components
│   ├── pricing-table.tsx
│   └── feature-grid.tsx
├── shared/       # Shared components
│   ├── logo.tsx
│   └── icons/
└── ui/          # Shadcn/UI components
    ├── button.tsx
    └── input.tsx

Server Architecture

Server-side code follows a clear separation of concerns:

src/server/
├── actions/     # Server actions
│   ├── auth.ts
│   └── user.ts
├── services/    # Business logic
│   ├── email.ts
│   └── payment.ts
└── db/         # Database layer
    ├── schema/
    └── migrations/

Server Actions

All mutations are handled through server actions:

// @/server/actions/user.ts
export async function updateProfile(data: ProfileData) {
  'use server'
  // Validation
  // Database update
  // Event logging
}

Services

Business logic is encapsulated in service modules:

// @/server/services/email.ts
export class EmailService {
  async sendWelcome(user: User) {
    // Email template
    // Send via Resend
    // Log delivery
  }
}

Database Layer

Using Drizzle ORM with PostgreSQL:

// @/server/db/schema/user.ts
export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  email: text('email').notNull().unique(),
  name: text('name'),
  createdAt: timestamp('created_at').defaultNow(),
});

Migrations

// @/server/db/migrations/0000_initial.ts
export async function up(db: Database) {
  // Create tables
  // Add indices
  // Set up foreign keys
}

Authentication

Using NextAuth/AuthJS v5 with multiple providers:

// @/server/auth.ts
export const { auth, signIn, signOut } = NextAuth({
  providers: [
    GitHub,
    Google,
    Discord,
    Email,
  ],
  callbacks: {
    // Custom callbacks
  },
});

Content Management

Dual CMS approach:

  1. Payload CMS: For structured content and admin
  2. Builder.io: For visual page building
// @/collections/posts.ts
export const Posts = buildCollection({
  slug: 'posts',
  auth: true,
  admin: {
    useAsTitle: 'title',
  },
  fields: [
    // Field definitions
  ],
});

Type System

Comprehensive type safety throughout:

// @/types/index.ts
export interface User {
  id: string;
  email: string;
  name?: string;
  role: 'user' | 'admin';
}

// Zod schemas for validation
export const userSchema = z.object({
  email: z.string().email(),
  name: z.string().optional(),
});

Performance Optimizations

  1. Route Segments:

    • Parallel routes for loading states
    • Intercepting routes for modals
    • Dynamic imports for code splitting
  2. Caching:

    // @/server/actions/data.ts
    export async function getData() {
      return unstable_cache(
        async () => {
          // Fetch data
        },
        ['data-key'],
        { revalidate: 60 }
      )();
    }
    
  3. Static Generation:

    // @/app/blog/[slug]/page.tsx
    export async function generateStaticParams() {
      return getAllPostSlugs();
    }
    

Security Measures

  1. Input Validation:

    // @/lib/validate.ts
    export function validateInput<T>(
      schema: z.Schema<T>,
      data: unknown
    ): T {
      return schema.parse(data);
    }
    
  2. CSRF Protection:

    • Built-in Next.js CSRF protection
    • Custom token validation
  3. Rate Limiting:

    // @/server/middleware.ts
    export const rateLimit = new RateLimit({
      windowMs: 15 * 60 * 1000,
      max: 100
    });
    

Development Guidelines

  1. Component Rules:

    • Use Server Components by default
    • Client Components for interactivity
    • Keep state close to where it's used
  2. Code Style:

    • Strict TypeScript
    • ESLint + Prettier
    • Conventional Commits
  3. Testing Strategy:

    • Vitest for unit tests
    • Playwright for E2E
    • MSW for API mocking

Notes

  • All routes use React Server Components by default
  • State management through React Context and Server Components
  • API routes minimized in favor of Server Actions
  • Strong focus on type safety and validation
  • Performance optimizations built into architecture
  • Security measures implemented at all levels