@latte-macchiat-io/latte-payload
v1.0.10
Published
Reusable Payload CMS collections, utilities, and components for Latte projects
Maintainers
Readme
@latte-macchiat-io/latte-payload
Reusable Payload CMS collections, utilities, and components for Latte projects. This package provides a solid foundation for building Payload CMS applications with pre-configured collections, access control, email queuing, and more.
Features
- 5 Pre-built Collections: Users, Media, ContactMessages, EmailTemplates, QueuedEmails
- 2 Global Configs: PrivacyPolicy, TermsOfUse
- 8 Access Control Functions: Ready-to-use access control patterns
- Email System: Template-based emails with queue and retry logic
- Background Jobs: Async email processing with exponential backoff
- Admin UI Components: Custom components for better UX
- Fully Typed: Complete TypeScript support
- Configurable: All collections and utilities accept configuration options
Installation
pnpm add @latte-macchiat-io/latte-payloadPeer Dependencies
pnpm add [email protected] \
@payloadcms/[email protected] \
@payloadcms/[email protected] \
@payloadcms/[email protected] \
@payloadcms/[email protected] \
[email protected] \
[email protected] \
[email protected] \
[email protected]Optional Dependencies
# For email functionality
pnpm add @payloadcms/[email protected] # or @payloadcms/[email protected]
# For S3 storage
pnpm add @payloadcms/[email protected]⚠️ Important: Payload Version Alignment
All @payloadcms/* packages and payload must be at the exact same version (minimum 3.64.0).
Payload CMS enforces strict version matching across all its packages. If any package has a different version, you'll encounter this error:
Error: Mismatching "payload" dependency versions foundEnsuring Version Alignment
Add the following to your project's package.json to enforce version alignment:
{
"pnpm": {
"overrides": {
"@payloadcms/db-postgres": "3.64.0",
"@payloadcms/email-nodemailer": "3.64.0",
"@payloadcms/email-resend": "3.64.0",
"@payloadcms/next": "3.64.0",
"@payloadcms/richtext-lexical": "3.64.0",
"@payloadcms/storage-s3": "3.64.0",
"@payloadcms/ui": "3.64.0",
"payload": "3.64.0"
}
}
}For npm users:
{
"overrides": {
"@payloadcms/db-postgres": "3.64.0",
"@payloadcms/email-nodemailer": "3.64.0",
"@payloadcms/email-resend": "3.64.0",
"@payloadcms/next": "3.64.0",
"@payloadcms/richtext-lexical": "3.64.0",
"@payloadcms/storage-s3": "3.64.0",
"@payloadcms/ui": "3.64.0",
"payload": "3.64.0"
}
}For yarn users:
{
"resolutions": {
"@payloadcms/db-postgres": "3.64.0",
"@payloadcms/email-nodemailer": "3.64.0",
"@payloadcms/email-resend": "3.64.0",
"@payloadcms/next": "3.64.0",
"@payloadcms/richtext-lexical": "3.64.0",
"@payloadcms/storage-s3": "3.64.0",
"@payloadcms/ui": "3.64.0",
"payload": "3.64.0"
}
}Why This Matters
Payload CMS validates that all its packages share the same version to prevent compatibility issues. Even if transitive dependencies (packages installed by other packages) try to pull in different versions, the overrides above will ensure version consistency.
Quick Start
Basic Usage
// payload.config.ts
import { buildConfig } from 'payload';
import { postgresAdapter } from '@payloadcms/db-postgres';
import {
Users,
Media,
EmailTemplates,
QueuedEmails,
PrivacyPolicy,
TermsOfUse,
processEmailQueueTaskConfig
} from '@latte-macchiat-io/latte-payload';
export default buildConfig({
collections: [
Users,
Media,
EmailTemplates,
QueuedEmails,
// Add your custom collections here
],
globals: [
PrivacyPolicy,
TermsOfUse,
],
jobs: {
tasks: [processEmailQueueTaskConfig],
},
db: postgresAdapter({
pool: {
connectionString: process.env.DATABASE_URI,
},
}),
// ... other config
});Collections
Users
Complete authentication system with email verification and password reset.
import { createUsersCollection } from '@latte-macchiat-io/latte-payload';
// Customize the Users collection
const CustomUsers = createUsersCollection({
roles: [
{ label: { fr: 'Admin', nl: 'Admin', en: 'Admin' }, value: 'admin' },
{ label: { fr: 'Éditeur', nl: 'Redacteur', en: 'Editor' }, value: 'editor' },
{ label: { fr: 'Utilisateur', nl: 'Gebruiker', en: 'User' }, value: 'user' },
],
defaultLocale: 'fr',
tokenExpiration: 60 * 60 * 24 * 7, // 1 week
verifyEmailConfig: {
generateVerifyUrl: async (token, user) => {
return `https://yourdomain.com/verify?token=${token}`;
},
},
});Media
File upload collection with S3 support.
import { Media } from '@latte-macchiat-io/latte-payload';
import { s3Storage } from '@payloadcms/storage-s3';
export default buildConfig({
collections: [Media],
plugins: [
s3Storage({
collections: {
media: true,
},
bucket: process.env.S3_BUCKET,
config: {
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
},
region: process.env.S3_REGION,
},
}),
],
});EmailTemplates
Manage email templates in the CMS.
import { createEmailTemplatesCollection } from '@latte-macchiat-io/latte-payload';
const CustomEmailTemplates = createEmailTemplatesCollection({
emailCodes: [
{ label: 'verify-email', value: 'verify-email' },
{ label: 'password-lost', value: 'password-lost' },
{ label: 'welcome', value: 'welcome' },
{ label: 'order-confirmation', value: 'order-confirmation' },
],
});QueuedEmails
Email queue with retry logic and admin UI.
import { QueuedEmails } from '@latte-macchiat-io/latte-payload';ContactMessages
Store contact form submissions.
import { createContactMessagesCollection } from '@latte-macchiat-io/latte-payload';
const CustomContactMessages = createContactMessagesCollection({
locales: ['en', 'fr', 'nl', 'de'],
emailNotificationConfig: {
contactEmail: '[email protected]',
subject: 'New Contact Form Submission',
},
});Globals
PrivacyPolicy & TermsOfUse
Localized legal content with Next.js cache revalidation.
import { PrivacyPolicy, TermsOfUse } from '@latte-macchiat-io/latte-payload';Access Control
8 pre-built access control patterns:
import {
anyone, // Public access
authenticated, // Authenticated users only
authenticatedFieldLevel, // Field-level authenticated access
admins, // Admin users only
adminsFieldLevel, // Field-level admin access
publicReadAuthenticatedAccess, // Public read, authenticated write
authenticatedAccessOnly, // All operations require auth
adminAccessOnly, // All operations require admin
} from '@latte-macchiat-io/latte-payload';
// Use in your custom collections
export const MyCollection: CollectionConfig = {
slug: 'my-collection',
access: publicReadAuthenticatedAccess,
fields: [
{
name: 'sensitiveField',
type: 'text',
access: {
read: adminsFieldLevel,
update: adminsFieldLevel,
},
},
],
};Utilities
Queue Email
import { queueEmail } from '@latte-macchiat-io/latte-payload';
await queueEmail({
payload,
to: '[email protected]',
emailCode: 'welcome',
variables: {
name: 'John Doe',
url: 'https://yourdomain.com',
},
locale: 'en',
idempotencyKey: `welcome-${userId}`, // Prevent duplicates
});Generate Email HTML
import { generateEmailHtmlFromTemplate } from '@latte-macchiat-io/latte-payload';
const emailContent = await generateEmailHtmlFromTemplate({
payload,
emailCode: 'order-confirmation',
locale: 'fr',
variables: {
orderNumber: '#12345',
customerName: 'Jane Doe',
},
});Get Payload Client
import { getPayloadClient } from '@latte-macchiat-io/latte-payload';
import config from './payload.config';
const payload = await getPayloadClient(config);Background Tasks
Process Email Queue
Automatically process queued emails with retry logic.
import { createProcessEmailQueueTask } from '@latte-macchiat-io/latte-payload';
import * as Sentry from '@sentry/nextjs';
const emailTask = createProcessEmailQueueTask({
timezone: 'America/New_York',
maxEmailsPerRun: 50,
delayBetweenEmails: 500, // 0.5 seconds
defaultFromAddress: '[email protected]',
errorReporter: {
captureException: Sentry.captureException,
},
});
export default buildConfig({
jobs: {
tasks: [emailTask],
},
});Email HTML Template
Create an HTML email template at ./emails/template.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{ emailSubject }}</title>
</head>
<body>
<div style="max-width: 600px; margin: 0 auto; padding: 20px;">
{{ emailContent }}
</div>
</body>
</html>The {{ emailContent }} placeholder will be replaced with your email template content.
Environment Variables
# Required
DATABASE_URI=postgresql://user:password@localhost:5432/dbname
PAYLOAD_SECRET=your-secret-key
# Email (choose one)
ENABLE_EMAILS_SENDING=true
RESEND_API_KEY=re_xxx # For production (Resend)
# OR
SMTP_HOST=localhost # For development (Mailpit/Nodemailer)
SMTP_PORT=1025
[email protected]
# Contact form
[email protected]
# Dashboard widget
NEXT_PUBLIC_CLIENT_DASHBOARD_URL=https://dashboard.latte-macchiat.io/your-project
# S3 Storage (optional)
S3_ENDPOINT=https://s3.amazonaws.com
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=xxx
S3_SECRET_ACCESS_KEY=xxx
S3_BUCKET=your-bucket-nameAdmin UI Components
ClientSpaceButton
A dashboard widget that links to your Latte Macchiat.io dashboard for support, feature requests, and issue tracking.
// payload.config.ts
import { buildConfig } from 'payload';
export default buildConfig({
admin: {
components: {
afterDashboard: [
'@latte-macchiat-io/latte-payload/components#ClientSpaceButton',
],
},
},
// ... rest of config
});Environment Variable:
# URL to your Latte Macchiat.io dashboard
NEXT_PUBLIC_CLIENT_DASHBOARD_URL=https://dashboard.latte-macchiat.io/your-projectFeatures:
- Opens dashboard in a new tab with proper security attributes
- Hidden in production when
CLIENT_DASHBOARD_URLis not set - Shows warning in development mode when URL is missing
- Uses Payload's native Button and Banner components
- Automatically adapts to Payload's theme (light/dark mode)
TypeScript Types
import type {
Locale,
EmailTemplateCode,
QueuedEmailStatus,
UsersCollectionConfig,
ContactMessagesConfig,
EmailTemplatesConfig,
ProcessEmailQueueConfig,
} from '@latte-macchiat-io/latte-payload';Version Compatibility
- Payload CMS: >=3.64.0 <4.0.0 (all @payloadcms/* packages must match)
- React: ^19.0.0
- Next.js: ^15.0.0
- Sharp: ^0.34.0
- Node.js: >=22.x
- pnpm: ^10.0.0
Important: All @payloadcms/* packages must be at the same version. Use package manager overrides (see above) to enforce this.
Contributing
This package is maintained by Latte Macchiat.io for internal use across projects. If you find bugs or have suggestions, please open an issue.
License
MIT
