initial commit

This commit is contained in:
cubecraft-agents[bot]
2026-04-25 18:51:05 +00:00
commit 230c3b295d
78 changed files with 8093 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
using Extrudex.Domain.Base;
namespace Extrudex.Domain.Entities;
/// <summary>
/// Represents a single slot within an AMS unit. Each slot can hold one spool
/// and tracks the tray index, remaining weight, and which spool is loaded.
/// </summary>
public class AmsSlot : AuditableEntity
{
/// <summary>
/// The 1-based tray/slot index within the AMS unit (1-4 per unit).
/// </summary>
public int TrayIndex { get; set; }
/// <summary>
/// Foreign key to the AMS unit this slot belongs to.
/// </summary>
public Guid AmsUnitId { get; set; }
/// <summary>
/// Navigation to the parent AMS unit.
/// </summary>
public AmsUnit AmsUnit { get; set; } = null!;
/// <summary>
/// Foreign key to the spool currently loaded in this slot. Null if empty.
/// </summary>
public Guid? SpoolId { get; set; }
/// <summary>
/// Navigation to the spool currently loaded in this slot. Null if no spool is loaded.
/// </summary>
public Spool? Spool { get; set; }
/// <summary>
/// Remaining filament weight in grams as reported by the AMS.
/// Bambu Lab AMS reports remaining weight per tray.
/// </summary>
public decimal? RemainingWeightG { get; set; }
}

View File

@@ -0,0 +1,30 @@
using Extrudex.Domain.Base;
namespace Extrudex.Domain.Entities;
/// <summary>
/// Represents an AMS (Automatic Material System) unit installed on a Bambu Lab printer.
/// Each AMS unit contains multiple slots that hold spools.
/// </summary>
public class AmsUnit : AuditableEntity
{
/// <summary>
/// The 1-based index of this AMS unit on the printer (e.g., AMS 1, AMS 2).
/// </summary>
public int UnitIndex { get; set; }
/// <summary>
/// Foreign key to the parent Printer this AMS unit is installed on.
/// </summary>
public Guid PrinterId { get; set; }
/// <summary>
/// Navigation to the parent Printer.
/// </summary>
public Printer Printer { get; set; } = null!;
/// <summary>
/// Navigation collection of slots in this AMS unit.
/// </summary>
public ICollection<AmsSlot> Slots { get; set; } = new List<AmsSlot>();
}

View File

@@ -0,0 +1,36 @@
using Extrudex.Domain.Base;
namespace Extrudex.Domain.Entities;
/// <summary>
/// Base polymer/material type. This is a lookup table enforcing consistent
/// material naming across all spools. Free-text material names are not allowed.
/// </summary>
public class MaterialBase : AuditableEntity
{
/// <summary>
/// Human-readable name of the base material (e.g., "PLA", "PETG", "ABS").
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// Density of the material in g/cm³ (g/mL). Used for deriving grams consumed
/// from mm extruded: grams = mm × cross_section_area × density.
/// </summary>
public decimal DensityGperCm3 { get; set; }
/// <summary>
/// Navigation collection of finishes available for this material base.
/// </summary>
public ICollection<MaterialFinish> Finishes { get; set; } = new List<MaterialFinish>();
/// <summary>
/// Navigation collection of modifiers applicable to this material base.
/// </summary>
public ICollection<MaterialModifier> Modifiers { get; set; } = new List<MaterialModifier>();
/// <summary>
/// Navigation collection of spools made from this material base.
/// </summary>
public ICollection<Spool> Spools { get; set; } = new List<Spool>();
}

View File

@@ -0,0 +1,30 @@
using Extrudex.Domain.Base;
namespace Extrudex.Domain.Entities;
/// <summary>
/// Surface finish descriptor for a material. This is REQUIRED on every spool
/// record. The default value is "Basic" (not "Standard").
/// </summary>
public class MaterialFinish : AuditableEntity
{
/// <summary>
/// Human-readable name of the finish (e.g., "Basic", "Matte", "Silk", "Glitter").
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// Foreign key to the parent MaterialBase. A finish belongs to exactly one base material.
/// </summary>
public Guid MaterialBaseId { get; set; }
/// <summary>
/// Navigation to the parent MaterialBase.
/// </summary>
public MaterialBase MaterialBase { get; set; } = null!;
/// <summary>
/// Navigation collection of spools with this finish.
/// </summary>
public ICollection<Spool> Spools { get; set; } = new List<Spool>();
}

View File

@@ -0,0 +1,30 @@
using Extrudex.Domain.Base;
namespace Extrudex.Domain.Entities;
/// <summary>
/// Optional modifier/additive for a material (e.g., "Carbon Fiber", "Glass Fiber",
/// "Wood Fill", "Glow-in-the-Dark"). Not every spool has a modifier.
/// </summary>
public class MaterialModifier : AuditableEntity
{
/// <summary>
/// Human-readable name of the modifier (e.g., "Carbon Fiber", "Wood Fill").
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// Foreign key to the parent MaterialBase. A modifier belongs to exactly one base material.
/// </summary>
public Guid MaterialBaseId { get; set; }
/// <summary>
/// Navigation to the parent MaterialBase.
/// </summary>
public MaterialBase MaterialBase { get; set; } = null!;
/// <summary>
/// Navigation collection of spools with this modifier.
/// </summary>
public ICollection<Spool> Spools { get; set; } = new List<Spool>();
}

