Pixarts CMS Modules
Pattern per aggiungere moduli funzionali al CMS Payload multi-tenant.
Architettura Moduli
Ogni modulo è un pacchetto self-contained che aggiunge:
- Collections Payload con access control multi-tenant
- Fields riutilizzabili
- Hooks per side effects (email, revalidation, ecc.)
- Frontend components per rendering
Moduli Disponibili
1. Reservations (Prenotazioni)
Use case: Ristoranti, saloni, studi professionali, hotel
Collections:
// collections/bookings.ts
export const Bookings: CollectionConfig = {
slug: 'bookings',
admin: { useAsTitle: 'customerName' },
fields: [
tenantField,
{ name: 'customerName', type: 'text', required: true },
{ name: 'customerEmail', type: 'email', required: true },
{ name: 'customerPhone', type: 'text' },
{ name: 'service', type: 'relationship', relationTo: 'services', required: true },
{ name: 'date', type: 'date', required: true },
{ name: 'timeSlot', type: 'text', required: true },
{ name: 'status', type: 'select', options: ['pending', 'confirmed', 'cancelled', 'completed'], defaultValue: 'pending' },
{ name: 'notes', type: 'textarea' },
],
access: { read: tenantReadAccess, create: () => true, update: tenantWriteAccess },
}
// collections/services.ts
export const Services: CollectionConfig = {
slug: 'services',
fields: [
tenantField,
{ name: 'name', type: 'text', required: true, localized: true },
{ name: 'description', type: 'textarea', localized: true },
{ name: 'duration', type: 'number', required: true }, // minuti
{ name: 'price', type: 'number' },
{ name: 'active', type: 'checkbox', defaultValue: true },
],
}
// collections/availability.ts
export const Availability: CollectionConfig = {
slug: 'availability',
fields: [
tenantField,
{ name: 'dayOfWeek', type: 'select', options: ['mon','tue','wed','thu','fri','sat','sun'] },
{ name: 'startTime', type: 'text', required: true }, // "09:00"
{ name: 'endTime', type: 'text', required: true }, // "18:00"
{ name: 'slotDuration', type: 'number', defaultValue: 30 }, // minuti
{ name: 'active', type: 'checkbox', defaultValue: true },
],
}
2. E-commerce
Use case: Negozi online, vendita prodotti
Collections:
products: name, slug, description, price, compareAtPrice, images, categories, inventory, variants, active
orders: orderNumber, customer (name, email, phone, address), items[], total, status (pending/paid/shipped/delivered/cancelled), paymentMethod
customers: name, email, phone, addresses[], orderHistory
3. Events (Eventi)
Use case: Teatri, conferenze, corsi, workshop
Collections:
events: title, slug, description, date, endDate, location, capacity, price, image, categories, status (draft/published/cancelled)
registrations: event (rel), attendee (name, email, phone), ticketType, quantity, status (pending/confirmed/cancelled), paymentStatus
tickets: event (rel), type (name, price, quantity, description)
4. Portfolio
Use case: Agenzie, freelancer, studi creativi
Collections:
projects: title, slug, client, description, featuredImage, gallery[], technologies[], url, year, featured, order
5. FAQ
Use case: Qualsiasi sito con domande frequenti
Collections:
faqs: question (localized), answer (richText, localized), category (rel), order, active
faq-categories: name (localized), slug, order
6. Newsletter
Use case: Blog, marketing, e-commerce
Collections:
subscribers: email, name, status (active/unsubscribed), source, subscribedAt
campaigns: subject, content, sentAt, status (draft/sent), recipientCount
7. Reviews (Recensioni)
Use case: E-commerce, ristoranti, servizi
Collections:
reviews: author, email, rating (1-5), title, content, product/service (rel), status (pending/approved/rejected), featured
8. Jobs (Lavoro)
Use case: Aziende che assumono
Collections:
job-listings: title, slug, department, location, type (full-time/part-time/contract/remote), description (richText), requirements, salary, active
applications: job (rel), name, email, phone, coverLetter, resume (upload), status (new/reviewed/interviewed/hired/rejected)
9. Memberships
Use case: Palestre, club, SaaS
Collections:
plans: name, slug, description, price, interval (monthly/yearly), features[], active, order
subscriptions: user (rel), plan (rel), status (active/cancelled/expired), startDate, endDate, stripeId
10. Affiliates
Use case: E-commerce, SaaS
Collections:
affiliates: name, email, code, commissionRate, status (active/inactive), totalEarnings
referrals: affiliate (rel), order (rel), commission, status (pending/paid)
Pattern di Installazione
# Comando
/cms-module <modulo> <tenant-slug>
Workflow:
- Crea le collection files in
cms/collections/modules/<modulo>/
- Registra le collections in
payload.config.ts
- Aggiungi access control multi-tenant
- Crea hooks per notifiche/revalidation
- Genera i tipi TypeScript
- Crea i componenti frontend per il rendering
Access Control Standard per Moduli
// Tutti i moduli usano lo stesso pattern
import { tenantField, tenantReadAccess, tenantWriteAccess } from '../fields/tenant';
// Lettura pubblica (sito frontend)
const publicRead: Access = ({ req }) => {
// Utenti autenticati: filtro tenant
if (req.user?.tenant) return { tenant: { equals: req.user.tenant } };
// Utenti non autenticati: solo dati pubblicati
return { _status: { equals: 'published' } };
};
1---2name: pixarts-cms-modules3description: Pixarts CMS modules pattern - reservations, ecommerce, events, portfolio, newsletter. Use when adding functional modules to Payload CMS tenant, implementing reservations, e-commerce, or event management.4---56# Pixarts CMS Modules78Pattern per aggiungere moduli funzionali al CMS Payload multi-tenant.910## Architettura Moduli1112Ogni modulo è un pacchetto self-contained che aggiunge:131. **Collections** Payload con access control multi-tenant142. **Fields** riutilizzabili153. **Hooks** per side effects (email, revalidation, ecc.)164. **Frontend components** per rendering1718## Moduli Disponibili1920### 1. Reservations (Prenotazioni)2122**Use case**: Ristoranti, saloni, studi professionali, hotel2324**Collections:**2526```typescript27// collections/bookings.ts28export const Bookings: CollectionConfig = {29 slug: 'bookings',30 admin: { useAsTitle: 'customerName' },31 fields: [32 tenantField,33 { name: 'customerName', type: 'text', required: true },34 { name: 'customerEmail', type: 'email', required: true },35 { name: 'customerPhone', type: 'text' },36 { name: 'service', type: 'relationship', relationTo: 'services', required: true },37 { name: 'date', type: 'date', required: true },38 { name: 'timeSlot', type: 'text', required: true },39 { name: 'status', type: 'select', options: ['pending', 'confirmed', 'cancelled', 'completed'], defaultValue: 'pending' },40 { name: 'notes', type: 'textarea' },41 ],42 access: { read: tenantReadAccess, create: () => true, update: tenantWriteAccess },43}4445// collections/services.ts46export const Services: CollectionConfig = {47 slug: 'services',48 fields: [49 tenantField,50 { name: 'name', type: 'text', required: true, localized: true },51 { name: 'description', type: 'textarea', localized: true },52 { name: 'duration', type: 'number', required: true }, // minuti53 { name: 'price', type: 'number' },54 { name: 'active', type: 'checkbox', defaultValue: true },55 ],56}5758// collections/availability.ts59export const Availability: CollectionConfig = {60 slug: 'availability',61 fields: [62 tenantField,63 { name: 'dayOfWeek', type: 'select', options: ['mon','tue','wed','thu','fri','sat','sun'] },64 { name: 'startTime', type: 'text', required: true }, // "09:00"65 { name: 'endTime', type: 'text', required: true }, // "18:00"66 { name: 'slotDuration', type: 'number', defaultValue: 30 }, // minuti67 { name: 'active', type: 'checkbox', defaultValue: true },68 ],69}70```7172### 2. E-commerce7374**Use case**: Negozi online, vendita prodotti7576**Collections:**77- `products`: name, slug, description, price, compareAtPrice, images, categories, inventory, variants, active78- `orders`: orderNumber, customer (name, email, phone, address), items[], total, status (pending/paid/shipped/delivered/cancelled), paymentMethod79- `customers`: name, email, phone, addresses[], orderHistory8081### 3. Events (Eventi)8283**Use case**: Teatri, conferenze, corsi, workshop8485**Collections:**86- `events`: title, slug, description, date, endDate, location, capacity, price, image, categories, status (draft/published/cancelled)87- `registrations`: event (rel), attendee (name, email, phone), ticketType, quantity, status (pending/confirmed/cancelled), paymentStatus88- `tickets`: event (rel), type (name, price, quantity, description)8990### 4. Portfolio9192**Use case**: Agenzie, freelancer, studi creativi9394**Collections:**95- `projects`: title, slug, client, description, featuredImage, gallery[], technologies[], url, year, featured, order9697### 5. FAQ9899**Use case**: Qualsiasi sito con domande frequenti100101**Collections:**102- `faqs`: question (localized), answer (richText, localized), category (rel), order, active103- `faq-categories`: name (localized), slug, order104105### 6. Newsletter106107**Use case**: Blog, marketing, e-commerce108109**Collections:**110- `subscribers`: email, name, status (active/unsubscribed), source, subscribedAt111- `campaigns`: subject, content, sentAt, status (draft/sent), recipientCount112113### 7. Reviews (Recensioni)114115**Use case**: E-commerce, ristoranti, servizi116117**Collections:**118- `reviews`: author, email, rating (1-5), title, content, product/service (rel), status (pending/approved/rejected), featured119120### 8. Jobs (Lavoro)121122**Use case**: Aziende che assumono123124**Collections:**125- `job-listings`: title, slug, department, location, type (full-time/part-time/contract/remote), description (richText), requirements, salary, active126- `applications`: job (rel), name, email, phone, coverLetter, resume (upload), status (new/reviewed/interviewed/hired/rejected)127128### 9. Memberships129130**Use case**: Palestre, club, SaaS131132**Collections:**133- `plans`: name, slug, description, price, interval (monthly/yearly), features[], active, order134- `subscriptions`: user (rel), plan (rel), status (active/cancelled/expired), startDate, endDate, stripeId135136### 10. Affiliates137138**Use case**: E-commerce, SaaS139140**Collections:**141- `affiliates`: name, email, code, commissionRate, status (active/inactive), totalEarnings142- `referrals`: affiliate (rel), order (rel), commission, status (pending/paid)143144---145146## Pattern di Installazione147148```bash149# Comando150/cms-module <modulo> <tenant-slug>151```152153**Workflow:**1541. Crea le collection files in `cms/collections/modules/<modulo>/`1552. Registra le collections in `payload.config.ts`1563. Aggiungi access control multi-tenant1574. Crea hooks per notifiche/revalidation1585. Genera i tipi TypeScript1596. Crea i componenti frontend per il rendering160161## Access Control Standard per Moduli162163```typescript164// Tutti i moduli usano lo stesso pattern165import { tenantField, tenantReadAccess, tenantWriteAccess } from '../fields/tenant';166167// Lettura pubblica (sito frontend)168const publicRead: Access = ({ req }) => {169 // Utenti autenticati: filtro tenant170 if (req.user?.tenant) return { tenant: { equals: req.user.tenant } };171 // Utenti non autenticati: solo dati pubblicati172 return { _status: { equals: 'published' } };173};174```