package db // Project is the top-level entity. One project ↔ one .excalidraw drawing. type Project struct { ID int64 `json:"id"` Name string `json:"name"` DrawingName string `json:"drawing_name"` Description string `json:"description"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // CableType is global. Renaming/recolouring affects every project. type CableType struct { ID int64 `json:"id"` Name string `json:"name"` Color string `json:"color"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // Frame is a sub-zone inside a project (`desk`, `rack`, …). type Frame struct { ID int64 `json:"id"` ProjectID int64 `json:"project_id"` Name string `json:"name"` X float64 `json:"x"` Y float64 `json:"y"` Width float64 `json:"width"` Height float64 `json:"height"` ExcalidrawID *string `json:"excalidraw_id,omitempty"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // Device is a hardware item inside a project, optionally inside a frame. // v4: type_id (nullable) lets a device inherit its port profile from a // device_types catalog row. type Device struct { ID int64 `json:"id"` ProjectID int64 `json:"project_id"` FrameID *int64 `json:"frame_id"` // nullable: device "outside" any frame TypeID *int64 `json:"type_id"` // nullable: freeform device when null Name string `json:"name"` Color string `json:"color"` X float64 `json:"x"` Y float64 `json:"y"` Width float64 `json:"width"` Height float64 `json:"height"` ExcalidrawID *string `json:"excalidraw_id,omitempty"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // DeviceType is a catalog row. Built-in rows have ProjectID nil and // BuiltIn true. Project-custom rows have ProjectID set. type DeviceType struct { ID int64 `json:"id"` ProjectID *int64 `json:"project_id"` Name string `json:"name"` Kind string `json:"kind"` Icon *string `json:"icon,omitempty"` Description string `json:"description"` BuiltIn bool `json:"built_in"` Ports []DeviceTypePort `json:"ports"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // DeviceTypePort is a row of a type's port profile. The seeder uses // (cable_type_id, count, label_prefix, edge, sort_order) to lay out // concrete ports on a freshly-created device. type DeviceTypePort struct { ID int64 `json:"id"` DeviceTypeID int64 `json:"device_type_id"` CableTypeID int64 `json:"cable_type_id"` LabelPrefix string `json:"label_prefix"` Count int `json:"count"` Edge string `json:"edge"` SortOrder int `json:"sort_order"` } // Port is a connector on a device. cable_type colour drives the visual // rendering; ports are instance-owned even when seeded from a type. type Port struct { ID int64 `json:"id"` ProjectID int64 `json:"project_id"` DeviceID int64 `json:"device_id"` TypeID int64 `json:"type_id"` // cable type Label *string `json:"label"` XOffset float64 `json:"x_offset"` YOffset float64 `json:"y_offset"` ExcalidrawID *string `json:"excalidraw_id,omitempty"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // ConnectionRequirement is the solver's per-project input. // pair_lo/pair_hi are the ordered (MIN,MAX) of (from, to) so the // UNIQUE on (project_id, pair_lo, pair_hi, preferred_cable_type_id) // prevents (A,B,T) AND (B,A,T) from coexisting. type ConnectionRequirement struct { ID int64 `json:"id"` ProjectID int64 `json:"project_id"` FromDeviceID int64 `json:"from_device_id"` ToDeviceID int64 `json:"to_device_id"` PreferredCableTypeID *int64 `json:"preferred_cable_type_id"` MustConnect bool `json:"must_connect"` Notes string `json:"notes"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // Cable is a typed connection. Each endpoint is exactly one of // (port, device, io-marker). Auto=true means the solver placed it. type Cable struct { ID int64 `json:"id"` ProjectID int64 `json:"project_id"` TypeID int64 `json:"type_id"` Label *string `json:"label"` FromPortID *int64 `json:"from_port_id"` FromDeviceID *int64 `json:"from_device_id"` FromIOID *int64 `json:"from_io_id"` ToPortID *int64 `json:"to_port_id"` ToDeviceID *int64 `json:"to_device_id"` ToIOID *int64 `json:"to_io_id"` Auto bool `json:"auto"` ExcalidrawID *string `json:"excalidraw_id,omitempty"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // Bundle is a named group of cables that physically run together. type Bundle struct { ID int64 `json:"id"` ProjectID int64 `json:"project_id"` Name string `json:"name"` Auto bool `json:"auto"` CableIDs []int64 `json:"cable_ids"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // SetupTemplate is a named recipe of device-types + requirements. type SetupTemplate struct { ID int64 `json:"id"` Name string `json:"name"` Description string `json:"description"` BuiltIn bool `json:"built_in"` Devices []SetupTemplateDevice `json:"devices"` Requirements []SetupTemplateRequirement `json:"requirements"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } type SetupTemplateDevice struct { ID int64 `json:"id"` TemplateID int64 `json:"template_id"` DeviceTypeID int64 `json:"device_type_id"` DeviceType *DeviceType `json:"device_type,omitempty"` SuggestedName *string `json:"suggested_name"` SortOrder int `json:"sort_order"` } type SetupTemplateRequirement struct { ID int64 `json:"id"` TemplateID int64 `json:"template_id"` FromTemplateDeviceID int64 `json:"from_template_device_id"` ToTemplateDeviceID int64 `json:"to_template_device_id"` PreferredCableTypeID *int64 `json:"preferred_cable_type_id"` MustConnect bool `json:"must_connect"` } // SolveResult is the response shape from POST /api/projects/:pid/solve. type SolveResult struct { CablesAdded []Cable `json:"cables_added"` CablesKept []int64 `json:"cables_kept"` CablesRemoved []int64 `json:"cables_removed"` BundlesAdded []Bundle `json:"bundles_added"` BundlesRemoved []int64 `json:"bundles_removed"` Unsatisfied []UnsatisfiedReq `json:"unsatisfied"` Warnings []string `json:"warnings"` } type UnsatisfiedReq struct { RequirementID int64 `json:"requirement_id"` Reason string `json:"reason"` WhichSide string `json:"which_side,omitempty"` // "from" | "to" | "" when both/neither CableType string `json:"cable_type,omitempty"` // when known } // ApplyTemplateResult is the response from POST /apply-template. type ApplyTemplateResult struct { FramesAdded []Frame `json:"frames_added"` DevicesAdded []Device `json:"devices_added"` RequirementsAdded []ConnectionRequirement `json:"requirements_added"` SkippedDevices []SkippedTemplateDevice `json:"skipped_devices"` RequirementsSkipped []SkippedTemplateReq `json:"requirements_skipped"` } type SkippedTemplateDevice struct { TemplateDeviceID int64 `json:"template_device_id"` Reason string `json:"reason"` } type SkippedTemplateReq struct { TemplateRequirementID int64 `json:"template_requirement_id"` Reason string `json:"reason"` } // Snapshot is the editor's one-shot loader payload for a single project. // Arrays for collections still gated by future slices stay non-nil [] so // JSON encodes as [] not null. type Snapshot struct { Project Project `json:"project"` Frames []Frame `json:"frames"` Devices []Device `json:"devices"` Ports []Port `json:"ports"` Cables []Cable `json:"cables"` IOMarkers []IOMarker `json:"io_markers"` Bundles []Bundle `json:"bundles"` CableTypes []CableType `json:"cable_types"` ConnectionRequirements []ConnectionRequirement `json:"connection_requirements"` Clamps []Clamp `json:"clamps"` CableClamps []CableClamp `json:"cable_clamps"` } // Clamp is a routing anchor on the canvas. Cables route through clamps // in `ord` sequence (see cable_clamps), giving m a physical handle on // where bundles converge. type Clamp struct { ID int64 `json:"id"` ProjectID int64 `json:"project_id"` X float64 `json:"x"` Y float64 `json:"y"` Label string `json:"label"` FrameID *int64 `json:"frame_id"` ExcalidrawID *string `json:"excalidraw_id,omitempty"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } // CableClamp is one (cable, clamp, ord) row. Ord is 1-based along the // cable's from→to direction. type CableClamp struct { CableID int64 `json:"cable_id"` ClampID int64 `json:"clamp_id"` Ord int `json:"ord"` }