# 0020. Back office sign-in

- Status: Accepted
- Date: 2026-10-28

## Context

The back office (M7) is a web app served by the hub, for owners and managers on a laptop or
phone. It edits the menu, staff and settings that every device sells with, removes devices and
shows reports, so it needs real sign-in. Until now a hub only knew devices (ADR 0019): tokens
issued by pairing, and staff identified by short PINs on the device itself. A 4–8 digit PIN is
fine behind a device's own lock screen and lockout, but too weak for a page that may be reachable
over the internet. A shop reaches the back office in one of two ways: set up from scratch in the
browser, or moved to the hub from its first POS device (ADR 0019), with an owner who has a PIN
but no password yet. One hub may serve several shops, and one person may run more than one.

## Decision

**Accounts.** A back office account is an email and a password, kept in the hub's registry
(`hub.sqlite`) next to device tokens. Each account is linked, per shop, to one staff member of
that shop. The staff member's role decides what the account may do: owners and managers may sign
in; cashiers can't. Archiving a staff member or making them a cashier ends their sign-in at
once. One account can manage several shops on the same hub and switch between them. Passwords
are hashed with scrypt (N = 2^15, r = 8, p = 1, parameters stored with the hash) and are at least
8 characters.

**Sessions.** Signing in sets an `HttpOnly`, `SameSite=Lax` cookie (`Secure` behind HTTPS)
holding a random token; the hub stores only its hash. Sessions last 30 days from last use. Every
request that changes something must carry the `x-openkedai-api` header, which a page on another
site can't send without the hub's permission (CORS is never granted), so the cookie can't be
used by a forged form. Wrong passwords and codes are limited per address and per email.

**Ways in.**
- **New shop in the browser.** The setup wizard asks for the hub's setup code (ADR 0019), then
  the shop's details, the owner's name and POS PIN, and an email and password. A person who is
  already signed in adds the shop to their account.
- **A shop moved from a POS device.** An owner or manager on a paired device opens Settings → Hub
  → Back office and gets a one-time **sign-in code** (8 characters, 30 minutes) with the back
  office's address. In the browser, "I have a code from the POS" asks for the code, an email and
  a password. The device asks for the code on behalf of the staff member using it, trusted as
  devices are (ADR 0019).
- **Forgotten password.** A new sign-in code from a POS device resets the password of the staff
  member's account and signs it out everywhere.
- **Managers.** An owner can give a manager (or another owner) an email and password from the
  Staff page.

**Rules the hub enforces** (devices still enforce roles on themselves): only owners manage owners
or give back office access; a shop always keeps at least one owner; nobody changes their own role
or removes themselves.

**Plugin routes** (ADR 0018) get real meaning: `owner` routes answer a signed-in owner or manager
of the shop, `staff` routes a signed-in owner or manager or a paired device, `device` routes a
paired device.

**Removing devices.** Owners and managers remove a device in the back office or from another
device (a device can't remove itself). Its tokens stop working at once, its live connection is
told and closed, and it stops syncing with a reason. Its row and sales stay. A pairing code can
bring it back with its own id and device code (`POST /api/devices/rejoin`), so its sales waiting
in its outbox still reach the hub.

## Consequences

- Owners and managers can run the shop from a browser without a terminal; the only secret they
  may need from the server is the setup code, which a hosted or PaaS deploy can set with
  `OPENKEDAI_SETUP_CODE`.
- Accounts live in the hub's registry rather than in a shop's file, because one person can run
  several shops. Moving a shop's file to another hub doesn't move its accounts; its owner signs
  in again with a code from a POS device.
- No email is ever sent: there is no mail server to configure, and the POS sign-in code covers
  password resets. Email-based resets and two-factor sign-in can come later.
- Sign-in on a shop LAN without HTTPS sends the password in the clear on that network, as device
  tokens are (ADR 0019). The hub guide recommends HTTPS for any hub reachable from the internet.
