@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.
@@ -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.41",
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[]
@@ -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 @id @default(cuid())
244
- model String? @db.VarChar(100)
245
- name String @unique @db.VarChar(100)
246
- 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
247
260
  clp_index String?
248
- acquired_date DateTime? @db.Date
249
- macAddress String? @db.VarChar(17)
250
- isDeleted Boolean @default(false)
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? @default(discrete)
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[] @relation("stationFrom")
260
- stationTo ItemsHandlingRegister[] @relation("stationTo")
261
- sector Sector? @relation(fields: [sectorId], references: [id])
262
- 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)
263
276
  MachineFormula MachineFormula[]
264
277
  MachineFormulaResult MachineFormulaResult[]
265
278
  machineSensors MachineSensors?
266
279
  operationRegister OperationRegister[]
267
280
  productionNodes ProductionNode?
268
- operationResources Resource[] @relation("MachineToResource")
281
+ operationResources Resource[] @relation("MachineToResource")
269
282
  processingScriptId String?
270
- processingScript ProcessingScript? @relation(fields: [processingScriptId], references: [id])
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 @id @default(cuid())
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 @default(10)
383
- numberOfCuts Int @default(0)
384
- nodeId String @unique
401
+ timeToProduce Int @default(10)
402
+ numberOfCuts Int @default(0)
403
+ nodeId String @unique
385
404
  nodeIndex Int?
386
- amount Int @default(1)
405
+ amount Int @default(1)
387
406
  operationId String?
388
- engineeringTime Int @default(0)
389
- initialTime Int @default(0)
390
- pcpTime Int @default(0)
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 @relation(fields: [nodeId], references: [id], onDelete: Cascade)
397
- resource Resource @relation(fields: [resourceId], references: [id])
398
- 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)
399
418
  operationRegisters OperationRegister[]
400
- inputOf OperationToOperation[] @relation("inputOperation")
401
- outputOf OperationToOperation[] @relation("outputOperation")
419
+ inputOf OperationToOperation[] @relation("inputOperation")
420
+ outputOf OperationToOperation[] @relation("outputOperation")
402
421
  products ProductToOperation[]
403
422
  productionNodes ProductionNode[]
404
- operationGroups OperationGroup[] @relation("OperationToOperationGroup")
423
+ operationGroups OperationGroup[] @relation("OperationToOperationGroup")
405
424
  // Relações para grupos
406
- groupMemberships OperationGroupMember[] @relation("GroupOperations")
407
- memberOfGroups OperationGroupMember[] @relation("MemberOperations")
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 @id @default(cuid())
496
- name String @unique
520
+ id String @id @default(cuid())
521
+ name String @unique
497
522
  nickname String?
498
- birthDate DateTime? @db.Date
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 @default(false)
529
+ isDeleted Boolean @default(false)
505
530
  tenantId String?
506
531
  deviceOperators DeviceOperator[]
507
532
  downtimeEvents DowntimeEvent[]
508
533
  operationRegisters OperationRegister[]
509
- operatorRole OperatorRole? @relation(fields: [operatorRoleId], references: [id])
510
- 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)
511
536
  ProductionNode ProductionNode?
512
- habilityResources Resource[] @relation("OperatorToResource")
513
- shifts Shift[] @relation("OperatorToShift")
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
+ }