diff --git a/.github/workflows/db-migration.yml b/.github/workflows/db-migration.yml index e618a7f..9eef53d 100644 --- a/.github/workflows/db-migration.yml +++ b/.github/workflows/db-migration.yml @@ -4,6 +4,7 @@ on: pull_request: paths: - 'prisma/schema.prisma' + - 'prisma.config.ts' - 'prisma/migrations/**' permissions: diff --git a/prisma.config.ts b/prisma.config.ts index 5a946fe..3bb4f68 100644 --- a/prisma.config.ts +++ b/prisma.config.ts @@ -1,3 +1,14 @@ + +import { defineConfig } from "prisma/config"; + +const databaseUrl = + process.env.DATABASE_URL ?? + "postgresql://test_user:test_password@localhost:5432/test_db"; + +export default defineConfig({ + schema: "prisma/schema.prisma", + datasource: { + url: databaseUrl, import { defineConfig } from '@prisma/config'; export default defineConfig({ diff --git a/prisma/migrations/20260622080500_create_organization_entity/migration.sql b/prisma/migrations/20260622080500_create_organization_entity/migration.sql new file mode 100644 index 0000000..809a0dd --- /dev/null +++ b/prisma/migrations/20260622080500_create_organization_entity/migration.sql @@ -0,0 +1,44 @@ +-- CreateTable +CREATE TABLE "organizations" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "ownerId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "organizations_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "organization_members" ( + "id" TEXT NOT NULL, + "organizationId" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "role" TEXT NOT NULL DEFAULT 'member', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "organization_members_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "organizations_slug_key" ON "organizations"("slug"); + +-- CreateIndex +CREATE INDEX "organizations_ownerId_idx" ON "organizations"("ownerId"); + +-- CreateIndex +CREATE INDEX "organization_members_userId_idx" ON "organization_members"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "organization_members_organizationId_userId_key" ON "organization_members"("organizationId", "userId"); + +-- AddForeignKey +ALTER TABLE "organizations" ADD CONSTRAINT "organizations_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "organization_members" ADD CONSTRAINT "organization_members_organizationId_fkey" FOREIGN KEY ("organizationId") REFERENCES "organizations"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "organization_members" ADD CONSTRAINT "organization_members_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 79988ca..342f900 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -7,25 +7,58 @@ datasource db { } model User { - id String @id @default(cuid()) - email String @unique - createdAt DateTime @default(now()) - alerts Alert[] - watchlist Watchlist[] + id String @id @default(cuid()) + email String @unique + createdAt DateTime @default(now()) + alerts Alert[] + watchlist Watchlist[] notificationPreferences NotificationPreference[] auditLogs AuditLog[] + ownedOrganizations Organization[] @relation("OrganizationOwner") + organizationMemberships OrganizationMember[] @@map("users") } +model Organization { + id String @id @default(cuid()) + name String + slug String @unique + ownerId String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + owner User @relation("OrganizationOwner", fields: [ownerId], references: [id]) + members OrganizationMember[] + + @@index([ownerId]) + @@map("organizations") +} + +model OrganizationMember { + id String @id @default(cuid()) + organizationId String + userId String + role String @default("member") + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([organizationId, userId]) + @@index([userId]) + @@map("organization_members") +} + model Alert { - id String @id @default(cuid()) + id String @id @default(cuid()) userId String message String severity String - status String @default("open") - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + status String @default("open") + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt acknowledgedAt DateTime? acknowledgedBy String? @@ -86,8 +119,8 @@ model Proposal { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt - votes Vote[] - events GovernanceEvent[] + votes Vote[] + events GovernanceEvent[] @@map("proposals") } @@ -96,25 +129,25 @@ model Vote { id String @id @default(cuid()) proposalId String voter String - choice String // "yes", "no", "abstain" + choice String // "yes", "no", "abstain" weight String createdAt DateTime @default(now()) - proposal Proposal @relation(fields: [proposalId], references: [id]) + proposal Proposal @relation(fields: [proposalId], references: [id]) @@map("votes") } model GovernanceEvent { id String @id @default(cuid()) - eventType String // "proposal_created", "vote_cast" + eventType String // "proposal_created", "vote_cast" proposalId String? voter String? transactionHash String @unique metadata Json? createdAt DateTime @default(now()) - proposal Proposal? @relation(fields: [proposalId], references: [id]) + proposal Proposal? @relation(fields: [proposalId], references: [id]) @@map("governance_events") } @@ -124,17 +157,17 @@ model GovernanceEvent { // --------------------------------------------------------------------------- model InvestigationNote { - id String @id @default(cuid()) + id String @id @default(cuid()) caseId String authorId String authorName String title String? content String tags String[] - deleted Boolean @default(false) + deleted Boolean @default(false) deletedAt DateTime? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt auditEntries NoteAuditLog[] @@ -145,7 +178,7 @@ model InvestigationNote { model NoteAuditLog { id String @id @default(cuid()) noteId String - action String // "created" | "updated" | "deleted" + action String // "created" | "updated" | "deleted" actorId String actorName String previousValues Json? @@ -156,4 +189,4 @@ model NoteAuditLog { @@index([noteId]) @@map("note_audit_logs") -} \ No newline at end of file +}