# PRD — unity-soft-ui (Unity Soft / UnityLite)

Evidence date: 2026-09-30. Source: `https://bitbucket.org/overdrive/unity-soft-ui.git`, `main` `afdeab6` (2022-01-24).

Provenance labels: **Documented**, **Implemented**, **Inferred**, **Planned**, **Unknown**.

No formal PRD existed in the repository or in `silicon_ark/unity-soft-ui/` before this file. Requirements below are recovered from the React screens, the route table, and the Amplify calls. They are not a new product decision.

Identifier values in `src/aws-config.js` are omitted. The login form's initial email and password literals are omitted. The files that hold them are named where the behaviour depends on their presence.

## Product purpose

A person opens a web app titled **UnityLite**. The shell brands itself **Unity Soft**. They can browse a set of pages as a guest. To be treated as signed in they use email and password against Amazon Cognito, after which the app stores a role string and a user payload in `localStorage` and sends them to `/`.

**Implemented** in `public/index.html`, `src/components/common/Navbar/TopNav.js`, and `src/components/Login.js`. The README calls the project "Unity - Soft UI" and says it uses Amplify / lambda. The Lambda code is not in this repository. Provenance of the Lambda claim: **Documented** in `README.md` only.

Three names are in the tree and they are not the same string: page title `UnityLite`, brand `Unity Soft`, package name `role-based-access-control`. Which name is the product name is **Unknown / Requires Confirmation**.

## Users and roles

`src/config/Roles.js` defines five role strings and comments that they are "placeholder roles you can replace". Provenance of the list: **Implemented**. Provenance of "placeholder": **Documented** in that comment.

| Role | Where it is allowed | What the code actually distinguishes | Provenance |
|---|---|---|---|
| `GUEST` | Default when `localStorage.roles` is null. Every route except Profile, and only this role may open Login, Register, and Forgot Password | Unauthenticated browser | **Implemented** |
| `CUSTOMER` | Every route except Login, Register, and Forgot Password, including Profile | Not distinct from ADMIN or MANAGER in the route table | **Implemented** permission list. Distinct behaviour is **Unknown** |
| `MANAGER` | Same as CUSTOMER | Same | **Implemented** |
| `ADMIN` | Same as CUSTOMER | Same | **Implemented** |
| `SUPER_ADMIN` | Same as CUSTOMER | Same | **Implemented** |

`getAllowedRoutes` (`src/utils/index.js`) keeps a route when `lodash.intersection` of the route's `permission` array and the parsed `roles` value is non-empty. Routes with a missing or empty `permission` are kept for everyone.

Signed-in state is **not** a Cognito session check. `isLoggedIn()` returns true when `localStorage` has a `roles` key. Provenance: **Implemented**, and the function comment says the app "assume[s] if local storage have roles it means user is authenticated".

What the API field `strRole` contains (one name, or a JSON array of names) is **Unknown / Requires Confirmation**. Login stores it with `localStorage.setItem('roles', body.data.strRole)` and does not `JSON.stringify` it. Route filtering then `JSON.parse`s that value. If `strRole` is not already a JSON array string, `JSON.parse` throws and the route tree does not render. **Inferred** from those two call sites. Not executed in a browser for this document.

## Major workflows

### 1. Open the app

Trigger: browser loads the CRA bundle (`src/index.js`).

Behaviour:

- Amplify is configured for Auth (Cognito, `mandatorySignIn: true`), Storage (S3 bucket `unity-lite-files`), and an API endpoint named `unity`. Region in config is `eu-west-1`. Ids live in `src/aws-config.js`.
- `serviceWorker.unregister()` runs. The manifest in `public/manifest.json` (`short_name` "Unity Soft", `display` standalone) is linked, but the service worker is not registered.
- `App` wraps the tree in `BrowserRouter`, MUI `StyledEngineProvider` and `ThemeProvider`, and `CssBaseline`.
- `routes/index.js` builds the allowed route list from `RoutingConfig` and the current `roles` value.
- `MapAllowedRoutes` renders `TopNav`, a `Switch` of exact routes, `Footer`, and a `PopupModalProvider`. Unknown paths render `NotFound`.
- On `/`, the page contents element receives class `shortFooter`. Other paths remove it.

Output: the shell and whichever routes the role filter kept. A guest sees Home, Calendar, Tasklist, Users, Config, Dashboard, Login in the nav (those have `canNavigate: true`). Terms is footer-only (`canNavigate: false`, `showInFooter: true`). Register and Forgot Password are not in the nav; Login links to them.

