examples: multi-tenant seed script, readme and other improvements (#10702)
This commit is contained in:
@@ -10,11 +10,17 @@ To spin up this example locally, follow these steps:
|
||||
|
||||
- `npx create-payload-app --example multi-tenant`
|
||||
|
||||
2. `pnpm dev`, `yarn dev` or `npm run dev` to start the server
|
||||
2. `cp .env.example .env` to copy the example environment variables
|
||||
|
||||
3. `pnpm dev`, `yarn dev` or `npm run dev` to start the server
|
||||
- Press `y` when prompted to seed the database
|
||||
3. `open http://localhost:3000` to access the home page
|
||||
4. `open http://localhost:3000/admin` to access the admin panel
|
||||
- Login with email `demo@payloadcms.com` and password `demo`
|
||||
4. `open http://localhost:3000` to access the home page
|
||||
5. `open http://localhost:3000/admin` to access the admin panel
|
||||
|
||||
### Default users
|
||||
|
||||
The seed script seeds 3 tenants.
|
||||
Login with email `demo@payloadcms.com` and password `demo`
|
||||
|
||||
## How it works
|
||||
|
||||
@@ -28,7 +34,7 @@ See the [Collections](https://payloadcms.com/docs/configuration/collections) doc
|
||||
|
||||
- #### Users
|
||||
|
||||
The `users` collection is auth-enabled and encompass both app-wide and tenant-scoped users based on the value of their `roles` and `tenants` fields. Users with the role `super-admin` can manage your entire application, while users with the _tenant role_ of `admin` have limited access to the platform and can manage only the tenant(s) they are assigned to, see [Tenants](#tenants) for more details.
|
||||
The `users` collection is auth-enabled and encompasses both app-wide and tenant-scoped users based on the value of their `roles` and `tenants` fields. Users with the role `super-admin` can manage your entire application, while users with the _tenant role_ of `admin` have limited access to the platform and can manage only the tenant(s) they are assigned to, see [Tenants](#tenants) for more details.
|
||||
|
||||
For additional help with authentication, see the official [Auth Example](https://github.com/payloadcms/payload/tree/main/examples/cms#readme) or the [Authentication](https://payloadcms.com/docs/authentication/overview#authentication-overview) docs.
|
||||
|
||||
@@ -40,13 +46,13 @@ See the [Collections](https://payloadcms.com/docs/configuration/collections) doc
|
||||
|
||||
**Domain-based Tenant Setting**:
|
||||
|
||||
This example also supports domain-based tenant selection, where tenants can be associated with a specific domain. If a tenant is associated with a domain (e.g., `gold.localhost.com:3000`), when a user logs in from that domain, they will be automatically scoped to the matching tenant. This is accomplished through an optional `afterLogin` hook that sets a `payload-tenant` cookie based on the domain.
|
||||
This example also supports domain-based tenant selection, where tenants can be associated with a specific domain. If a tenant is associated with a domain (e.g., `gold.test:3000`), when a user logs in from that domain, they will be automatically scoped to the matching tenant. This is accomplished through an optional `afterLogin` hook that sets a `payload-tenant` cookie based on the domain.
|
||||
|
||||
The seed script seeds 3 tenants, for the domain portion of the example to function properly you will need to add the following entries to your systems `/etc/hosts` file:
|
||||
For the domain portion of the example to function properly, you will need to add the following entries to your system's `/etc/hosts` file:
|
||||
|
||||
- gold.localhost.com:3000
|
||||
- silver.localhost.com:3000
|
||||
- bronze.localhost.com:3000
|
||||
```
|
||||
127.0.0.1 gold.test silver.test bronze.test
|
||||
```
|
||||
|
||||
- #### Pages
|
||||
|
||||
@@ -54,7 +60,7 @@ See the [Collections](https://payloadcms.com/docs/configuration/collections) doc
|
||||
|
||||
## Access control
|
||||
|
||||
Basic role-based access control is setup to determine what users can and cannot do based on their roles, which are:
|
||||
Basic role-based access control is set up to determine what users can and cannot do based on their roles, which are:
|
||||
|
||||
- `super-admin`: They can access the Payload admin panel to manage your multi-tenant application. They can see all tenants and make all operations.
|
||||
- `user`: They can only access the Payload admin panel if they are a tenant-admin, in which case they have a limited access to operations based on their tenant (see below).
|
||||
|
||||
@@ -10,10 +10,10 @@ export default async ({ params: paramsPromise }: { params: Promise<{ slug: strin
|
||||
<p>When you visit a tenant by domain, the domain is used to determine the tenant.</p>
|
||||
<p>
|
||||
For example, visiting{' '}
|
||||
<a href="http://gold.localhost.com:3000/tenant-domains/login">
|
||||
http://gold.localhost.com:3000/tenant-domains/login
|
||||
<a href="http://gold.test:3000/tenant-domains/login">
|
||||
http://gold.test:3000/tenant-domains/login
|
||||
</a>{' '}
|
||||
will show the tenant with the domain "gold.localhost.com".
|
||||
will show the tenant with the domain "gold.test".
|
||||
</p>
|
||||
|
||||
<h2>Slugs</h2>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Access } from 'payload'
|
||||
/**
|
||||
* Tenant admins and super admins can will be allowed access
|
||||
*/
|
||||
export const superAdminOrTeanantAdminAccess: Access = ({ req }) => {
|
||||
export const superAdminOrTenantAdminAccess: Access = ({ req }) => {
|
||||
if (!req.user) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import { ensureUniqueSlug } from './hooks/ensureUniqueSlug'
|
||||
import { superAdminOrTeanantAdminAccess } from '@/collections/Pages/access/superAdminOrTenantAdmin'
|
||||
import { superAdminOrTenantAdminAccess } from '@/collections/Pages/access/superAdminOrTenantAdmin'
|
||||
|
||||
export const Pages: CollectionConfig = {
|
||||
slug: 'pages',
|
||||
access: {
|
||||
create: superAdminOrTeanantAdminAccess,
|
||||
delete: superAdminOrTeanantAdminAccess,
|
||||
create: superAdminOrTenantAdminAccess,
|
||||
delete: superAdminOrTenantAdminAccess,
|
||||
read: () => true,
|
||||
update: superAdminOrTeanantAdminAccess,
|
||||
update: superAdminOrTenantAdminAccess,
|
||||
},
|
||||
admin: {
|
||||
useAsTitle: 'title',
|
||||
|
||||
@@ -1,6 +1,33 @@
|
||||
import type { MigrateUpArgs } from '@payloadcms/db-mongodb'
|
||||
|
||||
export async function up({ payload }: MigrateUpArgs): Promise<void> {
|
||||
const tenant1 = await payload.create({
|
||||
collection: 'tenants',
|
||||
data: {
|
||||
name: 'Tenant 1',
|
||||
slug: 'gold',
|
||||
domain: 'gold.test',
|
||||
},
|
||||
})
|
||||
|
||||
const tenant2 = await payload.create({
|
||||
collection: 'tenants',
|
||||
data: {
|
||||
name: 'Tenant 2',
|
||||
slug: 'silver',
|
||||
domain: 'silver.test',
|
||||
},
|
||||
})
|
||||
|
||||
const tenant3 = await payload.create({
|
||||
collection: 'tenants',
|
||||
data: {
|
||||
name: 'Tenant 3',
|
||||
slug: 'bronze',
|
||||
domain: 'bronze.test',
|
||||
},
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: 'users',
|
||||
data: {
|
||||
@@ -10,47 +37,16 @@ export async function up({ payload }: MigrateUpArgs): Promise<void> {
|
||||
},
|
||||
})
|
||||
|
||||
const tenant1 = await payload.create({
|
||||
collection: 'tenants',
|
||||
data: {
|
||||
name: 'Tenant 1',
|
||||
slug: 'gold',
|
||||
domain: 'gold.localhost.com',
|
||||
},
|
||||
})
|
||||
|
||||
const tenant2 = await payload.create({
|
||||
collection: 'tenants',
|
||||
data: {
|
||||
name: 'Tenant 2',
|
||||
slug: 'silver',
|
||||
domain: 'silver.localhost.com',
|
||||
},
|
||||
})
|
||||
|
||||
const tenant3 = await payload.create({
|
||||
collection: 'tenants',
|
||||
data: {
|
||||
name: 'Tenant 3',
|
||||
slug: 'bronze',
|
||||
domain: 'bronze.localhost.com',
|
||||
},
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: 'tenant1@payloadcms.com',
|
||||
password: 'test',
|
||||
password: 'demo',
|
||||
tenants: [
|
||||
{
|
||||
roles: ['tenant-admin'],
|
||||
tenant: tenant1.id,
|
||||
},
|
||||
// {
|
||||
// roles: ['tenant-admin'],
|
||||
// tenant: tenant2.id,
|
||||
// },
|
||||
],
|
||||
username: 'tenant1',
|
||||
},
|
||||
@@ -60,7 +56,7 @@ export async function up({ payload }: MigrateUpArgs): Promise<void> {
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: 'tenant2@payloadcms.com',
|
||||
password: 'test',
|
||||
password: 'demo',
|
||||
tenants: [
|
||||
{
|
||||
roles: ['tenant-admin'],
|
||||
@@ -75,7 +71,7 @@ export async function up({ payload }: MigrateUpArgs): Promise<void> {
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: 'tenant3@payloadcms.com',
|
||||
password: 'test',
|
||||
password: 'demo',
|
||||
tenants: [
|
||||
{
|
||||
roles: ['tenant-admin'],
|
||||
@@ -90,7 +86,7 @@ export async function up({ payload }: MigrateUpArgs): Promise<void> {
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: 'multi-admin@payloadcms.com',
|
||||
password: 'test',
|
||||
password: 'demo',
|
||||
tenants: [
|
||||
{
|
||||
roles: ['tenant-admin'],
|
||||
@@ -105,7 +101,7 @@ export async function up({ payload }: MigrateUpArgs): Promise<void> {
|
||||
tenant: tenant3.id,
|
||||
},
|
||||
],
|
||||
username: 'tenant3',
|
||||
username: 'multi-admin',
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user