# Story 2.5: Org Chart Diagram Type Renderer

Status: done

<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->

## Story

As a user,
I want to create and view organizational charts with hierarchical nodes,
so that I can model team structures with roles and departments.

## Acceptance Criteria

1. **Given** I open or create an org chart, **When** the canvas renders, **Then** person nodes display with name, role/title, and department, **And** nodes have a professional card-like appearance with an avatar placeholder.

2. **Given** an org chart has hierarchical relationships, **When** auto-layout runs, **Then** the tree layout positions nodes in a top-down hierarchy, **And** managers appear above their direct reports with clear parent-child connections.

3. **Given** an org chart renders, **When** I view the edges, **Then** hierarchical connections use straight/orthogonal routing (not curved), **And** sibling nodes are evenly spaced.

## Tasks / Subtasks

- [x] Task 1: Create org chart constants and type registry (AC: #1)
  - [x]1.1: Create `apps/web/src/modules/diagram/types/orgchart/constants.ts` with `OC_SIZES`, `resolveOrgchartNodeType()`, `resolveOrgchartEdgeType()`, `getOrgchartPersonHeight()`
  - [x]1.2: Create `apps/web/src/modules/diagram/types/orgchart/index.ts` barrel export

- [x] Task 2: Create OrgchartPersonNode custom @xyflow/react component (AC: #1)
  - [x]2.1: Create `apps/web/src/modules/diagram/types/orgchart/OrgchartPersonNode.tsx` — professional card with avatar placeholder (icon emoji or default user icon), person name (label), role/title (tag), department (group), department color stripe

- [x] Task 3: Create OrgchartHierarchyEdge custom @xyflow/react component (AC: #2, #3)
  - [x]3.1: Create `apps/web/src/modules/diagram/types/orgchart/OrgchartHierarchyEdge.tsx` — clean orthogonal edge with `getSmoothStepPath`, no cardinality labels, subtle color using `--diagram-orgchart`

- [x] Task 4: Update graph converter for org chart type resolution (AC: #1, #2)
  - [x]4.1: Import `resolveOrgchartNodeType`, `resolveOrgchartEdgeType` from `../types/orgchart/constants` in `graph-converter.ts`
  - [x]4.2: Add `orgchart` diagramType and `org:` prefix handling in `resolveFlowNodeType()`
  - [x]4.3: Add `orgchart` diagramType handling in `resolveFlowEdgeType()`

- [x] Task 5: Register org chart types in DiagramCanvas (AC: #1, #2, #3)
  - [x]5.1: Import OrgchartPersonNode and OrgchartHierarchyEdge in `DiagramCanvas.tsx`
  - [x]5.2: Add org chart entries to `nodeTypes` and `edgeTypes` objects (OUTSIDE component)

- [x] Task 6: Org chart layout verification (AC: #2, #3)
  - [x]6.1: Verify `buildElkGraph` handles org chart person nodes with fixed `OC_SIZES.person` dimensions — add type guard similar to E-R entity height computation
  - [x]6.2: Verify ELK layered algorithm with DOWN direction produces correct top-down hierarchy for org charts

- [x] Task 7: Add org chart CSS styles (AC: #1)
  - [x]7.1: Add `.oc-person`, `.oc-person-avatar`, `.oc-person-info`, `.oc-person-name`, `.oc-person-role`, `.oc-person-dept` styles to `globals.css`
  - [x]7.2: Use `--diagram-orgchart` (green) accent color for org chart elements

- [x] Task 8: Tests (AC: all)
  - [x]8.1: Unit tests for org chart constants — `resolveOrgchartNodeType`, `resolveOrgchartEdgeType`, `getOrgchartPersonHeight` (6+ tests)
  - [x]8.2: Unit tests for graph converter org chart type mapping — node and edge types correctly resolved for `diagramType === "orgchart"` (3+ tests)
  - [x]8.3: Unit test for ELK buildElkGraph with org chart person nodes using fixed dimensions
  - [x]8.4: All existing 97 tests must continue passing — no regressions

## Dev Notes

### Overview — What This Story Builds

This story adds the Org Chart diagram type renderer: hierarchical organizational charts with professional person card nodes and clean orthogonal hierarchy edges. Like E-R (Story 2.4), org charts use **flat ELK layout** (no compound pool/lane hierarchy). The ELK layered algorithm with DOWN direction naturally produces tree-like top-down hierarchies.

**This story builds:**
- 1 custom org chart node component (OrgchartPersonNode — professional card with avatar, name, role, department)
- 1 custom org chart edge component (OrgchartHierarchyEdge — clean orthogonal hierarchy line)
- Org chart constants and type registry
- Graph converter org chart type resolution
- Org chart CSS styles using `--diagram-orgchart` green accent

**This story does NOT implement:**
- Other diagram types (Stories 2.6-2.8)
- Smart Inspector for org chart field editing (future epic)
- Manual node repositioning (Story 2.9)
- Liveblocks/CRDT integration (Epic 4)
- AI-triggered mutations (Epic 3)

### Architecture Compliance

**MANDATORY patterns from Architecture Decision Document:**

1. **Unified Graph Data Model (Decision 1):** Org chart nodes use type-prefixed `type` field (`org:person`). Existing DiagramNode fields are semantically reused: `label` = person name, `tag` = role/title, `icon` = avatar emoji, `color` = department accent color, `group` = department name. NO new fields on DiagramNode needed.

2. **Component Structure:** Feature code in `~/modules/diagram/types/orgchart/` — follows the BPMN (`types/bpmn/`) and E-R (`types/er/`) pattern. NOT co-located in route directories.

3. **@xyflow/react Custom Nodes:** All custom node components use `NodeProps` typing. The `nodeTypes` and `edgeTypes` objects MUST be defined OUTSIDE the component (performance critical — Story 2.1/2.3/2.4 pattern).

4. **ELK.js Flat Layout:** Org charts use standard flat `buildElkGraph()` — no compound hierarchy needed. The ELK layered algorithm with `direction: DOWN` naturally positions managers above their reports.

5. **Lean JSON Data Model:** No x/y positions stored for org chart nodes. All positioning computed by ELK at render time.

6. **Type Prefixing Convention (Enforcement Rule #5):** `org:person` prefix on DiagramNode.type. Edge type defaults to `"hierarchy"` for org chart.

### Org Chart Data Model — Field Mapping

The existing DiagramNode fields perfectly satisfy org chart needs:

```typescript
// How DiagramNode fields map to org chart display
interface OrgChartSemantics {
  id: string;                    // Unique person/role identifier
  type: "org:person";            // Type-prefixed node type
  label: string;                 // Person name (e.g., "Antonio García")
  tag?: string;                  // Role/title (e.g., "CEO", "Director of Engineering")
  icon?: string;                 // Avatar emoji (e.g., "👤", "💻", "🔧")
  color?: string;                // Department accent color (hex or CSS variable)
  w?: number;                    // Node width override (default: 280)
  group?: string;                // Department name (e.g., "Technology", "Sales")
  // position, manuallyPositioned — handled by ELK layout
}
```

**Reference from Flexicar org chart JSON:**
- `tag: "PRESIDENTE"` → role/title
- `label: "Oliver"` → person name
- `icon: "👤"` → avatar emoji
- `color: "#2B2A2A"` → level color (dark for executives, orange for department heads)
- `w: 300` → node width

### Org Chart Node Types — Size Constants

Org chart person nodes have fixed height (unlike E-R which is dynamic based on columns):

```typescript
export const OC_SIZES = {
  person: {
    w: 280,     // Fixed width for all person cards
    h: 80,      // Fixed height (avatar + name + role + department fits in 80px)
  },
} as const;

/** Get org chart person node height (fixed — not dynamic like E-R) */
export function getOrgchartPersonHeight(): number {
  return OC_SIZES.person.h;
}
```

### Org Chart Node Type → @xyflow/react Type Mapping

| DiagramNode.type | @xyflow Node type | Component |
|---|---|---|
| `org:person` | `orgchartPerson` | `OrgchartPersonNode` |

Only one node type needed. The person node handles all org chart roles — executives, managers, and staff are differentiated by `color` and hierarchy position, not by node type.

**Type resolution:**
```typescript
export function resolveOrgchartNodeType(type: string): string {
  const bare = type.startsWith("org:") ? type.slice(4) : type;
  switch (bare) {
    case "person":
    default:
      return "orgchartPerson";
  }
}

export function resolveOrgchartEdgeType(_type: string | undefined): string {
  return "orgchartHierarchy";
}
```

### Org Chart Edge Type — Hierarchy Connection

| DiagramEdge.type | @xyflow Edge type | Visual |
|---|---|---|
| `hierarchy` (or default) | `orgchartHierarchy` | Clean orthogonal step edge, no labels, subtle green color |

**Edge rendering approach:**
Use `getSmoothStepPath` for orthogonal routing (matching AC #3: "straight/orthogonal routing"). The edge is clean and professional — no arrow markers, no labels. Just a solid line connecting parent to child.

```typescript
import { BaseEdge, getSmoothStepPath } from "@xyflow/react";
import type { EdgeProps } from "@xyflow/react";

export function OrgchartHierarchyEdge(props: EdgeProps) {
  const [edgePath] = getSmoothStepPath({
    sourceX: props.sourceX,
    sourceY: props.sourceY,
    targetX: props.targetX,
    targetY: props.targetY,
    sourcePosition: props.sourcePosition,
    targetPosition: props.targetPosition,
    borderRadius: 8,
  });

  return (
    <BaseEdge
      id={props.id}
      path={edgePath}
      style={{ stroke: "var(--diagram-orgchart)", strokeWidth: 2 }}
    />
  );
}
```

**No arrow markers needed** — org charts use clean lines to show hierarchy. The direction (top-down) already communicates the reporting relationship.

### OrgchartPersonNode — Implementation Pattern

The person node renders as a professional card:

```
┌──────────────────────────────────────┐
│ ▌ 👤  Antonio García                │  ← Green left border stripe
│ ▌     CEO                           │  ← Role/title in muted color
│ ▌     Executive                     │  ← Department in smaller text
└──────────────────────────────────────┘
```

**Key implementation details:**

```typescript
import { Handle, Position } from "@xyflow/react";
import type { NodeProps } from "@xyflow/react";
import type { DiagramNode } from "../graph";

export function OrgchartPersonNode({ data }: NodeProps) {
  const d = data as unknown as DiagramNode & { label: string };
  const icon = d.icon ?? "👤";
  const role = d.tag;
  const department = d.group;
  const accentColor = d.color ?? "var(--diagram-orgchart)";

  return (
    <div className="oc-person" style={{ borderLeftColor: accentColor }}>
      <div className="oc-person-avatar">{icon}</div>
      <div className="oc-person-info">
        <div className="oc-person-name">{d.label}</div>
        {role && <div className="oc-person-role">{role}</div>}
        {department && <div className="oc-person-dept">{department}</div>}
      </div>
      <Handle type="target" position={Position.Top} style={{ opacity: 0 }} />
      <Handle type="source" position={Position.Bottom} style={{ opacity: 0 }} />
      <Handle type="target" position={Position.Left} id="left" style={{ opacity: 0 }} />
      <Handle type="source" position={Position.Right} id="right" style={{ opacity: 0 }} />
    </div>
  );
}
```

**All 4 handles** (top/right/bottom/left) for edge connections in any layout direction — same pattern as BPMN and E-R nodes.

**Avatar:** Uses `icon` emoji field. If not set, defaults to `"👤"`. This matches the Flexicar reference pattern where each person has an emoji icon.

### Graph Converter Updates

Add org chart type resolution alongside existing BPMN and E-R resolution:

```typescript
// In resolveFlowNodeType():
if (diagramType === "orgchart" || nodeType.startsWith("org:")) {
  return resolveOrgchartNodeType(nodeType);
}

// In resolveFlowEdgeType():
if (diagramType === "orgchart") {
  return resolveOrgchartEdgeType(edgeType);
}
```

**Import from orgchart/constants.ts** — same pattern as BPMN and E-R imports.

**No container nodes needed** — Org charts are flat hierarchies. The `graphToFlow()` function's existing default path (flat node mapping) handles org charts correctly.

**Existing data fields already preserved:** `graphNodeToFlowNode` spreads all node data into `data: { ...node }`, which includes `tag`, `icon`, `group`. And `flowNodeToGraphNode` already preserves `tag`, `icon`, `color`, `group`. No changes needed to the roundtrip logic.

### DiagramCanvas Updates

Add org chart node/edge types to the `nodeTypes` and `edgeTypes` objects:

```typescript
import { OrgchartPersonNode } from "../../types/orgchart/OrgchartPersonNode";
import { OrgchartHierarchyEdge } from "../../types/orgchart/OrgchartHierarchyEdge";

const nodeTypes = {
  // Existing BPMN + E-R types...
  orgchartPerson: OrgchartPersonNode,
};

const edgeTypes = {
  // Existing BPMN + E-R types...
  orgchartHierarchy: OrgchartHierarchyEdge,
};
```

**No additional marker defs needed** — org chart hierarchy edges don't use arrow markers.

**BFS Path Highlighting:** The existing `handleNodeClick` uses `CONTAINER_TYPES` to skip container nodes. Org charts have no container nodes, so no changes needed. BFS highlighting works on org chart person nodes out of the box.

### Layout — ELK Flat Layout for Org Charts

Org charts use the existing flat `buildElkGraph()` — no compound layout detection needed.

**Key:** Person node dimensions are fixed (unlike E-R entities which have dynamic height). In `buildElkGraph`, add type detection for `orgchartPerson` nodes to use `OC_SIZES.person`:

```typescript
children: nodes.map((node) => {
  const data = node.data as unknown as DiagramNode;
  // E-R entities: compute height from columns
  const isErEntity = node.type === "erEntity";
  // Org chart persons: fixed dimensions
  const isOcPerson = node.type === "orgchartPerson";
  const height =
    isErEntity && data.columns
      ? getErEntityHeight(data.columns)
      : isOcPerson
        ? OC_SIZES.person.h
        : (node.measured?.height ?? DEFAULT_NODE_HEIGHT);
  const width =
    isOcPerson
      ? (data.w ?? OC_SIZES.person.w)
      : (data.w ?? node.measured?.width ?? DEFAULT_NODE_WIDTH);
  return {
    id: node.id,
    width,
    height,
  };
}),
```

**Layout algorithm note:** The ELK `layered` algorithm produces good tree-like layouts with `direction: DOWN`. The `mrtree` algorithm would be even more specialized for pure trees (centers parents over children), but `layered` is sufficient for v1 and maintains consistency with other diagram types. Optimizing to `mrtree` can be a future enhancement.

**Sibling spacing (AC #3):** The default `nodeSpacing: 80` ensures even spacing between sibling nodes at the same hierarchy level.

### CSS Styles for Org Chart Nodes

Add to `globals.css`:

```css
/* ── Org Chart Person Styles ──────────────────────────────────────── */

.oc-person {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--node-bg);
  border: 1.5px solid var(--diagram-orgchart);
  border-left: 4px solid var(--diagram-orgchart);
  border-radius: 8px;
  padding: 10px 14px;
  min-width: 240px;
  max-width: 320px;
  cursor: pointer;
}

.oc-person-avatar {
  font-size: 24px;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  background: color-mix(in oklch, var(--diagram-orgchart) 10%, transparent);
  border-radius: 50%;
}

.oc-person-info {
  min-width: 0;
  flex: 1;
}

.oc-person-name {
  font-weight: 600;
  font-size: 13px;
  color: var(--foreground);
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.oc-person-role {
  font-size: 11px;
  color: var(--muted-foreground);
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.oc-person-dept {
  font-size: 10px;
  color: var(--diagram-orgchart);
  font-weight: 500;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
```

**Color note:** The person card uses `--diagram-orgchart` (green) for the left border stripe and department text. The `borderLeftColor` can be overridden per-node via `data.color` for department-specific coloring (executives = dark, sales = orange, tech = blue, etc.).

**Dark mode:** Uses CSS custom properties (`--node-bg`, `--foreground`, `--muted-foreground`, `--diagram-orgchart`) which automatically adapt to dark mode through the existing `:root` / `.dark` theme definitions.

### Existing Code to Reuse / Modify

| File | Action | What |
|------|--------|------|
| `apps/web/src/modules/diagram/components/editor/DiagramCanvas.tsx` | **MODIFY** | Register org chart node types and edge types |
| `apps/web/src/modules/diagram/lib/graph-converter.ts` | **MODIFY** | Add org chart type resolution for nodes and edges (import from orgchart/constants) |
| `apps/web/src/modules/diagram/lib/elk-layout.ts` | **MODIFY** | Add org chart person node size handling in `buildElkGraph` |
| `apps/web/src/assets/styles/globals.css` | **MODIFY** | Add org chart person node CSS styles |
| `apps/web/src/modules/diagram/types/graph.ts` | **READ** | DiagramNode (tag, icon, group, color) — already defined, no changes |
| `apps/web/src/modules/diagram/lib/bfs-path.ts` | **REUSE** | Path highlighting works for org charts — diagram-type-agnostic |
| `apps/web/src/modules/diagram/stores/useGraphStore.ts` | **REUSE** | highlightedNodeId/setHighlightedNodeId — no changes needed |
| `apps/web/src/modules/diagram/hooks/useAutoLayout.ts` | **REUSE** | Auto-layout works with flat ELK — no changes needed |

### Library & Framework Requirements

**No new packages required.** Everything built with existing dependencies:
- `@xyflow/react` 12.10.1 — custom nodes, edges, handles, BaseEdge, getSmoothStepPath
- `elkjs` 0.11.0 — flat layered layout with DOWN direction
- `zustand` 5.0.8 — highlight state (reuse existing)

### File Structure for This Story

New files:
```
apps/web/src/modules/diagram/
├── types/orgchart/
│   ├── index.ts                          # Exports all org chart components + constants
│   ├── constants.ts                      # OC_SIZES, type mappings, getOrgchartPersonHeight
│   ├── constants.test.ts                # Tests for org chart constants
│   ├── OrgchartPersonNode.tsx           # Person custom node (professional card)
│   └── OrgchartHierarchyEdge.tsx        # Hierarchy edge (clean orthogonal line)
```

Modified files:
```
apps/web/src/modules/diagram/components/editor/DiagramCanvas.tsx  # Register org chart node/edge types
apps/web/src/modules/diagram/lib/graph-converter.ts               # Org chart type mapping
apps/web/src/modules/diagram/lib/graph-converter.test.ts          # Add org chart converter tests
apps/web/src/modules/diagram/lib/elk-layout.ts                    # Org chart person size in buildElkGraph
apps/web/src/modules/diagram/lib/elk-layout.test.ts               # Add org chart ELK tests
apps/web/src/assets/styles/globals.css                             # Org chart CSS styles
```

### Project Structure Notes

- Org chart node components go in `~/modules/diagram/types/orgchart/` — follows BPMN (`types/bpmn/`) and E-R (`types/er/`) pattern
- Layout utilities in `~/modules/diagram/lib/` — org chart uses the existing flat `buildElkGraph`, only person node size handling added
- `bfs-path.ts` reused as-is — diagram-type-agnostic
- Tests co-located next to source files

### Anti-Patterns to Avoid

- **NEVER put `nodeTypes` or `edgeTypes` inside the component** — causes re-renders on every state change (Story 2.1/2.3/2.4 pattern)
- **NEVER hardcode positions for org chart nodes** — all positioning from ELK layout
- **NEVER import from `reactflow`** — use `@xyflow/react` (v12+)
- **NEVER use `require()`** — ESM-only project
- **NEVER co-locate feature code in route directories** — use `~/modules/diagram/`
- **NEVER store ELK-computed positions in persisted graph data** — positions are ephemeral
- **NEVER use compound/hierarchical ELK layout for org chart** — flat layout is correct (no pools/lanes)
- **NEVER add new fields to DiagramNode** — use existing fields (`tag`, `icon`, `group`, `color`) with org chart semantics
- **DO NOT implement Smart Inspector for org chart** — that's a future story
- **DO NOT implement other diagram type renderers** — those are Stories 2.6-2.8
- **DO NOT break existing tests** — 97 tests must continue passing
- **DO NOT use inline styles for org chart colors** — use CSS custom properties (`--diagram-orgchart`)
- **DO NOT add arrow markers to hierarchy edges** — clean lines communicate hierarchy via direction

### Previous Story Intelligence (Story 2.4 — E-R)

**Key learnings to carry forward:**
- Constants file pattern: `ER_SIZES` map → `OC_SIZES` equivalent. Type resolution functions: `resolveXNodeType`, `resolveXEdgeType`
- Node component pattern: Cast `data` as `DiagramNode & { label: string }`, use `Handle` with `style={{ opacity: 0 }}` at 4 positions
- Edge component pattern: `BaseEdge` + `getSmoothStepPath`, simpler than E-R (no cardinality labels needed)
- Graph converter: `resolveFlowNodeType` switch on `diagramType`, import type resolver from `types/[type]/constants`
- DiagramCanvas: import components, add to `nodeTypes`/`edgeTypes` objects
- CSS: Use `--diagram-[type]` CSS variable for accent colors
- `graphNodeToFlowNode` already spreads all DiagramNode fields into `data` — custom nodes access `data.tag`, `data.icon`, `data.group` directly
- `flowNodeToGraphNode` already preserves `tag`, `icon`, `group`, `color` fields — roundtrip works
- Code review from 2.4: Use `color-mix()` for hover/bg tints instead of hardcoded oklch values
- 97 web tests currently pass — don't break them

### Previous Story Intelligence (Story 2.2 — ELK Layout)

**Key learnings:**
- `buildElkGraph()` is the flat layout builder — org chart uses this directly
- `resolvePositions()` handles flat graphs — org chart uses this directly
- `computeLayout()` detects BPMN compound layout via `isCompound = nodes.some(n => n.type === "bpmnPool")` — org chart won't trigger this since it has no pools
- Person node dimensions are fixed (unlike E-R where height depends on column count) — simpler size handling

### Git Intelligence

Recent commits:
- `0a7838a feat: implement Story 2.3 — BPMN diagram type renderer`
- `7dd5af1 feat: implement Story 2.2 — ELK.js auto-layout engine in Web Worker`
- `5033109 feat: implement Story 2.1 — canvas workspace with @xyflow/react and unified graph model`

Established patterns:
- Commit message: `feat: implement Story X.Y — description`
- Feature code in `apps/web/src/modules/diagram/`
- Co-located tests next to source files
- `diagramTypeConfig` in DiagramCard.tsx already has org chart config: `{ label: "Org Chart", icon: Icons.UsersRound, color: "text-green-500" }`
- CSS variable `--diagram-orgchart: oklch(0.723 0.219 150)` already defined in globals.css

### Latest Tech Information

**@xyflow/react 12.10.1 — getSmoothStepPath for orthogonal edges:**
- `getSmoothStepPath` produces step/orthogonal edges (right-angle turns) — perfect for org chart hierarchy
- `borderRadius` parameter controls corner rounding (8px recommended for professional look)
- Returns `[path, labelX, labelY, offsetX, offsetY]` — only `path` needed for hierarchy edges (no labels)
- `BaseEdge` accepts `path` and `style` props — minimal edge implementation

**ELK.js Layered Algorithm with DOWN direction:**
- `elk.direction: DOWN` + `elk.algorithm: layered` produces top-down hierarchical layout
- `elk.layered.nodePlacement.strategy: BRANDES_KOEPF` centers nodes well in tree structures
- `elk.layered.crossingMinimization.strategy: LAYER_SWEEP` minimizes edge crossings
- Default settings already configured in `elk-layout.ts` — no changes to layout options needed
- The layered algorithm naturally positions parent nodes in upper layers and child nodes in lower layers

**DiagramNode fields (already defined in graph.ts):**
```typescript
interface DiagramNode {
  id: string;
  type: string;        // "org:person"
  tag?: string;        // role/title
  label: string;       // person name
  icon?: string;       // avatar emoji
  color?: string;      // department accent color
  w?: number;          // width override
  group?: string;      // department name
  // ... other fields (position, manuallyPositioned, etc.)
}
```

### References

- [Source: _bmad-output/planning-artifacts/epics.md#Story 2.5] — Full AC: person nodes with name/role/department, top-down tree layout, orthogonal routing
- [Source: _bmad-output/planning-artifacts/architecture.md#Decision 1] — Unified Graph Data Model: `org:person` prefix, shared base fields
- [Source: _bmad-output/planning-artifacts/architecture.md#Enforcement Guidelines] — 7 mandatory rules, type prefixing: `org:`
- [Source: _bmad-output/planning-artifacts/ux-design-specification.md#Diagram Type Renderers] — Org Chart: Person node (avatar, name, role)
- [Source: _bmad-output/planning-artifacts/ux-design-specification.md#Diagram Type Color Accents] — Org Chart: green oklch(0.723 0.219 150)
- [Source: _bmad-output/implementation-artifacts/2-4-entity-relationship-diagram-type-renderer.md] — E-R implementation patterns (constants, nodes, edges, converter, canvas registration)
- [Source: _bmad-output/project-context.md] — 62 critical implementation rules
- [Source: /Users/agutierrez/Desktop/flexicar-context/.diagrams/app/orgchart.json] — Reference org chart: tag=role, label=name, icon=emoji, color per department
- [Source: apps/web/src/modules/diagram/types/graph.ts] — DiagramNode (tag, icon, group, color), DiagramType includes "orgchart"
- [Source: apps/web/src/modules/diagram/lib/graph-converter.ts] — Current converter with BPMN + E-R resolution to extend for org chart
- [Source: apps/web/src/modules/diagram/lib/elk-layout.ts] — Current flat layout builder, E-R height pattern to follow for org chart width/height
- [Source: apps/web/src/modules/diagram/components/editor/DiagramCanvas.tsx] — Canvas to register org chart types
- [Source: apps/web/src/assets/styles/globals.css] — CSS with `--diagram-orgchart` already defined

## Dev Agent Record

### Agent Model Used

Claude Opus 4.6

### Debug Log References

None — clean implementation with no failures.

### Completion Notes List

- **Task 1:** Created `constants.ts` with `OC_SIZES` (w:280, h:80), `getOrgchartPersonHeight()`, `resolveOrgchartNodeType()`, `resolveOrgchartEdgeType()`. Created `index.ts` barrel export.
- **Task 2:** Created `OrgchartPersonNode.tsx` — professional card with green left border stripe, avatar emoji (defaults to person emoji), name (label), role/title (tag), department (group). Accent color overridable via `data.color`. 4 handles for multi-direction edges.
- **Task 3:** Created `OrgchartHierarchyEdge.tsx` — clean orthogonal edge using `getSmoothStepPath` with 8px border radius. Green stroke (2px) from `--diagram-orgchart`. No arrow markers — direction communicates hierarchy.
- **Task 4:** Updated `graph-converter.ts` — added `orgchart` diagramType and `org:` prefix resolution for both nodes and edges. Imported from `orgchart/constants`. Data fields (`tag`, `icon`, `group`, `color`) already preserved by existing spread pattern.
- **Task 5:** Updated `DiagramCanvas.tsx` — registered `orgchartPerson` and `orgchartHierarchy` in `nodeTypes`/`edgeTypes` objects. No additional marker defs needed.
- **Task 6:** Updated `elk-layout.ts` — `buildElkGraph` now detects `orgchartPerson` nodes and uses `OC_SIZES.person` for fixed width (280) and height (80). Respects `data.w` override for width. Org chart uses flat layout (no compound detection triggered).
- **Task 7:** Added org chart CSS to `globals.css` — person card with flex layout, avatar circle with green tint background, name/role/department text with proper overflow handling. All using `--diagram-orgchart` green accent and `color-mix()` for tints.
- **Task 8:** 11 new tests (6 constants + 3 converter + 2 ELK). Updated 1 existing test (`org:` prefix now resolves to `orgchartPerson`). All 108 tests pass (97 existing + 11 new).

### Senior Developer Review (AI)

**Reviewer:** Claude Opus 4.6 (adversarial code review)
**Date:** 2026-02-25
**Outcome:** Approved with fixes applied

**Issues Found (7 total: 3 Medium, 4 Low) — All resolved:**

- [x] [AI-Review][MEDIUM] Removed dead code `getOrgchartPersonHeight()` — never used in production, `elk-layout.ts` uses `OC_SIZES.person.h` directly. Removed from `constants.ts`, `index.ts`, and test file.
- [x] [AI-Review][MEDIUM] Fixed empty string color guard in `OrgchartPersonNode` — changed `??` to `||` so falsy `data.color` (including `""`) falls back to CSS default correctly.
- [x] [AI-Review][MEDIUM] Eliminated unnecessary inline style object on every render — now conditionally applies `borderLeftColor` only when `data.color` is truthy, avoiding 100+ redundant object allocations per render cycle.
- [x] [AI-Review][LOW] Removed dead `getOrgchartPersonHeight` export from barrel `index.ts`.
- [x] [AI-Review][LOW] Fixed misleading test data — changed `org:unit` to `org:person` in "handle all 6 diagram types" test.
- [x] [AI-Review][LOW] Added `:hover` effect on `.oc-person` card with subtle green tint.
- [ ] [AI-Review][LOW] No component rendering tests for OrgchartPersonNode/OrgchartHierarchyEdge — noted as known gap, consistent with existing BPMN/E-R pattern. Deferred to E2E testing phase.

**Test results after fixes:** 107 passing (removed 1 dead test for getOrgchartPersonHeight).

### Change Log

- 2026-02-25: Code review — fixed 6 issues (dead code, empty string guard, render perf, test accuracy, hover UX). 107 tests pass.
- 2026-02-24: Implemented Story 2.5 — Org Chart diagram type renderer with person nodes, hierarchy edges, graph converter integration, ELK layout support, and CSS styles.

### File List

New files:
- `apps/web/src/modules/diagram/types/orgchart/constants.ts`
- `apps/web/src/modules/diagram/types/orgchart/constants.test.ts`
- `apps/web/src/modules/diagram/types/orgchart/index.ts`
- `apps/web/src/modules/diagram/types/orgchart/OrgchartPersonNode.tsx`
- `apps/web/src/modules/diagram/types/orgchart/OrgchartHierarchyEdge.tsx`

Modified files:
- `apps/web/src/modules/diagram/lib/graph-converter.ts`
- `apps/web/src/modules/diagram/lib/graph-converter.test.ts`
- `apps/web/src/modules/diagram/lib/elk-layout.ts`
- `apps/web/src/modules/diagram/lib/elk-layout.test.ts`
- `apps/web/src/modules/diagram/components/editor/DiagramCanvas.tsx`
- `apps/web/src/assets/styles/globals.css`
- `_bmad-output/implementation-artifacts/sprint-status.yaml`
