Skip to content

Add a Prisma Model

Canonical example: Faq model at libs/_prisma/src/schema/api.prisma:113-123.

1. Pick the right schema file

The Prisma schema is split across three files under libs/_prisma/src/schema/. Each maps to a PostgreSQL schema:

File PG schema What goes here
api.prisma public Everything except game-server tables
blackjack.prisma blackjack Blackjack tables/hands/configs
speed_roulette.prisma speed_roulette Speed-roulette rounds/bets

The generator and datasource blocks live only in api.prisma:1-14 — don't duplicate them.

2. Define the model

Add your model at the bottom of the chosen file. Follow the existing conventions exactly:

model Announcement {
  id        Int      @id @default(autoincrement()) @map("id")
  title     String   @map("title")
  body      String   @map("body")
  active    Boolean  @default(true) @map("active")
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  @@map("announcement")
  @@schema("public")
}

Conventions enforced by the codebase:

  • @map("snake_case") on every field — Prisma uses camelCase in TypeScript, the DB uses snake_case.
  • @@map("table_name") — sets the Postgres table name.
  • @@schema("public") — required because multiSchema is enabled (api.prisma:3).
  • @id @default(autoincrement()) for integer PKs, or @id @default(uuid()) for UUID PKs (see UserFairnessSeeds at api.prisma:147).
  • @default(now()) on createdAt, @updatedAt on updatedAt.

Adding a relation

Follow the UserNote pattern (api.prisma:322-337):

model Announcement {
  id        Int      @id @default(autoincrement()) @map("id")
  title     String   @map("title")
  body      String   @map("body")
  active    Boolean  @default(true) @map("active")
  authorId  Int      @map("author_id")
  author    User     @relation(fields: [authorId], references: [id])
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  @@index([authorId])
  @@map("announcement")
  @@schema("public")
}

Then add the back-relation on the User model:

// inside model User { ... }
announcements Announcement[]

Adding an enum

Define it next to the model. Every enum also needs @@map and @@schema:

enum AnnouncementPriority {
  LOW
  NORMAL
  HIGH

  @@map("announcement_priority")
  @@schema("public")
}

3. Generate the migration

cd ebit-api
npm run db:migrate:dev
# Prisma prompts for a migration name — use snake_case: add_announcement

This does three things in one command: 1. Diffs your schema against the database 2. Creates a SQL migration file under libs/_prisma/src/schema/migrations/<timestamp>_add_announcement/migration.sql 3. Applies the migration and regenerates the Prisma Client

All prisma commands are wrapped with env-cmd -f .env (package.json:23) — never call npx prisma directly or it will miss the DATABASE_URL.

To create a migration without applying it (for review):

npm run db:migrate:dev:create

4. Regenerate the client (if needed separately)

npm run db:generate        # package.json:25

The generated client lands at node_modules/.prisma/client (no custom output in the generator block at api.prisma:1-4). Import it as:

import { PrismaClient, Announcement } from '@prisma/client';

5. Add seed data

Create libs/_prisma/src/seed/announcement.ts:

import prisma from './prisma';

export default async function announcement() {
  await prisma.announcement.upsert({
    where: { id: 1 },
    update: {},
    create: {
      title: 'Welcome',
      body: 'First announcement',
      active: true,
    },
  });
}

Register it in libs/_prisma/src/seed/index.ts:26-54 — add the import at the top and call await announcement() inside main():

import announcement from './announcement';

async function main() {
  // ... existing seeds ...
  await announcement();       // add at the end of the non-debug block
}

Use upsert so the seed is idempotent — it won't fail on re-runs.

6. Wire it into the app

Create a repository (standard NestJS pattern — see apps/api/src/bet/bet.repository.ts):

import { Injectable } from '@nestjs/common';
import { PrismaService } from '@app/_prisma';

@Injectable()
export class AnnouncementRepository {
  constructor(private readonly prisma: PrismaService) {}

  findMany() {
    return this.prisma.announcement.findMany({
      where: { active: true },
      orderBy: { createdAt: 'desc' },
    });
  }
}

Register it as a provider in your module.

Useful commands

Command Purpose
npm run db:migrate:dev Create + apply migration + regen client
npm run db:migrate:dev:create Create migration only (review before applying)
npm run db:seed Re-run all seeds
npm run db:reset Drop + recreate + migrate + seed (destructive)
npm run db:studio Open Prisma Studio GUI at localhost:5555
npm run prisma:dev:test Migrate the test database (uses .env.test)

You're done — test by...

npm run db:migrate:dev
npm run db:seed
npm run db:studio
# Open Prisma Studio → click "Announcement" → verify your seed row exists