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

Rename your project

One dotnet new command renames the .NET 10 solution, namespaces, database, Keycloak realm and Aspire resources to your name, and leaves the Appointment domain untouched.

You'll get
A renamed copy that builds and passes tests
Time
A few minutes
Touches
Every project, plus config and infra names
Before you start
.NET 10 SDK; Docker and Node to run

Install the template, run dotnet new appointme -n <Name>, and commit the output before you change anything.

  1. Install the template. Pin the version so you can generate the same output again later.

    Terminal window
    dotnet new install BravoDev.AppointMe.Templates::1.2.1
  2. Generate. -n is the only option the template takes. The output goes into a new Contoso.Booking/ folder. Pass -o <dir> to put it somewhere else.

    Terminal window
    dotnet new appointme -n Contoso.Booking
  3. Commit the untouched output. The template doesn’t create a git repository, and nothing in the generated files records which version made them. Commit right away and put the version in the message, because taking updates later starts from this commit.

    Terminal window
    cd Contoso.Booking
    git init
    git add -A
    git commit -m "Generate from BravoDev.AppointMe.Templates 1.2.1"
  4. Build and test. Both pass on a fresh copy, with no code changes.

    Terminal window
    dotnet build Contoso.Booking.sln
    dotnet test Contoso.Booking.sln
  5. Run it. Trust the dev certificate once per machine, then start the Aspire host. The quick start covers what comes up and where.

    Terminal window
    dotnet dev-certs https --trust
    cd src/Contoso.Booking.Aspire && dotnet run

Every brand token becomes your name, in whichever form the place it sits in allows.

What In AppointMe With -n Contoso.Booking Form
Namespaces, projects, folders, solution AppointMe.Crm, AppointMe.sln Contoso.Booking.Crm, Contoso.Booking.sln As typed
SQL database Database=AppointMe Database=Contoso.Booking As typed
Connection string name AppointMeSql ContosoBookingSql Separators removed
Keycloak realm and its file appointme, appointme-realm.json contoso.booking, contoso.booking-realm.json Lowercase
Cookies and the demo login appointme.auth, demo@appointme.dev contoso.booking.auth, demo@contoso.booking.dev Lowercase
Aspire resources, Compose containers appointme-sql, appointme-api contoso-booking-sql, contoso-booking-api Kebab-case
Aspire project type in Program.cs AppointMe_Api Contoso_Booking_Api Underscores
Azure names in infra/main.bicep acrappointme…, stappointme… acrcontosobooking…, stcontosobooking… Lowercase letters and digits

Each form exists because the target rejects the others. Aspire resource names can’t contain dots or underscores (its ASPIRE006 check), C# identifiers can’t contain dots, and Azure registry and storage account names allow only lowercase letters and digits.

The template picks the form from the character that follows each match. This symbol handles the dotted form, and it fires only before one of nine characters:

.template.config/template.jsonView source ↗
"identityBucket": {
"type": "derived",
"valueSource": "name",
"valueTransform": "identity",
"replaces": "AppointMe",
"fileRename": "AppointMe",
"onlyIf": [
{ "before": "." }, { "before": " " }, { "before": "\"" }, { "before": "'" },
{ "before": "\n" }, { "before": "\r" }, { "before": ";" }, { "before": "-" }, { "before": "<" }
]
},

templates/README.md in the upstream repo lists every symbol and why it exists. If you add an identifier that contains AppointMe and the character after it isn’t on any list (AddAppointMeBilling is followed by B), the template won’t rename it.

The lowercase brand token appointme is the first nine letters of appointment. A plain find-and-replace would also rewrite the Appointment aggregate, the /appointments route and the appointments.statistics:view permission.

So the template never matches the lowercase token on its own. It matches guarded forms such as appointme-, appointme. and appointme", and appointmen… matches none of them. The PascalCase AppointMe can’t collide, because Appointment has a lowercase m.

Left as it is Why
Appointment, /appointments, appointments.statistics:view Domain vocabulary, not the brand. CI’s template smoke test counts every Appointment before and after the rename.
Module names Identity, Organizations, Crm, Booking They aren’t brand tokens, so -n Contoso.Booking gives you Contoso.Booking.Booking.
Company and Authors in Directory.Build.props Still BravoDev. Only the repository name inside RepositoryUrl changes.
LICENSE MIT requires you to keep BravoDev’s copyright notice. Add your own line next to it.
Password1 and the Keycloak client secrets in appsettings.Development.json Every generated project starts with the same local values.

Fix the metadata and placeholders before you deploy: What to change first has the list.

Why is the name the only option?1 min · optional

The modules are wired together through events. Booking builds its own copies of CRM customers and of Organizations companies and employees from their domain events, so a switch that dropped a module would generate code that doesn’t compile.

With one parameter there’s one combination to test. .github/workflows/template.yml runs templates/smoke-test.sh on every pull request: it packs the template, generates Contoso.Booking, builds and tests it, lints its frontend and checks that no brand token is left. To drop a module, generate first and then follow Remove a module.

Use a valid C# namespace such as Contoso.Booking. dotnet new accepts any name, so a bad one only shows up when you build.

