Skip to content

Express + Prisma example ​

apps/example/prisma-test/ is the Prisma dogfood app in this repository. It is not the library. It is the story the Trust guides keep pointing at.

To copy the same createAdmin / register options into your server, follow Wire it into your app.

The TypeORM twin is Express + TypeORM.

What is in it ​

Prisma models: User, Post, Tenant, AdminAuditLog.

Only User and Post are registered. Tenant is a join key. The audit table is write-only from audit.write.

The seed creates application users and tenant data. Administrator accounts are separate and are created with the superuser command.

Run it ​

From the repository root (this is for people cloning the repo, not npm install consumers):

bash
pnpm install
pnpm --filter paneljs build
pnpm --filter @paneljs/express build
pnpm --filter @paneljs/prisma build
pnpm --filter @paneljs/example db:up

cp apps/example/prisma-test/.env.example apps/example/prisma-test/.env

pnpm --filter @paneljs/example db:generate
pnpm --filter @paneljs/example db:push
pnpm --filter @paneljs/example db:seed
pnpm --filter @paneljs/example admin:createsuperuser
pnpm --filter @paneljs/example dev

Open http://localhost:3000/admin/login and sign in with the superuser you created.

What the host actually configures ​

ts
const admin = createAdmin({
  adapter: prismaAdapter({ prisma }),
  siteName: "Express Admins",
  auth: {
    mode: "built-in",
    identifier: "email",
    secureCookies: false,
  },
  audit: {
    write: async (event) => {
      /* AdminAuditLog.create */
    },
  },
});

admin.register("User", {
  listDisplay: ["email", "fullName", "role", "isActive"],
  listFilter: ["role", "isActive"],
  searchFields: ["email", "fullName"],
  scope: async (adminUser) =>
    adminUser.isSuperAdmin
      ? {}
      : { tenantId: adminUser.tenantId ?? "__no_tenant__" },
});

admin.register("Post", {
  listDisplay: ["title", "author", "published", "createdAt"],
  listFilter: ["published", "createdAt"],
  searchFields: ["title", "content"],
  scope: async (adminUser) =>
    adminUser.isSuperAdmin
      ? {}
      : { tenantId: adminUser.tenantId ?? "__no_tenant__" },
  actions: [
    /* publish_selected, unpublish_selected */
  ],
});

What you should see ​

As a superuser: both tenants, both posts, and both author lists. Create an ExpressAdminUser with role ADMIN and a seeded tenantId to try the scoped administrator view.

If any of that fails, scope is not on that path. File an issue — that is a security bug, not a missing feature.

Source ​

apps/example/prisma-test on GitHub.

Released under the MIT License.