@juliobrim/prisma-shared 1.0.40 → 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/20260121134419_operation_stitches_by_machine/migration.sql +18 -0
- 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 +193 -46
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- CreateTable
|
|
2
|
+
CREATE TABLE "public"."machine_operation_stitch" (
|
|
3
|
+
"machineId" TEXT NOT NULL,
|
|
4
|
+
"operationId" TEXT NOT NULL,
|
|
5
|
+
"stitches" INTEGER NOT NULL,
|
|
6
|
+
"tenantId" TEXT,
|
|
7
|
+
|
|
8
|
+
CONSTRAINT "machine_operation_stitch_pkey" PRIMARY KEY ("machineId","operationId")
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
-- AddForeignKey
|
|
12
|
+
ALTER TABLE "public"."machine_operation_stitch" ADD CONSTRAINT "machine_operation_stitch_machineId_fkey" FOREIGN KEY ("machineId") REFERENCES "public"."machine"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
13
|
+
|
|
14
|
+
-- AddForeignKey
|
|
15
|
+
ALTER TABLE "public"."machine_operation_stitch" ADD CONSTRAINT "machine_operation_stitch_operationId_fkey" FOREIGN KEY ("operationId") REFERENCES "public"."operation"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
16
|
+
|
|
17
|
+
-- AddForeignKey
|
|
18
|
+
ALTER TABLE "public"."machine_operation_stitch" ADD CONSTRAINT "machine_operation_stitch_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "public"."tenant"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@@ -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[]
|
|
@@ -59,6 +60,9 @@ model Tenant {
|
|
|
59
60
|
users User[]
|
|
60
61
|
userPermissions UserPermission[]
|
|
61
62
|
userShifts UserShift[]
|
|
63
|
+
machineOperationStitch MachineOperationStitch[]
|
|
64
|
+
productivityIntervals ProductivityIntervalCache[]
|
|
65
|
+
aiConversations AiConversation[]
|
|
62
66
|
|
|
63
67
|
@@map("tenant")
|
|
64
68
|
}
|
|
@@ -120,6 +124,8 @@ model DowntimeEvent {
|
|
|
120
124
|
|
|
121
125
|
@@index([operatorId, end_time, elapsedTime])
|
|
122
126
|
@@index([tenantId, operatorId, end_time])
|
|
127
|
+
@@index([machine_id, start_time])
|
|
128
|
+
@@index([downtimeReasonId])
|
|
123
129
|
@@map("downtime_event")
|
|
124
130
|
}
|
|
125
131
|
|
|
@@ -192,6 +198,9 @@ model InputRegister {
|
|
|
192
198
|
productionOrder ProductionOrder? @relation(fields: [productionOrderId], references: [id], onDelete: Cascade)
|
|
193
199
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
194
200
|
|
|
201
|
+
@@index([machineId, timestamp])
|
|
202
|
+
@@index([productionOrderId])
|
|
203
|
+
@@index([tenantId])
|
|
195
204
|
@@map("input_register")
|
|
196
205
|
}
|
|
197
206
|
|
|
@@ -211,6 +220,7 @@ model IotMessageRegister {
|
|
|
211
220
|
machine Machine @relation(fields: [machineId], references: [id], onDelete: Cascade)
|
|
212
221
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
213
222
|
|
|
223
|
+
@@index([machineId, timestamp])
|
|
214
224
|
@@map("iot_message_register")
|
|
215
225
|
}
|
|
216
226
|
|
|
@@ -235,41 +245,50 @@ model ItemsHandlingRegister {
|
|
|
235
245
|
stationTo Machine? @relation("stationTo", fields: [stationToId], references: [id])
|
|
236
246
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
237
247
|
|
|
248
|
+
@@index([productionOrderId])
|
|
249
|
+
@@index([productId])
|
|
250
|
+
@@index([operationId])
|
|
251
|
+
@@index([tenantId])
|
|
238
252
|
@@map("items_handling_register")
|
|
239
253
|
}
|
|
240
254
|
|
|
241
255
|
model Machine {
|
|
242
|
-
id String
|
|
243
|
-
model String?
|
|
244
|
-
name String
|
|
245
|
-
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
|
|
246
260
|
clp_index String?
|
|
247
|
-
acquired_date DateTime?
|
|
248
|
-
macAddress String?
|
|
249
|
-
isDeleted Boolean
|
|
261
|
+
acquired_date DateTime? @db.Date
|
|
262
|
+
macAddress String? @db.VarChar(17)
|
|
263
|
+
isDeleted Boolean @default(false)
|
|
250
264
|
sectorId String?
|
|
251
265
|
tenantId String?
|
|
252
|
-
type MachineType?
|
|
266
|
+
type MachineType? @default(discrete)
|
|
253
267
|
device Device?
|
|
254
268
|
downtime DowntimeEvent[]
|
|
255
269
|
followers Follower[]
|
|
256
270
|
inputRegisters InputRegister[]
|
|
257
271
|
IotMessageRegister IotMessageRegister[]
|
|
258
|
-
stationFrom ItemsHandlingRegister[]
|
|
259
|
-
stationTo ItemsHandlingRegister[]
|
|
260
|
-
sector Sector?
|
|
261
|
-
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)
|
|
262
276
|
MachineFormula MachineFormula[]
|
|
263
277
|
MachineFormulaResult MachineFormulaResult[]
|
|
264
278
|
machineSensors MachineSensors?
|
|
265
279
|
operationRegister OperationRegister[]
|
|
266
280
|
productionNodes ProductionNode?
|
|
267
|
-
operationResources Resource[]
|
|
281
|
+
operationResources Resource[] @relation("MachineToResource")
|
|
268
282
|
processingScriptId String?
|
|
269
|
-
processingScript ProcessingScript?
|
|
283
|
+
processingScript ProcessingScript? @relation(fields: [processingScriptId], references: [id])
|
|
270
284
|
MachineProcessingScript MachineProcessingScript?
|
|
271
285
|
MachineScriptState MachineScriptState?
|
|
286
|
+
machineOperationStitch MachineOperationStitch[]
|
|
287
|
+
productivityIntervals ProductivityIntervalCache[]
|
|
272
288
|
|
|
289
|
+
@@index([sectorId])
|
|
290
|
+
@@index([tenantId])
|
|
291
|
+
@@index([isDeleted])
|
|
273
292
|
@@map("machine")
|
|
274
293
|
}
|
|
275
294
|
|
|
@@ -319,6 +338,8 @@ model MachineFormulaResult {
|
|
|
319
338
|
machine Machine @relation(fields: [machineId], references: [id])
|
|
320
339
|
tenant Tenant? @relation(fields: [tenantId], references: [id])
|
|
321
340
|
|
|
341
|
+
@@index([machineId, timestamp])
|
|
342
|
+
@@index([formulaId])
|
|
322
343
|
@@map("machine_formula_result")
|
|
323
344
|
}
|
|
324
345
|
|
|
@@ -372,37 +393,39 @@ model NotificationToUser {
|
|
|
372
393
|
}
|
|
373
394
|
|
|
374
395
|
model Operation {
|
|
375
|
-
id String
|
|
396
|
+
id String @id @default(cuid())
|
|
376
397
|
stitches Int
|
|
377
398
|
finalIntervalTime Float
|
|
378
399
|
description String
|
|
379
400
|
resourceId String
|
|
380
|
-
timeToProduce Int
|
|
381
|
-
numberOfCuts Int
|
|
382
|
-
nodeId String
|
|
401
|
+
timeToProduce Int @default(10)
|
|
402
|
+
numberOfCuts Int @default(0)
|
|
403
|
+
nodeId String @unique
|
|
383
404
|
nodeIndex Int?
|
|
384
|
-
amount Int
|
|
405
|
+
amount Int @default(1)
|
|
385
406
|
operationId String?
|
|
386
|
-
engineeringTime Int
|
|
387
|
-
initialTime Int
|
|
388
|
-
pcpTime Int
|
|
407
|
+
engineeringTime Int @default(0)
|
|
408
|
+
initialTime Int @default(0)
|
|
409
|
+
pcpTime Int @default(0)
|
|
389
410
|
tenantId String?
|
|
390
411
|
downtimeEvents DowntimeEvent[]
|
|
391
412
|
inputRegisters InputRegister[]
|
|
392
413
|
itemsHandlingRegisters ItemsHandlingRegister[]
|
|
393
414
|
nodeOperationQueue NodeOperationQueue[]
|
|
394
|
-
node Node
|
|
395
|
-
resource Resource
|
|
396
|
-
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)
|
|
397
418
|
operationRegisters OperationRegister[]
|
|
398
|
-
inputOf OperationToOperation[]
|
|
399
|
-
outputOf OperationToOperation[]
|
|
419
|
+
inputOf OperationToOperation[] @relation("inputOperation")
|
|
420
|
+
outputOf OperationToOperation[] @relation("outputOperation")
|
|
400
421
|
products ProductToOperation[]
|
|
401
422
|
productionNodes ProductionNode[]
|
|
402
|
-
operationGroups OperationGroup[]
|
|
423
|
+
operationGroups OperationGroup[] @relation("OperationToOperationGroup")
|
|
403
424
|
// Relações para grupos
|
|
404
|
-
groupMemberships OperationGroupMember[]
|
|
405
|
-
memberOfGroups OperationGroupMember[]
|
|
425
|
+
groupMemberships OperationGroupMember[] @relation("GroupOperations")
|
|
426
|
+
memberOfGroups OperationGroupMember[] @relation("MemberOperations")
|
|
427
|
+
machineOperationStitch MachineOperationStitch[]
|
|
428
|
+
productivityIntervals ProductivityIntervalCache[]
|
|
406
429
|
|
|
407
430
|
@@index([nodeId], map: "idx_operation_node_id")
|
|
408
431
|
@@map("operation")
|
|
@@ -462,6 +485,7 @@ model OperationRegister {
|
|
|
462
485
|
tenantId String?
|
|
463
486
|
quantity Int @default(1)
|
|
464
487
|
timeSinceLastOperation BigInt?
|
|
488
|
+
timeToProduceSnapshot Int?
|
|
465
489
|
machine Machine @relation(fields: [machineId], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "fk_machine")
|
|
466
490
|
operator Operator @relation(fields: [operatorId], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "fk_operator")
|
|
467
491
|
operationGroup OperationGroup? @relation(fields: [operationGroupId], references: [id])
|
|
@@ -472,6 +496,10 @@ model OperationRegister {
|
|
|
472
496
|
|
|
473
497
|
@@index([operatorId, endTime, elapsedTime])
|
|
474
498
|
@@index([tenantId, operatorId, endTime])
|
|
499
|
+
@@index([machineId, startTime])
|
|
500
|
+
@@index([productionOrderId])
|
|
501
|
+
@@index([operationId])
|
|
502
|
+
@@index([productionNodeId])
|
|
475
503
|
@@map("operation_register")
|
|
476
504
|
}
|
|
477
505
|
|
|
@@ -489,25 +517,26 @@ model OperationToOperation {
|
|
|
489
517
|
}
|
|
490
518
|
|
|
491
519
|
model Operator {
|
|
492
|
-
id String
|
|
493
|
-
name String
|
|
520
|
+
id String @id @default(cuid())
|
|
521
|
+
name String @unique
|
|
494
522
|
nickname String?
|
|
495
|
-
birthDate DateTime?
|
|
523
|
+
birthDate DateTime? @db.Date
|
|
496
524
|
phoneNumber String?
|
|
497
525
|
profileImgUrl String?
|
|
498
526
|
stringfiedProfileImgUrl String?
|
|
499
527
|
operatorRoleId String?
|
|
500
528
|
pin String?
|
|
501
|
-
isDeleted Boolean
|
|
529
|
+
isDeleted Boolean @default(false)
|
|
502
530
|
tenantId String?
|
|
503
531
|
deviceOperators DeviceOperator[]
|
|
504
532
|
downtimeEvents DowntimeEvent[]
|
|
505
533
|
operationRegisters OperationRegister[]
|
|
506
|
-
operatorRole OperatorRole?
|
|
507
|
-
tenant Tenant?
|
|
534
|
+
operatorRole OperatorRole? @relation(fields: [operatorRoleId], references: [id])
|
|
535
|
+
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
508
536
|
ProductionNode ProductionNode?
|
|
509
|
-
habilityResources Resource[]
|
|
510
|
-
shifts Shift[]
|
|
537
|
+
habilityResources Resource[] @relation("OperatorToResource")
|
|
538
|
+
shifts Shift[] @relation("OperatorToShift")
|
|
539
|
+
productivityIntervals ProductivityIntervalCache[]
|
|
511
540
|
|
|
512
541
|
@@index([tenantId, isDeleted])
|
|
513
542
|
@@map("operator")
|
|
@@ -579,6 +608,8 @@ model Product {
|
|
|
579
608
|
operations ProductToOperation[]
|
|
580
609
|
productionOrders ProductionOrder[]
|
|
581
610
|
|
|
611
|
+
@@index([tenantId])
|
|
612
|
+
@@index([isDeleted])
|
|
582
613
|
@@map("product")
|
|
583
614
|
}
|
|
584
615
|
|
|
@@ -638,6 +669,9 @@ model ProductionOrder {
|
|
|
638
669
|
Product Product @relation(fields: [productId], references: [id])
|
|
639
670
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
640
671
|
|
|
672
|
+
@@index([tenantId, isFinished])
|
|
673
|
+
@@index([productId])
|
|
674
|
+
@@index([flowId])
|
|
641
675
|
@@map("production_order")
|
|
642
676
|
}
|
|
643
677
|
|
|
@@ -706,6 +740,7 @@ model SewMachineRawData {
|
|
|
706
740
|
tenantId String?
|
|
707
741
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
708
742
|
|
|
743
|
+
@@index([machine_id, start_timestamp])
|
|
709
744
|
@@map("sew_machine_raw_data")
|
|
710
745
|
}
|
|
711
746
|
|
|
@@ -774,6 +809,7 @@ model User {
|
|
|
774
809
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
775
810
|
userPermissions UserPermission[]
|
|
776
811
|
UserShift UserShift[]
|
|
812
|
+
aiConversations AiConversation[]
|
|
777
813
|
|
|
778
814
|
@@map("user")
|
|
779
815
|
}
|
|
@@ -802,6 +838,26 @@ model UserShift {
|
|
|
802
838
|
@@map("user_shift")
|
|
803
839
|
}
|
|
804
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
|
+
|
|
805
861
|
model VerificationToken {
|
|
806
862
|
id String @id @default(cuid())
|
|
807
863
|
token String @unique
|
|
@@ -976,3 +1032,94 @@ enum Colors {
|
|
|
976
1032
|
pink
|
|
977
1033
|
violet
|
|
978
1034
|
}
|
|
1035
|
+
|
|
1036
|
+
model MachineOperationStitch {
|
|
1037
|
+
machineId String
|
|
1038
|
+
operationId String
|
|
1039
|
+
stitches Int
|
|
1040
|
+
tenantId String?
|
|
1041
|
+
|
|
1042
|
+
machine Machine @relation(fields: [machineId], references: [id], onDelete: Cascade)
|
|
1043
|
+
operation Operation @relation(fields: [operationId], references: [id], onDelete: Cascade)
|
|
1044
|
+
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
1045
|
+
|
|
1046
|
+
@@id([machineId, operationId])
|
|
1047
|
+
@@map("machine_operation_stitch")
|
|
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
|
+
}
|