Issue Tracker

Build your own Linear/Jira

✓ Good to Vibe

Issue trackers are perfect vibe coding territory. The core is simple (issues with status), the UX is well-established (Linear set the bar), and you can start useful in a weekend. Skip the enterprise features until you need them—most teams use 20% of Jira.

Why This Works

Linear-level UX is achievable

Modern UI libraries make fast, keyboard-driven interfaces tractable. Framer Motion, cmdk, and optimistic updates.

Your workflow, your fields

No fighting the tool. Custom fields, statuses, and automations that match how you actually work.

Deep integrations

Connect directly to your codebase, deployments, and other tools without going through APIs.

No per-seat pricing

Linear is $8/user/month. Fine for 5 people, painful for 50.

Speed matters

Self-hosted means instant responses. No API latency for every interaction.

Data portability

Your issues, your database. Query, export, migrate freely.

Tech Stack

LayerToolsWhy
FrontendNext.js + TailwindServer components for initial load, client for interactions. Tailwind for rapid UI development.
Real-timeLiveblocks or PartyKitReal-time sync for collaborative editing. Liveblocks is easier, PartyKit more flexible.
DatabasePostgreSQL + PrismaRelational model fits issues naturally. Full-text search built in.
Command PalettecmdkThe library behind Linear and Vercel's command palettes.
MarkdownTipTap or PlateRich text editing with markdown shortcuts. TipTap is more mature.
Drag & Dropdnd-kitAccessible drag-and-drop for Kanban boards and priority reordering.

Architecture

┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Web UI │◀───▶│ Liveblocks │◀───▶│ PostgreSQL │ │ (React) │ │ (Realtime) │ │ (Data) │ └─────────────┘ └─────────────┘ └─────────────┘ │ ▲ │ ┌─────────────┐ │ └───────────▶│ Next.js │────────────┘ │ API │ └─────────────┘

The Prompt

Copy this into Cursor, Claude, or ChatGPT to generate a working implementation:

Build a Linear-style issue tracker: ## Database Schema model Issue { id String @id @default(cuid()) identifier String @unique // e.g., "ENG-123" title String description String? // Markdown/JSON for rich text status String // backlog, todo, in_progress, done, canceled priority Int // 0=none, 1=urgent, 2=high, 3=medium, 4=low projectId String project Project @relation(fields: [projectId], references: [id]) assigneeId String? assignee User? @relation("Assignee", fields: [assigneeId], references: [id]) creatorId String creator User @relation("Creator", fields: [creatorId], references: [id]) parentId String? parent Issue? @relation("Subtasks", fields: [parentId], references: [id]) subtasks Issue[] @relation("Subtasks") labels Label[] comments Comment[] estimate Int? // Story points or hours dueDate DateTime? sortOrder Float // For manual ordering within status createdAt DateTime @default(now()) updatedAt DateTime @updatedAt completedAt DateTime? @@index([projectId, status]) @@index([assigneeId]) @@index([status, sortOrder]) } model Project { id String @id @default(cuid()) name String key String @unique // e.g., "ENG" description String? teamId String team Team @relation(fields: [teamId], references: [id]) issues Issue[] issueCount Int @default(0) // For identifier generation createdAt DateTime @default(now()) } model Comment { id String @id @default(cuid()) body String issueId String issue Issue @relation(fields: [issueId], references: [id]) authorId String author User @relation(fields: [authorId], references: [id]) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Label { id String @id @default(cuid()) name String color String issues Issue[] } ## Core Features ### Issue List View - Infinite scroll with virtualization (react-window) - Filterable by status, assignee, label, priority, project - Sortable by created, updated, priority - Inline editing of title, status, assignee, priority - Multi-select with bulk actions ### Board View - Kanban columns by status - Drag-and-drop between columns (dnd-kit) - Swimlanes by assignee or priority (optional) - WIP limits per column (visual indicator) - Quick create in any column ### Issue Detail - Full-width drawer (not modal—keeps context) - Rich text editor with markdown shortcuts - Activity feed (comments + changes) - Subtasks list with progress - Keyboard navigation (j/k for prev/next) ### Command Palette (Cmd+K) - Create issue - Search issues (fuzzy match) - Jump to project/view - Change status/assignee/priority - Quick filters ### Keyboard Shortcuts - c: Create issue - /: Search - g then b: Go to board - g then l: Go to list - Arrows: Navigate - Enter: Open issue - Esc: Close/back ## Optimistic Updates All mutations should update UI immediately: 1. Apply change to local state 2. Send to server 3. If error, rollback with toast Use Tanstack Query mutations with optimistic updates.

Timeline

Week 1: Core CRUD

  • Set up database schema
  • Build issue list with filtering and sorting
  • Create issue detail view with editing
  • Implement comment system
  • Add project and team basics

Week 2: UX Polish

  • Build command palette with cmdk
  • Add keyboard shortcuts throughout
  • Implement Kanban board view
  • Create drag-and-drop reordering
  • Add optimistic updates to all mutations

Week 3: Collaboration

  • Integrate Liveblocks for real-time sync
  • Add presence indicators (who's viewing)
  • Build notification system
  • Create activity feed
  • GitHub integration for linking PRs

Open Source References

Plane ↗

Open-source Linear alternative. Great reference architecture.

Huly ↗

Full project management suite. Study their real-time approach.

cmdk ↗

Command palette library. Used by Linear, Vercel, Raycast.

dnd-kit ↗

Accessible drag-and-drop. Best-in-class for React.

Cost Comparison

Linear

$800/month
100 users at $8/user. Plus workspace features.

Self-Hosted

$50/month
Database + hosting + Liveblocks.
$750/month
potential annual savings

Watch Out For