CREATE TABLE IF NOT EXISTS material_consumption_snapshots ( timestamp timestamptz NOT NULL, calculation_id text NOT NULL, machine_id text NOT NULL, production_order text NOT NULL, run_id text NOT NULL, consumption_kg double precision NOT NULL, PRIMARY KEY (calculation_id, machine_id, production_order, timestamp) ); -- Machine time series across orders; the primary key covers a specific order. CREATE INDEX IF NOT EXISTS material_consumption_snapshots_machine_time_idx ON material_consumption_snapshots (calculation_id, machine_id, timestamp); -- Channel identities are intentionally independent of material assignment. CREATE TABLE IF NOT EXISTS channel_material_consumption_snapshots ( timestamp timestamptz NOT NULL, calculation_id text NOT NULL, machine_id text NOT NULL, extruder text NOT NULL, doser_channel text NOT NULL, production_order text NOT NULL, run_id text NOT NULL, cumulative_consumption_kg double precision NOT NULL, material_number text NULL, material_name text NULL, material_mapping_status text NOT NULL CHECK (material_mapping_status IN ('ASSIGNED', 'UNAVAILABLE', 'AMBIGUOUS', 'UNMAPPED')), percentage_sum_valid boolean NOT NULL, PRIMARY KEY (calculation_id, machine_id, extruder, doser_channel, production_order, timestamp) ); CREATE TABLE IF NOT EXISTS material_efficiency_snapshots ( erp_feedback_timestamp timestamptz NOT NULL, material_snapshot_timestamp timestamptz NOT NULL, calculation_id text NOT NULL, machine_id text NOT NULL, workplace text NOT NULL, erp_production_order text NOT NULL, enlyze_production_order text NOT NULL, article_number text NULL, article_description text NULL, nominal_width_m double precision NULL, good_quantity_m2 double precision NOT NULL, material_consumption_kg double precision NOT NULL, material_consumption_kg_per_m2 double precision NOT NULL, material_consumption_g_per_m2 double precision NOT NULL, PRIMARY KEY (calculation_id, machine_id, enlyze_production_order, erp_feedback_timestamp) ); CREATE INDEX IF NOT EXISTS material_efficiency_snapshots_machine_time_idx ON material_efficiency_snapshots (calculation_id, machine_id, erp_feedback_timestamp); -- Instantaneous process measurements; no ERP good-area denominator. CREATE TABLE IF NOT EXISTS material_application_snapshots ( timestamp timestamptz NOT NULL, calculation_id text NOT NULL, machine_id text NOT NULL, production_order text NOT NULL, run_id text NOT NULL, application_g_m2 double precision NOT NULL, PRIMARY KEY (calculation_id, machine_id, production_order, timestamp) ); CREATE INDEX IF NOT EXISTS material_application_snapshots_machine_time_idx ON material_application_snapshots (calculation_id, machine_id, timestamp); CREATE TABLE IF NOT EXISTS power_meter_readings ( meter text NOT NULL, timestamp timestamptz NOT NULL, energy_total_kwh double precision NOT NULL, energy_delta_kwh double precision NOT NULL, active_power_total_kw double precision NOT NULL, grid_frequency_hz double precision NOT NULL, power_outages double precision NULL, outage_delta double precision NULL, phase_active_power_kw jsonb NOT NULL DEFAULT '{}'::jsonb, PRIMARY KEY (meter, timestamp) ); CREATE INDEX IF NOT EXISTS power_meter_readings_time_idx ON power_meter_readings (meter, timestamp DESC); CREATE TABLE IF NOT EXISTS power_meter_monthly_reports ( meter text NOT NULL, month text NOT NULL, report_path text NOT NULL, summary jsonb NOT NULL, generated_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (meter, month) ); -- Mutable ENLYZE downtime source records. external_id is the stable ENLYZE UUID. CREATE TABLE IF NOT EXISTS production_downtime_events ( external_id text PRIMARY KEY, machine_id text NOT NULL, production_order text NULL, source_type text NOT NULL, source_start timestamptz NOT NULL, source_end timestamptz NULL, attributed_start timestamptz NULL, attributed_end timestamptz NULL, attributed_duration_seconds double precision NULL, reason_id text NULL, reason_name text NULL, reason_description text NULL, reason_group text NULL, category text NOT NULL CHECK (category IN ('PLANNED', 'UNPLANNED', 'UNKNOWN')), comment text NULL, source_updated_at timestamptz NULL, last_reconciled_at timestamptz NOT NULL ); CREATE INDEX IF NOT EXISTS production_downtime_events_machine_attributed_time_idx ON production_downtime_events (machine_id, attributed_start); CREATE INDEX IF NOT EXISTS production_downtime_events_production_order_idx ON production_downtime_events (production_order); CREATE INDEX IF NOT EXISTS production_downtime_events_category_idx ON production_downtime_events (category); CREATE INDEX IF NOT EXISTS production_downtime_events_unresolved_idx ON production_downtime_events (machine_id, source_start) WHERE source_end IS NULL OR category = 'UNKNOWN'; -- One observed ERP order boundary per machine, used to clip open ENLYZE downtimes. CREATE TABLE IF NOT EXISTS production_order_attribution_state ( machine_id text PRIMARY KEY, production_order text NOT NULL, started_at timestamptz NOT NULL, ended_at timestamptz NULL );