@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.
@@ -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,2 @@
1
+ -- RenameIndex
2
+ ALTER INDEX "public"."productivity_interval_cache_tenantId_machineId_group_start_time" RENAME TO "productivity_interval_cache_tenantId_machineId_group_start__idx";
@@ -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.40",
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 = "prisma-client-js"
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 @id @default(cuid())
12
- name String @unique
13
- slug String @unique
14
- domain String? @unique
15
- isActive Boolean @default(true)
16
- createdAt DateTime @default(now())
17
- updatedAt DateTime @updatedAt
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 @id @default(cuid())
243
- model String? @db.VarChar(100)
244
- name String @unique @db.VarChar(100)
245
- capacity Float? @db.Real
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? @db.Date
248
- macAddress String? @db.VarChar(17)
249
- isDeleted Boolean @default(false)
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? @default(discrete)
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[] @relation("stationFrom")
259
- stationTo ItemsHandlingRegister[] @relation("stationTo")
260
- sector Sector? @relation(fields: [sectorId], references: [id])
261
- tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
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[] @relation("MachineToResource")
281
+ operationResources Resource[] @relation("MachineToResource")
268
282
  processingScriptId String?
269
- processingScript ProcessingScript? @relation(fields: [processingScriptId], references: [id])
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 @id @default(cuid())
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 @default(10)
381
- numberOfCuts Int @default(0)
382
- nodeId String @unique
401
+ timeToProduce Int @default(10)
402
+ numberOfCuts Int @default(0)
403
+ nodeId String @unique
383
404
  nodeIndex Int?
384
- amount Int @default(1)
405
+ amount Int @default(1)
385
406
  operationId String?
386
- engineeringTime Int @default(0)
387
- initialTime Int @default(0)
388
- pcpTime Int @default(0)
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 @relation(fields: [nodeId], references: [id], onDelete: Cascade)
395
- resource Resource @relation(fields: [resourceId], references: [id])
396
- tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
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[] @relation("inputOperation")
399
- outputOf OperationToOperation[] @relation("outputOperation")
419
+ inputOf OperationToOperation[] @relation("inputOperation")
420
+ outputOf OperationToOperation[] @relation("outputOperation")
400
421
  products ProductToOperation[]
401
422
  productionNodes ProductionNode[]
402
- operationGroups OperationGroup[] @relation("OperationToOperationGroup")
423
+ operationGroups OperationGroup[] @relation("OperationToOperationGroup")
403
424
  // Relações para grupos
404
- groupMemberships OperationGroupMember[] @relation("GroupOperations")
405
- memberOfGroups OperationGroupMember[] @relation("MemberOperations")
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 @id @default(cuid())
493
- name String @unique
520
+ id String @id @default(cuid())
521
+ name String @unique
494
522
  nickname String?
495
- birthDate DateTime? @db.Date
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 @default(false)
529
+ isDeleted Boolean @default(false)
502
530
  tenantId String?
503
531
  deviceOperators DeviceOperator[]
504
532
  downtimeEvents DowntimeEvent[]
505
533
  operationRegisters OperationRegister[]
506
- operatorRole OperatorRole? @relation(fields: [operatorRoleId], references: [id])
507
- tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
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[] @relation("OperatorToResource")
510
- shifts Shift[] @relation("OperatorToShift")
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
+ }