Manage stakeholders implemented

This commit is contained in:
adilallo
2026-05-09 23:07:59 -06:00
parent 534c6c7c0e
commit 9f2141a62d
43 changed files with 2082 additions and 93 deletions
@@ -0,0 +1,35 @@
-- CreateTable
CREATE TABLE "RuleStakeholder" (
"id" TEXT NOT NULL,
"ruleId" TEXT NOT NULL,
"email" TEXT NOT NULL,
"invitedByUserId" TEXT,
"userId" TEXT,
"inviteTokenHash" TEXT,
"inviteExpiresAt" TIMESTAMP(3),
"invitedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"acceptedAt" TIMESTAMP(3),
CONSTRAINT "RuleStakeholder_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "RuleStakeholder_inviteTokenHash_key" ON "RuleStakeholder"("inviteTokenHash");
-- CreateIndex
CREATE INDEX "RuleStakeholder_userId_idx" ON "RuleStakeholder"("userId");
-- CreateIndex
CREATE INDEX "RuleStakeholder_email_idx" ON "RuleStakeholder"("email");
-- CreateIndex
CREATE UNIQUE INDEX "RuleStakeholder_ruleId_email_key" ON "RuleStakeholder"("ruleId", "email");
-- AddForeignKey
ALTER TABLE "RuleStakeholder" ADD CONSTRAINT "RuleStakeholder_ruleId_fkey" FOREIGN KEY ("ruleId") REFERENCES "PublishedRule"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "RuleStakeholder" ADD CONSTRAINT "RuleStakeholder_invitedByUserId_fkey" FOREIGN KEY ("invitedByUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "RuleStakeholder" ADD CONSTRAINT "RuleStakeholder_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
+30
View File
@@ -18,6 +18,10 @@ model User {
rules PublishedRule[]
/// At most one pending verified email change (CR-103).
emailChangeToken EmailChangeToken?
/// Rules this user was invited to as a stakeholder (after accepting invite).
ruleStakeholders RuleStakeholder[] @relation("RuleStakeholderUser")
/// Stakeholder rows where this user sent the invite.
stakeholderInvitesSent RuleStakeholder[] @relation("RuleStakeholderInvitedBy")
}
/// Pending email change: user must open verify link sent to `newEmail` (CR-103).
@@ -74,9 +78,35 @@ model PublishedRule {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
stakeholders RuleStakeholder[]
@@index([userId])
}
/// Invite + access for a published rule: email invite at publish; userId set after magic-link-style accept.
model RuleStakeholder {
id String @id @default(cuid())
ruleId String
rule PublishedRule @relation(fields: [ruleId], references: [id], onDelete: Cascade)
/// Normalized lowercase email (invite target).
email String
/// Publisher at invite time; null if that account was removed.
invitedByUserId String?
invitedBy User? @relation("RuleStakeholderInvitedBy", fields: [invitedByUserId], references: [id], onDelete: SetNull)
/// Set when the invitee completes the verify link (same account as `email`).
userId String?
user User? @relation("RuleStakeholderUser", fields: [userId], references: [id], onDelete: SetNull)
/// One-time invite token (hashed); null after accept or revoke path (consume on verify).
inviteTokenHash String? @unique
inviteExpiresAt DateTime?
invitedAt DateTime @default(now())
acceptedAt DateTime?
@@unique([ruleId, email])
@@index([userId])
@@index([email])
}
model RuleTemplate {
id String @id @default(cuid())
slug String @unique