examples: multi-tenant seed script, readme and other improvements (#10702)

This commit is contained in:
Boyan Bratvanov
2025-02-04 16:09:26 +02:00
committed by GitHub
parent 1a68fa14bb
commit ae0736b738
5 changed files with 57 additions and 55 deletions

View File

@@ -10,11 +10,17 @@ To spin up this example locally, follow these steps:
- `npx create-payload-app --example multi-tenant` - `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 - Press `y` when prompted to seed the database
3. `open http://localhost:3000` to access the home page 4. `open http://localhost:3000` to access the home page
4. `open http://localhost:3000/admin` to access the admin panel 5. `open http://localhost:3000/admin` to access the admin panel
- Login with email `demo@payloadcms.com` and password `demo`
### Default users
The seed script seeds 3 tenants.
Login with email `demo@payloadcms.com` and password `demo`
## How it works ## How it works
@@ -28,7 +34,7 @@ See the [Collections](https://payloadcms.com/docs/configuration/collections) doc
- #### Users - #### 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. 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**: **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 127.0.0.1 gold.test silver.test bronze.test
- bronze.localhost.com:3000 ```
- #### Pages - #### Pages

View File

@@ -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>When you visit a tenant by domain, the domain is used to determine the tenant.</p>
<p> <p>
For example, visiting{' '} For example, visiting{' '}
<a href="http://gold.localhost.com:3000/tenant-domains/login"> <a href="http://gold.test:3000/tenant-domains/login">
http://gold.localhost.com:3000/tenant-domains/login http://gold.test:3000/tenant-domains/login
</a>{' '} </a>{' '}
will show the tenant with the domain "gold.localhost.com". will show the tenant with the domain "gold.test".
</p> </p>
<h2>Slugs</h2> <h2>Slugs</h2>

View File

@@ -5,7 +5,7 @@ import { Access } from 'payload'
/** /**
* Tenant admins and super admins can will be allowed access * Tenant admins and super admins can will be allowed access
*/ */
export const superAdminOrTeanantAdminAccess: Access = ({ req }) => { export const superAdminOrTenantAdminAccess: Access = ({ req }) => {
if (!req.user) { if (!req.user) {
return false return false
} }

View File

@@ -1,15 +1,15 @@
import type { CollectionConfig } from 'payload' import type { CollectionConfig } from 'payload'
import { ensureUniqueSlug } from './hooks/ensureUniqueSlug' import { ensureUniqueSlug } from './hooks/ensureUniqueSlug'
import { superAdminOrTeanantAdminAccess } from '@/collections/Pages/access/superAdminOrTenantAdmin' import { superAdminOrTenantAdminAccess } from '@/collections/Pages/access/superAdminOrTenantAdmin'
export const Pages: CollectionConfig = { export const Pages: CollectionConfig = {
slug: 'pages', slug: 'pages',
access: { access: {
create: superAdminOrTeanantAdminAccess, create: superAdminOrTenantAdminAccess,
delete: superAdminOrTeanantAdminAccess, delete: superAdminOrTenantAdminAccess,
read: () => true, read: () => true,
update: superAdminOrTeanantAdminAccess, update: superAdminOrTenantAdminAccess,
}, },
admin: { admin: {
useAsTitle: 'title', useAsTitle: 'title',

View File

@@ -1,6 +1,33 @@
import type { MigrateUpArgs } from '@payloadcms/db-mongodb' import type { MigrateUpArgs } from '@payloadcms/db-mongodb'
export async function up({ payload }: MigrateUpArgs): Promise<void> { 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({ await payload.create({
collection: 'users', collection: 'users',
data: { 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({ await payload.create({
collection: 'users', collection: 'users',
data: { data: {
email: 'tenant1@payloadcms.com', email: 'tenant1@payloadcms.com',
password: 'test', password: 'demo',
tenants: [ tenants: [
{ {
roles: ['tenant-admin'], roles: ['tenant-admin'],
tenant: tenant1.id, tenant: tenant1.id,
}, },
// {
// roles: ['tenant-admin'],
// tenant: tenant2.id,
// },
], ],
username: 'tenant1', username: 'tenant1',
}, },
@@ -60,7 +56,7 @@ export async function up({ payload }: MigrateUpArgs): Promise<void> {
collection: 'users', collection: 'users',
data: { data: {
email: 'tenant2@payloadcms.com', email: 'tenant2@payloadcms.com',
password: 'test', password: 'demo',
tenants: [ tenants: [
{ {
roles: ['tenant-admin'], roles: ['tenant-admin'],
@@ -75,7 +71,7 @@ export async function up({ payload }: MigrateUpArgs): Promise<void> {
collection: 'users', collection: 'users',
data: { data: {
email: 'tenant3@payloadcms.com', email: 'tenant3@payloadcms.com',
password: 'test', password: 'demo',
tenants: [ tenants: [
{ {
roles: ['tenant-admin'], roles: ['tenant-admin'],
@@ -90,7 +86,7 @@ export async function up({ payload }: MigrateUpArgs): Promise<void> {
collection: 'users', collection: 'users',
data: { data: {
email: 'multi-admin@payloadcms.com', email: 'multi-admin@payloadcms.com',
password: 'test', password: 'demo',
tenants: [ tenants: [
{ {
roles: ['tenant-admin'], roles: ['tenant-admin'],
@@ -105,7 +101,7 @@ export async function up({ payload }: MigrateUpArgs): Promise<void> {
tenant: tenant3.id, tenant: tenant3.id,
}, },
], ],
username: 'tenant3', username: 'multi-admin',
}, },
}) })