Collision detection root cause:
pointerWithin returns ALL droppables containing the pointer, in
registration order — not sorted by element size. Rack columns register
via useSortable before their child RackSlots, so they always came first
in the result list. over.data.current was { dragType: 'rack' }, never
{ dropType: 'slot' }, so handleDragEnd's slot check never matched and
the module snapped back.
Fix: filter droppableContainers to elements with data.current.dropType
=== 'slot' before running pointerWithin. This does an exact pointer
hit-test against only the 44px slot rects. If no slot is hit (e.g. the
pointer is in a gap or over a rack header), fall back to closestCenter
over all droppables so rack-column reorder still works.
Width fix:
24 ports * 10px + 23 gaps * 3px = 309px
+ px-2 padding (16px) + border-l-4 (4px) = 329px minimum
w-80 (320px) was 9px short, clipping port 24.
Increased to w-96 (384px) / min-w-[384px] — 55px of breathing room.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: SortableContext registers each rack column as a droppable.
Each column is ~1800px tall (42U x 44px). The default closestCenter
algorithm compared center-to-center distances, so the rack column's
center consistently beat the 44px RackSlot's center — meaning over.data
resolved to { dragType: 'rack' } and handleDragEnd's check for
dropType === 'slot' never matched. Drops silently did nothing.
Fix: replace closestCenter with a two-phase collision detection:
1. pointerWithin — returns droppables whose bounding rect contains
the actual pointer position. Slots are exactly hit-tested.
2. closestCenter fallback — used when the pointer is not within any
registered droppable (e.g. dragging a rack header between columns
for sortable reorder where the pointer may be in the gap).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Complete project scaffold with working auth, REST API, Prisma/SQLite
schema, Docker config, and React frontend for both Rack Planner and
Service Mapper modules. Both server and client pass TypeScript strict
mode with zero errors. Initial migration applied.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>