Quasar HQ /Administration

Users and Roles

Accounts, access and security
Access System Content & AI

Users

UserEmailRoleAccessLast login2FAStatus
Loading...

Departments

app_settings 'roles.departments' - admin-only, audited
DepartmentMembersPeople
Loading...

Click a department's People chips to change who is in it (HR or admin only; audited). Renaming or removing a department here does not touch anyone's existing People directory record - it only changes the list offered when assigning someone, and on the People page. Removing a department that still has members does not unassign them. An account tagged "no People record" has a login but no directory record yet (so roles alone can never place it in a department) - assign it to one to create the record.

Chat rooms follow this list (HQ-503): saving a rename here renames the room and carries its access across in the same save; a new department gets a room the moment it saves, and a removed department's room stops existing (its messages are kept). Who may open each room is set in the Team chat channels card below.

Team chat channels

RoomAccess
Loading...

Department rooms follow the Departments card above - renaming a department there renames its chat room in the same save, and a new department gets a room the moment it saves. A custom channel is any extra room added here; "members" on a custom channel means administrators only until per-channel membership exists. All Chat stays open to every signed-in person and a direct message is its two participants only; neither is set here. Applies immediately to every send, read, unread count and the room list itself, and a restricted room stops mirroring to Google Chat while it stays restricted.

Functional roles

These are the roles you assign to a person on Users and Roles (tick them on their record or when creating the login). This page defines what each role reaches - it does not assign anybody. Pick a role to see and edit every module it reaches: left tick = View (the module appears in their menu), right tick = Edit.

Which Edit ticks actually do something

Edit now drives the role's in-module ACTION buttons (HQ-542): on invite or re-sync, a module's action keys are granted only where the role holds Edit there - View alone shows the tab and nothing else - so the Edit column here and the Action column on a user record describe the same thing. Money and other gated actions additionally stay locked to their named roles whatever Edit says. Server-side WRITE enforcement of Edit exists today for Manufacturing (boms / bom_lines / bom_operations / test_equipment) only; B2B edit stays code-locked to sales + sales_manager (HQ-456) - the B2B Edit tick is a display of that code constant, so unticking it removes nothing. Widening server write enforcement to the other modules is tracked as HQ-539. Built-in roles: module grants editable, key and label locked. Custom roles: label, description and grants editable; Archive is soft (grants kept, the role stops being grantable or effective).

Loading...

Full matrix - every role side by side (wide; scrolls sideways)
Loading...
This page sets what each role reaches. To change which roles a person holds, go to Users and Roles. The locked floor below stays code-enforced whatever this matrix says.
What cannot be changed here (locked in code) (collapsed by default)

Loading...

Money approval layers

app_settings 'approvals.money_rules' - admin-only, audited

Loading...

Enforced server-side in the RMA money authorisation (G-R3) - management (Administrator or Money authorised) always passes, at any amount, whatever is configured below. A saved change applies from the very next authorisation attempt - no deploy needed. When someone attempts an amount above every layer they hold, the people named in the covering layer get an in-app notification, and the requester is told the attempt needs a higher approval.

Money approval layers (refunds, chargeable warranty invoices, replacements and the default) are real and server-enforced in the card above (HQ-470). The rule builder below is still a preview: nothing there is wired to a server table or gate.
Other approval rules (preview - wired to no server table or gate; collapsed by default)

Other approval rules

Preview - not yet wired to a server table or gate
RuleApproversThreshold / ConditionsEnforced inAction

Rule details

Select a rule to view its approvers and notes.

General settings

Security & access policies

Require 2FA for all staffEnforced at sign-in: staff with no authenticator get a setup step instead of a session
Enforce access server-sideAlways on (data-layer gate)
Not yet wired - "Session timeout" and "Min password length" are RECORDED here but nothing reads them: session life is fixed server-side (7 days, or 30 with "Keep me signed in"), and the password floor is fixed at 12 characters, refused server-side by change-password, accept-invite and the admin password reset. Changing these values changes no behaviour yet.

