Internode: Project Management Tool
Engineering-grade project management platform with Kanban boards, real-time task tracking, and a developer-centric dark interface.









Internode was born out of frustration with bloated project management tools. As a CTO managing an 8-member engineering team across 16 repositories, I needed something that matched the speed and precision of modern development workflows — not Jira's 200ms response times.
The Problem
Most project management tools are designed for product managers, not engineers. They're slow, cluttered, and divorced from how developers actually think. I needed:
- Sub-100ms task updates — No waiting for spinners while switching boards
- Keyboard-first navigation — Mouseless workflow for power users
- Engineering-grade auth — Real security, not cookie-based sessions from 2010
- Zero vendor lock-in — Own your data, own your schema
Architecture Overview
Key Technical Decisions
Next.js 16 App Router + React Server Components
The entire data-fetching layer runs server-side. Project boards, task lists, and user assignments are streamed directly from the database to pre-rendered HTML — no client-side loading states for the initial render. Only interactive mutation actions (drag-and-drop reordering, inline task editing) hydrate client-side React.
// Server Component — zero-JS data fetching
export default async function BoardPage({ params }: { params: { projectId: string } }) {
const tasks = await db.query.tasks.findMany({
where: eq(tasks.projectId, params.projectId),
orderBy: [asc(tasks.order)],
with: { assignee: true, labels: true }
});
return <KanbanBoard initialTasks={tasks} />;
}Drizzle ORM — Type-Safe Schema
Unlike Prisma's runtime overhead, Drizzle generates pure SQL at compile time. Every query is fully typed — no more any types leaking from raw database responses.
export const tasks = pgTable('tasks', {
id: uuid('id').primaryKey().defaultRandom(),
title: text('title').notNull(),
status: taskStatusEnum('status').default('todo').notNull(),
priority: taskPriorityEnum('priority').default('medium').notNull(),
projectId: uuid('project_id').notNull().references(() => projects.id, { onDelete: 'cascade' }),
assigneeId: uuid('assignee_id').references(() => users.id),
order: integer('order').default(0).notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at').defaultNow().notNull(),
});Better-Auth — Production Security
Better-Auth provides cryptographic session management with refresh token rotation, CSRF protection, and zero-trust middleware — more secure than NextAuth.js defaults out of the box.
Model Context Protocol (MCP) Server Integration
Internode exposes a native, secure Model Context Protocol (MCP) server endpoint at /api/mcp. This enables developers to connect local or remote LLM agents (e.g., Claude Desktop, Cursor) directly to their active workspace context:
- Resource Expositions: Maps database entities (task states, team backlogs, project meta) into read-only markdown references for local agent injection.
- Actionable Tools: Exposes write operations allowing agents to dynamically query assignments, create cards, append tags, and transition task statuses through structured JSON schemas.
- RBAC Security Guardrails: Exclusively gates the
/api/mcpquery loop via short-lived, cryptographically generated API keys. External tools cannot access internal resources unless explicitly authorized by the workspace owner.
Production-Grade Subscription Engine (Lemon Squeezy)
To support scaling engineering teams, Internode implements a robust, webhooks-driven subscription billing engine integrated with Lemon Squeezy:
- State-Synchronized Webhook Pipeline: Built a dedicated webhook endpoint
/api/webhooks/lemonsqueezyverifying cryptographically signed payloads (X-Signature) using HMAC-SHA256. It processes all major billing states (subscription_created,subscription_updated,subscription_cancelled,subscription_expired) dynamically syncing the local PostgreSQLorganizationsschema. - Granular Plan Gatekeeping: Restricts workspace allocations (maximum members, project boards, task items) via automated Drizzle query interceptors that cross-reference active subscription plans (
free,pro,enterprise) in real time. - Transactional React Email Relays: Hooks directly into status transition events to trigger beautifully formatted, welcome and transactional status notifications using custom React Email templates dispatched via Resend and transactional SMTP relays.
Feature Set
| Feature | Detail |
|---|---|
| Kanban Board | Drag-and-drop columns with optimistic UI updates |
| List View | Filterable, sortable task table with inline editing |
| Task Detail | Rich description editor, labels, priority, assignees |
| Team Management | Invite members via email, role-based permissions |
| Auth | Email/password + OAuth (GitHub) via Better-Auth |
| MCP Integration | Native /api/mcp server endpoint exposing workspace context and task-actions to LLM agents |
| SaaS Subscriptions | Lemon Squeezy webhooks-driven billing syncing active tiers (Free/Pro/Enterprise) |
| Dark Mode | System-aware with persistent user preference |
What I Learned
Building Internode taught me how powerful React Server Components genuinely are when paired with a type-safe ORM. The key insight: stream data, hydrate interactions. Most of the UI doesn't need client-side JavaScript at all — only the parts that need real-time mutation do. This keeps the JS bundle lean and the initial paint instant.