Skip to content

Creating a Module

AnthonyChen05 edited this page Feb 23, 2026 · 1 revision

Creating a Module

This is the full walkthrough for building a new Prism module from scratch. By the end you'll have a working page served at /<your-name>.


1. Create the folder

Inside backend/src/modules/, create a folder with your module's name. The folder name becomes the URL.

backend/src/modules/kanban/

→ Served at http://localhost:3000/kanban

Naming rules:

  • lowercase, no spaces
  • hyphens are fine (task-board, my-crm)
  • the folder name is the URL — pick something clean

2. Create index.ts

This is the backend entry point. It must export a default AppModule.

// backend/src/modules/kanban/index.ts

import path from 'path'
import fs from 'fs'
import type { AppModule } from '../../shared/types/module'

const KanbanModule: AppModule = {
  name: 'kanban',
  version: '1.0.0',

  async register(server, services, prefix) {
    // prefix = "/kanban" — automatically derived from your folder name
    const publicDir = path.join(process.cwd(), 'src', 'modules', 'kanban', 'public')
    const assetPrefix = `${prefix}-assets`

    // Serve your HTML page at /kanban
    server.get(prefix, { config: { public: true } } as never, async (_req, reply) => {
      const html = fs.readFileSync(path.join(publicDir, 'index.html'), 'utf-8')
        .replaceAll('{{ASSETS}}', assetPrefix)
      reply.type('text/html').send(html)
    })

    // Add your API routes under /kanban/api/...
    server.get(`${prefix}/api/boards`, { config: { public: true } } as never, async () => {
      return { boards: [] } // replace with real db queries
    })
  }
}

export default KanbanModule

3. Create public/index.html

Your UI. Use {{ASSETS}} wherever you reference a CSS or JS file — it gets replaced with the correct path at serve time.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Kanban</title>
  <link rel="stylesheet" href="{{ASSETS}}/style.css" />
</head>
<body>
  <h1>My Kanban Board</h1>
  <div id="app"></div>
  <script src="{{ASSETS}}/app.js"></script>
</body>
</html>

4. Create public/app.js

Your frontend logic. Use window.location.pathname as the API base so your fetch calls route correctly regardless of what the module is named.

// The current page path — e.g. "/kanban"
// Prepend this to all API calls so they hit your module's routes
const API = window.location.pathname.replace(/\/$/, '')

async function loadBoards() {
  const res = await fetch(API + '/api/boards')
  const data = await res.json()
  console.log(data.boards)
}

document.addEventListener('DOMContentLoaded', loadBoards)

5. Add public/style.css

Plain CSS. Reference it from your HTML via {{ASSETS}}/style.css.

body {
  font-family: system-ui, sans-serif;
  margin: 0;
  padding: 24px;
}

6. Restart the server

npm run dev

Open http://localhost:3000/kanban. Your page is live.

The plugin loader scans src/modules/ on every startup and registers everything it finds. No config changes, no manual wiring.


Full file structure

backend/src/modules/kanban/
├── index.ts
└── public/
    ├── index.html
    ├── app.js
    └── style.css

Next steps

Clone this wiki locally