Categories were baked into config/<site>.site.json, so adding one meant a rebuild and a redeploy. They are now data: data/sections.json, seeded from the config the first time, and managed in the admin (add, rename, reorder, remove). A category's web address is fixed when it is created because that is what a QR code points at, and a category cannot be removed while it still holds menus. The landing and the top bar were the ugliest parts. The landing was a column of hairlines with tiny meta — a broadsheet, and the paper that makes this app worth looking at was nowhere on it. It is now a shelf: each category is a row whose right edge is a sliver of that menu's first page, bleeding off the screen, with the shelf edge in brass and the name in heavy tight Archivo. The bar was a row of teal pills that would not survive more categories: it now names the menu you are reading and opens a sheet listing the rest, each with its own paper sliver, and the current one is the only teal thing on screen. The sheet is a link to the landing page, so navigating still works without the script. Also fixes the category manager's own layout, which I shipped unstyled, and the markup contract the route tests described.
99 lines
4.3 KiB
Markdown
99 lines
4.3 KiB
Markdown
# Operating the menus
|
|
|
|
For whoever is on the other end of "the menu is wrong". The design is in
|
|
`plan.md`, the vocabulary in `CONTEXT.md`, and the deployment in
|
|
`ansible-playbooks/menu-admin/readme.md`.
|
|
|
|
## Where things are
|
|
|
|
| Thing | Where |
|
|
| --- | --- |
|
|
| The app | container `menu-app.<site>` on `monoco`, image `registry.tanshu.com/menu-admin:<tag>` |
|
|
| Menu content | `/var/lib/menu-app.<site>/data` — `originals/`, `drafts/`, `published/` |
|
|
| Admin | `https://<vhost>/admin` |
|
|
| The password | `/var/lib/menu-app.<site>/site.env` (mode 600, never in git) |
|
|
| Categories | `data/sections.json`, edited in the admin |
|
|
| Brand and theme | `config/<site>.site.json` in this repo, baked into the image |
|
|
|
|
## Everyday tasks
|
|
|
|
**Publish a new menu.** Sign in at `/admin`, find the Section, fill in "New Menu
|
|
Set" (label, optional valid-until date), Create Draft, then drop the photos in.
|
|
Drag to reorder — the order in the editor is the order customers see. Press
|
|
Preview to check it, then Publish. Publishing archives whatever was current.
|
|
|
|
**Put an older menu back.** Open the Section's "older menus" fold in the admin,
|
|
open the set you want and press "Make current". Its URL does not change.
|
|
|
|
**Change the admin password.** On the server:
|
|
|
|
```sh
|
|
bash /tmp/provision-site-env.sh /var/lib/menu-app.hopsngrains.com --force
|
|
docker restart menu-app.hopsngrains.com
|
|
```
|
|
|
|
**Add, rename, reorder or remove a category.** In the admin, open the
|
|
**Categories** fold at the bottom of the dashboard. A new category starts empty,
|
|
so customers do not see it until you publish a menu into it. Reordering there is
|
|
the order customers see. Two rules: a category's web address is fixed when it is
|
|
created (rename the name as often as you like — a printed QR code keeps working),
|
|
and a category can only be removed once it holds no menus.
|
|
|
|
**Change brand or theme.** Edit `config/<site>.site.json`, rebuild and push
|
|
(`./deploy.sh <tag>`), then run the playbook with the new tag.
|
|
|
|
**Fix a missing image.** If a Page's thumbnail or viewing image is lost while its
|
|
Original survives, the app can rebuild them:
|
|
|
|
```sh
|
|
docker run --rm --user 1000:1000 -e MENU_ROOT=/data \
|
|
-e MENU_SITE_CONFIG=/app/config/hopsngrains.site.json \
|
|
-v /var/lib/menu-app.hopsngrains.com:/data \
|
|
--entrypoint node registry.tanshu.com/menu-admin:<tag> src/cli/repair.ts
|
|
```
|
|
|
|
`src/cli/verify.ts` does the same inventory without changing anything, and is
|
|
what the server refuses to boot on.
|
|
|
|
## When something looks wrong
|
|
|
|
| Symptom | Look here |
|
|
| --- | --- |
|
|
| Landing page says the menus are being updated | no Section has a Current Menu Set — publish one in the admin |
|
|
| A Section 404s | that Section has no Current set, or the URL is misspelled |
|
|
| Sign-in rejects the right password | `docker logs menu-app.<site>`, then check `site.env` exists and is owned by the app user |
|
|
| Admin is missing entirely | `site.env` was unreadable at boot, so the admin is disabled: run the provision script and `docker restart` |
|
|
| A photo uploads but looks wrong | the browser shrinks to 3000px before upload; that is expected, and the Original is kept |
|
|
| The container will not start | `docker logs` — a fatal integrity problem makes it refuse to serve a data directory it cannot trust |
|
|
| Caddy reload failed during a deploy | nothing is down: Caddy validates before applying. Read the error in the playbook output |
|
|
| Everything is slow | check the tag is current; a Viewing image is ~1600px, so a Section page should not be megabytes |
|
|
|
|
**Logs.** `docker logs -f menu-app.<site>` — JSON lines, one per event, including
|
|
every upload, publish, restore and failed sign-in.
|
|
|
|
**Checking from outside.** No sign-in, no writes, exits non-zero on failure, so
|
|
it can gate a cutover:
|
|
|
|
```sh
|
|
npm run check-site -- https://menu.hopsngrains.com
|
|
```
|
|
|
|
## Backups
|
|
|
|
The app is the only writer. The irreplaceable part is
|
|
`/var/lib/menu-app.<site>/data/originals` — the photos exactly as uploaded, from
|
|
which everything else can be regenerated with `repair`. Back that directory up;
|
|
`site.env` is worth keeping too (otherwise you re-provision the password).
|
|
|
|
## Rolling back
|
|
|
|
The old nginx Site is kept, not deleted. To go back:
|
|
|
|
```sh
|
|
docker start nginx-menu.hopsngrains.com
|
|
```
|
|
|
|
then point Caddy back at it — the cutover section of the playbook readme has the
|
|
exact invocation, including the flag that stops the app's snippet from being
|
|
re-added.
|