This document details the Zastrozzi CDP Users Library. This library provides functionality for managing both administrator and enduser accounts within the Zastrozzi CDP suite. It leverages NgRx for state management (via actions, effects, reducers, selectors, and facades), exposes API routes and configuration tokens, provides shared accessors, and includes a variety of reusable UI components and services. The library covers domains such as admin‑users and endusers, along with their associated state and API operations.
The Zastrozzi CDP Users Library delivers user management capabilities across two main domains:
The library uses a robust NgRx state management setup to ensure that state is predictable and actions are traceable. It also offers a range of UI components (such as lists, paginated tables, and filter inputs) and accessors for handling user tokens. Additionally, API routes and services—both live and mock—provide flexibility when integrating with backend endpoints.
A high-level overview of the CDP‑Users library layout (located in /packages/cdp/users):
.eslintrc.json
jest.config.ts
ng-package.json
package.json
project.json
README.md
tsconfig.json
tsconfig.lib.json
tsconfig.lib.prod.json
tsconfig.spec.json
src/
index.ts
test-setup.ts
lib/
cdp-users.module.ts // Main module that aggregates state, components, services, and API routes.
cdp-users.ts // Aggregates exports (state, models, accessors, routes, and services).
+state/
identifiers.ts // Defines namespaced keys for admin-user and enduser states.
index.ts // Re-exports state pieces.
state.ts // Combines reducers into a central state.
actions/ // Contains NgRx actions for admin-user and enduser domains.
effects/ // Contains NgRx effects for asynchronous operations.
facades/ // Exposes high-level facades for state access:
// e.g. AdminUserFacade, EnduserFacade, EnduserDeviceFacade, etc.
reducers/ // Contains reducers for processing actions immutably.
selectors/ // Provides memoized selectors for state slices.
accessors/
admin-user.access-token.accessor.ts // Provides helper methods for admin user token operations.
index.ts
api-routes/ // Aggregates API route definitions (for admin-user and enduser operations).
components/ // Reusable UI components (lists, forms, paginated tables, etc.).
config/ // Configuration files and tokens (e.g. CDP_USERS_API_CONFIG).
model/ // Shared models, enums, filters, requests, and responses.
routes/ // Angular route definitions specific to admin and enduser modules.
services/ // Contains abstract, live, and mock API service implementations.
cdp-users.module.ts, the module imports common modules (e.g. CommonModule, ZWPCommonModule, ZWPLayoutModule, ZWPAuthModule), registers state via NgRx, and declares UI components. It also configures API routes and injects service providers based on module configuration.forRoot() method accepts a configuration object (of type CDPUsersAPIConfig) and sets up API endpoints and the live or mock service implementations accordingly.The library leverages NgRx to handle both admin-user and enduser states. Each domain defines its own actions, effects, reducers, selectors, and facades.
CDP_USERS_ACTION_IDENTIFIERADMIN_USER_STATE_FEATURE_KEYADMIN_USER_DEVICE_STATE_FEATURE_KEYADMIN_USER_EMAIL_STATE_FEATURE_KEYADMIN_USER_SESSION_STATE_FEATURE_KEYENDUSER_STATE_FEATURE_KEYENDUSER_ACTIVITY_STATE_FEATURE_KEYThe CDP‑Users library organizes its actions into two main domains: Admin‑User Actions and Enduser Actions. In addition to the main CRUD actions, sub‑actions handle operations for related domains (such as addresses, credentials, devices, emails, sessions, phones, and activity). Each action dispatches a specific event to the NgRx store via NgRx’s createAction and is used in effects to perform asynchronous operations and update state.
These actions cover operations related to administrator accounts as well as the management of their sub-resources.
request: CreateAdminUserRequest (properties such as name, email, role, etc.) createAdminUser({ request: { name: 'Alice Admin', email: 'alice@example.com', role: 'admin' } })
adminUserId: string getAdminUser({ adminUserId: 'admin123' })
adminUserId: stringupdate: UpdateAdminUserRequest updateAdminUser({ adminUserId: 'admin123', update: { email: 'newemail@example.com' } })
force flag may bypass validations.adminUserId: stringforce?: boolean deleteAdminUser({ adminUserId: 'admin123', force: true })
These sub‑actions manage additional aspects of an admin user account.
adminUserId: stringcredential: { type: string, value: string } createAdminUserCredential({ adminUserId: 'admin123', credential: { type: 'password', value: 'securePass!' } })
adminUserId: stringcredentialId: stringupdate: Partial<CredentialUpdate> updateAdminUserCredential({ adminUserId: 'admin123', credentialId: 'cred456', update: { value: 'newSecurePass!' } })
adminUserId: stringcredentialId: string deleteAdminUserCredential({ adminUserId: 'admin123', credentialId: 'cred456' })
adminUserId: stringdevice: DeviceInfo registerAdminUserDevice({ adminUserId: 'admin123', device: { deviceId: 'dev001', type: 'desktop' } })
adminUserId: stringdeviceId: stringupdate: Partial<DeviceInfo> updateAdminUserDevice({ adminUserId: 'admin123', deviceId: 'dev001', update: { type: 'laptop' } })
adminUserId: stringdeviceId: string deleteAdminUserDevice({ adminUserId: 'admin123', deviceId: 'dev001' })
adminUserId: stringemail: string addAdminUserEmail({ adminUserId: 'admin123', email: 'admin.new@example.com' })
adminUserId: stringemailId: stringupdate: Partial<EmailUpdate> updateAdminUserEmail({ adminUserId: 'admin123', emailId: 'email789', update: { verified: true } })
adminUserId: stringemailId: string deleteAdminUserEmail({ adminUserId: 'admin123', emailId: 'email789' })
adminUserId: stringsessionDetails: SessionStartInfo startAdminUserSession({ adminUserId: 'admin123', sessionDetails: { token: 'abc123', expiresIn: 3600 } })
adminUserId: stringsessionId: string endAdminUserSession({ adminUserId: 'admin123', sessionId: 'sess456' })
adminUserId: stringsessionId: stringnewToken: string refreshAdminUserSession({ adminUserId: 'admin123', sessionId: 'sess456', newToken: 'newtoken789' })
adminUserId: stringactivity: ActivityEvent recordAdminUserActivity({ adminUserId: 'admin123', activity: { type: 'LOGIN', timestamp: Date.now() } })
adminUserId: string clearAdminUserActivity({ adminUserId: 'admin123' })
These actions manage standard enduser accounts and include additional operations for sub-resources such as addresses, credentials, devices, emails, phones, sessions, and activity.
request: CreateEnduserRequest (includes firstName, lastName, email, etc.) createEnduser({ request: { firstName: 'Bob', lastName: 'User', email: 'bob@example.com' } })
enduserId: string getEnduser({ enduserId: 'enduser456' })
enduserId: stringupdate: UpdateEnduserRequest updateEnduser({ enduserId: 'enduser456', update: { phone: '123-456-7890' } })
enduserId: stringforce?: boolean deleteEnduser({ enduserId: 'enduser456', force: true })
enduserId: stringaddress: AddressInfo createEnduserAddress({ enduserId: 'enduser456', address: { street: '123 Main St', city: 'Metropolis' } })
enduserId: stringaddressId: stringupdate: Partial<AddressInfo> updateEnduserAddress({ enduserId: 'enduser456', addressId: 'addr789', update: { city: 'Gotham' } })
enduserId: stringaddressId: string deleteEnduserAddress({ enduserId: 'enduser456', addressId: 'addr789' })
enduserId: stringcredential: { type: string, value: string } createEnduserCredential({ enduserId: 'enduser456', credential: { type: 'password', value: 'enduserPass!' } })
enduserId: stringcredentialId: stringupdate: Partial<CredentialUpdate> updateEnduserCredential({ enduserId: 'enduser456', credentialId: 'cred101', update: { value: 'newPass123' } })
enduserId: stringcredentialId: string deleteEnduserCredential({ enduserId: 'enduser456', credentialId: 'cred101' })
enduserId: stringdevice: DeviceInfo registerEnduserDevice({ enduserId: 'enduser456', device: { deviceId: 'dev002', type: 'mobile' } })
enduserId: stringdeviceId: stringupdate: Partial<DeviceInfo> updateEnduserDevice({ enduserId: 'enduser456', deviceId: 'dev002', update: { type: 'tablet' } })
enduserId: stringdeviceId: string deleteEnduserDevice({ enduserId: 'enduser456', deviceId: 'dev002' })
enduserId: stringemail: string addEnduserEmail({ enduserId: 'enduser456', email: 'bob.user@example.com' })
enduserId: stringemailId: stringupdate: Partial<EmailUpdate> updateEnduserEmail({ enduserId: 'enduser456', emailId: 'email202', update: { verified: true } })
enduserId: stringemailId: string deleteEnduserEmail({ enduserId: 'enduser456', emailId: 'email202' })
enduserId: stringphone: string addEnduserPhone({ enduserId: 'enduser456', phone: '+11234567890' })
enduserId: stringphoneId: stringupdate: Partial<PhoneUpdate> updateEnduserPhone({ enduserId: 'enduser456', phoneId: 'phone303', update: { primary: true } })
enduserId: stringphoneId: string deleteEnduserPhone({ enduserId: 'enduser456', phoneId: 'phone303' })
enduserId: stringsessionDetails: SessionStartInfo startEnduserSession({ enduserId: 'enduser456', sessionDetails: { token: 'xyz789', expiresIn: 3600 } })
enduserId: stringsessionId: string endEnduserSession({ enduserId: 'enduser456', sessionId: 'sess999' })
enduserId: stringsessionId: stringnewToken: string refreshEnduserSession({ enduserId: 'enduser456', sessionId: 'sess999', newToken: 'newtoken321' })
enduserId: stringactivity: ActivityEvent recordEnduserActivity({ enduserId: 'enduser456', activity: { type: 'UPDATE', timestamp: Date.now() } })
enduserId: string clearEnduserActivity({ enduserId: 'enduser456' })
Each of these actions is typically defined with NgRx’s createAction function in the corresponding action file (e.g. admin-user.actions.ts, enduser.actions.ts, etc.) and are later used in effects to perform API calls, updating reducers to change the state.
effects/ folder) use RxJS operators (switchMap, map, catchError) to invoke API services and dispatch success/failure actions.reducers/ folder update state immutably based on dispatched actions.createReducer and on functions for both admin-user and enduser subdomains.selectors/ folder) provide memoized views of the state — for instance, current user lists, selected user details, filter settings, and pagination metadata.createSelector to derive slices of the admin-user and enduser state.Facades simplify store interactions by exposing observable state and dispatch methods.
adminUsers$: Emits an array of admin user records.adminUserFilters$: Emits current filter criteria.adminUserRemotePagination$: Emits pagination metadata.adminUserRemoteState$: Emits the status of remote API calls.createAdminUser(request: CreateAdminUserRequest): voidgetAdminUser(adminUserId: string): voidupdateAdminUser(adminUserId: string, update: UpdateAdminUserRequest): voiddeleteAdminUser(adminUserId: string, force?: boolean): voidselectAdminUser(adminUserId: string): voiddeselectAdminUser(): voidupdateAdminUserFilters(filters: Partial<AdminUserFilters>, triggerRemoteFetch?: boolean): voidresetAdminUserFilters(triggerRemoteFetch?: boolean): voidresetPagination(): voidendusers$: Emits a list of enduser records.enduserFilters$: Emits current filter criteria.enduserRemotePagination$: Emits pagination details.enduserRemoteState$: Emits the remote API status.createEnduser(request: CreateEnduserRequest): voidgetEnduser(enduserId: string): voidupdateEnduser(enduserId: string, update: UpdateEnduserRequest): voiddeleteEnduser(enduserId: string, force?: boolean): voidselectEnduser(enduserId: string): voiddeselectEnduser(): voidupdateEnduserFilters(filters: Partial<EnduserFilters>, triggerRemoteFetch?: boolean): voidresetEnduserFilters(triggerRemoteFetch?: boolean): voidresetPagination(): voidAdditional facades exist for managing subfeatures such as admin-user devices, emails, credentials, and enduser phones, sessions, etc.
The library provides accessors to simplify working with tokens and other computed data. For example, the admin-user.access-token.accessor.ts exports helper functions to retrieve and update admin user access tokens from state or storage.
API route definitions are located in the api-routes/ folder and consolidate endpoints for both admin-user and enduser operations.
CDP_USERS_API_CONFIG and CDP_USERS_API_BASE_URL) are defined in the config/ folder to allow environment-specific behavior (e.g. switching between local and remote endpoints).The library provides several layers of API services:
createAdminUser(request: Model.CreateAdminUserRequest): Observable<Model.AdminUserResponse>Abstract interfaces (e.g. AdminUserAPIService and EnduserAPIService) are defined in the services/abstract folder. Injection tokens (such as ADMIN_USER_API_SERVICE and ENDUSER_API_SERVICE) allow the application to switch between live and mock implementations based on configuration.
The CDP‑Users library declares a rich set of reusable UI components for managing user data. These include:
AdminUserListComponent: Displays a paginated table of admin users with filtering and sorting.AdminAccountDevicesComponent: Manages device information for an admin user.AdminAccountEmailComponent: Handles email addresses.EnduserListComponent: A list component for endusers with paginated tables, filter inputs, and sort options.EnduserAccountDevicesComponent, EnduserAccountCommunicationsComponent, etc.AudienceListComponent: Provides an aggregated view of audiences with filtering and selection capabilities.Components utilize Angular Material elements, responsive layouts (using Flex Layout) and connect to facades for state data.
nx build cdp.users
nx test cdp.users
import { CDPUsersModule } from '@zwp/cdp.users';
@NgModule({
imports: [
CDPUsersModule.forRoot({
remoteBaseUrl: 'https://api.remote.example.com',
localBaseUrl: 'http://localhost:3000',
apiState: ModuleAPIState.LIVE, // or ModuleAPIState.MOCK
}),
// Other module imports
]
})
export class AppModule {}
The Zastrozzi CDP Users Library provides a complete, scalable solution for managing both admin and enduser accounts. With comprehensive NgRx state management, shared accessors, well-structured API routes, and a suite of live and mock API services, this library supports robust user management across the CDP suite. Customize its components, facades, and services as our project requirements evolve.