Workflow defaults

Auto-escalate breached SLAs
Not yet wired - these three are RECORDED here but no gate reads them: case/RMA assignment and approval routing still come from each module's own rules, and no job escalates on an SLA breach. Changing them changes no behaviour yet.

Notifications

In-app notifications
Email notifications
Google Chat alerts
Pending HQ-86 - the notification surface + the Chat webhook secret are still being wired; these toggles persist the preference, the channels light up when HQ-86 lands.

Monitoring & records

Support caseCASE-####
RMA (return, continuous)RMA-#####
CAPA (operations)CAPA-OPS-####
Form / SOP / recordFRM- / SOP- / REG-

Numbering format is fixed server-side (DB triggers) and shown for reference. RMA numbering is continuous and never reused (mirrors _support-numbering.cjs).

Data & backups

DatabaseNeon Postgres (Netlify DB)
Soft-deleteEnabled
Last config backupToday 08:30
Pending HQ-276 - "Run backup now" / export config. Backups are managed by Netlify/Neon; a self-serve trigger needs a server function.

Configuration summary

Active settings-
Pending changes0
Last config backupToday 08:30
Enforced server-sideAlways

Recent changes

View all

Loading...

Shared mailboxes

Gmail sends as the mailbox that authorised it, so a company address such as sales@safiery.com can only be chosen as the From address on a document once that mailbox itself is connected here. An alias is not enough. Connecting one never affects your own personal Gmail connection.

MailboxStatusConnected byLast updated
Loading...

Customer comms rail

app_settings 'comms.*' - admin-only, audited

Where a customer conversation travels while Safiery moves off Intercom. Turning a half off here never deletes anything: the imported Intercom history lives in HQ's own tables and stays exactly where it is.

Off means a reply leaves through Gmail instead, from the mailbox chosen on the case. This half is safe to switch off today.

Reading sales@ and support@ directly is not built yet. Until it is, turning the incoming half off means HQ receives no customer email at all: the inbox poller reads personal mailboxes only, so mail to support@ is never collected, and a first-contact email is not turned into a case. Leave this on until the Gmail-direct path ships.

Email signatures

app_settings 'signature.*' - admin-only, audited

What gets appended when mail leaves through a compose From choice. A person's own signature is theirs to edit (Profile > Email signature); sending as yourself wraps it in the company template below. Sending as a role mailbox uses that mailbox's block. Empty means an honest name-only default, never an invented title or number.

SKU convention

app_settings 'sku.*' - admin-only, audited

Own (Safiery-made) products get a dotted code, checked as it is entered on Inventory's + New item; resale products keep the supplier SKU untouched. A format issue prompts the person entering it and they can still consciously save (flag, don't block); a duplicate SKU is always refused outright. Existing codes are never re-checked or regenerated.

Prompt on new product SKUsOff = no format prompt; the duplicate-SKU refusal always stays on

AI providers

Assistants work only when the system-level keys are configured. Provider keys are held server-side, never in the browser.

Pending HQ-274 - per-provider enable toggles. Provider keys live in server env / a secret store (no front-end secrets); a toggle needs an admin settings write + a server read of which keys are present. Shown read-only.

Data access

Assistants work only when system-level keys are setOn
Sensitive data excluded by defaultAddresses, finance, ACNs
Provider keys held server-sideEnforced
Per-staff connect under own profileAllowed

Admin sets the policy here; each staff member connects their own AI account under their own profile. WooCommerce is retired per CLAUDE.md v2.0 (Xero is the order-of-record); the Woo card is reference-only.

Audit log

WhenUserActionModule / RecordDetail
Loading...

Deleted records

Loading...

Deleting through HQ hides a record but never destroys it. All deletes are soft (deleted_at) and remain in the audit trail for ISO traceability; permanent removal needs a 14-day retention window and a privileged gate (pending HQ-275).

Status

