# Commands

> Every command for AppointMe. Run the .NET 10 stack with Aspire or Docker Compose, build and test, the Vite+ frontend, API client generation, EF Core migrations, Wolverine codegen and dotnet new.

Source page: https://appointme.dev/docs/reference/commands/

* **Run everything:** `dotnet run` in `src/AppointMe.Aspire`
* **Test everything:** `dotnet test AppointMe.sln`, no database needed
* **Frontend:** npm scripts that call Vite+ `vp`
* **Extra tool:** `dotnet-ef`, for migrations only

These are the commands the repo itself uses: in its README, CI workflows, Dockerfile, npm scripts and agent skills. Run them from the repo root unless the table says otherwise. In a project generated with `dotnet new -n`, replace `AppointMe` in paths with your name.

## Run

**One command starts the whole stack. The others run a single piece, the backing services, or fix the dev certificate.**

### Aspire and the API

| Command                                                         | Run from               | What it does                                                                                                                                           |
| --------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `aspire run`                                                    | Repo root              | Starts the AppHost through the Aspire CLI, which `.aspire/settings.json` points at `src/AppointMe.Aspire`. Optional: the AppHost doesn’t need the CLI. |
| `dotnet dev-certs https --check --trust`                        | Anywhere               | Exits `0` when the dev certificate is trusted. The AppHost runs this check at startup.                                                                 |
| `dotnet dev-certs https --clean`                                | Anywhere               | Removes the dev certificate. Run `--trust` again afterwards.                                                                                           |
| `dotnet dev-certs https --trust`                                | Anywhere               | Creates and trusts the dev certificate. Once per machine.                                                                                              |
| `dotnet run`                                                    | `src/AppointMe.Aspire` | Starts SQL Server, Keycloak, Mailpit, the API and the frontend                                                                                         |
| `dotnet run --project src/AppointMe.Api --launch-profile https` | Repo root              | Runs the API alone on `https://localhost:7233` and `http://localhost:5179`. Needs the Compose services.                                                |

### Docker Compose

Compose runs only SQL Server, Keycloak and Mailpit. Run these from the repo root.

| Command                                | What it does                                                                                                                       |
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `./docker/keycloak/export-dev-cert.sh` | Trusts the dev certificate and exports it as `docker/keycloak/certs/keycloak.crt` and `keycloak.key`. Once, before the first `up`. |
| `docker compose down`                  | Removes the containers. The `sqlserver-data` and `keycloak-data` volumes stay.                                                     |
| `docker compose down -v`               | Removes the containers and both volumes                                                                                            |
| `docker compose logs -f keycloak`      | Follows one service’s logs (`sqlserver`, `keycloak` or `mailpit`)                                                                  |
| `docker compose ps`                    | Shows status. SQL Server and Keycloak report `healthy` when ready.                                                                 |
| `docker compose stop`                  | Stops the containers and keeps all data                                                                                            |
| `docker compose up -d`                 | Starts SQL Server, Keycloak and Mailpit                                                                                            |

## Build and test

**`dotnet build` also writes the OpenAPI document, and `dotnet test` needs no running services.**

| Command                                                            | What it does                                                                                                                                                                                                                          |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `docker build -f src/AppointMe.Api/Dockerfile .`                   | Builds the production image: the SPA bundle, Wolverine’s pre-generated handlers and the API. The context is the repo root.                                                                                                            |
| `dotnet build AppointMe.sln`                                       | Builds all 17 projects, and writes `src/AppointMe.Api/obj/openapi.json`                                                                                                                                                               |
| `dotnet build AppointMe.sln -c Release --no-restore`               | The CI build, after `dotnet restore AppointMe.sln`                                                                                                                                                                                    |
| `dotnet test AppointMe.sln`                                        | Runs all 221 tests in six projects. They’re unit tests that never open a database connection, so nothing needs to be running. Name the solution: the root also holds `AppointMe.slnx`, and a bare `dotnet test` stops with `MSB1011`. |
| `dotnet test AppointMe.sln --filter "FullyQualifiedName~TestName"` | Runs the tests whose full name contains `TestName`                                                                                                                                                                                    |
| `dotnet test src/CRM/AppointMe.Crm.Tests`                          | Runs one test project                                                                                                                                                                                                                 |

## Frontend

**Every script except `generate:api` is a thin wrapper around Vite+’s `vp` command. Run them from `src/AppointMe.Frontend`.**

src/AppointMe.Frontend/package.json

```json
"scripts": {
    "dev": "vp dev",
    "build": "vp build",
    "check": "vp check",
    "lint": "vp lint .",
    "format": "vp fmt",
    "preview": "vp preview",
    "generate:api": "dotnet build ../AppointMe.Api/AppointMe.Api.csproj -c Release --nologo -v q && orval"
},
```

| Command                           | What it does                                                                                     |
| --------------------------------- | ------------------------------------------------------------------------------------------------ |
| `npm ci`                          | Installs the locked versions without touching `package-lock.json`. CI and the Dockerfile use it. |
| `npm run build`                   | Production build into `dist/`                                                                    |
| `npm run check`                   | Format check, lint and type-check in one pass. CI runs it and fails on unformatted code.         |
| `npm run dev`                     | Dev server on `https://localhost:5173`, with the `/api`, `/signin-oidc` and `/admin` proxy       |
| `npm run format`                  | Formats the code with Oxfmt, using the `fmt` block of `vite.config.ts`                           |
| `npm run lint`                    | Oxlint with type-aware rules, using the `lint` block of `vite.config.ts`                         |
| `npm run preview`                 | Serves the production build locally                                                              |
| `npx vp check --no-fmt --no-lint` | Type-check only                                                                                  |

