SEAM uses a layered extension pattern: every new module you build goes through the same five steps — repository, service, page, router registration, and (optionally) real-time operation listeners. Following the pattern keeps each concern isolated and makes new pages as maintainable as the existing ones. The templates below are derived directly from theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/TheSerchCp/SEAM/llms.txt
Use this file to discover all available pages before exploring further.
users module, which is the canonical reference implementation.
Create the repository file
The repository is the only place that talks to the backend. Create Each export is a one-liner that returns the Promise from
js/repositories/mimodulo.repository.js and call ApiClient directly for each HTTP operation your module needs:js/repositories/mimodulo.repository.js
ApiClient. No error handling, no transformation — that belongs in the service layer.Create the service file
The service layer imports from the repository and exposes intention-revealing function names to the rest of the app. Create If you need to transform data before returning it to the page (mapping field names, computing derived values, filtering), do it here — never in the repository or the page.
js/services/mimodulo.service.js:js/services/mimodulo.service.js
Create the page file
The page file is an async function that returns an HTML string. It wraps its content in
PrivateLayout, subscribes to EventBus events, and registers a cleanup function so listeners are removed when the user navigates away.Create js/pages/mimodulo/mimodulo.page.js:js/pages/mimodulo/mimodulo.page.js
Register the route in Router.js
Open The router strips the hash prefix and resolves routes by their base path segment, so
js/core/Router.js and add your new route to the routes object. For most pages, use the lazy dynamic import() pattern so the module is only loaded when the user navigates to that route:js/core/Router.js
The lazy
import() pattern — () => import('...').then(m => m.PageFn()) — means the JavaScript for that page is only fetched and parsed when the user first visits that route. Use it for every route except those that must be available immediately on page load (like LoginPage and HomePage). This keeps the initial load fast.#/mimodulo/123 resolves to the /mimodulo entry automatically.Add operation listeners for real-time updates (optional)
If your module’s data can change in real time because other users are modifying the same records, register your page key and the relevant socket operation strings in Back in your page file,
js/core/OperationListeners.js:js/core/OperationListeners.js
shouldUpdatePage('mimodulo', payload?.operation) will return true only when the incoming data:changed socket event carries one of the operations you listed here, preventing unnecessary re-renders on unrelated events.Summary checklist
Repository
js/repositories/mimodulo.repository.js — one export per HTTP verb, ApiClient calls only.Service
js/services/mimodulo.service.js — re-exports with clean names, transformation logic if needed.Page
js/pages/mimodulo/mimodulo.page.js — renderPage() returns HTML, MimoduloPage() wraps it in PrivateLayout and wires events.Router
One new entry in the
routes object inside js/core/Router.js, using the lazy import() pattern.