`App.js` passes `history` from `src/utils/history.js` into `BrowserRouter`. React Router DOM v5 `BrowserRouter` does not use a `history` prop (that prop belongs to `Router`). **Inferred**: the custom history object is unused. Not executed for this document.

### 2. Sign in

Trigger: Login button on `/login`, `handleSubmit` in `src/components/Login.js`.

Inputs: email, password. The component's initial state already contains an email and a password literal. Those values are omitted here. Whether that default is intentional is **Requires Confirmation**. It is **Implemented**.

Validation:

- Email blank → "Cannot be blank!".
- Email failing `validateFieldType(..., "Email")` → "Email is invalid!".
- Password blank → "Cannot be blank!".
- No other password rule is applied in this file.

Behaviour when validation passes:

- `Auth.signIn(email, password)`.
- If `response.attributes.email_verified` is not true, a modal says the email is not verified and offers a redirect to `/register?verify=<email>`.
- If verified, `API.get('unity', '/user/details?strCognitoUuid=<cognito username>')`.
- When `body.result === true`, the payload is stored: `roles` = `payload.data.strRole`, `userDetails` = the payload via `useLocalStorage`, `IDNumbers` = a JSON array of `data.strIdNumber` plus each `additionalIds[].strIDNumber` that is non-empty. After 100 ms the app navigates to `/`.
- When `body.payload === "User does not exist"`, a details modal collects name, surname, cellphone, and an id number, then `API.post('unity', '/register', ...)` with `strCognitoUuid`, `strName`, `strSurname`, `strEmail`, `strIdType`, `strIdNumber`, `strMobileNumber`. Success closes the modal and does not itself navigate home. The button label path sets `setIsLogingIn(false)` only. **Implemented**. Whether the person must click Login again is **Inferred** from the absence of `history.push` in `handleDetailsProceed`.

Errors:

- Cognito `NotAuthorizedException` → popup "Incorrect email or password".
- Any other thrown error → popup `error.message`.
- Validation errors stay on the form. `isinvalid` is passed as a string `"true"` / `"false"` on React-Bootstrap `Form.Control`. Whether Bootstrap treats that as the `isInvalid` prop is **Inferred** to fail, because the prop name in this library is `isInvalid`. Not executed for this document.

The route `/login` has `permission: [GUEST]` only. After a successful login the role list no longer includes the guest default, so Login drops out of the allowed routes. **Implemented**.

### 3. Register

Trigger: `/register`, or the unverified-email redirect `/register?verify=<email>`.

Inputs: email, name, surname, cellphone, id type, id number, password, confirm password. On the verify query, the email is prefilled and the code step is shown immediately (`Register.js` reads `window.location.search` during render).

Validation: same field rules as the login details modal, plus password non-blank and confirm must match. Password complexity beyond non-blank is not checked here. Cognito's pool policy is **Unknown**.

Id type options:

| Code | Label | Client check |
|---|---|---|
| `02` | RSA ID Number | 13-digit shape plus a mod-10 check digit (`validateFieldType` / `mod10CheckDigit`) |
| `03` | Foreign ID Number | Function returns `true` for any value that reached it |
| `04` | Business Registration | Function returns `true` for any value that reached it |

Behaviour:

- `Auth.signUp` with username = email, password, and attribute email.
- `UsernameExistsException` is written onto the email error. Other errors open the popup.
- `isMultifactor` is hardcoded `true`, so the next screen is the verification code, not the success panel. The comment says to set the flag when Cognito MFA is enabled. The code that runs is `Auth.confirmSignUp`, then `Auth.signIn`, then the user-details lookup. **Inferred**: the flag gates email confirmation, not a separate MFA challenge. **Documented** intent in the comment disagrees with that.
- After confirmation, the client loads `/user/details` twice (by Cognito uuid and by email). If the email lookup payload is `"User does not exist"`, it POSTs `/register` through `unityRequests`. Otherwise, if either lookup has `result === false`, it POSTs `/updateregistration` with `strCognitoUuid` and `strEmail`. Then it shows "Your account registration has been submitted" and a link to `/login`.
- "Didn't get an email?" calls `Auth.resendSignUp`. Success popup: "New invite sent!".

The submit line says: By clicking Submit you agree to **Paymyfines.com**'s Terms and Conditions and Privacy Policy. The modals say "A whole bunch of terms" and "A whole bunch of policies". The shell brand is Unity Soft, not Paymyfines. Provenance: **Implemented** copy. Whether this product is Paymyfines is **Unknown / Requires Confirmation**.

