npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@consilioweb/payload-support

v2.0.1

Published

Payload CMS plugin — professional support & ticketing system with AI, SLA, time tracking, live chat, and more

Readme

npm version MIT License Node.js Payload Tests TypeScript

📑 Table of Contents

✨ Features

🎫 Complete ticketing

Statuses, priorities, categories, tags, merge/split, snooze, scheduled replies, internal notes, an immutable activity log and a keyboard-driven Superhuman-style inbox.

⏱️ SLA & automation

SLA policies (business hours + pause-on-hold), escalation, macros, round-robin, and a visual automation-rules engine (conditions → actions).

🤖 Built-in AI

Sentiment, reply suggestions, multi-style rewriting, cached synthesis, a KB chatbot, and an autonomous AI agent that answers or escalates. Anthropic, OpenAI or self-hosted Ollama.

💬 Omnichannel & portal

Inbound/outbound email, live chat (SSE), widget, a full client portal (auth, 2FA, Google OAuth), knowledge base and deflection.

💶 Time tracking & billing

Timer, manual entries, time dashboard, per-project pre-billing and a print-ready invoice (HTML → PDF).

📊 Reporting & privacy

Real-time dashboard, CSAT + NPS, email tracking, HMAC-signed webhooks, notification digests, CSV exports. 100% self-hostable.

🚀 Quick Start

// payload.config.ts
import { buildConfig } from 'payload'
import { supportPlugin } from '@consilioweb/payload-support'

export default buildConfig({
  plugins: [
    supportPlugin({
      features: { ai: true, sla: true, timeTracking: true, chat: true },
      ai: { provider: 'anthropic', model: 'claude-haiku-4-5-20251001' },
      locale: 'fr',
    }),
  ],
})
pnpm payload generate:importmap
pnpm dev

Open /admin/support/inbox for the agent inbox, or /support for the client portal. The plugin injects collections, API endpoints and admin views automatically — no external SaaS.

📦 Installation

npm

npm install @consilioweb/payload-support

yarn

yarn add @consilioweb/payload-support

pnpm

pnpm add @consilioweb/payload-support

