user-profile
Self-service account page (fw#2312: declarative projectionDetail bound to the signed-in user’s own me row) plus its change-email write handler (re-auth via current password, uniqueness check, resets emailVerified and expects the app to trigger the verification flow). Change-password and change-email stay custom EditExtensionSection components (re-auth flows a declarative action can’t express); account deletion (user-data-rights request/cancel with grace period) is declarative fields + actions. Apps place the screen (id “profile”) in their logged-in area via r.nav — no type: "custom" / __component registration needed on the app side anymore. Requires user, auth-email-password, user-data-rights, and user-data-rights-defaults (so the GDPR boot-validator finds export/delete hooks for user’s PII fields once user-data-rights is mounted).
Quick example
Section titled “Quick example”From recipes-user-profile — the smallest working mount:
// user-profile Recipe — shows the app-side wiring for the self-service// account page: the bundled feature ships the screen itself (fw#2312:// declarative `projectionDetail`, id "profile") including handler + i18n;// the app only has to navigate to it, no own `r.screen()` registration// anymore (unlike before #2312 — see user-data-rights' recipe/demo pattern:// `r.nav({ screen: "<feature>:screen:<id>", ... })`).//// Client-side, the app only registers the two extension-section components// (change-password/change-email stay React, re-auth):// import { userProfileClient } from// "@cosmicdrift/kumiko-bundled-features/user-profile/web";// createKumikoApp({// 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: just the nav " + "entry — user-profile registers the `profile` screen itself " + "(fw#2312 declarative projectionDetail).", ); r.requires("user-profile");
r.nav({ id: "profile", label: "account:nav.profile", icon: "user", screen: "user-profile: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
Live preview
Section titled “Live preview”
How it fits
Section titled “How it fits”What this feature needs to run (Requires, top) and the write commands this feature provides (Provides, bottom).
flowchart TB
n_user_profile["user-profile"]
subgraph how_reqs["Requires"]
n_user["user"]
n_auth_email_password["auth-email-password"]
n_user_data_rights["user-data-rights"]
n_user_data_rights_defaults["user-data-rights-defaults"]
end
subgraph how_provides["Provides"]
n_cmd_user_profile_write_change_email(["change-email"])
end
n_user --> n_user_profile
n_auth_email_password --> n_user_profile
n_user_data_rights --> n_user_profile
n_user_data_rights_defaults --> n_user_profile
n_user_profile --> n_cmd_user_profile_write_change_email
Provides — write commands this feature registers (dispatch them through the command bus):
Getting started
Section titled “Getting started”Start with recipes-user-profile for a step-by-step walkthrough with runnable code and integration tests.
Dependencies
Section titled “Dependencies”- Requires:
user,auth-email-password,user-data-rights,user-data-rights-defaults - Activation: always on (not toggleable)