Skip to content

Adding a New Credit Union Client

A complete walkthrough for onboarding a new credit union onto the Progress platform, from project scaffolding through production deployment on Azure.

Prerequisites

  • .NET 10 SDK installed
  • Docker Desktop installed
  • Azure CLI (az) installed and authenticated
  • Azure subscription with permissions to create resources
  • Access to the Azure Artifacts NuGet feed (CUCloud-Web-Packages)

Step 1: Create the Project from Template

1.1 Install the template (first time only)

cd dbl.Progress
dotnet new install ./templates/Progress.Template

Verify installation:

dotnet new list | grep progress-cu

1.2 Scaffold the project

Replace all values with the actual client details:

dotnet new progress-cu \
  --ProjectName "MyCreditUnion" \
  --ClientSlug "mycu" \
  --Domain "mycu.ie" \
  --DbServer "mycu-sql.database.windows.net" \
  --DbUser "mycu_admin" \
  --DbPassword "YourStrongPassword123!" \
  --AdminEmail "admin@mycu.ie" \
  --AdminPassword "UmbracoAdmin1!" \
  --Country "Ireland" \
  --County "Wexford" \
  --UmbracoVersion "17.2.2"

Template Parameters Reference

Parameter Default Description
ProjectName MyCreditUnion Display name (used in UI and notification emails)
ClientSlug mycu Lowercase slug for DB name, Docker container, config files
Domain mycu.ie Production domain for Umbraco URL routing
DbServer localhost SQL Server hostname
DbUser sa SQL Server username
DbPassword CHANGEME SQL Server password
AdminEmail admin@mycu.ie Umbraco backoffice admin email
AdminPassword CHANGEME Umbraco backoffice admin password
Country Ireland Country for notification settings
County Dublin County/region for notification settings
UmbracoVersion 17.2.2 Umbraco CMS NuGet package version

1.3 Generated project structure

MyCreditUnion/
  nuget.config                         # Private NuGet feed configuration
  Dockerfile                           # Multi-stage Docker build
  src/
    MyCreditUnion/
      MyCreditUnion.csproj         # Thin host referencing baseline NuGet packages
      Program.cs                        # DI setup and Umbraco pipeline
      appsettings.json                  # Base configuration
      appsettings.mycu.json       # Client-specific overrides
      Views/
        _ViewImports.cshtml             # Shared Razor imports (301 baseline views copied on build)
      wwwroot/
        cssCreditUnion/
          theme.css                     # Client CSS theme

The generated project is a thin host -- it references Progress.Baseline.Core and Progress.Baseline.Web NuGet packages for all shared services, views, and static assets. Client-specific customization is limited to configuration, CSS themes, and optional view overrides.


Step 2: Configure the Database

Create the Azure SQL resources:

# Create resource group
az group create --name rg-mycu --location westeurope

# Create SQL server
az sql server create \
  --name mycu-sql \
  --resource-group rg-mycu \
  --location westeurope \
  --admin-user mycu_admin \
  --admin-password "YourStrongPassword123!"

# Create database (S1 tier is a good starting point)
az sql db create \
  --name mycu_cms \
  --resource-group rg-mycu \
  --server mycu-sql \
  --service-objective S1

# Allow Azure services to access the SQL server
az sql server firewall-rule create \
  --name AllowAzureServices \
  --resource-group rg-mycu \
  --server mycu-sql \
  --start-ip-address 0.0.0.0 \
  --end-ip-address 0.0.0.0

The connection string in appsettings.json will be:

Server=mycu-sql.database.windows.net;Database=mycu_cms;User Id=mycu_admin;Password=YourStrongPassword123!;TrustServerCertificate=True;MultipleActiveResultSets=true;

Option B: Local SQL Server (for development)

Use a local SQL Server instance or a Docker SQL Server container:

docker run -d --name mycu-sql \
  -e "ACCEPT_EULA=Y" \
  -e "MSSQL_SA_PASSWORD=YourStrongPassword123!" \
  -p 1433:1433 \
  mcr.microsoft.com/mssql/server:2022-latest

Connection string:

Server=localhost,1433;Database=mycu_cms;User Id=sa;Password=YourStrongPassword123!;TrustServerCertificate=True;MultipleActiveResultSets=true;

The database itself does not need to be created manually. Umbraco will create it on first run via the unattended install.


Step 3: Create the Client CSS Theme

Edit src/MyCreditUnion/wwwroot/cssCreditUnion/theme.css:

/*
 * My Credit Union - Theme Overrides
 *
 * These variables override the baseline styles from Progress.Baseline.Web.
 * Client CSS loads after baseline CSS and takes precedence.
 */

