<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: seyed mojtaba shadab</title>
    <description>The latest articles on DEV Community by seyed mojtaba shadab (@shaadcode).</description>
    <link>https://dev.to/shaadcode</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2895375%2Fb01f1045-84c0-40ab-937f-4156a274202f.jpg</url>
      <title>DEV Community: seyed mojtaba shadab</title>
      <link>https://dev.to/shaadcode</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shaadcode"/>
    <language>en</language>
    <item>
      <title>What is ShaadKit? A Look at My Personal Foundation for Next.js Projects</title>
      <dc:creator>seyed mojtaba shadab</dc:creator>
      <pubDate>Wed, 23 Sep 2026 13:28:06 +0000</pubDate>
      <link>https://dev.to/shaadcode/what-is-shaadkit-a-look-at-my-personal-foundation-for-nextjs-projects-19k0</link>
      <guid>https://dev.to/shaadcode/what-is-shaadkit-a-look-at-my-personal-foundation-for-nextjs-projects-19k0</guid>
      <description>&lt;h2&gt;
  
  
  Where Does the Problem Start?
&lt;/h2&gt;

&lt;p&gt;Imagine you've started a new Next.js project. You're about to build something new and exciting. But before you even write a single line of code for the actual product, you have to get through a mountain of repetitive tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Setting up ESLint&lt;/strong&gt; with the right config and strict rules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setting up Stylelint&lt;/strong&gt; for CSS and CSS Modules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setting up Storybook&lt;/strong&gt; for component-driven development&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adding testing&lt;/strong&gt; with Vitest and Playwright&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setting up i18n&lt;/strong&gt; for multilingual support from the start&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choosing a UI library&lt;/strong&gt; and integrating it with Next.js&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setting up the project structure&lt;/strong&gt; in a way that's ready to scale&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance tooling&lt;/strong&gt; like Bundle Analyzer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Various Next.js configurations&lt;/strong&gt; for optimization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project conventions&lt;/strong&gt; from naming to file structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And this cycle repeats with &lt;strong&gt;every new project&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;create-next-app
      ↓
  configure
      ↓
fix conventions
      ↓
 add tooling
      ↓
 add testing
      ↓
add UI infrastructure
      ↓
finally start building
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Regardless of the fact that this is a repetitive process for every project, it's honestly extremely exhausting (I get really tired of it!)&lt;/p&gt;

&lt;p&gt;One of the best solutions is to use ready-made templates or boilerplates. Given that my main focus is on Next.js, the following can be mentioned as examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ixartz/Next-js-Boilerplate" rel="noopener noreferrer"&gt;Nextjs-boilerplate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/steven-tey/precedent" rel="noopener noreferrer"&gt;precedent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/theodorusclarence/ts-nextjs-tailwind-starter" rel="noopener noreferrer"&gt;ts-nextjs-tailwind-starter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/arhamkhnz/next-shadcn-admin-dashboard" rel="noopener noreferrer"&gt;next-shadcn-admin-dashboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/TailAdmin/free-nextjs-admin-dashboard" rel="noopener noreferrer"&gt;free-nextjs-admin-dashboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Given the variety of repos, I could probably come up with 50 more examples! But I had a bigger problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Don't Want a Template with Too Many Features
&lt;/h2&gt;

&lt;p&gt;I love it when a project has many capabilities. For example, Next.js handles server components, optimizes images, creates routing, manages backend APIs, and so on. But this is not a good idea at all for ready-made templates!&lt;/p&gt;

&lt;p&gt;The reason is obvious. Every technology or feature means making the learning curve steeper. And if a template has too many capabilities, its learning cost increases, while the whole point of using a template is to get started quickly! A developer might even be forced to learn something they've never worked with before or have no interest in using, but they're stuck with it.&lt;/p&gt;

&lt;p&gt;I was looking for something where the capabilities would be plentiful enough, but I wouldn't be obligated to use them. I just wanted to use what I actually needed right now! I believe everything should be just enough — neither more nor less... That's why I created &lt;strong&gt;ShaadKit&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  I'm Happy I Built ShaadKit
&lt;/h2&gt;

&lt;p&gt;For a long time, I was looking for a project that was neither as simple as &lt;code&gt;create-next-app&lt;/code&gt; nor like some boilerplates that pack in more than 50 technologies. I wanted to build an MVP very quickly, so I would use technologies that prioritized speed over quality (though quality is also very important to me).&lt;/p&gt;

&lt;p&gt;Now, with ShaadKit, I can set up a scalable frontend foundation in just a few clicks!&lt;/p&gt;

&lt;p&gt;ShaadKit uses the following technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚡ &lt;strong&gt;Bun&lt;/strong&gt; as the Package Manager — ultra-fast installation and execution&lt;/li&gt;
&lt;li&gt;🧩 &lt;strong&gt;Mantine v9&lt;/strong&gt; — powerful and accessible components&lt;/li&gt;
&lt;li&gt;🌍 &lt;strong&gt;next-intl&lt;/strong&gt; — ready for internationalization from the start&lt;/li&gt;
&lt;li&gt;📖 &lt;strong&gt;Storybook 10&lt;/strong&gt; — component-driven development with MCP and A11y&lt;/li&gt;
&lt;li&gt;🧪 &lt;strong&gt;Vitest + Playwright&lt;/strong&gt; — fast and reliable tests&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;Stylelint + ESLint (Antfu Config)&lt;/strong&gt; — top-tier code quality&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;Bundle Analyzer&lt;/strong&gt; — bundle analysis and optimization&lt;/li&gt;
&lt;li&gt;⚛️ &lt;strong&gt;React 19 + React Compiler&lt;/strong&gt; — the latest React with automatic optimization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But you might say this contradicts what I said a few paragraphs ago: "Every technology or feature means making the learning curve steeper. And if a template has too many capabilities..." However, my approach to this project is a bit different.&lt;/p&gt;

&lt;p&gt;As I explained in the &lt;a href="https://github.com/shaadcode/shaadkit#what-is-the-philosophy-of-this-stack" rel="noopener noreferrer"&gt;What is the philosophy of this stack?&lt;/a&gt; section, I didn't have complex technologies in mind for using ShaadKit, and there's no obligation to use the current technologies. You can even skip Mantine (which is the project's main foundation), but I have good reasons for choosing my technologies.&lt;/p&gt;

&lt;p&gt;You don't necessarily have to use ShaadKit for large projects. Sometimes you need to create a simple table, or validate an idea very quickly. &lt;a href="https://mantine.dev/" rel="noopener noreferrer"&gt;Mantine&lt;/a&gt; was chosen because it was perfectly suited for such an approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  It Has a Simple Configuration That Is Just Creative and Powerful Enough
&lt;/h2&gt;

&lt;p&gt;This is something I personally find very appealing. I wanted it so that if a developer doesn't like my coding style, they'd still admit that I chose a forward-thinking foundation for the project.&lt;/p&gt;

&lt;p&gt;This is appealing to all businesses and employers.&lt;/p&gt;

&lt;p&gt;ShaadKit doesn't have any complex configuration. Everything is simple and minimal, but based on the experience I'd gained, I tried to address some of the blind spots that existed.&lt;/p&gt;

&lt;p&gt;Extending the configuration is very easy, and even beginner developers can do it!&lt;/p&gt;

&lt;p&gt;I didn't add any library that I didn't find useful. As a result, ShaadKit's core is lightweight.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Care a Lot About Code Quality
&lt;/h2&gt;

&lt;p&gt;It's very important to me that the code I write always meets the necessary standards. Naturally, for this I had to use tools like &lt;a href="https://eslint.org/" rel="noopener noreferrer"&gt;ESLint&lt;/a&gt; or &lt;a href="https://oxc.rs/docs/guide/usage/linter" rel="noopener noreferrer"&gt;Oxlint&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I consider Oxlint a very appealing choice, but I chose ESLint because it has more capabilities.&lt;/p&gt;

&lt;p&gt;I also added &lt;a href="https://storybook.js.org/" rel="noopener noreferrer"&gt;Storybook&lt;/a&gt; because developing a component in Storybook is faster than in Next.js! This is possible thanks to Vite. When I first got to know Storybook, it honestly became very hard for me to walk away from it.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Chose the Best Package Manager (In My Opinion)
&lt;/h2&gt;

&lt;p&gt;I've used both npm and pnpm! Aside from being the most stable, npm doesn't have any defensible feature, but pnpm is a milestone for the world of package managers.&lt;/p&gt;

&lt;p&gt;However, on Windows (which has no shortage of developers), pnpm usually performs much slower than it claims, due to the nature of symlinks.&lt;/p&gt;

&lt;p&gt;I decided to use &lt;a href="https://bun.com/package-manager" rel="noopener noreferrer"&gt;Bun as the package manager&lt;/a&gt; so I could get both pnpm's speed and npm's stability. If you want to use the same symlink capability, &lt;a href="https://bun.com/blog/bun-v1.4#global-virtual-store-up-to-7x-faster-installs" rel="noopener noreferrer"&gt;you can enable it in Bun&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Don't Use Next-intl Just for Internationalization!
&lt;/h2&gt;

&lt;p&gt;Of course, the main reason &lt;a href="https://next-intl.dev/" rel="noopener noreferrer"&gt;Next-intl&lt;/a&gt; was created is to solve internationalization problems in Next.js, but I look at it from a different angle!&lt;/p&gt;

&lt;p&gt;The thing is, maybe the site being developed is monolingual, and there are no plans to add more languages in the near future.&lt;/p&gt;

&lt;p&gt;But there's another problem that Next-intl can solve: "managing static text." You've surely run into the issue where, to change a single word on the site, you have to go into several files across different parts of the project and edit them. With Next-intl, all the words are managed in one place with the utmost simplicity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating Next.js and Next-intl with Mantine
&lt;/h2&gt;

&lt;p&gt;This is also mentioned in Mantine's own documentation. Mantine internally maintains two components, &lt;code&gt;Image&lt;/code&gt; and &lt;code&gt;Anchor&lt;/code&gt; (which is similar to &lt;code&gt;Link&lt;/code&gt; in Next.js).&lt;/p&gt;

&lt;p&gt;But the problem is that, under normal circumstances, using these two components means losing the power of Next.js!&lt;/p&gt;

&lt;p&gt;In ShaadKit's configuration, from the very start, the &lt;code&gt;Image&lt;/code&gt; component (from Next.js) has been merged with the &lt;code&gt;Image&lt;/code&gt; component (from Mantine).&lt;/p&gt;

&lt;p&gt;Also, for internationalization and Next.js optimization, the &lt;code&gt;Anchor&lt;/code&gt; component has been merged with the &lt;code&gt;Link&lt;/code&gt; component (exported from Next-intl, which itself extends Next.js).&lt;/p&gt;

&lt;h2&gt;
  
  
  Just Try It Once
&lt;/h2&gt;

&lt;p&gt;As I said, you can set up ShaadKit very quickly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure you have Bun installed, and using Node.js version 24 is highly recommended&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone the project&lt;/span&gt;
git clone https://github.com/shaadcode/shaadkit.git
&lt;span class="nb"&gt;cd &lt;/span&gt;shaadkit

&lt;span class="c"&gt;# Install dependencies with Bun&lt;/span&gt;
bun &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Run the development server&lt;/span&gt;
bun dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Who Should Use ShaadKit?
&lt;/h2&gt;

&lt;p&gt;ShaadKit is useful for most projects, but there are always some considerations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js developers&lt;/li&gt;
&lt;li&gt;SaaS projects&lt;/li&gt;
&lt;li&gt;MVPs that are likely to grow&lt;/li&gt;
&lt;li&gt;Production projects&lt;/li&gt;
&lt;li&gt;Multilingual projects&lt;/li&gt;
&lt;li&gt;Projects where testing and component development matter&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contribute, Give Feedback, Support
&lt;/h2&gt;

&lt;p&gt;Contributing to ShaadKit is easy. You can report a bug, offer your suggestion, or share your criticism:&lt;/p&gt;

&lt;p&gt;If ShaadKit managed to solve a problem for you, I'd be very happy if you gave the repo a star (⭐).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/shaadcode/shaadkit" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/shaadcode/shaadkit/issues" rel="noopener noreferrer"&gt;Issues&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/shaadcode/shaadkit/pulls" rel="noopener noreferrer"&gt;Pull Requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/shaadcode/shaadkit/discussions/categories/feature-requests-and-ideas" rel="noopener noreferrer"&gt;Feature requests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>frontend</category>
      <category>nextjs</category>
      <category>react</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Introducing ICU Studio - Fast and lightweight IDE for ICU messages</title>
      <dc:creator>seyed mojtaba shadab</dc:creator>
      <pubDate>Wed, 09 Sep 2026 20:53:39 +0000</pubDate>
      <link>https://dev.to/shaadcode/introducing-icu-studio-fast-and-lightweight-ide-for-icu-messages-f1c</link>
      <guid>https://dev.to/shaadcode/introducing-icu-studio-fast-and-lightweight-ide-for-icu-messages-f1c</guid>
      <description>&lt;p&gt;As a front-end developer, I often encounter projects that require internationalization (i18n). Making a website multilingual with plain text messages is quite challenging and doesn't offer a great development experience. That's why I decided to use ICU messages.&lt;/p&gt;

&lt;p&gt;It's worth noting that using ICU messages directly doesn't make sense—you always need a parser to process them.&lt;/p&gt;

&lt;p&gt;Typically, ICU messages are stored inside JSON files so they can be easily used across different projects. However, there's a major issue: editors like VS Code cannot recognize the structure of ICU messages or highlight the different parts of a message (which is natural, since they weren't built for this purpose).&lt;/p&gt;

&lt;p&gt;For example, in the image below, it's quite difficult to tell that the argument is actually an ICU variable:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu32ee0f97nxymmksq3cr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu32ee0f97nxymmksq3cr.png" alt=" " width="571" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And of course it gets harder if the message gets a bit more complicated (although in real scenarios this is also a simple message):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjem28e1wutujyvuu4w29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjem28e1wutujyvuu4w29.png" alt=" " width="800" height="79"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As I mentioned earlier, this isn't really a problem—it's the normal behavior of editors or IDEs. Because from our perspective, this is an ICU message, but from the editor's perspective, it's just a string and the value of a message key.&lt;/p&gt;

&lt;p&gt;So creating or editing ICU messages (at least for me) became a tedious task.&lt;/p&gt;

&lt;h3&gt;
  
  
  I looked for a tool, but I couldn't find what I wanted!
&lt;/h3&gt;

&lt;p&gt;I was really surprised that this internationalization standard doesn't have a sufficiently good tool to manage it.&lt;/p&gt;

&lt;p&gt;Most web developers use VS Code, and there are several extensions that directly or indirectly help with creating or editing ICU messages—but they simply weren't enough. Because even though VS Code is powerful, it can be limiting for development.&lt;/p&gt;

&lt;p&gt;Also, I couldn't find any standalone software that I could install on my operating system and comfortably manage ICU messages without any dependencies.&lt;/p&gt;

&lt;p&gt;These were the reasons that led me to create ICU Studio...&lt;/p&gt;

&lt;h3&gt;
  
  
  A lightweight but powerful editor
&lt;/h3&gt;

&lt;p&gt;I decided to use my React development skills to create a desktop application that would solve my problems in this area.&lt;/p&gt;

&lt;p&gt;But there were some points I had to consider. For example, my editor had to be fast and very lightweight so it wouldn't slow down development. React is fast enough, but when combined with Electron, it can sometimes become slow—and that's due to Electron's nature, not React itself. Also, it should consume less memory when idle.&lt;/p&gt;

