A Next.js document management application built to teach Role-Based Access Control (RBAC), Attribute-Based Access Control (ABAC), and Relationship-Based Access Control (ReBAC) concepts.
Watch the Permission Systems that Scale course on Frontend Masters
This project is broken down into different phases which correspond to specific Git branches:
1-basic-permissions2-fix-basic-permission-errors3-add-service-layer3.5-basic-rbac-checkpoint4-basic-rbac5-rbac-limits5.5-basic-abac-checkpoint6-basic-abac7-advanced-abac8-casl
Make sure you have the following installed:
- Node.js v20 or higher
- Docker (for running PostgreSQL)
- Git
- A code editor (VS Code recommended)
git clone https://github.com/WebDevSimplified/fem-permission-systems-that-scale-demo-project.git
cd fem-permission-systems-that-scale-demo-project
git checkout 1-basic-permissionsnpm installThe project includes a Docker Compose file for PostgreSQL. Start it with:
docker compose upThis will start a PostgreSQL container on port 5432.
Don't have Docker? You can use any PostgreSQL instance. Just update the connection details in your environment variables.
Create a .env file in the root directory with the following variables if it doesn't already exist:
DB_PASSWORD=password
DB_USER=postgres
DB_NAME=permissions-demo
DB_HOST=localhost
DB_PORT=5432
Apply the database schema using Drizzle:
npm run db:pushPopulate the database with sample users, projects, and documents:
npm run db:seednpm run devOpen http://localhost:3000 in your browser.
You should see a login page with quick-login buttons for different users. Try logging in as different users to see the application from different permission perspectives.
The application has three main entities with clear relationships:
Users are the people who interact with the application. Each user has:
| Field | Description |
|---|---|
id |
Unique identifier |
email |
Login credential |
name |
Display name |
role |
One of: viewer, editor, author, admin |
department |
The department they belong to (e.g., "Engineering", "Marketing") |
Projects are containers for documents. They're scoped to departments:
| Field | Description |
|---|---|
id |
Unique identifier |
name |
Project name |
description |
What the project is about |
ownerId |
The user who created the project |
department |
The department this project belongs to (can be null for cross-department projects) |
Documents are the core content of the application:
| Field | Description |
|---|---|
id |
Unique identifier |
title |
Document title |
content |
The actual document content |
status |
One of: draft, published, archived |
isLocked |
Whether the document is locked from editing |
projectId |
The project this document belongs to |
creatorId |
The user who created the document |
lastEditedById |
The user who last modified the document |
Users and projects belong to departments. The intended behavior is:
- Users should primarily see and interact with their department's projects
- Some projects have
department: null, meaning they're cross-department and all users can access them
These are the starting permissions for each role:
| Role | View | Create | Edit | Delete |
|---|---|---|---|---|
| Viewer | β | β | β | β |
| Editor | β | β | β | β |
| Author | β | β | β | β |
| Admin | β | β | β | β |
- All roles other than
admincan only view projects with adepartmentthat matches their own department or withdepartment: null(cross-department projects)
| Role | View | Create | Edit | Delete |
|---|---|---|---|---|
| Viewer | β | β | β | β |
| Editor | β | β | β | β |
| Author | β | β | β | β |
| Admin | β | β | β | β |
Here are the key parts of the codebase:
src/
βββ actions/ # Server actions (form submissions)
β βββ documents.ts # Document CRUD operations
β βββ projects.ts # Project CRUD operations
βββ app/ # Next.js app router pages
βββ dal/ # Data access layer
β βββ documents/ # Document queries and mutations
β βββ projects/ # Project queries and mutations
βββ drizzle/ # Database schema and migrations
β βββ schema/ # Entity schemas
βββ components/ # React components
βββ ui/ # shadcn/ui components
Make sure Docker is running and the PostgreSQL container is up:
docker compose psIf port 5432 is already in use, update the port in your .env file.
Make sure you've run the migrations first:
npm run db:pushnpm run dev- Start development servernpm run build- Build for productionnpm run start- Start production servernpm run db:push- Push schema changes to databasenpm run db:seed- Seed database with sample datanpm run db:studio- Open Drizzle Studio (database GUI)