2026-10-07 12:22:57 +00:00
|
|
|
|
# User access
|
|
|
|
|
|
|
2026-10-09 08:16:50 +00:00
|
|
|
|
Named PocketBase sign-in is required in every environment. Shared PIN sign-in
|
|
|
|
|
|
is disabled, even if an old environment file still contains `AUTH_MODE=pin`.
|
2026-10-07 12:22:57 +00:00
|
|
|
|
|
|
|
|
|
|
| Account type | App access | Site scope | User settings |
|
|
|
|
|
|
| --- | --- | --- | --- |
|
2026-10-09 08:16:50 +00:00
|
|
|
|
| Admin | Dashboard, Management, Ask, Clock | All sites | Manage users |
|
2026-10-07 12:22:57 +00:00
|
|
|
|
| Site manager | Operational dashboard and Clock | Assigned sites | Create and list clock accounts within assigned sites |
|
|
|
|
|
|
| Clock user | Clock only: worker/fleet scans and document uploads | Assigned sites | None |
|
|
|
|
|
|
| Office user | Selected dashboard sections with full actions | Assigned sites or All sites | None |
|
|
|
|
|
|
|
2026-10-09 08:16:50 +00:00
|
|
|
|
## Management planning
|
|
|
|
|
|
|
|
|
|
|
|
Management sits below Overview in the navigation. Its Turnover Overview,
|
|
|
|
|
|
Project Planning, Retention and Year Comparison pages require a named admin
|
|
|
|
|
|
account. Operational Site manager accounts and Office accounts have no access,
|
|
|
|
|
|
including those with all sites or every operational section enabled. Future
|
|
|
|
|
|
pages under `/dashboard/management/` inherit this restriction.
|
|
|
|
|
|
|
|
|
|
|
|
The initial data comes from `src/lib/management/workbook-snapshot.json`,
|
|
|
|
|
|
extracted from the supplied turnover workbook. `data.ts` checks access before
|
|
|
|
|
|
loading it; `model.ts` calculates results independently. Replace the provider's
|
|
|
|
|
|
source when connecting the planning database. Never import the snapshot into
|
|
|
|
|
|
a client component or put it in `public/`.
|
|
|
|
|
|
|
|
|
|
|
|
The overview preserves the workbook's reported monthly income and cost
|
|
|
|
|
|
summaries, including its manual values. Project detail remains separate and
|
|
|
|
|
|
the reconciliation shows the differences. All amounts are ZAR. The main plan
|
|
|
|
|
|
follows March–February headings from the workbook titled 2025, without
|
|
|
|
|
|
inventing exact reporting years. Retention releases have their own supplied
|
|
|
|
|
|
November 2025–October 2026 dates. Year Comparison follows the source's actual
|
|
|
|
|
|
January–December 2024 and 2025 columns, including its estimates. There is no
|
|
|
|
|
|
live actuals feed or planning editor yet.
|
|
|
|
|
|
|
2026-10-07 12:22:57 +00:00
|
|
|
|
## Office setup
|
|
|
|
|
|
|
|
|
|
|
|
In Settings · Users, choose Office user, then an access preset (Workforce,
|
|
|
|
|
|
Financial, or Plant) or select sections individually. At least one section is
|
|
|
|
|
|
required. Each section includes its overview, details, imports, corrections,
|
|
|
|
|
|
and future pages under the same section. Selecting several sections gives the
|
|
|
|
|
|
user all of those sections. Overview is the company dashboard overview;
|
|
|
|
|
|
Workforce's own overview is included with Workforce.
|
|
|
|
|
|
|
|
|
|
|
|
Choose All sites for head-office work spanning the company. This includes new
|
|
|
|
|
|
sites automatically. Turn it off to select specific sites. Site lookup names
|
|
|
|
|
|
and the site selector still work within enabled sections; this does not grant
|
|
|
|
|
|
access to the Sites management section. Ask and user administration remain
|
|
|
|
|
|
unavailable to Office users.
|
|
|
|
|
|
|
|
|
|
|
|
For Julius, after deploying this version, edit his existing account:
|
|
|
|
|
|
|
|
|
|
|
|
- Account type: Office user.
|
|
|
|
|
|
- Preset: Workforce (only Workforce selected).
|
|
|
|
|
|
- Site scope: All sites if his remit covers the company; otherwise select his sites.
|
|
|
|
|
|
|
|
|
|
|
|
He starts on Workforce overview and sees Workers, Timesheets, and On site now.
|
|
|
|
|
|
Worker details, rates, sick notes, calendars, timesheet imports/upload status,
|
|
|
|
|
|
and missed-clock-out corrections inherit Workforce access. Other section URLs
|
|
|
|
|
|
redirect him to his first enabled section, and other section APIs return 403.
|
|
|
|
|
|
|
|
|
|
|
|
## Schema rollout
|
|
|
|
|
|
|
|
|
|
|
|
Existing account roles, passwords, and sites are preserved. The additive
|
|
|
|
|
|
migration adds `office_user` to `users.role`, multi-select `users.modules`
|
|
|
|
|
|
(`overview`, `sites`, `workforce`, `plant`, `financial`), and Boolean
|
|
|
|
|
|
`users.all_sites`. Existing non-office accounts retain their role defaults;
|
|
|
|
|
|
office fields do not grant extra access to clock or site-manager accounts.
|
|
|
|
|
|
|
|
|
|
|
|
Run the dry run against the configured PocketBase environment:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 scripts/migrations/2026-10-07-office-access.py --env-file .env.local
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Apply before deploying Office user settings, passing the exact URL printed by
|
|
|
|
|
|
the dry run as `--confirm-host`:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
python3 scripts/migrations/2026-10-07-office-access.py --env-file .env.local --apply --confirm-host "$POCKETBASE_URL"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
This changes only the users collection fields. It does not convert Julius or
|
|
|
|
|
|
any other existing account. Convert accounts after deploying, because the old
|
|
|
|
|
|
app rejects the new Office user role.
|
|
|
|
|
|
|
|
|
|
|
|
## Extending sections
|
|
|
|
|
|
|
|
|
|
|
|
`src/lib/auth/path-access.ts` is the shared page/API policy used by the proxy,
|
|
|
|
|
|
navigation, and operation guard. New nested pages inherit their section root.
|
2026-10-19 14:33:41 +00:00
|
|
|
|
Workforce employee, employer/broker and `/api/workforce/` routes inherit
|
|
|
|
|
|
Workforce access. Unknown API routes remain admin-only until assigned an
|
|
|
|
|
|
explicit category.
|
|
|
|
|
|
|
|
|
|
|
|
**A new `/api/...` route is invisible to site managers until it is named in
|
|
|
|
|
|
`src/lib/auth/proxy-path.ts`.** The proxy runs before the route handler, so an
|
|
|
|
|
|
unclassified API path falls through to the admin-only default and the handler's
|
|
|
|
|
|
own `requireApiUser` / `canAccessSite` checks never run. Symptom: an admin
|
|
|
|
|
|
succeeds, a site manager gets `{"error":"Not allowed"}` (403) from the proxy,
|
|
|
|
|
|
and the route's own tests still pass because they mock the guard. Name the
|
|
|
|
|
|
route in `classifyAuthPath` and map it to a module in `moduleForPath` in the
|
|
|
|
|
|
same change. `npx vitest run src/lib/auth` covers the policy.
|
2026-10-07 12:22:57 +00:00
|
|
|
|
|
|
|
|
|
|
Use `getSiteScope(searchParams, "workforce")` (or the relevant section) before
|
|
|
|
|
|
loading page data, and `requireApiUser("workforce")` in its handlers. Shared
|
|
|
|
|
|
operation routes use `authorizeOperation(request)` plus record/site checks.
|
|
|
|
|
|
The only Financial handlers permitting clock accounts are document uploads
|
|
|
|
|
|
and purchase-order upload status/retry; new dashboard operations must not use
|
|
|
|
|
|
`allowClock: true`.
|