Skip to content

Liber Tertius · Chapter 2 · Starting a project

Create a project

One command does nearly all of it, and it takes minutes because it builds an image, installs core and migrates a database. What is left to you is small and easy to skip. Copy a password that is shown once, and understand why the first commit holds only three files.

≈10 min 6 steps A machine where grim doctor passes A database that accepts root without a password
Source

Before you start

The machine is ready: Docker runs, you are logged in, and grim doctor outside any project ends with All checks passed!. If this is a new machine, do the install recipe for your system first.

The install will create the project's database with the mysql client on your machine, as root with no password. When that login does not work, the step is passed over without a word and the run fails later, at the migrations. Try the exact login now.

$ mysql -u root -e "SELECT 1"
$ cd ~/code

Stand in the directory that should hold the project. The name you pick becomes the directory, the name in grim.json, the database and the local domain. Use lowercase letters, digits and hyphens. grim does not reject other names, and a domain or a database will.

The ritual, in order

Six steps. The first does nearly all the work, the fourth is optional, and only the last touches git.

  1. Create it

    grim create-project first checks that Docker runs and can pull from ghcr.io, then asks two questions. Module preset? offers minimal, all and custom. Frontend theme? offers blank, an existing theme or a new one. Enter takes minimal and blank, and both can be changed later.

    $ grim create-project shop
    Creating project: shop
    
    ✓ Created shop/grim.json
      0 modules, theme: blank
    
    Running grim install...
    
      Project installed
      ───────────────────────────────────────
      Project       shop
      Core          2.5.0
      Modules       0
      Themes        2
      · · · · · · · · · · · · · · · · · · · ·
      Admin         admin@shop.test
      Password      3f9c1a7e5b2d8046
      · · · · · · · · · · · · · · · · · · · ·
      Next          cd shop
      Then          grim up

    Between the two halves, grim install prints one line per step with its duration: core, modules, themes, configuration, the lock, the database, the image build, the migrations, the admin. The first failure stops the run.

    The Password row is the only place the admin password is ever shown. Copy it before the terminal scrolls. When the two admin rows are missing, the account was not created, and step four makes one.

  2. Bring it up

    The install leaves the containers running. grim up adds what is still missing: the certificate for shop.test, and the Vite dev server on your machine.

    $ cd shop
    $ grim up
    
      Development ready
      ───────────────────────────────────────
      URL           https://shop.test
      Mailpit       https://mail.shop.test
      Vite HMR      https://shop.test:5173

    Look for TLS chain verified above the table. It means the certificate that Traefik serves is the one your browser will trust. On Linux and WSL2 expect a sudo prompt for /etc/hosts, and on WSL2 a UAC prompt on the Windows desktop.

  3. Sign in

    Open the login page and use the Admin and Password rows from step one.

    $ curl -sI https://shop.test/login | head -n 1
    $ open https://shop.test/login

    The first line of the answer is the status the app gave. Any mail the app sends lands in Mailpit at https://mail.shop.test, never in a real inbox. On Linux use xdg-open, and on WSL2 cmd.exe /c start.

  4. Make an account of your own

    Optional. admin@shop.test is a fine account for a project only you run. For a name of your own, or when the password from step one is gone, grim user creates another admin.

    $ grim user anna@example.com

    The summary is titled User created and carries a new generated password. User (check output above) means it failed. The exit code is 0 either way.

  5. Run the suite once

    grim test creates the database shop_test next to shop, migrates it and runs the suite. Run it now, while nothing of yours can be the reason for a failure.

    $ grim test

    A red suite on an untouched project is a finding about the train or the machine, not about your code.

  6. Make the first commit

    grim does not run git init. It does write a .gitignore, and that file ignores everything except itself and two others.

    $ git init
    $ git add .gitignore grim.json grim.lock
    $ git status --short
    A  .gitignore
    A  grim.json
    A  grim.lock
    $ git commit -m "chore: create shop"

    Three files are the project. git clone and grim install rebuild the rest, at the versions the lock records. The .gitignore is yours from now on, and grim never rewrites it. For every file or directory the project itself owns, add a line such as !/app/ before you expect git to see it.

What you have now

shop/
  grim.json, grim.lock    what the project is made of, and at which versions
  .gitignore              the allowlist: itself and the two files above
  .env                    local settings, APP_KEY filled in, DB_HOST=host.docker.internal
  docker-compose.yml      yours to edit from now on
  docker/                 Dockerfiles and nginx config, renewed by grim upgrade
  src/<Module>/           one git checkout per module
  resources/themes/       one checkout per theme

On the machine: the database shop and shop_test, a certificate in ~/.grim/traefik/certs, and a stack that grim down stops and grim up starts. Modules come and go with grim require and grim remove.

When it does not work

“Not authenticated to ghcr.io.”

Docker cannot pull the base image. Answer yes to Run `grim auth:login` now to authenticate? and the run continues. When a 403 follows, the token lacks read:packages or is fine-grained. Make a classic one and run grim auth:login --token <new-pat>.

The migrations fail with an unknown database

The Creating local database step was passed over because mysql -u root did not log in. The project directory is complete up to that point. Create the database with whatever login your server accepts, then run the install again inside the project. Core on disk is left alone and the run goes on to the migrations.

$ mysql -u root -p -e "CREATE DATABASE shop CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"
$ cd shop
$ grim install
``` When the server wants a password, put `DB_USERNAME` and `DB_PASSWORD` into `.env` before that install. A project named `my-shop` gets the database `my_shop`.

### “Directory shop already exists.”

A failed run leaves its directory behind. When nothing in it is worth keeping, stop its containers with `grim down` inside it, delete it and start again. Otherwise go in and run `grim install`.

### “Could not load module catalog”

You chose `custom` and the registry did not answer, which is nearly always the token. Run `grim auth:login`, or name the modules yourself with `--modules=cart,payments`.

### The browser cannot find shop.test

On macOS nothing on the machine answers the `.test` resolver. On Linux the `sudo` prompt was declined. Add the line by hand, and on WSL2 also run `grim hosts:windows`.

```console
$ echo '127.0.0.1 shop.test mail.shop.test' | sudo tee -a /etc/hosts

Next recipe

Bring an existing app onto grim

Convert the instance into a grim.json without installing, read the dry run, settle the modules nobody asked for, point the copied .env at this machine, install, move your own files in, then test and commit.

Read it

Spells used here