This project is a collaborative Todo app built with Next.js, Next-Auth, ZenStack, Tanstack Query, Zod, and Tailwind CSS. It's purpose is to test and demonstrate the usage of Prisma and ZenStack in a monorepo setup. All apps and packages are 100% TypeScript and configured as ES Modules.
In this fictitious app, users can be invited to workspaces where they can collaborate on todos. Public todo lists are visible to all members in the workspace. Password authentication is implemented using ZenStack and NextAuth.
Tip
See a live deployment at: https://sample-todo-nextjs-turbo.vercel.app.
For more information on using ZenStack, visit https://zenstack.dev.
-
apps
todo
: a Next.js app
-
packages
-
@erikdakoda
-
auth
: NextAuth configuration; Models for User, Account, Space, and SpaceUser; OwnedItem polymorphic base model declaring created dates, owner, and space -
auth-ui
: React user context and auth components -
database
: Prisma Client and schema; ZenStack generates Tanstack Query hooks, Prisma client, and Zod schemas here -
todo
: Models for Todo, and List -
todo-ui
: React components for Todo and List
-
-
default-configs
: Shared default configs for eslint and tsconfig
-
-
The
@erikdakoda/database
package implements Prisma and ZenStack.-
The data client is configured in
schema.zmodel
in this package, while the models for individual entities reside in their various packages. -
The Prisma Client is generated in the
prisma
folder and then exported from the package. -
Tanstack Query React CRUD hooks are generated in the
hooks
folder. -
Zod schemas are generated in the
zod
folder and are used by ZenStack to validate CRUD operations. You can also use them in conjunction with React Hook Form to validate forms.
-
-
An automatic RESTful API is mounted at
/api/model
inapps/todo/pages/api/model/[...path].ts
. -
On the server side always import the Prisma Client from the database package.
-
In API routes and
getServerSideProps()
usegetEnhancedPrisma()
to get a Prisma Client with extensions and ZenStack enhancements enabled. Permissions with the credentials of the currently signed-in user will be enforced. Seeapps/todo/src/pages/index.tsx
for an example. -
In server code where the context is not available and/or you need to execute administrative tasks, use
import { adminEnhancedPrisma } from '@erikdakoda/database/server/adminEnhancedPrisma'
to get a Prisma Client with extensions and ZenStack enhancements enabled. This Prisma Client impersonates an administrator. -
There is a mechanism for packages to register Prisma Client extensions but it is not yet documented. In the meantime see
@erikdakoda/database/server/prismaExtensions.ts
for a minimal example.
-
-
Setup a database
Rename
apps/todo/.env.example
to.env
. For testing purposes, you can use the sample database provided. This database may be reset periodically. -
Install dependencies
pnpm run pnpm:install
-
Generate server and client-side code from the model
pnpm run zen:generate
-
Synchronize database schema
pnpm run prisma:push
-
Start dev server
pnpm run dev
-
Visit the app at http://localhost:3000
While converting my Prisma/ZenStack project to a monorepo, I learned the following:
-
I had to add
public-hoist-pattern[]='*'
to.npmrc
. I tried just adding*prisma*
and*zenstack*
but I kept getting broken builds. This can probably be fine tuned with more patience. -
I had to add
@prisma/nextjs-monorepo-workaround-plugin
tonext.config.js
-
I had to use the
serverComponentsExternalPackages
experimental option for@zenstackhq/runtime
innext.config.js
-
I had to add my packages to
transpilePackages
innext.config.json
or stange things started happening.
Turborepo can use a technique known as Remote Caching to share cache artifacts across machines, enabling you to share build caches with your team and CI/CD pipelines.
By default, Turborepo will cache locally. To enable Remote Caching you will need an account with Vercel. If you don't have an account you can create one, then enter the following commands:
cd sample-todo-monorepo
npx turbo login
This will authenticate the Turborepo CLI with your Vercel account.
Next, you can link your Turborepo to your Remote Cache by running the following command from the root of your Turborepo:
npx turbo link
Learn more about the power of Turborepo: