Files
modrinth/packages/moderation
e2085c43c5 Feat: Many moderation checklist changes (#6730)
* Rule 1.x, 3.2 and 3.3x support

* reorganize

* Kinda Jank dynamic list stuff that should probably be implemented better but its 1:30 am

* Checklist Stage Title

* Make Stage Title Good

* Rule 1.x, 3.2 and 3.3x support

* reorganize

* Kinda Jank dynamic list stuff that should probably be implemented better but its 1:30 am

* Checklist Stage Title

* Make Stage Title Good

* oops i forgot 3.1

* Insufficient description improvement test

* "i forgor" checklist tooltips tooltips (kinda jank but they work)
update to latest

* only use indexedDb for moderation storage, localStorage forces a bunch of cringe

* store moderation stuff separately + compact checklist stuff

* give stages actual titles + rename what was previously called titles to hints

* Title & Slug, Summary Description, Links, License, Gallery, Versions and Reupload migrated to new system™️

* put stageoptions before nodes

* do state and variablse in tooltips

* checklist fully migrated to new system, not much new has been added (yet)

* forgot to only do modpack permissions for modpacks

* Idk why I wasn't just mutating the builder

* actual node type hierarchy + action abstraction + improve message/text handling

* dropdown + "functional" quick fixes

* dropdown + "functional" quick fixes

* Allow moderators to suggest correct environment.

* remove vestigial function

* Prioritization™️

* quickest fixes in the west

* start of metadata stage + optimize checklist parsing + a couple of qol features

* futureproof™️ environment metadata + just give me project context everywhere

* tidy up after today's refactoring

* tidy up after tidying up after today's refactoring

* move loaders to metadata (from versions)

* better required display + vueify + reorganize messages + tag quick fixes + todo

* fix log spam + concat md

* more bugs

* nested state access

* update description stage, add showcase clarity

* Fix links stage mostly, and tweak metadata stage.

* fix links lag + actions on stages

* setup links bonus buttons

* Change stage order

* Update rules stage

* Move conditional stages to the top where they belong.

* fix some metadata stuff

* fix stage selector

* don't show non-english buttons on servers without english support.

* prepr

* stop linter from trying to break my markdown

* fix: some issues

* fix: lint

* not sure why but link's links weren't links

* fix quick fixes (again) (idk how they keep breaking)

* make messages only actually count as messages if they actually have content

* rename horror button to spoilers button

* Update links name to match the links settings

* re-review stage

* unbreak stage selector

* passing off version stage fixing.

* actually fix the stage selector this time

* fix showcase clarity msg

* redirect when checklist updates slug
fix initial stage not being first if first stage is only shown under certain conditions
move to a consistent naming scheme

* redirect when checklist updates slug
fix initial stage not being first if first stage is only shown under certain conditions
move to a consistent naming scheme

* ok maybe lets use kebab

* move custom description advice stage to first button.

* temp priority on corrections applied

* make metadata page go to non setting versions page

* links stage bonus buttons, src required flag, show link value in msgs, fix msg groupings.

* update re-review button

* reupload stage navigates to project Description.

* fix: link stage using page context too late

* chore: run prepr

* fix(ci): tell typo check to ignore moderation utils

* fix: pr comment if storybook fails

* make complex nodes less complex (for the most part)
fix re-review stage shown condition
new fancy message collection system
all buttons that contribute to messages now have relevant tooltips
don't store default values in checklist db

* make complex nodes less complex (for the most part)
fix re-review stage shown condition
new fancy message collection system
all buttons that contribute to messages now have relevant tooltips
don't store default values in checklist db

* maybe fixed markdown escaping?

* tweak re-review wording.

* Update license stage handling and info

* add mixed option back for env info

* fix: formatEnvironments
fix: formatEnvironments

* update metadata environment group shown

* fix: status alert priority

* fix: display suggested slug in slug/misused message

* actually navigate when we change project slug

* ok like redirect but like don't lose state when slug changes :smart:

* make checklist reset button reset only current stage if there's modifications to it instead of full checklist

* fix versions stage messages not working

* fix donation links not being in a column

* I think slug stuff is working?
also like actually 100% garunteed markdown escaping works now

* prepr

* pseudo stages no longer interact with non-pseudo stages at all
also query projects better I think?
fix repetitive message spam in links stage

* apply quick fixes before refreshing page

* differentiate reset and return to start

* remove random empty lines in some situations

* better inaccurate slug message

* slug correction input reset button resets to current slug again instead of auto

* better keybind navigation

* incorrect environment message tweak

* use environment name(s) in checklist info

* prepr

---------

Signed-off-by: Prospector <6166773+Prospector@users.noreply.github.com>
Co-authored-by: chyzman <chyzalt@gmail.com>
Co-authored-by: Calum H. (IMB11) <contact@cal.engineer>
Co-authored-by: Gravy Boat <gravy@thatgravyboat.tech>
Co-authored-by: Michael H. <michael@iptables.sh>
Co-authored-by: chyz <32403637+chyzman@users.noreply.github.com>
Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com>
2026-07-20 20:52:46 +00:00
..
2025-07-11 16:09:04 +00:00
2026-05-29 15:55:39 +00:00
2026-05-19 18:11:48 +00:00

@modrinth/moderation

This package contains both the moderation checklist system used by moderators for reviewing projects on Modrinth, and the publishing checklist (nag system) that provides automated feedback to project authors during the submission process.

Structure

The package is organized as follows:

/packages/moderation/
├── data/
│   ├── checklist.ts        # Main moderation checklist definition - imports and exports all stages
│   ├── messages/           # Markdown files containing message templates for moderation
│   │   ├── title/          # Messages for the title stage
│   │   ├── description/    # Messages for the description stage
│   │   └── ...             # One directory per stage
│   ├── stages/             # Moderation stage definition files
│   │   ├── title.ts        # Title stage definition
│   │   ├── description.ts  # Description stage definition
│   │   └── ...             # One file per stage
│   └── nags/               # Publishing checklist (nag system) files
│       ├── core.ts         # Core nags (required fields, basic validation)
│       └── ...
└── types/                  # Type definitions
    ├── actions.ts          # Action-related types (moderation)
    ├── messages.ts         # Message-related types (moderation)
    ├── stage.ts            # Stage-related types (moderation)
    └── nags.ts             # Nag-related types (publishing checklist)

Moderation Checklist System

The moderation checklist provides a structured and transparent way to define moderation stages, actions, and messages that are displayed to moderators during the review process.

Stages

A stage represents a discrete step in the moderation process, like checking a project's title, description, or links. Each stage has:

  • A title displayed to moderators
  • A link to guidance documentation
  • An optional navigation path to direct moderators to the relevant part of the project page
  • A list of actions that moderators can take

Stages are defined in individual files in the data/stages directory and are assembled into the complete checklist in data/checklist.ts.

Actions

Actions represent decisions moderators can make for each stage. They can be buttons, dropdowns, toggles, etc. Actions can have:

  • Labels displayed to the moderator
  • Messages that are included in the final moderation decision
  • Suggested moderation status and severity
  • Optional text inputs for additional information
  • Conditional behavior based on other selected actions

Each action requires a unique id field that is used for conditional logic and action relationships. The suggestedStatus and severity fields help determine the overall moderation outcome.

Messages

Messages are the actual text that will be included in communications to project authors. To promote maintainability and reuse, messages are stored as Markdown files in the data/messages directory, organized by stage.

Variable replacement

You can use variables in your messages that will be replaced with user input:

  1. Define a variable in the relevantExtraInput array of an action:
relevantExtraInput: [
  {
    label: 'Explanation for the user',
    variable: 'MESSAGE',
    required: true,
  },
],
  1. Use the variable in your message with %VARIABLE% syntax:
# Your Message Title

Here is some explanation about the issue.

%MESSAGE%

More text after the variable.

The %MESSAGE% placeholder will be replaced with the text entered by the moderator.

Conditional logic

The moderation system supports conditional behavior that changes based on the selection of other actions.

Conditional messages

You can define different messages for an action based on other selected actions:

{
  id: 'my_action',
  type: 'button',
  label: 'My Action',
  weight: 100,
  message: async () => (await import('../messages/default-message.md?raw')).default,
  conditionalMessages: [
    {
      conditions: {
        requiredActions: ['other_action_id'],
        excludedActions: ['another_action_id']
      },
      message: async () => (await import('../messages/conditional-message.md?raw')).default,
    }
  ]
}

Enabling and disabling actions

Actions can enable or disable other actions when selected:

{
  id: 'parent_action',
  type: 'button',
  label: 'Parent Action',
  // This will show these actions when parent_action is selected
  enablesActions: [
    {
      id: 'child_action',
      type: 'button',
      label: 'Child Action',
      // ...other properties
    }
  ],
  // This will hide actions with these IDs when parent_action is selected
  disablesActions: ['incompatible_action_id']
}

Conditional text inputs

Text inputs can be conditionally shown based on selected actions:

relevantExtraInput: [
	{
		label: 'Additional Information',
		variable: 'INFO',
		showWhen: {
			requiredActions: ['specific_action_id'],
			excludedActions: ['incompatible_action_id'],
		},
	},
]

Publishing Checklist (Nag System)

The nag system provides automated feedback to project authors during the submission process, helping them improve their projects before they reach moderation. It analyzes project data and provides suggestions, warnings, and requirements.

Nags

A nag represents a specific issue or suggestion for improvement. Each nag has:

  • A unique id for identification
  • A title and description displayed to the user
  • A status indicating severity: 'required', 'warning', or 'suggestion'
  • A shouldShow function that determines when the nag should be displayed
  • An optional link to help users address the issue

Internationalization

Use vintl's defineMessage syntax.

If you want to use context in the messages, you can do so like this:

description: (context: NagContext) => {
  const { formatMessage } = useVIntl()

  return formatMessage(defineMessage(...), {
    length: context.project.body?.length || 0,
    minChars: MIN_DESCRIPTION_CHARS,
  })
}

Nag Context

The NagContext type provides access to:

  • project: Current project data
  • versions: Project versions
  • tags: Frontend "tags" (generated state)
  • currentRoute: Current page route
  • and other data...

Adding New Nags

To add a new nag:

  1. Add the nag definition to the appropriate category file (or make a new category file and add it to data/nags.ts)
  2. Add corresponding i18n messages to the .i18n.ts file
  3. Implement the shouldShow logic based on project state
  4. Add appropriate links to help users resolve the issue
  5. Run pnpm run fix to fix lint issues & generate the root locale index.json file.

Example:

// In description.ts
{
  id: 'new-nag',
  title: messages.newNagTitle,
  description: messages.newNagDescription,
  status: 'warning',
  shouldShow: (context: NagContext) => {
    // Your validation logic here
    return someCondition
  },
  link: {
    path: 'settings/description',
    title: messages.editDescriptionTitle,
    shouldShow: (context: NagContext) => context.currentRoute !== 'type-project-settings-description',
  },
}
// In description.i18n.ts
newNagTitle: {
  id: 'nags.new-nag.title',
  defaultMessage: 'New Nag Title',
},
newNagDescription: {
  id: 'nags.new-nag.description',
  defaultMessage: 'Description of the new nag issue.',