trpc + next.js + prisma + PostgreSQL
coolify 自动化部署
数据表结构:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
///////////////////////
// User & Accounts //
///////////////////////
model User {
id String @id @default(cuid())
walletAddress String @unique @db.VarChar(42)
ensName String? @db.VarChar(255)
name String?
avatar String?
bio String?
links Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
ownedProjects Project[] @relation("ProjectOwner")
contributions ContributionContributor[]
votes Vote[]
projectMembers ProjectMember[]
@@index([createdAt(sort: Desc)], map: "idx_user_created_desc")
@@index([deletedAt])
@@map("users")
}
///////////////////////
// Projects //
///////////////////////
model Project {
id String @id @default(cuid())
key String @unique(map: "uq_project_key")
name String
description String
logo String?
links Json?
tokenSymbol String?
status ProjectStatus @default(ACTIVE)
validateType ProjectValidateType @default(SPECIFIC_MEMBERS)
approvalStrategy Json?
submitStrategy ProjectSubmitStrategy @default(EVERYONE)
ownerId String
owner User @relation("ProjectOwner", fields: [ownerId], references: [id])
contributions Contribution[]
members ProjectMember[]
defaultHourRate Float?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
@@index([status, createdAt(sort: Desc)], map: "idx_project_status_created")
@@index([ownerId])
@@index([deletedAt])
@@map("projects")
}
enum ProjectStatus {
ACTIVE
PAUSED
COMPLETED
ARCHIVED
}
enum ProjectValidateType {
SPECIFIC_MEMBERS
ALL_MEMBERS
}
enum ProjectSubmitStrategy {
EVERYONE
RESTRICTED
}
///////////////////////
// ProjectMember //
///////////////////////
model ProjectMember {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id])
projectId String
project Project @relation(fields: [projectId], references: [id])
role MemberRole[] @default([CONTRIBUTOR])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
@@unique([userId, projectId])
@@index([userId])
@@index([projectId])
@@index([role], type: Gin)
@@map("project_members")
}
enum MemberRole {
ADMIN
VALIDATOR
CONTRIBUTOR
}
///////////////////////
// Contributions //
///////////////////////
model Contribution {
id String @id @default(cuid())
content String
hours Float?
tags String[] @default([])
startAt DateTime?
endAt DateTime?
status ContributionStatus @default(VALIDATING)
projectId String
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
contributors ContributionContributor[]
votes Vote[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
@@index([projectId, status, createdAt(sort: Desc)], map: "idx_contrib_proj_status_time")
@@index([deletedAt])
@@index([tags], type: Gin)
@@map("contributions")
}
enum ContributionStatus {
VALIDATING
PASSED
FAILED
ON_CHAIN
}
///////////////////////
// Votes //
///////////////////////
model Vote {
id String @id @default(cuid())
type VoteType
voterId String
voter User @relation(fields: [voterId], references: [id])
contributionId String
contribution Contribution @relation(fields: [contributionId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
@@unique([voterId, contributionId])
@@index([contributionId])
@@index([voterId])
@@index([type])
@@index([createdAt(sort: Desc)])
@@map("votes")
}
enum VoteType {
PASS
FAIL
SKIP
}
///////////////////////
// Contributors ↔ //
///////////////////////
model ContributionContributor {
id String @id @default(cuid())
contributionId String
contribution Contribution @relation(fields: [contributionId], references: [id], onDelete: Cascade)
contributorId String
contributor User @relation(fields: [contributorId], references: [id])
hours Float?
points Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
@@unique([contributionId, contributorId])
@@index([contributorId])
@@index([contributionId])
@@index([contributorId, createdAt(sort: Desc)], map: "idx_contributor_time")
@@index([createdAt(sort: Desc)])
@@map("contribution_contributors")
}