[data-reveal]{opacity:1!important;transform:none!important}
Introduction
Interfaces

Introduction

The core contract of the DMS: pages and modules, components, permissions, tenancy, invites, hooks, realtime, quick actions and layout banners.

Overview

The root export of @antelopejs/interface-dms and the subpaths listed below are the core contract of the AntelopeJS DMS. It encodes one inversion: the backend declares the screen, as serializable data. A page is a controller class, its components are static fields holding builders, and the page's layout route returns the description a shared frontend renders. Adding an admin screen is a backend change.

Around that core the interface carries what an admin backend needs to be more than a renderer: hierarchical permissions derived from the page tree, multi-tenant data access scoped by the model handle, lifecycle hooks, realtime topics, and command-palette entries.

Everything here is imported from a subpath of @antelopejs/interface-dms. Two other domains of the same package complete the picture and are referenced throughout these pages: Auth (/auth) for authentication and the User table, and Base (/base) for the concrete component vocabulary (Form, TableView, Grid, the chart family) built on the component types documented here.

Key Features

  • Pages as controllers — PageController builds a controller class bound to a URL; @RegisterPage() records it, registers its permissions, and serves its layout.
  • Components that serialize — a ComponentBuilder produces data, not a live component, so one frontend renders every module's screens.
  • Categories and modules — a sidebar tree of nested categories, plus modules that own a whole branch under /modules.
  • Dynamic navigation — providers that resolve extra menu entries per request, so one page can back an entry per project or workspace.
  • Page extensions — inject components into a page owned by another module, permissioned in that page's own tree.
  • Hierarchical permissions — ids derived from page, component and action, with a base set from roles and an effective set shaped by registered resolvers.
  • Route guards — permission, tenant-member and tenant-owner decorators usable as parameter or property decorators.
  • Tenancy in the handle — per-tenant schemas and model handles bound to one tenant, rather than a tenant column filtered on every query.
  • Tenant access gates — one binary check that denies a tenant at every authorization surface at once.
  • Invites — one call that either grants membership to an existing user or issues a token-bearing invite.
  • Lifecycle hooks — typed events for tenants, members, invites and registrations, dispatched either to notify or to collect contributions.
  • Realtime topics — bind a topic to a page, publish to whoever is on it, and subscribe from the backend to what others publish.
  • Quick actions — contribute grouped, permission-gated entries to the command palette.

Dependencies

This interface relies on the following AntelopeJS packages:

Quick Start

Declare the application's table and model first. BookModel is not a DMS export; this example defines it with the stock flag used by the KPI query.

db.ts
import {
  BasicDataModel,
  Field,
  RegisterTable,
  Table,
} from "@antelopejs/interface-database-decorators";

export const CATALOG_SCHEMA = "example_catalog";

@RegisterTable("books", CATALOG_SCHEMA)
export class Book extends Table {
  @Field("string") declare _id: string;
  @Field("string") declare title: string;
  @Field("boolean") declare inStock: boolean;
}

export class BookModel extends BasicDataModel(Book, "books") {}

Then declare a category, a page with a component, and the route that component fetches from:

books-page.ts
import { Get } from "@antelopejs/interface-api";
import { GetModel } from "@antelopejs/interface-database-decorators";
import {
  Category,
  PageController,
  RegisterPage,
  pagesCategory,
} from "@antelopejs/interface-dms/page";
import { KpiCard } from "@antelopejs/interface-dms/base";
import { BookModel } from "./db";

export const catalog = Category("catalog", {
  displayName: "Catalog",
  icon: "i-ph-books",
  category: pagesCategory,
});

