Skip to content

Commit 2a85194

Browse files
committed
feat(db): add platform notification models and relations
Add PlatformNotification and PlatformNotificationInteraction Prisma models, including enums PlatformNotificationSurface and PlatformNotificationScope, indexes, timestamps, and fields for scoping (user, project, organization), lifecycle (startsAt, endsAt, archivedAt) and delivery behavior (CLI-specific fields, priority). Wire new relations into User, Organization, Project, OrgMember and Workspace models so notifications and interactions can be queried from those entities. Add SQL migration to create the new enums and adjust schema constraints and indexes required for the migration. The change enables admin-created, scoped platform notifications with per-user interaction tracking for both webapp and CLI surfaces.
1 parent dbbe9f7 commit 2a85194

File tree

2 files changed

+167
-0
lines changed

2 files changed

+167
-0
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
-- CreateEnum
2+
CREATE TYPE "public"."PlatformNotificationSurface" AS ENUM ('WEBAPP', 'CLI');
3+
4+
-- CreateEnum
5+
CREATE TYPE "public"."PlatformNotificationScope" AS ENUM ('USER', 'PROJECT', 'ORGANIZATION', 'GLOBAL');
6+
7+
-- CreateTable
8+
CREATE TABLE "public"."PlatformNotification" (
9+
"id" TEXT NOT NULL,
10+
"friendlyId" TEXT NOT NULL,
11+
"title" TEXT NOT NULL,
12+
"payload" JSONB NOT NULL,
13+
"surface" "public"."PlatformNotificationSurface" NOT NULL,
14+
"scope" "public"."PlatformNotificationScope" NOT NULL,
15+
"userId" TEXT,
16+
"organizationId" TEXT,
17+
"projectId" TEXT,
18+
"startsAt" TIMESTAMP(3) NOT NULL,
19+
"endsAt" TIMESTAMP(3),
20+
"cliMaxDaysAfterFirstSeen" INTEGER,
21+
"cliMaxShowCount" INTEGER,
22+
"priority" INTEGER NOT NULL DEFAULT 0,
23+
"archivedAt" TIMESTAMP(3),
24+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
25+
"updatedAt" TIMESTAMP(3) NOT NULL,
26+
27+
CONSTRAINT "PlatformNotification_pkey" PRIMARY KEY ("id")
28+
);
29+
30+
-- CreateTable
31+
CREATE TABLE "public"."PlatformNotificationInteraction" (
32+
"id" TEXT NOT NULL,
33+
"notificationId" TEXT NOT NULL,
34+
"userId" TEXT NOT NULL,
35+
"firstSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
36+
"showCount" INTEGER NOT NULL DEFAULT 1,
37+
"webappDismissedAt" TIMESTAMP(3),
38+
"cliDismissedAt" TIMESTAMP(3),
39+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
40+
"updatedAt" TIMESTAMP(3) NOT NULL,
41+
42+
CONSTRAINT "PlatformNotificationInteraction_pkey" PRIMARY KEY ("id")
43+
);
44+
45+
-- CreateIndex
46+
CREATE UNIQUE INDEX "PlatformNotification_friendlyId_key" ON "public"."PlatformNotification"("friendlyId");
47+
48+
-- CreateIndex
49+
CREATE INDEX "PlatformNotification_surface_scope_startsAt_idx" ON "public"."PlatformNotification"("surface", "scope", "startsAt");
50+
51+
-- CreateIndex
52+
CREATE UNIQUE INDEX "PlatformNotificationInteraction_notificationId_userId_key" ON "public"."PlatformNotificationInteraction"("notificationId", "userId");
53+
54+
-- AddForeignKey
55+
ALTER TABLE "public"."PlatformNotification" ADD CONSTRAINT "PlatformNotification_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
56+
57+
-- AddForeignKey
58+
ALTER TABLE "public"."PlatformNotification" ADD CONSTRAINT "PlatformNotification_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "public"."Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
59+
60+
-- AddForeignKey
61+
ALTER TABLE "public"."PlatformNotification" ADD CONSTRAINT "PlatformNotification_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "public"."Project"("id") ON DELETE CASCADE ON UPDATE CASCADE;
62+
63+
-- AddForeignKey
64+
ALTER TABLE "public"."PlatformNotificationInteraction" ADD CONSTRAINT "PlatformNotificationInteraction_notificationId_fkey" FOREIGN KEY ("notificationId") REFERENCES "public"."PlatformNotification"("id") ON DELETE CASCADE ON UPDATE CASCADE;
65+
66+
-- AddForeignKey
67+
ALTER TABLE "public"."PlatformNotificationInteraction" ADD CONSTRAINT "PlatformNotificationInteraction_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