`/register` permission is `[GUEST]` and `canNavigate` is false.

### 4. Reset a password

Trigger: `/forgot-password`, linked from Login. Permission `[GUEST]`, not in the nav.

Inputs: email and confirm email, then a code and a new password plus confirm.

Validation: emails non-blank, email passes the Email pattern, emails must match ("Emails must match!!"). Code non-blank. Passwords non-blank and must match ("Passwords must match!!").

Behaviour: `Auth.forgotPassword(email)`, then `Auth.forgotPasswordSubmit(email, code, password)`. Success replaces the form with a check-circle message (the confirmed branch in the same file). Failures open the popup with `error.message`.

### 5. Sign out

Trigger: Logout in the nav, only when `isLoggedIn()` is true (`TopNav.js`).

Behaviour: `Auth.signOut()`, then `deleteFromStorage('roles')` and `deleteFromStorage('userDetails')`, then `history.push('/')`. `IDNumbers` is not removed. **Implemented**. **Inferred** consequence: a later session on the same browser still has the previous id list until login overwrites it.

Errors are logged and do not show the popup.

### 6. Use the calendar

Trigger: `/calendar`. Allowed for every role including `GUEST`.

Behaviour (`src/components/Calendar.js`):

- FullCalendar month view, with week and day buttons, editable and selectable, weekends on by default. A checkbox toggles weekends.
- Sidebar text tells the person to select dates to create an event (a `prompt` asks for a title), drag or resize events, and click an event to delete it (`window.confirm`).
- When the visible range changes, the client POSTs `/unity/getcalendarevents/` with `userID: getUserDetails().userID`, `dtStartDate`, `dtEndDate`. It expects `{body}` to be a JSON string of rows, then maps `CalendarIDitem`, `txtDescription`, `txtNotes`, `dtStartDate`, `dtEndDate`, `strFirstUser`, `refSysUserID`.
- Add POSTs `/unity/addcalendarevent/` and sets the event id from `body.id`. Change POSTs `/unity/updatecalendarevent/`. Remove POSTs `/unity/removecalendarevent/`. A thrown error calls `revert()` on add, change, and remove.

`unityRequests` returns the Amplify result directly. Callers destructure `{body}`. If the API JSON has no `body` property, `body` is undefined and `JSON.parse` throws, which this screen catches and logs. **Inferred** mismatch. The response shape is **Unknown / Requires Confirmation**.

`getUserDetails()` parses `userDetails`. Login stores the details payload, whose shown fields are under `.data` (`strRole`, `strIdNumber`) in the login success branch. Calendar reads `.userID` and `.userName` on the top-level object. **Inferred**: those properties are absent unless the payload also has them. **Requires Confirmation** against a real payload.

A guest has no `userDetails`. `getUserDetails()` then `JSON.parse(null)` and the calendar load throws. The catch logs it and leaves `currentEvents` empty. **Inferred** from the guest default and `getUserDetails`. The route still allows `GUEST`.

### 7. View users

Trigger: `/users`.

Behaviour: on mount, POST `/unity/getusers/1` via `unityRequests`, `JSON.parse(body)`, render a react-table with columns Name (`strUser`), Contact (`strTel`), Job (`strJobTitle`), Role (`strRole`), Email (`strEmail`), Location (`strLocation`), and an EDIT link to `/app/user/<UserID>` carrying `data: UserID`.

`/app/user/:id` is not in `RoutingConfig`. The link renders `NotFound`. **Implemented** link, **not** a destination. `makeData(20)` is computed and unused; the table's `data` prop is `users`.

`useEffect`'s second argument is the boolean `isLoggedin`, not an array. **Inferred**: React will warn or throw because the dependency argument must be an array. Not executed for this document.

### 8. View the dashboard

Trigger: `/dashboard`.

Behaviour: `Dashboard.js` sets `graphsArr` from a literal payload (not from the API). Types used: `PieGraph`, `StackGraph`, `RadarGraph`, `CounterGraph`. Titles include "Ratio of vehicles", "Total Traffic over time", "Total Cars", "Total Bikes", "Total Trucks", "Total Pedestrians", "Total Onions", "Total Spaghett". Counter graphs sit in one grid; the others in a second. Empty arrays render "No Graphs Available". A `showPreloader` flag is set and cleared and is not read by the JSX. **Implemented** sample. Whether live traffic data was ever intended is **Unknown**. The last commit message is "add more example data".

