Files
monorepo/LCU.API.Internal.MemberPreferencesApi
2026-04-07 13:11:39 -05:00
..
2026-03-31 16:43:12 -05:00
2026-04-07 13:11:39 -05:00
2026-04-07 13:11:39 -05:00
2026-03-31 16:43:12 -05:00
2026-03-31 16:43:12 -05:00
2026-03-31 16:43:12 -05:00
2026-03-31 16:43:12 -05:00
2026-03-31 16:43:12 -05:00
2026-04-07 13:11:39 -05:00
2026-03-31 16:43:12 -05:00
2026-03-31 16:43:12 -05:00
2026-03-31 16:43:12 -05:00
2026-03-31 16:43:12 -05:00

Application

This contains the service layer and repositories with business logic.

Azure Notes (Debug Security)

  1. Figure out your thumbprints, there will be two:
    1. NCR Public - Retrieve from NCR, or check the production Azure App Service (See below)
    2. Landmark Private - Retrieve from IT, or check the production Azure App Service (See Below)
    3. Thumbprints looks like this: 78C8DD6DE0FFD3802E265E96578DE39903F6A7D4
  2. Check the Azure App Service for the environment:
  3. Under TLS/SSL Settings, Private Key Tab, there should be a certificate that is valid. Note the thumbprint!
  4. Under TLS/SSL Settings, Public key tab, there should be a certificate. Note the thumbprint!
  5. Under Configuration, Application Settings, ensure the following key/value pairs:
  6. ASPNETCORE_ENVIRONMENT=Development|Production
  7. WEBSITE_LOAD_CERTIFICATES=* (If this isn't a *, it should be the two thumbprints separated by a comma)
  8. Check the Key Vault in Azure for the environment
    1. The landmark (private) signature in the vault should match that in the app service.
    2. The DI/NCR (public) signature in the vault should match that in the app service.
  9. You can view the logs by using the Kudu tool and going into site/www folder, the file names match the setup in appsettings.json
  10. Remember that the path is Client => Vendor API => Relay Api => Member Preferences API.

Domain

This contains the domain bounded entities, as well as the models and DTO objects used to link the service layer and the web api.

WebApi

This project implements the scaffolding and RESTful controllers by communicating with the services in the application layer via models.

SQL API

Consumed mainly as a reporting API.

The table structure produced by entity framework for this application is used as an API by external teams. The tables are referenced directly, not through any form of abstraction (e.g. a view). Given that there is currently no versioning strategy and no abstraction the SQL API is likely to only ever support non-break forwards compatible changes (a breaking change might be changing a column from holding a value to holding a foreign key to that value)

In the future it would be great to separate the storage model from the application model from the contract model(s). Because so much of the current application (2022) is written to rely implicitly on Entity Framework's change tracking (implicit coupling between repository consumers and repository implementation) this change in architecture likely means a rewrite of a large portion of the LCU.API.Internal.MemberPreferencesApi.

These two factors together work to produce an awkward application data model by the constraints they impose against change.

Vocabulary

  • e-Notice Preference [Existing]
  • e-Statement Preference [Existing]
  • Unified Preference (Labelled: Paperless Preference) [Future]

Important Data from XP (Code Side)

  • Membership.MAIL_CODE_STMT
  • SHARE.OVERDRAFT_OPT_IN_METHOD
  • SHARE.IS_OVERDRAFT_OPT_IN

Vendors

  • Online Banking (NCR/DI)
  • XDI
  • OSG

Online Banking (NCR/DI)

  • Provides an iFrame to update XDI e-Notice preference.
  • Provides a way to select e-Statement.

XDI

  • Internally stores e-Notices flag; from iFrame, which includes email. [Existing]
  • Send this flag to XDI [Future]
  • Notices, Arm Statements, S.D. Mortgage Statement are sent to XDI, unless DNA [Transition]
  • An associate currently logs into XDI to opt members out.

XDI Ftp Information

Within your home directory there are three sub-folders of interest:

Pickup - this is where you would retrieve files from XDI. Files placed in this folder will be encrypted and password protected. It is appropriate to delete files from the Pickup folder once you have retrieved the file. Test - this is where you would place all non-production files. Files placed in this folder are flagged as test and appropriate XDI staff is notified of its arrival. Proof - this is where you would place non-production or production files that you want a proof created and returned to you. Files placed in this folder are flagged as proof and appropriate XDI staff is notified of its arrival.

OSG

  • Statements use flag below. [Existing]
  • Some paper notices, no electronic => No way of getting OSG the XDI flag. [Existing]
  • Get email from query, does it use the opt-in column? [Blocker]
  • Uses flag on statement PDF/Binary File to determine electronic or paper; believe that is sourced from MAIL_CODE_STMT. [Blocker]
  • Should eventually transition all notices and statements to OSG, 11/01/2021. [Transition]
  • Walter is working on a standard data file template for sending to OSG, there are ~100 documents to do this for. [Transition]
  • Can OSG be told to produce a document even if not electronic (for view in OBS)

Future State

  • Move to where this is a single path/flow for users instead of two. (and two terms&conditions)
  • View preference data all in one place.
  • Members go two places to view preferences, would like to go to one place and see the one preference.

Notes

  • Email tool is outside our scope.
  • The DateTimeService uses the following library https://github.com/mattjohnsonpint/TimeZoneConverter, in order to determine if AINA or Windows time zones should be used. See the IncentiveManager/IncentiveAPI project for the reasoning behind this architectural decision.

SQL

This is known to get the currently interesting columns: SELECT m.MEMBER_NBR, m.MAIL_CODE_STMT, mc.MAIL_CODE_NAME, m.MAIL_CODE_STMT_2, m.MAIL_CYCLE_STMT, m.CC_MAIL_CODE_STMT_2, m.CC_MAIL_CODE_STMT, s.OVERDRAFT_OPT_IN_METHOD, s.IS_OVERDRAFT_OPT_IN FROM DB2INST1.MEMBERSHIP m JOIN DB2INST1.MAILCODE mc ON m.MAIL_CODE_STMT = mc.MAIL_CODE_ID JOIN DB2INST1.SHARE s ON s.MEMBER_NBR = m.MEMBER_NBR;

Feature Management

This application uses Microsoft's FeatureManagement package to enable/disable features in the code.

This is initialized in startup like so: services.AddFeatureManagement();

The feature flags are configured at their default location in any of the appsettings:

"FeatureFlags" : {
  "EnableControllers" : true,
  "RunHostedServices": false,
  "BounceBackNotifications" : false
}

After adding an item to the config it is suggested to add the Flag's string to the FeatureFlag.cs static class under the configuration folder of the main project.

Feature flags can be used in [FeatureGate(*nameOfFlag*)] attributes in controllers to enable and disable them dynamically by changing the config:

namespace LCU.API.Collections.RepoApi.Controllers
{
     [Route("api/[controller]")]
     [ApiController]
     [FeatureGate(FeatureFlags.EnableControllers)]
      public class RefundStatusController : RepoControllerBase
      {

After injecting IFeatureManagement they can also be used inline to prevent entire bloks of code from running:

 if (await featureManager.IsEnabledAsync(FeatureFlags.FeatureA)) { // Run the following code }

Learn more about Microsoft.FeatureManagement : (https://docs.microsoft.com/en-us/azure/azure-app-configuration/use-feature-flags-dotnet-core?tabs=core5x)

Learn more about the history and use cases of Feature Management: (https://martinfowler.com/articles/feature-toggles.html)

Current FeatureFlags

  • EnableControllers: Enable MemberOptInSettingsController & MemberOptInSettingsController
  • RunHostedServices: Add hosted services inside Startup.cs
  • BounceBackNotifications: Turn on or off the SixtyDaysUndeliverableEmailPolicy when an email has failed to send

Ef Migration

This project currently uses EF Migration to handle setting up the database instead of a DACPAC. The files efmigrate.ps1 and efupdate.ps1 contain sample instructions that you can use, and will continue to be updated. It's important to note which environment you want to run against, as well as making sure that inMemory = false.

Within the code, this migration is called with dbContext.Database.Migrate() in startup.cs

You can read about EF Migrations here: https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/?tabs=dotnet-core-cli

Outside scope

  • managing the terms and conditions.
  • managing lists of email, etc.
  • Navigating the user around OBS.

Important Tags

The following are tags for historic changes in the codebase that may be of interest to future developers

Tag Reason
pre-pdfverification-depreciation This tag is the last commit that contained the MemberVerificationPdfService (Used to generate Pdf with a 5-character hash) and its related controller. This requirement may return in the future.

Adding New DNA Audit Process

  • Add the DNA Process Name to the Enum in Domain > Enums > DnaAuditProcessType
  • Add Endpoint to AppSettings files under "CoreApiEndpoints"
  • Insert DnaProcess into Database using the below insert statement
    • Insert INTO DnaAuditProcess (DnaProcessType, LastUpdated, ConsecutiveFailures) Values ({DnaProcessTypeFromEnum}, {GETDATE}, 0);
      • {DnaProcessTypeFromEnum} should be the index of the new DNAProcessType in the enum.
      • {GETDATE} should be used for last updated unless you need to gather a certain amount of history for this audit type.
        • Using a minimum DateTime value will most likely overload the core-api-wrapper call
      • ConsecutiveFailures should be set at 0 since the process has not failed yet.
      • ProcessId will populate as it is the auto incrementing Primary Key. ProcessId is not currently used in DNAAudit Process logic
  • Add EnqueDateAuditFor{Type} method in Application > Services > Producers > DNADataAuditProducerService (and Interface)
  • Add Get{ProcessType} method to CoreDao and Interface
  • Add method call to switch statement in Application > Services > Producers > DNADataAuditProducerService > RunDataAudit()

Additional Notes (More to come with next solution version)

-DNADataAuditProcessService has a method called RunDataAuditProcesses from the scheduled HostedDnaDataAuditProcessService. This service calls the core to get the latest updated accounts, and determines if an account needs to have its delivery method reset and queues an update.

Summary of Refactor

-Removal of Projects that were used to help load data from XP2 before DNA launch. -Follow design patterns as a guide url for reference: https://landmarkcu.visualstudio.com/Platform/_git/LCU.Platform.PatternTemplates -Mass Transit Queue Upgrade, removal of Real Time Queue processing -Removal of separate Queue Topics available for other APIs using real-time queue library -Two HostedServices - DnaAuditProcesses, XdiBatch -DnaAudit services are queued separately by process type: DNAAgreement, DNAAccounts, DNAOrganization -Removal of EF migration for table defintion, replaced with dacpac -Prepare API for AKS migration

Summarized Comments removed from original implementation code

MemberOptInSettingsController.cs -The header parameters in UpdateOptinPreference is accessed elsewhere in the application and added for swagger.

MemberPreferenceController.cs -The header parameters in UpdateOptinPreference is accessed elsewhere in the application and added for swagger

HostedService for XDI Batch Processing -The job processes the fields stored in the XDI Batch sql table and produces csv files and are queued via Sftp.

MemberPreferenceService.cs -Uses no tracking with database lookup of Getting Member Opt In Settings -Original comment in code: "use no tracking to reduce processing load and time" -Has a method SaveMemberPreferanceDefaultAsync to check to see if a value exists, provides a default value of Paper if it doesn't. -Updates value by userId if default value is different than a saved value.

IntegrationService.cs -Original intent was to publish an event and inform external systems that we have recorded a change to a member preference (specifically opt-in). -Currently this service creates a new Xdi batch item with (userId, createdDate, BatchState (New, TransferPending), lastUpdated) -Purpose of the batch item is to determine if there is an existing change within sql XdiBatchItems table for a user to send as ftp request to XDI.

XDIBatchFileRow.cs -Includes UserId, Email(depending on file type), Cell phone (if provided but doesn't appear to be included)

XDIFileType.cs -DeleteMember = Example name: Enrollment_Delete_LMCU.txt • Deletes member from Enrollment database (including history visible to LMCU) • File Format Example: 999999999|

-AddMemberElectronic = Enrollment_AddElectronic_LMCU.txt • Adds member to Enrollment database with member delivery preference set to Electronic for all doc types/service types. Members already existing will not be re-added. • Data File Format: Must include Member Number and HTML Email Address. • File Format Example: 999999999|[email protected]|[email protected]|

-UpdateMemberToElectronic = Enrollment_UpdateToElectronic_LMCU.txt • Sets delivery preference to Electronic for all doc types/service types, member must exist in Enrollment database • Also updates other fields that have changed (blank fields will replace the database entry with a blank field • Data File Format: Must include Member Number and HTML Email Address. • Optionally, you can include the MMS Cell Phone Number • File Format Example: 999999999|[email protected]|[email protected]|

-UpdateMemberToPrint = Enrollment_UpdateToPrint_LMCU.txt

•	Sets delivery preference to Print for all doc types/service types member must exist in Enrollment database
•	Also updates other fields that have changed blank fields will replace the database entry with a blank field
•	Data File Format: List one member number on each line. 
•	File Format Example: 999999999|

-UpdateMemberEmail • File Format Example: 999999999|[email protected]|[email protected]|

XDIBatch.cs -Sets properties of XdiFileTypes according to the process checking of a batch item and the current member opt in settings. -Some of these checks may not apply today as they were added prior to DNA Go-Live 2021

•(Current UniversalOptIn = Paper and Current ENotfications = Electronic) => Update to Paper, already in XDI => Enrollment_UpdateToPrint
•(Current UniversalOptIn = Electronic and Current ENotification != Electronic and Current ENotification = Paper) => Update to Electronic, already in XDI => Enrollment_UpdateToElectronic
•(Current UniversalOptIn = Electronic and Current ENotification != Electronic and Current ENotification = NULL) => Update to Electronic, not in XDI => Enrollment_AddElectronic
•(Current UniversalOptIn = Electronic and Current ENotification = Electronic and Current UnifiedOptInEmail != Current ENotificationsEmail) Update email not Pref, already in XDI => Enrollment_UpdateEmail
•(Current UniversalOptIn = Hold and Current ENotification = Electronic) Update to hold, already in XDI => Enrollment_UpdateToPrint
•(Current UniversalOptIn = Microfiche and Current ENotification = Electronic) Update to microfiche, already in XDI => Enrollment_UpdateToPrint

General Member Preferences API Functionality Notes

-Online Banking replaced some functionality of the Unified Opt In process.

-There is a Member Preferences Tool site in the lower environments that can be used to set preferences, the changes are handled by Alkami the requests from Alkami are sent to LMCU Relay API with a specific http request route. The http request is handled by the LMCU Member Preferences Wrapper Api which calls Member Preferences Api directly to post member preference changes to DNA via LMCU Core Api Wrapper

-PreferenceTypes: ENotification, EStatements, UnifiedOptIn, ENotificationsEmail, EStatementsEmail, UnifiedOptInEmail

-XDI File types: DeleteMember, AddMemberElectronic, UpdateMemberToElectronic, UpdateMemberToPrint, UpdateMemberEmail

-Add the 60 Day Undeliverable logic and what is calling it (Data team has a query of the tables to determine the users and their email adddresses to send a generated email to users who have had failed email deliveries after 60 days.

-The rule of a failed delivery from Send Grid to Doc Ingestor is three times Doc Ingestor will call Member Preferences API and mark Member Preference table and add a Status Count per userid.

-Add Document Manager references and add links to specific items, diagrams and repositories

-The DNA Audit Process checks for any DNA activity table changes with an agreement, account, or organzation activity that updated the delivery method of account statements -Based on those results the delivery method is compared to what is saved in the Member Preferences table. There is a process in Member Preferences Api that determines what the source delivery method should be for a userid.

-Any changes to the delivery method is then sent to XDI to determine if they should have printed statements or not. Specific information in this file can be found in XDIFileType.cs notes above in readme file.

Net 8 Upgrade - 1/31/25

Added necessary changes for Net 8 version. SSH.Net nuget package was marked as vulnerable, updated version 2024.2