Core Configuration

Essential configuration files and their purposes

Core Configuration

This document outlines the core configuration files and their purposes in the ShipKit project.

Package Management

ShipKit uses PNPM as its package manager. The main configuration file is package.json.

Key Dependencies

{
  "dependencies": {
    "next": "^14.0.4",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "typescript": "^5.3.3",
    "@auth/core": "^0.18.6",
    "next-auth": "5.0.0-beta.4",
    "drizzle-orm": "^0.29.3",
    "postgres": "^3.4.3",
    "resend": "^2.1.0",
    "@builder.io/sdk-react": "^0.12.2",
    "@payloadcms/db-postgres": "^0.1.8",
    "@payloadcms/richtext-slate": "^1.3.1",
    "payload": "^2.5.0",
    "@lemonsqueezy/lemonsqueezy.js": "^1.2.5"
  },
  "devDependencies": {
    "@types/node": "^20.10.6",
    "@types/react": "^18.2.46",
    "@types/react-dom": "^18.2.18",
    "autoprefixer": "^10.4.16",
    "postcss": "^8.4.32",
    "tailwindcss": "^3.4.0",
    "drizzle-kit": "^0.20.9",
    "@biomejs/biome": "1.4.1",
    "vitest": "^1.1.1",
    "@playwright/test": "^1.40.1"
  }
}

Scripts

{
  "scripts": {
    // Development
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "biome check .",
    "format": "biome format . --write",

    // Database
    "db:generate": "drizzle-kit generate:pg",
    "db:migrate": "drizzle-kit push:pg",
    "db:studio": "drizzle-kit studio",
    "db:seed": "tsx scripts/seed.ts",

    // Testing
    "test": "vitest",
    "test:ui": "vitest --ui",
    "test:e2e": "playwright test",
    "test:coverage": "vitest run --coverage",

    // Types
    "typecheck": "tsc --noEmit",

    // Payload CMS
    "payload": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload",

    // Documentation
    "docs:dev": "mintlify dev",
    "docs:build": "mintlify build"
  }
}

Next.js Configuration

The next.config.ts file contains the core Next.js configuration:

import { env } from "@/env";
import { FILE_UPLOAD_MAX_SIZE } from "@/config/file";
import BuilderDevTools from "@builder.io/dev-tools/next";
import createMDX from "@next/mdx";
import { withPayload } from "@payloadcms/next/withPayload";

const config = {
  /*
   * React configuration
   */
  reactStrictMode: true,

  /*
   * Image configuration
   */
  images: {
    remotePatterns: [
      { hostname: "avatars.githubusercontent.com" },
      { hostname: "github.com" },
      { hostname: "*.supabase.co" },
      { hostname: "*.builder.io" },
    ],
  },

  /*
   * Experimental features
   */
  experimental: {
    serverActions: {
      bodySizeLimit: FILE_UPLOAD_MAX_SIZE,
    },
    nextScriptWorkers: true,
  },

  /*
   * Logging configuration
   */
  logging: {
    fetches: {
      fullUrl: true,
    },
  },

  /*
   * Development indicators
   */
  devIndicators: {
    buildActivityPosition: "bottom-right",
  },
};

/*
 * Apply configurations in order
 */

// Builder.io config
let nextConfig = !env.NEXT_PUBLIC_BUILDER_API_KEY || env.DISABLE_BUILDER === "true"
  ? config
  : BuilderDevTools()(config);

// Payload CMS config
nextConfig = env.DISABLE_PAYLOAD === "true"
  ? nextConfig
  : withPayload(nextConfig);

// MDX config
const withMDX = createMDX({
  extension: /\.mdx?$/,
  options: {
    remarkPlugins: [
      ["remark-frontmatter", { type: "yaml", marker: "-" }],
      ["remark-mdx-frontmatter", {}],
    ],
    rehypePlugins: [],
  },
});
nextConfig = withMDX(nextConfig);

export default nextConfig;

TypeScript Configuration

Multiple TypeScript configurations for different purposes:

Base Configuration (tsconfig.json)

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

Environment Variables

Environment variables are strictly typed and validated using Zod:

// @/env.schema.ts
import { z } from "zod";

export const envSchema = z.object({
  // Node
  NODE_ENV: z.enum(["development", "test", "production"]),

  // Database
  DATABASE_URL: z.string().url(),

  // Auth
  AUTH_URL: z.string().url(),
  AUTH_SECRET: z.string().min(32),
  AUTH_GITHUB_ID: z.string().optional(),
  AUTH_GITHUB_SECRET: z.string().optional(),
  AUTH_DISCORD_ID: z.string().optional(),
  AUTH_DISCORD_SECRET: z.string().optional(),
  AUTH_GOOGLE_ID: z.string().optional(),
  AUTH_GOOGLE_SECRET: z.string().optional(),

  // Email
  RESEND_API_KEY: z.string().optional(),

  // CMS
  PAYLOAD_SECRET: z.string().min(32),
  NEXT_PUBLIC_BUILDER_API_KEY: z.string().optional(),

  // Payments
  LEMONSQUEEZY_API_KEY: z.string().optional(),
  LEMONSQUEEZY_STORE_ID: z.string().optional(),
  LEMONSQUEEZY_WEBHOOK_SECRET: z.string().optional(),

  // Feature Flags
  DISABLE_PAYLOAD: z.enum(["true", "false"]).optional(),
  DISABLE_BUILDER: z.enum(["true", "false"]).optional(),
});

Code Quality Tools

Biome Configuration (biome.json)

{
  "$schema": "https://biomejs.dev/schemas/1.4.1/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  },
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 80
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "double",
      "trailingComma": "es5"
    }
  }
}

Testing Configuration (vitest.config.ts)

import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
import { defineConfig } from "vitest/config";

export default defineConfig({
  plugins: [react(), tsconfigPaths()],
  test: {
    environment: "jsdom",
    globals: true,
    setupFiles: ["./src/test/setup.ts"],
    coverage: {
      provider: "v8",
      reporter: ["text", "json", "html"],
      exclude: [
        "node_modules/**",
        "src/test/**",
        "**/*.d.ts",
        "**/*.config.ts",
      ],
    },
  },
});

Security Configuration

Content Security Policy

// @/config/security.ts
export const cspConfig = {
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'", "'unsafe-eval'", "'unsafe-inline'"],
    styleSrc: ["'self'", "'unsafe-inline'"],
    imgSrc: ["'self'", "data:", "https:"],
    connectSrc: ["'self'", "https:"],
    fontSrc: ["'self'"],
    objectSrc: ["'none'"],
    mediaSrc: ["'self'"],
    frameSrc: ["'self'"],
  },
};

Rate Limiting

// @/config/rate-limit.ts
export const rateLimitConfig = {
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // Limit each IP to 100 requests per windowMs
};

Notes

  • All configuration is TypeScript-based for type safety
  • Environment variables are strictly validated at runtime
  • Security measures are implemented at multiple levels
  • Feature flags control optional integrations
  • Build and development optimizations are configurable
  • Testing setup supports unit, integration, and E2E tests