Server kill switch (env)-
Company AI key-
Model-
Hourly cap per visitor-
Chatbot enabledBoth this AND the server env switch must be on
Allow "Talk to a human"Creates a Conversations case (needs_human)

The bot answers ONLY from the knowledge sources below. The env switch and API key are server-side facts (read-only here); flipping the toggle alone cannot enable the bot.

Settings are admin-only; knowledge and review are open to support managers.

Knowledge sources

Reference documents (store)Titles and links only - cited, not quoted. See Reference library below to let the bot read the full text.
Product cataloguePublic fields only - never cost, stock or margins

Source toggles are saved with Save settings. The curated knowledge list below is always on.

Knowledge

Curated entries
Enabled
Documents

Each document is converted to plain text on the server and split into knowledge entries by heading, added to the curated list above. The original file is never stored, and re-ingesting a document with the same title disables its previous entries first.

Reference library

Refresh

The library of manuals, datasheets, wiring guides and certificates is created and tagged on the Reference Docs page. Link one below to let the bot read its full text - split into entries above, exactly like an upload - instead of only citing its title and link.

Unlink disables that document's entries; re-link to pull in a newer version.

Review queue

Show all recent

Test console

Test questions run the REAL engine (logged as mode "test", capped 30/hr per user) but skip the public visitor cap. Works before the public kill switch is on.

Embed on the website

Optional attributes: data-accent takes your brand colour; data-title renames the launcher. The widget fails to a friendly offline note whenever the bot is disabled.

One server prerequisite: the website's origin (e.g. https://safiery.com) must be listed in the CORS_ALLOW_ORIGIN environment variable on this site, or the browser will block the widget's calls. Ask whoever manages the Netlify environment before embedding.

The bot answers only from the knowledge allow-listed here. Money matters (discounts, refunds, pricing promises) are hard-locked to humans server-side; the public endpoint is rate-capped per visitor and fails closed without its env switch and key.

On site now

Visitors and contractors signed in and not yet signed out
NameKindCompanyHostSigned inInduction version
Loading...
This is the non-staff half of the muster list. Staff presence comes from the clock register (the kiosk's own roster screen shows both together) - in an evacuation read the tablet, which counts staff and visitors in one list. A visitor who walks out without signing out stays on this list until someone closes them off, which is the safe failure: the warden looks for a person who has left, never the reverse. If the tiles above show ? the read FAILED - that is not an empty site, so press Refresh rather than trusting it; and if the count says the list was clipped, more people may be on site than are shown here.

Visitor and contractor record

NameKindCompanyHostSigned inSigned outInduction acknowledged
Loading...
The induction version column is the retained safety record: it names the exact document version the person agreed to, stamped by the server at sign-in, never taken from the tablet. Re-publishing the induction below does not rewrite these rows.

Paired tablets

TabletPaired byPairedLast activityStateAction
Loading...
Pairing mints a long-lived device token and shows it once. It is not stored anywhere you can read it back and it is never shown again - paste it into the tablet straight away, and if it is lost, revoke the tablet and pair it again. The token authenticates the tablet only: it can never sign in to HQ, and revoking bumps the device's token version so every outstanding copy dies on its next request.

WHS and Emergency induction

Shown on the tablet to every visitor and contractor before they can sign in
Publishing bumps the version. Everyone currently on site acknowledged the previous version and will not be asked again until they next sign in. Existing records keep the version they agreed to - that is the point of the version, so never edit wording to "correct" an old acknowledgement. Publish a new version instead.

The wording and the version are one record: this editor only ever writes them together, so the text can never change under acknowledgements already recorded against a version. Stored in app_settings under kiosk.whs_induction, which is admin-only server-side (the kiosk. prefix lock in the db function) - a hidden button is not the control.

Work type vocabulary

Read-only here

Loading...

Not signed in on this address - open the main app to sign in, then return.
Checking your session...
The first load after a deploy can take a few seconds while the server wakes up. If this message never goes away, the page script failed to start - press F12, open the Console tab, and photograph what it shows.
Administration failed to load.