Skip to content
StarLive demo →
GuideChecked against main · 31 Oct 20269 min read

What to change first

A checklist for a new project built from the AppointMe .NET template. Names, branding, committed dev secrets, demo mode, the Keycloak realm, unused modules, licenses, CI and Azure defaults.

You'll end with
A project that carries your name
When
Before your first deploy
Touches
Config, realm, SPA, infra/, .github/
Before you start
A running stack from the Quick start

This page assumes you generated the project with dotnet new appointme -n Contoso.Booking. If you cloned the repo instead, nothing has been renamed yet: start with Rename your project. Paths below use the upstream AppointMe names; in your project they carry yours.

Names: what -n changed and what it didn’t

Section titled “Names: what -n changed and what it didn’t”

dotnet new -n renames every brand token it can match without touching the domain word “appointment”. Three build properties still name BravoDev.

Item After -n Contoso.Booking
Namespaces, projects, folders, the solution Contoso.Booking.Api, src/Contoso.Booking.Aspire, Contoso.Booking.sln
The database Contoso.Booking
The Keycloak realm and its file contoso.booking, in contoso.booking-realm.json
The Compose project, containers and Aspire resources contoso-booking, contoso-booking-sql, contoso-booking-api
The demo account demo@contoso.booking.dev, password ContosoBooking1
Domain words Unchanged: Appointment, /appointments, appointments.statistics:view
What Where Why How
Company, Authors, RepositoryUrl Directory.Build.props They’re still BravoDev and github.com/bravodev-hub/..., and every assembly you build embeds them Set your company, authors and repository URL
The product name in the browser tab src/AppointMe.Frontend/index.html, <title> -n put your dotted name there, for example Contoso.Booking Write the name users should see
Directory.Build.propsView source ↗
<Company>BravoDev</Company>
<Authors>BravoDev</Authors>
<RepositoryUrl>https://github.com/bravodev-hub/appointme.git</RepositoryUrl>

templates/README.md in the upstream repo documents the rename rules token by token.

The SPA’s logo, wordmark and colors live in a handful of files. The wordmark is split across a <span>, so -n didn’t touch it.

What Where Why How
Wordmark Appoint<span className='font-semibold'>Me</span> in src/app/layouts/sidebar/app-sidebar.tsx, src/app/layouts/footer/footer.tsx, src/app/auth/signup/signup.tsx, src/app/onboarding/onboarding.tsx and src/app/invitations/invitations.tsx It still reads “AppointMe” on every screen Replace it in all five files, or move it into one component first
Sidebar logo src/app/layouts/sidebar/app-logo.tsx AppLogo is an inline SVG of the AppointMe mark Swap the path, or render your own SVG
Favicon src/assets/logo.svg, linked from index.html The same mark, as a file Replace the SVG
Colors src/index.css, the :root and .dark blocks The palette is neutral grays (--primary: oklch(0.205 0 0)) Change the tokens. The @theme inline block maps them to Tailwind colors.
Footer version src/app/layouts/footer/version.ts Shows VITE_APP_VERSION, which the Docker build sets, or dev locally Nothing to change, unless you version differently

Paths in this table are relative to src/AppointMe.Frontend/. Frontend overview covers the rest of the SPA.

Every local credential is committed on purpose and predictable in every project made from the template. Never reuse one outside your machine, and decide where demo mode stays on.

Secret Where Value
SQL Server sa password src/AppointMe.Aspire/Program.cs (sqlPassword), compose.yaml (MSSQL_SA_PASSWORD), appsettings.Development.json (connection string) Password1
Keycloak admin Program.cs (username, password), compose.yaml (KC_BOOTSTRAP_ADMIN_*) admin / admin
appointme-api client secret appointme-realm.json, and KeycloakAdmin:ClientSecret in appsettings.Development.json A fixed 32-character string
appointme-frontend client secret Authentication:Keycloak:FrontendClientSecret in appsettings.Development.json A fixed 32-character string
Demo user appointme-realm.json, and Demo:User in appsettings.Development.json demo@appointme.dev / AppointMe1, renamed by -n as above

These only protect containers on your machine. Deployed environments read their secrets from Azure Key Vault, so never copy one of these values into a deployed environment’s settings. If you rotate them, change every place in the row together, and see the gitleaks note under CI.

What Where Why How
Demo:Enabled true in appsettings.Development.json, false in appsettings.json, true in appsettings.Devtest.example.json It turns on the demo login, demo data for every new company, and two daily top-up jobs at 03:00 UTC Keep it for local work. Set it to false in any environment real customers use.
Demo seeding src/AppointMe.Api/Demo/DemoSeedingSaga.cs Every company registered while demo mode is on gets 150 fake customers and about 450 appointments Turn demo mode off, or delete the saga and the SeedDemo* and TopUpDemo* slices
Super admins Authentication:SuperAdmins The demo user is a super admin in Development, which opens /admin/jobs List your own operator emails per environment
Dashboard revenue src/AppointMe.Frontend/src/app/dashboard/dummy-revenue.ts There’s no payments domain, so revenue is fake data derived from appointment counts Replace it with a real endpoint, or hide the revenue widgets

The demo gate is the first thing the saga checks:

src/AppointMe.Api/Demo/DemoSeedingSaga.csView source ↗
public static DemoSeedingSaga? Start(CompanyRegistered @event, IConfiguration configuration)
{
if (!configuration.GetValue<bool>("Demo:Enabled"))
{
return null;
}
return new DemoSeedingSaga
{
Id = @event.CompanyId,
CustomersExpected = CustomerCount,
};
}

