src/Application/Handlers/UpdateNodeHandler.php:21: 'op' => 'node.update', src/Application/Handlers/RenameColumnHandler.php:20: 'op' => 'column.rename', src/Application/Handlers/MoveColumnHandler.php:20: 'op' => 'node.move', src/Application/Handlers/MoveNodeHandler.php:20: 'op' => 'node.move', src/Application/Handlers/CreateColumnHandler.php:23: 'op' => 'node.create', src/Application/Handlers/RenameWorkspaceHandler.php:20: 'op' => 'workspace.rename', src/Application/Handlers/CreateWorkspaceHandler.php:21: 'op' => 'node.create', src/Application/Handlers/CreateNodeHandler.php:32: 'op' => 'node.create', src/Application/Handlers/UpdateTagFilterHandler.php:22: 'op' => 'tagFilter.set', src/Application/Handlers/AddTagHandler.php:18: 'op' => 'tag.add', src/Application/Handlers/RemoveTagHandler.php:19: 'op' => 'tag.remove', src/Application/Handlers/DeleteNodeHandler.php:20: 'op' => 'node.delete', /** @param array $state */ private function applyOperation(array $state, array $operation): array { return match ($operation['op']) { // v3 generic node/tag operations 'node.create' => $this->opNodeCreate($state, $operation), 'node.update' => $this->opNodeUpdate($state, $operation), 'node.move' => $this->opNodeMove($state, $operation), 'node.delete' => $this->opNodeDelete($state, $operation), 'tag.add' => $this->opTagAdd($state, $operation), 'tag.remove' => $this->opTagRemove($state, $operation), // filters persist (renommé) 'filters.set' => $this->opFiltersSet($state, $operation), 'tagFilter.set' => $this->opTagFilterSet($state, $operation), 'workspace.rename' => $this->opWorkspaceRename($state, $operation), 'column.rename' => $this->opColumnRename($state, $operation), default => $state, }; } private function opNodeCreate(array $state, array $op): array { $nodes = &$state['nodes']; $parentId = (string) $op['parentId']; $index = isset($op['index']) ? (int) $op['index'] : null; $nodeId = $op['nodeId'] ?? Identifiers::new(); if (!isset($nodes[$parentId])) return $state; $parent = $nodes[$parentId]; if (($parent['sys']['shape'] ?? null) !== 'container') { throw new BoardInvariantViolation('shape.leaf_has_children', 'Cannot append child to leaf node'); } $shape = $this->extractShape($op['sys'] ?? null); $tags = $op['tags'] ?? []; if (!is_array($tags)) { $tags = []; } $node = [ 'id' => $nodeId,