## API client

**`npm run generate:api` builds the API, which writes the OpenAPI document, then runs orval on it. No running backend is needed.**

| Command                                           | Run from                 | What it does                                                                                                   |
| ------------------------------------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------- |
| `git diff --stat src/AppointMe.Frontend/src/api/` | Repo root                | Shows the contract change as reviewers see it                                                                  |
| `npm run generate:api`                            | `src/AppointMe.Frontend` | Builds `AppointMe.Api` in Release, then regenerates `src/api/client.ts` and `src/api/client.schemas.ts`        |
| `npx orval`                                       | `src/AppointMe.Frontend` | Regenerates from the last build’s `obj/openapi.json` without building. Only useful when that build is current. |

The build runs the app’s startup in the `Codegen` environment, with placeholder settings from `appsettings.Codegen.json` and no database. It uses Release so it doesn’t collide with an API that Aspire is running from `bin/Debug`. See [Typed API client](/docs/frontend/api-client/).

## EF Core migrations

**There’s no tool manifest or script in the repo. Install `dotnet-ef` globally, then add migrations per module.**

```bash
dotnet tool install --global dotnet-ef
dotnet ef migrations add AddCustomerNotes \
  --project src/CRM/AppointMe.Crm \
  --startup-project src/AppointMe.Api \
  --context CrmDbContext \
  --output-dir Database/Migrations
```

| Module        | `--project`                                 | `--context`              |
| ------------- | ------------------------------------------- | ------------------------ |
| Booking       | `src/Booking/AppointMe.Booking`             | `BookingDbContext`       |
| CRM           | `src/CRM/AppointMe.Crm`                     | `CrmDbContext`           |
| Identity      | `src/Identity/AppointMe.Identity`           | `IdentityDbContext`      |
| Organizations | `src/Organizations/AppointMe.Organizations` | `OrganizationsDbContext` |

`--startup-project src/AppointMe.Api` and `--output-dir Database/Migrations` are the same for all four. `dotnet ef migrations remove` with the same `--project`, `--startup-project` and `--context` undoes the last migration, as the tool’s own output suggests. [Database migrations](/docs/guides/database-migrations/) walks through a full change.

## Wolverine codegen

**Wolverine generates its handler code at runtime in Development, and ahead of time for other environments. These commands drive that generation.**

| Command                                                     | What it does                                                                                                                  |
| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `dotnet run --project src/AppointMe.Api -- codegen preview` | Prints the generated handler code                                                                                             |
| `dotnet run --project src/AppointMe.Api -- codegen write`   | Writes it to `src/AppointMe.Api/Internal/Generated/`, which is git-ignored. The Dockerfile runs this before `dotnet publish`. |
| `dotnet run --project src/AppointMe.Api -- codegen test`    | Generates and compiles all handler code in memory. CI runs it after the build.                                                |
| `dotnet run --project src/AppointMe.Api -- codegen delete`  | Deletes the written files                                                                                                     |
| `dotnet run --project src/AppointMe.Api -- help`            | Lists every JasperFx command the API host offers, such as `describe`, `resources` and `storage`                               |

Any argument list that contains `codegen` switches the host to the `Codegen` environment, so these commands need no database. CI’s exact form is `dotnet run --project src/AppointMe.Api/AppointMe.Api.csproj -c Release --no-build --no-launch-profile -- codegen test`.

## Template

**`dotnet new` creates a renamed copy of the whole repo. The smoke test is the gate that keeps the template working.**

| Command                                                  | What it does                                                                                                                                                                                     |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `./templates/smoke-test.sh`                              | Upstream repo only. Packs the template, installs it, generates `Contoso.Booking`, then builds, tests, lints and builds the output. Set `NAME` to test another name, `KEEP=1` to keep the output. |
| `dotnet new appointme -n Contoso.Booking`                | Generates a project in `./Contoso.Booking`. `-n` must be a dotted .NET identifier.                                                                                                               |
| `dotnet new appointme -n Contoso.Booking -o <dir>`       | Generates into `<dir>` instead                                                                                                                                                                   |
| `dotnet new install BravoDev.AppointMe.Templates::1.2.1` | Installs the template package. Pin the version so a generation is reproducible.                                                                                                                  |
| `dotnet new uninstall BravoDev.AppointMe.Templates`      | Removes the template package                                                                                                                                                                     |

### Why is there no database update step?

The API applies migrations itself. Each module’s `Add<Module>Module()` calls `AddDatabaseMigration<TContext>()`, and one hosted service runs `MigrateAsync()` for every registered context when the API starts, locally and in Azure alike.

That keeps one path for every environment: start the app and its schema is current. The cost is that a broken migration stops the API from starting, so test new migrations locally before you tag a release.

## Next

* [Local services & ports](/docs/reference/local-services/) (Reference)
* [Database migrations](/docs/guides/database-migrations/) (Guide)
* [Troubleshooting](/docs/reference/troubleshooting/) (Reference)