Peer dependencies: payload@^3, react@^18 || ^19, react-dom@^18 || ^19, next@^14 || ^15 || ^16. lucide-react and the @payloadcms/* packages are optional depending on the features you enable. After adding admin components, run pnpm payload generate:importmap.

💻 Usage

Basic

// All features are on by default — turn off what you don't need:
supportPlugin({ features: { chat: false, pendingEmails: false }, locale: 'en' })

Advanced

supportPlugin({
  features: { ai: true, sla: true, roundRobin: true, webhooks: true, snooze: true },
  rateLimitStore: 'payload', // shared, persistent limits for multi-instance deployments
  ticketNumber: { prefix: 'TK-', padding: 6 },
  ai: { provider: 'ollama', model: 'qwen2.5', baseUrl: process.env.OLLAMA_API_URL },
  email: { fromName: 'Support ACME', fromAddress: '[email protected]', replyTo: '[email protected]' },
  allowedEmailDomains: ['acme.com'],          // restrict OAuth auto-registration
  collectionSlugs: { tickets: 'support-tickets' }, // slug overrides
  navGroup: 'Support',
  basePath: '/support',
})

Deployment adapters

Version 2 keeps provider-specific code in the host application while the plugin owns the generic support workflow. Optional capabilities include SMS, inbound email, digests, AI titles and summaries, detailed billing, volunteering, thread cleanup and project suggestions.

supportPlugin({
  rateLimitStore: 'payload',
  capabilities: {
    sms: {
      adapter: {
        isConfigured: () => Boolean(process.env.SMS_PROVIDER_ACCOUNT),
        send: async ({ message, to }) => mySmsProvider.send({ message, to }),
      },
    },
    inboundEmail: {
      secret: process.env.SUPPORT_WEBHOOK_SECRET,
      secretHeader: 'x-webhook-secret',
      handle: handleInboundSupportEmail,
    },
    detailedBilling: true,
    volunteering: true,
  },
})

Upgrading from 1.x

Version 2.0 is a security and ownership release with intentional breaking changes:

  1. Generate an additive Payload migration for the new support-counters collection and, when rateLimitStore: 'payload' is enabled, support-rate-limits. Run it before restart.
  2. Regenerate Payload types and the admin import map.
  3. Remove duplicated host routes and enable the plugin endpoints (skipEndpoints: false).
  4. Read portal authentication exclusively from the HttpOnly cookie. Login, OAuth and 2FA responses no longer expose the JWT in JSON.
  5. Send cron and webhook secrets only through their configured headers. Query-string secrets are rejected.
  6. Custom rate-limit stores must implement the asynchronous RateLimitStore interface.

The process-local memory store remains the default for development and single-instance use. Use rateLimitStore: 'payload' or a shared custom store in production with multiple instances.

Run the AI agent on a ticket

await fetch('/api/support/ai-agent', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ ticketId, confidenceThreshold: 0.7 }),
})

🔌 API Reference

supportPlugin(config)

The Payload plugin. Adds collections, admin views, editor components and API endpoints.

supportPlugin(config?: SupportPluginConfig): Plugin

Exports

import { supportPlugin, generateTicketSynthesis, dispatchWebhook } from '@consilioweb/payload-support'
import type { SupportPluginConfig, SupportFeatures } from '@consilioweb/payload-support'

Key HTTP endpoints (under /api/support)

| Method | Path | Purpose | |---|---|---| | POST | /ai | Sentiment, reply suggestion, rewrite, synthesis (admin). | | POST | /ai-agent | Autonomous AI agent — answers from the KB or escalates. | | POST | /login, /2fa, /oauth/google | Client portal auth (password, 2FA, OAuth). | | GET | /admin-stats | Dashboard KPIs (real volume series, CSAT, NPS). | | GET | /billing, /billing/invoice | Pre-billing + print-ready invoice. | | POST | /process-snooze, /process-digests, /process-scheduled, /auto-close | Cron jobs (guarded by x-cron-secret). |

⚙️ Configuration

| Option | Type | Default | Description | |--------|------|---------|-------------| | features | SupportFeatures | all true | Toggle each feature on/off. | | ai | AIProviderConfig | anthropic | AI provider: anthropic | openai | ollama | custom. | | email | EmailConfig | — | fromName, fromAddress, replyTo. | | rateLimitStore | RateLimitStore \| 'payload' | memory | Persistent/shared storage for endpoint limits. | | ticketNumber | { prefix?, padding? } | TK-, no padding | Atomic sequential ticket-number formatting. | | capabilities | SupportCapabilities | — | Optional host adapters for SMS, inbound email, AI and deployment-specific workflows. | | locale | 'fr' \| 'en' | 'fr' | Admin/portal language. | | basePath | string | '/support' | Admin views prefix. | | userCollectionSlug | string | 'users' | Agents collection. | | allowedEmailDomains | string[] | — | Domains allowed for OAuth auto-registration. | | collectionSlugs | object | — | Collection slug overrides. | | skipCollections / skipViews / skipEndpoints | boolean | false | Skip injecting that part. |

Environment variables

| Env var | Required | Description | |---------|----------|-------------| | PAYLOAD_SECRET | ✅ | Payload secret (also signs 2FA & tracking). | | NEXT_PUBLIC_SERVER_URL | ✅ | Public URL (email/portal links). | | CRON_SECRET | for crons | x-cron-secret header for the cron endpoints. | | ANTHROPIC_API_KEY / OLLAMA_API_URL | if AI | AI provider keys/URL. | | GOOGLE_OAUTH_CLIENT_ID / _SECRET | if OAuth | Portal Google sign-in. | | VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY | if push | Web Push keys (npx web-push generate-vapid-keys). | | VAPID_SUBJECT | optional | Push contact (mailto: or URL), defaults to mailto:[email protected]. | | SUPPORT_TEAM_SCOPING | optional | 1 to scope agents to their team's tickets. | | SUPPORT_EMAIL / SUPPORT_REPLY_TO | optional | From/reply-to addresses. |

⚡ Performance

Engineered to stay fast under load (no fabricated benchmarks — figures depend on your volume and host):

| Concern | Approach | |---------|----------| | Settings reads | In-process cache (TTL + invalidation) — avoids ~8 redundant DB reads per ticket mutation. | | List queries | SQLite indexes on filtered fields — inbox/dashboard/SLA in O(index) instead of full scans. | | Email sends | Fire-and-forget — the response no longer waits on the SMTP round-trip (−200-500 ms). | | Stats & billing | Paginated aggregation + bounded select — never loads all tickets in memory. | | AI synthesis | Cached per ticket — no LLM recompute on every view. |

📚 Examples

Automation rule (no code)

Create a Automation Rules entry: event = ticket_created, condition category = bug, action set_priority = urgent. New "bug" tickets become "urgent" automatically.

Wire the cron jobs

# Hourly: auto-close, snooze wake-up, scheduled replies
curl -X POST https://your-app/api/support/auto-close      -H "x-cron-secret: $CRON_SECRET"
curl -X POST https://your-app/api/support/process-snooze  -H "x-cron-secret: $CRON_SECRET"
# Daily / weekly: notification digests
curl -X POST https://your-app/api/support/process-digests -H "x-cron-secret: $CRON_SECRET" -d '{"frequency":"daily"}'

❓ FAQ

Built and tested on SQLite (@payloadcms/db-sqlite) with a sequential seed and busyTimeout. It works with any Payload adapter, but indexes and queries were validated on SQLite.

Node.js 18+, Payload 3.x, React 18 or 19.

Yes — strict TypeScript, with business types exported (SupportPluginConfig, SupportFeatures, …).

No. AI features are optional and you can run self-hosted Ollama to depend on no cloud (sovereignty/GDPR). Anthropic and OpenAI are also supported.

In standalone mode the schema isn't auto-migrated: generate/push the schema (new fields and collections) before deploying. See Troubleshooting.

🔧 Troubleshooting

useServerFunctions must be used within ServerFunctionsProvider

Use Payload 3.75+ for all @payloadcms/* packages (aligned versions).

SQLITE_BUSY / database is locked during seed

Make the seed sequential (no Promise.all on inserts) and add busyTimeout: 10000 to the SQLite adapter.

Admin views don't load

Regenerate the import map after adding components: pnpm payload generate:importmap. In a plugin/headless context, use skipViews: true if you don't mount the admin UI.

New fields/collections missing in production

Standalone doesn't run migrations: push the schema for googleId, twoFactorVerifiedAt, slaPausedAt, nps, mentions, and the notification-queue / automation-rules collections.

🔐 Security

Security is a first-class concern — several guardrails are validated by integration tests.

  • Cross-client isolation — a client can never read another's tickets/messages (filtered by owned tickets).
  • 2FA enforced server-side (beforeLogin); OAuth verifies the Google email.
  • Sanitization of message HTML server-side (stored-XSS protection).
  • HMAC-signed webhooks and tracking pixels with constant-time verification and idempotent writes.
  • Cookie-only JWTs for portal authentication (HttpOnly, Secure, SameSite=Lax).
  • Persistent rate limiting for authentication, 2FA, chats, invitations, transfers and AI endpoints.
  • Bounded inbound email payloads and attachments; cron/webhook secrets are accepted in headers only.

Reporting Security Issues

Please email [email protected] instead of opening a public issue.

Best Practices

  • ✅ Set a strong PAYLOAD_SECRET (never a default value)
  • ✅ Set CRON_SECRET to protect the cron endpoints
  • ✅ Restrict read access to the media collection to the ticket owner
  • ✅ Put the app behind a trusted proxy (x-forwarded-for header)
  • ✅ Keep the plugin up-to-date

🤝 Contributing

Contributions are very welcome!

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'feat: add AmazingFeature')
  4. Push the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Run the checks before submitting:

pnpm typecheck && pnpm test && pnpm build

📝 Changelog

See CHANGELOG.md for the full history.

[2.0.1] — 2026-07-16

  • 🌍 Loads the complete shared FR/EN catalogs in every support admin view, fixing raw keys such as ticket statuses, relative dates, time tracking, tags and billing labels.
  • 🧭 Removes translation-key collisions in the support dashboard and settings views.
  • ✅ Adds regression coverage for all 518 literal translation keys used by the support UI and keeps both locales aligned (132 tests passing).

[2.0.0] — 2026-07-16

  • 🔐 Security hardening for authentication, tracking pixels, webhook/cron secrets, HTML/AI output and inbound-email limits.
  • 🚦 Asynchronous persistent rate limiting with a Payload-backed store and memory fallback.
  • 🔢 Atomic persistent ticket counters with configurable prefix and padding.
  • 🧩 Typed deployment adapters for SMS, inbound email, AI workflows, billing, volunteering, cleanup and project suggestions.
  • 🏗️ The plugin is now the single owner of generic support collections, hooks, views and endpoints.
  • ✅ 124 tests covering the security regressions and new capabilities.

[1.1.1] — 2026-06-26

  • 🐛 Fix client ticket reopen: allow clients to set waiting_support (the status the portal's "Reopen" button sends). It was silently rejected, leaving the ticket resolved.

[1.1.0] — 2026-06-25

  • 🎯 Per-team SLA policies & dashboards (team policy overrides the default, ?teamId= scoping).
  • 🔔 Native push / browser notifications (Web Push / VAPID, agent pushed on new client messages).
  • 🎭 End-to-end UI test harness (browser-driven admin via Playwright, pnpm test:e2e).
  • ✅ 109 integration tests (up from 102).

[1.0.0] — 2026-06-25

  • ✨ Complete ticketing, SLA (+ pause-on-hold), automation & visual rules engine.
  • 🤖 AI (sentiment, suggestion, synthesis, chatbot) + autonomous AI agent.
  • 💬 Live chat, client portal (2FA, OAuth), knowledge base.
  • 💶 Time tracking, pre-billing & print-ready invoice.
  • 📊 CSAT + NPS, real volume series, digests, webhooks.
  • 🔐 Security hardening (cross-client isolation, anti-XSS, server-side 2FA).
  • ✅ Integration test harness (Payload + in-memory SQLite), 102 tests.
  • 0.16.0 — Manual client reminder + auto-close after 24h
  • 0.15.0 — Next 16 compatibility + accumulated features
  • 0.9.0 → 0.9.13 — Enriched views (Client Intelligence, Billing), bundled RichTextEditor, code blocks in emails, inline message editing, enriched pre-billing, per-ticket cached AI synthesis, multi-style rewriting
  • 0.6.0 → 0.6.4 — Split build (bundle:false) for Next.js RSC compatibility + barrel exports
  • 0.5.0 — Full i18n across the 13 admin views
  • 0.4.0 — Per-user preferences (locale, signature) vs global settings
  • 0.3.0 — Feature parity with ConsilioWEB + skipCollections / skipViews / skipEndpoints
  • 0.2.0 — 2026-04-08 — Security overhaul, SSE live chat, webhooks, SLA, scheduled replies, client portal
  • 0.1.0 — 2026-04-08 — Initial scaffold: supportPlugin(), 15 collections, feature flags, AI provider abstraction

🗺️ Roadmap

  • [x] Ticketing, SLA, time tracking & billing
  • [x] AI assists + autonomous AI agent
  • [x] Live chat, client portal, knowledge base
  • [x] Visual automation-rules engine
  • [x] Native binary PDF invoice (alongside the print-ready HTML)
  • [x] Full admin i18n (all views)
  • [x] Social channels (WhatsApp, Messenger)
  • [x] Multi-team / workspaces mode
  • [x] Per-team SLA policies & dashboards
  • [x] Native push / browser notifications
  • [x] End-to-end UI test harness (browser-driven admin)

☕ Support

If this plugin saves you time, consider buying me a coffee!

📄 License

Licensed under the MIT License. See the LICENSE file for details.