# 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.` on `monoco`, image `registry.tanshu.com/menu-admin:` | | Menu content | `/var/lib/menu-app./data` — `originals/`, `drafts/`, `published/` | | Admin | `https:///admin` | | The password | `/var/lib/menu-app./site.env` (mode 600, never in git) | | Categories | `data/sections.json`, edited in the admin | | Brand and theme | `config/.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.json`, rebuild and push (`./deploy.sh `), 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: 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.`, 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.` — 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./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.