7.4 KiB
tools-app Specification
Purpose
Host the YOUreka tools web front-end: a landing page linking the Image Cropper and the Fingerprint Agent wizard, YOUreka Auth cookie-session login, and same-origin proxies to the a2loft identity API so browser calls never carry operator credentials directly to third parties.
Requirements
Requirement: Landing page links the YOUreka tools
The app SHALL serve a landing page at / containing links to the Image
Cropper (/cropper) and to the Fingerprint Agent page (/fingerprint).
Scenario: Landing page renders both tool links
- WHEN a user opens the app root URL
- THEN the page shows a link to the Image Cropper pointing at
/cropperand a link to/fingerprint
Requirement: YOUreka Auth login establishes a cookie session
The app SHALL authenticate operators through the YOUreka portal web-auth
flow: create a web auth session at the portal with a local callback URL,
redirect the operator to the portal's login URL, and on callback redeem the
returned session id for a PocketBase session cookie. The app SHALL persist
the PocketBase cookie value under its own httpOnly session cookie (30-day
max age) together with the operator's profile (first name, last name,
phone).
Scenario: Successful login round-trip
- WHEN the operator completes the portal login and returns with a redeemable session id
- THEN the app sets the
sessionand profile cookies and redirects to/fingerprint
Scenario: Expired or rejected login link
- WHEN the callback session id cannot be redeemed (expired, timed out, or incomplete verification)
- THEN the app shows an authentication error and does not set a session cookie
Requirement: Session persistence and refresh
The app SHALL recover the operator's PocketBase session from the session
cookie on every request, refreshing the token when it is invalid or expires
within 5 minutes, and SHALL persist the refreshed cookie value. When the
session cannot be recovered, the app SHALL treat the operator as anonymous
and clear the stale cookie.
Scenario: Refresh near expiry
- WHEN a request arrives with a session cookie whose token expires within 5 minutes and the portal accepts a refresh
- THEN the app serves the request with the refreshed token and updates
the
sessioncookie
Scenario: Unrecoverable session
- WHEN the stored token is expired and refresh fails
- THEN the request is treated as anonymous and the stale cookie is cleared
Requirement: Protected pages require a session
The app SHALL redirect anonymous operators to the login flow when they request the Fingerprint Agent page, and SHALL return an authentication error for session-requiring API calls made without a session.
Scenario: Anonymous access to the wizard page
- WHEN an operator without a valid session requests
/fingerprint - THEN the app redirects them to the login flow
Requirement: Session endpoint exposes capture context
The app SHALL expose a session endpoint that, for an authenticated operator, returns the current PocketBase token, the operator's phone and name, the fpagent URL, the list of permitted domains (see the fingerprint-wizard capability for the checking and caching rules), and the time that set was last checked.
Scenario: Authenticated session fetch
- WHEN an authenticated operator fetches the session endpoint
- THEN the response includes their token, phone, name, the fpagent URL, the permitted domains, and the time the set was last checked
Requirement: Forced domain re-check endpoint
The app SHALL provide a force-refresh endpoint that, for the authenticated operator, re-checks every catalog domain against the portal verify endpoint bypassing the cache, replaces the cached result, and returns the updated permitted-domain list with the new last-checked time. It SHALL refuse the request while the 5-minute cache is still fresh, without contacting the portal.
Scenario: Force-refresh after the cache elapses
- WHEN the cache period has elapsed and the operator's client calls the force-refresh endpoint
- THEN every catalog domain is re-checked, the cache is replaced, and the response carries the updated list and last-checked time
Scenario: Force-refresh refused while the cache is fresh
- WHEN the force-refresh endpoint is called within 5 minutes of the last check
- THEN the request is refused with an error and no portal calls are made
Requirement: a2loft proxies inject operator identity
The app SHALL proxy staff lookup and fingerprint-save calls to
https://apis.a2loft.net under same-origin API routes. The proxy SHALL
attach the operator's phone from the server-side session and forward the
OTP supplied by the page as query parameters (phone, otp), preserving
the a2loft request and response shapes. The proxies SHALL require a
session; the OTP SHALL NOT be accepted without one.
Scenario: Staff lookup via proxy
- WHEN the page requests staff details for a domain and reference with an OTP
- THEN the app calls a2loft's identity endpoint with the operator's phone from the session and the supplied OTP, and returns a2loft's response unchanged
Scenario: Unauthenticated proxy call rejected
- WHEN a proxy route is called without a valid session
- THEN the app rejects the call without contacting a2loft
Requirement: Configuration is hardcoded
The app SHALL hardcode all configuration in source: port 4173, portal
https://portal.yrka.app, PocketBase https://pb.itcass.net, a2loft
https://apis.a2loft.net, agent http://127.0.0.1:9000, and the fingerprint
agent release forge https://sources.yrka.app. There SHALL be no runtime
configuration via environment variables or config files, with two exceptions:
the Image Cropper's service credentials (Minio keys, Azure storage connection
string, nodered credentials, cleanup-service key) SHALL come from environment
variables and SHALL NOT be stored in source; and the Fingerprint Agent
installer's release key (GITEA_RELEASE_INSTALL_KEY) SHALL come from the
environment and SHALL NOT be stored in source.
Scenario: No configuration required to run
- WHEN the app is started with no environment variables or config files
- THEN it serves on port 4173 with the hardcoded external endpoints
Scenario: Cropper credentials from the environment
- WHEN the cropper credentials are supplied as environment variables
- THEN the cropper routes use them without any change to the hardcoded URL/port configuration
Scenario: Installer key from the environment
- WHEN the fpagent installer release key is supplied as an environment variable
- THEN the installer and release-proxy routes use it without any change to the hardcoded URL/port configuration
Requirement: Carbon Design System UI
The tools pages SHALL be built on the Carbon Design System: Carbon web components (version-pinned via CDN) for buttons, notifications, toasts, tags, progress and tiles; Carbon-styled native form controls; IBM Plex Sans typography and Carbon color tokens for layout. Errors, confirmations and successes SHALL surface as Carbon notifications rather than ad-hoc alert dialogs.
Scenario: Pages render with Carbon components
- WHEN any tools page is opened
- THEN its interactive controls are Carbon components (or Carbon-styled native controls) and its notifications render as Carbon notifications