@RegisterPage()
export class BooksPage extends PageController("books", {
  displayName: "Books",
  description: "Everything currently in the catalog",
  icon: "i-ph-book-open",
  category: catalog,
  order: 1,
}) {
  static inStockKpi = KpiCard({
    title: "In stock",
    icon: "i-ph-package",
    fetchUrl: "/catalog/books/stats/in-stock",
    valueFormat: "number",
  });

  @Get("/stats/in-stock")
  async inStock() {
    const value = await GetModel(BookModel).table
      .filter((book) => book.key("inStock").eq(true)).count().run();
    return { value };
  }
}

Import the page and register the schema from your module's entry file, merging this into an existing start() if necessary:

index.ts
import "./books-page";
import { RegisterSchema } from "@antelopejs/interface-database-decorators";
import { CATALOG_SCHEMA } from "./db";

export async function start(): Promise<void> {
  await RegisterSchema(CATALOG_SCHEMA);
}

The page resolves at /catalog/books and its layout at /dms/pages/catalog/books/pagelayout: a page controller's routes live under /dms/pages (pageRoutePath), a prefix the frontend server proxies to the backend, since the page's own path is the page. Its permission id is the chain of ids down from the root category — pages.catalog.books — with pages.catalog.books.inStockKpi registered underneath it.

Subpath Map

SubpathContainsDocumented in
/pagePages, categories, modules, layouts, page extensions, dynamic menus, frontend modulesPages and Modules
/componentComponent, ComponentBuilder, actions, watchesComponents
/component-slotsRegisterComponentSlot, ComponentSlotResolver, SlotOptionsComponents
/attachmentsSaveComponentFiles and its request, field and result typesPages and Modules
/permission-gateShared PermissionGate fieldsBase types
/permissionsThe permission registry and the permission computationPermissions
/permissions-resolverRegistering and running permission resolversPermissions
/guardsAuthUserWithPermission, AuthTenantOwner, AuthTenantMemberPermissions
/constantsSchema names and the default tenantTenancy
/dbThe Tenant, TenantMember, Role and UserInvite tables and modelsTenancy, Invites
/request-tenantgetRequestTenantIdTenancy
/tenant-scoped-modelTenantScopedModelTenancy
/tenant-accessTenant access gatesTenancy
/tenant-ownershipMembership and ownership writesTenancy
/tenant-lifecycleProducer admission and closure before tenant deletionTenancy
/data-controllersThe built-in members and roles data controllersTenancy
/invitesInviting a user into a tenantInvites
/invite-extensionsInvite form contributions, callbacks and availabilityInvites
/invite-resolutionDurable terminal decisions and retryable effectsInvites
/hooksThe Hook enum, handlers and dispatchHooks
/tenant-exportThe tenant data export archive, contribution and manifest types, re-exported from /hooksHooks
/realtimePage topics, publishing and backend subscriptionRealtime
/quick-actionsCommand-palette entriesQuick Actions
/layout-bannersGlobal banners under the dashboard headerLayout Banners
/uploadsSigned upload tokens for the file and image fields of a serialized componentPages and Modules
/typesMaybePromise, the one shared type aliasPages and Modules
/api-base-url, /client-base-urlGetApiBaseUrl, GetClientBaseUrl: the public origins of the API and the dashboardPages and Modules
/client-ipgetClientIp, ResolveClientIp: a request's client address behind the trusted proxiesPages and Modules

Paths under internal/, symbols tagged @internal, and internal namespaces are implementation wiring, not supported consumer APIs. The wildcard export does not change that boundary.

Documentation Sections

  • Pages and Modules - Declare pages, group them into categories, own a branch of the sidebar with a module, and extend a page from another one
  • Components - Build serializable components, declare actions and watches
  • Permissions - Register permissions, compute a user's effective set, guard routes
  • Tenancy - Schemas, the tenancy tables, tenant-scoped models and access gates
  • Invites - Bring a user into a tenant by email
  • Hooks - React to platform events and contribute to the tenant data export
  • Realtime - Bind topics to pages, publish messages and subscribe to them
  • Quick Actions - Contribute entries to the command palette
  • Layout Banners - Show a global banner under the dashboard header, decided per request