Name What happens
Contoso.Booking Builds. The documented form: company, then product.
Contoso Builds. A single segment is a valid namespace too.
my-booking-app dotnet new reports success. The build then fails with hundreds of CS1022 and CS0116 errors, because the code now says namespace my-booking-app.Shared….
  • Each dot-separated segment must be a C# identifier: letters, digits and underscores, not starting with a digit. No hyphens and no spaces.
  • Use PascalCase segments. Namespaces take the name exactly as typed, so contoso.booking gives you lowercase namespaces.
  • Keep it short if anyone builds on Windows without long-path support. The name appears in nearly every path, often twice: src/CRM/Contoso.Booking.Crm/Contoso.Booking.Crm.csproj.

A generated project gets its own README, written for your copy, with the demo login already renamed.

It comes from templates/overlay/README.md, not from the repo’s marketing README. It covers running the stack, the demo user, and a “Change these before deploying” list. The local Keycloak realm ships with a demo account, which Authentication:SuperAdmins in appsettings.Development.json makes a super admin. Its credentials follow your name:

Demo login Rule For Contoso.Booking
Email demo@<name, lowercased>.dev demo@contoso.booking.dev
Password <name without separators>1 ContosoBooking1

To skip the login form, open https://localhost:5173/api/v1/login/demo. Demo:Enabled switches it. It’s on in appsettings.Development.json, and also in appsettings.Devtest.example.json.

The package also leaves out files that belong to upstream:

Not in a generated project Why
CHANGELOG.md, the root README.md, docs/images/ Upstream release material
src/AppointMe.Api/appsettings.Devtest.json BravoDev’s deployment config. You get appsettings.Devtest.example.json to fill in.
templates/, .template.config/, .github/workflows/template.yml The packaging project, and the job that publishes BravoDev’s NuGet package
.claude/settings.json, docs/superpowers/ Upstream’s own tooling settings and plans

Everything else ships, renamed: CLAUDE.md and the agent skills, the Bicep files in infra/, and the devtest.yml, codeql.yml and secret-scan.yml workflows.

There’s no rename script in the repo. To rename a clone, pack the template from it and generate from the package.

You want Do this
The easiest upstream merges Keep the AppointMe names. A clone with upstream’s names can merge release tags directly.
Your own names, and you haven’t changed anything yet Use dotnet new from nuget.org, as above
Your own names, keeping work you’ve already done in the clone Pack the clone, then generate from the package
  1. Pack the template from the clone’s root. The package takes your working tree, minus build output and the withheld files above. Its version comes from <Version> in templates/AppointMe.Templates.csproj, which is still 1.2.1 on main.

    Terminal window
    dotnet pack templates/AppointMe.Templates.csproj -c Release -o ../appointme-pack
  2. Install the package and generate. If another copy of the template is installed, uninstall it first, because both use the same package id.

    Terminal window
    dotnet new uninstall BravoDev.AppointMe.Templates
    dotnet new install ../appointme-pack/BravoDev.AppointMe.Templates.1.2.1.nupkg
    dotnet new appointme -n Contoso.Booking -o ../Contoso.Booking
  3. Look for brand tokens the template didn’t know. These are the smoke test’s own leftover checks, and both should print nothing. A hit in your own code needs a rename by hand.

    Terminal window
    cd ../Contoso.Booking
    grep -rIl "AppointMe" . --exclude-dir=node_modules --exclude-dir=obj --exclude-dir=bin --exclude-dir=dist
    grep -rIoE 'appointme([^n]|$)' . --exclude-dir=node_modules --exclude-dir=obj --exclude-dir=bin --exclude-dir=dist
  4. Start a new repository, and uninstall the template. The generated folder has no git history: your history stays in the clone. Commit the output as in step 3 at the top of this page, then run dotnet new uninstall BravoDev.AppointMe.Templates.

A good rename builds, passes its tests and leaves no brand token behind.

Check Command Expect
The backend builds dotnet build Contoso.Booking.sln 0 Error(s)
The tests pass dotnet test Contoso.Booking.sln No failures: 217 tests from 1.2.1, 221 from main
No brand token is left The two grep commands above No output
The frontend passes its checks npm ci && npm run check in src/Contoso.Booking.Frontend No errors
The stack starts dotnet run in src/Contoso.Booking.Aspire You can sign in as demo@contoso.booking.dev
Symptom Cause Fix
Hundreds of CS1022 and CS0116 errors in a fresh project -n isn’t a valid namespace, for example my-booking-app Generate again with a dotted PascalCase name
dotnet new doesn’t know appointme The template isn’t installed dotnet new install BravoDev.AppointMe.Templates::1.2.1
The output contains .git, CHANGELOG.md or appsettings.Devtest.json You installed the clone folder, not a package dotnet new uninstall <folder>, then pack and install the .nupkg
AppointMe still appears in your own code The character after it isn’t one the template routes Rename it by hand
Keycloak won’t import the realm after you renamed it by hand Keycloak requires the file to be named <realm>-realm.json (“File name / realm name mismatch”) Keep the file name and its "realm" value in step