Skip to content

Add kind palette with affinity ranking and post-create kind editing#49

Merged
CuriouslyCory merged 1 commit into
mainfrom
feature/kind-palette-affinity
May 31, 2026
Merged

Add kind palette with affinity ranking and post-create kind editing#49
CuriouslyCory merged 1 commit into
mainfrom
feature/kind-palette-affinity

Conversation

@CuriouslyCory

@CuriouslyCory CuriouslyCory commented May 31, 2026

Copy link
Copy Markdown
Owner

Summary

  • Expanded NodeKind from 6 → 26 values covering the full hierarchy story: global infrastructure → datacenters → networks → hosts → containers → services/microservices/crons → applications/modules → classes/functions → variables/branches, plus data (TABLE, STORED_PROCEDURE), interface (ENDPOINT, WEBHOOK), and messaging (TOPIC, CONSUMER, PRODUCER) kinds. Kind stays cosmetic (ADR-0018).
  • Kind palette — a shadcn/cmdk Command popover replacing the <select>. Search + keyboard nav + icons; organized into a "Suggested for inside ⟨parent⟩" group above a separator and "All kinds" (alphabetic) below, so every kind is always reachable.
  • Kind affinity — a client-side Record<NodeKind | "ROOT", readonly NodeKind[]> map that ranks the palette by the current Canvas scope's parent kind. Inside DATABASETABLE / STORED_PROCEDURE; inside HOSTCONTAINER / SERVICE / MICROSERVICE / CRON; at the project root → infrastructure-flavored kinds. Affinity is ranking, never constraint (ADR-0019) — the service accepts any kind regardless of parent.
  • Change a Component's kind after creation via a narrow updateNodeKind mutation, surfaced as a Kind row in the Component-detail panel that reopens the same palette (single kind-selection surface).
  • getCanvas breadcrumbs now carry kind — one-column widening of the recursive CTE (no extra round trip per ADR-0001/0006); the picker reads breadcrumbs.at(-1)?.kind ?? null.
  • One value set, lockstep maps: Zod ↔ Prisma parity guard, plus exhaustive Record<NodeKind, …> for KIND_LABEL, KIND_ICON, KIND_AFFINITY, and the server-side serializer label map. A new kind cannot ship without label + icon + affinity row.

New files

  • src/lib/node-kinds.tsKIND_LABEL, KIND_ICON, KIND_ORDER, KIND_AFFINITY, suggestedKinds()
  • src/components/ui/command.tsx — Tailwind wrapper over cmdk (no full shadcn install)
  • src/app/p/[slug]/_canvas/kind-palette.tsxKindPalette + reusable KindPickerPopover
  • prisma/migrations/20260531181535_expand_node_kind_taxonomy/migration.sql
  • docs/adr/0018-nodekind-expanded-taxonomy-stays-cosmetic.md
  • docs/adr/0019-kind-affinity-is-ranking-not-constraint.md

Docs

  • CONTEXT.md: rewrote Component kind, added Kind affinity and Kind palette, touched Breadcrumbs shape note.
  • ADR-0018: the expanded taxonomy stays cosmetic; one value set, four lockstep maps, two guards.
  • ADR-0019: kind affinity is a UI ranking, not a constraint; map is a client-side constant; rejected alternatives (Prisma whitelist, service-side assertKindAllowedUnder, server-derived suggestions) recorded with rationale.

Test plan

  • pnpm check — clean (lint + typecheck)
  • pnpm test — 210/210 pass, including:
    • breadcrumbs carry kind ordered root→current
    • every kind in the expanded enum round-trips create → persist → getCanvas
    • updateNodeKind happy path, off-parent-affinity accepted, no Edge/Flow cascade, authz, not-found, soft-deleted, Zod rejection
  • pnpm build — clean (no client/server bundle leak; cmdk and the catalog bundle into the SSR-disabled island)
  • pnpm db:migrate + pnpm db:check — no drift
  • End-to-end UI verification in a real Discord-authenticated browser:
    • Palette at root shows "Suggested for the project root" with Global infrastructure, Data center, Region, Network, Host, External API first
    • "All kinds" group: 20 remaining kinds, alphabetized; multi-word labels render (Stored procedure, External API, Data center, Global infrastructure)
    • Inside DATACENTER → palette ranks Host, Network, Database, Queue first
    • Inside HOST → ranks Container, Service, Microservice, Cron first
    • Detail panel Kind row opens the palette keyed by the parent's kind, marks current kind
    • Change-kind: pick Microservice → optimistic icon swap → reload → persists (no stale "Service" anywhere on the page)

