> ## Documentation Index
> Fetch the complete documentation index at: https://www.chapterjs.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Organising a growing project

> Share code between files, keep what the bot learns, set a cooldown, keep files short, and know what the framework does not do yet

With a dozen commands, a few events and some components, a project needs a little order. This page is about the habits that keep it readable, and about the two questions every bot meets on its first week: "where do I put the code two files share?" and "where do I store things?".

## Shared code

Any folder of `src/` that the framework does not read is yours. The usual one is `src/lib/`. Put a function there, import it from a relative path, without extension:

```ts src/lib/warnings.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
const warnings = new Map<string, number>();

export function addWarning(userId: string): number {
  const count = (warnings.get(userId) ?? 0) + 1;
  warnings.set(userId, count);
  return count;
}

export function warningsOf(userId: string): number {
  return warnings.get(userId) ?? 0;
}
```

```ts src/commands/warnings.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { command } from 'chapterjs';
import { warningsOf } from '../lib/warnings';

export default command({
  name: 'warnings',
  description: 'Counts the warnings of someone',
  options: {
    who: { type: 'user', description: 'Who', required: true },
  },
  async run({ interaction, options }) {
    const count = warningsOf(options.who.id);
    await interaction.reply(
      `${options.who.displayName} has ${count} warning(s).`
    );
  },
});
```

The files you import are watched like the others: saving `src/lib/warnings.ts` reloads every file that uses it.

A file that declares nothing is plain code: shared code can also sit next to the files that use it, `src/moderation/checks.ts` beside `src/moderation/ban.ts`. Pick one habit and keep it; `src/lib/` is the simplest.

## Keeping files short

A command file should read like a summary: check, do, answer. When `run` grows past a screen, move the work to a function in `src/lib/` and keep the file as the glue between Discord and that function. Two reasons:

* A function in `src/lib/` can be tested or reused without Discord; a `run` can't.
* The next person to read the file (you, in three months) sees what the command does without reading how.

## Storing data

The `Map` of `warnings.ts` above is fine for shared code, and wrong for data: it starts empty every time the bot starts, `chapterjs dev` reloads it on every save, and in production each process has its own. What must be remembered goes in a [store](https://www.chapterjs.org/tutorial/storage.md), the previous chapter: `export const warnings = store<number>()`, kept in `data/`, per server, and shared by every process.

A store is for what fits in memory. A bot with millions of rows uses a database made for Node (SQLite through a package, or a server like PostgreSQL), kept in `src/lib/` behind a few functions (`getSettings(guildId)`, `saveSettings(...)`), so that the commands and events never know how it is stored.

## A cooldown

"Not more than once a day per person" is a common need, and a command declares it with `cooldown`:

```ts src/commands/daily.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { command } from 'chapterjs';

export default command({
  name: 'daily',
  description: 'Claims your daily reward',
  ephemeral: true,
  cooldown: '1d',
  async run({ interaction }) {
    await interaction.reply('Here is your reward! 🎁');
  },
});
```

Someone who uses `/daily` again too soon gets a private answer saying when they can ("You can use this command again 8 October 2026 17:12."; a short cooldown reads "in 5 seconds", counting down, and the answer goes away when the time comes), and `run` does not run. `cooldown: { user: '10m', channel: '1m', guild: '1h' }` makes a channel or a whole server wait too. Like the `Map` above, the last uses are kept in memory: they start empty when the bot starts. The details are in the [Guide](https://www.chapterjs.org/commands.md#cooldowns).

## Grouping files

Where a file is and what it is called mean nothing to the framework: a command is a command because of `command()`, wherever the file sits. So sort your files the way you think: a folder per kind (`src/commands/`, `src/events/`), or a folder per feature (`src/moderation/`, with its commands, its buttons and its events together, in one file or several), as the `moderation` template does. The [tour](https://www.chapterjs.org/tutorial/tour.md#your-files-your-order) shows both.

For commands, prefer **commands** (`/ban`, `/kick`) over **subcommands** (`/mod ban`, `/mod kick`), unless they are variants of one action (`/timeout add`, `/timeout remove`). Discord hides a whole command from people who lack its permissions, never one subcommand: with `/mod ban` and `/mod kick`, someone who may only kick still sees `/mod ban`.

## What the framework does not do yet

ChapterJS is young, and some things a bot may want are not there. Knowing them saves a search:

| Not there yet | Meanwhile |
| - | - |
| Context menu commands (right-click on a user or a message) | A slash command with a `user` option |
| Waiting for the next message or click of a person | A button or a menu that carries what it needs in `data` |
| Recording what people say in a voice channel | The bot joins and plays, and is deafened by default |
| Running on several machines | Several processes on one machine, by itself |

The full list, kept up to date, is [Roadmap](https://www.chapterjs.org/roadmap.md).

## Recap

* Shared code goes in `src/lib/` (or next to the files that use it), imported without extension, and reloaded with the files that use it.
* A `Map` is for shared code, not for data: what must be remembered goes in a store, and millions of rows in a database behind a few functions.
* A cooldown is one setting of the command, `cooldown: '1d'`, kept in memory; a growing project sorts its files by feature, since the framework reads what they export, not where they are.

> [card] [Memory and limits](https://www.chapterjs.org/tutorial/memory-and-limits.md)
>
> What the bot remembers, and the limits of Discord it handles for you.

> [card] [Guide: Roadmap](https://www.chapterjs.org/roadmap.md)
>
> Everything the framework does not do, and what to do meanwhile.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.