&lt;p&gt;Tauri was the tool that helped me build ICU Studio. The result was a very lightweight and optimized application that launches in less than 2 seconds.&lt;/p&gt;

&lt;p&gt;But speed wasn't the only thing that mattered to me. I wanted to read ICU messages faster, edit them faster, test different variations, and more...&lt;/p&gt;

&lt;h3&gt;
  
  
  ICU Studio Features
&lt;/h3&gt;

&lt;p&gt;At the time I'm publishing this article, this editor is in its MVP stage, but it still has enough features that truly solved my problem as a user.&lt;/p&gt;

&lt;h4&gt;
  
  
  Dedicated Syntax Highlighting
&lt;/h4&gt;

&lt;p&gt;Naturally, the first thing I needed was to understand the structure of my message. Parsing the message and highlighting it made it possible to grasp the overall structure of any message within the first moments of encountering it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Formatting
&lt;/h4&gt;

&lt;p&gt;In addition to highlighting, formatting the message was another important and fundamental feature of this editor—it increased the readability of messages many times over.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp0uz6sok2mj7zivemfrt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp0uz6sok2mj7zivemfrt.png" alt=" " width="190" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Copy with Different Output Formats
&lt;/h4&gt;

&lt;p&gt;One problem I personally faced in my projects was that sometimes I needed to use the message inside components, and other times inside JSON files. Now ICU Studio can copy the same message in the following four ways:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// simple or pretty copy:&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;variable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;select&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;option1&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;option2&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;other&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// one line copy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;variable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;select&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;option1&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;option2&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;other&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;

&lt;span class="c1"&gt;// json property copy&lt;/span&gt;
&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{variable,select,option1{text} option2{text} other{text}}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="c1"&gt;// function copy&lt;/span&gt;
&lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Ready-to-Use Snippets
&lt;/h4&gt;

&lt;p&gt;Up to this point, I had only improved readability. But the problem that still remained was creating an ICU message in the shortest possible time. For example, creating a plural message still took time! Snippets allowed me to generate the entire structure with just one click:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnjmh3fxzu63olubo5sxv.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnjmh3fxzu63olubo5sxv.gif" alt=" " width="588" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Simple Statistics for Variable Count
&lt;/h4&gt;

&lt;p&gt;When messages become complex, it's helpful to know what types of variables exist and how many of each there are:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpfdhsz0pxj1w8gnbgr98.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpfdhsz0pxj1w8gnbgr98.png" alt=" " width="517" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Testing Variables Inside the Message
&lt;/h4&gt;

&lt;p&gt;This is a feature I truly enjoy. With a simple user interface, you can quickly test your message, examine different outputs, and have a real-time preview:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcctt2itfgc08x98lm2hw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcctt2itfgc08x98lm2hw.png" alt=" " width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the image, details of each variable are also displayed, which can be very useful in complex messages.&lt;/p&gt;

&lt;h4&gt;
  
  
  Message Validation
&lt;/h4&gt;

&lt;p&gt;It's completely normal that human errors can cause the message structure to be incorrect, leading to errors in the project. In ICU Studio, if you encounter an error, you can see the exact reason for it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkyhhws6yhleprqvyu9er.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkyhhws6yhleprqvyu9er.png" alt=" " width="329" height="170"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Variable Actions
&lt;/h4&gt;

&lt;p&gt;By right-clicking on any variable in your message, you can perform three actions: Delete, Copy, and Cut. All actions are applied only to the specific variable you clicked on:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3pera8749idedt8tb62k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3pera8749idedt8tb62k.png" alt=" " width="400" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Undo/Redo
&lt;/h4&gt;

&lt;p&gt;The simplest and one of the most frequently used features that I've found invaluable in ICU Studio. You can comfortably work on complex messages because your change history is never lost, and you can always go back to previous versions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Smart JSON Property Insertion
&lt;/h4&gt;

