Skip to content

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

  1. Create or locate the root user object. NewUser creates a fresh clsUser with a new EXT_USER_SEQ identifier, while GetUser loads an existing row by numeric user ID or AD user ID (SQL-015, EXT_USER).
  2. Initialize a new registration from clsNewUserArgs. InitializeContactAndCustomer copies override audit fields, creates a temporary password through clsPassword.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).
  3. If the request is not an import, it sets EmailVerificationExpirationDate and clears AcceptedUserAgreement.
  4. If the request is a registration or import, it leaves PasswordChangeRequired off; other entry paths require a password change on first use.
  5. Resolve the primary user type and customer context. AddUserType creates a clsUserType, assigns UserID, and derives CustomerID, SourceSystemID, and SourceSystemGroupID from the selected user type.
  6. Agency users resolve customer info from the agent number.
  7. Auditor users query PA_AUDITOR by AD user ID and vendor number, with the same test-user fallback used by the dedicated lookup path (SQL-041, PA_AUDITOR).
  8. Group, loss-control, and RTW users use mdlGroupAssociation helpers, including the RTW_LOAD_CODE lookup for RTW groups (SQL-040).
  9. Injured-worker variants translate the claim context into person and worker identifiers.
  10. Medical-provider users resolve provider customer IDs and may auto-select provider access groups.
  11. Policyholder users load policy data and auto-select the state-agency group when the policy entity code is 50.
  12. Attach the contact relationship and access-group defaults. When the resolved customer is available, AddUserType ensures 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 from clsUserAccessGroupCollection.GetAllUserTypeAccessGroups (SQL-023, SQL-024, EXT_USER_ACCESS_GROUP).
  13. 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.
  14. Validate uniqueness and required fields before persistence. IsValid runs the child clsNewUserArgs rules for new users, then applies clsUser rules for names, email, phone, phone format, test-user expiry, and access-group combinations.
  15. 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).
  16. New users also require the AD user ID to be available before insert.
  17. Insert the EXT_USER row for a new account. BeforeInsert sets create/update stamps, applies test-user expiration windows, and binds the account flags into the EXT_USER insert statement (BR-EU-01, SQL-005, EXT_USER).
  18. On insert row-count failure, the object records an insert error instead of marking the row clean.
  19. Update an existing EXT_USER row with optimistic concurrency. BeforeUpdate refreshes the audit stamp, extends email-verification expiry when the email changed, and issues the UPDATE ... AND update_num = :UpdateNum statement (BR-EU-01, BR-EU-05, SQL-045, EXT_USER).
  20. On a zero-row update, the object reports a DB-contention error and leaves the aggregate dirty.
  21. Save dependent children around the root save. OnSave persists 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. OnSaveComplete then saves security questions, user types, and any deny-self-registration rows attached to the user aggregate.
  22. Reload existing users and their supporting projections. Retrieval fills the base EXT_USER fields from SQL-015; later property access lazy-loads user types, security questions, and contacts.
    • Types loads user-type projections for the user and reattaches user-type rules.
    • SecurityQuestions loads the user's answers by user ID (SQL-028, EXT_USER_SECURITY_QUESTION).
    • GetProvider loads provider-display information for an external user type (SQL-018, EXT_USER_TYPE).
  23. Resolve forgotten-user requests through progressively broader identity matches. GetForgottenUser first 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).
  24. 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).
  25. Update the last-logon timestamp for sign-in activity. UpdateLastLogonDate issues a direct update by AD user ID and returns True only 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 Nothing without changing persisted data.
  • Last-logon updates succeed only when the AD user ID matches exactly one row.

Sources

  • Business\SAIF.Business.External.Users\clsUser.vb
  • Business\SAIF.Business.External.Users\clsPassword.vb
  • Business\SAIF.Business.External.Users\mdlAuditor.vb
  • Business\SAIF.Business.External.Users\mdlCodeMaps.vb
  • Business\SAIF.Business.External.Users\mdlGroupAssociation.vb