Audit Logs now uses a fixed table layout with tuned column widths:
every column fits the card without horizontal scrolling, long entity
names truncate with a hover tooltip, timestamps show a compact
no-seconds form (full value on hover), and the 9-digit user SSO renders
fully.
Removed the Collector service token quick-preset from the create modal
per user preference - the collector.ingest checkbox in the scope grid
is the path now.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 401 interceptor (session expired) redirected to bare /login,
losing the page the user was on - the router guard already preserved
it but the expiry path bypassed the guard. The interceptor now carries
?redirect= like the guard does, and Login returns there.
The API tokens tables overflowed the card: the token column no longer
repeats the shopdb_pat_ prefix per row (short prefix shown, full form
on hover) - the token itself was already never displayed after
creation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A token scoped to the new collector.ingest permission is a collector
service token: the collector endpoints accept it via X-API-Key or
Bearer alongside the env fleet keys (which remain the fallback), giving
the fleet credential rotation, revocation, and last-used visibility
from the API Tokens page. Containment holds both ways: a collector
token authorizes nothing else, and no other credential gains collector
access. Shared token validation refactored out of the auth shim; a
Collector service token quick-preset in the create modal; integration
guide documents minting, rotation via site-config.json, and the
service-identity pattern.
765 tests pass; live acceptance matrix verified.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A token may carry a scopes list: it then grants only those permissions,
intersected with what the owner holds at use time, with the admin role
bypass suspended and role-gated routes denied - a scoped token from an
admin account is genuinely limited. Scope ceiling enforced at
create/update too (only permissions the owner holds; 400 lists
violations) and the picker only offers what you hold. Token management
itself now requires the new apitokens.create permission (admin by
default, grantable via roles). Unscoped tokens keep the exact prior
act-as-owner behavior; imports need an unscoped admin token.
Migration 7d22.
756 tests pass; live-verified scoped 201/403 matrix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
API tokens: any user mints named, optionally-expiring tokens
(shopdb_pat_..., sha256-stored, secret shown once) at Settings > API
Tokens; a before-request shim swaps a valid PAT for a request-scoped
JWT of its owner, so the entire existing auth/authz/import-mode stack
works unchanged and revoked/expired tokens 401 cleanly. Built for
long-running scripts - the legacy import no longer dies when a login
JWT expires. Migration 7d21_apitokens; create/revoke audit-logged.
Audited integration gaps fixed: Asset.to_dict serializes measuring
tools (typedata + pluginid - relationship links to tools resolve); map
subtype filter/colors and MapEditor include them; dashboard totals
count them; warranty links use a new by-asset route; the measuringtools
ADR-010 hooks are real (corrected presentation token, implemented
map-overlay endpoint); the login avatar resolves through the
employee-photo helper.
737 tests pass; naming green; frontend builds; both features verified
live end-to-end.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>