View File

@@ -0,0 +1,100 @@
using Extrudex.Domain.Base;
using Extrudex.Domain.Enums;
namespace Extrudex.Domain.Entities;
/// <summary>
/// Represents a single print job. Tracks which printer and spool were used,
/// how much filament was consumed, and audit snapshots of material properties
/// at the time of printing (to preserve COGS accuracy even if material data
/// changes later).
/// </summary>
public class PrintJob : AuditableEntity
{
/// <summary>
/// Foreign key to the printer that executed this print job.
/// </summary>
public Guid PrinterId { get; set; }
/// <summary>
/// Navigation to the printer that executed this print job.
/// </summary>
public Printer Printer { get; set; } = null!;
/// <summary>
/// Foreign key to the spool that provided filament for this print job.
/// </summary>
public Guid SpoolId { get; set; }
/// <summary>
/// Navigation to the spool that provided filament for this print job.
/// </summary>
public Spool Spool { get; set; } = null!;
/// <summary>
/// Human-readable name or identifier for the print job.
/// </summary>
public string PrintName { get; set; } = string.Empty;
/// <summary>
/// Path or filename of the G-code file being printed.
/// </summary>
public string? GcodeFilePath { get; set; }
/// <summary>
/// Total millimeters of filament extruded during this print job.
/// The primary input to the COGS derivation formula.
/// </summary>
public decimal MmExtruded { get; set; }
/// <summary>
/// Derived grams consumed for this print, calculated as:
/// mm_extruded × cross_section_area × material_density_at_print.
/// </summary>
public decimal GramsDerived { get; set; }
/// <summary>
/// Calculated cost of goods sold (COGS) for this print job.
/// Derived from grams consumed and the spool's purchase price.
/// </summary>
public decimal? CostPerPrint { get; set; }
/// <summary>
/// Timestamp when the print job started (UTC).
/// </summary>
public DateTime? StartedAt { get; set; }
/// <summary>
/// Timestamp when the print job completed or failed (UTC).
/// </summary>
public DateTime? CompletedAt { get; set; }
/// <summary>
/// Current status of the print job.
/// </summary>
public JobStatus Status { get; set; } = JobStatus.Queued;
/// <summary>
/// The source of the print job data (which integration path provided it).
/// </summary>
public DataSource DataSource { get; set; }
/// <summary>
/// Audit snapshot: the filament diameter (mm) recorded at the time of printing.
/// Preserved so COGS calculations remain accurate even if the spool's
/// diameter is later corrected.
/// </summary>
public decimal FilamentDiameterAtPrintMm { get; set; }
/// <summary>
/// Audit snapshot: the material density (g/cm³) recorded at the time of printing.
/// Preserved so COGS calculations remain accurate even if the material's
/// density is later corrected.
/// </summary>
public decimal MaterialDensityAtPrint { get; set; }
/// <summary>
/// Optional notes about the print job (e.g., "First layer adhesion issues").
/// </summary>
public string? Notes { get; set; }
}

View File

@@ -0,0 +1,97 @@
using Extrudex.Domain.Base;
using Extrudex.Domain.Enums;
namespace Extrudex.Domain.Entities;
/// <summary>
/// Represents a 3D printer in the fleet. Stores connection details for
/// MQTT (Bambu Lab) or Moonraker (Elegoo Centauri Carbon) integration.
/// </summary>
public class Printer : AuditableEntity
{
/// <summary>
/// Current operational status of the printer, updated via real-time telemetry.
/// </summary>
public PrinterStatus Status { get; set; } = PrinterStatus.Offline;
/// <summary>
/// Human-readable name for the printer (e.g., "Bambu X1C #1", "Elegoo Centauri").
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// Manufacturer/brand of the printer (e.g., "Bambu Lab", "Elegoo").
/// </summary>
public string Manufacturer { get; set; } = string.Empty;
/// <summary>
/// Model name (e.g., "X1 Carbon", "Centauri Carbon").
/// </summary>
public string Model { get; set; } = string.Empty;
/// <summary>
/// The hardware type of the printer (FDM or Resin).
/// </summary>
public PrinterType PrinterType { get; set; } = PrinterType.Fdm;
/// <summary>
/// The connectivity protocol used by this printer (MQTT or Moonraker).
/// </summary>
public ConnectionType ConnectionType { get; set; } = ConnectionType.Mqtt;
/// <summary>
/// Hostname or IP address for connecting to the printer.
/// </summary>
public string HostnameOrIp { get; set; } = string.Empty;
/// <summary>
/// Port number for the printer connection. Defaults: 8883 (MQTT/TLS), 7125 (Moonraker).
/// </summary>
public int Port { get; set; }
/// <summary>
/// MQTT username for Bambu Lab printer authentication.
/// Stored only for MQTT connection type printers.
/// </summary>
public string MqttUsername { get; set; } = string.Empty;
/// <summary>
/// MQTT password for Bambu Lab printer authentication.
/// Stored only for MQTT connection type printers.
/// </summary>
public string MqttPassword { get; set; } = string.Empty;
/// <summary>
/// Whether to use TLS for the MQTT connection. Bambu Lab printers
/// require TLS on port 8883.
/// </summary>
public bool MqttUseTls { get; set; }
/// <summary>
/// Moonraker API key for Elegoo Centauri Carbon authentication.
/// Stored only for Moonraker connection type printers.
/// </summary>
public string ApiKey { get; set; } = string.Empty;
/// <summary>
/// Whether this printer is currently active and available for print jobs.
/// Inactive printers are retained for historical records.
/// </summary>
public bool IsActive { get; set; } = true;
/// <summary>
/// Timestamp of the last status update received from the printer (UTC).
/// Used to detect stale connections.
/// </summary>
public DateTime? LastSeenAt { get; set; }
/// <summary>
/// Navigation collection of AMS units installed on this printer.
/// </summary>
public ICollection<AmsUnit> AmsUnits { get; set; } = new List<AmsUnit>();
/// <summary>
/// Navigation collection of print jobs executed on this printer.
/// </summary>
public ICollection<PrintJob> PrintJobs { get; set; } = new List<PrintJob>();
}

