Quick Start Guide
This guide will help you set up a new ShipKit project and understand its core features. Follow these steps to create a production-ready application foundation.
Prerequisites
Ensure you have the following installed:
Creating Your Project
Create a new ShipKit project:
pnpm create shipkit-app@latest my-app
cd my-app
Install dependencies:
Configure your environment:
Update your .env
file with required credentials:
# Core Auth
AUTH_URL="http://localhost:3000" # Base URL for authentication
AUTH_SECRET="generate_a_secure_secret_here" # openssl rand -base64 32
# OAuth Providers (Optional)
# GitHub: https://github.com/settings/developers
AUTH_GITHUB_ID="" # GitHub OAuth App Client ID
AUTH_GITHUB_SECRET="" # GitHub OAuth App Client Secret
# Database
DATABASE_URL="postgresql://postgres:password@localhost:5432/shipkit"
DB_PREFIX="sk" # Prefix for database tables
# Email (Resend: https://resend.com)
RESEND_API_KEY="re_123456789" # Get from Resend dashboard
# CMS (Payload)
PAYLOAD_SECRET="generate_another_secret_here" # openssl rand -base64 32
# Node Environment
NODE_ENV="development" # development, test, or production
Initialize your database:
# Start PostgreSQL (if using Docker)
pnpm db:start
# Generate database schema
pnpm db:generate
# Push schema to database
pnpm db:push
# Optional: Seed with sample data
pnpm db:seed
Start the development server:
# Start with experimental features (recommended)
pnpm dev
# Start without experimental features
pnpm dev.legacy
# Start with HTTPS (for testing secure features)
pnpm dev.https
Your application will be running at http://localhost:3000
Project Structure
ShipKit follows a domain-driven structure:
my-app/
├── src/
│ ├── app/ # Next.js App Router pages and layouts
│ │ ├── (auth)/ # Authentication routes
│ │ ├── (marketing)/ # Public marketing pages
│ │ ├── api/ # API routes
│ │ └── dashboard/ # Protected dashboard routes
│ ├── components/ # React components
│ │ ├── ui/ # Shadcn/UI components
│ │ ├── forms/ # Form components
│ │ └── shared/ # Shared components
│ ├── server/ # Server-side code
│ │ ├── actions/ # Server actions
│ │ ├── services/ # Business logic services
│ │ ├── db/ # Database schema and queries
│ │ ├── utils/ # Server utilities
│ │ └── middleware/ # Custom middleware
│ ├── lib/ # Utility functions
│ │ ├── utils/ # Helper functions
│ │ ├── hooks/ # React hooks
│ │ └── config/ # Configuration files
│ ├── types/ # TypeScript types
│ └── workers/ # Web workers
├── public/ # Static assets
├── tests/ # Test files
│ ├── e2e/ # Playwright tests
│ └── unit/ # Vitest tests
├── scripts/ # Maintenance scripts
└── .env.example # Environment variables template
Core Features
Authentication
ShipKit uses NextAuth v5 with JWT sessions and activity logging:
// src/server/auth.config.ts
import type { NextAuthConfig } from "next-auth";
import { ActivityLogger } from "./utils/activity-logger";
export const authOptions: NextAuthConfig = {
providers,
callbacks: {
async signIn({ user, account }) {
await ActivityLogger.auth.logLogin(null, {
details: `User signed in via ${account?.provider}`,
metadata: {
provider: account?.provider,
email: user.email,
},
});
return true;
},
session({ session, token }) {
if (token) {
session.user.id = token.id as string;
session.user.name = token.name as string | null;
session.user.bio = token.bio as string | null;
session.user.githubUsername = token.githubUsername as string | null;
session.user.theme = token.theme as "light" | "dark" | "system";
session.user.emailNotifications = token.emailNotifications as boolean;
}
return session;
}
}
};
Database Operations
Type-safe queries with Drizzle ORM:
// src/server/db/schema.ts
import { relations, sql } from "drizzle-orm";
import { pgTableCreator, varchar, timestamp, text, boolean } from "drizzle-orm/pg-core";
const createTable = pgTableCreator((name) => `${env.DB_PREFIX}_${name}`);
export const users = createTable("user", {
id: varchar("id", { length: 255 })
.notNull()
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
name: varchar("name", { length: 255 }),
email: varchar("email", { length: 255 }).notNull(),
emailVerified: timestamp("email_verified", {
mode: "date",
withTimezone: true,
}).default(sql`CURRENT_TIMESTAMP`),
githubUsername: varchar("github_username", { length: 255 }),
role: varchar("role", { length: 50 }).default("user").notNull(),
bio: text("bio"),
theme: varchar("theme", { length: 20 }).default("system"),
emailNotifications: boolean("email_notifications").default(true),
createdAt: timestamp("created_at", { withTimezone: true })
.default(sql`CURRENT_TIMESTAMP`)
.notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true }).$onUpdate(
() => new Date(),
),
});
// Type-safe relations
export const usersRelations = relations(users, ({ many }) => ({
accounts: many(accounts),
}));
Server Actions
Type-safe form handling with Zod validation:
// src/server/actions/projects.ts
'use server'
import { z } from "zod";
import { db } from "@/server/db";
import { projects } from "@/server/db/schema";
const createProjectSchema = z.object({
name: z.string().min(1, "Project name is required"),
teamId: z.string().min(1, "Team ID is required"),
});
export async function createProject(input: z.infer<typeof createProjectSchema>) {
const validated = createProjectSchema.parse(input);
return await db.insert(projects).values({
name: validated.name,
teamId: validated.teamId,
}).returning();
}
UI Components
Build accessible interfaces with Shadcn/UI and React Server Components:
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { useFormStatus } from "react-dom";
export function LoginForm() {
const { pending } = useFormStatus();
return (
<form className="space-y-4">
<Input
type="email"
name="email"
placeholder="Email"
disabled={pending}
required
/>
<Button
type="submit"
disabled={pending}
className="w-full"
>
{pending ? 'Logging in...' : 'Login'}
</Button>
</form>
);
}
Development Workflow
Running Tests
# Unit tests
pnpm test
# E2E tests
pnpm test:e2e
# Test coverage
pnpm test:coverage
Database Management
# Generate migrations
pnpm db:generate
# Apply migrations
pnpm db:push
# Reset database
pnpm db:reset
# Start database
pnpm db:start
# Seed data
pnpm db:seed
Code Quality
# Type checking
pnpm typecheck
# Linting
pnpm lint
# Format code
pnpm format
# Check code style
pnpm check
Next Steps
Development Guide - Learn development workflows
Core Concepts - Understand the architecture
API Reference - Explore the API
UI Components - Browse available components