User self-registration and account management¶
This operation covers the clsUser lifecycle around external-user accounts: constructing a new account from clsNewUserArgs, resolving the first user type and contact linkage, persisting the EXT_USER row, saving child collections, reloading existing users, handling forgotten-user recovery, and updating the last-logon timestamp.
| Field | Value |
|---|---|
| Operation ID | OP-EU-01 |
| Trigger | Registration/import creates a new clsUser; administration loads a user for edit; authentication updates last-logon; support flows call forgotten-user lookup |
| Inputs | clsNewUserArgs, UserID, AD user ID, email address, source-system identifiers, child user types, access groups, and security questions |
| Outputs | Persisted EXT_USER row, populated user aggregate, forgotten-user match, and updated last-logon timestamp |
| Primary components | clsUser.InitializeContactAndCustomer, clsUser.AddUserType, clsUser.OnSave, clsUser.GetForgottenUser, clsUser.UpdateLastLogonDate |
| Entry point | Business\SAIF.Business.External.Users\clsUser.vb |
Steps¶
- Create or locate the root user object.
NewUsercreates a freshclsUserwith a newEXT_USER_SEQidentifier, whileGetUserloads an existing row by numeric user ID or AD user ID (SQL-015, EXT_USER). - Initialize a new registration from
clsNewUserArgs.InitializeContactAndCustomercopies override audit fields, creates a temporary password throughclsPassword.Generate, builds or reuses the contact/email/phone records, sets authorization and verification flags, and records test-user or injured-worker indicators (BR-EU-01). - If the request is not an import, it sets
EmailVerificationExpirationDateand clearsAcceptedUserAgreement. - If the request is a registration or import, it leaves
PasswordChangeRequiredoff; other entry paths require a password change on first use. - Resolve the primary user type and customer context.
AddUserTypecreates aclsUserType, assignsUserID, and derivesCustomerID,SourceSystemID, andSourceSystemGroupIDfrom the selected user type. - Agency users resolve customer info from the agent number.
- Auditor users query
PA_AUDITORby AD user ID and vendor number, with the same test-user fallback used by the dedicated lookup path (SQL-041, PA_AUDITOR). - Group, loss-control, and RTW users use
mdlGroupAssociationhelpers, including theRTW_LOAD_CODElookup for RTW groups (SQL-040). - Injured-worker variants translate the claim context into person and worker identifiers.
- Medical-provider users resolve provider customer IDs and may auto-select provider access groups.
- Policyholder users load policy data and auto-select the state-agency group when the policy entity code is
50. - Attach the contact relationship and access-group defaults. When the resolved customer is available,
AddUserTypeensures the customer has an external-security contact relationship for this contact, applies the caller's selected access groups, and adds any system-controlled default groups fromclsUserAccessGroupCollection.GetAllUserTypeAccessGroups(SQL-023, SQL-024, EXT_USER_ACCESS_GROUP). - Derive the initial account status. New registrations become Active for imports, Pending steward activation for agency or steward-governed registrations, and Pending email verification for all other registration flows.
- Validate uniqueness and required fields before persistence.
IsValidruns the childclsNewUserArgsrules for new users, then appliesclsUserrules for names, email, phone, phone format, test-user expiry, and access-group combinations. - Duplicate active email detection queries other active non-test users by normalized email and blocks any matching type-and-group combination (BR-EU-04, SQL-016, EXT_USER, EMAIL_ADDRESS, EXT_USER_TYPE).
- New users also require the AD user ID to be available before insert.
- Insert the
EXT_USERrow for a new account.BeforeInsertsets create/update stamps, applies test-user expiration windows, and binds the account flags into theEXT_USERinsert statement (BR-EU-01, SQL-005, EXT_USER). - On insert row-count failure, the object records an insert error instead of marking the row clean.
- Update an existing
EXT_USERrow with optimistic concurrency.BeforeUpdaterefreshes the audit stamp, extends email-verification expiry when the email changed, and issues theUPDATE ... AND update_num = :UpdateNumstatement (BR-EU-01, BR-EU-05, SQL-045, EXT_USER). - On a zero-row update, the object reports a DB-contention error and leaves the aggregate dirty.
- Save dependent children around the root save.
OnSavepersists a new customer/contact before the root row or saves a dirty existing contact, resets the user agreement if access groups changed, and calls the base save.OnSaveCompletethen saves security questions, user types, and any deny-self-registration rows attached to the user aggregate. - Reload existing users and their supporting projections. Retrieval fills the base
EXT_USERfields from SQL-015; later property access lazy-loads user types, security questions, and contacts.Typesloads user-type projections for the user and reattaches user-type rules.SecurityQuestionsloads the user's answers by user ID (SQL-028, EXT_USER_SECURITY_QUESTION).GetProviderloads provider-display information for an external user type (SQL-018, EXT_USER_TYPE).
- Resolve forgotten-user requests through progressively broader identity matches.
GetForgottenUserfirst searches by the supplied source-system identifier and email, then retries by provider ID when the identifier is a provider tax ID, and finally retries by worker ID when the identifier is a valid claim number (SQL-017, SQL-018, EXT_USER, EMAIL_ADDRESS, EXT_USER_TYPE). - Retrieve peer users for worker or group checks when needed.
GetUsers(userType, sourceSystemGroupID)reloads users that share a type-and-group combination so validation can detect existing injured-worker logons (SQL-019, EXT_USER, EXT_USER_TYPE). - Update the last-logon timestamp for sign-in activity.
UpdateLastLogonDateissues a direct update by AD user ID and returnsTrueonly when one row changed (SQL-046, EXT_USER).
Process flow¶
The following diagram visualizes this operation's control flow.
flowchart TD
Start([Registration, retrieval, or sign-in request]) --> Mode{New account?}
Mode -->|Yes| Init[Initialize contact, user type, and status]
Init --> Validate[Run uniqueness and field validation]
Validate --> SaveRoot[Insert user row]
SaveRoot --> SaveChildren[Save contact, questions, and types]
Mode -->|No| Retrieve[Load user or forgotten-user match]
Retrieve --> Edit{Update requested?}
Edit -->|Yes| Update[Apply optimistic-concurrency update]
Edit -->|No| Done([Return loaded account])
Update --> Done
SaveChildren --> Done
Failure and edge-case behavior¶
- Email changes automatically restart the verification window on update.
- Test and production-test users receive different expiration windows during insert.
- Agency, policyholder, and medical-provider access-group combinations can fail child validation before the root user row is saved.
- A forgotten-user lookup can fail all three identity strategies and return
Nothingwithout changing persisted data. - Last-logon updates succeed only when the AD user ID matches exactly one row.
Related documentation¶
Sources¶
Business\SAIF.Business.External.Users\clsUser.vbBusiness\SAIF.Business.External.Users\clsPassword.vbBusiness\SAIF.Business.External.Users\mdlAuditor.vbBusiness\SAIF.Business.External.Users\mdlCodeMaps.vbBusiness\SAIF.Business.External.Users\mdlGroupAssociation.vb