Keycloak runs only on your machine, from one committed realm file. Two of its settings point at BravoDev or the template’s ports.

What Where Why How
Google sign-in identityProviders in appointme-realm.json It carries BravoDev’s Google OAuth client ID and an empty secret, and “Continue with Google” on the sign-up form uses it Put in your own Google client ID and secret, or remove the provider and the button in src/components/signup/signup-form.tsx
Redirect URIs The appointme-frontend and appointme-api clients They allow only https://localhost:5173 and https://localhost:7233 Update them if you move the dev ports
Email sender smtpServer Mail goes from noreply@appointme.local to the Mailpit host on port 1025 Change the display name if you like. Keep the host for local work.
Login page look The realm sets no loginTheme Users see Keycloak’s default theme locally Add a theme only if local branding matters to you

Keycloak imports the realm only when it doesn’t exist yet, and its container keeps a data volume. To apply an edit, remove the Keycloak container and its volume, then start the stack again; this also deletes the local users you signed up. Deployed environments use Entra External ID instead: see Entra External ID.

Delete the modules you won’t use while the project is young, and keep BravoDev’s copyright line in LICENSE.

What Where Why How
Unused modules src/<Module>/, the Add<Module>Module() call in Program.cs, the API’s project references, the SPA’s pages Each one adds tables, endpoints and permissions Follow Remove a module
LICENSE Repo root It reads Copyright (c) 2026 BravoDev. The MIT license requires every copy to keep that notice. Keep it. Add your own copyright line next to it if you want one.
THIRD-PARTY-NOTICES.md Repo root A curated list of dependency licenses. Hangfire is LGPL-3.0 (or commercial). Using the unmodified NuGet package is fine. Modifying Hangfire’s own source triggers the LGPL obligations.
Full license report The commands at the end of THIRD-PARTY-NOTICES.md The file isn’t an exhaustive transitive list Generate one with dotnet-project-licenses and license-checker-rseidelsohn before you ship a binary or image

The workflows run as soon as you push to GitHub. The Bicep is sized for a demo environment, not production.

What Where Why How
Deploy job .github/workflows/devtest.yml Build and test run on every push to main, every v* tag and every PR. The deploy job runs on v* tags (or a manual run) and needs six secrets (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID, AZURE_RESOURCE_GROUP, ACR_NAME, APP_SERVICE_NAME). Set them as in GitHub Actions CI/CD, or delete the job until you need it
Secret scanning .github/workflows/secret-scan.yml, .gitleaks.toml gitleaks scans the full history on every PR and push to main. The allowlist matches the committed dev values by value. If you commit rotated dev values, add them to the allowlist. Better, keep real values out of Git.
Code scanning .github/workflows/codeql.yml CodeQL for C# and TypeScript on push, PR and every Monday Keep it. The workflow notes it’s free for public repos.
Dependabot .github/dependabot.yml Weekly NuGet, npm and Actions PRs. It skips Vite+ and container images. Bump Vite+ and the images in Program.cs and compose.yaml by hand
Template workflow .github/workflows/template.yml Only in a clone: it publishes BravoDev’s package on v* tags. Generated projects don’t get it. Delete it in a clone
Plan and database size infra/modules/app-service-plan.bicep (F1), infra/modules/sql.bicep (Basic) F1 unloads the app after about 20 idle minutes and has a daily CPU quota Move to B1 or higher before real traffic
Environment and admin login infra/main.bicepparam environmentName = 'devtest', SQL admin appointme_admin Set yours. The password comes from SQL_ADMIN_PASSWORD.
Cloudflare Worker route infra/cloudflare-worker/wrangler.jsonc Its routes and zone_name point at a domain derived from your project name Set your domain, or delete the folder if you don’t front the app with Cloudflare

infra/README.md ends with a prod-hardening checklist (private endpoints, WAF, Key Vault purge protection and more). Production checklist walks through it.

After the changes, the BravoDev name should survive only where it must, and the build, tests and frontend check should still pass.

Terminal window
git grep -n -i "bravodev"
git grep -n "Appoint<span"
dotnet build AppointMe.sln
dotnet test AppointMe.sln
cd src/AppointMe.Frontend && npm ci && npm run check

Once your generated project is in Git, bravodev should match only LICENSE and the generated README.md, and the wordmark search should find nothing.

Symptom Cause Fix
Login fails after you rotated a Keycloak client secret The realm and appsettings.Development.json disagree Use the same value in both, then recreate the Keycloak container and volume
Realm edits don’t show up The realm already exists in Keycloak’s data volume, so the import is skipped Remove the Keycloak container and its volume
secret-scan fails after you rotated dev values gitleaks no longer recognizes them as allowlisted Add the new values to .gitleaks.toml, or keep them out of Git
“Continue with Google” fails The realm’s Google provider has no client secret Configure your own Google client, or remove the provider and the button
Why commit dev secrets at all?1 min · optional

Committed values let the whole stack start with no setup: Aspire, Compose, the API and the realm all agree on the same passwords from the first dotnet run. They protect nothing but containers on your own machine.

The risk is reuse. That’s why deployed environments read Key Vault, why the realm runs only locally, and why gitleaks allowlists these exact values by value rather than by file, so a real secret added to the same files still fails the scan.