internal-packages/database/prisma/schema.prisma

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ model User {
6565
impersonationsReceived ImpersonationAuditLog[] @relation("ImpersonationTarget")
6666
customerQueries CustomerQuery[]
6767
metricsDashboards MetricsDashboard[]
68+
69+
platformNotifications PlatformNotification[]
70+
platformNotificationInteractions PlatformNotificationInteraction[]
6871
}
6972

7073
model MfaBackupCode {
@@ -228,6 +231,8 @@ model Organization {
228231
githubAppInstallations GithubAppInstallation[]
229232
customerQueries CustomerQuery[]
230233
metricsDashboards MetricsDashboard[]
234+
235+
platformNotifications PlatformNotification[]
231236
}
232237

233238
model OrgMember {
@@ -417,6 +422,8 @@ model Project {
417422
onboardingData Json?
418423
taskScheduleInstances TaskScheduleInstance[]
419424
metricsDashboards MetricsDashboard[]
425+
426+
platformNotifications PlatformNotification[]
420427
}
421428

422429
enum ProjectVersion {
@@ -2577,3 +2584,96 @@ model MetricsDashboard {
25772584
/// Fast lookup for the list
25782585
@@index([projectId, createdAt(sort: Desc)])
25792586
}
2587+
2588+
enum PlatformNotificationSurface {
2589+
WEBAPP
2590+
CLI
2591+
}
2592+
2593+
enum PlatformNotificationScope {
2594+
USER
2595+
PROJECT
2596+
ORGANIZATION
2597+
GLOBAL
2598+
}
2599+
2600+
/// Admin-created notification definitions
2601+
model PlatformNotification {
2602+
id String @id @default(cuid())
2603+
2604+
friendlyId String @unique @default(cuid())
2605+
2606+
/// Admin-facing title for identification in admin tools
2607+
title String
2608+
2609+
/// Versioned JSON rendering content (see payload schema in spec)
2610+
payload Json
2611+
2612+
surface PlatformNotificationSurface
2613+
scope PlatformNotificationScope
2614+
2615+
/// Set when scope = USER
2616+
user User? @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
2617+
userId String?
2618+
2619+
/// Set when scope = ORGANIZATION
2620+
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
2621+
organizationId String?
2622+
2623+
/// Set when scope = PROJECT
2624+
project Project? @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade)
2625+
projectId String?
2626+
2627+
/// When notification becomes active
2628+
startsAt DateTime
2629+
2630+
/// When notification expires. Null = persists until dismissed or archived
2631+
endsAt DateTime?
2632+
2633+
/// CLI: auto-expire N days after user first saw it
2634+
cliMaxDaysAfterFirstSeen Int?
2635+
2636+
/// CLI: auto-expire after shown N times to user
2637+
cliMaxShowCount Int?
2638+
2639+
/// Ordering within same scope level (higher = more important)
2640+
priority Int @default(0)
2641+
2642+
/// Soft delete
2643+
archivedAt DateTime?
2644+
2645+
createdAt DateTime @default(now())
2646+
updatedAt DateTime @updatedAt
2647+
2648+
interactions PlatformNotificationInteraction[]
2649+
2650+
@@index([surface, scope, startsAt])
2651+
}
2652+
2653+
/// Per-user tracking of notification views and dismissals
2654+
model PlatformNotificationInteraction {
2655+
id String @id @default(cuid())
2656+
2657+
notification PlatformNotification @relation(fields: [notificationId], references: [id], onDelete: Cascade, onUpdate: Cascade)
2658+
notificationId String
2659+
2660+
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
2661+
userId String
2662+
2663+
/// Set by beacon/CLI GET on first impression
2664+
firstSeenAt DateTime @default(now())
2665+
2666+
/// Times shown (incremented per beacon/CLI view)
2667+
showCount Int @default(1)
2668+
2669+
/// User dismissed in webapp
2670+
webappDismissedAt DateTime?
2671+
2672+
/// Auto-dismissed or expired in CLI
2673+
cliDismissedAt DateTime?
2674+
2675+
createdAt DateTime @default(now())
2676+
updatedAt DateTime @updatedAt
2677+
2678+
@@unique([notificationId, userId])
2679+
}

0 commit comments

Comments
 (0)