:root {
  /* Brand colors */
  --cu-primary: #0056b3;
  --cu-secondary: #6c757d;
  --cu-accent: #28a745;

  /* Header and navigation */
  --cu-header-bg: #003366;
  --cu-header-text: #ffffff;
  --cu-nav-bg: #004080;
  --cu-nav-hover: #0066cc;

  /* Footer */
  --cu-footer-bg: #1a1a2e;
  --cu-footer-text: #cccccc;

  /* Buttons */
  --cu-btn-primary-bg: var(--cu-primary);
  --cu-btn-primary-text: #ffffff;
  --cu-btn-secondary-bg: var(--cu-secondary);
  --cu-btn-secondary-text: #ffffff;

  /* Typography */
  --cu-font-family: 'Open Sans', sans-serif;
  --cu-heading-font: 'Montserrat', sans-serif;
}

Get the exact variable names from the baseline CSS in Progress.Baseline.Web. The variables above are illustrative -- use the actual variable names defined in the RCL.

Place the logo at:

src/MyCreditUnion/wwwroot/images/logo.png
src/MyCreditUnion/wwwroot/images/logo-white.png  (for dark backgrounds)

Step 4: Configure appsettings

The template pre-fills most values from the parameters you passed in Step 1. Review and update any remaining placeholders.

4.1 Base configuration (appsettings.json)

Key sections to verify:

{
  "ConnectionStrings": {
    "umbracoDbDSN": "Server=mycu-sql.database.windows.net;Database=mycu_cms;User Id=mycu_admin;Password=YourStrongPassword123!;TrustServerCertificate=True;MultipleActiveResultSets=true;"
  },
  "Umbraco": {
    "CMS": {
      "WebRouting": {
        "UmbracoApplicationUrl": "https://mycu.ie/"
      },
      "Unattended": {
        "InstallUnattended": true,
        "UpgradeUnattended": true,
        "UnattendedUserName": "Admin",
        "UnattendedUserEmail": "admin@mycu.ie",
        "UnattendedUserPassword": "UmbracoAdmin1!"
      }
    }
  },
  "ProgressSettings": {
    "ProjectAlias": "mycu",
    "GoogleMapsApiKey": "YOUR_GOOGLE_MAPS_API_KEY",
    "Notifications": {
      "OnlineBanking": "true",
      "MobileBanking": "true",
      "Country": "Ireland",
      "County": "Wexford",
      "CuName": "MyCreditUnion"
    }
  }
}

4.2 Client-specific overrides (appsettings.mycu.json)

Use this file for environment-specific values. For example, different connection strings for staging vs production:

{
  "ConnectionStrings": {
    "umbracoDbDSN": "Server=mycu-sql.database.windows.net;Database=mycu_cms_staging;..."
  }
}

Set the ASPNETCORE_ENVIRONMENT environment variable to mycu to activate this file.

4.3 uSync configuration

uSync is pre-configured to import schema on startup. The uSync files from the baseline packages define all content types, data types, templates, and media types. On first run, uSync will create the full Umbraco schema automatically:

{
  "uSync": {
    "Settings": {
      "ImportAtStartup": true,
      "ExportAtStartup": false,
      "ExportOnSave": true
    }
  }
}

Step 5: Build and Test Locally

5.1 Restore and build

cd MyCreditUnion
dotnet restore src/MyCreditUnion/MyCreditUnion.csproj
dotnet build src/MyCreditUnion/MyCreditUnion.csproj

5.2 Run locally

dotnet run --project src/MyCreditUnion/MyCreditUnion.csproj

The site starts at http://localhost:5000. On first run:

  1. Umbraco performs an unattended install (creates the database schema and admin user).
  2. uSync imports all content types, data types, and templates from the baseline packages.
  3. The site is ready with an empty content tree.

Navigate to http://localhost:5000/umbraco and log in with the admin credentials you specified.

5.3 Verify the setup

  • Backoffice loads without errors
  • All content types are present (check Settings > Document Types)
  • All data types are present (check Settings > Data Types)
  • All templates are present (check Settings > Templates)
  • The theme CSS is loading (inspect page source for cssCreditUnion/theme.css)
  • The client logo appears (if added)

Step 6: Create the Docker Image

6.1 Build the image

From the project root (where the Dockerfile is):

docker build -t mycu:latest .

The Dockerfile uses a multi-stage build:

  1. Build stage (mcr.microsoft.com/dotnet/sdk:10.0): restores packages from the private NuGet feed, compiles, and publishes.
  2. Runtime stage (mcr.microsoft.com/dotnet/aspnet:10.0): runs the published app.

