VelocityKitVelocityKit

Development Workflow

Commands, patterns, and AI-assisted development.

VelocityKit is designed for rapid, AI-assisted development.

Essential Commands

pnpm dev          # Start development server
pnpm build        # Build for production
pnpm check        # Run all checks (lint, typecheck, format, test)
pnpm test         # Run unit tests
pnpm test:e2e     # Run end-to-end tests

Database Commands

pnpm supabase:start          # Start local Supabase
pnpm supabase:stop           # Stop local Supabase
pnpm supabase:reset          # Reset and run migrations
pnpm supabase:push           # Push to remote database
pnpm supabase:types          # Generate TypeScript types
pnpm supabase:migration:new  # Create new migration

Git Workflow

pnpm commit              # Stage all, AI commit message, push
pnpm commit -m "message" # Stage all, use your message, push
pnpm commit --no-ai      # Stage all, open editor, push
pnpm ship                # Release: version bump, changelog, tag, deploy

AI Commit Messages

The pnpm commit command can generate commit messages using AI:

# Add an API key to .env.local
OPENAI_API_KEY=sk-...
# or
ANTHROPIC_API_KEY=sk-ant-...
AI_PROVIDER=anthropic

Without an API key, it falls back to opening your editor.

Project Structure

src/
├── app/                 # Next.js App Router
│   ├── (auth)/         # Auth pages
│   ├── (marketing)/    # Public pages
│   ├── dashboard/      # Protected pages
│   └── api/            # API routes
├── components/
│   ├── ui/             # shadcn/ui components
│   └── [feature]/      # Feature components
├── lib/
│   ├── supabase/       # Database clients
│   ├── stripe/         # Billing utilities
│   └── [feature]/      # Feature actions
├── config/             # Site configuration
└── hooks/              # React hooks

Adding Features

Follow this pattern when adding new features:

1. Database Migration

Create a new migration:

pnpm supabase:migration:new add_items_table

Add your table with RLS:

CREATE TABLE items (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  account_id UUID REFERENCES accounts(id) NOT NULL,
  created_by UUID REFERENCES auth.users(id) NOT NULL,
  title TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT now()
);

ALTER TABLE items ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Users can manage their account items"
ON items FOR ALL
USING (account_id IN (
  SELECT account_id FROM account_users WHERE user_id = auth.uid()
));

2. Server Actions

Create src/lib/items/actions.ts:

"use server";

import { createClient } from "@/lib/supabase/server";
import { getCurrentAccountId } from "@/lib/account/actions";
import { z } from "zod";

const schema = z.object({
  title: z.string().min(1).max(200),
});

export async function createItem(
  _prevState: { error?: string } | null,
  formData: FormData
) {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();

  if (!user) return { error: "Not authenticated" };

  const accountId = await getCurrentAccountId();
  if (!accountId) return { error: "No account found" };

  const parsed = schema.safeParse({
    title: formData.get("title"),
  });

  if (!parsed.success) {
    return { error: parsed.error.issues[0].message };
  }

  const { error } = await supabase.from("items").insert({
    account_id: accountId,
    created_by: user.id,
    ...parsed.data,
  });

  if (error) return { error: "Failed to create item" };

  return { success: true };
}

3. Components

Create form with useActionState:

"use client";

import { useActionState } from "react";
import { createItem } from "@/lib/items/actions";

export function CreateItemForm() {
  const [state, formAction, isPending] = useActionState(createItem, null);

  return (
    <form action={formAction}>
      {state?.error && <p className="text-destructive">{state.error}</p>}
      <input name="title" required />
      <button disabled={isPending}>
        {isPending ? "Creating..." : "Create"}
      </button>
    </form>
  );
}

4. Page

Create src/app/dashboard/items/page.tsx and add to sidebar navigation.

AI-Assisted Development

VelocityKit is optimized for AI tools like Claude Code:

  • CLAUDE.md — Project context for AI assistants
  • docs/prompts/ — Templates for common tasks
  • Consistent patterns — Makes AI suggestions reliable

Tips for AI-assisted development:

  1. Reference existing patterns (e.g., "like the todos feature")
  2. Be specific about requirements
  3. Ask for one thing at a time
  4. Review generated code before committing