View File

@@ -0,0 +1,105 @@
using Extrudex.Domain.Base;
namespace Extrudex.Domain.Entities;
/// <summary>
/// Represents a physical spool of filament. Every spool must have a MaterialBase
/// and MaterialFinish. MaterialModifier is optional.
/// Spools are the core inventory unit and link to PrintJobs for COGS tracking.
/// </summary>
public class Spool : AuditableEntity
{
/// <summary>
/// Foreign key to the base material. Every spool must specify a material base.
/// </summary>
public Guid MaterialBaseId { get; set; }
/// <summary>
/// Navigation to the base material (e.g., PLA, PETG, ABS).
/// </summary>
public MaterialBase MaterialBase { get; set; } = null!;
/// <summary>
/// Foreign key to the material finish. REQUIRED on every spool — default is "Basic".
/// </summary>
public Guid MaterialFinishId { get; set; }
/// <summary>
/// Navigation to the material finish (e.g., Basic, Matte, Silk, Glitter).
/// </summary>
public MaterialFinish MaterialFinish { get; set; } = null!;
/// <summary>
/// Foreign key to the optional material modifier. Null if no modifier applies.
/// </summary>
public Guid? MaterialModifierId { get; set; }
/// <summary>
/// Navigation to the optional material modifier (e.g., Carbon Fiber, Wood Fill).
/// </summary>
public MaterialModifier? MaterialModifier { get; set; }
/// <summary>
/// Human-readable brand name (e.g., "Bambu Lab", "Polymaker", "eSUN").
/// </summary>
public string Brand { get; set; } = string.Empty;
/// <summary>
/// Human-readable color name (e.g., "Fire Engine Red", "Galaxy Black").
/// </summary>
public string ColorName { get; set; } = string.Empty;
/// <summary>
/// Hex color code for the filament (e.g., "#FF0000" for red).
/// Enables color-based filtering and visual identification.
/// </summary>
public string ColorHex { get; set; } = string.Empty;
/// <summary>
/// Total spool weight in grams when full (brand new, unopened).
/// </summary>
public decimal WeightTotalGrams { get; set; }
/// <summary>
/// Current remaining weight in grams. Updated via AMS data or manual check-in.
/// </summary>
public decimal WeightRemainingGrams { get; set; }
/// <summary>
/// Filament diameter in millimeters. Typically 1.75mm for FDM printers.
/// Used in the COGS derivation formula: grams = mm × cross_section_area × density.
/// </summary>
public decimal FilamentDiameterMm { get; set; } = 1.75m;
/// <summary>
/// Manufacturer-assigned serial number for the spool. Used for barcode/QR scanning.
/// Must be unique across all spools.
/// </summary>
public string SpoolSerial { get; set; } = string.Empty;
/// <summary>
/// Purchase price per spool in the system currency. Used for COGS calculations.
/// </summary>
public decimal? PurchasePrice { get; set; }
/// <summary>
/// Date the spool was purchased or received.
/// </summary>
public DateTime? PurchaseDate { get; set; }
/// <summary>
/// Whether the spool is currently active and available for use.
/// Inactive spools are retained for historical COGS records.
/// </summary>
public bool IsActive { get; set; } = true;
/// <summary>
/// Navigation collection of AMS slots where this spool is loaded.
/// </summary>
public ICollection<AmsSlot> AmsSlots { get; set; } = new List<AmsSlot>();
/// <summary>
/// Navigation collection of print jobs that consumed filament from this spool.
/// </summary>
public ICollection<PrintJob> PrintJobs { get; set; } = new List<PrintJob>();
}