6.2 Test the image locally

docker run -d -p 8080:8080 \
  -e "ConnectionStrings__umbracoDbDSN=Server=host.docker.internal,1433;Database=mycu_cms;User Id=sa;Password=YourStrongPassword123!;TrustServerCertificate=True;MultipleActiveResultSets=true;" \
  -e "ASPNETCORE_ENVIRONMENT=Production" \
  --name mycu \
  mycu:latest

Visit http://localhost:8080 to verify it works.

6.3 Push to Azure Container Registry

# Create ACR (first time only)
az acr create --name mycu --resource-group rg-mycu --sku Basic --admin-enabled true

# Log in to ACR
az acr login --name mycu

# Tag and push
docker tag mycu:latest mycu.azurecr.io/mycu:latest
docker push mycu.azurecr.io/mycu:latest

Step 7: Deploy to Azure

7.1 Create an App Service Plan

az appservice plan create \
  --name asp-mycu \
  --resource-group rg-mycu \
  --is-linux \
  --sku B2

B2 is a good starting tier. Scale up to S1/P1v3 if needed for production traffic.

7.2 Create the Web App for Containers

# Get ACR credentials
ACR_PASSWORD=$(az acr credential show --name mycu --query "passwords[0].value" -o tsv)

# Create Web App
az webapp create \
  --name mycu-web \
  --resource-group rg-mycu \
  --plan asp-mycu \
  --container-image-name mycu.azurecr.io/mycu:latest \
  --container-registry-url https://mycu.azurecr.io \
  --container-registry-user mycu \
  --container-registry-password "$ACR_PASSWORD"

7.3 Configure environment variables

az webapp config appsettings set \
  --name mycu-web \
  --resource-group rg-mycu \
  --settings \
    ConnectionStrings__umbracoDbDSN="Server=mycu-sql.database.windows.net;Database=mycu_cms;User Id=mycu_admin;Password=YourStrongPassword123!;TrustServerCertificate=True;MultipleActiveResultSets=true;" \
    ASPNETCORE_ENVIRONMENT="Production" \
    Umbraco__CMS__WebRouting__UmbracoApplicationUrl="https://mycu.ie/" \
    Umbraco__CMS__Global__UseHttps="true" \
    WEBSITES_PORT="8080"

7.4 Enable persistent storage (for media uploads)

az webapp config appsettings set \
  --name mycu-web \
  --resource-group rg-mycu \
  --settings WEBSITES_ENABLE_APP_SERVICE_STORAGE="true"

For production, consider using Azure Blob Storage for media instead of local disk. This avoids data loss on container restarts and supports horizontal scaling.

7.5 Enable continuous deployment from ACR

az webapp deployment container config \
  --name mycu-web \
  --resource-group rg-mycu \
  --enable-cd true

This creates a webhook in ACR so that pushing a new image automatically triggers a redeployment.


Step 8: Configure Custom Domain and SSL

8.1 Add DNS records

At your DNS provider, create:

Type Name Value
A mycu.ie (App Service IP from Azure portal)
CNAME www.mycu.ie mycu-web.azurewebsites.net
TXT asuid.mycu.ie (verification ID from Azure portal)

Get the verification ID:

az webapp show --name mycu-web --resource-group rg-mycu --query "customDomainVerificationId" -o tsv

8.2 Add the custom domain to the Web App

az webapp config hostname add \
  --webapp-name mycu-web \
  --resource-group rg-mycu \
  --hostname mycu.ie

az webapp config hostname add \
  --webapp-name mycu-web \
  --resource-group rg-mycu \
  --hostname www.mycu.ie

8.3 Enable free managed SSL certificate

az webapp config ssl create \
  --name mycu-web \
  --resource-group rg-mycu \
  --hostname mycu.ie

az webapp config ssl bind \
  --name mycu-web \
  --resource-group rg-mycu \
  --certificate-thumbprint <THUMBPRINT_FROM_PREVIOUS_COMMAND> \
  --ssl-type SNI

Repeat for www.mycu.ie.

8.4 Enforce HTTPS

az webapp update \
  --name mycu-web \
  --resource-group rg-mycu \
  --https-only true

Step 9: Umbraco First-Run Setup

On the first request to the deployed site, Umbraco performs an unattended install:

  1. Creates the database schema (all tables, indexes, constraints).
  2. Creates the admin user with the email and password from appsettings.json > Umbraco:CMS:Unattended.
  3. uSync imports all content types, data types, templates, and other schema from the baseline RCL packages.

