Local dev now runs on .NET Aspire.
aspire run(from the repo root) brings up SQL Server + Azurite + WebAPI + AdminUI with one command (replacingup.ps1+docker compose). See the full guide: Aspire-Local-Dev.md. This page covers the end-to-end setup, including mobile and iOS signing.
NOTE:
%%──────────────────────────────────────────────────────────
%% SSW-red on charcoal – same layout as your first diagram
%%──────────────────────────────────────────────────────────
%%{ init: {
"theme":"base",
"darkMode":true, /* custom colours win */
"themeVariables":{
"fontSize":"15px",
"fontFamily":"Inter, Segoe UI, sans-serif",
/* red accents */
"lineColor":"#d50000",
"arrowheadColor":"#d50000",
"clusterBorder":"#d50000",
/* link label colour (edge text) */
"tertiaryTextColor":"#cccccc"
},
"themeCSS":".node rect, .node polygon, .cluster rect { filter:none !important; }",
"flowchart":{ "curve":"basis" }
}%%
flowchart LR
%%──────────────────── Local ────────────────────
subgraph Local["🧑💻 Local"]
direction TB
MobileApp["📱 Mobile App<br/>(.NET MAUI)"]
DevTunnel[/"🌐 Tailscale<br/>(stable URL, trusted cert)"/]
AdminUI["🖥️ Admin UI<br/>(Blazor)"]
WebAPI{{"⚡ WebAPI<br/>(ASP.NET Core)"}}
MobileApp -- HTTPS --> DevTunnel
DevTunnel -- HTTPS --> WebAPI
AdminUI -- HTTPS --> WebAPI
end
%%──────────────────── Docker ───────────────────
subgraph Docker["🐳 Docker (via .NET Aspire)"]
direction TB
SQLServer[("🗄️ SQL Server")]
Azurite[("🪣 Azurite Blob Storage")]
WebAPI -- SQL --> SQLServer
WebAPI -- "Blob API" --> Azurite
end
%%────────────────── External ───────────────────
subgraph External["🌐 External"]
direction TB
SSWIdentity["🔐 SSW.Identity<br/>(can run local)"]
SSWQuizGPT["🧠 SSW.QuizGPT<br/>(can run local)"]
NotificationHub["🔔 AWS Notification Hub"]
WebAPI -- HTTPS --> SSWQuizGPT
WebAPI -- HTTPS --> SSWIdentity
AdminUI -- HTTPS --> SSWIdentity
MobileApp -- HTTPS --> WebAPI
MobileApp -- HTTPS --> SSWIdentity
WebAPI -- Notifications --> NotificationHub
NotificationHub -- Push --> MobileApp
end
%%────────────────── Styling ────────────────────
classDef clusterStyle stroke-width:2,rx:6,ry:6;
classDef service fill:#1e1e1e,stroke:#d50000,stroke-width:1,color:#ffffff;
class Local,Docker,External clusterStyle;
class MobileApp,DevTunnel,AdminUI,WebAPI,SQLServer,Azurite,SSWIdentity,SSWQuizGPT,NotificationHub service;
TODO Find Azurite seed data for the API (Tylah might be blind)
-
.NET 10 SDK https://dotnet.microsoft.com/en-us/download/dotnet/10.0 (
global.jsonpins10.0.301) -
Aspire CLI ≥ 13.4.6:
dotnet tool install -g aspire(ordotnet tool update -g aspire) -
Docker Desktop — Aspire runs SQL + Azurite as containers
-
IDE - Visual Studio Enterprise Latest // Jetbrains Rider // VS Code
-
Android SDK (for the mobile app) + MAUI workloads:
dotnet workload install maui(ormaui-android; needssudoon a system-wide .NET install) -
Optional: Azure Data Studio (Not required, can use IDE Tools for DB Querying)
-
Optional: Azure Storage Explorer (Easy way to upload and download files)
-
For testing the mobile app on a phone, use Tailscale for a stable, iOS-trusted URL (see the Mobile UI section below) — it replaces Dev Tunnels / ngrok.
- XCode v15.0.1+
- Check or set
Command Line Toolslocation - Preferences | Locations | Command Line Tools
- Check or set
-
Clone this Repo https://github.com/SSWConsulting/SSW.Rewards.Mobile.git
-
Download and install latest .NET 10 SDK
-
Trust the local dev HTTPS certificate (one-time):
dotnet dev-certs https --trust
(Also available later as the Tools: Trust dev HTTPS cert dashboard command. If you get "A valid HTTPS certificate is already present", run
dotnet dev-certs https --cleanfirst.)Before the first run, put the secrets in place — Keeper is the only external resource. Every stack secret lives in one store (the AppHost user-secrets); copy the single
SSW.Rewards ▸ SSW.Rewards — Aspire Dev SecretsKeeper record, then:./rewards-dev secrets edit # opens secrets.json — paste the Keeper record, save ./rewards-dev secrets check # ✓/✗ per key; tells you what's missing + where in Keeper
-
Start the local stack with Aspire (Docker must be running):
aspire run # from the repo root (.aspire/settings.json targets src/AppHost)WebAPI/AdminUIno longer carry their own secrets — everything is injected from the AppHost. If a secret is missing, Aspire reports ValueMissing and SQL won't start; run./rewards-dev secrets edit, paste, and re-run.
The dashboard opens automatically. SQL Server + Azurite come up as persistent containers, then WebAPI + AdminUI start once SQL is healthy (EF migrations apply on WebAPI startup):
- AdminUI → https://localhost:7137
- WebAPI Swagger → https://localhost:5001/swagger/index.html
Full guide, dashboard commands, and the
rewards-devtarget switcher: Aspire-Local-Dev.md.
- Check manage-database skill if you want to restore an existing DB.
TODO: Current seeding might not fully work for development. Tech-Debt - #540
Currently, we need to restore the DB like for instance from staging or another developer. Follow the manage-database skill (.agents/skills/manage-database/SKILL.md) for backup and restore instructions.
Follow Microsoft Learn’s step-by-step guide to get your first .NET MAUI project up and running. It lets you run Mobile UI without issues. https://learn.microsoft.com/en-us/dotnet/maui/get-started/first-app?view=net-maui-8.0&tabs=vsmac&pivots=devices-android
Don't hand-edit
Constants.cs. The DEBUG API/identity URLs come from a git-ignored override written by therewards-devCLI. See Aspire-Local-Dev.md for the full flow.
-
Install the MAUI workload (one-time):
dotnet workload install maui(ormaui-android). -
Make sure the Firebase config files exist (git-ignored): copy
google-services.json/GoogleService-Info.plistfrom Keeper intosrc/MobileUI/Platforms/{Android,iOS}/, or use the Mobile: Sync mobile secrets (isolated) dashboard command. Only*.templateplaceholders are committed. -
Point the app at a backend (emulators can't reach
localhost, so usestagingortailscale):dotnet run --project tools/RewardsDev -- env staging # or: api tailscale + identity staging -
Build and deploy to a running emulator:
dotnet build src/MobileUI/MobileUI.csproj -t:Run -f net10.0-android -c Debug
(
-t:Runis required for Debug builds — a plainadb installof the APK won't start due to Fast Deployment.)
tailscale serve --bg https / https+insecure://localhost:5001 # iOS-trusted HTTPS to the local API
dotnet run --project tools/RewardsDev -- api tailscale # auto-detects your *.ts.net URL- Complete the steps above, then target an iOS simulator/device (requires the
maui-iosworkload).
NOTE: if you cannot build and see an error relating to the provisioning profile/ app signing identity
NOTE: if the solution fails to load, open a terminal in the SSW.Rewards.Mobile folder and run:
dotnet workload update
dotnet workload restore- Open up the iOS project settings by right clicking on SSW.Consulting.iOS and selecting Options.
- go to 'iOS Bundle Signing' and select your signing identity and provisioning profile.
- These should be automatic by default but if you get an error you can manually set them.
- If you don't have these, talk to another Team Member or Sys Admin and get them to add your AppleID to the Superior Software for Windows Pty Ltd Apple Developer Program Team
If you want to set up to deploy to your own iPhone, talk to an App Manager, it's hard! :) Or you can give it a go yourself. For that you will be using 2 portals - App Store Connect and Apple Developer Portal:
- Talk to a team member who has either Admin or App Manager role in App Store Connect. Give them your Apple ID (you can provide your personal one) and they will send you an invite to the Apple Developer team. If you've never used Apple products before, you will need to create an Apple ID. You need to be granted at least the App Manager role to be able to perform some of the steps below; otherwise ask someone with the App Manager Role or higher to assist you.
- On your mac create a Certificate Signing Request (CSR) using Keychain. Go to Keychain Access -> Certificate Assistant -> Request a certificate from a certificate authority. Fill the fields and save generated CSR somewhere.
- Go to https://developer.apple.com, scroll down and click "Certificates, IDs, & Profiles".
- Select the Certificates tab. Add a new Certificate of type
Apple Development. For that you will need to upload the CSR. Once the certificate is created, the CSR is no longer needed and can be deleted. - Download the certificate on your mac and double click it to install.
- Go back to the developer portal and select the Devices tab.
- Add a device you are gonna be using for testing. To get your device's UDID connect it to your mac and open the Music app. Select your device on the left and then click a couple of times on the subtitle which displays your iPhone model, storage and battery level.
- Once your device is added to the developer portal, select the Profiles tab. Update the provisioning profile for iOS App Development
SSWRewards_Dev. Select the certificate and device added on the previous steps. Tip: Any changes to the provisioning profile won't disrupt the work of your team. - Download the provisioning profile on your mac and double click to install it. Tip: provisioning profiles are installed to ~/Library/MobileDevice/Provisioning Profiles/
After that you should be able to deploy and debug the application on your iPhone.
Currently we have GitHub Actions which build and push the application to InternalTesting and TestFlight. But sometimes it's required to build and sign the application locally. Below is a detailed description how to do that.
Apple expects developers to have individual development certificates (up to 2 per developer) and share distribution certificates (up to 3 per team). To be able to build and sign an ipa file you need to have a distribution certificate and provisioning profile associated with it installed on your machine. All the secrets can be found in our password manager (PM).
- Get distribution certificate as a base-64 string from PM and run:
echo <cert-base64-string> | base64 --decode > DistributionCertificate.p12 - Double click the certificate to install it; use the password from PM
- Download distribution provisioning profile form the Apple Developer Portal
- Double click the provisioning profile to install it
- Cd into the MobileUI folder
- Run
dotnet publish -f net10.0-ios -p:ArchiveOnBuild=true -p:CodesignKey="XXX" -p:CodesignProvision="YYY"; XXX is the CertificateName (in PM) and YYY is ProfileName (same as in Apple Developer Portal) - The ipa file in the ../MobileUI/bin/Release/net10.0-ios/ios-arm64/publish/ folder is ready to be uploaded to TestFlight
- Find keystore info in PM
- Run
echo <keystore-base64-string> | base64 --decode > rewards.keystore - To see the info about keystore run
keytool -list -v -keystore rewards.keystore - Run
dotnet publish -f net10.0-android -p:AndroidKeyStore=true -p:AndroidSigningKeyStore=rewards.keystore -p:AndroidSigningKeyAlias=XXX -p:AndroidSigningKeyPass=YYY -p:AndroidSigningStorePass=YYY; XXX and YYY can be found in PM - The signed aab file in the ../MobileUI/bin/Release/net10.0-android/publish/ folder is ready to be uploaded to InternalTesting
Now you are setup, lets get started on a PBI
Be sure to read the Definition of done and the Definition of ready