diff --git a/backend/API/Controllers/UsageLogsController.cs b/backend/API/Controllers/UsageLogsController.cs
new file mode 100644
index 0000000..f6727f3
--- /dev/null
+++ b/backend/API/Controllers/UsageLogsController.cs
@@ -0,0 +1,117 @@
+using Extrudex.API.DTOs.UsageLogs;
+using Extrudex.Domain.Enums;
+using Extrudex.Domain.Interfaces;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Extrudex.API.Controllers;
+
+///
+/// API controller for recording and querying filament usage logs.
+/// Usage logs provide a fine-grained audit trail of filament consumption
+/// from printer integrations or manual input.
+///
+[ApiController]
+[Route("api/[controller]")]
+[Produces("application/json")]
+public class UsageLogsController : ControllerBase
+{
+ private readonly IUsageLogService _usageLogService;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The usage log service for recording and querying usage.
+ public UsageLogsController(IUsageLogService usageLogService)
+ {
+ _usageLogService = usageLogService;
+ }
+
+ ///
+ /// Records a new filament usage entry.
+ ///
+ /// The usage entry details.
+ /// The created usage log entry.
+ [HttpPost]
+ [ProducesResponseType(typeof(UsageLogResponse), StatusCodes.Status201Created)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ public async Task> Create([FromBody] CreateUsageLogRequest request)
+ {
+ if (!Enum.TryParse(request.DataSource, ignoreCase: true, out var dataSource))
+ {
+ return BadRequest($"Invalid data source: '{request.DataSource}'. Valid values: Mqtt, Moonraker, Manual.");
+ }
+
+ var entry = await _usageLogService.RecordUsageAsync(
+ spoolId: request.SpoolId,
+ gramsUsed: request.GramsUsed,
+ dataSource: dataSource,
+ printerId: request.PrinterId,
+ printJobId: request.PrintJobId,
+ mmExtruded: request.MmExtruded,
+ usageTimestamp: request.UsageTimestamp,
+ notes: request.Notes
+ );
+
+ return CreatedAtAction(
+ nameof(GetBySpool),
+ new { spoolId = entry.SpoolId },
+ MapToResponse(entry));
+ }
+
+ ///
+ /// Gets usage logs for a specific spool, ordered by most recent first.
+ ///
+ /// The spool ID to filter by.
+ /// A collection of usage log entries for the spool.
+ [HttpGet("spool/{spoolId:guid}")]
+ [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)]
+ public async Task>> GetBySpool(Guid spoolId)
+ {
+ var logs = await _usageLogService.GetBySpoolAsync(spoolId);
+ return Ok(logs.Select(MapToResponse));
+ }
+
+ ///
+ /// Gets usage logs for a specific printer, ordered by most recent first.
+ ///
+ /// The printer ID to filter by.
+ /// A collection of usage log entries for the printer.
+ [HttpGet("printer/{printerId:guid}")]
+ [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)]
+ public async Task>> GetByPrinter(Guid printerId)
+ {
+ var logs = await _usageLogService.GetByPrinterAsync(printerId);
+ return Ok(logs.Select(MapToResponse));
+ }
+
+ ///
+ /// Gets usage logs for a specific print job, ordered by most recent first.
+ ///
+ /// The print job ID to filter by.
+ /// A collection of usage log entries for the print job.
+ [HttpGet("print-job/{printJobId:guid}")]
+ [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)]
+ public async Task>> GetByPrintJob(Guid printJobId)
+ {
+ var logs = await _usageLogService.GetByPrintJobAsync(printJobId);
+ return Ok(logs.Select(MapToResponse));
+ }
+
+ ///
+ /// Maps a UsageLog domain entity to a UsageLogResponse DTO.
+ ///
+ private static UsageLogResponse MapToResponse(Domain.Entities.UsageLog log) => new()
+ {
+ Id = log.Id,
+ SpoolId = log.SpoolId,
+ PrinterId = log.PrinterId,
+ PrintJobId = log.PrintJobId,
+ GramsUsed = log.GramsUsed,
+ MmExtruded = log.MmExtruded,
+ UsageTimestamp = log.UsageTimestamp,
+ DataSource = log.DataSource.ToString(),
+ Notes = log.Notes,
+ CreatedAt = log.CreatedAt,
+ UpdatedAt = log.UpdatedAt
+ };
+}
\ No newline at end of file
diff --git a/backend/API/DTOs/UsageLogs/UsageLogDtos.cs b/backend/API/DTOs/UsageLogs/UsageLogDtos.cs
new file mode 100644
index 0000000..a1087de
--- /dev/null
+++ b/backend/API/DTOs/UsageLogs/UsageLogDtos.cs
@@ -0,0 +1,115 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Extrudex.API.DTOs.UsageLogs;
+
+///
+/// Request DTO for recording a filament usage entry.
+///
+public class CreateUsageLogRequest
+{
+ ///
+ /// The ID of the spool that provided the filament.
+ ///
+ [Required]
+ public Guid SpoolId { get; set; }
+
+ ///
+ /// The number of grams of filament consumed.
+ ///
+ [Required]
+ [Range(0.01, double.MaxValue, ErrorMessage = "GramsUsed must be a positive value.")]
+ public decimal GramsUsed { get; set; }
+
+ ///
+ /// The source of the usage data (Mqtt, Moonraker, Manual).
+ ///
+ [Required]
+ public string DataSource { get; set; } = string.Empty;
+
+ ///
+ /// The ID of the printer that consumed the filament. Optional.
+ ///
+ public Guid? PrinterId { get; set; }
+
+ ///
+ /// The ID of the print job associated with this usage. Optional.
+ ///
+ public Guid? PrintJobId { get; set; }
+
+ ///
+ /// The number of millimeters of filament extruded. Optional.
+ ///
+ public decimal? MmExtruded { get; set; }
+
+ ///
+ /// When the usage occurred (UTC). Defaults to now if not specified.
+ ///
+ public DateTime? UsageTimestamp { get; set; }
+
+ ///
+ /// Optional notes about this usage entry.
+ ///
+ [MaxLength(2000)]
+ public string? Notes { get; set; }
+}
+
+///
+/// Response DTO for a usage log entry.
+///
+public class UsageLogResponse
+{
+ ///
+ /// Unique identifier for the usage log entry.
+ ///
+ public Guid Id { get; set; }
+
+ ///
+ /// The spool that provided the filament.
+ ///
+ public Guid SpoolId { get; set; }
+
+ ///
+ /// The printer that consumed the filament, if applicable.
+ ///
+ public Guid? PrinterId { get; set; }
+
+ ///
+ /// The print job associated with this usage, if applicable.
+ ///
+ public Guid? PrintJobId { get; set; }
+
+ ///
+ /// Grams of filament consumed.
+ ///
+ public decimal GramsUsed { get; set; }
+
+ ///
+ /// Millimeters of filament extruded, if available.
+ ///
+ public decimal? MmExtruded { get; set; }
+
+ ///
+ /// When the usage occurred (UTC).
+ ///
+ public DateTime UsageTimestamp { get; set; }
+
+ ///
+ /// Source of the usage data (Mqtt, Moonraker, Manual).
+ ///
+ public string DataSource { get; set; } = string.Empty;
+
+ ///
+ /// Optional notes about this usage entry.
+ ///
+ public string? Notes { get; set; }
+
+ ///
+ /// When the record was created (UTC).
+ ///
+ public DateTime CreatedAt { get; set; }
+
+ ///
+ /// When the record was last updated (UTC).
+ ///
+ public DateTime UpdatedAt { get; set; }
+}
\ No newline at end of file
diff --git a/backend/Domain/Entities/UsageLog.cs b/backend/Domain/Entities/UsageLog.cs
new file mode 100644
index 0000000..c9cfed0
--- /dev/null
+++ b/backend/Domain/Entities/UsageLog.cs
@@ -0,0 +1,72 @@
+using Extrudex.Domain.Base;
+using Extrudex.Domain.Enums;
+
+namespace Extrudex.Domain.Entities;
+
+///
+/// Represents a single filament usage log entry. Records how much filament
+/// was consumed, by which printer, at what time, and optionally linked to
+/// a print job. This provides a fine-grained audit trail of filament consumption
+/// independent of print job lifecycle.
+///
+public class UsageLog : AuditableEntity
+{
+ ///
+ /// Foreign key to the spool that provided the filament.
+ ///
+ public Guid SpoolId { get; set; }
+
+ ///
+ /// Navigation to the spool that provided the filament.
+ ///
+ public Spool Spool { get; set; } = null!;
+
+ ///
+ /// Foreign key to the printer that consumed the filament.
+ /// Nullable to support manual entries without a specific printer.
+ ///
+ public Guid? PrinterId { get; set; }
+
+ ///
+ /// Navigation to the printer that consumed the filament.
+ ///
+ public Printer? Printer { get; set; }
+
+ ///
+ /// Foreign key to the print job associated with this usage entry.
+ /// Nullable because usage can be logged before or without a print job.
+ ///
+ public Guid? PrintJobId { get; set; }
+
+ ///
+ /// Navigation to the print job associated with this usage entry.
+ ///
+ public PrintJob? PrintJob { get; set; }
+
+ ///
+ /// The number of grams of filament consumed in this usage event.
+ ///
+ public decimal GramsUsed { get; set; }
+
+ ///
+ /// The number of millimeters of filament extruded in this usage event.
+ /// Optional — may not be available for all data sources.
+ ///
+ public decimal? MmExtruded { get; set; }
+
+ ///
+ /// Timestamp when the usage occurred (UTC). This is the actual time of
+ /// consumption, which may differ from CreatedAt if the entry was recorded later.
+ ///
+ public DateTime UsageTimestamp { get; set; } = DateTime.UtcNow;
+
+ ///
+ /// The source of the usage data (which integration path provided it).
+ ///
+ public DataSource DataSource { get; set; } = DataSource.Manual;
+
+ ///
+ /// Optional notes about this usage entry.
+ ///
+ public string? Notes { get; set; }
+}
\ No newline at end of file
diff --git a/backend/Domain/Interfaces/IUsageLogService.cs b/backend/Domain/Interfaces/IUsageLogService.cs
new file mode 100644
index 0000000..1d99f64
--- /dev/null
+++ b/backend/Domain/Interfaces/IUsageLogService.cs
@@ -0,0 +1,57 @@
+using Extrudex.Domain.Entities;
+using Extrudex.Domain.Enums;
+
+namespace Extrudex.Domain.Interfaces;
+
+///
+/// Service for recording filament usage entries. Writes to the usage_logs table
+/// and provides query capabilities for usage history.
+///
+public interface IUsageLogService
+{
+ ///
+ /// Records a filament usage entry.
+ ///
+ /// The spool that provided the filament.
+ /// Grams of filament consumed.
+ /// Where the data came from.
+ /// Optional printer ID.
+ /// Optional print job ID.
+ /// Optional mm extruded.
+ /// When the usage occurred (defaults to UTC now).
+ /// Optional notes.
+ /// The created UsageLog entity.
+ Task RecordUsageAsync(
+ Guid spoolId,
+ decimal gramsUsed,
+ DataSource dataSource,
+ Guid? printerId = null,
+ Guid? printJobId = null,
+ decimal? mmExtruded = null,
+ DateTime? usageTimestamp = null,
+ string? notes = null);
+
+ ///
+ /// Retrieves usage logs for a specific spool, ordered by usage timestamp descending.
+ ///
+ /// The spool ID to filter by.
+ /// Cancellation token.
+ /// A collection of usage logs for the spool.
+ Task> GetBySpoolAsync(Guid spoolId, CancellationToken cancellationToken = default);
+
+ ///
+ /// Retrieves usage logs for a specific printer, ordered by usage timestamp descending.
+ ///
+ /// The printer ID to filter by.
+ /// Cancellation token.
+ /// A collection of usage logs for the printer.
+ Task> GetByPrinterAsync(Guid printerId, CancellationToken cancellationToken = default);
+
+ ///
+ /// Retrieves usage logs for a specific print job, ordered by usage timestamp descending.
+ ///
+ /// The print job ID to filter by.
+ /// Cancellation token.
+ /// A collection of usage logs for the print job.
+ Task> GetByPrintJobAsync(Guid printJobId, CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/backend/Infrastructure/Data/Configurations/UsageLogConfiguration.cs b/backend/Infrastructure/Data/Configurations/UsageLogConfiguration.cs
new file mode 100644
index 0000000..127cccb
--- /dev/null
+++ b/backend/Infrastructure/Data/Configurations/UsageLogConfiguration.cs
@@ -0,0 +1,91 @@
+using Extrudex.Domain.Entities;
+using Extrudex.Domain.Enums;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
+namespace Extrudex.Infrastructure.Data.Configurations;
+
+///
+/// EF Core configuration for the UsageLog entity.
+/// Maps to the usage_logs table with snake_case columns and appropriate indexes.
+///
+public class UsageLogConfiguration : BaseEntityConfiguration
+{
+ ///
+ public override void Configure(EntityTypeBuilder builder)
+ {
+ base.Configure(builder);
+
+ builder.Property(e => e.SpoolId)
+ .HasColumnName("spool_id")
+ .IsRequired();
+
+ builder.Property(e => e.PrinterId)
+ .HasColumnName("printer_id");
+
+ builder.Property(e => e.PrintJobId)
+ .HasColumnName("print_job_id");
+
+ builder.Property(e => e.GramsUsed)
+ .HasColumnName("grams_used")
+ .HasPrecision(10, 2)
+ .IsRequired();
+
+ builder.Property(e => e.MmExtruded)
+ .HasColumnName("mm_extruded")
+ .HasPrecision(12, 2);
+
+ builder.Property(e => e.UsageTimestamp)
+ .HasColumnName("usage_timestamp")
+ .IsRequired();
+
+ builder.Property(e => e.DataSource)
+ .HasColumnName("data_source")
+ .HasConversion()
+ .HasMaxLength(50)
+ .IsRequired();
+
+ builder.Property(e => e.Notes)
+ .HasColumnName("notes")
+ .HasMaxLength(2000);
+
+ // Index on spool_id for querying usage by spool
+ builder.HasIndex(e => e.SpoolId)
+ .HasDatabaseName("ix_usage_logs_spool_id");
+
+ // Index on printer_id for querying usage by printer
+ builder.HasIndex(e => e.PrinterId)
+ .HasDatabaseName("ix_usage_logs_printer_id");
+
+ // Index on print_job_id for querying usage by print job
+ builder.HasIndex(e => e.PrintJobId)
+ .HasDatabaseName("ix_usage_logs_print_job_id");
+
+ // Index on usage_timestamp for chronological queries
+ builder.HasIndex(e => e.UsageTimestamp)
+ .HasDatabaseName("ix_usage_logs_usage_timestamp");
+
+ // Index on data_source for filtering by integration path
+ builder.HasIndex(e => e.DataSource)
+ .HasDatabaseName("ix_usage_logs_data_source");
+
+ // Relationships
+ builder.HasOne(e => e.Spool)
+ .WithMany()
+ .HasForeignKey(e => e.SpoolId)
+ .HasConstraintName("fk_usage_logs_spool")
+ .OnDelete(DeleteBehavior.Restrict);
+
+ builder.HasOne(e => e.Printer)
+ .WithMany()
+ .HasForeignKey(e => e.PrinterId)
+ .HasConstraintName("fk_usage_logs_printer")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ builder.HasOne(e => e.PrintJob)
+ .WithMany()
+ .HasForeignKey(e => e.PrintJobId)
+ .HasConstraintName("fk_usage_logs_print_job")
+ .OnDelete(DeleteBehavior.SetNull);
+ }
+}
\ No newline at end of file
diff --git a/backend/Infrastructure/Data/ExtrudexDbContext.cs b/backend/Infrastructure/Data/ExtrudexDbContext.cs
index 270718c..3e5fe9a 100644
--- a/backend/Infrastructure/Data/ExtrudexDbContext.cs
+++ b/backend/Infrastructure/Data/ExtrudexDbContext.cs
@@ -24,6 +24,7 @@ public class ExtrudexDbContext : DbContext
public DbSet AmsSlots => Set();
public DbSet PrintJobs => Set();
public DbSet FilamentUsages => Set();
+ public DbSet UsageLogs => Set();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
diff --git a/backend/Infrastructure/Data/Migrations/20260426184329_AddUsageLogTable.Designer.cs b/backend/Infrastructure/Data/Migrations/20260426184329_AddUsageLogTable.Designer.cs
new file mode 100644
index 0000000..2e6cf81
--- /dev/null
+++ b/backend/Infrastructure/Data/Migrations/20260426184329_AddUsageLogTable.Designer.cs
@@ -0,0 +1,1061 @@
+//
+using System;
+using Extrudex.Infrastructure.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Extrudex.Infrastructure.Data.Migrations
+{
+ [DbContext(typeof(ExtrudexDbContext))]
+ [Migration("20260426184329_AddUsageLogTable")]
+ partial class AddUsageLogTable
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.AmsSlot", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("AmsUnitId")
+ .HasColumnType("uuid")
+ .HasColumnName("ams_unit_id");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.Property("RemainingWeightG")
+ .HasPrecision(10, 2)
+ .HasColumnType("numeric(10,2)")
+ .HasColumnName("remaining_weight_g");
+
+ b.Property("SpoolId")
+ .HasColumnType("uuid")
+ .HasColumnName("spool_id");
+
+ b.Property("TrayIndex")
+ .HasColumnType("integer")
+ .HasColumnName("tray_index");
+
+ b.Property("UpdatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SpoolId")
+ .HasDatabaseName("ix_ams_slots_spool_id");
+
+ b.HasIndex("AmsUnitId", "TrayIndex")
+ .IsUnique()
+ .HasDatabaseName("ix_ams_slots_ams_unit_id_tray_index");
+
+ b.ToTable("ams_slots", (string)null);
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.AmsUnit", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.Property("PrinterId")
+ .HasColumnType("uuid")
+ .HasColumnName("printer_id");
+
+ b.Property("UnitIndex")
+ .HasColumnType("integer")
+ .HasColumnName("unit_index");
+
+ b.Property("UpdatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PrinterId", "UnitIndex")
+ .IsUnique()
+ .HasDatabaseName("ix_ams_units_printer_id_unit_index");
+
+ b.ToTable("ams_units", (string)null);
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.MaterialBase", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.Property("DensityGperCm3")
+ .HasPrecision(10, 4)
+ .HasColumnType("numeric(10,4)")
+ .HasColumnName("density_g_per_cm3");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)")
+ .HasColumnName("name");
+
+ b.Property("UpdatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name")
+ .IsUnique()
+ .HasDatabaseName("ix_material_bases_name");
+
+ b.ToTable("material_bases", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("10000000-0000-0000-0000-000000000001"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(6535),
+ DensityGperCm3 = 1.24m,
+ Name = "PLA",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(6535)
+ },
+ new
+ {
+ Id = new Guid("10000000-0000-0000-0000-000000000002"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7016),
+ DensityGperCm3 = 1.27m,
+ Name = "PETG",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7016)
+ },
+ new
+ {
+ Id = new Guid("10000000-0000-0000-0000-000000000003"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7027),
+ DensityGperCm3 = 1.04m,
+ Name = "ABS",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7028)
+ },
+ new
+ {
+ Id = new Guid("10000000-0000-0000-0000-000000000004"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7034),
+ DensityGperCm3 = 1.07m,
+ Name = "ASA",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7035)
+ },
+ new
+ {
+ Id = new Guid("10000000-0000-0000-0000-000000000005"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7042),
+ DensityGperCm3 = 1.21m,
+ Name = "TPU",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7042)
+ },
+ new
+ {
+ Id = new Guid("10000000-0000-0000-0000-000000000006"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7049),
+ DensityGperCm3 = 1.14m,
+ Name = "Nylon",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7049)
+ });
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.MaterialFinish", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.Property("MaterialBaseId")
+ .HasColumnType("uuid")
+ .HasColumnName("material_base_id");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)")
+ .HasColumnName("name");
+
+ b.Property("UpdatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.HasKey("Id");
+
+ b.HasIndex("MaterialBaseId", "Name")
+ .IsUnique()
+ .HasDatabaseName("ix_material_finishes_material_base_id_name");
+
+ b.ToTable("material_finishes", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000001"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7291),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
+ Name = "Basic",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7292)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000002"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7453),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
+ Name = "Matte",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7453)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000003"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7461),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
+ Name = "Silk",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7461)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000004"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7468),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
+ Name = "Glitter",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7468)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000005"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7474),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
+ Name = "Marble",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7474)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000006"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7480),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
+ Name = "Sparkle",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7481)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000007"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7487),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000002"),
+ Name = "Basic",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7487)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000008"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7493),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000002"),
+ Name = "Matte",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7493)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000009"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7500),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000002"),
+ Name = "Silk",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7500)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000010"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7507),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000003"),
+ Name = "Basic",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7507)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000011"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7513),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000003"),
+ Name = "Matte",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7513)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000012"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7519),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000004"),
+ Name = "Basic",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7520)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000013"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7526),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000004"),
+ Name = "Matte",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7526)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000014"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7532),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000005"),
+ Name = "Basic",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7532)
+ },
+ new
+ {
+ Id = new Guid("20000000-0000-0000-0000-000000000015"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7538),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000006"),
+ Name = "Basic",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7539)
+ });
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.MaterialModifier", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.Property("MaterialBaseId")
+ .HasColumnType("uuid")
+ .HasColumnName("material_base_id");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("character varying(100)")
+ .HasColumnName("name");
+
+ b.Property("UpdatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.HasKey("Id");
+
+ b.HasIndex("MaterialBaseId", "Name")
+ .IsUnique()
+ .HasDatabaseName("ix_material_modifiers_material_base_id_name");
+
+ b.ToTable("material_modifiers", (string)null);
+
+ b.HasData(
+ new
+ {
+ Id = new Guid("30000000-0000-0000-0000-000000000001"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7690),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
+ Name = "Carbon Fiber",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7690)
+ },
+ new
+ {
+ Id = new Guid("30000000-0000-0000-0000-000000000002"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7838),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
+ Name = "Glass Fiber",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7838)
+ },
+ new
+ {
+ Id = new Guid("30000000-0000-0000-0000-000000000003"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7846),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
+ Name = "Wood Fill",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7846)
+ },
+ new
+ {
+ Id = new Guid("30000000-0000-0000-0000-000000000004"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7853),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
+ Name = "Glow-in-the-Dark",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7853)
+ },
+ new
+ {
+ Id = new Guid("30000000-0000-0000-0000-000000000005"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7859),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000002"),
+ Name = "Carbon Fiber",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7859)
+ },
+ new
+ {
+ Id = new Guid("30000000-0000-0000-0000-000000000006"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7865),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000002"),
+ Name = "Glass Fiber",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7866)
+ },
+ new
+ {
+ Id = new Guid("30000000-0000-0000-0000-000000000007"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7872),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000003"),
+ Name = "Carbon Fiber",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7872)
+ },
+ new
+ {
+ Id = new Guid("30000000-0000-0000-0000-000000000008"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7878),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000003"),
+ Name = "Glass Fiber",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7879)
+ },
+ new
+ {
+ Id = new Guid("30000000-0000-0000-0000-000000000009"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7885),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000004"),
+ Name = "Carbon Fiber",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7885)
+ },
+ new
+ {
+ Id = new Guid("30000000-0000-0000-0000-000000000010"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7891),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000006"),
+ Name = "Carbon Fiber",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7891)
+ },
+ new
+ {
+ Id = new Guid("30000000-0000-0000-0000-000000000011"),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7898),
+ MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000006"),
+ Name = "Glass Fiber",
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7898)
+ });
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.PrintJob", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("CompletedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("completed_at");
+
+ b.Property("CostPerPrint")
+ .HasPrecision(10, 4)
+ .HasColumnType("numeric(10,4)")
+ .HasColumnName("cost_per_print");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.Property("DataSource")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)")
+ .HasColumnName("data_source");
+
+ b.Property("FilamentDiameterAtPrintMm")
+ .HasPrecision(6, 3)
+ .HasColumnType("numeric(6,3)")
+ .HasColumnName("filament_diameter_at_print_mm");
+
+ b.Property("GcodeFilePath")
+ .HasMaxLength(1000)
+ .HasColumnType("character varying(1000)")
+ .HasColumnName("gcode_file_path");
+
+ b.Property("GramsDerived")
+ .HasPrecision(10, 2)
+ .HasColumnType("numeric(10,2)")
+ .HasColumnName("grams_derived");
+
+ b.Property("MaterialDensityAtPrint")
+ .HasPrecision(10, 4)
+ .HasColumnType("numeric(10,4)")
+ .HasColumnName("material_density_at_print");
+
+ b.Property("MmExtruded")
+ .HasPrecision(12, 2)
+ .HasColumnType("numeric(12,2)")
+ .HasColumnName("mm_extruded");
+
+ b.Property("Notes")
+ .HasMaxLength(2000)
+ .HasColumnType("character varying(2000)")
+ .HasColumnName("notes");
+
+ b.Property("PrintName")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("character varying(500)")
+ .HasColumnName("print_name");
+
+ b.Property("PrinterId")
+ .HasColumnType("uuid")
+ .HasColumnName("printer_id");
+
+ b.Property("SpoolId")
+ .HasColumnType("uuid")
+ .HasColumnName("spool_id");
+
+ b.Property("StartedAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("started_at");
+
+ b.Property("Status")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)")
+ .HasDefaultValue("Queued")
+ .HasColumnName("status");
+
+ b.Property("UpdatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DataSource")
+ .HasDatabaseName("ix_print_jobs_data_source");
+
+ b.HasIndex("PrinterId")
+ .HasDatabaseName("ix_print_jobs_printer_id");
+
+ b.HasIndex("SpoolId")
+ .HasDatabaseName("ix_print_jobs_spool_id");
+
+ b.HasIndex("Status")
+ .HasDatabaseName("ix_print_jobs_status");
+
+ b.ToTable("print_jobs", (string)null);
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.Printer", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("ApiKey")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("character varying(500)")
+ .HasColumnName("api_key");
+
+ b.Property("ConnectionType")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)")
+ .HasColumnName("connection_type");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.Property("HostnameOrIp")
+ .IsRequired()
+ .HasMaxLength(255)
+ .HasColumnType("character varying(255)")
+ .HasColumnName("hostname_or_ip");
+
+ b.Property("IsActive")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("boolean")
+ .HasDefaultValue(true)
+ .HasColumnName("is_active");
+
+ b.Property("LastSeenAt")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("last_seen_at");
+
+ b.Property("Manufacturer")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("manufacturer");
+
+ b.Property("Model")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("model");
+
+ b.Property("MqttPassword")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("character varying(500)")
+ .HasColumnName("mqtt_password");
+
+ b.Property("MqttUseTls")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("boolean")
+ .HasDefaultValue(false)
+ .HasColumnName("mqtt_use_tls");
+
+ b.Property("MqttUsername")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("mqtt_username");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("name");
+
+ b.Property("Port")
+ .HasColumnType("integer")
+ .HasColumnName("port");
+
+ b.Property("PrinterType")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)")
+ .HasColumnName("printer_type");
+
+ b.Property("Status")
+ .IsRequired()
+ .ValueGeneratedOnAdd()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)")
+ .HasDefaultValue("Offline")
+ .HasColumnName("status");
+
+ b.Property("UpdatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ConnectionType")
+ .HasDatabaseName("ix_printers_connection_type");
+
+ b.HasIndex("IsActive")
+ .HasDatabaseName("ix_printers_is_active");
+
+ b.HasIndex("PrinterType")
+ .HasDatabaseName("ix_printers_printer_type");
+
+ b.HasIndex("Status")
+ .HasDatabaseName("ix_printers_status");
+
+ b.ToTable("printers", (string)null);
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.Spool", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("Brand")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("brand");
+
+ b.Property("ColorHex")
+ .IsRequired()
+ .HasMaxLength(7)
+ .HasColumnType("character varying(7)")
+ .HasColumnName("color_hex");
+
+ b.Property("ColorName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("color_name");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.Property("FilamentDiameterMm")
+ .HasPrecision(6, 3)
+ .HasColumnType("numeric(6,3)")
+ .HasColumnName("filament_diameter_mm");
+
+ b.Property("IsActive")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("boolean")
+ .HasDefaultValue(true)
+ .HasColumnName("is_active");
+
+ b.Property("MaterialBaseId")
+ .HasColumnType("uuid")
+ .HasColumnName("material_base_id");
+
+ b.Property("MaterialFinishId")
+ .HasColumnType("uuid")
+ .HasColumnName("material_finish_id");
+
+ b.Property("MaterialModifierId")
+ .HasColumnType("uuid")
+ .HasColumnName("material_modifier_id");
+
+ b.Property("PurchaseDate")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("purchase_date");
+
+ b.Property("PurchasePrice")
+ .HasPrecision(10, 2)
+ .HasColumnType("numeric(10,2)")
+ .HasColumnName("purchase_price");
+
+ b.Property("SpoolSerial")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("character varying(200)")
+ .HasColumnName("spool_serial");
+
+ b.Property("UpdatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.Property("WeightRemainingGrams")
+ .HasPrecision(10, 2)
+ .HasColumnType("numeric(10,2)")
+ .HasColumnName("weight_remaining_grams");
+
+ b.Property("WeightTotalGrams")
+ .HasPrecision(10, 2)
+ .HasColumnType("numeric(10,2)")
+ .HasColumnName("weight_total_grams");
+
+ b.HasKey("Id");
+
+ b.HasIndex("IsActive")
+ .HasDatabaseName("ix_spools_is_active");
+
+ b.HasIndex("MaterialBaseId")
+ .HasDatabaseName("ix_spools_material_base_id");
+
+ b.HasIndex("MaterialFinishId")
+ .HasDatabaseName("ix_spools_material_finish_id");
+
+ b.HasIndex("MaterialModifierId")
+ .HasDatabaseName("ix_spools_material_modifier_id");
+
+ b.HasIndex("SpoolSerial")
+ .IsUnique()
+ .HasDatabaseName("ix_spools_spool_serial");
+
+ b.ToTable("spools", (string)null);
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.UsageLog", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.Property("DataSource")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)")
+ .HasColumnName("data_source");
+
+ b.Property("GramsUsed")
+ .HasPrecision(10, 2)
+ .HasColumnType("numeric(10,2)")
+ .HasColumnName("grams_used");
+
+ b.Property("MmExtruded")
+ .HasPrecision(12, 2)
+ .HasColumnType("numeric(12,2)")
+ .HasColumnName("mm_extruded");
+
+ b.Property("Notes")
+ .HasMaxLength(2000)
+ .HasColumnType("character varying(2000)")
+ .HasColumnName("notes");
+
+ b.Property("PrintJobId")
+ .HasColumnType("uuid")
+ .HasColumnName("print_job_id");
+
+ b.Property("PrinterId")
+ .HasColumnType("uuid")
+ .HasColumnName("printer_id");
+
+ b.Property("SpoolId")
+ .HasColumnType("uuid")
+ .HasColumnName("spool_id");
+
+ b.Property("UpdatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.Property("UsageTimestamp")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("usage_timestamp");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DataSource")
+ .HasDatabaseName("ix_usage_logs_data_source");
+
+ b.HasIndex("PrintJobId")
+ .HasDatabaseName("ix_usage_logs_print_job_id");
+
+ b.HasIndex("PrinterId")
+ .HasDatabaseName("ix_usage_logs_printer_id");
+
+ b.HasIndex("SpoolId")
+ .HasDatabaseName("ix_usage_logs_spool_id");
+
+ b.HasIndex("UsageTimestamp")
+ .HasDatabaseName("ix_usage_logs_usage_timestamp");
+
+ b.ToTable("usage_logs", (string)null);
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.AmsSlot", b =>
+ {
+ b.HasOne("Extrudex.Domain.Entities.AmsUnit", "AmsUnit")
+ .WithMany("Slots")
+ .HasForeignKey("AmsUnitId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_ams_slots_ams_unit");
+
+ b.HasOne("Extrudex.Domain.Entities.Spool", "Spool")
+ .WithMany("AmsSlots")
+ .HasForeignKey("SpoolId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("fk_ams_slots_spool");
+
+ b.Navigation("AmsUnit");
+
+ b.Navigation("Spool");
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.AmsUnit", b =>
+ {
+ b.HasOne("Extrudex.Domain.Entities.Printer", "Printer")
+ .WithMany("AmsUnits")
+ .HasForeignKey("PrinterId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired()
+ .HasConstraintName("fk_ams_units_printer");
+
+ b.Navigation("Printer");
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.MaterialFinish", b =>
+ {
+ b.HasOne("Extrudex.Domain.Entities.MaterialBase", "MaterialBase")
+ .WithMany("Finishes")
+ .HasForeignKey("MaterialBaseId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_material_finishes_material_base");
+
+ b.Navigation("MaterialBase");
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.MaterialModifier", b =>
+ {
+ b.HasOne("Extrudex.Domain.Entities.MaterialBase", "MaterialBase")
+ .WithMany("Modifiers")
+ .HasForeignKey("MaterialBaseId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_material_modifiers_material_base");
+
+ b.Navigation("MaterialBase");
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.PrintJob", b =>
+ {
+ b.HasOne("Extrudex.Domain.Entities.Printer", "Printer")
+ .WithMany("PrintJobs")
+ .HasForeignKey("PrinterId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_print_jobs_printer");
+
+ b.HasOne("Extrudex.Domain.Entities.Spool", "Spool")
+ .WithMany("PrintJobs")
+ .HasForeignKey("SpoolId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_print_jobs_spool");
+
+ b.Navigation("Printer");
+
+ b.Navigation("Spool");
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.Spool", b =>
+ {
+ b.HasOne("Extrudex.Domain.Entities.MaterialBase", "MaterialBase")
+ .WithMany("Spools")
+ .HasForeignKey("MaterialBaseId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_spools_material_base");
+
+ b.HasOne("Extrudex.Domain.Entities.MaterialFinish", "MaterialFinish")
+ .WithMany("Spools")
+ .HasForeignKey("MaterialFinishId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_spools_material_finish");
+
+ b.HasOne("Extrudex.Domain.Entities.MaterialModifier", "MaterialModifier")
+ .WithMany("Spools")
+ .HasForeignKey("MaterialModifierId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("fk_spools_material_modifier");
+
+ b.Navigation("MaterialBase");
+
+ b.Navigation("MaterialFinish");
+
+ b.Navigation("MaterialModifier");
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.UsageLog", b =>
+ {
+ b.HasOne("Extrudex.Domain.Entities.PrintJob", "PrintJob")
+ .WithMany()
+ .HasForeignKey("PrintJobId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("fk_usage_logs_print_job");
+
+ b.HasOne("Extrudex.Domain.Entities.Printer", "Printer")
+ .WithMany()
+ .HasForeignKey("PrinterId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("fk_usage_logs_printer");
+
+ b.HasOne("Extrudex.Domain.Entities.Spool", "Spool")
+ .WithMany()
+ .HasForeignKey("SpoolId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_usage_logs_spool");
+
+ b.Navigation("PrintJob");
+
+ b.Navigation("Printer");
+
+ b.Navigation("Spool");
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.AmsUnit", b =>
+ {
+ b.Navigation("Slots");
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.MaterialBase", b =>
+ {
+ b.Navigation("Finishes");
+
+ b.Navigation("Modifiers");
+
+ b.Navigation("Spools");
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.MaterialFinish", b =>
+ {
+ b.Navigation("Spools");
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.MaterialModifier", b =>
+ {
+ b.Navigation("Spools");
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.Printer", b =>
+ {
+ b.Navigation("AmsUnits");
+
+ b.Navigation("PrintJobs");
+ });
+
+ modelBuilder.Entity("Extrudex.Domain.Entities.Spool", b =>
+ {
+ b.Navigation("AmsSlots");
+
+ b.Navigation("PrintJobs");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/backend/Infrastructure/Data/Migrations/20260426184329_AddUsageLogTable.cs b/backend/Infrastructure/Data/Migrations/20260426184329_AddUsageLogTable.cs
new file mode 100644
index 0000000..483a8a6
--- /dev/null
+++ b/backend/Infrastructure/Data/Migrations/20260426184329_AddUsageLogTable.cs
@@ -0,0 +1,534 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Extrudex.Infrastructure.Data.Migrations
+{
+ ///
+ public partial class AddUsageLogTable : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "usage_logs",
+ columns: table => new
+ {
+ id = table.Column(type: "uuid", nullable: false),
+ spool_id = table.Column(type: "uuid", nullable: false),
+ printer_id = table.Column(type: "uuid", nullable: true),
+ print_job_id = table.Column(type: "uuid", nullable: true),
+ grams_used = table.Column(type: "numeric(10,2)", precision: 10, scale: 2, nullable: false),
+ mm_extruded = table.Column(type: "numeric(12,2)", precision: 12, scale: 2, nullable: true),
+ usage_timestamp = table.Column(type: "timestamp with time zone", nullable: false),
+ data_source = table.Column(type: "character varying(50)", maxLength: 50, nullable: false),
+ notes = table.Column(type: "character varying(2000)", maxLength: 2000, nullable: true),
+ created_at = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "now() at time zone 'utc'"),
+ updated_at = table.Column(type: "timestamp with time zone", nullable: false, defaultValueSql: "now() at time zone 'utc'")
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_usage_logs", x => x.id);
+ table.ForeignKey(
+ name: "fk_usage_logs_print_job",
+ column: x => x.print_job_id,
+ principalTable: "print_jobs",
+ principalColumn: "id",
+ onDelete: ReferentialAction.SetNull);
+ table.ForeignKey(
+ name: "fk_usage_logs_printer",
+ column: x => x.printer_id,
+ principalTable: "printers",
+ principalColumn: "id",
+ onDelete: ReferentialAction.SetNull);
+ table.ForeignKey(
+ name: "fk_usage_logs_spool",
+ column: x => x.spool_id,
+ principalTable: "spools",
+ principalColumn: "id",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.UpdateData(
+ table: "material_bases",
+ keyColumn: "id",
+ keyValue: new Guid("10000000-0000-0000-0000-000000000001"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(6535), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(6535) });
+
+ migrationBuilder.UpdateData(
+ table: "material_bases",
+ keyColumn: "id",
+ keyValue: new Guid("10000000-0000-0000-0000-000000000002"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7016), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7016) });
+
+ migrationBuilder.UpdateData(
+ table: "material_bases",
+ keyColumn: "id",
+ keyValue: new Guid("10000000-0000-0000-0000-000000000003"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7027), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7028) });
+
+ migrationBuilder.UpdateData(
+ table: "material_bases",
+ keyColumn: "id",
+ keyValue: new Guid("10000000-0000-0000-0000-000000000004"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7034), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7035) });
+
+ migrationBuilder.UpdateData(
+ table: "material_bases",
+ keyColumn: "id",
+ keyValue: new Guid("10000000-0000-0000-0000-000000000005"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7042), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7042) });
+
+ migrationBuilder.UpdateData(
+ table: "material_bases",
+ keyColumn: "id",
+ keyValue: new Guid("10000000-0000-0000-0000-000000000006"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7049), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7049) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000001"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7291), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7292) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000002"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7453), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7453) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000003"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7461), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7461) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000004"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7468), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7468) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000005"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7474), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7474) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000006"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7480), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7481) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000007"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7487), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7487) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000008"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7493), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7493) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000009"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7500), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7500) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000010"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7507), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7507) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000011"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7513), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7513) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000012"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7519), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7520) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000013"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7526), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7526) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000014"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7532), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7532) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000015"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7538), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7539) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000001"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7690), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7690) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000002"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7838), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7838) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000003"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7846), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7846) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000004"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7853), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7853) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000005"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7859), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7859) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000006"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7865), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7866) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000007"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7872), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7872) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000008"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7878), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7879) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000009"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7885), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7885) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000010"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7891), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7891) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000011"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7898), new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7898) });
+
+ migrationBuilder.CreateIndex(
+ name: "ix_usage_logs_data_source",
+ table: "usage_logs",
+ column: "data_source");
+
+ migrationBuilder.CreateIndex(
+ name: "ix_usage_logs_print_job_id",
+ table: "usage_logs",
+ column: "print_job_id");
+
+ migrationBuilder.CreateIndex(
+ name: "ix_usage_logs_printer_id",
+ table: "usage_logs",
+ column: "printer_id");
+
+ migrationBuilder.CreateIndex(
+ name: "ix_usage_logs_spool_id",
+ table: "usage_logs",
+ column: "spool_id");
+
+ migrationBuilder.CreateIndex(
+ name: "ix_usage_logs_usage_timestamp",
+ table: "usage_logs",
+ column: "usage_timestamp");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "usage_logs");
+
+ migrationBuilder.UpdateData(
+ table: "material_bases",
+ keyColumn: "id",
+ keyValue: new Guid("10000000-0000-0000-0000-000000000001"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1096), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1096) });
+
+ migrationBuilder.UpdateData(
+ table: "material_bases",
+ keyColumn: "id",
+ keyValue: new Guid("10000000-0000-0000-0000-000000000002"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1620), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1620) });
+
+ migrationBuilder.UpdateData(
+ table: "material_bases",
+ keyColumn: "id",
+ keyValue: new Guid("10000000-0000-0000-0000-000000000003"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1630), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1630) });
+
+ migrationBuilder.UpdateData(
+ table: "material_bases",
+ keyColumn: "id",
+ keyValue: new Guid("10000000-0000-0000-0000-000000000004"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1638), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1638) });
+
+ migrationBuilder.UpdateData(
+ table: "material_bases",
+ keyColumn: "id",
+ keyValue: new Guid("10000000-0000-0000-0000-000000000005"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1645), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1645) });
+
+ migrationBuilder.UpdateData(
+ table: "material_bases",
+ keyColumn: "id",
+ keyValue: new Guid("10000000-0000-0000-0000-000000000006"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1651), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1652) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000001"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1850), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(1850) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000002"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2041), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2041) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000003"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2049), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2049) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000004"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2055), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2056) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000005"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2062), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2062) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000006"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2068), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2068) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000007"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2075), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2075) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000008"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2081), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2081) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000009"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2100), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2100) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000010"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2107), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2107) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000011"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2113), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2113) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000012"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2120), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2120) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000013"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2126), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2126) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000014"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2132), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2133) });
+
+ migrationBuilder.UpdateData(
+ table: "material_finishes",
+ keyColumn: "id",
+ keyValue: new Guid("20000000-0000-0000-0000-000000000015"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2139), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2139) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000001"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2304), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2304) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000002"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2463), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2463) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000003"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2471), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2471) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000004"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2477), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2478) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000005"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2484), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2484) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000006"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2490), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2491) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000007"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2497), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2497) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000008"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2503), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2503) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000009"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2510), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2510) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000010"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2516), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2516) });
+
+ migrationBuilder.UpdateData(
+ table: "material_modifiers",
+ keyColumn: "id",
+ keyValue: new Guid("30000000-0000-0000-0000-000000000011"),
+ columns: new[] { "created_at", "updated_at" },
+ values: new object[] { new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2522), new DateTime(2026, 4, 26, 13, 14, 18, 745, DateTimeKind.Utc).AddTicks(2523) });
+ }
+ }
+}
diff --git a/backend/Infrastructure/Data/Migrations/ExtrudexDbContextModelSnapshot.cs b/backend/Infrastructure/Data/Migrations/ExtrudexDbContextModelSnapshot.cs
index f214506..e20d707 100644
--- a/backend/Infrastructure/Data/Migrations/ExtrudexDbContextModelSnapshot.cs
+++ b/backend/Infrastructure/Data/Migrations/ExtrudexDbContextModelSnapshot.cs
@@ -104,77 +104,6 @@ namespace Extrudex.Infrastructure.Data.Migrations
b.ToTable("ams_units", (string)null);
});
- modelBuilder.Entity("Extrudex.Domain.Entities.FilamentUsage", b =>
- {
- b.Property("Id")
- .HasColumnType("uuid")
- .HasColumnName("id");
-
- b.Property("CreatedAt")
- .ValueGeneratedOnAdd()
- .HasColumnType("timestamp with time zone")
- .HasColumnName("created_at")
- .HasDefaultValueSql("now() at time zone 'utc'");
-
- b.Property("GramsUsed")
- .HasPrecision(10, 2)
- .HasColumnType("numeric(10,2)")
- .HasColumnName("grams_used");
-
- b.Property("MmExtruded")
- .HasPrecision(12, 2)
- .HasColumnType("numeric(12,2)")
- .HasColumnName("mm_extruded");
-
- b.Property("Notes")
- .HasMaxLength(2000)
- .HasColumnType("character varying(2000)")
- .HasColumnName("notes");
-
- b.Property("PrintJobId")
- .HasColumnType("uuid")
- .HasColumnName("print_job_id");
-
- b.Property("PrinterId")
- .HasColumnType("uuid")
- .HasColumnName("printer_id");
-
- b.Property("RecordedAt")
- .ValueGeneratedOnAdd()
- .HasColumnType("timestamp with time zone")
- .HasColumnName("recorded_at")
- .HasDefaultValueSql("now() at time zone 'utc'");
-
- b.Property("SpoolId")
- .HasColumnType("uuid")
- .HasColumnName("spool_id");
-
- b.Property("UpdatedAt")
- .ValueGeneratedOnAdd()
- .HasColumnType("timestamp with time zone")
- .HasColumnName("updated_at")
- .HasDefaultValueSql("now() at time zone 'utc'");
-
- b.HasKey("Id");
-
- b.HasIndex("PrintJobId")
- .HasDatabaseName("ix_filament_usages_print_job_id");
-
- b.HasIndex("PrinterId")
- .HasDatabaseName("ix_filament_usages_printer_id");
-
- b.HasIndex("RecordedAt")
- .HasDatabaseName("ix_filament_usages_recorded_at");
-
- b.HasIndex("SpoolId")
- .HasDatabaseName("ix_filament_usages_spool_id");
-
- b.HasIndex("SpoolId", "RecordedAt")
- .HasDatabaseName("ix_filament_usages_spool_id_recorded_at");
-
- b.ToTable("filament_usages", (string)null);
- });
-
modelBuilder.Entity("Extrudex.Domain.Entities.MaterialBase", b =>
{
b.Property("Id")
@@ -216,50 +145,50 @@ namespace Extrudex.Infrastructure.Data.Migrations
new
{
Id = new Guid("10000000-0000-0000-0000-000000000001"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 291, DateTimeKind.Utc).AddTicks(9388),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(6535),
DensityGperCm3 = 1.24m,
Name = "PLA",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 291, DateTimeKind.Utc).AddTicks(9388)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(6535)
},
new
{
Id = new Guid("10000000-0000-0000-0000-000000000002"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 291, DateTimeKind.Utc).AddTicks(9871),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7016),
DensityGperCm3 = 1.27m,
Name = "PETG",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 291, DateTimeKind.Utc).AddTicks(9871)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7016)
},
new
{
Id = new Guid("10000000-0000-0000-0000-000000000003"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 291, DateTimeKind.Utc).AddTicks(9881),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7027),
DensityGperCm3 = 1.04m,
Name = "ABS",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 291, DateTimeKind.Utc).AddTicks(9881)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7028)
},
new
{
Id = new Guid("10000000-0000-0000-0000-000000000004"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 291, DateTimeKind.Utc).AddTicks(9888),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7034),
DensityGperCm3 = 1.07m,
Name = "ASA",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 291, DateTimeKind.Utc).AddTicks(9888)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7035)
},
new
{
Id = new Guid("10000000-0000-0000-0000-000000000005"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 291, DateTimeKind.Utc).AddTicks(9895),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7042),
DensityGperCm3 = 1.21m,
Name = "TPU",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 291, DateTimeKind.Utc).AddTicks(9895)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7042)
},
new
{
Id = new Guid("10000000-0000-0000-0000-000000000006"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 291, DateTimeKind.Utc).AddTicks(9901),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7049),
DensityGperCm3 = 1.14m,
Name = "Nylon",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 291, DateTimeKind.Utc).AddTicks(9902)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7049)
});
});
@@ -303,122 +232,122 @@ namespace Extrudex.Infrastructure.Data.Migrations
new
{
Id = new Guid("20000000-0000-0000-0000-000000000001"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(90),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7291),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
Name = "Basic",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(90)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7292)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000002"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(251),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7453),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
Name = "Matte",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(251)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7453)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000003"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(259),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7461),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
Name = "Silk",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(259)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7461)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000004"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(266),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7468),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
Name = "Glitter",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(266)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7468)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000005"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(272),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7474),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
Name = "Marble",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(272)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7474)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000006"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(278),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7480),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
Name = "Sparkle",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(278)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7481)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000007"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(285),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7487),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000002"),
Name = "Basic",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(285)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7487)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000008"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(291),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7493),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000002"),
Name = "Matte",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(291)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7493)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000009"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(297),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7500),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000002"),
Name = "Silk",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(298)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7500)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000010"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(304),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7507),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000003"),
Name = "Basic",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(304)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7507)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000011"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(310),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7513),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000003"),
Name = "Matte",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(310)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7513)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000012"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(316),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7519),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000004"),
Name = "Basic",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(317)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7520)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000013"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(323),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7526),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000004"),
Name = "Matte",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(323)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7526)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000014"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(329),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7532),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000005"),
Name = "Basic",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(329)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7532)
},
new
{
Id = new Guid("20000000-0000-0000-0000-000000000015"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(336),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7538),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000006"),
Name = "Basic",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(336)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7539)
});
});
@@ -462,90 +391,90 @@ namespace Extrudex.Infrastructure.Data.Migrations
new
{
Id = new Guid("30000000-0000-0000-0000-000000000001"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(482),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7690),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
Name = "Carbon Fiber",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(482)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7690)
},
new
{
Id = new Guid("30000000-0000-0000-0000-000000000002"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(805),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7838),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
Name = "Glass Fiber",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(806)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7838)
},
new
{
Id = new Guid("30000000-0000-0000-0000-000000000003"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(815),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7846),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
Name = "Wood Fill",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(815)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7846)
},
new
{
Id = new Guid("30000000-0000-0000-0000-000000000004"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(821),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7853),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000001"),
Name = "Glow-in-the-Dark",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(821)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7853)
},
new
{
Id = new Guid("30000000-0000-0000-0000-000000000005"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(828),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7859),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000002"),
Name = "Carbon Fiber",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(828)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7859)
},
new
{
Id = new Guid("30000000-0000-0000-0000-000000000006"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(834),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7865),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000002"),
Name = "Glass Fiber",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(834)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7866)
},
new
{
Id = new Guid("30000000-0000-0000-0000-000000000007"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(840),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7872),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000003"),
Name = "Carbon Fiber",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(840)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7872)
},
new
{
Id = new Guid("30000000-0000-0000-0000-000000000008"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(847),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7878),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000003"),
Name = "Glass Fiber",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(847)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7879)
},
new
{
Id = new Guid("30000000-0000-0000-0000-000000000009"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(853),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7885),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000004"),
Name = "Carbon Fiber",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(853)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7885)
},
new
{
Id = new Guid("30000000-0000-0000-0000-000000000010"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(859),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7891),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000006"),
Name = "Carbon Fiber",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(860)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7891)
},
new
{
Id = new Guid("30000000-0000-0000-0000-000000000011"),
- CreatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(866),
+ CreatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7898),
MaterialBaseId = new Guid("10000000-0000-0000-0000-000000000006"),
Name = "Glass Fiber",
- UpdatedAt = new DateTime(2026, 4, 26, 18, 34, 33, 292, DateTimeKind.Utc).AddTicks(866)
+ UpdatedAt = new DateTime(2026, 4, 26, 18, 43, 28, 895, DateTimeKind.Utc).AddTicks(7898)
});
});
@@ -877,6 +806,81 @@ namespace Extrudex.Infrastructure.Data.Migrations
b.ToTable("spools", (string)null);
});
+ modelBuilder.Entity("Extrudex.Domain.Entities.UsageLog", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("uuid")
+ .HasColumnName("id");
+
+ b.Property("CreatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("created_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.Property("DataSource")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("character varying(50)")
+ .HasColumnName("data_source");
+
+ b.Property("GramsUsed")
+ .HasPrecision(10, 2)
+ .HasColumnType("numeric(10,2)")
+ .HasColumnName("grams_used");
+
+ b.Property("MmExtruded")
+ .HasPrecision(12, 2)
+ .HasColumnType("numeric(12,2)")
+ .HasColumnName("mm_extruded");
+
+ b.Property("Notes")
+ .HasMaxLength(2000)
+ .HasColumnType("character varying(2000)")
+ .HasColumnName("notes");
+
+ b.Property("PrintJobId")
+ .HasColumnType("uuid")
+ .HasColumnName("print_job_id");
+
+ b.Property("PrinterId")
+ .HasColumnType("uuid")
+ .HasColumnName("printer_id");
+
+ b.Property("SpoolId")
+ .HasColumnType("uuid")
+ .HasColumnName("spool_id");
+
+ b.Property("UpdatedAt")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("updated_at")
+ .HasDefaultValueSql("now() at time zone 'utc'");
+
+ b.Property("UsageTimestamp")
+ .HasColumnType("timestamp with time zone")
+ .HasColumnName("usage_timestamp");
+
+ b.HasKey("Id");
+
+ b.HasIndex("DataSource")
+ .HasDatabaseName("ix_usage_logs_data_source");
+
+ b.HasIndex("PrintJobId")
+ .HasDatabaseName("ix_usage_logs_print_job_id");
+
+ b.HasIndex("PrinterId")
+ .HasDatabaseName("ix_usage_logs_printer_id");
+
+ b.HasIndex("SpoolId")
+ .HasDatabaseName("ix_usage_logs_spool_id");
+
+ b.HasIndex("UsageTimestamp")
+ .HasDatabaseName("ix_usage_logs_usage_timestamp");
+
+ b.ToTable("usage_logs", (string)null);
+ });
+
modelBuilder.Entity("Extrudex.Domain.Entities.AmsSlot", b =>
{
b.HasOne("Extrudex.Domain.Entities.AmsUnit", "AmsUnit")
@@ -909,36 +913,6 @@ namespace Extrudex.Infrastructure.Data.Migrations
b.Navigation("Printer");
});
- modelBuilder.Entity("Extrudex.Domain.Entities.FilamentUsage", b =>
- {
- b.HasOne("Extrudex.Domain.Entities.PrintJob", "PrintJob")
- .WithMany("FilamentUsages")
- .HasForeignKey("PrintJobId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired()
- .HasConstraintName("fk_filament_usages_print_job");
-
- b.HasOne("Extrudex.Domain.Entities.Printer", "Printer")
- .WithMany("FilamentUsages")
- .HasForeignKey("PrinterId")
- .OnDelete(DeleteBehavior.Restrict)
- .IsRequired()
- .HasConstraintName("fk_filament_usages_printer");
-
- b.HasOne("Extrudex.Domain.Entities.Spool", "Spool")
- .WithMany("FilamentUsages")
- .HasForeignKey("SpoolId")
- .OnDelete(DeleteBehavior.Restrict)
- .IsRequired()
- .HasConstraintName("fk_filament_usages_spool");
-
- b.Navigation("PrintJob");
-
- b.Navigation("Printer");
-
- b.Navigation("Spool");
- });
-
modelBuilder.Entity("Extrudex.Domain.Entities.MaterialFinish", b =>
{
b.HasOne("Extrudex.Domain.Entities.MaterialBase", "MaterialBase")
@@ -1013,6 +987,34 @@ namespace Extrudex.Infrastructure.Data.Migrations
b.Navigation("MaterialModifier");
});
+ modelBuilder.Entity("Extrudex.Domain.Entities.UsageLog", b =>
+ {
+ b.HasOne("Extrudex.Domain.Entities.PrintJob", "PrintJob")
+ .WithMany()
+ .HasForeignKey("PrintJobId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("fk_usage_logs_print_job");
+
+ b.HasOne("Extrudex.Domain.Entities.Printer", "Printer")
+ .WithMany()
+ .HasForeignKey("PrinterId")
+ .OnDelete(DeleteBehavior.SetNull)
+ .HasConstraintName("fk_usage_logs_printer");
+
+ b.HasOne("Extrudex.Domain.Entities.Spool", "Spool")
+ .WithMany()
+ .HasForeignKey("SpoolId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired()
+ .HasConstraintName("fk_usage_logs_spool");
+
+ b.Navigation("PrintJob");
+
+ b.Navigation("Printer");
+
+ b.Navigation("Spool");
+ });
+
modelBuilder.Entity("Extrudex.Domain.Entities.AmsUnit", b =>
{
b.Navigation("Slots");
@@ -1037,17 +1039,10 @@ namespace Extrudex.Infrastructure.Data.Migrations
b.Navigation("Spools");
});
- modelBuilder.Entity("Extrudex.Domain.Entities.PrintJob", b =>
- {
- b.Navigation("FilamentUsages");
- });
-
modelBuilder.Entity("Extrudex.Domain.Entities.Printer", b =>
{
b.Navigation("AmsUnits");
- b.Navigation("FilamentUsages");
-
b.Navigation("PrintJobs");
});
@@ -1055,8 +1050,6 @@ namespace Extrudex.Infrastructure.Data.Migrations
{
b.Navigation("AmsSlots");
- b.Navigation("FilamentUsages");
-
b.Navigation("PrintJobs");
});
#pragma warning restore 612, 618
diff --git a/backend/Infrastructure/Services/UsageLogService.cs b/backend/Infrastructure/Services/UsageLogService.cs
new file mode 100644
index 0000000..4629b65
--- /dev/null
+++ b/backend/Infrastructure/Services/UsageLogService.cs
@@ -0,0 +1,81 @@
+using Extrudex.Domain.Entities;
+using Extrudex.Domain.Enums;
+using Extrudex.Domain.Interfaces;
+using Extrudex.Infrastructure.Data;
+using Microsoft.EntityFrameworkCore;
+
+namespace Extrudex.Infrastructure.Services;
+
+///
+/// Implementation of that persists usage entries
+/// to the usage_logs table via EF Core.
+///
+public class UsageLogService : IUsageLogService
+{
+ private readonly ExtrudexDbContext _dbContext;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The EF Core database context for data persistence.
+ public UsageLogService(ExtrudexDbContext dbContext)
+ {
+ _dbContext = dbContext;
+ }
+
+ ///
+ public async Task RecordUsageAsync(
+ Guid spoolId,
+ decimal gramsUsed,
+ DataSource dataSource,
+ Guid? printerId = null,
+ Guid? printJobId = null,
+ decimal? mmExtruded = null,
+ DateTime? usageTimestamp = null,
+ string? notes = null)
+ {
+ var entry = new UsageLog
+ {
+ SpoolId = spoolId,
+ GramsUsed = gramsUsed,
+ DataSource = dataSource,
+ PrinterId = printerId,
+ PrintJobId = printJobId,
+ MmExtruded = mmExtruded,
+ UsageTimestamp = usageTimestamp ?? DateTime.UtcNow,
+ Notes = notes
+ };
+
+ _dbContext.UsageLogs.Add(entry);
+ await _dbContext.SaveChangesAsync();
+
+ return entry;
+ }
+
+ ///
+ public async Task> GetBySpoolAsync(Guid spoolId, CancellationToken cancellationToken = default)
+ {
+ return await _dbContext.UsageLogs
+ .Where(u => u.SpoolId == spoolId)
+ .OrderByDescending(u => u.UsageTimestamp)
+ .ToListAsync(cancellationToken);
+ }
+
+ ///
+ public async Task> GetByPrinterAsync(Guid printerId, CancellationToken cancellationToken = default)
+ {
+ return await _dbContext.UsageLogs
+ .Where(u => u.PrinterId == printerId)
+ .OrderByDescending(u => u.UsageTimestamp)
+ .ToListAsync(cancellationToken);
+ }
+
+ ///
+ public async Task> GetByPrintJobAsync(Guid printJobId, CancellationToken cancellationToken = default)
+ {
+ return await _dbContext.UsageLogs
+ .Where(u => u.PrintJobId == printJobId)
+ .OrderByDescending(u => u.UsageTimestamp)
+ .ToListAsync(cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/backend/Program.cs b/backend/Program.cs
index ad24693..d664d0c 100644
--- a/backend/Program.cs
+++ b/backend/Program.cs
@@ -58,6 +58,9 @@ builder.Services.AddScoped();
// ── Low Stock Detection ────────────────────────────────────
builder.Services.AddSingleton();
+// ── Usage Logging ───────────────────────────────────────────
+builder.Services.AddScoped();
+
// ── FluentValidation ──────────────────────────────────────
// Registers all validators from the API assembly into DI.
builder.Services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());