This process takes 1-3 minutes. Monitor the logs:

az webapp log tail --name mycu-web --resource-group rg-mycu

After completion, access the backoffice at https://mycu.ie/umbraco and log in with:

  • Email: admin@mycu.ie
  • Password: The password you specified in AdminPassword

Post-install: disable unattended install

After the first successful run, update the app settings to disable unattended install so it does not re-run:

az webapp config appsettings set \
  --name mycu-web \
  --resource-group rg-mycu \
  --settings Umbraco__CMS__Unattended__InstallUnattended="false"

Step 10: Content Setup in the Backoffice

With the schema imported via uSync and the admin user created, set up the site content.

10.1 Website Configuration node

  1. In the Content tree, create a node of type Website Configuration at the root.
  2. Fill in the required fields:
  3. Credit Union Name: My Credit Union
  4. Phone Number: +353 1 234 5678
  5. Email: info@mycu.ie
  6. Address: 123 Main Street, Wexford, Ireland
  7. Social Media Links: Facebook, Twitter/X, LinkedIn URLs
  8. Google Maps API Key: Your API key
  9. Online Banking URL: Link to the online banking portal
  10. Mobile Banking URLs: App Store and Google Play links

10.2 Home page

  1. Create a Home node at the content root.
  2. Set it as the site root (right-click > Culture and Hostnames > add mycu.ie).
  3. Add hero banner content, featured sections, and call-to-action blocks using the BlockGrid editor.

10.3 Navigation menus

  1. Install and configure UmbNav for the main navigation.
  2. In the Content tree, the Website Configuration node should have a Navigation tab with UmbNav fields for:
  3. Main Menu: Top-level navigation links
  4. Footer Menu: Footer link columns
  5. Utility Menu: Top bar quick links (login, contact, etc.)

10.4 Standard pages

Create the standard credit union pages. Each uses BlockGrid for flexible content layout:

Page Document Type Notes
About Us Content Page History, team, values
Loans Landing Page Loan products with calculators
Savings Landing Page Savings account types
Contact Us Contact Page Contact form + map
News News Listing Blog/news section
Privacy Policy Content Page Legal content
Terms & Conditions Content Page Legal content

10.5 Media library

Upload the client's media assets:

  1. Logo variants (color, white, favicon)
  2. Hero images for the home page and landing pages
  3. Staff photos if applicable
  4. Document PDFs (rates, forms, terms)

Organize media into folders: Images/, Documents/, Logos/.

10.6 Forms (Umbraco Forms)

Create any required forms:

  • Contact form
  • Loan enquiry form
  • Membership application form
  • Newsletter signup

Configure form notification emails to go to the appropriate client email addresses.

10.7 Final checks

  • Home page renders correctly with the client theme
  • All navigation menus work
  • Contact form submits and sends notification emails
  • All images and media load correctly
  • Mobile responsive layout works
  • SSL certificate is valid and HTTPS is enforced
  • Backoffice is accessible and functional
  • Google Maps loads on the contact page (API key configured)

Appendix: Ongoing Maintenance

Updating baseline packages

When a new version of Progress.Baseline.Core or Progress.Baseline.Web is published:

cd src/MyCreditUnion
dotnet restore
dotnet build

The Version="1.*" wildcard in the .csproj automatically picks up the latest 1.x release. For major version bumps, update the version constraint manually.

Always review git diffs after upgrading

The dotnet build step copies updated baseline views into your Views/ folder, overwriting existing files. You must run git diff -- Views/ after each upgrade to check if any of your customizations were overwritten. Use git checkout -p or a merge tool to reconcile changes.

# After upgrading and building, always check what changed
git diff -- Views/

Customizing views

After dotnet build, all 301 baseline views are physically present in your Views/ folder. To customize a view:

  1. Edit the view directly in your Views/ folder (e.g., Views/Partials/SiteLayout/_Footer.cshtml)
  2. Commit your changes to git
  3. After each NuGet upgrade + build, run git diff -- Views/ and merge any conflicts

Rebuilding and redeploying

# Build new Docker image
docker build -t mycu.azurecr.io/mycu:latest .

# Push to ACR (triggers automatic redeployment if CD is enabled)
docker push mycu.azurecr.io/mycu:latest

Scaling

For high-traffic periods, scale the App Service Plan:

az appservice plan update \
  --name asp-mycu \
  --resource-group rg-mycu \
  --sku P1v3

If running multiple client sites, they can share an App Service Plan to reduce costs. Each client gets its own Web App, ACR image, and SQL database.

Migration documentation by Double for Progress Credit Union