Refs

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Expanded component kind taxonomy from 6 to 26 types, covering infrastructure, services, data, and messaging scopes.
    • Introduced searchable command-palette-based kind picker replacing the dropdown, with context-aware "Suggested" and "All kinds" grouping.
    • Component owners can now change a component's kind, updating its icon, color, and label.
  • Documentation

    • Added architecture decision records defining the expanded taxonomy and kind-affinity ranking system.

Expands NodeKind from 6 to 26 values covering the global-infra → code
hierarchy, replaces the <select> with a shadcn/cmdk Command palette, and
introduces kind affinity — a parent-kind → suggested-children ranking
keyed by the current Canvas scope (read off the breadcrumb, which now
carries kind). Components can be re-kinded after creation via a narrow
updateNodeKind mutation surfaced as a Kind row in the detail panel that
reopens the same palette. Kind stays cosmetic per ADR-0018; affinity is
ranking, never constraint, per ADR-0019.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@vercel

vercel Bot commented May 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
infinite-docs Ready Ready Preview, Comment May 31, 2026 8:21pm

Request Review

@coderabbitai

coderabbitai Bot commented May 31, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 575d87d2-d7c3-4b46-a8b6-c42bb9300350

📥 Commits

Reviewing files that changed from the base of the PR and between 7154133 and 3acb274.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • CONTEXT.md
  • docs/adr/0018-nodekind-expanded-taxonomy-stays-cosmetic.md
  • docs/adr/0019-kind-affinity-is-ranking-not-constraint.md
  • package.json
  • prisma/migrations/20260531181535_expand_node_kind_taxonomy/migration.sql
  • prisma/schema.prisma
  • src/app/p/[slug]/_canvas/add-component.tsx
  • src/app/p/[slug]/_canvas/boundary-group-node.tsx
  • src/app/p/[slug]/_canvas/boundary-proxy-node.tsx
  • src/app/p/[slug]/_canvas/canvas.tsx
  • src/app/p/[slug]/_canvas/component-detail-panel.tsx
  • src/app/p/[slug]/_canvas/component-node.tsx
  • src/app/p/[slug]/_canvas/kind-palette.tsx
  • src/components/ui/command.tsx
  • src/lib/node-kinds.ts
  • src/lib/schemas.ts
  • src/server/api/routers/architecture.ts
  • src/server/architecture/__tests__/node.service.test.ts
  • src/server/architecture/markdown.ts
  • src/server/architecture/node.service.ts

📝 Walkthrough

Walkthrough

This PR expands the NodeKind taxonomy from 6 to 26 hierarchical values (infrastructure, networking, runtime, software, data, interfaces, messaging), implements kind-affinity-based ranking for a new cmdk-powered kind picker, integrates kind into canvas breadcrumbs for context-aware suggestions, adds an owner-only updateNodeKind mutation, and ensures kind remains cosmetic (affecting only UI/affinity, never nesting or authorization).

Changes

NodeKind Taxonomy & Kind-Affinity System

