multi tenancy stuff

This commit is contained in:
m5r
2021-08-06 01:07:15 +08:00
parent b54f9ef43c
commit d20eeb0617
51 changed files with 907 additions and 2542 deletions

View File

@ -0,0 +1,148 @@
/*
Warnings:
- You are about to drop the column `customerId` on the `Message` table. All the data in the column will be lost.
- You are about to drop the column `twilioSid` on the `Message` table. All the data in the column will be lost.
- You are about to drop the column `customerId` on the `NotificationSubscription` table. All the data in the column will be lost.
- You are about to drop the column `customerId` on the `PhoneCall` table. All the data in the column will be lost.
- You are about to drop the column `twilioSid` on the `PhoneCall` table. All the data in the column will be lost.
- You are about to drop the column `customerId` on the `PhoneNumber` table. All the data in the column will be lost.
- You are about to drop the column `phoneNumber` on the `PhoneNumber` table. All the data in the column will be lost.
- You are about to drop the column `phoneNumberSid` on the `PhoneNumber` table. All the data in the column will be lost.
- The `role` column on the `User` table would be dropped and recreated. This will lead to data loss if there is data in the column.
- You are about to drop the `Customer` table. If the table is not empty, all the data it contains will be lost.
- A unique constraint covering the columns `[phoneNumberId,id]` on the table `Message` will be added. If there are existing duplicate values, this will fail.
- A unique constraint covering the columns `[phoneNumberId,id]` on the table `PhoneCall` will be added. If there are existing duplicate values, this will fail.
- A unique constraint covering the columns `[organizationId,id]` on the table `PhoneNumber` will be added. If there are existing duplicate values, this will fail.
- Added the required column `phoneNumberId` to the `Message` table without a default value. This is not possible if the table is not empty.
- Added the required column `organizationId` to the `NotificationSubscription` table without a default value. This is not possible if the table is not empty.
- Added the required column `phoneNumberId` to the `NotificationSubscription` table without a default value. This is not possible if the table is not empty.
- Added the required column `phoneNumberId` to the `PhoneCall` table without a default value. This is not possible if the table is not empty.
- Added the required column `number` to the `PhoneNumber` table without a default value. This is not possible if the table is not empty.
- Added the required column `organizationId` to the `PhoneNumber` table without a default value. This is not possible if the table is not empty.
*/
-- CreateEnum
CREATE TYPE "MembershipRole" AS ENUM ('OWNER', 'ADMIN', 'USER');
-- CreateEnum
CREATE TYPE "GlobalRole" AS ENUM ('SUPERADMIN', 'CUSTOMER');
-- AlterEnum
ALTER TYPE "MessageStatus" ADD VALUE 'Error';
-- DropForeignKey
ALTER TABLE "Customer" DROP CONSTRAINT "Customer_id_fkey";
-- DropForeignKey
ALTER TABLE "Message" DROP CONSTRAINT "Message_customerId_fkey";
-- DropForeignKey
ALTER TABLE "NotificationSubscription" DROP CONSTRAINT "NotificationSubscription_customerId_fkey";
-- DropForeignKey
ALTER TABLE "PhoneCall" DROP CONSTRAINT "PhoneCall_customerId_fkey";
-- DropForeignKey
ALTER TABLE "PhoneNumber" DROP CONSTRAINT "PhoneNumber_customerId_fkey";
-- AlterTable
ALTER TABLE "Message" DROP COLUMN "customerId",
DROP COLUMN "twilioSid",
ADD COLUMN "phoneNumberId" TEXT NOT NULL;
-- AlterTable
ALTER TABLE "NotificationSubscription" DROP COLUMN "customerId",
ADD COLUMN "organizationId" TEXT NOT NULL,
ADD COLUMN "phoneNumberId" TEXT NOT NULL;
-- AlterTable
ALTER TABLE "PhoneCall" DROP COLUMN "customerId",
DROP COLUMN "twilioSid",
ADD COLUMN "phoneNumberId" TEXT NOT NULL;
-- AlterTable
ALTER TABLE "PhoneNumber" DROP COLUMN "customerId",
DROP COLUMN "phoneNumber",
DROP COLUMN "phoneNumberSid",
ADD COLUMN "number" TEXT NOT NULL,
ADD COLUMN "organizationId" TEXT NOT NULL;
-- AlterTable
ALTER TABLE "User" DROP COLUMN "role",
ADD COLUMN "role" "GlobalRole" NOT NULL DEFAULT E'CUSTOMER';
-- DropTable
DROP TABLE "Customer";
-- CreateTable
CREATE TABLE "TwilioCredentials" (
"accountSid" TEXT NOT NULL,
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMPTZ NOT NULL,
"authToken" TEXT NOT NULL,
"twimlAppSid" TEXT,
"organizationId" TEXT NOT NULL,
PRIMARY KEY ("accountSid")
);
-- CreateTable
CREATE TABLE "Organization" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMPTZ NOT NULL,
"encryptionKey" TEXT NOT NULL,
"paddleCustomerId" TEXT,
"paddleSubscriptionId" TEXT,
PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Membership" (
"id" TEXT NOT NULL,
"role" "MembershipRole" NOT NULL,
"organizationId" TEXT NOT NULL,
"userId" TEXT,
"invitedName" TEXT,
"invitedEmail" TEXT,
PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "Membership.organizationId_invitedEmail_unique" ON "Membership"("organizationId", "invitedEmail");
-- CreateIndex
CREATE UNIQUE INDEX "Message.phoneNumberId_id_unique" ON "Message"("phoneNumberId", "id");
-- CreateIndex
CREATE UNIQUE INDEX "PhoneCall.phoneNumberId_id_unique" ON "PhoneCall"("phoneNumberId", "id");
-- CreateIndex
CREATE UNIQUE INDEX "PhoneNumber.organizationId_id_unique" ON "PhoneNumber"("organizationId", "id");
-- AddForeignKey
ALTER TABLE "TwilioCredentials" ADD FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Membership" ADD FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Membership" ADD FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Message" ADD FOREIGN KEY ("phoneNumberId") REFERENCES "PhoneNumber"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "PhoneCall" ADD FOREIGN KEY ("phoneNumberId") REFERENCES "PhoneNumber"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "PhoneNumber" ADD FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "NotificationSubscription" ADD FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "NotificationSubscription" ADD FOREIGN KEY ("phoneNumberId") REFERENCES "PhoneNumber"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -0,0 +1,16 @@
/*
Warnings:
- You are about to drop the `TwilioCredentials` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropForeignKey
ALTER TABLE "TwilioCredentials" DROP CONSTRAINT "TwilioCredentials_organizationId_fkey";
-- AlterTable
ALTER TABLE "Organization" ADD COLUMN "twilioAccountSid" TEXT,
ADD COLUMN "twilioAuthToken" TEXT,
ADD COLUMN "twimlAppSid" TEXT;
-- DropTable
DROP TABLE "TwilioCredentials";

View File

@ -0,0 +1,36 @@
/*
Warnings:
- A unique constraint covering the columns `[organizationId,phoneNumberId,id]` on the table `Message` will be added. If there are existing duplicate values, this will fail.
- A unique constraint covering the columns `[id,twilioAccountSid]` on the table `Organization` will be added. If there are existing duplicate values, this will fail.
- A unique constraint covering the columns `[organizationId,phoneNumberId,id]` on the table `PhoneCall` will be added. If there are existing duplicate values, this will fail.
- Added the required column `organizationId` to the `Message` table without a default value. This is not possible if the table is not empty.
- Added the required column `organizationId` to the `PhoneCall` table without a default value. This is not possible if the table is not empty.
*/
-- DropIndex
DROP INDEX "Message.phoneNumberId_id_unique";
-- DropIndex
DROP INDEX "PhoneCall.phoneNumberId_id_unique";
-- AlterTable
ALTER TABLE "Message" ADD COLUMN "organizationId" TEXT NOT NULL;
-- AlterTable
ALTER TABLE "PhoneCall" ADD COLUMN "organizationId" TEXT NOT NULL;
-- CreateIndex
CREATE UNIQUE INDEX "Message.organizationId_phoneNumberId_id_unique" ON "Message"("organizationId", "phoneNumberId", "id");
-- CreateIndex
CREATE UNIQUE INDEX "Organization.id_twilioAccountSid_unique" ON "Organization"("id", "twilioAccountSid");
-- CreateIndex
CREATE UNIQUE INDEX "PhoneCall.organizationId_phoneNumberId_id_unique" ON "PhoneCall"("organizationId", "phoneNumberId", "id");
-- AddForeignKey
ALTER TABLE "Message" ADD FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "PhoneCall" ADD FOREIGN KEY ("organizationId") REFERENCES "Organization"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -12,18 +12,68 @@ generator client {
// --------------------------------------
model User {
id String @id @default(uuid())
createdAt DateTime @default(now()) @db.Timestamptz
updatedAt DateTime @updatedAt @db.Timestamptz
name String?
email String @unique
hashedPassword String?
role Role @default(USER)
model Organization {
id String @id @default(uuid())
createdAt DateTime @default(now()) @db.Timestamptz
updatedAt DateTime @updatedAt @db.Timestamptz
encryptionKey String
paddleCustomerId String?
paddleSubscriptionId String?
tokens Token[]
sessions Session[]
customer Customer[]
twilioAccountSid String?
twilioAuthToken String? // TODO: encrypt it with encryptionKey
twimlAppSid String?
memberships Membership[]
phoneNumbers PhoneNumber[]
notificationSubscriptions NotificationSubscription[]
messages Message[]
phoneCalls PhoneCall[]
@@unique([id, twilioAccountSid])
}
model Membership {
id String @id @default(uuid())
role MembershipRole
organization Organization @relation(fields: [organizationId], references: [id])
organizationId String
user User? @relation(fields: [userId], references: [id])
userId String?
// When the user joins, we will clear out the name and email and set the user.
invitedName String?
invitedEmail String?
@@unique([organizationId, invitedEmail])
}
enum MembershipRole {
OWNER
ADMIN
USER
}
// The owners of the SaaS (you) can have a SUPERADMIN role to access all data
enum GlobalRole {
SUPERADMIN
CUSTOMER
}
model User {
id String @id @default(uuid())
createdAt DateTime @default(now()) @db.Timestamptz
updatedAt DateTime @updatedAt @db.Timestamptz
name String?
email String @unique
hashedPassword String?
role GlobalRole @default(CUSTOMER)
memberships Membership[]
tokens Token[]
sessions Session[]
}
enum Role {
@ -65,25 +115,6 @@ enum TokenType {
RESET_PASSWORD
}
model Customer {
id String @id
createdAt DateTime @default(now()) @db.Timestamptz
updatedAt DateTime @updatedAt @db.Timestamptz
encryptionKey String
accountSid String?
authToken String?
// TODO: encrypt it with encryptionKey
twimlAppSid String?
paddleCustomerId String?
paddleSubscriptionId String?
user User @relation(fields: [id], references: [id])
messages Message[]
phoneCalls PhoneCall[]
phoneNumbers PhoneNumber[]
notificationSubscriptions NotificationSubscription[]
}
model Message {
id String @id @default(uuid())
sentAt DateTime @db.Timestamptz
@ -92,10 +123,13 @@ model Message {
to String
direction Direction
status MessageStatus
twilioSid String?
customer Customer @relation(fields: [customerId], references: [id])
customerId String
organization Organization @relation(fields: [organizationId], references: [id])
organizationId String
phoneNumber PhoneNumber @relation(fields: [phoneNumberId], references: [id])
phoneNumberId String
@@unique([organizationId, phoneNumberId, id])
}
enum Direction {
@ -117,20 +151,25 @@ enum MessageStatus {
Read
PartiallyDelivered
Canceled
Error
}
model PhoneCall {
id String @id @default(uuid())
id String @id
createdAt DateTime @default(now()) @db.Timestamptz
twilioSid String
from String
to String
status CallStatus
direction Direction
duration String
customer Customer @relation(fields: [customerId], references: [id])
customerId String
organization Organization @relation(fields: [organizationId], references: [id])
organizationId String
phoneNumber PhoneNumber @relation(fields: [phoneNumberId], references: [id])
phoneNumberId String
@@unique([organizationId, phoneNumberId, id])
}
enum CallStatus {
@ -145,13 +184,18 @@ enum CallStatus {
}
model PhoneNumber {
id String @id @default(uuid())
createdAt DateTime @default(now()) @db.Timestamptz
phoneNumberSid String
phoneNumber String
id String @id
createdAt DateTime @default(now()) @db.Timestamptz
number String
customer Customer @relation(fields: [customerId], references: [id])
customerId String
messages Message[]
phoneCalls PhoneCall[]
notificationSubscriptions NotificationSubscription[]
organization Organization @relation(fields: [organizationId], references: [id])
organizationId String
@@unique([organizationId, id])
}
model NotificationSubscription {
@ -163,6 +207,8 @@ model NotificationSubscription {
keys_p256dh String
keys_auth String
customer Customer @relation(fields: [customerId], references: [id])
customerId String
organization Organization @relation(fields: [organizationId], references: [id])
organizationId String
phoneNumber PhoneNumber @relation(fields: [phoneNumberId], references: [id])
phoneNumberId String
}