My App
BoardKitBackend

Prisma Adapter

PrismaBoardAdapter setup and Prisma schema reference

PrismaBoardAdapter implements BoardStorage using Prisma. It uses structural typing and never imports @prisma/client directly.

Setup

import { PrismaBoardAdapter } from '@hfu.digital/boardkit-nestjs';
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

const boardStorage = new PrismaBoardAdapter({
    board: prisma.board,
    page: prisma.page,
    element: prisma.element,
    boardMember: prisma.boardMember,
    shareLink: prisma.shareLink,
});

Configuration Interface

interface PrismaBoardAdapterConfig {
    board: PrismaDelegate;
    page: PrismaDelegate;
    element: PrismaElementDelegate;
    boardMember: PrismaBoardMemberDelegate;
    shareLink: PrismaShareLinkDelegate;
}

Each delegate matches the structural shape of Prisma model clients (e.g., prisma.board). This means you can use any ORM or database client that provides the same method signatures.

Prisma Schema

Here is a reference Prisma schema for the required models:

model Board {
    id          String   @id @default(uuid())
    name        String
    ownerId     String
    sessionType String   @default("persistent")
    isArchived  Boolean  @default(false)
    createdAt   DateTime @default(now())
    updatedAt   DateTime @updatedAt

    pages       Page[]
    members     BoardMember[]
    shareLinks  ShareLink[]
}

model Page {
    id        String   @id @default(uuid())
    boardId   String
    name      String
    order     Int
    thumbnail String?
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt

    board    Board     @relation(fields: [boardId], references: [id], onDelete: Cascade)
    elements Element[]
}

model Element {
    id        String   @id @default(uuid())
    pageId    String
    type      String
    data      Json
    zIndex    Int
    lockedBy  String?
    createdBy String
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt

    page Page @relation(fields: [pageId], references: [id], onDelete: Cascade)
}

model BoardMember {
    id       String   @id @default(uuid())
    boardId  String
    userId   String
    role     String
    joinedAt DateTime @default(now())

    board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)

    @@unique([boardId, userId])
}

model ShareLink {
    id         String   @id @default(uuid())
    boardId    String
    token      String   @unique
    permission String
    expiresAt  DateTime?
    createdAt  DateTime @default(now())

    board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
}

model BoardEvent {
    id        String   @id @default(uuid())
    boardId   String
    pageId    String?
    type      String
    payload   Json
    userId    String
    sequence  Int
    timestamp DateTime @default(now())

    @@index([boardId, sequence])
}

model BoardSnapshot {
    id            String   @id @default(uuid())
    boardId       String
    snapshotData  Json
    eventSequence Int
    createdAt     DateTime @default(now())

    @@index([boardId])
}

How It Works

  • Board CRUD: Direct Prisma create, findUnique, findMany, update, delete
  • Page ordering: Pages are sorted by order field; reorderPages updates each page's order
  • Element upsert: Uses Prisma's upsert for each element (create if new, update if existing)
  • Element batch delete: Uses deleteMany with id: { in: ids }
  • Share links: Token generated with crypto.randomUUID(), expiration checked on resolve
  • Members: Uses findFirst to check existence, then create or update

On this page