&lt;p&gt;In VS Code (when you haven't selected any text), pressing Ctrl+C copies the entire line. Now, if you copy a message with its JSON property, smart insertion allows you to extract just the message value. This is especially useful when your message is long and selecting it with the mouse might take time:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fylhdzt1oxn1s11oe927o.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fylhdzt1oxn1s11oe927o.gif" alt=" " width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Use It?
&lt;/h3&gt;

&lt;p&gt;From download to usage, it takes less than 2 minutes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;a href="https://github.com/shaadcode/ICU-Studio/releases" rel="noopener noreferrer"&gt;GitHub Releases page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Download and install the appropriate version for your operating system&lt;/li&gt;
&lt;li&gt;That's it!&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Future of ICU Studio
&lt;/h3&gt;

&lt;p&gt;Approximately 80% of the major features for ICU Studio have not been built yet. This is a deliberate decision because I want to gather feedback from users and steer the project based on actual needs—not just what I personally want. So there are definitely bigger features waiting for ICU Studio in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  Your Support Means a Lot...
&lt;/h3&gt;

&lt;p&gt;This project started as a personal endeavor, but I decided to release it as open source. If this project manages to solve a problem for you, I would be very happy if you could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⭐ Give the project a star on &lt;a href="https://github.com/shaadcode/ICU-Studio" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🐛 Report any issues you encounter&lt;/li&gt;
&lt;li&gt;💡 Share your feature requests with me&lt;/li&gt;
&lt;li&gt;🤝 Contribute to making the project even better&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>i18n</category>
      <category>tauri</category>
      <category>opensource</category>
      <category>react</category>
    </item>
    <item>
      <title>Exploring customLogger: Smart, Customizable Logging in Payload CMS</title>
      <dc:creator>seyed mojtaba shadab</dc:creator>
      <pubDate>Tue, 27 May 2025 05:51:03 +0000</pubDate>
      <link>https://dev.to/shaadcode/exploring-customlogger-smart-customizable-logging-in-payload-cms-10kc</link>
      <guid>https://dev.to/shaadcode/exploring-customlogger-smart-customizable-logging-in-payload-cms-10kc</guid>
      <description>&lt;h2&gt;
  
  
  🧾 Brief Introduction to Payload CMS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://payloadcms.com/" rel="noopener noreferrer"&gt;Payload CMS&lt;/a&gt;&lt;/strong&gt; is a &lt;strong&gt;Headless&lt;/strong&gt; content management system based on Node.js and TypeScript, designed for developers. Unlike many traditional CMSs that come with pre-built UIs or themes, Payload focuses on providing a developer-centric, API-driven, and customizable experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  🎯 Key Features of Payload:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript-first&lt;/strong&gt; structure: All structures, data models, and configurations are defined with the powerful TypeScript type system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern admin interface&lt;/strong&gt;: Automatically generates a complete content management UI from your schema.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in security and authentication&lt;/strong&gt;: It has a built-in, extensible authentication and access control system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hooks and Plugins Support&lt;/strong&gt;: You can control the behavior of the system precisely using hooks and plugins.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Payload allows developers to create a highly customizable, secure, and extensible content management system without being limited to predefined structures. That is why it is a popular choice for complex, custom, and modern projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔍 What is the &lt;code&gt;payload-auditor&lt;/code&gt; plugin?
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;payload-auditor&lt;/code&gt;&lt;/strong&gt; plugin is a powerful plugin for Payload CMS that allows for precise &lt;strong&gt;audit&lt;/strong&gt; of operations performed on collections. The plugin automatically records all changes such as &lt;strong&gt;create&lt;/strong&gt;, &lt;strong&gt;update&lt;/strong&gt;, and &lt;strong&gt;delete&lt;/strong&gt; data and stores them in a structured log format.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✨ The main goal of this plugin:
&lt;/h3&gt;

&lt;p&gt;Provide a transparent and reliable logging system for monitoring user behavior and reviewing database-level change history.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚙️ Key features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Automatic logging of operations on collections&lt;/li&gt;
&lt;li&gt;Support for defining &lt;strong&gt;custom logger&lt;/strong&gt; for custom logging&lt;/li&gt;
&lt;li&gt;Support for all CMS payload hooks&lt;/li&gt;
&lt;li&gt;Modular design with extensibility for complex projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using this plugin, developers and system administrators can easily understand who, when, and what changes were made to the system; a vital feature for projects where security, transparency, and audit trails are of high importance. To learn more about this plugin, you can read the article &lt;a href="https://dev.to/shaadcode/tracking-and-security-in-payload-cms-with-the-payload-auditor-plugin-mpk"&gt;Tracking and Security in Payload CMS with the Payload-Auditor Plugin&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  📚 The importance of custom logging in content management systems (CMS)
&lt;/h2&gt;

&lt;p&gt;In content management systems, especially in enterprise or sensitive projects, &lt;strong&gt;accurate tracking of user activities and data changes&lt;/strong&gt; plays a very important role. While basic logging can capture general information about operations, custom logging allows for &lt;strong&gt;accurate, targeted, and analyzable information&lt;/strong&gt; to be stored for the specific needs of each project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do we need custom logging?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. 🎯 Customization
&lt;/h4&gt;

&lt;p&gt;Projects are different; one project may need to record user IP, another may want to store user roles or geographic information. Custom logging allows for &lt;strong&gt;critical information tailored to the project scenario&lt;/strong&gt; to be recorded.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. 🕵️‍♀️ Transparency and Audit Trail
&lt;/h4&gt;

&lt;p&gt;For systems that require user behavior to be investigated or security issues to be addressed, the &lt;strong&gt;complete change trail&lt;/strong&gt; (who changed what, when, and how) must be clearly visible. This transparency cannot be achieved without accurate and customized logging.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. 🔐 Security and Accountability
&lt;/h4&gt;

&lt;p&gt;In many projects, especially in areas such as finance, medicine or government, accurate recording of activities plays an important role in &lt;strong&gt;data security and user accountability&lt;/strong&gt;. Custom logs can also be used as legal evidence.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. 📊 Analytics and Intelligence
&lt;/h4&gt;

&lt;p&gt;With rich and structured logs, you can analyze user behavior, identify process weaknesses and ultimately make &lt;strong&gt;more informed decisions&lt;/strong&gt; to improve system performance.&lt;/p&gt;

&lt;p&gt;Logging is not just a monitoring tool; it is an integral part of &lt;strong&gt;security, optimization and professional management of content systems&lt;/strong&gt;. By providing the ability to record custom logs, you can have much more control and insight into what is happening in the system.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔧 What is &lt;code&gt;customLogger&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;payload-auditor&lt;/code&gt; plugin, the &lt;code&gt;customLogger&lt;/code&gt; feature allows developers to &lt;strong&gt;fully customize logging behavior at the hook level&lt;/strong&gt;. This feature is designed for projects that need to generate or modify log content in a specific way depending on different conditions, since it is almost impossible to predict the default values for logging in the logs.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧩 Defining &lt;code&gt;customLogger&lt;/code&gt; at the Hook Level
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;customLogger&lt;/code&gt; is an &lt;strong&gt;optional&lt;/strong&gt; function that can be specified in the &lt;code&gt;payload-auditor&lt;/code&gt; plugin configuration. This function is called when the hook used for each operation is executed and can &lt;strong&gt;edit or overwrite&lt;/strong&gt; the log data before final storage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;customLogger&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Parameters&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AllCollectionHooks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;afterChange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Omit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuditorLog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Omit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuditorLog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Omit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuditorLog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;args&lt;/code&gt;: Contains information about the hook for the same document and can have values like &lt;code&gt;req&lt;/code&gt;, &lt;code&gt;operation&lt;/code&gt;, &lt;code&gt;doc&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fields&lt;/code&gt;: Contains the default log structure without the &lt;code&gt;hook&lt;/code&gt; field (because the principle of which hook created this log should not change).&lt;/li&gt;
&lt;li&gt;The output of the function should be a final version of &lt;code&gt;AuditorLog&lt;/code&gt; (except for the &lt;code&gt;hook&lt;/code&gt; added by the plugin).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🔀 Multi-level &lt;code&gt;customLoggers&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;payload-auditor&lt;/code&gt;, we have considered four levels of the customLogger function to increase flexibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔢 &lt;code&gt;customLogger&lt;/code&gt; definition levels (in order of execution priority):
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. 🥇 Operation-Level
&lt;/h4&gt;

&lt;p&gt;At this level, a dedicated &lt;code&gt;customLogger&lt;/code&gt; can be defined for each specific operation (&lt;code&gt;create&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;). This level has the &lt;strong&gt;highest execution priority&lt;/strong&gt; and if it exists, no other levels will be executed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;customLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📌 Applies only to that specific operation&lt;br&gt;
✅ Has the highest priority&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h4&gt;
  
  
  2. 🥈 Hook-Level
&lt;/h4&gt;

&lt;p&gt;If &lt;code&gt;customLogger&lt;/code&gt; is not defined for a specific operation, the system looks for &lt;code&gt;customLogger&lt;/code&gt; at the hook level, such as &lt;code&gt;afterChange&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;customLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📌 Only for &lt;strong&gt;specific hook&lt;/strong&gt; (e.g. afterChange)&lt;br&gt;
❌ Not executed if &lt;code&gt;customLogger&lt;/code&gt; is defined as an operation level&lt;br&gt;
✅ Only works on active operations&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h4&gt;
  
  
  3. 🥉 All Hooks Level (Hooks-Level)
&lt;/h4&gt;

&lt;p&gt;At this level, &lt;code&gt;customLogger&lt;/code&gt; is applied to &lt;strong&gt;all hooks and operations&lt;/strong&gt;, if none of the previous two levels exist.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;customLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📌 Only runs if there is no logger at the hook and operation level&lt;br&gt;
✅ Only works on active operations&lt;br&gt;
❌ Cannot be defined for a specific hook – covers the entire hook system&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h4&gt;
  
  
  4. 🏁 Global-Level
&lt;/h4&gt;

&lt;p&gt;If no &lt;code&gt;customLogger&lt;/code&gt; is defined at the operation, hook or all hooks level, then the global &lt;code&gt;customLogger&lt;/code&gt; is run. This level works for &lt;strong&gt;all collections&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;customLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;custom user agent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;📌 Last level of fallback in execution priority&lt;br&gt;
✅ Works only on active operations&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  🔁 Execution hierarchy summary:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Highest priority] Operation → Hook → All hooks → Global [Lowest priority]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The more detailed the definition level, the higher the execution priority. This hierarchy provides great flexibility for precise, customized, and targeted logging.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧬 &lt;code&gt;customLogger&lt;/code&gt; structure
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;customLogger&lt;/code&gt; function is the heart of the custom logging mechanism in the &lt;code&gt;payload-auditor&lt;/code&gt; plugin. This function allows you to &lt;strong&gt;edit or generate log fields&lt;/strong&gt; before final logging. To do this, the function takes two inputs and must return a specific output.&lt;/p&gt;

&lt;h3&gt;
  
  
  🛠 Function Inputs
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;customLogger&lt;/code&gt; function has two main inputs:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. &lt;code&gt;args&lt;/code&gt;: All hook arguments
&lt;/h4&gt;

