# Overview

URL: https://zerodev.ca/docs/prism/developer-documentation

> How a Prism module is laid out, how it loads and what it can hook into.



Everything Prism does at runtime comes from a module, including Core. Your own modules load the same way and get the same access to the database, API, dashboard, audit log and languages.

For installing and running Prism, see the [Setup Guide](/docs/prism/setup).

## Layout

Each folder in `modules/` is one module. Prism imports its `main.js` and loads everything under `src/` and `resources/` by folder.

```text
modules/
  example/
    main.js
    resources/
      config/
      lang/
      web/
        pages/
    src/
      clocks/
      events/
      handlers/
      models/
      routes/
```

| Folder                 | Files loaded                                        | Base class |
| ---------------------- | --------------------------------------------------- | ---------- |
| `main.js`              | The module                                          | `Modules`  |
| `src/models/`          | Every `*.js`                                        | `Models`   |
| `src/handlers/`        | Every `*.js`                                        | `Handlers` |
| `src/routes/`          | Every `route.js`, at any depth                      | `Routes`   |
| `src/clocks/`          | Every `*.js`                                        | `Clocks`   |
| `src/events/`          | Every `*.js`                                        | `Events`   |
| `resources/config/`    | Every `*.js`                                        | `Configs`  |
| `resources/lang/`      | `en/*.js` classes, plus a folder of JSON per locale | `Langs`    |
| `resources/web/pages/` | Every `page.js`, at any depth                       | `Pages`    |

Import every base class from `#prism/modules`. Each file exports one class. Code goes in `src/`, config and setup in `resources/`.

## Loading

Prism loads modules in two passes. Core always goes first, then every other module after the modules it `requires`.

1. **Register.** Install any missing `dependencies.node` packages, then read configs, languages, models, routes and pages.
2. **Load.** Create the tables, start handlers, events and clocks, call `onStartup()` and mount routes.

When Prism stops, it stops clocks, removes events and calls `onShutdown()` for each module in reverse order.

A module that throws while loading is marked as failed and shown on the **Modules** page and the Overview. The others keep running. If Core fails, Prism stops.

## main.js

```js title="modules/example/main.js"
import { Modules } from "#prism/modules";

export class Example extends Modules {
    constructor(prism) {
        super(prism, {
            name: "example",
            author: "Your Name",
            version: "1.0.0",
            description: "Does one thing well",
            icon: "box",
            requires: ["core"],
            dependencies: { node: ["nanoid"] }
        });
    }

    permissions() {
        return [{ id: "example.view", label: "View examples" }, { id: "example.edit", label: "Edit examples" }];
    }

    async onStartup() {
        this.prism.console.log(this.prism.console.levels.info, `${this.getName()} started.`);
    }
}
```

| Key                                | Default  | What it does                                                                                                                                       |
| ---------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                             | Required | The module ID. Use the lowercase folder name.                                                                                                      |
| `displayName`                      | `name`   | Fallback label. Translate the name with `module.<id>.name` instead. See [Languages](/docs/prism/developer-documentation/languages#dashboard-text). |
| `author`, `version`, `description` | None     | Shown on the **Modules** page.                                                                                                                     |
| `icon`                             | `puzzle` | A [Lucide](https://lucide.dev/icons) icon name.                                                                                                    |
| `requires`                         | `[]`     | Modules that must load first. Missing ones fail this module.                                                                                       |
| `dependencies.node`                | `[]`     | npm packages Prism installs before loading the module.                                                                                             |

## Hooks

Add any of these methods to your module class.

| Method                         | Called                                                                                                  |
| ------------------------------ | ------------------------------------------------------------------------------------------------------- |
| `onStartup()`                  | After the module loads.                                                                                 |
| `onShutdown()`                 | Before it unloads.                                                                                      |
| `permissions()`                | When Prism lists permissions. Return `[{ id, label }]`. They show up when editing roles and API tokens. |
| `fields(module, page)`         | When another module's page is described. Return extra form fields for it.                               |
| `decorate(module, page, rows)` | When another module's page lists or creates rows. Return the rows with your data added.                 |

The Kora module uses `fields` and `decorate` to add a **Kora product** picker to Core's product form:

```js
fields(module, page) {
    if (module !== "core" || page !== "products") return [];
    return [{ key: "kora_product", label: "Kora product", type: "reference", source: { module: "kora", endpoint: "/products", label: "name", value: "id" }, empty: "No products found" }];
}
```

Core also runs a customer's licenses through `decorate("core", "accountLicenses", licenses)` before `GET /api/v1/account/licenses` returns them. Each license has a `fields` array that the **My Licenses** card shows under the product. Push `{ key, label, value, copy }` entries onto it, where `label` is a translation key from your module's `common.json` and `copy` adds a copy button. Kora uses this to show the Kora license key issued for each purchase:

```js
decorate(module, page, rows) {
    if (module !== "core" || page !== "accountLicenses") return rows;
    return rows.map(row => ({ ...row, fields: [...row.fields, { key: "kora_key", label: "account.licenses.field.kora_key", value: "KORA-XXXX", copy: true }] }));
}
```

## The prism Object

Every class gets the running instance as `this.prism`.

| Property              | What it is                                                                          |
| --------------------- | ----------------------------------------------------------------------------------- |
| `this.prism.database` | The database connection. `this.prism.database.sequelize` is the Sequelize instance. |
| `this.prism.settings` | Values from the **Settings** and **Theme** pages.                                   |
| `this.prism.console`  | The logger.                                                                         |
| `this.prism.audit`    | The audit log.                                                                      |
| `this.prism.signer`   | Signs and checks payloads with the response signing key.                            |
| `this.prism.mail`     | Sends email through the SMTP settings.                                              |
| `this.prism.storage`  | Uploads to and signs links for the S3 bucket.                                       |
| `this.prism.events`   | The event bus. See [Events](/docs/prism/developer-documentation/events).            |
| `this.prism.modules`  | Every loaded module and its parts.                                                  |
| `this.prism.api`      | The API server and permission checks.                                               |

See [Utilities](/docs/prism/developer-documentation/utilities) for each one.

## Reaching Other Modules

```js
this.prism.modules.models.get("core", "products");
this.prism.modules.handlers.get("core", "licenses");
this.prism.modules.config.values("kora", "kora");
this.prism.modules.lang.phrase("core", "messages", "not_found");
```

`get` returns `null` when that module is not loaded.

## Addons

Paid extras on the Prism license, such as **Watermark**, are checked with:

```js
if (this.prism.hasAddon("Watermark")) return;
```