`Graphs.js` can also render `LineMarkGraph`, `VerticalBarGraph`, `RadialBarGraph`, `AreaGraph`, and `ScatterGraph`. Unknown types render "Unknown Graph Type". Empty `data.length` renders "No Data". For non-counter charts it coerces numeric-looking series values with `Number(...)`. That coercion is the "graph data sanitization" commit (`5b33ed4`). **Implemented**.

### 9. Open profile

Trigger: `/profile`. Hidden from `GUEST`. The nav label is the signed-in `userDetails.data.strName`, truncated to 22 characters plus `...`.

Behaviour: POST `/unity/getdetails` with `{id: location.data}`. `location.data` is set only when some other screen navigates with a `data` field. The Users EDIT link uses `/app/user/...`, not `/profile`, so opening Profile from the nav does not pass an id. **Inferred**: the request id is undefined on the normal nav path.

The form shows Company disabled with default value "Silicon Overdrive"; username, first name, last name, and address all bound to `user.strUser`; email `user.strEmail`; city, country, and postal code all bound to `user.strLocation`; About Me default "I am definitly a person and not a robot"; a multi-select of the five role names held only in component state. Update Profile is `type="submit"` with no `onSubmit` handler that calls the API. Social buttons call `preventDefault`. **Implemented** as a display form. Saving is **not implemented**.

### 10. Other routed pages

| Path | Screen | Behaviour |
|---|---|---|
| `/` | `LandingPage.js` | Card titled "Landing Page" and the sentence "Wow Such landing page..." |
| `/tasklist` | `Tasklist.js` | Two hardcoded tasks, one of which is "Work on Language changes for SAWIS". Add Task toggles a form. Save Task is `type="submit"` and does not append to `tasks` or call an API. Star and priority checkboxes update local booleans shared by every row |
| `/configer` | `Configer.js` | Expects a `children` prop, filters it, and nests another `MapAllowedRoutes` at base path `/app/configer`. The parent route renders `<Component/>` with no children. **Inferred**: `getAllowedRoutes(undefined)` throws when this page opens. The route path is `/configer`, not `/app/configer` |
| `/staff` | `Staff.js` | Jumbotron title "Staff" only. Declared as a child of Config and also pushed onto the top-level route list by `MapAllowedRoutes`, so the path is `/staff` |
| `/cronjobs` | `CronJobs.js` | Jumbotron title "CronJobs" only. Same child-flattening as Staff |
| `/termsAndConditions` | `TermsAndConditions.js` | Jumbotron title only. Footer link. Not the register-page terms modal |

SAWIS is a string inside sample task copy. It is not evidence of a SAWIS integration. **Unknown** whether that product is in scope.

## Functional requirements

### FR-001 — Guest shell

Requirement: A browser with no `roles` key in `localStorage` is treated as `GUEST` and can open every configured route except Profile, Login-only pages aside.

Who: anonymous visitor.

Trigger: first load, or after logout removes `roles`.

Inputs: none.

Expected behaviour: nav links for Home, Calendar, Tasklist, Users, Config, Dashboard, Login. Footer includes those with `showInFooter: true` plus Terms and Conditions.

Output: the matching screen, or `NotFound` for any other path.

Validation: none.

Error: a throw inside a screen is not given an error boundary in `App.js`. **Implemented** absence.

Evidence: `src/utils/index.js`, `src/config/RoutingConfig.js`, `src/routes/MapAllowedRoutes.js`.

Implementation: Implemented.

Confidence: High.

### FR-002 — Cognito sign-in and local session

Requirement: Email and password are sent to Cognito. A verified user with `result === true` from `/user/details` is stored locally and sent to `/`.

Who: person on `/login`.

Trigger: Login button.

Inputs: email, password. Cognito username used afterwards is `response.username` (the uuid), not the email, for the details query.

Expected behaviour: as workflow 2.

Outputs: `localStorage` keys `roles`, `userDetails`, `IDNumbers`. Navigation to `/`.

Validation: blank checks and the Email pattern.

Error: popup for Cognito failures. Unverified email offers `/register?verify=`.

Evidence: `src/components/Login.js`, `src/index.js`.

Implementation: Implemented. The shape of `strRole` **Requires Confirmation** (see Users and roles).

Confidence: High for the call sequence. Medium for a successful route refresh, because it depends on `strRole` parsing.

### FR-003 — Register and attach a Unity user

Requirement: Sign-up creates a Cognito user, confirms the emailed code, then either creates or links a Unity user.

Who: guest on `/register`.

Trigger: Submit, then Confirm Code.

