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)¶
Verify installation:
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¶
Option A: Azure SQL Database (recommended for production)¶
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.
Adding a client logo¶
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¶
The site starts at http://localhost:5000. On first run:
- Umbraco performs an unattended install (creates the database schema and admin user).
- uSync imports all content types, data types, and templates from the baseline packages.
- 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):
The Dockerfile uses a multi-stage build:
- Build stage (
mcr.microsoft.com/dotnet/sdk:10.0): restores packages from the private NuGet feed, compiles, and publishes. - 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¶
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:
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¶
Step 9: Umbraco First-Run Setup¶
On the first request to the deployed site, Umbraco performs an unattended install:
- Creates the database schema (all tables, indexes, constraints).
- Creates the admin user with the email and password from
appsettings.json>Umbraco:CMS:Unattended. - 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:
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¶
- In the Content tree, create a node of type Website Configuration at the root.
- Fill in the required fields:
- Credit Union Name: My Credit Union
- Phone Number: +353 1 234 5678
- Email: info@mycu.ie
- Address: 123 Main Street, Wexford, Ireland
- Social Media Links: Facebook, Twitter/X, LinkedIn URLs
- Google Maps API Key: Your API key
- Online Banking URL: Link to the online banking portal
- Mobile Banking URLs: App Store and Google Play links
10.2 Home page¶
- Create a Home node at the content root.
- Set it as the site root (right-click > Culture and Hostnames > add
mycu.ie). - Add hero banner content, featured sections, and call-to-action blocks using the BlockGrid editor.
10.3 Navigation menus¶
- Install and configure UmbNav for the main navigation.
- In the Content tree, the Website Configuration node should have a Navigation tab with UmbNav fields for:
- Main Menu: Top-level navigation links
- Footer Menu: Footer link columns
- 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:
- Logo variants (color, white, favicon)
- Hero images for the home page and landing pages
- Staff photos if applicable
- 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:
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.
Customizing views¶
After dotnet build, all 301 baseline views are physically present in your Views/ folder. To customize a view:
- Edit the view directly in your
Views/folder (e.g.,Views/Partials/SiteLayout/_Footer.cshtml) - Commit your changes to git
- 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:
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.