πŸš€ Vibe Coding Kit

Building a Linear-like Issue Tracker That Feels Fast

Production-Ready Blueprint

1. Why Linear is Vibeable

Linear isn't magicβ€”it's deliberate design. You can build this.

Core Functionality is Straightforward

Issue CRUD, status updates, priority sorting, filtering. This isn't complex. The underlying data model is simpleβ€”what matters is the interface.

The Magic is in UI/UX Polish

Fast keyboard navigation, optimistic updates, smooth transitions, instant search. Users feel control. Responsiveness creates the vibe.

Modern React Makes Fast UIs Easy

React Server Components, Next.js 14, client-side prefetching, and optimistic state management eliminate the work. Build once, ship fast.

2. Tech Stack for Speed

Every choice is deliberate. Here's why each layer matters:

Frontend

Next.js 14 with React Server Components. App Router for minimal JS bundles. Streaming for instant perceived speed.

Database

PostgreSQL + Prisma. Type-safe ORM. Prisma Client for real-time subscriptions. Fast queries on indexed status/priority.

State

React Query (TanStack). Automatic cache invalidation, optimistic mutations, background refetch. Handles offline gracefully.

Keyboard

cmdk library. CMD+K palette for power users. j/k for navigation. Reminders in UI. Zero friction.

Real-Time

Supabase Realtime or Liveblocks. Multiplayer updates without custom WebSocket code. Presence awareness.

UI

Tailwind CSS + shadcn/ui. Prebuilt components. Consistent design system. Accessible by default.

3. Copy-Paste Prompt for AI Code Generation

Use this prompt with Claude (or your favorite LLM) to generate the core app. It's battle-tested.