Inputs: identity fields in workflow 3.

Expected behaviour: `Auth.signUp`, `Auth.confirmSignUp`, `Auth.signIn`, then `/register` or `/updateregistration`.

Outputs: success copy and a login link. This flow does not write `roles` itself.

Validation: field rules in workflow 3. Foreign id and business registration are not checked beyond non-blank.

Error: username-exists on the email field; other errors in the popup; resend uses "New invite sent!" or "Error resending invite".

Evidence: `src/components/Register.js`, `src/utils/index.js` `validateFieldType`.

Implementation: Implemented.

Confidence: High for the client sequence. The branch between create and update depends on API payload text `"User does not exist"`.

### FR-004 — Password reset

Requirement: A guest can request a Cognito reset code and set a new password.

Who: guest.

Trigger: `/forgot-password`.

Inputs: email twice, then code and new password twice.

Expected behaviour: `Auth.forgotPassword` then `Auth.forgotPasswordSubmit`.

Outputs: confirmed state in the page. No navigation is coded after success.

Validation: workflow 4.

Error: popup with the Cognito message.

Evidence: `src/components/ForgotPassword.js`.

Implementation: Implemented.

Confidence: High.

### FR-005 — Logout

Requirement: Logout ends the Cognito session and clears `roles` and `userDetails`.

Who: a browser for which `isLoggedIn()` is true.

Trigger: Logout link.

Inputs: none.

Expected behaviour: workflow 5. `IDNumbers` remains.

Outputs: nav returns to the guest set after navigation re-reads `roles`.

Error: console only.

Evidence: `src/components/common/Navbar/TopNav.js`.

Implementation: Implemented.

Confidence: High.

### FR-006 — Calendar events

Requirement: The calendar loads, creates, updates, and deletes events for a date range through the `unity` API.

Who: any role the route allows, including guest. The request includes `getUserDetails().userID`.

Trigger: opening `/calendar`, changing the visible range, selecting a range, dragging, or confirming delete.

Inputs: prompt title; start and end from FullCalendar; user fields from `userDetails`.

Expected behaviour: workflow 6. Failed mutations revert the calendar change.

Outputs: events on the calendar and in the sidebar list.

Validation: empty title does not add an event (`if (title)`). No other validation.

Error: logged; load failure leaves the previous or empty list.

Evidence: `src/components/Calendar.js`, `src/components/unityRequests.js`.

Implementation: Implemented client. API contract **Requires Confirmation**.

Confidence: Medium.

### FR-007 — User list

Requirement: `/users` shows a table of users from `/unity/getusers/1`.

Who: any allowed role.

Trigger: opening the page.

Inputs: none beyond the fixed path segment `1`. What `1` means is **Unknown**.

Expected behaviour: columns listed in workflow 7.

Outputs: HTML table. EDIT does not open an editor that exists in this repo.

Validation: none.

Error: logged; table stays empty.

Evidence: `src/components/Users.js`.

Implementation: Implemented fetch and table. Edit destination is not implemented.

Confidence: Medium, because of the `{body}` destructure and the `useEffect` dependency.

### FR-008 — Dashboard charts

Requirement: `/dashboard` shows the sample chart payload through `Graphs`.

Who: any allowed role.

Trigger: opening the page.

Inputs: none. Data is in the component.

Expected behaviour: counters and three charts as in workflow 8.

Outputs: Recharts output, or "No Graphs Available".

Validation: numeric coercion inside `Graphs.js` for series fields.

Error: unknown `GraphType` renders "Unknown Graph Type" inside `Graphs`, not on this page's sample set.

Evidence: `src/components/Dashboard.js`, `src/components/common/Graphs.js`.

Implementation: Implemented as sample data.

Confidence: High.

### FR-009 — Profile display

Requirement: `/profile` is hidden from guests and shows an edit form. The nav item title is the stored first name.

Who: a role other than the guest default. The permission list is the four non-guest roles.

Trigger: nav link.

Inputs: `location.data` as the id, when present.

Expected behaviour: load `/unity/getdetails`. Update Profile does not call the API.

Outputs: form fields as in workflow 9.

Validation: none on this form.

Error: logged; form shows empty values.

Evidence: `src/components/Profile.js`, `RoutingConfig.js`.

Implementation: Load is implemented. Save is not.

Confidence: Medium.

### FR-010 — Route and footer visibility

Requirement: `canNavigate` controls the nav. `showInFooter` controls the footer. Child routes of Config are flattened into the switch at their own `path`.

Who: whoever passed the role filter.