Layer / File(s) Summary
Documentation, ADRs, and Taxonomy Schema
CONTEXT.md, docs/adr/0018-*.md, docs/adr/0019-*.md, prisma/schema.prisma, prisma/migrations/*, src/lib/schemas.ts
Adds ADRs documenting expanded NodeKind (26 values) and kind-affinity as UI-only ranking; updates Prisma enum and Zod schema; database migration adds new enum values; establishes compile-time parity guard between client/server.
Client Kind Catalog and Command UI Library
package.json, src/lib/node-kinds.ts, src/components/ui/command.tsx
Creates KIND_LABEL, KIND_ICON, KIND_ORDER, KIND_AFFINITY records and suggestedKinds() helper for affinity-split ranking; adds cmdk dependency and Command/CommandInput/CommandList/CommandGroup/CommandItem UI wrapper components with Tailwind styling.
Kind Palette Picker Component
src/app/p/[slug]/_canvas/kind-palette.tsx
Exports KindPalette (searchable, keyboard-navigable command palette splitting kinds into Suggested and All kinds via suggestedKinds) and KindPickerPopover (stateful popover with outside-click and escape-key dismiss).
Server Kind Mutation and Breadcrumb Integration
src/server/architecture/node.service.ts, src/server/api/routers/architecture.ts, src/server/architecture/markdown.ts
Adds updateNodeKind mutation (owner-only, parses input, authorizes, updates only kind field); updates getCanvas to include kind in each breadcrumb for picker affinity lookup; expands NodeKind↔PrismaNodeKind parity arrays; updates markdown serializer KIND_LABEL map.
Canvas and Component UI Integration
src/app/p/[slug]/_canvas/canvas.tsx, src/app/p/[slug]/_canvas/add-component.tsx, src/app/p/[slug]/_canvas/component-detail-panel.tsx, src/app/p/[slug]/_canvas/component-node.tsx, src/app/p/[slug]/_canvas/boundary-*.tsx
Canvas derives parentKind from breadcrumbs and passes to AddComponent; wires commitNodeKind callback for optimistic kind updates with cache rollback on failure; ComponentDetailPanel shows/edits kind via KindSection using KindPickerPopover; centralizes KIND_ICON/KIND_LABEL in node-kinds lib.
Test Coverage for Kind Persistence and Mutation
src/server/architecture/__tests__/node.service.test.ts
Tests kind enum round-trip (createNode→getCanvas), breadcrumb kind field, updateNodeKind (success, off-affinity acceptance, cosmetic-only behavior, auth/notfound/schema errors).

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Canvas as CanvasInner
  participant AddComponent as AddComponent/Detail
  participant KindPickerPopover
  participant commitNodeKind as optimistic update
  participant updateNodeKind as TRPC mutation
  participant Server as node.service
  
  User->>Canvas: load canvas
  Canvas->>Server: getCanvas()
  Server-->>Canvas: breadcrumbs[{id, title, kind}]
  Canvas->>Canvas: parentKind = breadcrumbs[-1]?.kind
  
  User->>AddComponent: click + or select component
  AddComponent->>KindPickerPopover: render with parentKind
  KindPickerPopover->>KindPickerPopover: suggestedKinds(parentKind)
  User->>KindPickerPopover: select kind
  KindPickerPopover->>Canvas: onSelect(kind)
  
  Canvas->>commitNodeKind: onChangeKind(nodeId, kind)
  commitNodeKind->>Canvas: optimistic: update node.kind + cache
  commitNodeKind->>updateNodeKind: call mutation
  updateNodeKind->>Server: updateNodeKind(id, kind)
  Server->>Server: assertCanWrite(owner)
  Server->>Server: UPDATE Node.kind
  Server-->>updateNodeKind: success
  updateNodeKind-->>Canvas: confirm (cache already updated)
  
  alt mutation fails
    updateNodeKind->>Canvas: rollback if cache still matches optimistic
    Canvas->>Canvas: restore prior kind
    Canvas->>User: show toast error
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The PR spans 23 files with mixed complexity: documentation and schema updates are straightforward, but the integration of kind picker, affinity ranking, breadcrumb wiring, and optimistic mutation handling requires careful review of consistency across client/server and round-trip behavior. The comprehensive test suite mitigates some risk by covering persistence, authorization, and cosmetic-only semantics.

Possibly related issues

  • CuriouslyCory/infinite-docs#2: Implements the expanded NodeKind taxonomy, kind-affinity picker, and breadcrumb-kind integration that the original product requirements specified.

Possibly related PRs

  • CuriouslyCory/infinite-docs#22: Both PRs implement the core Component kind feature end-to-end; this PR extends it to the full 26-value taxonomy, adds kind-affinity ranking, and completes the updateNodeKind mutation path.

Poem

🐰 Twenty-six kinds now bloom and sway,
Icons paint the cosmic way,
Affinity whispers which to choose,
No rules enforced—just UI muse,
Cosmetic beauty, truth holds fast!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main changes: adding a kind palette with affinity ranking and enabling kind editing after component creation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/kind-palette-affinity

Comment @coderabbitai help to get the list of available commands and usage tips.

@CuriouslyCory CuriouslyCory merged commit 7b1ff86 into main May 31, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant