api: introduce insights table/lint prisma schema

Pedro Lucas Porcellis porcellis@eletrotupi.com 6 days ago 7345b48d923131a3d857706a8b5c39e75fa15b8f
Parents: 9263a7a
3 file(s) changed
  • api/prisma/migrations/20260608193402_create_insights_tables_and_enums/migration.sql +24 -0
  • api/prisma/migrations/20260608201123/migration.sql +8 -0
  • api/prisma/schema.prisma +87 -54
api/prisma/migrations/20260608193402_create_insights_tables_and_enums/migration.sql
@@ -0,0 +1,24 @@
1 + -- CreateEnum
2 + CREATE TYPE "InsightType" AS ENUM ('MOOD_TREND', 'ENERGY_SLEEP_CORRELATION', 'TRIGGER_PATTERN', 'WEEKLY_SUMMARY', 'STREAK');
3 +
4 + -- CreateEnum
5 + CREATE TYPE "InsightPeriod" AS ENUM ('DAILY', 'WEEKLY', 'MONTHLY');
6 +
7 + -- CreateTable
8 + CREATE TABLE "insights" (
9 + "id" SERIAL NOT NULL,
10 + "user_id" INTEGER NOT NULL,
11 + "type" "InsightType" NOT NULL,
12 + "period" "InsightPeriod" NOT NULL,
13 + "title" TEXT NOT NULL,
14 + "body" TEXT NOT NULL,
15 + "metadata" JSONB,
16 + "generated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
17 + "period_start" TIMESTAMP(3) NOT NULL,
18 + "period_end" TIMESTAMP(3) NOT NULL,
19 +
20 + CONSTRAINT "insights_pkey" PRIMARY KEY ("id")
21 + );
22 +
23 + -- AddForeignKey
24 + ALTER TABLE "insights" ADD CONSTRAINT "insights_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
api/prisma/migrations/20260608201123/migration.sql
@@ -0,0 +1,8 @@
1 + /*
2 + Warnings:
3 +
4 + - A unique constraint covering the columns `[user_id,type,period_start]` on the table `insights` will be added. If there are existing duplicate values, this will fail.
5 +
6 + */
7 + -- CreateIndex
8 + CREATE UNIQUE INDEX "insights_user_id_type_period_start_key" ON "insights"("user_id", "type", "period_start");
api/prisma/schema.prisma
@@ -8,41 +8,42 @@ provider = "postgresql"
8 8 }
9 9
10 10 model User {
11 - id Int @id @default(autoincrement())
12 - firstName String @map("first_name")
13 - lastName String? @map("last_name")
14 - email String @unique
15 - encryptedPassword String @map("encrypted_password")
16 - passwordResetToken String? @map("password_reset_token")
11 + id Int @id @default(autoincrement())
12 + firstName String @map("first_name")
13 + lastName String? @map("last_name")
14 + email String @unique
15 + encryptedPassword String @map("encrypted_password")
16 + passwordResetToken String? @map("password_reset_token")
17 17 passwordResetExpires DateTime? @map("password_reset_expires")
18 - createdAt DateTime @default(now()) @map("created_at")
19 - updatedAt DateTime @updatedAt @map("updated_at")
20 - avatarKey String? @map("avatar_key")
21 - avatarURL String? @map("avatar_url")
18 + createdAt DateTime @default(now()) @map("created_at")
19 + updatedAt DateTime @updatedAt @map("updated_at")
20 + avatarKey String? @map("avatar_key")
21 + avatarURL String? @map("avatar_url")
22 22
23 - activationCode String? @map("activation_code")
23 + activationCode String? @map("activation_code")
24 24 activationCodeExpiresAt DateTime? @map("activation_code_expires_at")
25 - active Boolean @default(false) @map("active")
25 + active Boolean @default(false) @map("active")
26 26
27 - moods Mood[]
27 + moods Mood[]
28 28 interventions Intervention[]
29 - triggers Trigger[]
30 - reminders Reminder[]
31 - sleepRecords SleepRecord[]
29 + triggers Trigger[]
30 + reminders Reminder[]
31 + sleepRecords SleepRecord[]
32 + insights Insight[]
32 33
33 34 @@map("users")
34 35 }
35 36
36 37 model Mood {
37 - id Int @id @default(autoincrement())
38 - annotation String? @db.Text
39 - moment DateTime @default(now())
38 + id Int @id @default(autoincrement())
39 + annotation String? @db.Text
40 + moment DateTime @default(now())
40 41 selectedMood BaseMoodOption @default(GOOD) @map("selected_mood")
41 - anxietyLevel Int @map("anxiety_level")
42 - stressLevel Int @map("stress_level")
43 - energyLevel Int @map("energy_level")
44 - userId Int @map("user_id")
45 - user User @relation(fields: [userId], references: [id])
42 + anxietyLevel Int @map("anxiety_level")
43 + stressLevel Int @map("stress_level")
44 + energyLevel Int @map("energy_level")
45 + userId Int @map("user_id")
46 + user User @relation(fields: [userId], references: [id])
46 47
47 48 moodComponents MoodComponent[]
48 49
@@ -50,65 +51,97 @@ @@map("moods")
50 51 }
51 52
52 53 model MoodComponent {
53 - id Int @id @default(autoincrement())
54 + id Int @id @default(autoincrement())
54 55 component MoodComponentOption
55 - intensity IntensityLevel @default(LIGHT)
56 + intensity IntensityLevel @default(LIGHT)
56 57
57 - moodId Int @map("mood_id")
58 - mood Mood @relation(fields: [moodId], references: [id], onDelete: Cascade)
58 + moodId Int @map("mood_id")
59 + mood Mood @relation(fields: [moodId], references: [id], onDelete: Cascade)
59 60
60 61 @@map("mood_components")
61 62 }
62 63
63 64 model Intervention {
64 - id Int @id @default(autoincrement())
65 - comment String?
66 - interventionType InterventionType @map("intervention_type")
67 - eficacy Int
68 - startAt DateTime @map("start_at")
69 - endAt DateTime @map("end_at")
65 + id Int @id @default(autoincrement())
66 + comment String?
67 + interventionType InterventionType @map("intervention_type")
68 + eficacy Int
69 + startAt DateTime @map("start_at")
70 + endAt DateTime @map("end_at")
70 71
71 - userId Int @map("user_id")
72 - user User @relation(fields: [userId], references: [id])
72 + userId Int @map("user_id")
73 + user User @relation(fields: [userId], references: [id])
73 74
74 75 @@map("interventions")
75 76 }
76 77
77 78 model Trigger {
78 - id Int @id @default(autoincrement())
79 - comment String? @db.Text
80 - category TriggerType
81 - moment DateTime @default(now())
79 + id Int @id @default(autoincrement())
80 + comment String? @db.Text
81 + category TriggerType
82 + moment DateTime @default(now())
82 83
83 - userId Int @map("user_id")
84 - user User @relation(fields: [userId], references: [id])
84 + userId Int @map("user_id")
85 + user User @relation(fields: [userId], references: [id])
85 86
86 87 @@map("triggers")
87 88 }
88 89
89 90 model Reminder {
90 - id Int @id @default(autoincrement())
91 - hour Int
92 - minute Int
91 + id Int @id @default(autoincrement())
92 + hour Int
93 + minute Int
93 94 description String?
94 - active Boolean @default(false)
95 + active Boolean @default(false)
95 96
96 - userId Int @map("user_id")
97 - user User @relation(fields: [userId], references: [id])
97 + userId Int @map("user_id")
98 + user User @relation(fields: [userId], references: [id])
98 99
99 100 @@map("reminders")
100 101 }
101 102
102 103 model SleepRecord {
103 - id Int @id @default(autoincrement())
104 - average Float
105 - date DateTime @db.Date
106 - annotations String? @db.Text
104 + id Int @id @default(autoincrement())
105 + average Float
106 + date DateTime @db.Date
107 + annotations String? @db.Text
107 108
108 - userId Int @map("user_id")
109 - user User @relation(fields: [userId], references: [id])
109 + userId Int @map("user_id")
110 + user User @relation(fields: [userId], references: [id])
110 111
111 112 @@map("sleep_records")
113 + }
114 +
115 + model Insight {
116 + id Int @id @default(autoincrement())
117 + userId Int @map("user_id")
118 + user User @relation(fields: [userId], references: [id])
119 +
120 + type InsightType
121 + period InsightPeriod
122 + title String
123 + body String @db.Text
124 + metadata Json? // flexible payload: correlations, deltas, scores
125 + generatedAt DateTime @default(now()) @map("generated_at")
126 + periodStart DateTime @map("period_start")
127 + periodEnd DateTime @map("period_end")
128 +
129 + @@unique([userId, type, periodStart])
130 + @@map("insights")
131 + }
132 +
133 + enum InsightType {
134 + MOOD_TREND
135 + ENERGY_SLEEP_CORRELATION
136 + TRIGGER_PATTERN
137 + WEEKLY_SUMMARY
138 + STREAK
139 + }
140 +
141 + enum InsightPeriod {
142 + DAILY
143 + WEEKLY
144 + MONTHLY
112 145 }
113 146
114 147 enum IntensityLevel {