Run your own descriptor
Run the published standalone image over a descriptor you wrote, with API keys for the roles it declares, using Docker and three downloaded files.
Before you start
Section titled “Before you start”- Docker with Compose v2,
curlandopenssl, and port 8080 free. If the Quick start’s stack is still running, stop it first: both listen on127.0.0.1:8080. - A descriptor file. If you do not have one yet, the commands below use
examples/help-desk, and Start from an example takesexamples/simple-tasksas a starting point.
1. Declare keys your descriptor knows
Section titled “1. Declare keys your descriptor knows”The quick start’s docker-compose.quickstart.yml defines one dev key, demo. Its roles are the built-in admin and
authenticated, so it authenticates against any descriptor, but a key with one role the descriptor does not declare
authenticates nothing: every request with it is a 401 unauthenticated. A key’s roles must be listed in the
descriptor’s auth.roles or be built in (authenticated and admin are). So declare keys for your own roles in a
compose override, a second file that compose merges over the first:
# Saved as docker-compose.override.yml next to docker-compose.quickstart.yml. With# COMPOSE_FILE=docker-compose.quickstart.yml:docker-compose.override.yml exported, every `docker compose`# command merges it over the quick start's stack. It serves ./help-desk.alvo.json instead of an example# inside the image, runs as its own project (its own database), and adds two dev keys for examples/help-desk# beside the quick start's demo key (index 0). Every role a key carries must be declared in the descriptor's# auth.roles or be built in (authenticated, admin): a key with one undeclared role authenticates nothing.name: alvo-help-desk
services: alvo: environment: Alvo__DescriptorPath: /alvo/descriptor.json Alvo__Auth__DevKeys__1__KeyId: agent Alvo__Auth__DevKeys__1__Secret: ${ALVO_AGENT_KEY_SECRET:?set ALVO_AGENT_KEY_SECRET before starting the stack} Alvo__Auth__DevKeys__1__User: 3f2b8c1e-7a4d-4e9b-9c21-5d6e7f8a9b01 Alvo__Auth__DevKeys__1__Roles__0: agent Alvo__Auth__DevKeys__1__Roles__1: authenticated Alvo__Auth__DevKeys__1__Scopes__0: "*:read" Alvo__Auth__DevKeys__1__Scopes__1: "*:write" Alvo__Auth__DevKeys__2__KeyId: admin Alvo__Auth__DevKeys__2__Secret: ${ALVO_ADMIN_KEY_SECRET:?set ALVO_ADMIN_KEY_SECRET before starting the stack} Alvo__Auth__DevKeys__2__User: 8d4e2a6c-1b3f-4c5d-8e7a-9f0b1c2d3e02 Alvo__Auth__DevKeys__2__Roles__0: admin Alvo__Auth__DevKeys__2__Roles__1: authenticated Alvo__Auth__DevKeys__2__Scopes__0: "*:read" Alvo__Auth__DevKeys__2__Scopes__1: "*:write" volumes: - ./help-desk.alvo.json:/alvo/descriptor.json:roIt adds two keys for help-desk, whose auth.roles are admin and agent: agent (roles agent,
authenticated) and admin (roles admin, authenticated). Change the KeyIds and roles to your descriptor’s.
Each secret is read from a variable, and the :? form makes compose refuse to start rather than invent one; a secret
must be at least 32 characters.
The override also mounts ./help-desk.alvo.json read-only at /alvo/descriptor.json and points the host at it, so
the stack serves your file instead of an example inside the image. To serve a file with another name, change the left
side of that volumes line. name: alvo-help-desk gives this stack its own database, apart from the quick start’s.
2. Start the stack over your descriptor
Section titled “2. Start the stack over your descriptor”-
Make a directory for the stack, download the compose file, the override and the descriptor, generate the secrets, and start it:
Terminal mkdir -p alvo-help-desk && cd alvo-help-deskcurl -fsSLO https://raw.githubusercontent.com/Burgyn/MMLib.Alvo/main/docker-compose.quickstart.ymlcurl -fsSL -o docker-compose.override.yml https://raw.githubusercontent.com/Burgyn/MMLib.Alvo/main/website/src/snippets/shell/help-desk.compose.override.ymlcurl -fsSL -o help-desk.alvo.json https://raw.githubusercontent.com/Burgyn/MMLib.Alvo/main/examples/help-desk/help-desk.alvo.jsonexport COMPOSE_FILE=docker-compose.quickstart.yml:docker-compose.override.ymlexport ALVO_DEMO_KEY_SECRET="$(openssl rand -hex 16)" ALVO_ADMIN_PASSWORD="$(openssl rand -hex 12)"export ALVO_AGENT_KEY_SECRET="$(openssl rand -hex 16)" ALVO_ADMIN_KEY_SECRET="$(openssl rand -hex 16)"docker compose up --wait --wait-timeout 90curl -sS localhost:8080/api/tickets -H "X-Alvo-Api-Key: agent.$ALVO_AGENT_KEY_SECRET"COMPOSE_FILEnames both files, so every plaindocker composecommand in this shell uses them together.--waitreturns once the API is ready, which means the descriptor is applied. The last command lists the tickets with theagentkey: an empty page, because nothing has been written yet. -
Every compose command reads both files again,
downincluded, so keep these variables exported in the shell you use for the stack, or put them in a.envfile next to the compose files, which compose reads by itself.
The API is at http://localhost:8080/api/<entity>, its OpenAPI document at /openapi/v1.json, an API browser at
/scalar, and the dashboard at /admin, where you sign in as admin@alvo.local with ALVO_ADMIN_PASSWORD. The
Tutorial walks through this exact stack one change at a time.
3. Change it
Section titled “3. Change it”Edit help-desk.alvo.json, then recreate the alvo container so it reads the file again:
docker compose up -d --wait --force-recreate alvoOn start, Alvo compares the descriptor with the schema it applied before. A change that discards nothing (a new entity, a new field, a changed rule) is applied; one that would drop or narrow data is refused, and the container stops with the plan in its log. To apply without a restart, send the descriptor to the Management API instead; both paths, with dry runs, revisions and rollback, are in Apply and evolve your descriptor. In this build everything but a new entity takes effect that way at once; a new entity gets its Data API route after a restart (#103).
Start from an example
Section titled “Start from an example”examples/simple-tasks is the smallest real backend: projects and the tasks inside them, owned by the user who created
them. Download it over the mounted file, and from then on it is your descriptor:
docker compose down --volumescurl -fsSL -o help-desk.alvo.json https://raw.githubusercontent.com/Burgyn/MMLib.Alvo/main/examples/simple-tasks/tasks.alvo.jsondocker compose up --wait --wait-timeout 90curl -sS localhost:8080/api/projects -H "X-Alvo-Api-Key: admin.$ALVO_ADMIN_KEY_SECRET"The first line deletes the stack’s database. A database holds the schema of the descriptor it served; starting a different descriptor over it would drop the old tables, and Alvo refuses that (see What can go wrong).
simple-tasks declares no auth.roles, so of the override’s keys only admin works there (its roles are both built
in, like the demo key’s); the agent key answers 401 until you add "roles": ["agent"] to the descriptor’s auth
block, or remove agent from the key.
Tear it down
Section titled “Tear it down”Stop the stack and delete its database, in the same shell. The unset makes a plain docker compose in this shell
stop reaching for the override; the quick start’s commands name their file with -f anyway:
docker compose down --volumesunset COMPOSE_FILEWithout Docker
Section titled “Without Docker”Run the host with the .NET SDK and SQLite instead
The same descriptor and the same two keys, on the host process directly, from a clone of the repository
(git clone https://github.com/Burgyn/MMLib.Alvo; run the commands in its root). You need the .NET SDK the
repository’s global.json pins. The database is a SQLite file in your temporary directory, and the host listens on
the address the stack uses, so stop the stack first.
export ALVO_DESCRIPTOR="$PWD/examples/help-desk/help-desk.alvo.json"export ALVO_AGENT_KEY_SECRET="$(openssl rand -hex 16)"export ALVO_ADMIN_KEY_SECRET="$(openssl rand -hex 16)"openssl rand -base64 24 > .alvo-admin-passworddotnet run --project src/MMLib.Alvo.Host -- \ --environment Development --urls http://127.0.0.1:8080 \ --Alvo:DescriptorPath="$ALVO_DESCRIPTOR" \ --Alvo:Database:Provider=sqlite \ "--Alvo:Database:SqliteConnectionString=Data Source=${TMPDIR:-/tmp}/alvo-help-desk.db" \ --Alvo:Admin:BootstrapEmail=admin@example.com \ --Alvo:Admin:BootstrapPasswordFile="$PWD/.alvo-admin-password" \ --Alvo:Auth:DevKeys:0:KeyId=agent --Alvo:Auth:DevKeys:0:Secret="$ALVO_AGENT_KEY_SECRET" \ --Alvo:Auth:DevKeys:0:User=3f2b8c1e-7a4d-4e9b-9c21-5d6e7f8a9b01 \ --Alvo:Auth:DevKeys:0:Roles:0=agent --Alvo:Auth:DevKeys:0:Roles:1=authenticated \ "--Alvo:Auth:DevKeys:0:Scopes:0=*:read" "--Alvo:Auth:DevKeys:0:Scopes:1=*:write" \ --Alvo:Auth:DevKeys:1:KeyId=admin --Alvo:Auth:DevKeys:1:Secret="$ALVO_ADMIN_KEY_SECRET" \ --Alvo:Auth:DevKeys:1:User=8d4e2a6c-1b3f-4c5d-8e7a-9f0b1c2d3e02 \ --Alvo:Auth:DevKeys:1:Roles:0=admin --Alvo:Auth:DevKeys:1:Roles:1=authenticated \ "--Alvo:Auth:DevKeys:1:Scopes:0=*:read" "--Alvo:Auth:DevKeys:1:Scopes:1=*:write"Ctrl+C stops it. A change to the descriptor applies on the next start, as with the stack.
What can go wrong
Section titled “What can go wrong”| Status | Problem type | When | Fix | Returned by |
|---|---|---|---|---|
| 401 | unauthenticated | The key carries a role the descriptor does not declare (the agent key over a descriptor without agent), or the secret is wrong. | Give the key only declared or built-in roles; export the same secret the stack was started with. | every host |
The stack does not start. docker compose up --wait fails and the alvo container has exited. Read why:
docker compose logs alvoThe end of the log says what to change. The common reasons:
-
The descriptor is invalid. The log shows
Descriptor validation failed:and one line per problem: its JSON pointer, for example/entities/tickets/fields/estimate_cost/computed, what is wrong and how to fix it. Correct the file and start again. -
The change would discard data. The log says
Alvo cannot start:, lists the plan with the destructive steps marked (such asDropEntity tickets), and the container exits with code 78. Keep what the descriptor dropped, or, if the data is disposable, start over with an empty database:Terminal docker compose down --volumes -
A variable is missing. Compose itself refuses, naming the variable (
set ALVO_AGENT_KEY_SECRET before starting the stack), before any container starts. Export it again.
Reference
Section titled “Reference”- Configuration:
Alvo:Authdev keys and every other key, the dev-key secret minimum. - Descriptor keys:
auth.roles. - Problem types:
unauthenticated. - The compose file:
docker-compose.quickstart.yml; the host and the startup mode, in depth:docs/architecture/host.md.
Apply and evolve your descriptor: change a running backend safely, with dry runs, revisions and rollback.