sourcebot/packages/db/prisma/schema.prisma
Michael Sukkarieh 173a56ab64
Revamp onboarding flow (#376)
* sign up copy nits

* first pass at new onboarding page

* wip join onboard logic

* refactor auth provider fetch logic

* add member approval and invite link flag logic

* update join request flow and remove jit logic

* onboard guard

* nits, onboard role check, invite link enabled check

* fix bg color issue in onboarding page

* refactor onboard UI

* ui nits and more onboarding resource cards

* revamp auth docs

* change member approval default behavior and updated docs

* merge prisma migrations

* add id to resource card

* feedback

* feedback

* feedback and fixed build

* settings drop down UI nit

* ui nits

* handle join when max capacity case

* add news data for member toggle

* refactor for public access case

* add iap bridge to onboard logic

* fetch member approval req and invite link enabled flag on server

* ui nits

* fix invite link enable toggle snapping issue

* ui nits

* styling and ui nits, pass in invite id from server

* add mcp resource in onboard step

* get invite link in server

* fix build issue

* refactor docs on config

* minor doc nit
2025-07-14 20:14:41 -07:00

313 lines
7.6 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum RepoIndexingStatus {
NEW
IN_INDEX_QUEUE
INDEXING
INDEXED
FAILED
IN_GC_QUEUE
GARBAGE_COLLECTING
GARBAGE_COLLECTION_FAILED
}
enum ConnectionSyncStatus {
SYNC_NEEDED
IN_SYNC_QUEUE
SYNCING
SYNCED
SYNCED_WITH_WARNINGS
FAILED
}
enum StripeSubscriptionStatus {
ACTIVE
INACTIVE
}
model Repo {
id Int @id @default(autoincrement())
name String
displayName String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
/// When the repo was last indexed successfully.
indexedAt DateTime?
isFork Boolean
isArchived Boolean
metadata Json // For schema see repoMetadataSchema in packages/backend/src/types.ts
cloneUrl String
webUrl String?
connections RepoToConnection[]
imageUrl String?
repoIndexingStatus RepoIndexingStatus @default(NEW)
// The id of the repo in the external service
external_id String
// The type of the external service (e.g., github, gitlab, etc.)
external_codeHostType String
// The base url of the external service (e.g., https://github.com)
external_codeHostUrl String
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
orgId Int
searchContexts SearchContext[]
@@unique([external_id, external_codeHostUrl, orgId])
}
model SearchContext {
id Int @id @default(autoincrement())
name String
description String?
repos Repo[]
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
orgId Int
@@unique([name, orgId])
}
model Connection {
id Int @id @default(autoincrement())
name String
config Json
isDeclarative Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
/// When the connection was last synced successfully.
syncedAt DateTime?
repos RepoToConnection[]
syncStatus ConnectionSyncStatus @default(SYNC_NEEDED)
syncStatusMetadata Json?
// The type of connection (e.g., github, gitlab, etc.)
connectionType String
// The organization that owns this connection
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
orgId Int
@@unique([name, orgId])
}
model RepoToConnection {
addedAt DateTime @default(now())
connection Connection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
connectionId Int
repo Repo @relation(fields: [repoId], references: [id], onDelete: Cascade)
repoId Int
@@id([connectionId, repoId])
}
model Invite {
/// The globally unique invite id
id String @id @default(cuid())
/// Time of invite creation
createdAt DateTime @default(now())
/// The email of the recipient of the invite
recipientEmail String
/// The user that created the invite
host User @relation(fields: [hostUserId], references: [id], onDelete: Cascade)
hostUserId String
/// The organization the invite is for
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
orgId Int
@@unique([recipientEmail, orgId])
}
model AccountRequest {
id String @id @default(cuid())
createdAt DateTime @default(now())
requestedBy User @relation(fields: [requestedById], references: [id], onDelete: Cascade)
requestedById String @unique
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
orgId Int
@@unique([requestedById, orgId])
}
model Org {
id Int @id @default(autoincrement())
name String
domain String @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
members UserToOrg[]
connections Connection[]
repos Repo[]
secrets Secret[]
apiKeys ApiKey[]
isOnboarded Boolean @default(false)
imageUrl String?
metadata Json? // For schema see orgMetadataSchema in packages/web/src/types.ts
memberApprovalRequired Boolean @default(true)
stripeCustomerId String?
stripeSubscriptionStatus StripeSubscriptionStatus?
stripeLastUpdatedAt DateTime?
/// List of pending invites to this organization
invites Invite[]
/// The invite id for this organization
inviteLinkEnabled Boolean @default(false)
inviteLinkId String?
audits Audit[]
accountRequests AccountRequest[]
searchContexts SearchContext[]
}
enum OrgRole {
OWNER
MEMBER
GUEST
}
model UserToOrg {
joinedAt DateTime @default(now())
/// The linked organization
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
orgId Int
/// The linked user
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String
role OrgRole @default(MEMBER)
@@id([orgId, userId])
}
model Secret {
orgId Int
key String
encryptedValue String
iv String
createdAt DateTime @default(now())
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
@@id([orgId, key])
}
model ApiKey {
name String
hash String @id @unique
createdAt DateTime @default(now())
lastUsedAt DateTime?
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
orgId Int
createdBy User @relation(fields: [createdById], references: [id], onDelete: Cascade)
createdById String
}
model Audit {
id String @id @default(cuid())
timestamp DateTime @default(now())
action String
actorId String
actorType String
targetId String
targetType String
sourcebotVersion String
metadata Json?
org Org @relation(fields: [orgId], references: [id], onDelete: Cascade)
orgId Int
@@index([actorId, actorType, targetId, targetType, orgId])
// Fast path for analytics queries orgId is first because we assume most deployments are single tenant
@@index([orgId, timestamp, action, actorId], map: "idx_audit_core_actions_full")
// Fast path for analytics queries for a specific user
@@index([actorId, timestamp], map: "idx_audit_actor_time_full")
}
// @see : https://authjs.dev/concepts/database-models#user
model User {
id String @id @default(cuid())
name String?
email String? @unique
hashedPassword String?
emailVerified DateTime?
image String?
accounts Account[]
orgs UserToOrg[]
accountRequest AccountRequest?
/// List of pending invites that the user has created
invites Invite[]
apiKeys ApiKey[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
// @see : https://authjs.dev/concepts/database-models#account
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
// @see : https://authjs.dev/concepts/database-models#verificationtoken
model VerificationToken {
identifier String
token String
expires DateTime
@@unique([identifier, token])
}