Trigger: every page render.

Inputs: the filtered route array.

Expected behaviour: Config's children Staff and Cron Jobs are addressable at `/staff` and `/cronjobs`. Profile uses the username as its nav label when `useUsername` is true.

Outputs: links.

Validation: none.

Error: if `PageContents` is missing, the scroll effect in `MapAllowedRoutes` throws when it reads `classList`. **Inferred** only if the layout markup changes. The layout does include `PageContents`.

Evidence: `src/routes/MapAllowedRoutes.js`, `TopNav.js`, `Footer.js`.

Implementation: Implemented.

Confidence: High.

## Integrations

| System | Purpose | Trigger | Direction | Auth | Response the client expects | Failure |
|---|---|---|---|---|---|---|
| Amazon Cognito | Sign-in, sign-up, confirm, resend, forgot password, sign-out | Auth screens and Logout | Client → Cognito via Amplify | User pool in `src/aws-config.js`. `mandatorySignIn: true` is set; route guarding uses `localStorage`, not this flag | Cognito user with `username`, `attributes.email_verified` | Popup or inline email error |
| API Gateway, Amplify name `unity` | User details, register, calendar, user list, profile | After auth and on those screens | Client → HTTPS API | Amplify attaches the Cognito session when a session exists. `unityRequests` calls `Auth.currentSession()` and does not await or pass the result | Login expects `{result, payload}`. Other screens expect `{body}` as a JSON string. These shapes disagree. **Requires Confirmation** | `console.log`; calendar mutators revert |
| Amazon S3 | Bucket `unity-lite-files` is configured, `MAX_ATTACHMENT_SIZE` 5000000 | App start configures Storage | Config only | Identity pool id in `src/aws-config.js` | No `Storage.get` / `Storage.put` call was found under `src/` | Not applicable in this tree |
| Google fonts, Material Icons, unpkg Leaflet 1.7.1 CSS | Linked from `public/index.html` | Page load | Browser → those hosts | None | Stylesheets | A failed stylesheet does not stop the app. No Leaflet map component was found. The CSS link is **Unknown** leftover |
| SonarScanner | `sonar-scanner.bat` launches the CLI from `C:\sonar-scanner` | Manual on a Windows machine that has that install | Local process | Not in the bat file | Scanner's own process | Bat exits 1 when Java is missing |

Footer mail links use `helpme@please.com` for both "Enquiries" and "Other Enquiries". Provenance: **Implemented** placeholder copy. It is not evidence of a monitored mailbox.

## Important constraints

- This repository cannot be operated as a closed system. User and calendar behaviour depends on Cognito and the `unity` API, whose server code is elsewhere.
- Role names in `Roles.js` are commented as placeholders. The route table does not encode a stricter permission model.
- `localStorage` is the session flag. Clearing it is enough for the UI to become a guest even if a Cognito session remains, and the reverse is also true: a leftover `roles` value marks the UI signed in without a fresh `Auth.signIn` on that page load. **Inferred** from `isLoggedIn` and the absence of a startup `Auth.currentSession` check in `App.js`.
- RSA id checks are client-side only. Foreign id and business registration accept any non-blank string.
- No server-side rendering, no database migrations, and no background worker exist in this repo. Cron Jobs is a title.

## Requirements discovered from implementation that are not written down as requirements

- Sample dashboard figures, including "Total Onions" and "Total Spaghett", ship in `Dashboard.js`.
- Task copy mentions SAWIS. No SAWIS client exists in the repo.
- Register legal copy names Paymyfines.com while the chrome says Unity Soft and the profile company field says Silicon Overdrive.
- Login's initial state includes a real-looking email and a password. Values omitted. **Requires Confirmation** that this should be removed.
- `Quotes.js` repeats the users table and is not routed. `Timesheet.js` is a jumbotron and is not exported from `src/components/index.js`. `Pivot.js` and a large pivot-table port (`Utilities.js`, `PivotTable.jsx`, `TableRenderers.jsx`, `PlotlyRenderers.jsx`) are not referenced by a route. `RoutingConfig.js` imports `PivotTable` and does not use it. `ExportableTable.js` implements search, formatted-column search, column sums, and CSV download, and no route renders it. `WYSIWYG.js` (TinyMCE) is exported and unused by the screens above.

## Planned behaviour

The only written forward-looking text is the README TODO: Soft UI work, styling, and documentation. Soft UI and styling commits already exist, so that TODO is not a reliable backlog. No issue tracker lives in the repo. Further planned work is **Unknown**.