&lt;p&gt;This argument contains complete information about the current hook and the operation that was executed. Typically contains values like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;req&lt;/code&gt;: HTTP request object&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;operation&lt;/code&gt;: Operation type (&lt;code&gt;create&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;doc&lt;/code&gt;: Final document after modification&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;previousDoc&lt;/code&gt;: Previous document (in update and delete operations)&lt;/li&gt;
&lt;li&gt;Other information depending on the hook type&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. &lt;code&gt;fields&lt;/code&gt;: Initial log structure (Log Fields)
&lt;/h4&gt;

&lt;p&gt;This object contains the default log data generated by the plugin, &lt;strong&gt;without fields&lt;/strong&gt; &lt;strong&gt;&lt;code&gt;hook&lt;/code&gt;&lt;/strong&gt;. You can override, modify, or add fields to this object.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📍Note: If you want to add a new field, you must define that field for the plugin root collection using &lt;code&gt;configureRootCollection&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  📤 Expected Output
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;customLogger&lt;/code&gt; function should return an object that has the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nb"&gt;Omit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuditorLog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is, it must include all the fields required for logging, except &lt;code&gt;hook&lt;/code&gt; which is automatically added by the plugin.&lt;/p&gt;

&lt;p&gt;📌 &lt;strong&gt;Simple example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unknown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ⏳ Support for async operations
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;customLogger&lt;/code&gt; function can also operate &lt;strong&gt;asynchronously (&lt;/strong&gt;***&lt;em&gt;**&lt;code&gt;async&lt;/code&gt;&lt;/em&gt;*  &lt;strong&gt;)&lt;/strong&gt; . That is, you can use async functions such as accessing a database, reading from external APIs or long-running processes and return the final value with &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;📌 &lt;strong&gt;Example with Promise:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;geoInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getGeoInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;geoInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔄 If the function output is of type &lt;code&gt;Promise&lt;/code&gt;, the plugin will automatically resolve it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This flexibility in the &lt;code&gt;customLogger&lt;/code&gt; structure allows you to generate the structure you want for any scenario, from simple logging to the most complex analytics.&lt;/p&gt;




&lt;h2&gt;
  
  
  📌 Practical examples
&lt;/h2&gt;

&lt;p&gt;In this section, we will examine two common examples of &lt;code&gt;customLogger&lt;/code&gt; usage; one simple and the other with async operations. Each example is analyzed line by line to make the practical concepts clear.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. 🧼 Changing the user value to &lt;code&gt;null&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;customLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  🧩 Line-by-line analysis
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;customLogger&lt;/code&gt;: is a synchronous function that takes two parameters:&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;args&lt;/code&gt;: information about the operation, such as request, document, etc.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fields&lt;/code&gt;: raw log data before final processing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;...fields&lt;/code&gt;: first we keep all the initial fields of the log.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user: null&lt;/code&gt;: then we manually set the value of &lt;code&gt;user&lt;/code&gt; to &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🎯 Real-world uses of this change
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Removal of sensitive information&lt;/strong&gt;: In some scenarios you may not want to record user IDs or information (for example, in anonymous forms).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anonymization of logs&lt;/strong&gt; for privacy or in test environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated processes&lt;/strong&gt; where no human user is involved and &lt;code&gt;user&lt;/code&gt; is irrelevant.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. 🌐 Adding custom information (e.g. IP)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;📍Note: If you want to add a new field, you must define that field for the plugin root collection using &lt;code&gt;configureRootCollection&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;customLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getIPFromRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  🧩 Line-by-line analysis
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The function is &lt;code&gt;async&lt;/code&gt; because it uses the &lt;code&gt;await&lt;/code&gt; helper function.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getIPFromRequest(args.req)&lt;/code&gt;: A hypothetical function to extract the IP from the request.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;...fields&lt;/code&gt;: Preserve the original data.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;meta: { ...fields.meta, ip }&lt;/code&gt;: Add the IP to the log metadata section, without removing the previous metadata.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🧰 Introducing the helper function
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;getIPFromRequest&lt;/code&gt; function can be defined simply as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getIPFromRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;PayloadRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-forwarded-for&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unknown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This function first gets the IP from &lt;code&gt;req.ip&lt;/code&gt;, otherwise it uses proxy headers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  🎯 Real-world applications
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security analysis&lt;/strong&gt;: Detect suspicious situations by examining IP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recording user behavior&lt;/strong&gt; based on geographic location.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring system load&lt;/strong&gt; from specific regions or specific users.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚠️ Critical points when using &lt;code&gt;customLogger&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;To use &lt;code&gt;customLogger&lt;/code&gt; correctly and effectively in the &lt;code&gt;payload-auditor&lt;/code&gt; plugin, it is crucial to be familiar with some limitations and prioritization behaviors. In this section, we will review the most important critical points:&lt;/p&gt;

&lt;h3&gt;
  
  
  🔄 1. Prioritization when using customLogger
&lt;/h3&gt;

&lt;p&gt;If you have defined &lt;code&gt;customLogger&lt;/code&gt; at different levels (for example, both at the operation level and at the hook or global level), the plugin will always &lt;strong&gt;use the closest definition&lt;/strong&gt;. The order of precedence is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;customLogger at the operation-level&lt;/strong&gt;
For example:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;customLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Highest priority – will only be executed for that specific operation.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;customLogger at hook level&lt;/strong&gt;
For example:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;afterChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;customLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Runs only if the corresponding operation does not have a dedicated customLogger.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;customLogger at the global hooks level&lt;/strong&gt;
For example:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;customLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Runs if neither operation-level nor hook-level customLogger exists.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;customLogger at global level (for all collections)&lt;/strong&gt; 
For example:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;auditor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;customLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Finally, the final fallback; runs only if no other level has a customLogger.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧩 2. Differences with &lt;code&gt;customLogger&lt;/code&gt; at hook level
&lt;/h3&gt;

&lt;p&gt;There are important differences between &lt;code&gt;customLogger&lt;/code&gt; at hook level (e.g. &lt;code&gt;afterChange&lt;/code&gt;) and operation level:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;customLogger (operation)&lt;/th&gt;
&lt;th&gt;customLogger (hook-level)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dependent on operation type&lt;/td&gt;
&lt;td&gt;For any operation you have defined&lt;/td&gt;
&lt;td&gt;Yes, but only when not defined&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope of effect&lt;/td&gt;
&lt;td&gt;A specific operation&lt;/td&gt;
&lt;td&gt;All operations related to that hook&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execution priority&lt;/td&gt;
&lt;td&gt;Higher&lt;/td&gt;
&lt;td&gt;Lower than operation level&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ It is important not to confuse these two levels, as you might think your customLogger is running, but because there is a more precise version at a lower level, it is not called at all.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ✅ Best Practices
&lt;/h2&gt;

&lt;p&gt;To make your logging system both fast and secure, it is very important to follow a few key principles in the design and implementation of &lt;code&gt;customLogger&lt;/code&gt;. In this section, we will discuss recommendations that will both improve the developer experience and make the system easier to maintain:&lt;/p&gt;

&lt;h3&gt;
  
  
  🧼 1. Keep your log structure simple
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimalism&lt;/strong&gt; in logging helps reduce data volume and storage costs.&lt;/li&gt;
&lt;li&gt;Avoid adding unnecessary or nested fields.&lt;/li&gt;
&lt;li&gt;Always design logs for fast processing in analytics systems (like ELK, Datadog, or Logstash).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Good example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❌ &lt;strong&gt;Bad example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;debugDump&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;requestHeaders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="na"&gt;callStack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔐 2. Avoid storing sensitive data (unless encrypted)
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;📍Note: The plugin itself may store email in raw form in the logs. It is the developer's responsibility to use encryption to store sensitive data&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Avoid storing private user data such as email, IP, or phone number in raw form.&lt;/li&gt;
&lt;li&gt;If you need to store this data, use encryption or hashing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Suggested example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="na"&gt;emailHash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🌐 3. Use async for external data
&lt;/h3&gt;

&lt;p&gt;If you need to get data from external sources (such as IP location, browser information, or external validations), &lt;code&gt;customLogger&lt;/code&gt; fully supports &lt;code&gt;async&lt;/code&gt; functions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Adding user location from IP&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;customLogger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getGeoLocation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📌 &lt;strong&gt;Note:&lt;/strong&gt;  If you use external resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pay attention to API latency.&lt;/li&gt;
&lt;li&gt;Consider caching or rate-limiting.&lt;/li&gt;
&lt;li&gt;Use appropriate timeouts so that the entire log process does not break.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🎯 Other recommendations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use collections for testing &lt;code&gt;customLogger&lt;/code&gt; whose changes are less critical.&lt;/li&gt;
&lt;li&gt;Do not use &lt;code&gt;customLogger&lt;/code&gt; to modify the original data (it is only for creating logs).&lt;/li&gt;
&lt;li&gt;If you need a different customLogger based on the user type, you can put a condition in it:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  📍 Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;customLogger&lt;/code&gt; feature in the &lt;code&gt;payload-auditor&lt;/code&gt; plugin is a very powerful tool for customizing the logging process in Payload CMS-based projects. This feature allows you to precisely and with full control, tailor the content of the logs to your project's security, analytical, and operational needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧩 Summary of features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High flexibility&lt;/strong&gt; at four levels: operation level, hook, hooks-level and global&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ability to process synchronously and asynchronously (async)&lt;/strong&gt;  in log generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Support for external data&lt;/strong&gt; such as IP, geolocation or user role&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ability to filter, modify, or remove sensitive information&lt;/strong&gt; before saving&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🎯 More accurate tracking of system changes
&lt;/h3&gt;

&lt;p&gt;By using &lt;code&gt;customLogger&lt;/code&gt; wisely, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Record and analyze specific changes based on user context&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate targeted and actionable logs&lt;/strong&gt; that are valuable for monitoring and security tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make the debugging process&lt;/strong&gt; faster and more accurate for the development team&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  💡 Suggestions for developers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;customLogger&lt;/code&gt; to &lt;strong&gt;build a reliable logging infrastructure&lt;/strong&gt; alongside other observability tools like Sentry Or use Grafana.&lt;/li&gt;
&lt;li&gt;For projects with high security requirements, be sure to &lt;strong&gt;encrypt sensitive data&lt;/strong&gt; in logs.&lt;/li&gt;
&lt;li&gt;Use async loggers to &lt;strong&gt;balance system performance with log richness.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ultimately, &lt;code&gt;customLogger&lt;/code&gt; is not just an optional feature, but can be a key part of your audit and security strategy. If used correctly, it can be the difference between a purely decorative log and a real analysis and response tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔗 Link to the main plugin documentation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/shaadcode/payload-auditor#readme" rel="noopener noreferrer"&gt;Official documentation &lt;/a&gt;&lt;a href="https://github.com/shaadcode/payload-auditor#readme" rel="noopener noreferrer"&gt;&lt;code&gt;payload-auditor&lt;/code&gt;&lt;/a&gt;
Includes a full explanation of options, log structure, logging levels, and practical examples.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  💻 GitHub Repository Link
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Repository:
👉 &lt;a href="https://github.com/shaadcode/payload-auditor" rel="noopener noreferrer"&gt;https://github.com/shaadcode/payload-auditor&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this repo you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;View and install the latest version of the plugin&lt;/li&gt;
&lt;li&gt;Track Issues and Feature Requests&lt;/li&gt;
&lt;li&gt;Contribute to the plugin development&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🤝 Appreciation and Contribution
&lt;/h4&gt;

&lt;p&gt;If you found this plugin useful or this article helped you understand it better, please support me by giving the &lt;a href="https://github.com/shaadcode/payload-auditor" rel="noopener noreferrer"&gt;payload-auditor&lt;/a&gt; repo a ⭐️. This motivates me to develop more open source tools.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🙏 Thank you for your support!&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>react</category>
      <category>security</category>
    </item>
    <item>
      <title>Tracking and Security in Payload CMS with the Payload-Auditor Plugin</title>
      <dc:creator>seyed mojtaba shadab</dc:creator>
      <pubDate>Sat, 24 May 2025 05:32:37 +0000</pubDate>
      <link>https://dev.to/shaadcode/tracking-and-security-in-payload-cms-with-the-payload-auditor-plugin-mpk</link>
      <guid>https://dev.to/shaadcode/tracking-and-security-in-payload-cms-with-the-payload-auditor-plugin-mpk</guid>
      <description>&lt;p&gt;Before we get into the main topic of the article, let's first learn about Payload CMS.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Brief Introduction to Payload CMS
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Payload CMS&lt;/strong&gt; is a modern, fully JavaScript-based, headless content management system. Unlike many traditional CMSs, Payload has a strong focus on &lt;strong&gt;customization, high performance, and a developer-centric experience&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of using pre-built panels, it allows you to fully define the structure and behavior of your admin panel through code. Some of its notable features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Full support for &lt;strong&gt;TypeScript&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Advanced system for defining &lt;strong&gt;collections and fields&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ability to add &lt;strong&gt;hooks and detailed access control&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Headless design for use in separate &lt;strong&gt;Frontend projects (React, Next.js, Vue, etc.)&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And strong support for &lt;strong&gt;authentication, file upload, and REST and GraphQL APIs&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, Payload CMS is a powerful option for developers who want full control over the structure and functionality of their CMS — without having to deal with the limitations of traditional platforms.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do we need logging and tracing in Payload?
&lt;/h3&gt;

&lt;p&gt;In the world of modern software, especially in projects built with headless CMSs like &lt;strong&gt;Payload CMS&lt;/strong&gt;, the issue of &lt;strong&gt;security, transparency, and user behavior analysis&lt;/strong&gt; is of utmost importance.&lt;/p&gt;

&lt;p&gt;As the scale of the project grows and the number of users or administrators increases, knowing &lt;strong&gt;who did what, when, and where&lt;/strong&gt; is no longer an optional feature — it is a &lt;strong&gt;vital need&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here are some reasons why logging and tracing is necessary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧑‍💻 &lt;strong&gt;Track user actions&lt;/strong&gt;: Who changed the information? When was a file deleted? Did someone log in with the wrong access?&lt;/li&gt;
&lt;li&gt;🛡️ &lt;strong&gt;Increase security&lt;/strong&gt;: Recording suspicious or sensitive events (such as changes to user information or suspicious logins) is the first line of defense against attacks.&lt;/li&gt;
&lt;li&gt;🧾 &lt;strong&gt;Organizational Transparency&lt;/strong&gt;: In multi-person teams, knowing the history of actions prevents repetitive errors and creates order in team processes.&lt;/li&gt;
&lt;li&gt;🧪 &lt;strong&gt;Debugging and analyzing system behavior&lt;/strong&gt;: Having a history of operations is very helpful when developing or investigating problems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Payload Auditor Plugin: Answering Your Monitoring and Security Needs
&lt;/h3&gt;

&lt;p&gt;This is where the &lt;strong&gt;Payload Auditor&lt;/strong&gt; plugin comes in. It is designed to work seamlessly with Payload CMS, allowing for &lt;strong&gt;detailed logging of operations, event tracking, and greater control over&lt;/strong&gt; backend security.&lt;/p&gt;

&lt;p&gt;Not only does the plugin allow you to specify which collections to track, but you can even fine-tune the &lt;strong&gt;type of operation (create, update, delete)&lt;/strong&gt;  per hook. Simply put, you have complete control over what gets logged — without any added overhead or unnecessary complexity.&lt;/p&gt;

&lt;p&gt;I’ll give you a more complete explanation later.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why Payload Auditor?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Common Problems in Payload Projects Without a Logging System
&lt;/h4&gt;

&lt;p&gt;In many projects built with &lt;strong&gt;Payload CMS&lt;/strong&gt;, developers focus primarily on data structure, admin panel design, and API interaction — but an important part that is often overlooked is &lt;strong&gt;the logging and event monitoring system&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here are some common problems that arise in the absence of a proper logging system:&lt;/p&gt;




&lt;p&gt;🔍 &lt;strong&gt;Lack of Clear Change View&lt;/strong&gt;&lt;br&gt;
In projects with multiple content managers or developers, it is often unclear who made what changes and when. This can lead to confusion, repeated errors, or even damage to important data.&lt;/p&gt;



&lt;p&gt;🛠️ &lt;strong&gt;Difficult Debugging&lt;/strong&gt;&lt;br&gt;
In the event of a problem, the lack of detailed reporting of the operations performed causes the development team to spend a lot of time searching through data or code to understand what happened.&lt;/p&gt;



&lt;p&gt;🛡️ &lt;strong&gt;High Security Risks&lt;/strong&gt;&lt;br&gt;
When no traces of sensitive operations (such as updating user information or deleting data) remain, it becomes very difficult to identify suspicious actions or possible abuses.&lt;/p&gt;



&lt;p&gt;📉 &lt;strong&gt;Lack of internal documentation of system performance&lt;/strong&gt;&lt;br&gt;
In organizational or team projects, automated documentation of user and system behavior plays a vital role in analyzing and improving processes. Otherwise, this task is either completely forgotten or performed manually and incompletely.&lt;/p&gt;



&lt;p&gt;⏸️ &lt;strong&gt;Lack of tracking and targeted stopping of operations&lt;/strong&gt;&lt;br&gt;
Without a monitoring system, it is not possible to centrally specify whether logging should be stopped in a specific section or only certain operations (such as creation or deletion) should be logged.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Payload Auditor&lt;/strong&gt; fills these gaps — as a simple, flexible, and powerful tool for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tracking all important activities&lt;/li&gt;
&lt;li&gt;Accurately recording the history of operations&lt;/li&gt;
&lt;li&gt;Controlling access to logs&lt;/li&gt;
&lt;li&gt;and increasing the overall security of your project&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Benefits of Using the Payload Auditor Plugin
&lt;/h3&gt;

&lt;p&gt;Using the &lt;strong&gt;Payload Auditor&lt;/strong&gt; plugin allows developers to make their projects more professional, secure, and more analyzable. Here are the most important benefits of this tool:&lt;/p&gt;



&lt;p&gt;✅ &lt;strong&gt;Full Activity Tracking&lt;/strong&gt;&lt;br&gt;
This plugin allows for accurate recording of operations such as user creation, editing, deletion, and login. You can know who did what, when, and what — something that is practically impossible in systems without logging.&lt;/p&gt;



&lt;p&gt;🔐 &lt;strong&gt;More security in multi-user environments&lt;/strong&gt;&lt;br&gt;
In projects where multiple users with different access levels are working, tracking and limiting access to logs plays an important role in preventing abuse or unwanted changes. This plugin allows you to control access to reports and closely monitor activities.&lt;/p&gt;



&lt;p&gt;🏢 &lt;strong&gt;Suitable for SaaS and Enterprise Projects&lt;/strong&gt;&lt;br&gt;
In SaaS and Enterprise-level projects, detailed reports, change history, and analytical tools are a must. By providing these features, Payload Auditor helps you build a professional, reliable, and industry-standard product.&lt;/p&gt;



&lt;p&gt;⚙️ &lt;strong&gt;High customization for specific needs&lt;/strong&gt;&lt;br&gt;
Through flexible settings, this plugin allows you to track only the collections that are important to you, select the type of operations, and even disable its functionality in certain situations.&lt;/p&gt;



&lt;p&gt;📊 &lt;strong&gt;Analysis of behavioral and operational data&lt;/strong&gt;&lt;br&gt;
By recording structured events, you can perform valuable analyses on user behavior, system problems, or usage patterns in the future. This information can be useful in optimizing the user experience or making management decisions.&lt;/p&gt;
&lt;h3&gt;
  
  
  Install and set up the Payload Auditor plugin
&lt;/h3&gt;

&lt;p&gt;Setting up the &lt;code&gt;payload-auditor&lt;/code&gt; plugin is very simple and quick, and it can be added to the Payload CMS project in a few short steps. Here are the basic installation and configuration steps:&lt;/p&gt;


&lt;h4&gt;
  
  
  🧱 Installing with npm / yarn / pnpm
&lt;/h4&gt;

&lt;p&gt;First, add the plugin to your project using your preferred package manager (although we recommend using pnpm):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;payload-auditor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you are using &lt;code&gt;yarn&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add payload-auditor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with &lt;code&gt;pnpm&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add payload-auditor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  ⚙️ Adding the plugin to the Payload configuration
&lt;/h4&gt;

&lt;p&gt;After installation, simply import and enable the plugin in the Payload configuration file (usually &lt;code&gt;payload.config.ts&lt;/code&gt; or &lt;code&gt;payload.config.js&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;buildConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;payload/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;auditorPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;payload-auditor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;buildConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// ... your collections here&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;auditorPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="c1"&gt;// plugin settings go here&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  🛠️ Basic configuration (simple example)
&lt;/h4&gt;

&lt;p&gt;In this simple example, we will configure only one collection called &lt;code&gt;media&lt;/code&gt; for logging. Payload-Auditor uses payload cms hooks for logging operations. In this configuration, only &lt;code&gt;update&lt;/code&gt; operations will be logged using the afterChange hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;auditorPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;trackCollections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;media&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;afterChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these simple settings, the plugin starts logging changes to the &lt;code&gt;media&lt;/code&gt; collection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Payload Auditor Plugin Configuration Options
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;payload-auditor&lt;/code&gt; plugin is designed for high flexibility, allowing you to specify exactly &lt;strong&gt;which collections are logged, under what conditions, and with what operations&lt;/strong&gt;. Here are the most important configuration options:&lt;/p&gt;

&lt;h4&gt;
  
  
  🕒 &lt;code&gt;automation&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;This option manages automated operations in the logging system. For example, you can specify how many old logs you want to delete. You can even specify which logs are considered old:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;      &lt;span class="nx"&gt;automation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;logCleanup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;manual&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;olderThan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2m&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, logs that are more than two minutes old are considered old and 66 of them are deleted each time. Please note that this is just an example.&lt;/p&gt;

&lt;h4&gt;
  
  
  📁 &lt;code&gt;trackCollections&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;In this option, you introduce a list of collections whose activities you want to track. For each collection you can have its own settings. The settings in this section are very flexible, meaning you can enable all Payload hooks for each collection and even specify which operations you want to enable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;trackCollections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;afterChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  🎯 Filtering operations inside hooks
&lt;/h4&gt;

&lt;p&gt;The plugin allows you to log &lt;strong&gt;only some specific operations&lt;/strong&gt; (for example, only &lt;code&gt;update&lt;/code&gt; or &lt;code&gt;delete&lt;/code&gt;).&lt;br&gt;
This way, the logs become more targeted and lightweight.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;afterOperation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  📦 Complete example of an advanced configuration
&lt;/h3&gt;

&lt;p&gt;In the following example, two collections (&lt;code&gt;users&lt;/code&gt; and &lt;code&gt;posts&lt;/code&gt;) are tracked. In the &lt;code&gt;users&lt;/code&gt; collection, only the &lt;code&gt;update&lt;/code&gt; operation is logged in the &lt;code&gt;afterChange&lt;/code&gt; hook. In the &lt;code&gt;posts&lt;/code&gt; collection, only the &lt;code&gt;delete&lt;/code&gt; is logged in the &lt;code&gt;afterOperation&lt;/code&gt; hook. Also, the logs are deleted after 30 days:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;auditorPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;automation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;logCleanup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;manual&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;olderThan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;7d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;trackCollections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;afterChange&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;afterOperation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  How the Payload Auditor Plugin Works
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;payload-auditor&lt;/code&gt; plugin uses the very powerful &lt;strong&gt;hooks feature of Payload CMS&lt;/strong&gt; to log and track important operations at the collection level. This approach makes logging non-destructive, modular, and controllable.&lt;/p&gt;




&lt;h4&gt;
  
  
  🔄 Using hooks for logging
&lt;/h4&gt;

&lt;p&gt;By default, Payload CMS provides a set of &lt;strong&gt;hooks for each collection&lt;/strong&gt;, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;beforeChange&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;afterChange&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;beforeOperation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;afterOperation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;and all payload cms hooks...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By connecting to these hooks, the &lt;code&gt;payload-auditor&lt;/code&gt; plugin intercepts and logs all operations that occur in your project — but only if you have enabled it.&lt;/p&gt;

&lt;p&gt;📌 Unlike some other tools, this plugin &lt;strong&gt;only logs when you tell it to&lt;/strong&gt;, so there is no additional overhead to your project.&lt;/p&gt;




&lt;h4&gt;
  
  
  ⚙️ Differences between operations (create, update, delete)
&lt;/h4&gt;

&lt;p&gt;For each hook you can specify exactly which type of operation should be logged. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;beforeValidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;update&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;update&lt;/code&gt; operation is logged in the &lt;code&gt;afterChange&lt;/code&gt; hook.&lt;/li&gt;
&lt;li&gt;But the &lt;code&gt;create&lt;/code&gt; operation is ignored. Of course, it is also ignored if you do not fully define this operation. This feature is mostly for when you want to ignore this operation for now and enable it later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This level of &lt;strong&gt;fine-grained control&lt;/strong&gt; allows you to tailor the logging system to exactly the needs of your project.&lt;/p&gt;




&lt;h4&gt;
  
  
  ⏸️ Ability to temporarily stop logging for a specific collection
&lt;/h4&gt;

&lt;p&gt;You may want to temporarily stop logging on a collection — for example, to fix a bug or during development. The plugin provides this feature as well. Just set the &lt;code&gt;enabled&lt;/code&gt; property value to &lt;code&gt;false&lt;/code&gt; or remove the collection from the &lt;code&gt;trackCollections&lt;/code&gt; list.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;comments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// This collection is temporarily untracked.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or remove it altogether so that no hooks are attached to it.&lt;/p&gt;

&lt;p&gt;This design is &lt;strong&gt;both simple and extensible&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Usage Scenarios
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;payload-auditor&lt;/code&gt; plugin is not just a logging tool; it is a tool for &lt;strong&gt;analysis, security, and better management of real projects&lt;/strong&gt;. Here are some of the most common scenarios where this plugin will be very useful:&lt;/p&gt;

&lt;h4&gt;
  
  
  🔐 Logging user logins and profile changes
&lt;/h4&gt;

&lt;p&gt;In projects where users can log into the admin panel, accurate tracking of when and how they log in or changes to their profile is very important from a security and support perspective.&lt;/p&gt;

&lt;p&gt;By enabling logging on the &lt;code&gt;users&lt;/code&gt; collection (assuming that site users are stored in a collection with the slug users), you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identify who logged in and when.&lt;/li&gt;
&lt;li&gt;Document changes to email, name, password, or user role.&lt;/li&gt;
&lt;li&gt;Track support reports faster.&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  🔍 Security Issues Investigation and User Behavior Analysis
&lt;/h4&gt;

&lt;p&gt;In many cases, suspicious behavior or security issues can be identified simply by looking at the logs. This plugin allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track unusual deletion or editing operations.&lt;/li&gt;
&lt;li&gt;Analyze specific user or admin behaviors and identify dangerous patterns.&lt;/li&gt;
&lt;li&gt;Generate a detailed report for security or compliance audits (in development).&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  👥 Use in multi-user projects with different access levels
&lt;/h4&gt;

&lt;p&gt;In projects where several people with different roles work on a CMS, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Content Editors&lt;/li&gt;
&lt;li&gt;Support Agents&lt;/li&gt;
&lt;li&gt;Admins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Managing changes and answering the question "Who did what?" becomes extremely difficult.&lt;br&gt;
The &lt;code&gt;payload-auditor&lt;/code&gt; plugin is essential in such environments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accurately logging operations for each role&lt;/li&gt;
&lt;li&gt;Preventing unwanted or erroneous changes&lt;/li&gt;
&lt;li&gt;Helping to build team discipline and trust in large teams&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Best practices for using Payload Auditor
&lt;/h3&gt;

&lt;p&gt;To use the &lt;code&gt;payload-auditor&lt;/code&gt; plugin effectively and securely, it is recommended to follow some tips and recommendations. Here are some important ones:&lt;/p&gt;


&lt;h4&gt;
  
  
  ✅ 1. Optimal and targeted configuration
&lt;/h4&gt;

&lt;p&gt;Not all collections need logging. Only select those that contain sensitive data or important operations (such as &lt;code&gt;users&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt;, &lt;code&gt;payments&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommendation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only enable hooks and operations that really need to be tracked.&lt;/li&gt;
&lt;li&gt;This will reduce the size of the logs and improve system performance.&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;
  
  
  🧹 2. Intelligent long-term log retention
&lt;/h4&gt;

&lt;p&gt;If not managed properly, logs can cause database size to increase and performance to decrease over time. Use the &lt;code&gt;automation&lt;/code&gt; option to control the lifetime of logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt; &lt;span class="nx"&gt;automation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//  ...&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;In sensitive projects&lt;/strong&gt;:&lt;br&gt;
If you need long-term retention, move logs to archive systems or centralized logging tools (like ELK Stack or Logstash). For this, you can use customLogger which is provided at 4 levels: global, hook level, specific hook level and operation level.&lt;/p&gt;


&lt;h4&gt;
  
  
  🔒 3. Restrict access to logs
&lt;/h4&gt;

&lt;p&gt;Not all users should have access to logs. For added security:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only root admins or users with specific roles (e.g. &lt;code&gt;Auditor&lt;/code&gt;) should be able to view or analyze logs.&lt;/li&gt;
&lt;li&gt;Restrict access to log collections using &lt;strong&gt;Access Control in Payload&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Simple example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Accessibility&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
          &lt;span class="c1"&gt;// Your configuration&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  🧪 4. Testing and Monitoring in the Development Environment
&lt;/h4&gt;

&lt;p&gt;Before using in the production environment, test the plugin’s performance thoroughly in the development or staging environment. Check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are logs recorded accurately?&lt;/li&gt;
&lt;li&gt;Are unnecessary operations not logged?&lt;/li&gt;
&lt;li&gt;Is system performance not degraded?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Following these practices will make the Payload Auditor plugin one of the pillars of your project’s security and professional maintenance, rather than an additional tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;Payload Auditor&lt;/strong&gt; plugin is a powerful and flexible tool that allows you to accurately and securely track user activities and important changes in your Payload CMS projects. With this plugin, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increase project security in multi-user environments,&lt;/li&gt;
&lt;li&gt;Quickly identify problems and suspicious behavior,&lt;/li&gt;
&lt;li&gt;Generate detailed and analytical reports for better project management,&lt;/li&gt;
&lt;li&gt;And experience all these features with high customization capabilities and precise log management.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are also looking to improve security and transparency in your Payload CMS projects, we recommend that you definitely try this plugin.&lt;/p&gt;




&lt;h3&gt;
  
  
  Contribute to development
&lt;/h3&gt;

&lt;p&gt;This project is open source and interested developers can help improve and expand it by providing feedback, suggestions, or contributing to its development. To view the source code, complete documentation, and start contributing, visit its official GitHub repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/shaadcode/payload-auditor" rel="noopener noreferrer"&gt;Payload Auditor on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this tool, take an important step towards increasing the security, control, and monitoring of your Payload CMS projects and experience more sustainable development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources and Links
&lt;/h3&gt;

&lt;p&gt;To learn more and better use the Payload Auditor plugin, as well as learn related concepts, you can refer to the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/shaadcode/payload-auditor" rel="noopener noreferrer"&gt;Official Payload Auditor Repository on GitHub&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://payloadcms.com/docs/" rel="noopener noreferrer"&gt;Official Payload CMS Documentation&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you’re looking to increase security, transparency, and analytics in your Payload CMS projects, try the Payload Auditor plugin today.&lt;br&gt;
We’re eager to hear your feedback, suggestions, and contributions to the development of this tool.&lt;br&gt;
Check out the project on GitHub, give it a ⭐ star, and join us in building a stronger and more secure Payload ecosystem!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>react</category>
      <category>security</category>
    </item>
  </channel>
</rss>
