diff --git a/OpenNest.Data/Defaults/CL-980.json b/OpenNest.Data/Defaults/CL-980.json deleted file mode 100644 index 6343ff4b..00000000 --- a/OpenNest.Data/Defaults/CL-980.json +++ /dev/null @@ -1,174 +0,0 @@ -{ - "id": "00000000-0000-0000-0000-000000980001", - "schemaVersion": 1, - "name": "CL-980", - "type": "laser", - "units": "inches", - "materials": [ - { - "name": "Mild Steel", - "grade": "A36", - "density": 0.2836, - "thicknesses": [ - { - "value": 0.060, - "kerf": 0.008, - "assistGas": "O2", - "leadIn": { "type": "Arc", "length": 0.125, "angle": 90.0, "radius": 0.0625 }, - "leadOut": { "type": "Line", "length": 0.0625, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.125, "minSegmentLength": 0.5, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x120", "60x120" ] - }, - { - "value": 0.075, - "kerf": 0.008, - "assistGas": "O2", - "leadIn": { "type": "Arc", "length": 0.125, "angle": 90.0, "radius": 0.0625 }, - "leadOut": { "type": "Line", "length": 0.0625, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.125, "minSegmentLength": 0.5, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x120", "60x120" ] - }, - { - "value": 0.105, - "kerf": 0.010, - "assistGas": "O2", - "leadIn": { "type": "Arc", "length": 0.1875, "angle": 90.0, "radius": 0.09375 }, - "leadOut": { "type": "Line", "length": 0.09375, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.1875, "minSegmentLength": 0.75, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x120", "60x120" ] - }, - { - "value": 0.135, - "kerf": 0.010, - "assistGas": "O2", - "leadIn": { "type": "Arc", "length": 0.1875, "angle": 90.0, "radius": 0.09375 }, - "leadOut": { "type": "Line", "length": 0.09375, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.1875, "minSegmentLength": 0.75, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x120", "60x120", "60x144" ] - }, - { - "value": 0.1875, - "kerf": 0.012, - "assistGas": "O2", - "leadIn": { "type": "Arc", "length": 0.25, "angle": 90.0, "radius": 0.125 }, - "leadOut": { "type": "Line", "length": 0.125, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.25, "minSegmentLength": 1.0, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x120", "60x120", "60x144" ] - }, - { - "value": 0.250, - "kerf": 0.012, - "assistGas": "O2", - "leadIn": { "type": "Arc", "length": 0.25, "angle": 90.0, "radius": 0.125 }, - "leadOut": { "type": "Line", "length": 0.125, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.25, "minSegmentLength": 1.0, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x120", "60x120", "60x144" ] - }, - { - "value": 0.375, - "kerf": 0.016, - "assistGas": "O2", - "leadIn": { "type": "Arc", "length": 0.375, "angle": 90.0, "radius": 0.1875 }, - "leadOut": { "type": "Line", "length": 0.1875, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.3125, "minSegmentLength": 1.25, "direction": "AwayFromOrigin" }, - "plateSizes": [ "60x120", "60x144", "72x120" ] - }, - { - "value": 0.500, - "kerf": 0.020, - "assistGas": "O2", - "leadIn": { "type": "Arc", "length": 0.5, "angle": 90.0, "radius": 0.25 }, - "leadOut": { "type": "Line", "length": 0.25, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.375, "minSegmentLength": 1.5, "direction": "AwayFromOrigin" }, - "plateSizes": [ "60x120", "60x144", "72x120" ] - } - ] - }, - { - "name": "Stainless Steel", - "grade": "304", - "density": 0.289, - "thicknesses": [ - { - "value": 0.060, - "kerf": 0.008, - "assistGas": "N2", - "leadIn": { "type": "Arc", "length": 0.125, "angle": 90.0, "radius": 0.0625 }, - "leadOut": { "type": "Line", "length": 0.0625, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.125, "minSegmentLength": 0.5, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x96", "48x120", "60x120" ] - }, - { - "value": 0.075, - "kerf": 0.008, - "assistGas": "N2", - "leadIn": { "type": "Arc", "length": 0.125, "angle": 90.0, "radius": 0.0625 }, - "leadOut": { "type": "Line", "length": 0.0625, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.125, "minSegmentLength": 0.5, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x96", "48x120", "60x120" ] - }, - { - "value": 0.105, - "kerf": 0.010, - "assistGas": "N2", - "leadIn": { "type": "Arc", "length": 0.1875, "angle": 90.0, "radius": 0.09375 }, - "leadOut": { "type": "Line", "length": 0.09375, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.1875, "minSegmentLength": 0.75, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x96", "48x120", "60x120" ] - }, - { - "value": 0.250, - "kerf": 0.014, - "assistGas": "N2", - "leadIn": { "type": "Arc", "length": 0.25, "angle": 90.0, "radius": 0.125 }, - "leadOut": { "type": "Line", "length": 0.125, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.25, "minSegmentLength": 1.0, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x96", "48x120", "60x120" ] - } - ] - }, - { - "name": "Aluminum", - "grade": "5052", - "density": 0.097, - "thicknesses": [ - { - "value": 0.060, - "kerf": 0.008, - "assistGas": "N2", - "leadIn": { "type": "Arc", "length": 0.125, "angle": 90.0, "radius": 0.0625 }, - "leadOut": { "type": "Line", "length": 0.0625, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.125, "minSegmentLength": 0.5, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x96", "48x120", "60x120" ] - }, - { - "value": 0.080, - "kerf": 0.008, - "assistGas": "N2", - "leadIn": { "type": "Arc", "length": 0.125, "angle": 90.0, "radius": 0.0625 }, - "leadOut": { "type": "Line", "length": 0.0625, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.125, "minSegmentLength": 0.5, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x96", "48x120", "60x120" ] - }, - { - "value": 0.125, - "kerf": 0.010, - "assistGas": "N2", - "leadIn": { "type": "Arc", "length": 0.1875, "angle": 90.0, "radius": 0.09375 }, - "leadOut": { "type": "Line", "length": 0.09375, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.1875, "minSegmentLength": 0.75, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x96", "48x120", "60x120" ] - }, - { - "value": 0.250, - "kerf": 0.014, - "assistGas": "N2", - "leadIn": { "type": "Arc", "length": 0.25, "angle": 90.0, "radius": 0.125 }, - "leadOut": { "type": "Line", "length": 0.125, "angle": 90.0, "radius": 0.0 }, - "cutOff": { "partClearance": 0.02, "overtravel": 0.25, "minSegmentLength": 1.0, "direction": "AwayFromOrigin" }, - "plateSizes": [ "48x96", "48x120", "60x120" ] - } - ] - } - ] -} diff --git a/OpenNest.Data/Defaults/Generic-Laser.json b/OpenNest.Data/Defaults/Generic-Laser.json new file mode 100644 index 00000000..4adbe1a9 --- /dev/null +++ b/OpenNest.Data/Defaults/Generic-Laser.json @@ -0,0 +1,52 @@ +{ + "id": "76974005-5de9-4de6-8ef0-4e4fa1ac6e98", + "schemaVersion": 1, + "name": "Generic Laser", + "type": "laser", + "units": "inches", + "materials": [ + { + "name": "Mild Steel", + "grade": "A36", + "density": 0.2836, + "thicknesses": [ + {"value": 0.06, "name": "16 ga", "kerf": 0.006, "assistGas": "O2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.0625}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.125, "minSegmentLength": 0.5, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.075, "name": "14 ga", "kerf": 0.006, "assistGas": "O2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.0625}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.125, "minSegmentLength": 0.5, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.105, "name": "12 ga", "kerf": 0.008, "assistGas": "O2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.09375}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.1875, "minSegmentLength": 0.75, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.12, "name": "11 ga", "kerf": 0.008, "assistGas": "O2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.09375}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.1875, "minSegmentLength": 0.75, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.135, "name": "10 ga", "kerf": 0.008, "assistGas": "O2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.09375}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.1875, "minSegmentLength": 0.75, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.1875, "name": "3/16", "kerf": 0.01, "assistGas": "O2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.125}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.25, "minSegmentLength": 1.0, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120", "60x144"]}, + {"value": 0.25, "name": "1/4", "kerf": 0.01, "assistGas": "O2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.125}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.25, "minSegmentLength": 1.0, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120", "60x144"]}, + {"value": 0.375, "name": "3/8", "kerf": 0.012, "assistGas": "O2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.1875}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.3125, "minSegmentLength": 1.25, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120", "60x144"]}, + {"value": 0.5, "name": "1/2", "kerf": 0.014, "assistGas": "O2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.25}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.375, "minSegmentLength": 1.5, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120", "60x144"]} + ] + }, + { + "name": "Stainless Steel", + "grade": "304", + "density": 0.289, + "thicknesses": [ + {"value": 0.06, "name": "16 ga", "kerf": 0.006, "assistGas": "N2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.0625}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.125, "minSegmentLength": 0.5, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.075, "name": "14 ga", "kerf": 0.006, "assistGas": "N2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.0625}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.125, "minSegmentLength": 0.5, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.105, "name": "12 ga", "kerf": 0.008, "assistGas": "N2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.09375}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.1875, "minSegmentLength": 0.75, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.12, "name": "11 ga", "kerf": 0.008, "assistGas": "N2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.09375}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.1875, "minSegmentLength": 0.75, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.135, "name": "10 ga", "kerf": 0.008, "assistGas": "N2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.09375}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.1875, "minSegmentLength": 0.75, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.1875, "name": "3/16", "kerf": 0.01, "assistGas": "N2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.125}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.25, "minSegmentLength": 1.0, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120", "60x144"]}, + {"value": 0.25, "name": "1/4", "kerf": 0.01, "assistGas": "N2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.125}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.25, "minSegmentLength": 1.0, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120", "60x144"]} + ] + }, + { + "name": "Aluminum", + "grade": "5052", + "density": 0.097, + "thicknesses": [ + {"value": 0.063, "name": "0.063", "kerf": 0.006, "assistGas": "N2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.0625}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.125, "minSegmentLength": 0.5, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.08, "name": "0.080", "kerf": 0.006, "assistGas": "N2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.0625}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.125, "minSegmentLength": 0.5, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.09, "name": "0.090", "kerf": 0.008, "assistGas": "N2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.09375}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.1875, "minSegmentLength": 0.75, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.125, "name": "1/8", "kerf": 0.008, "assistGas": "N2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.09375}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.1875, "minSegmentLength": 0.75, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120"]}, + {"value": 0.1875, "name": "3/16", "kerf": 0.01, "assistGas": "N2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.125}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.25, "minSegmentLength": 1.0, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120", "60x144"]}, + {"value": 0.25, "name": "1/4", "kerf": 0.01, "assistGas": "N2", "leadIn": {"type": "Arc", "length": 0.0, "angle": 90.0, "radius": 0.125}, "leadOut": {"type": "None", "length": 0.0, "angle": 90.0, "radius": 0.0}, "cutOff": {"partClearance": 0.02, "overtravel": 0.25, "minSegmentLength": 1.0, "direction": "AwayFromOrigin"}, "plateSizes": ["48x96", "48x120", "60x120", "60x144"]} + ] + } + ] +} diff --git a/OpenNest.Data/LocalJsonProvider.cs b/OpenNest.Data/LocalJsonProvider.cs index 11dac4a1..84dabf10 100644 --- a/OpenNest.Data/LocalJsonProvider.cs +++ b/OpenNest.Data/LocalJsonProvider.cs @@ -79,7 +79,7 @@ public class LocalJsonProvider : IDataProvider var assembly = typeof(LocalJsonProvider).Assembly; var resourceName = assembly .GetManifestResourceNames() - .FirstOrDefault(n => n.EndsWith("CL-980.json")); + .FirstOrDefault(n => n.EndsWith("Generic-Laser.json")); if (resourceName is null) return; diff --git a/OpenNest.Data/OpenNest.Data.csproj b/OpenNest.Data/OpenNest.Data.csproj index dcf94b0b..4d05a076 100644 --- a/OpenNest.Data/OpenNest.Data.csproj +++ b/OpenNest.Data/OpenNest.Data.csproj @@ -10,6 +10,6 @@ - + diff --git a/OpenNest.Tests/Data/DefaultConfigTests.cs b/OpenNest.Tests/Data/DefaultConfigTests.cs index 954c7b1d..7897919d 100644 --- a/OpenNest.Tests/Data/DefaultConfigTests.cs +++ b/OpenNest.Tests/Data/DefaultConfigTests.cs @@ -24,7 +24,7 @@ public class DefaultConfigTests : IDisposable provider.EnsureDefaults(); var machines = provider.GetMachines(); Assert.Single(machines); - Assert.Equal("CL-980", machines[0].Name); + Assert.Equal("Generic Laser", machines[0].Name); } [Fact] @@ -72,4 +72,39 @@ public class DefaultConfigTests : IDisposable } } } + + [Fact] + public void DefaultConfig_HasSensibleValues() + { + var provider = new LocalJsonProvider(_testDir); + provider.EnsureDefaults(); + var config = provider.GetMachine(provider.GetMachines()[0].Id); + + foreach (var material in config.Materials) + { + Assert.True(material.Density > 0); + var thicknesses = material.Thicknesses.OrderBy(t => t.Value).ToList(); + for (var i = 0; i < thicknesses.Count; i++) + { + var thickness = thicknesses[i]; + var label = $"{material.Name} {thickness.Value}"; + Assert.False(string.IsNullOrWhiteSpace(thickness.Name), label); + Assert.True(thickness.Kerf < thickness.Value / 4, label); + Assert.True(thickness.CutOff.PartClearance > thickness.Kerf, label); + Assert.True(thickness.CutOff.Overtravel > 0, label); + Assert.True(thickness.CutOff.MinSegmentLength > 0, label); + Assert.Equal("Arc", thickness.LeadIn.Type); + Assert.True(thickness.LeadIn.Radius >= thickness.Kerf * 4, label); + Assert.NotEmpty(thickness.PlateSizes); + Assert.All(thickness.PlateSizes, s => Assert.True(OpenNest.Shapes.PlateSizes.TryGet(s, out _), s)); + + if (i == 0) + continue; + var thinner = thicknesses[i - 1]; + Assert.True(thickness.Value > thinner.Value, label); + Assert.True(thickness.Kerf >= thinner.Kerf, label); + Assert.True(thickness.LeadIn.Radius >= thinner.LeadIn.Radius, label); + } + } + } } diff --git a/docs/nest-storage.md b/docs/nest-storage.md index 0eec0958..2bbc35c9 100644 --- a/docs/nest-storage.md +++ b/docs/nest-storage.md @@ -1130,7 +1130,7 @@ Listens on `ASPNETCORE_URLS` (default Kestrel ports) unless overridden. Docker must be built from the repository root: the server references `OpenNest.Data`, which references `OpenNest.Core`. The Dockerfile copies all three project files before restore and their source/resources before publish, including -Data's embedded `Defaults/CL-980.json`. The allowlist `.dockerignore` excludes +Data's embedded `Defaults/Generic-Laser.json`. The allowlist `.dockerignore` excludes other projects, host `bin`/`obj`, local databases, environment files, and launch settings. The server image uses the .NET 8 SDK to build and the .NET 8 ASP.NET runtime to run; IO/Engine are used only by the host-side smoke tool, not the image.