@juliobrim/prisma-shared 1.0.41 → 1.0.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/migrations/20260207060000_manual_fix_productivity/migration.sql +76 -0
- package/migrations/20260207070000_update_view_metrics/migration.sql +77 -0
- package/migrations/20260209000000_update_view_metrics_logic/migration.sql +109 -0
- package/migrations/20260209010000_add_productivity_interval_cache_table/migration.sql +39 -0
- package/migrations/20260209171700_add_cache_table/migration.sql +2 -0
- package/migrations/20260209173400_fix_view_downtime_column/migration.sql +110 -0
- package/migrations/20260209201231_add_missing_index_for_performance_improvement/migration.sql +80 -0
- package/migrations/20260210194351_add_ai_conversation_models/migration.sql +55 -0
- package/package.json +4 -1
- package/schema.prisma +176 -46
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
-- Manual Migration: Add Column and View
|
|
2
|
+
-- Addresses drift and implements productivity feature
|
|
3
|
+
|
|
4
|
+
-- 1. Add Column (Idempotent)
|
|
5
|
+
ALTER TABLE "public"."operation_register" ADD COLUMN IF NOT EXISTS "timeToProduceSnapshot" INTEGER;
|
|
6
|
+
|
|
7
|
+
-- 2. Create View
|
|
8
|
+
CREATE OR REPLACE VIEW "productivity_intervals" AS
|
|
9
|
+
WITH ranked_data AS (
|
|
10
|
+
SELECT
|
|
11
|
+
"id",
|
|
12
|
+
"tenantId",
|
|
13
|
+
"machineId",
|
|
14
|
+
"operatorId",
|
|
15
|
+
"operationId",
|
|
16
|
+
"startTime",
|
|
17
|
+
"endTime",
|
|
18
|
+
"quantity",
|
|
19
|
+
"timeToProduceSnapshot",
|
|
20
|
+
-- Previous Row Values for Gap Detection
|
|
21
|
+
LAG("machineId") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_machine,
|
|
22
|
+
LAG("operatorId") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_operator,
|
|
23
|
+
LAG("operationId") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_operation,
|
|
24
|
+
LAG("endTime") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_end_time
|
|
25
|
+
FROM "operation_register"
|
|
26
|
+
),
|
|
27
|
+
change_points AS (
|
|
28
|
+
SELECT
|
|
29
|
+
*,
|
|
30
|
+
CASE
|
|
31
|
+
-- Standard Grouping Triggers
|
|
32
|
+
WHEN "operatorId" IS DISTINCT FROM prev_operator THEN 1
|
|
33
|
+
WHEN "operationId" IS DISTINCT FROM prev_operation THEN 1
|
|
34
|
+
-- Time Gap Trigger (> 10 hours from previous end to current start)
|
|
35
|
+
WHEN "prev_end_time" IS NOT NULL AND ("startTime" - "prev_end_time") > INTERVAL '10 hours' THEN 1
|
|
36
|
+
ELSE 0
|
|
37
|
+
END as is_new_group
|
|
38
|
+
FROM ranked_data
|
|
39
|
+
),
|
|
40
|
+
grouped_data AS (
|
|
41
|
+
SELECT
|
|
42
|
+
*,
|
|
43
|
+
-- Generate a unique Group ID per partition (cumulative sum of flags)
|
|
44
|
+
SUM(is_new_group) OVER (PARTITION BY "machineId" ORDER BY "startTime") as group_id
|
|
45
|
+
FROM change_points
|
|
46
|
+
)
|
|
47
|
+
SELECT
|
|
48
|
+
-- Deterministic unique ID for the View
|
|
49
|
+
"machineId",
|
|
50
|
+
"group_id"::integer as "sequence_id",
|
|
51
|
+
|
|
52
|
+
-- Aggregates
|
|
53
|
+
MIN("startTime") as "group_start_timestamp",
|
|
54
|
+
MAX("endTime") as "group_end_timestamp",
|
|
55
|
+
"operatorId" as "operator_id",
|
|
56
|
+
"operationId" as "operation_id",
|
|
57
|
+
COUNT(*)::integer as "record_count",
|
|
58
|
+
SUM("quantity")::integer as "total_quantity",
|
|
59
|
+
|
|
60
|
+
-- Efficiency Calculation
|
|
61
|
+
CASE
|
|
62
|
+
WHEN EXTRACT(EPOCH FROM (MAX("endTime") - MIN("startTime"))) = 0 THEN 0
|
|
63
|
+
ELSE (
|
|
64
|
+
(SUM("quantity") * MAX("timeToProduceSnapshot"))::float
|
|
65
|
+
/
|
|
66
|
+
EXTRACT(EPOCH FROM (MAX("endTime") - MIN("startTime")))
|
|
67
|
+
) * 100 -- Percentage
|
|
68
|
+
END as "efficiency_percentage",
|
|
69
|
+
|
|
70
|
+
-- Metadata
|
|
71
|
+
MAX("timeToProduceSnapshot") as "time_to_produce_snapshot",
|
|
72
|
+
|
|
73
|
+
-- Tenant scope
|
|
74
|
+
"tenantId"
|
|
75
|
+
FROM grouped_data
|
|
76
|
+
GROUP BY "tenantId", "machineId", "operatorId", "operationId", "group_id";
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
-- View Update: Add time metrics (total_elapsed_time, total_duration)
|
|
2
|
+
|
|
3
|
+
DROP VIEW IF EXISTS "productivity_intervals";
|
|
4
|
+
CREATE OR REPLACE VIEW "productivity_intervals" AS
|
|
5
|
+
WITH ranked_data AS (
|
|
6
|
+
SELECT
|
|
7
|
+
"id",
|
|
8
|
+
"tenantId",
|
|
9
|
+
"machineId",
|
|
10
|
+
"operatorId",
|
|
11
|
+
"operationId",
|
|
12
|
+
"startTime",
|
|
13
|
+
"endTime",
|
|
14
|
+
"quantity",
|
|
15
|
+
"timeToProduceSnapshot",
|
|
16
|
+
"elapsedTime", -- Added to support aggregation
|
|
17
|
+
-- Previous Row Values for Gap Detection
|
|
18
|
+
LAG("machineId") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_machine,
|
|
19
|
+
LAG("operatorId") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_operator,
|
|
20
|
+
LAG("operationId") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_operation,
|
|
21
|
+
LAG("endTime") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_end_time
|
|
22
|
+
FROM "operation_register"
|
|
23
|
+
),
|
|
24
|
+
change_points AS (
|
|
25
|
+
SELECT
|
|
26
|
+
*,
|
|
27
|
+
CASE
|
|
28
|
+
-- Standard Grouping Triggers
|
|
29
|
+
WHEN "operatorId" IS DISTINCT FROM prev_operator THEN 1
|
|
30
|
+
WHEN "operationId" IS DISTINCT FROM prev_operation THEN 1
|
|
31
|
+
-- Time Gap Trigger (> 10 hours from previous end to current start)
|
|
32
|
+
WHEN "prev_end_time" IS NOT NULL AND ("startTime" - "prev_end_time") > INTERVAL '10 hours' THEN 1
|
|
33
|
+
ELSE 0
|
|
34
|
+
END as is_new_group
|
|
35
|
+
FROM ranked_data
|
|
36
|
+
),
|
|
37
|
+
grouped_data AS (
|
|
38
|
+
SELECT
|
|
39
|
+
*,
|
|
40
|
+
-- Generate a unique Group ID per partition (cumulative sum of flags)
|
|
41
|
+
SUM(is_new_group) OVER (PARTITION BY "machineId" ORDER BY "startTime") as group_id
|
|
42
|
+
FROM change_points
|
|
43
|
+
)
|
|
44
|
+
SELECT
|
|
45
|
+
-- Deterministic unique ID for the View
|
|
46
|
+
"machineId",
|
|
47
|
+
"group_id"::integer as "sequence_id",
|
|
48
|
+
|
|
49
|
+
-- Aggregates
|
|
50
|
+
MIN("startTime") as "group_start_timestamp",
|
|
51
|
+
MAX("endTime") as "group_end_timestamp",
|
|
52
|
+
"operatorId" as "operator_id",
|
|
53
|
+
"operationId" as "operation_id",
|
|
54
|
+
COUNT(*)::integer as "record_count",
|
|
55
|
+
SUM("quantity")::integer as "total_quantity",
|
|
56
|
+
|
|
57
|
+
-- NEW: Time Metrics
|
|
58
|
+
SUM("elapsedTime")::bigint as "total_elapsed_time",
|
|
59
|
+
EXTRACT(EPOCH FROM (MAX("endTime") - MIN("startTime")))::float as "total_duration",
|
|
60
|
+
|
|
61
|
+
-- Efficiency Calculation
|
|
62
|
+
CASE
|
|
63
|
+
WHEN EXTRACT(EPOCH FROM (MAX("endTime") - MIN("startTime"))) = 0 THEN 0
|
|
64
|
+
ELSE (
|
|
65
|
+
(SUM("quantity") * MAX("timeToProduceSnapshot"))::float
|
|
66
|
+
/
|
|
67
|
+
EXTRACT(EPOCH FROM (MAX("endTime") - MIN("startTime")))
|
|
68
|
+
) * 100 -- Percentage
|
|
69
|
+
END as "efficiency_percentage",
|
|
70
|
+
|
|
71
|
+
-- Metadata
|
|
72
|
+
MAX("timeToProduceSnapshot") as "time_to_produce_snapshot",
|
|
73
|
+
|
|
74
|
+
-- Tenant scope
|
|
75
|
+
"tenantId"
|
|
76
|
+
FROM grouped_data
|
|
77
|
+
GROUP BY "tenantId", "machineId", "operatorId", "operationId", "group_id";
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
-- View Update: Add downtime subtraction logic and changing gap to 3 minutes
|
|
2
|
+
|
|
3
|
+
DROP VIEW IF EXISTS "productivity_intervals";
|
|
4
|
+
CREATE OR REPLACE VIEW "productivity_intervals" AS
|
|
5
|
+
WITH ranked_data AS (
|
|
6
|
+
SELECT
|
|
7
|
+
"id",
|
|
8
|
+
"tenantId",
|
|
9
|
+
"machineId",
|
|
10
|
+
"operatorId",
|
|
11
|
+
"operationId",
|
|
12
|
+
"startTime",
|
|
13
|
+
"endTime",
|
|
14
|
+
"quantity",
|
|
15
|
+
"timeToProduceSnapshot",
|
|
16
|
+
"elapsedTime",
|
|
17
|
+
"productionOrderId", -- Added in case needed, but kept compliant with previous columns
|
|
18
|
+
-- Previous Row Values for Gap Detection (Local to Machine)
|
|
19
|
+
LAG("machineId") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_machine,
|
|
20
|
+
LAG("operatorId") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_operator,
|
|
21
|
+
LAG("operationId") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_operation,
|
|
22
|
+
LAG("endTime") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_end_time
|
|
23
|
+
FROM "operation_register"
|
|
24
|
+
),
|
|
25
|
+
change_points AS (
|
|
26
|
+
SELECT
|
|
27
|
+
*,
|
|
28
|
+
CASE
|
|
29
|
+
-- Standard Grouping Triggers
|
|
30
|
+
WHEN "operatorId" IS DISTINCT FROM prev_operator THEN 1
|
|
31
|
+
WHEN "operationId" IS DISTINCT FROM prev_operation THEN 1
|
|
32
|
+
-- Time Gap Trigger (> 3 minutes from previous end to current start)
|
|
33
|
+
WHEN "prev_end_time" IS NOT NULL AND ("startTime" - "prev_end_time") > INTERVAL '3 minutes' THEN 1
|
|
34
|
+
ELSE 0
|
|
35
|
+
END as is_new_group
|
|
36
|
+
FROM ranked_data
|
|
37
|
+
),
|
|
38
|
+
grouped_data AS (
|
|
39
|
+
SELECT
|
|
40
|
+
*,
|
|
41
|
+
-- Generate a unique Group ID per partition (cumulative sum of flags)
|
|
42
|
+
SUM(is_new_group) OVER (PARTITION BY "machineId" ORDER BY "startTime") as group_id
|
|
43
|
+
FROM change_points
|
|
44
|
+
),
|
|
45
|
+
aggregated_groups AS (
|
|
46
|
+
SELECT
|
|
47
|
+
-- Deterministic unique ID for the View
|
|
48
|
+
"machineId",
|
|
49
|
+
"group_id"::integer as "sequence_id",
|
|
50
|
+
|
|
51
|
+
-- Aggregates
|
|
52
|
+
MIN("startTime") as "group_start_timestamp",
|
|
53
|
+
MAX("endTime") as "group_end_timestamp",
|
|
54
|
+
"operatorId" as "operator_id",
|
|
55
|
+
"operationId" as "operation_id",
|
|
56
|
+
COUNT(*)::integer as "record_count",
|
|
57
|
+
SUM("quantity")::integer as "total_quantity",
|
|
58
|
+
|
|
59
|
+
-- Time Metrics
|
|
60
|
+
SUM("elapsedTime")::bigint as "sum_operation_elapsed_time", -- Original logic kept as reference if needed, but not exposed as main metric
|
|
61
|
+
EXTRACT(EPOCH FROM (MAX("endTime") - MIN("startTime")))::float as "gross_duration_seconds",
|
|
62
|
+
|
|
63
|
+
-- Metadata
|
|
64
|
+
MAX("timeToProduceSnapshot") as "time_to_produce_snapshot",
|
|
65
|
+
|
|
66
|
+
-- Tenant scope
|
|
67
|
+
"tenantId"
|
|
68
|
+
FROM grouped_data
|
|
69
|
+
GROUP BY "tenantId", "machineId", "operatorId", "operationId", "group_id"
|
|
70
|
+
),
|
|
71
|
+
groups_with_downtime AS (
|
|
72
|
+
SELECT
|
|
73
|
+
ag.*,
|
|
74
|
+
(
|
|
75
|
+
SELECT COALESCE(SUM("elapsedTime"), 0)
|
|
76
|
+
FROM "downtime_event" de
|
|
77
|
+
WHERE de."machine_id" = ag."machineId"
|
|
78
|
+
AND de."start_time" >= ag."group_start_timestamp"
|
|
79
|
+
AND de."end_time" <= ag."group_end_timestamp"
|
|
80
|
+
)::float / 1000.0 as "downtime_seconds"
|
|
81
|
+
FROM aggregated_groups ag
|
|
82
|
+
)
|
|
83
|
+
SELECT
|
|
84
|
+
"machineId",
|
|
85
|
+
"sequence_id",
|
|
86
|
+
"group_start_timestamp",
|
|
87
|
+
"group_end_timestamp",
|
|
88
|
+
"operator_id",
|
|
89
|
+
"operation_id",
|
|
90
|
+
"record_count",
|
|
91
|
+
"total_quantity",
|
|
92
|
+
|
|
93
|
+
-- NEW: Time Metrics
|
|
94
|
+
("gross_duration_seconds" - "downtime_seconds")::float as "total_elapsed_time", -- Net Time in Seconds
|
|
95
|
+
"gross_duration_seconds" as "total_duration",
|
|
96
|
+
|
|
97
|
+
-- Efficiency Calculation
|
|
98
|
+
CASE
|
|
99
|
+
WHEN ("gross_duration_seconds" - "downtime_seconds") <= 0.001 THEN 0 -- Avoid div by zero or negative
|
|
100
|
+
ELSE (
|
|
101
|
+
("total_quantity" * "time_to_produce_snapshot")::float
|
|
102
|
+
/
|
|
103
|
+
("gross_duration_seconds" - "downtime_seconds")
|
|
104
|
+
) * 100 -- Percentage
|
|
105
|
+
END as "efficiency_percentage",
|
|
106
|
+
|
|
107
|
+
"time_to_produce_snapshot",
|
|
108
|
+
"tenantId"
|
|
109
|
+
FROM groups_with_downtime;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
-- CreateTable
|
|
2
|
+
CREATE TABLE "productivity_interval_cache" (
|
|
3
|
+
"id" TEXT NOT NULL,
|
|
4
|
+
"tenantId" TEXT,
|
|
5
|
+
"machineId" TEXT NOT NULL,
|
|
6
|
+
"operatorId" TEXT NOT NULL,
|
|
7
|
+
"operationId" TEXT,
|
|
8
|
+
"sequence_id" INTEGER NOT NULL,
|
|
9
|
+
"group_start_timestamp" TIMESTAMP(3) NOT NULL,
|
|
10
|
+
"group_end_timestamp" TIMESTAMP(3) NOT NULL,
|
|
11
|
+
"record_count" INTEGER NOT NULL,
|
|
12
|
+
"total_quantity" INTEGER NOT NULL,
|
|
13
|
+
"total_elapsed_time" DOUBLE PRECISION NOT NULL,
|
|
14
|
+
"total_duration" DOUBLE PRECISION NOT NULL,
|
|
15
|
+
"efficiency_percentage" DOUBLE PRECISION NOT NULL,
|
|
16
|
+
"time_to_produce_snapshot" INTEGER,
|
|
17
|
+
"downtime_seconds" DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
18
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
19
|
+
|
|
20
|
+
CONSTRAINT "productivity_interval_cache_pkey" PRIMARY KEY ("id")
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
-- CreateIndex
|
|
24
|
+
CREATE INDEX "productivity_interval_cache_tenantId_machineId_group_start_timestamp_idx" ON "productivity_interval_cache"("tenantId", "machineId", "group_start_timestamp");
|
|
25
|
+
|
|
26
|
+
-- CreateIndex
|
|
27
|
+
CREATE UNIQUE INDEX "productivity_interval_cache_machineId_group_start_timestamp_key" ON "productivity_interval_cache"("machineId", "group_start_timestamp");
|
|
28
|
+
|
|
29
|
+
-- AddForeignKey
|
|
30
|
+
ALTER TABLE "productivity_interval_cache" ADD CONSTRAINT "productivity_interval_cache_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "tenant"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
31
|
+
|
|
32
|
+
-- AddForeignKey
|
|
33
|
+
ALTER TABLE "productivity_interval_cache" ADD CONSTRAINT "productivity_interval_cache_machineId_fkey" FOREIGN KEY ("machineId") REFERENCES "machine"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
34
|
+
|
|
35
|
+
-- AddForeignKey
|
|
36
|
+
ALTER TABLE "productivity_interval_cache" ADD CONSTRAINT "productivity_interval_cache_operatorId_fkey" FOREIGN KEY ("operatorId") REFERENCES "operator"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
37
|
+
|
|
38
|
+
-- AddForeignKey
|
|
39
|
+
ALTER TABLE "productivity_interval_cache" ADD CONSTRAINT "productivity_interval_cache_operationId_fkey" FOREIGN KEY ("operationId") REFERENCES "operation"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
-- View Update: Fix missing downtime_seconds column
|
|
2
|
+
|
|
3
|
+
DROP VIEW IF EXISTS "productivity_intervals";
|
|
4
|
+
CREATE OR REPLACE VIEW "productivity_intervals" AS
|
|
5
|
+
WITH ranked_data AS (
|
|
6
|
+
SELECT
|
|
7
|
+
"id",
|
|
8
|
+
"tenantId",
|
|
9
|
+
"machineId",
|
|
10
|
+
"operatorId",
|
|
11
|
+
"operationId",
|
|
12
|
+
"startTime",
|
|
13
|
+
"endTime",
|
|
14
|
+
"quantity",
|
|
15
|
+
"timeToProduceSnapshot",
|
|
16
|
+
"elapsedTime",
|
|
17
|
+
"productionOrderId", -- Added in case needed, but kept compliant with previous columns
|
|
18
|
+
-- Previous Row Values for Gap Detection (Local to Machine)
|
|
19
|
+
LAG("machineId") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_machine,
|
|
20
|
+
LAG("operatorId") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_operator,
|
|
21
|
+
LAG("operationId") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_operation,
|
|
22
|
+
LAG("endTime") OVER (PARTITION BY "machineId" ORDER BY "startTime") as prev_end_time
|
|
23
|
+
FROM "operation_register"
|
|
24
|
+
),
|
|
25
|
+
change_points AS (
|
|
26
|
+
SELECT
|
|
27
|
+
*,
|
|
28
|
+
CASE
|
|
29
|
+
-- Standard Grouping Triggers
|
|
30
|
+
WHEN "operatorId" IS DISTINCT FROM prev_operator THEN 1
|
|
31
|
+
WHEN "operationId" IS DISTINCT FROM prev_operation THEN 1
|
|
32
|
+
-- Time Gap Trigger (> 3 minutes from previous end to current start)
|
|
33
|
+
WHEN "prev_end_time" IS NOT NULL AND ("startTime" - "prev_end_time") > INTERVAL '3 minutes' THEN 1
|
|
34
|
+
ELSE 0
|
|
35
|
+
END as is_new_group
|
|
36
|
+
FROM ranked_data
|
|
37
|
+
),
|
|
38
|
+
grouped_data AS (
|
|
39
|
+
SELECT
|
|
40
|
+
*,
|
|
41
|
+
-- Generate a unique Group ID per partition (cumulative sum of flags)
|
|
42
|
+
SUM(is_new_group) OVER (PARTITION BY "machineId" ORDER BY "startTime") as group_id
|
|
43
|
+
FROM change_points
|
|
44
|
+
),
|
|
45
|
+
aggregated_groups AS (
|
|
46
|
+
SELECT
|
|
47
|
+
-- Deterministic unique ID for the View
|
|
48
|
+
"machineId",
|
|
49
|
+
"group_id"::integer as "sequence_id",
|
|
50
|
+
|
|
51
|
+
-- Aggregates
|
|
52
|
+
MIN("startTime") as "group_start_timestamp",
|
|
53
|
+
MAX("endTime") as "group_end_timestamp",
|
|
54
|
+
"operatorId" as "operator_id",
|
|
55
|
+
"operationId" as "operation_id",
|
|
56
|
+
COUNT(*)::integer as "record_count",
|
|
57
|
+
SUM("quantity")::integer as "total_quantity",
|
|
58
|
+
|
|
59
|
+
-- Time Metrics
|
|
60
|
+
SUM("elapsedTime")::bigint as "sum_operation_elapsed_time", -- Original logic kept as reference if needed, but not exposed as main metric
|
|
61
|
+
EXTRACT(EPOCH FROM (MAX("endTime") - MIN("startTime")))::float as "gross_duration_seconds",
|
|
62
|
+
|
|
63
|
+
-- Metadata
|
|
64
|
+
MAX("timeToProduceSnapshot") as "time_to_produce_snapshot",
|
|
65
|
+
|
|
66
|
+
-- Tenant scope
|
|
67
|
+
"tenantId"
|
|
68
|
+
FROM grouped_data
|
|
69
|
+
GROUP BY "tenantId", "machineId", "operatorId", "operationId", "group_id"
|
|
70
|
+
),
|
|
71
|
+
groups_with_downtime AS (
|
|
72
|
+
SELECT
|
|
73
|
+
ag.*,
|
|
74
|
+
(
|
|
75
|
+
SELECT COALESCE(SUM("elapsedTime"), 0)
|
|
76
|
+
FROM "downtime_event" de
|
|
77
|
+
WHERE de."machine_id" = ag."machineId"
|
|
78
|
+
AND de."start_time" >= ag."group_start_timestamp"
|
|
79
|
+
AND de."end_time" <= ag."group_end_timestamp"
|
|
80
|
+
)::float / 1000.0 as "downtime_seconds"
|
|
81
|
+
FROM aggregated_groups ag
|
|
82
|
+
)
|
|
83
|
+
SELECT
|
|
84
|
+
"machineId",
|
|
85
|
+
"sequence_id",
|
|
86
|
+
"group_start_timestamp",
|
|
87
|
+
"group_end_timestamp",
|
|
88
|
+
"operator_id",
|
|
89
|
+
"operation_id",
|
|
90
|
+
"record_count",
|
|
91
|
+
"total_quantity",
|
|
92
|
+
|
|
93
|
+
-- NEW: Time Metrics
|
|
94
|
+
("gross_duration_seconds" - "downtime_seconds")::float as "total_elapsed_time", -- Net Time in Seconds
|
|
95
|
+
"gross_duration_seconds" as "total_duration",
|
|
96
|
+
|
|
97
|
+
-- Efficiency Calculation
|
|
98
|
+
CASE
|
|
99
|
+
WHEN ("gross_duration_seconds" - "downtime_seconds") <= 0.001 THEN 0 -- Avoid div by zero or negative
|
|
100
|
+
ELSE (
|
|
101
|
+
("total_quantity" * "time_to_produce_snapshot")::float
|
|
102
|
+
/
|
|
103
|
+
("gross_duration_seconds" - "downtime_seconds")
|
|
104
|
+
) * 100 -- Percentage
|
|
105
|
+
END as "efficiency_percentage",
|
|
106
|
+
|
|
107
|
+
"time_to_produce_snapshot",
|
|
108
|
+
"downtime_seconds",
|
|
109
|
+
"tenantId"
|
|
110
|
+
FROM groups_with_downtime;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
-- CreateIndex
|
|
2
|
+
CREATE INDEX "downtime_event_machine_id_start_time_idx" ON "public"."downtime_event"("machine_id", "start_time");
|
|
3
|
+
|
|
4
|
+
-- CreateIndex
|
|
5
|
+
CREATE INDEX "downtime_event_downtimeReasonId_idx" ON "public"."downtime_event"("downtimeReasonId");
|
|
6
|
+
|
|
7
|
+
-- CreateIndex
|
|
8
|
+
CREATE INDEX "input_register_machineId_timestamp_idx" ON "public"."input_register"("machineId", "timestamp");
|
|
9
|
+
|
|
10
|
+
-- CreateIndex
|
|
11
|
+
CREATE INDEX "input_register_productionOrderId_idx" ON "public"."input_register"("productionOrderId");
|
|
12
|
+
|
|
13
|
+
-- CreateIndex
|
|
14
|
+
CREATE INDEX "input_register_tenantId_idx" ON "public"."input_register"("tenantId");
|
|
15
|
+
|
|
16
|
+
-- CreateIndex
|
|
17
|
+
CREATE INDEX "iot_message_register_machineId_timestamp_idx" ON "public"."iot_message_register"("machineId", "timestamp");
|
|
18
|
+
|
|
19
|
+
-- CreateIndex
|
|
20
|
+
CREATE INDEX "items_handling_register_productionOrderId_idx" ON "public"."items_handling_register"("productionOrderId");
|
|
21
|
+
|
|
22
|
+
-- CreateIndex
|
|
23
|
+
CREATE INDEX "items_handling_register_productId_idx" ON "public"."items_handling_register"("productId");
|
|
24
|
+
|
|
25
|
+
-- CreateIndex
|
|
26
|
+
CREATE INDEX "items_handling_register_operationId_idx" ON "public"."items_handling_register"("operationId");
|
|
27
|
+
|
|
28
|
+
-- CreateIndex
|
|
29
|
+
CREATE INDEX "items_handling_register_tenantId_idx" ON "public"."items_handling_register"("tenantId");
|
|
30
|
+
|
|
31
|
+
-- CreateIndex
|
|
32
|
+
CREATE INDEX "machine_sectorId_idx" ON "public"."machine"("sectorId");
|
|
33
|
+
|
|
34
|
+
-- CreateIndex
|
|
35
|
+
CREATE INDEX "machine_tenantId_idx" ON "public"."machine"("tenantId");
|
|
36
|
+
|
|
37
|
+
-- CreateIndex
|
|
38
|
+
CREATE INDEX "machine_isDeleted_idx" ON "public"."machine"("isDeleted");
|
|
39
|
+
|
|
40
|
+
-- CreateIndex
|
|
41
|
+
CREATE INDEX "machine_formula_result_machineId_timestamp_idx" ON "public"."machine_formula_result"("machineId", "timestamp");
|
|
42
|
+
|
|
43
|
+
-- CreateIndex
|
|
44
|
+
CREATE INDEX "machine_formula_result_formulaId_idx" ON "public"."machine_formula_result"("formulaId");
|
|
45
|
+
|
|
46
|
+
-- CreateIndex
|
|
47
|
+
CREATE INDEX "operation_register_machineId_startTime_idx" ON "public"."operation_register"("machineId", "startTime");
|
|
48
|
+
|
|
49
|
+
-- CreateIndex
|
|
50
|
+
CREATE INDEX "operation_register_productionOrderId_idx" ON "public"."operation_register"("productionOrderId");
|
|
51
|
+
|
|
52
|
+
-- CreateIndex
|
|
53
|
+
CREATE INDEX "operation_register_operationId_idx" ON "public"."operation_register"("operationId");
|
|
54
|
+
|
|
55
|
+
-- CreateIndex
|
|
56
|
+
CREATE INDEX "operation_register_productionNodeId_idx" ON "public"."operation_register"("productionNodeId");
|
|
57
|
+
|
|
58
|
+
-- CreateIndex
|
|
59
|
+
CREATE INDEX "product_tenantId_idx" ON "public"."product"("tenantId");
|
|
60
|
+
|
|
61
|
+
-- CreateIndex
|
|
62
|
+
CREATE INDEX "product_isDeleted_idx" ON "public"."product"("isDeleted");
|
|
63
|
+
|
|
64
|
+
-- CreateIndex
|
|
65
|
+
CREATE INDEX "production_order_tenantId_isFinished_idx" ON "public"."production_order"("tenantId", "isFinished");
|
|
66
|
+
|
|
67
|
+
-- CreateIndex
|
|
68
|
+
CREATE INDEX "production_order_productId_idx" ON "public"."production_order"("productId");
|
|
69
|
+
|
|
70
|
+
-- CreateIndex
|
|
71
|
+
CREATE INDEX "production_order_flowId_idx" ON "public"."production_order"("flowId");
|
|
72
|
+
|
|
73
|
+
-- CreateIndex
|
|
74
|
+
CREATE INDEX "productivity_interval_cache_operatorId_group_start_timestam_idx" ON "public"."productivity_interval_cache"("operatorId", "group_start_timestamp");
|
|
75
|
+
|
|
76
|
+
-- CreateIndex
|
|
77
|
+
CREATE INDEX "productivity_interval_cache_operationId_idx" ON "public"."productivity_interval_cache"("operationId");
|
|
78
|
+
|
|
79
|
+
-- CreateIndex
|
|
80
|
+
CREATE INDEX "sew_machine_raw_data_machine_id_start_timestamp_idx" ON "public"."sew_machine_raw_data"("machine_id", "start_timestamp");
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
-- CreateTable
|
|
2
|
+
CREATE TABLE "public"."ai_conversation" (
|
|
3
|
+
"id" TEXT NOT NULL,
|
|
4
|
+
"userId" TEXT NOT NULL,
|
|
5
|
+
"tenantId" TEXT,
|
|
6
|
+
"title" TEXT,
|
|
7
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
8
|
+
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
9
|
+
|
|
10
|
+
CONSTRAINT "ai_conversation_pkey" PRIMARY KEY ("id")
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
-- CreateTable
|
|
14
|
+
CREATE TABLE "public"."ai_message" (
|
|
15
|
+
"id" TEXT NOT NULL,
|
|
16
|
+
"conversationId" TEXT NOT NULL,
|
|
17
|
+
"role" TEXT NOT NULL,
|
|
18
|
+
"content" TEXT NOT NULL,
|
|
19
|
+
"sqlQuery" TEXT,
|
|
20
|
+
"toolCalls" JSONB,
|
|
21
|
+
"isCorrect" BOOLEAN,
|
|
22
|
+
"correction" TEXT,
|
|
23
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
24
|
+
|
|
25
|
+
CONSTRAINT "ai_message_pkey" PRIMARY KEY ("id")
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
-- CreateTable
|
|
29
|
+
CREATE TABLE "public"."ai_feedback" (
|
|
30
|
+
"id" TEXT NOT NULL,
|
|
31
|
+
"tenantId" TEXT,
|
|
32
|
+
"userId" TEXT NOT NULL,
|
|
33
|
+
"question" TEXT NOT NULL,
|
|
34
|
+
"generatedSql" TEXT NOT NULL,
|
|
35
|
+
"correctedSql" TEXT,
|
|
36
|
+
"comment" TEXT,
|
|
37
|
+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
38
|
+
|
|
39
|
+
CONSTRAINT "ai_feedback_pkey" PRIMARY KEY ("id")
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
-- CreateIndex
|
|
43
|
+
CREATE INDEX "ai_conversation_userId_idx" ON "public"."ai_conversation"("userId");
|
|
44
|
+
|
|
45
|
+
-- CreateIndex
|
|
46
|
+
CREATE INDEX "ai_message_conversationId_idx" ON "public"."ai_message"("conversationId");
|
|
47
|
+
|
|
48
|
+
-- AddForeignKey
|
|
49
|
+
ALTER TABLE "public"."ai_conversation" ADD CONSTRAINT "ai_conversation_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
50
|
+
|
|
51
|
+
-- AddForeignKey
|
|
52
|
+
ALTER TABLE "public"."ai_conversation" ADD CONSTRAINT "ai_conversation_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "public"."tenant"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
53
|
+
|
|
54
|
+
-- AddForeignKey
|
|
55
|
+
ALTER TABLE "public"."ai_message" ADD CONSTRAINT "ai_message_conversationId_fkey" FOREIGN KEY ("conversationId") REFERENCES "public"."ai_conversation"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juliobrim/prisma-shared",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.43",
|
|
4
4
|
"description": "Schema Prisma compartilhado entre projetos Sabcon",
|
|
5
5
|
"main": "schema.prisma",
|
|
6
6
|
"files": [
|
|
@@ -49,5 +49,8 @@
|
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": ">=16.0.0"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"dayjs": "^1.11.19"
|
|
52
55
|
}
|
|
53
56
|
}
|
package/schema.prisma
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
generator client {
|
|
2
|
-
provider
|
|
2
|
+
provider = "prisma-client-js"
|
|
3
|
+
previewFeatures = ["views"]
|
|
3
4
|
}
|
|
4
5
|
|
|
5
6
|
datasource db {
|
|
@@ -8,13 +9,13 @@ datasource db {
|
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
model Tenant {
|
|
11
|
-
id String
|
|
12
|
-
name String
|
|
13
|
-
slug String
|
|
14
|
-
domain String?
|
|
15
|
-
isActive Boolean
|
|
16
|
-
createdAt DateTime
|
|
17
|
-
updatedAt DateTime
|
|
12
|
+
id String @id @default(cuid())
|
|
13
|
+
name String @unique
|
|
14
|
+
slug String @unique
|
|
15
|
+
domain String? @unique
|
|
16
|
+
isActive Boolean @default(true)
|
|
17
|
+
createdAt DateTime @default(now())
|
|
18
|
+
updatedAt DateTime @updatedAt
|
|
18
19
|
accounts Account[]
|
|
19
20
|
breaks Break[]
|
|
20
21
|
devices Device[]
|
|
@@ -60,6 +61,8 @@ model Tenant {
|
|
|
60
61
|
userPermissions UserPermission[]
|
|
61
62
|
userShifts UserShift[]
|
|
62
63
|
machineOperationStitch MachineOperationStitch[]
|
|
64
|
+
productivityIntervals ProductivityIntervalCache[]
|
|
65
|
+
aiConversations AiConversation[]
|
|
63
66
|
|
|
64
67
|
@@map("tenant")
|
|
65
68
|
}
|
|
@@ -121,6 +124,8 @@ model DowntimeEvent {
|
|
|
121
124
|
|
|
122
125
|
@@index([operatorId, end_time, elapsedTime])
|
|
123
126
|
@@index([tenantId, operatorId, end_time])
|
|
127
|
+
@@index([machine_id, start_time])
|
|
128
|
+
@@index([downtimeReasonId])
|
|
124
129
|
@@map("downtime_event")
|
|
125
130
|
}
|
|
126
131
|
|
|
@@ -193,6 +198,9 @@ model InputRegister {
|
|
|
193
198
|
productionOrder ProductionOrder? @relation(fields: [productionOrderId], references: [id], onDelete: Cascade)
|
|
194
199
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
195
200
|
|
|
201
|
+
@@index([machineId, timestamp])
|
|
202
|
+
@@index([productionOrderId])
|
|
203
|
+
@@index([tenantId])
|
|
196
204
|
@@map("input_register")
|
|
197
205
|
}
|
|
198
206
|
|
|
@@ -212,6 +220,7 @@ model IotMessageRegister {
|
|
|
212
220
|
machine Machine @relation(fields: [machineId], references: [id], onDelete: Cascade)
|
|
213
221
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
214
222
|
|
|
223
|
+
@@index([machineId, timestamp])
|
|
215
224
|
@@map("iot_message_register")
|
|
216
225
|
}
|
|
217
226
|
|
|
@@ -236,42 +245,50 @@ model ItemsHandlingRegister {
|
|
|
236
245
|
stationTo Machine? @relation("stationTo", fields: [stationToId], references: [id])
|
|
237
246
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
238
247
|
|
|
248
|
+
@@index([productionOrderId])
|
|
249
|
+
@@index([productId])
|
|
250
|
+
@@index([operationId])
|
|
251
|
+
@@index([tenantId])
|
|
239
252
|
@@map("items_handling_register")
|
|
240
253
|
}
|
|
241
254
|
|
|
242
255
|
model Machine {
|
|
243
|
-
id String
|
|
244
|
-
model String?
|
|
245
|
-
name String
|
|
246
|
-
capacity Float?
|
|
256
|
+
id String @id @default(cuid())
|
|
257
|
+
model String? @db.VarChar(100)
|
|
258
|
+
name String @unique @db.VarChar(100)
|
|
259
|
+
capacity Float? @db.Real
|
|
247
260
|
clp_index String?
|
|
248
|
-
acquired_date DateTime?
|
|
249
|
-
macAddress String?
|
|
250
|
-
isDeleted Boolean
|
|
261
|
+
acquired_date DateTime? @db.Date
|
|
262
|
+
macAddress String? @db.VarChar(17)
|
|
263
|
+
isDeleted Boolean @default(false)
|
|
251
264
|
sectorId String?
|
|
252
265
|
tenantId String?
|
|
253
|
-
type MachineType?
|
|
266
|
+
type MachineType? @default(discrete)
|
|
254
267
|
device Device?
|
|
255
268
|
downtime DowntimeEvent[]
|
|
256
269
|
followers Follower[]
|
|
257
270
|
inputRegisters InputRegister[]
|
|
258
271
|
IotMessageRegister IotMessageRegister[]
|
|
259
|
-
stationFrom ItemsHandlingRegister[]
|
|
260
|
-
stationTo ItemsHandlingRegister[]
|
|
261
|
-
sector Sector?
|
|
262
|
-
tenant Tenant?
|
|
272
|
+
stationFrom ItemsHandlingRegister[] @relation("stationFrom")
|
|
273
|
+
stationTo ItemsHandlingRegister[] @relation("stationTo")
|
|
274
|
+
sector Sector? @relation(fields: [sectorId], references: [id])
|
|
275
|
+
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
263
276
|
MachineFormula MachineFormula[]
|
|
264
277
|
MachineFormulaResult MachineFormulaResult[]
|
|
265
278
|
machineSensors MachineSensors?
|
|
266
279
|
operationRegister OperationRegister[]
|
|
267
280
|
productionNodes ProductionNode?
|
|
268
|
-
operationResources Resource[]
|
|
281
|
+
operationResources Resource[] @relation("MachineToResource")
|
|
269
282
|
processingScriptId String?
|
|
270
|
-
processingScript ProcessingScript?
|
|
283
|
+
processingScript ProcessingScript? @relation(fields: [processingScriptId], references: [id])
|
|
271
284
|
MachineProcessingScript MachineProcessingScript?
|
|
272
285
|
MachineScriptState MachineScriptState?
|
|
273
286
|
machineOperationStitch MachineOperationStitch[]
|
|
287
|
+
productivityIntervals ProductivityIntervalCache[]
|
|
274
288
|
|
|
289
|
+
@@index([sectorId])
|
|
290
|
+
@@index([tenantId])
|
|
291
|
+
@@index([isDeleted])
|
|
275
292
|
@@map("machine")
|
|
276
293
|
}
|
|
277
294
|
|
|
@@ -321,6 +338,8 @@ model MachineFormulaResult {
|
|
|
321
338
|
machine Machine @relation(fields: [machineId], references: [id])
|
|
322
339
|
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
|
323
340
|
|
|
341
|
+
@@index([machineId, timestamp])
|
|
342
|
+
@@index([formulaId])
|
|
324
343
|
@@map("machine_formula_result")
|
|
325
344
|
}
|
|
326
345
|
|
|
@@ -374,38 +393,39 @@ model NotificationToUser {
|
|
|
374
393
|
}
|
|
375
394
|
|
|
376
395
|
model Operation {
|
|
377
|
-
id String
|
|
396
|
+
id String @id @default(cuid())
|
|
378
397
|
stitches Int
|
|
379
398
|
finalIntervalTime Float
|
|
380
399
|
description String
|
|
381
400
|
resourceId String
|
|
382
|
-
timeToProduce Int
|
|
383
|
-
numberOfCuts Int
|
|
384
|
-
nodeId String
|
|
401
|
+
timeToProduce Int @default(10)
|
|
402
|
+
numberOfCuts Int @default(0)
|
|
403
|
+
nodeId String @unique
|
|
385
404
|
nodeIndex Int?
|
|
386
|
-
amount Int
|
|
405
|
+
amount Int @default(1)
|
|
387
406
|
operationId String?
|
|
388
|
-
engineeringTime Int
|
|
389
|
-
initialTime Int
|
|
390
|
-
pcpTime Int
|
|
407
|
+
engineeringTime Int @default(0)
|
|
408
|
+
initialTime Int @default(0)
|
|
409
|
+
pcpTime Int @default(0)
|
|
391
410
|
tenantId String?
|
|
392
411
|
downtimeEvents DowntimeEvent[]
|
|
393
412
|
inputRegisters InputRegister[]
|
|
394
413
|
itemsHandlingRegisters ItemsHandlingRegister[]
|
|
395
414
|
nodeOperationQueue NodeOperationQueue[]
|
|
396
|
-
node Node
|
|
397
|
-
resource Resource
|
|
398
|
-
tenant Tenant?
|
|
415
|
+
node Node @relation(fields: [nodeId], references: [id], onDelete: Cascade)
|
|
416
|
+
resource Resource @relation(fields: [resourceId], references: [id])
|
|
417
|
+
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
399
418
|
operationRegisters OperationRegister[]
|
|
400
|
-
inputOf OperationToOperation[]
|
|
401
|
-
outputOf OperationToOperation[]
|
|
419
|
+
inputOf OperationToOperation[] @relation("inputOperation")
|
|
420
|
+
outputOf OperationToOperation[] @relation("outputOperation")
|
|
402
421
|
products ProductToOperation[]
|
|
403
422
|
productionNodes ProductionNode[]
|
|
404
|
-
operationGroups OperationGroup[]
|
|
423
|
+
operationGroups OperationGroup[] @relation("OperationToOperationGroup")
|
|
405
424
|
// Relações para grupos
|
|
406
|
-
groupMemberships OperationGroupMember[]
|
|
407
|
-
memberOfGroups OperationGroupMember[]
|
|
425
|
+
groupMemberships OperationGroupMember[] @relation("GroupOperations")
|
|
426
|
+
memberOfGroups OperationGroupMember[] @relation("MemberOperations")
|
|
408
427
|
machineOperationStitch MachineOperationStitch[]
|
|
428
|
+
productivityIntervals ProductivityIntervalCache[]
|
|
409
429
|
|
|
410
430
|
@@index([nodeId], map: "idx_operation_node_id")
|
|
411
431
|
@@map("operation")
|
|
@@ -465,6 +485,7 @@ model OperationRegister {
|
|
|
465
485
|
tenantId String?
|
|
466
486
|
quantity Int @default(1)
|
|
467
487
|
timeSinceLastOperation BigInt?
|
|
488
|
+
timeToProduceSnapshot Int?
|
|
468
489
|
machine Machine @relation(fields: [machineId], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "fk_machine")
|
|
469
490
|
operator Operator @relation(fields: [operatorId], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "fk_operator")
|
|
470
491
|
operationGroup OperationGroup? @relation(fields: [operationGroupId], references: [id])
|
|
@@ -475,6 +496,10 @@ model OperationRegister {
|
|
|
475
496
|
|
|
476
497
|
@@index([operatorId, endTime, elapsedTime])
|
|
477
498
|
@@index([tenantId, operatorId, endTime])
|
|
499
|
+
@@index([machineId, startTime])
|
|
500
|
+
@@index([productionOrderId])
|
|
501
|
+
@@index([operationId])
|
|
502
|
+
@@index([productionNodeId])
|
|
478
503
|
@@map("operation_register")
|
|
479
504
|
}
|
|
480
505
|
|
|
@@ -492,25 +517,26 @@ model OperationToOperation {
|
|
|
492
517
|
}
|
|
493
518
|
|
|
494
519
|
model Operator {
|
|
495
|
-
id String
|
|
496
|
-
name String
|
|
520
|
+
id String @id @default(cuid())
|
|
521
|
+
name String @unique
|
|
497
522
|
nickname String?
|
|
498
|
-
birthDate DateTime?
|
|
523
|
+
birthDate DateTime? @db.Date
|
|
499
524
|
phoneNumber String?
|
|
500
525
|
profileImgUrl String?
|
|
501
526
|
stringfiedProfileImgUrl String?
|
|
502
527
|
operatorRoleId String?
|
|
503
528
|
pin String?
|
|
504
|
-
isDeleted Boolean
|
|
529
|
+
isDeleted Boolean @default(false)
|
|
505
530
|
tenantId String?
|
|
506
531
|
deviceOperators DeviceOperator[]
|
|
507
532
|
downtimeEvents DowntimeEvent[]
|
|
508
533
|
operationRegisters OperationRegister[]
|
|
509
|
-
operatorRole OperatorRole?
|
|
510
|
-
tenant Tenant?
|
|
534
|
+
operatorRole OperatorRole? @relation(fields: [operatorRoleId], references: [id])
|
|
535
|
+
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
511
536
|
ProductionNode ProductionNode?
|
|
512
|
-
habilityResources Resource[]
|
|
513
|
-
shifts Shift[]
|
|
537
|
+
habilityResources Resource[] @relation("OperatorToResource")
|
|
538
|
+
shifts Shift[] @relation("OperatorToShift")
|
|
539
|
+
productivityIntervals ProductivityIntervalCache[]
|
|
514
540
|
|
|
515
541
|
@@index([tenantId, isDeleted])
|
|
516
542
|
@@map("operator")
|
|
@@ -582,6 +608,8 @@ model Product {
|
|
|
582
608
|
operations ProductToOperation[]
|
|
583
609
|
productionOrders ProductionOrder[]
|
|
584
610
|
|
|
611
|
+
@@index([tenantId])
|
|
612
|
+
@@index([isDeleted])
|
|
585
613
|
@@map("product")
|
|
586
614
|
}
|
|
587
615
|
|
|
@@ -641,6 +669,9 @@ model ProductionOrder {
|
|
|
641
669
|
Product Product @relation(fields: [productId], references: [id])
|
|
642
670
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
643
671
|
|
|
672
|
+
@@index([tenantId, isFinished])
|
|
673
|
+
@@index([productId])
|
|
674
|
+
@@index([flowId])
|
|
644
675
|
@@map("production_order")
|
|
645
676
|
}
|
|
646
677
|
|
|
@@ -709,6 +740,7 @@ model SewMachineRawData {
|
|
|
709
740
|
tenantId String?
|
|
710
741
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
711
742
|
|
|
743
|
+
@@index([machine_id, start_timestamp])
|
|
712
744
|
@@map("sew_machine_raw_data")
|
|
713
745
|
}
|
|
714
746
|
|
|
@@ -777,6 +809,7 @@ model User {
|
|
|
777
809
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
778
810
|
userPermissions UserPermission[]
|
|
779
811
|
UserShift UserShift[]
|
|
812
|
+
aiConversations AiConversation[]
|
|
780
813
|
|
|
781
814
|
@@map("user")
|
|
782
815
|
}
|
|
@@ -805,6 +838,26 @@ model UserShift {
|
|
|
805
838
|
@@map("user_shift")
|
|
806
839
|
}
|
|
807
840
|
|
|
841
|
+
view ProductivityInterval {
|
|
842
|
+
machineId String
|
|
843
|
+
sequenceId Int @map("sequence_id")
|
|
844
|
+
groupStartTimestamp DateTime @map("group_start_timestamp")
|
|
845
|
+
groupEndTimestamp DateTime? @map("group_end_timestamp")
|
|
846
|
+
operatorId String? @map("operator_id")
|
|
847
|
+
operationId String? @map("operation_id")
|
|
848
|
+
recordCount Int @map("record_count")
|
|
849
|
+
totalQuantity Int @map("total_quantity")
|
|
850
|
+
totalElapsedTime Float? @map("total_elapsed_time")
|
|
851
|
+
totalDuration Float? @map("total_duration")
|
|
852
|
+
efficiencyPercentage Float? @map("efficiency_percentage")
|
|
853
|
+
timeToProduceSnapshot Int? @map("time_to_produce_snapshot")
|
|
854
|
+
downtimeSeconds Float? @map("downtime_seconds")
|
|
855
|
+
tenantId String?
|
|
856
|
+
|
|
857
|
+
@@unique([machineId, sequenceId])
|
|
858
|
+
@@map("productivity_intervals")
|
|
859
|
+
}
|
|
860
|
+
|
|
808
861
|
model VerificationToken {
|
|
809
862
|
id String @id @default(cuid())
|
|
810
863
|
token String @unique
|
|
@@ -993,3 +1046,80 @@ model MachineOperationStitch {
|
|
|
993
1046
|
@@id([machineId, operationId])
|
|
994
1047
|
@@map("machine_operation_stitch")
|
|
995
1048
|
}
|
|
1049
|
+
|
|
1050
|
+
model ProductivityIntervalCache {
|
|
1051
|
+
id String @id @default(cuid())
|
|
1052
|
+
tenantId String?
|
|
1053
|
+
machineId String
|
|
1054
|
+
operatorId String
|
|
1055
|
+
operationId String?
|
|
1056
|
+
sequenceId Int @map("sequence_id")
|
|
1057
|
+
groupStartTimestamp DateTime @map("group_start_timestamp")
|
|
1058
|
+
groupEndTimestamp DateTime @map("group_end_timestamp")
|
|
1059
|
+
recordCount Int @map("record_count")
|
|
1060
|
+
totalQuantity Int @map("total_quantity")
|
|
1061
|
+
totalElapsedTime Float @map("total_elapsed_time")
|
|
1062
|
+
totalDuration Float @map("total_duration")
|
|
1063
|
+
efficiencyPercentage Float @map("efficiency_percentage")
|
|
1064
|
+
timeToProduceSnapshot Int? @map("time_to_produce_snapshot")
|
|
1065
|
+
downtimeSeconds Float @default(0) @map("downtime_seconds")
|
|
1066
|
+
|
|
1067
|
+
createdAt DateTime @default(now())
|
|
1068
|
+
|
|
1069
|
+
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
1070
|
+
machine Machine @relation(fields: [machineId], references: [id], onDelete: Cascade)
|
|
1071
|
+
operator Operator @relation(fields: [operatorId], references: [id], onDelete: Cascade)
|
|
1072
|
+
operation Operation? @relation(fields: [operationId], references: [id], onDelete: Cascade)
|
|
1073
|
+
|
|
1074
|
+
@@unique([machineId, groupStartTimestamp])
|
|
1075
|
+
@@index([tenantId, machineId, groupStartTimestamp])
|
|
1076
|
+
@@index([operatorId, groupStartTimestamp])
|
|
1077
|
+
@@index([operationId])
|
|
1078
|
+
@@map("productivity_interval_cache")
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// --- AI & I. Intelligence ---
|
|
1082
|
+
|
|
1083
|
+
model AiConversation {
|
|
1084
|
+
id String @id @default(cuid())
|
|
1085
|
+
userId String
|
|
1086
|
+
tenantId String?
|
|
1087
|
+
title String?
|
|
1088
|
+
messages AiMessage[]
|
|
1089
|
+
createdAt DateTime @default(now())
|
|
1090
|
+
updatedAt DateTime @updatedAt
|
|
1091
|
+
user User @relation(fields: [userId], references: [id])
|
|
1092
|
+
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
|
1093
|
+
|
|
1094
|
+
@@index([userId])
|
|
1095
|
+
@@map("ai_conversation")
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
model AiMessage {
|
|
1099
|
+
id String @id @default(cuid())
|
|
1100
|
+
conversationId String
|
|
1101
|
+
role String // 'user' | 'assistant' | 'system' | 'data'
|
|
1102
|
+
content String // Markdown content
|
|
1103
|
+
sqlQuery String? // The generated SQL (if assistant)
|
|
1104
|
+
toolCalls Json? // If the AI called tools
|
|
1105
|
+
isCorrect Boolean? // Feedback: true=Good, false=Bad
|
|
1106
|
+
correction String? // User's textual correction or correct SQL
|
|
1107
|
+
createdAt DateTime @default(now())
|
|
1108
|
+
conversation AiConversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
|
|
1109
|
+
|
|
1110
|
+
@@index([conversationId])
|
|
1111
|
+
@@map("ai_message")
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
model AiFeedback {
|
|
1115
|
+
id String @id @default(cuid())
|
|
1116
|
+
tenantId String?
|
|
1117
|
+
userId String
|
|
1118
|
+
question String
|
|
1119
|
+
generatedSql String
|
|
1120
|
+
correctedSql String?
|
|
1121
|
+
comment String?
|
|
1122
|
+
createdAt DateTime @default(now())
|
|
1123
|
+
|
|
1124
|
+
@@map("ai_feedback")
|
|
1125
|
+
}
|