> For the complete documentation index, see [llms.txt](https://docs.membercounter.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.membercounter.app/contributing/how-to-contribute.md).

# How to contribute

Report bugs, send pull requests, translate the bot, donate, help with these docs, and set up a local development environment.

Most of the ways to help Member Counter need no code.

## GitHub

The bot, the dashboard and everything around them live in one repository: [member-counter/bot](https://github.com/member-counter/bot). For an idea, a suggestion or a bug, [open an issue](https://github.com/member-counter/bot/issues) and answer the questions in the template. Say which counter, which channel type and which bot you were using. Useful reports, ideas and merged pull requests can earn a [badge](/contributing/badges.md).

Pull requests go to the `dev` branch, not to `master`. [Development environment](#development-environment) below sets you up.

## Tolgee

The bot and the dashboard are translated by the community on [Tolgee](https://tolgee.membercounter.app/), no development environment needed. To sign up with Discord, press **Sign Up with OAuth2** on the [sign up page](https://tolgee.membercounter.app/sign_up). Translators get the Translator badge, see [Badges](/contributing/badges.md).

## Donations

There is no donate button. Ask in the [support server](https://membercounter.app/support) and staff will arrange the donation. The [donors page](https://membercounter.app/donors) lists the donations so far.

After the donation, staff add the Donor badge to your profile and put your name on the donors page, unless you ask to stay anonymous.

{% hint style="info" %}
Both are done by hand, so they do not appear the moment you pay.
{% endhint %}

## Contributing to the docs

These docs are their own repository, [member-counter/docs](https://github.com/member-counter/docs), published with GitBook. Typos, missing steps and outdated screenshots are all fair game for a pull request. Read `tools/docs-style.md` first. It sets how each kind of page is built. For an outdated screenshot, open an issue or say which image and what changed: the images are generated by a tool that needs the maintainer's test server, so staff regenerate them.

## Development environment

This section gets the bot and the dashboard running on your machine. To run the bot for your own server, you want [self-hosting](/self-hosting/self-hosting.md) instead, which uses prebuilt images and needs none of this. You need [Git](https://git-scm.com/downloads), [Node.js 22](https://nodejs.org/en/download/) and [Docker](https://www.docker.com/get-started). pnpm is pinned in the repository, so `corepack enable` picks up the right version.

```bash
git clone -b dev git@github.com:member-counter/bot.git member-counter-bot
cd member-counter-bot
corepack enable
pnpm install
```

You also need your own Discord application. Never develop against the token of a bot that is in real servers. [Creating a Discord bot account](/custom-bot/creating-a-discord-bot-account.md) walks through the Developer Portal.

Copy `.env.example` to `.env` and set:

| Variable                                                                   | Value                                                                                          |
| -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `COOKIE_SECRET`                                                            | Anything with at least 32 characters. The example value is one character short, so replace it. |
| `DISCORD_CLIENT_ID`, `DISCORD_CLIENT_SECRET`, `DISCORD_BOT_INSTANCE_TOKEN` | The credentials of your development application.                                               |
| `DATABASE_URL`                                                             | `mongodb://localhost:27017/memberCounter?replicaSet=rs0&directConnection=true`                 |
| `REDIS_URL`                                                                | `redis://localhost:6379`                                                                       |
| `NODE_ENV`                                                                 | `development`                                                                                  |

Also register `http://localhost:3000/api/auth/callback`, the default `DISCORD_OAUTH2_REDIRECT_URI`, as an **OAuth2 redirect URL** in the Developer Portal.

`.env` is not hot-reloaded. After you change it, stop the app and start it again.

Then start everything and open `http://localhost:3000`:

```bash
pnpm dev:docker:up   # MongoDB, Redis and the helper containers
pnpm db:migrate up   # first time only: create the collections and indexes
pnpm db:push
pnpm dev             # bot, backend and frontend, in watch mode
# pnpm dev:docker:down stops the containers when you are done
```

### Open a pull request

Run the checks before you push:

```bash
pnpm format:fix && pnpm lint && pnpm typecheck
```

Then [create a pull request](https://github.com/member-counter/bot/pulls) against the `dev` branch.

<details>

<summary>Technical details</summary>

* `dev` is the working branch and builds the `:beta` images that self-hosters can opt into. `master` is the released one and builds the `:latest` images.
* `.nvmrc` pins Node `22.22`, and the repository requires at least `22.22.0`. `packageManager` pins `pnpm@9.15.5`, and `.npmrc` sets `node-linker=hoisted`.
* The development MongoDB runs as a single-node replica set named `rs0`, initiated once by the `setup-mongo-rs` container, which is why `DATABASE_URL` carries `replicaSet=rs0&directConnection=true`. Its data lives in `./storage/db`.
* The database and Redis URLs differ from the self-hosting ones on purpose: in development the services are reached from your machine on `localhost`, not from inside the Docker network.
* Other local addresses: `http://localhost:5173` the frontend dev server, `http://localhost:8080` the backend, `http://localhost:3001` mongo-express, `http://localhost:3002` RedisInsight, with the local Redis already registered in it.
* Port 3000 is an nginx container that proxies `/` to the frontend and `/api` to the backend, stripping the `/api` prefix. It answers with a gateway error whenever `pnpm dev` is not running. Use it for normal work anyway: Discord OAuth2 only comes back to the redirect URL you registered, and that is the port 3000 one.
* nginx reaches the dev servers through `host.docker.internal`. Docker Desktop resolves that name on its own, but a plain Docker on Linux does not: add `extra_hosts: ["host.docker.internal:host-gateway"]` to the `website` service in `docker-compose.dev.yml`, or port 3000 will never connect.
* `pnpm install` also runs `sherif` over the workspace through the `postinstall` script, which catches mismatched dependency versions between packages.
* Screenshots: one JSON spec per image in `tools/screenshots/specs/`; run `pnpm shoot <name>` from `tools/screenshots/`. It needs `env.json` with the test server ids and a logged-in browser profile (`tools/screenshots/README.md`).

</details>
