Skip to content

tenant

Registers the three core multi-tenancy entities — tenant, tenant-membership, and tenant-invitation (DB tables read_tenants, read_tenant_memberships, and read_tenant_invitations) — along with write handlers for create/update/disable/enable/addMember/removeMember/updateMemberRoles and the matching queries. It also declares a set of per-tenant config keys (companyName, timezone, locale, SMTP credentials) and system-only keys (priceModel, maxUsers) via r.config({ keys: { ... } }). Use this feature in every multi-tenant app; membership resolution and invitation flows depend on it, and auth-email-password requires it.

From recipes-user-profile — the smallest working mount:

// user-profile Recipe — zeigt das App-Wiring für die Self-Service-
// Kontoseite: das bundled feature liefert Handler (change-email) +
// ProfileScreen-Komponente + i18n; die App deklariert den Screen als
// `custom` mit der __component-Convention und hängt ihn in die Nav.
//
// Client-seitig registriert die App die Komponente im Renderer-Mount:
// import { ProfileScreen, userProfileClient } from
// "@cosmicdrift/kumiko-bundled-features/user-profile/web";
// createKumikoApp({
// components: { UserProfileScreen: ProfileScreen },
// clientFeatures: [emailPasswordClient(), userProfileClient()],
// })
import { createAuthEmailPasswordFeature } from "@cosmicdrift/kumiko-bundled-features/auth-email-password";
import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
import { createComplianceProfilesFeature } from "@cosmicdrift/kumiko-bundled-features/compliance-profiles";
import { createConfigFeature } from "@cosmicdrift/kumiko-bundled-features/config";
import { createDataRetentionFeature } from "@cosmicdrift/kumiko-bundled-features/data-retention";
import { createFilesFeature } from "@cosmicdrift/kumiko-bundled-features/files";
import { createPersonalAccessTokensFeature } from "@cosmicdrift/kumiko-bundled-features/personal-access-tokens";
import { createSessionsFeature } from "@cosmicdrift/kumiko-bundled-features/sessions";
import { createTenantFeature } from "@cosmicdrift/kumiko-bundled-features/tenant";
import { createUserFeature } from "@cosmicdrift/kumiko-bundled-features/user";
import { createUserDataRightsFeature } from "@cosmicdrift/kumiko-bundled-features/user-data-rights";
import { createUserDataRightsDefaultsFeature } from "@cosmicdrift/kumiko-bundled-features/user-data-rights-defaults";
import { createUserProfileFeature } from "@cosmicdrift/kumiko-bundled-features/user-profile";
import { defineFeature, type FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
export function createAccountFeature(): FeatureDefinition {
return defineFeature("account", (r) => {
r.describe(
"App-side wiring for the user-profile bundled feature: declares the " +
"profile screen (custom renderer, __component UserProfileScreen) and " +
"its nav entry.",
);
r.requires("user-profile");
r.screen({
id: "profile",
type: "custom",
renderer: { react: { __component: "UserProfileScreen" } },
});
r.nav({
id: "profile",
label: "account:nav.profile",
icon: "user",
screen: "account:screen:profile",
order: 90,
});
return {};
});
}
/** Volle Feature-Komposition inkl. der user-profile-Require-Kette
* (user-data-rights → data-retention + compliance-profiles + sessions). */
export function composeAccountApp(): FeatureDefinition[] {
return [
createConfigFeature(),
createUserFeature(),
createTenantFeature(),
createAuthEmailPasswordFeature(),
createDataRetentionFeature(),
createComplianceProfilesFeature(),
authFoundationFeature,
createPersonalAccessTokensFeature({ scopes: {} }),
createSessionsFeature(),
createFilesFeature(),
createUserDataRightsFeature(),
// registers the default export/erase hooks for core PII entities (user,
// fileRef, folder) so the GDPR boot gate (V3) is satisfied for the stack.
createUserDataRightsDefaultsFeature(),
createUserProfileFeature(),
createAccountFeature(),
];
}

📄 On GitHub: samples/recipes/user-profile/src/feature.ts

tenant feature preview

What this feature needs to run (Requires, top) and the write commands it provides (Provides, bottom).

flowchart TB
  n_tenant["tenant"]
  subgraph how_reqs["Requires"]
    n_config["config"]
  end
  subgraph how_provides["Provides"]
    n_cmd_tenant_write_add_member(["add-member"])
    n_cmd_tenant_write_cancel_invitation(["cancel-invitation"])
    n_cmd_tenant_write_create(["create"])
    n_cmd_tenant_write_disable(["disable"])
    n_cmd_tenant_write_enable(["enable"])
    n_cmd_tenant_write_remove_member(["remove-member"])
    n_cmd_more(["+3 more"])
  end
  n_config --> n_tenant
  n_tenant --> n_cmd_tenant_write_add_member
  n_tenant --> n_cmd_tenant_write_cancel_invitation
  n_tenant --> n_cmd_tenant_write_create
  n_tenant --> n_cmd_tenant_write_disable
  n_tenant --> n_cmd_tenant_write_enable
  n_tenant --> n_cmd_tenant_write_remove_member
  n_tenant --> n_cmd_more

Provides — write commands this feature registers (dispatch them through the command bus):

Start with recipes-user-profile for a step-by-step walkthrough with runnable code and integration tests.

  • Requires: config
  • Activation: always on (not toggleable)

Per-tenant config keys, set via the tenant-admin UI or a seed. 🔒 = encrypted at rest.

KeyTypeDefaultScopeWho can writeWho can read
company-nametext""tenantTenantAdmin, Admin, SystemAdminall
localeselect (de | en | fr | es)detenantTenantAdmin, Admin, SystemAdminall
max-usersnumber50systemsystemTenantAdmin, Admin, SystemAdmin
price-modelselect (basic | pro | enterprise)basicsystemsystemTenantAdmin, Admin, SystemAdmin
smtp-hosttexttenantSystemAdminTenantAdmin, Admin, SystemAdmin
smtp-passtexttenant 🔒SystemAdminSystemAdmin
timezoneselect (UTC | Europe/Berlin | Europe/London | Europe/Paris | Europe/Madrid | Europe/Rome | America/New_York | America/Los_Angeles | America/Sao_Paulo | Asia/Tokyo | Asia/Singapore | Australia/Sydney)Europe/BerlintenantTenantAdmin, Admin, SystemAdminall