You are building a Linear-like issue tracker (Vibe: fast, keyboard-first, beautiful). TECH STACK: - Next.js 14 (App Router, RSC) - React 18 + TypeScript - PostgreSQL + Prisma ORM - React Query (TanStack Query) for state - Tailwind CSS + shadcn/ui - cmdk for command palette - Supabase Realtime (optional, for multiplayer) CORE FEATURES (Priority order): 1. ISSUE CRUD (Week 1) - Create: CMD+N or button β†’ modal with title, description, assignee, priority, status, labels - Read: List view with infinite scroll, search, filters (status/priority/assignee/label) - Update: Click to edit any field (optimistic update on frontend immediately) - Delete: Soft delete with undo for 30s - Fields: id, title, description, status (todo/in-progress/done), priority (low/medium/high/urgent), assignee, labels, created_at, updated_at 2. KEYBOARD NAVIGATION (Week 1) - CMD+K: Open command palette with recent issues, quick actions - CMD+N: New issue - CMD+F: Search/filter - j/k: Next/previous issue (from list or selected issue detail) - Enter: Open issue detail - Esc: Close detail/modal - Keyboard hints shown in UI (grayed out, unobtrusive) 3. KANBAN BOARD (Week 2) - Columns: To Do, In Progress, Done (or custom statuses) - Drag-drop between columns (optimistic update) - Each card shows: title, priority indicator (color), assignee avatar, due date - Click card β†’ detail panel slides in from right - Filter/search applies to board too 4. ISSUE DETAIL PANEL - Slide-in from right on click - Inline editing: click any field to edit - History: show recent edits (who changed what, when) - Comments: basic comment section (optional for MVP) - Related issues: link to other issues - Activity timeline on the side 5. CYCLES / SPRINTS (Week 3) - Create cycles: name, start date, end date, goal - Assign issues to cycles - View all issues in a cycle - Cycle completion %, burndown-style (not required to be detailed) 6. FILTERS & VIEWS (Week 3) - Predefined: My issues, Assigned to me, Recent, Due soon - Custom filters: save a filter with name (e.g., "Backend TODOs") - Filter UI: easy multi-select for status, priority, assignee, label, cycle - Views: List, Kanban (switchable) 7. GITHUB INTEGRATION (Week 4) - Link issue to GitHub PR/issue: paste URL β†’ fetch and show metadata - Display PR status badge on issue - Sync PR status (open, merged, draft) in background 8. LABELS & PROJECTS (Week 3) - Create/edit labels: name, color - Bulk label issues - Filter by label - Group by label option (optional) PERFORMANCE & FEEL: - Optimistic updates: UI updates immediately, API call in background - Skeleton loading: Show placeholder while fetching - Pagination: Load 20 issues at a time, infinite scroll - Search: Client-side filtering for visible issues, server search for large datasets - No spinners: Use skeleton loaders and subtle transitions instead - Keyboard should feel snappy (no delays) DATABASE SCHEMA (Prisma): model Issue { id String @id @default(cuid()) title String description String? status String @default("todo") // todo, in-progress, done priority String @default("medium") // low, medium, high, urgent assignee User? @relation(fields: [assigneeId], references: [id]) assigneeId String? labels Label[] @relation("IssueLabels") cycle Cycle? @relation(fields: [cycleId], references: [id]) cycleId String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Label { id String @id @default(cuid()) name String @unique color String @default("#3b82f6") issues Issue[] @relation("IssueLabels") } model Cycle { id String @id @default(cuid()) name String startDate DateTime endDate DateTime issues Issue[] createdAt DateTime @default(now()) } model User { id String @id @default(cuid()) email String @unique name String? avatar String? issues Issue[] } API ENDPOINTS (REST or tRPC, your choice): - GET /api/issues (with filters: ?status=todo&priority=high&assignee=userid) - POST /api/issues (create) - PATCH /api/issues/:id (update) - DELETE /api/issues/:id (soft delete) - GET /api/issues/:id (detail) - POST /api/issues/:id/comments (add comment) - GET /api/cycles (list) - POST /api/cycles (create) - GET /api/labels (list) - POST /api/labels (create) DESIGN NOTES: - Use a subtle gray/blue color scheme (like Linear: dark text on light background, blue accents) - Card-based layout for issues - Plenty of whitespace - Hover states on interactive elements - Dark mode optional (not MVP) WHAT TO BUILD FIRST: 1. Authentication (NextAuth.js or Clerk) 2. Issue list with CRUD 3. Basic filters (status, priority) 4. Keyboard shortcuts (CMD+K, CMD+N, j/k) 5. Kanban board 6. Cycles 7. Detail panel with inline editing 8. Polish: animations, keyboard hints, undo Build this step-by-step. Start with a basic list, then add features. Focus on keyboard-first UX and instant feedback. OPTIONAL ENHANCEMENTS: - Real-time collaboration (Supabase Realtime) - Notifications (email on assignment) - Slack integration - Duplicate detection (similar issue titles) - AI-generated summaries - Bulk operations - Dark mode For each feature, prioritize: Does it make the app feel faster or more joyful? If yes, build it.

4. The Secret Sauce: Making It Fast

These four patterns separate Linear vibes from "feels slow" apps:

🎯 The Four Pillars of Speed

  1. Optimistic Updates. User clicks "Mark Done" β†’ button changes color immediately. API call happens in background. If it fails, revert. Users never wait.
  2. Virtualized Lists. Only render visible issues (50 issues on screen = render 50, not 5000). Use react-window or TanStack Virtual. Silky smooth scrolling.
  3. Prefetching. Hover over an issue β†’ prefetch its detail. User clicks β†’ instant load. Next.js Image component for avatars.
  4. Skeleton Loading. Instead of spinners, show gray placeholder cards. Perceived load time drops 40%. Feels native.

Code Pattern: Optimistic Update in React Query

const updateIssueMutation = useMutation({ mutationFn: (data) => api.patch(`/issues/${data.id}`, data), onMutate: async (newData) => { // Cancel any outgoing refetches await queryClient.cancelQueries({ queryKey: ['issues'] }); // Snapshot old data const previousIssues = queryClient.getQueryData(['issues']); // Update cache immediately (optimistic) queryClient.setQueryData(['issues'], (old) => old.map((issue) => issue.id === newData.id ? { ...issue, ...newData } : issue ) ); return { previousIssues }; }, onError: (err, newData, context) => { // Rollback on error queryClient.setQueryData(['issues'], context.previousIssues); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['issues'] }); }, });

Keyboard Shortcuts Pattern (cmdk)

import { Command } from "cmdk"; <Command> <CommandInput placeholder="Search issues or commands..." /> <CommandList> <CommandGroup heading="Issues"> {issues.map((issue) => ( <CommandItem key={issue.id} onSelect={() => router.push(`/issues/${issue.id}`)} > {issue.title} </CommandItem> ))} </CommandGroup> <CommandGroup heading="Actions"> <CommandItem onSelect={() => openNewIssueModal()}> New Issue (CMD+N) </CommandItem> </CommandGroup> </CommandList> </Command>

5. Week-by-Week Development Plan

A realistic 4-week roadmap to a shipping product.

Week 1: Core Issues + Keyboard Nav
  • Setup: Next.js, Prisma, PostgreSQL, Tailwind, shadcn/ui
  • Database schema: Issue, Label, Cycle, User
  • Basic CRUD: Create, read, update, delete (soft)
  • List view: Infinite scroll, basic filters (status, priority)
  • Keyboard: CMD+K palette, CMD+N new, j/k nav, Esc to close
  • Auth: Basic NextAuth or Clerk setup
  • Goal: Ship an issue tracker that responds to keyboard instantly
Week 2: Board View + Drag-Drop
  • Kanban board: Three columns (To Do, In Progress, Done)
  • Drag-drop library: react-beautiful-dnd or dnd-kit
  • Optimistic updates: Move card β†’ UI updates β†’ API catches up
  • Card design: Title, priority badge, assignee, due date
  • Detail panel: Slide in on card click, inline edit fields
  • Filters apply to board too
  • Goal: Board feels snappy, no lag on drag
Week 3: Cycles, Filters, Views
  • Cycles: Create, edit, assign issues to cycles
  • Cycle view: List all issues in a cycle + progress %
  • Advanced filters: Custom filter builder, save filters
  • Predefined views: My Issues, Assigned to Me, Recent, Due Soon
  • Labels: CRUD + color picker, bulk label issues
  • Search: Full-text search on title/description
  • Goal: Power users have full control, filtering feels natural
Week 4: GitHub Integration + Polish
  • GitHub OAuth: Link issues to PRs/issues
  • PR metadata: Display status badge, sync in background
  • Polish: Animations, loading states, error handling
  • Keyboard hints: Show CMD+K shortcuts in UI
  • Performance: Virtualized lists, prefetch detail on hover
  • Testing: E2E tests for critical paths
  • Deploy: Vercel or self-hosted
  • Goal: Ship a product that feels polished and fast

6. Open Source References to Learn From

These projects are production-grade. Study their patterns.

  • makeplane/plane
    The best Linear alternative (open source). Study their:
    • Issue filtering architecture (nested properties)
    • Keyboard shortcuts (they're comprehensive)
    • Real-time sync pattern (Pusher/WebSocket)
    • UI component design (Tailwind + custom)
  • calcom/cal.com
    Study for keyboard-first UX patterns:
    • Event creation with keyboard-only flow
    • Modal/dialog management
    • Form handling (react-hook-form patterns)
    • Responsive design
  • vercel/next.js examples
    Clone and study:
    • Database examples (Prisma, edge functions)
    • Incremental Static Regeneration (ISR)
    • API route patterns
  • shadcn/ui
    Don't just use itβ€”read the source:
    • Component composition patterns
    • Accessibility (a11y) best practices
    • Tailwind theming approach

7. Quick Start: From Zero to Issue Tracker in 30 Minutes

Step 1: Create a Next.js project

npx create-next-app@latest linear-tracker --typescript --tailwind

Step 2: Add dependencies

npm install @prisma/client react-query cmdk @radix-ui/dialog tailwindcss shadcn-ui

Step 3: Setup Prisma

npx prisma init # Edit .env.local with DATABASE_URL npx prisma migrate dev --name init

Step 4: Build a list component

// app/issues/page.tsx 'use client'; import { useQuery } from '@tanstack/react-query'; export default function IssuesPage() { const { data: issues } = useQuery({ queryKey: ['issues'], queryFn: () => fetch('/api/issues').then(r => r.json()), }); return ( <div className="p-8"> <h1 className="text-3xl font-bold mb-4">Issues</h1> <div className="space-y-2"> {issues?.map((issue) => ( <div key={issue.id} className="p-3 bg-gray-50 rounded cursor-pointer hover:bg-gray-100"> {issue.title} </div> ))} </div> </div> ); }

Step 5: Add keyboard shortcuts

// Add to layout.tsx 'use client'; import { useEffect } from 'react'; export default function RootLayout({ children }) { useEffect(() => { const handleKeyDown = (e) => { if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); // Open command palette } if ((e.metaKey || e.ctrlKey) && e.key === 'n') { e.preventDefault(); // New issue modal } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, []); return <html>...</html>; }

πŸ’‘ Pro Tip: Don't build everything at once. Ship a minimal kanban board first (list view with status columns). Get feedback. Then add cycles, filters, and polish.

8. The Vibe Checklist: Does Your App Feel Like Linear?

βœ… Speed Signals

  • Buttons respond instantly (no spinner wait)
  • Keyboard shortcuts work immediately
  • Scrolling is smooth (no jank)
  • Search filters in <100ms
  • Cards drag smoothly

βœ… UX Signals

  • CMD+K palette feels natural
  • j/k navigation works everywhere
  • Inline editing (click field β†’ edit)
  • Undo/redo on delete
  • Keyboard hints visible but subtle

βœ… Design Signals

  • Plenty of whitespace
  • Consistent typography
  • Color used purposefully (not rainbow)
  • Hover states on all interactive elements
  • Icons are clear and simple

βœ… Delight Signals

  • Subtle animations (not over-the-top)
  • Empty states have personality
  • Error messages are helpful
  • Success feels rewarding
  • Dark mode optional but supported

9. Deployment: From Laptop to Production

Option 1: Vercel (Easiest)

git push origin main # Your repo on GitHub # Vercel auto-deploys on push # Environment variables: DATABASE_URL in Vercel dashboard # Done. Your app is live.

Option 2: Self-Hosted (Docker)

# Dockerfile FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --omit=dev COPY . . RUN npx prisma generate RUN npm run build CMD ["npm", "start"] # docker-compose.yml version: '3.8' services: app: build: . ports: - '3000:3000' environment: DATABASE_URL: postgresql://user:pass@db:5432/tracker db: image: postgres:16 environment: POSTGRES_PASSWORD: password POSTGRES_DB: tracker volumes: - postgres_data:/var/lib/postgresql/data volumes: postgres_data:

Option 3: Railway or Render (Balanced)

Connect your GitHub repo, set DATABASE_URL, and deploy. Works great for indie projects.

10. Resources to Keep Handy

Documentation

Libraries (Copy-Paste Ready)

You've Got This πŸŽ‰

Linear isn't magic. It's JavaScript + React + good taste. You have everything you need to build something fast and beautiful.

The secret? Start small. Ship early. Get feedback. Polish obsessively. That's how you get the vibe.

πŸš€ Next Step: Open your terminal, run the quick start, and build the first version. Keyboard nav + issue list. Everything else flows from there.