Skip to content

Commit 73db7f8

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 24b92d3 commit 73db7f8

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
@@ -64,6 +64,9 @@ model User {
6464
impersonationsReceived ImpersonationAuditLog[] @relation("ImpersonationTarget")
6565
customerQueries CustomerQuery[]
6666
metricsDashboards MetricsDashboard[]
67+
68+
platformNotifications PlatformNotification[]
69+
platformNotificationInteractions PlatformNotificationInteraction[]
6770
}
6871

6972
model MfaBackupCode {
@@ -225,6 +228,8 @@ model Organization {
225228
githubAppInstallations GithubAppInstallation[]
226229
customerQueries CustomerQuery[]
227230
metricsDashboards MetricsDashboard[]
231+
232+
platformNotifications PlatformNotification[]
228233
}
229234

230235
model OrgMember {
@@ -413,6 +418,8 @@ model Project {
413418
buildSettings Json?
414419
taskScheduleInstances TaskScheduleInstance[]
415420
metricsDashboards MetricsDashboard[]
421+
422+
platformNotifications PlatformNotification[]
416423
}
417424

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

0 commit comments

Comments
 (0)