# Technical documentation — unity-soft-ui

Evidence date: 2026-09-30. Source revision: `main` `afdeab6` (2022-01-24).

Identifier values in `src/aws-config.js` (user pool id, app client id, identity pool id, API Gateway hostname) are omitted. Behaviour that depends on them is described by naming that file.

## What this repository is

A client-only Create React App. It does not contain a database, an HTTP server, or the Lambda handlers the README mentions. The runnable unit is the React bundle. Amazon Cognito and an API Gateway stage front the data.

Package name: `role-based-access-control`, version `0.1.0`, `private: true` (`package.json`).

## Application structure

```text
public/                 index.html, manifest, favicon, apple icon
src/index.js            Amplify.configure, ReactDOM.render, service worker unregister
src/App.js              BrowserRouter, MUI theme, Routes
src/aws-config.js       region, bucket, API URL, Cognito ids
src/config/Roles.js     role name constants
src/config/RoutingConfig.js
src/routes/             allowed-route filter wiring and Switch
src/utils/index.js      session helpers, validators, getNiceName
src/components/         screens and unityRequests
src/components/common/  Sui* design-system wrappers, nav, footer, Graphs, ExportableTable
src/assets/theme/       Soft UI theme (base, components, functions)
src/contexts/           popup modal
src/hooks/              useFormFields, usePopupModal, useWindowDimensions
sonar-scanner.bat       stock SonarScanner launcher
```

`jsconfig.json` sets `baseUrl` to `./src`, so imports such as `components`, `config`, `utils`, and `assets/theme` resolve from `src/`.

`src/hooks/useFormFields.js` exists. Login and Register keep their own `useState` form objects and do not use that hook. **Implemented** unused hook.

## Frameworks and languages

| Piece | Version in package.json | Where it shows up |
|---|---|---|
| JavaScript (no TypeScript) | — | Entire `src/` |
| React | 17.0.2 | All screens |
| react-scripts | 4.0.3 | `start`, `build`, `test` |
| react-router-dom | 5.2.0 | `BrowserRouter`, `Switch`, `Route`, `Link` |
| aws-amplify | 3.3.21 | Auth, API, Storage config |
| MUI 5 (`@mui/material`, `@mui/icons-material`, `@mui/styles`) | 5.0.0 | Theme, `TopNav`, dashboard grid |
| Material UI 4 (`@material-ui/core`) | 4.12.3 | `CssBaseline` import in `App.js` |
| react-bootstrap / bootstrap | 1.6.1 / 5.0.1 | Forms, cards, layout on auth and users |
| FullCalendar | 5.5.x | `Calendar.js` |
| recharts | 2.1.0 | `Graphs.js` |
| react-table | 7.6.3 | `Users.js` (and unrouted `Quotes.js`) |
| lodash | 4.17.15 | `intersection` in the route filter |
| TinyMCE | 5.8.2 and `@tinymce/tinymce-react` 3.12.6 | `WYSIWYG.js`, unmounted |
| Emotion, stylis, jss, jss-rtl | as declared | Theme engine. `theme-rtl.js` exists. RTL is not selected in `App.js` |
| Storybook | 5.2.1 devDependencies | Scripts only; no `.storybook` config |
| Prettier | 1.18.2 | `yarn pretty`. `.prettierrc.json` is present |

`react-trello`, `chartist`, `react-chartist`, `react-data-table`, `react-data-table-component`, `react-flatpickr`, `react-pivottable`, `plotly.js`, and `namor` are dependencies. Chartist, react-trello, and the data-table packages had no import under `src/` in this pass. Pivot and Plotly are imported by the unrouted pivot files. `namor` is the usual companion of `makeData.js` sample rows.

Both MUI 4 and MUI 5 are on the page. `StyledEngineProvider injectFirst` was added in commit `afb24c3` so Emotion styles win. **Implemented**.

## Runtime configuration

There is no `.env` in the repository. Endpoints are constants in `src/aws-config.js`:

| Key | Value that is safe to name | Notes |
|---|---|---|
| `s3.REGION` / `cognito.REGION` / `apiGateway.REGION` | `eu-west-1` | Shared region |
| `s3.BUCKET` | `unity-lite-files` | Passed to Amplify Storage |
| `apiGateway.URL` | omitted | Amplify endpoint name `unity` |
| `cognito.USER_POOL_ID`, `APP_CLIENT_ID`, `IDENTITY_POOL_ID` | omitted | `src/index.js` |
| `MAX_ATTACHMENT_SIZE` | `5000000` | Not referenced by an uploader in `src/` |

`src/index.js` sets `Auth.mandatorySignIn: true`. The UI does not block rendering on that flag. Guests still receive routes. **Implemented** config versus **Implemented** route behaviour: they disagree. **Requires Confirmation** which one was intended.

Scripts (`package.json`):

| Script | Command |
|---|---|
| `start` | `react-scripts --max-http-header-size=77777 start` |
| `build` | `react-scripts build` |
| `test` | `react-scripts test` |
| `eject` | `react-scripts eject` |
| `install:clean` | Unix `rm -rf` then `npm install` and `npm start`. Not a Windows command as written |
| `pretty` | Prettier on `src/**/*.js` with tabs, single quotes, always-parens |
| `storybook` / `build-storybook` | Storybook CLI on port 6006. No `.storybook` directory in the tree |

README start steps: `yarn install`, `yarn start`. A `yarn.lock` is present. **Documented**.

The enlarged Node header size (`77777`) is **Implemented** in the start script. Why the default was too small is **Unknown**.

## Authentication

Amplify Auth talks to the Cognito user pool in `aws-config.js`.

| Action | API | File |
|---|---|---|
| Sign in | `Auth.signIn` | `Login.js` |
| Sign up | `Auth.signUp` | `Register.js` |
| Confirm sign-up | `Auth.confirmSignUp` | `Register.js` |
| Resend | `Auth.resendSignUp` | `Register.js` |
| Forgot password | `Auth.forgotPassword`, `Auth.forgotPasswordSubmit` | `ForgotPassword.js` |
| Sign out | `Auth.signOut` | `TopNav.js` |
| Current session | `Auth.currentSession()` | Called and not awaited in `unityRequests.js`. Called and not awaited in `Login.js` before `API.get` |

The UI session flag is `localStorage.roles`, read by `isLoggedIn` and `getAllowedRoutes`. `userDetails` is written with `@rehooks/local-storage`. Logout uses `deleteFromStorage` for `roles` and `userDetails` only.

`unityRequests` assigns `const user = Auth.currentSession()` and never reads `user`. Amplify's API category attaches credentials from its own cache when a session exists. **Inferred**: the explicit `currentSession` line has no effect until it is awaited and used.

## HTTP API

All application HTTP goes through Amplify API name `unity`.

| Caller | Method as written | Path | Body / query |
|---|---|---|---|
| `Login.js` | `API.get` | `/user/details` | Query `strCognitoUuid` |
| `Register.js` | `API.get` | `/user/details` | Query `strCognitoUuid` or `strEmail` |
| `Login.js` | `API.post` | `/register` | Amplify init `{body: fields}`. HTTP JSON is the field object (`strCognitoUuid`, `strName`, `strSurname`, `strEmail`, `strIdType`, `strIdNumber`, `strMobileNumber`) |
| `Register.js` via `unityRequests` | POST (default) | `/register` | Same field object as the HTTP JSON |
| `Register.js` via `unityRequests` | POST | `/updateregistration` | Caller passes `{body: {strCognitoUuid, strEmail}}` and `unityRequests` wraps that again as Amplify `body`, so the HTTP JSON is `{body: {strCognitoUuid, strEmail}}` |
| `Users.js`, `Quotes.js` | POST | `/unity/getusers/1` | `{}` |
| `Profile.js` | POST | `/unity/getdetails` | `{id}` |
| `Calendar.js` | POST | `/unity/getcalendarevents/` | `{userID, dtStartDate, dtEndDate}` |
| `Calendar.js` | POST | `/unity/addcalendarevent/` | transformed event |
| `Calendar.js` | POST | `/unity/updatecalendarevent/` | transformed event |
| `Calendar.js` | POST | `/unity/removecalendarevent/` | transformed event |

`unityRequests(path, vars, action)` uses `API.get` only when `action == "get"`. Every current caller omits `action`, so the call is `API.post(apiName, path, {body: vars})`.

Login's `/register` and Register's `/register` send the same field object. `/updateregistration` is wrapped twice, so its HTTP JSON has an extra `body` key. **Inferred** from the two call shapes. **Requires Confirmation** against the API.

Login treats a successful details response as `{result: true, payload: {data, additionalIds}}`. Calendar, users, and profile destructure `{body}` and `JSON.parse` it. **Inferred** that both shapes are assumed. **Requires Confirmation** of the real responses.

No other HTTP client (`fetch`, `axios`) is used for product data. Fonts and Leaflet CSS are document links in `public/index.html`.

## Storage

S3 is configured. No `Storage` import was found under `src/`. Attachments are not implemented in this tree. `MAX_ATTACHMENT_SIZE` is unused.

## Routing implementation notes

`MapAllowedRoutes` copies child route objects onto the end of the same array it is rendering, and sets `isChild`. The `Switch` then matches `/staff` and `/cronjobs` as exact routes. The nav skips entries with `isChild`. Config's own page (`Configer.js`) tries to render children again under base path `/app/configer`, but:

- the route path is `/configer`, not `/app/configer`;
- `<Component/>` is rendered with no `children` prop.

**Inferred**: `/configer` throws when `getAllowedRoutes` is called with `undefined`. Staff and Cron Jobs are still listed at `/staff` and `/cronjobs` because the flatten loop pushes them onto the route array during render. **Requires Confirmation** in a browser. This was not executed for this document.

`BrowserRouter` from v5 ignores a `history` prop. `src/utils/history.js` creates one and `App.js` passes it. **Inferred** dead wiring. In-app navigation uses `useHistory()` from the router context, which still works.

A `useEffect` in `MapAllowedRoutes` scrolls to the top and toggles `shortFooter` on `.PageContents` when the path changes.

## UI architecture

Soft UI pieces live under `src/components/common/` as `SuiBox`, `SuiButton`, `SuiInput`, `SuiTypography`, `SuiAvatar`, `SuiBadge`, `SuiAlert`, `SuiPagination`, `SuiProgress`, plus layout containers. Screens mix those with React-Bootstrap. There is no single design-system boundary.

Theme source: `src/assets/theme/index.js` and `theme-rtl.js`, with tokens in `base/` and component overrides in `components/`. This matches the Creative Tim Soft UI Dashboard layout the README links (`https://www.creative-tim.com/learning-lab/react/quick-start/soft-ui-dashboard`). Provenance of the link: **Documented** in `README.md`. Provenance of the theme files: **Implemented**.

`ExportableTable.js` contains a `renderComponent` function that builds a demo table titled "Traffic Data". It is not the default export and nothing calls it. The default export is the reusable table (search, sums, CSV). Unmounted.

## Data held in the browser

| Key | Writer | Reader | Cleared on logout |
|---|---|---|---|
| `roles` | `localStorage.setItem` in `Login.js` | `getAllowedRoutes`, `isLoggedIn` | Yes |
| `userDetails` | `useLocalStorage` in `Login.js` | `getUserDetails`, nav, footer | Yes |
| `IDNumbers` | `localStorage.setItem` in `Login.js` | No reader was found under `src/` | No |

No IndexedDB, cookie, or cache-storage use was found. The service worker is unregistered, so CRA's production cache is not installed by this code.

## Background work, queues, monitoring

- No worker, cron runtime, or queue client is in the repo. `/cronjobs` is a title.
- No logging library. Failures use `console.log`.
- No analytics snippet was found.
- Sonar: `sonar-scanner.bat` is the upstream Windows launcher for scanner CLI 4.6.2.2472. `SONAR_SCANNER_HOME` is hardcoded to `C:\sonar-scanner\bin\..`. There is no `sonar-project.properties`. `.scannerwork/.sonar_lock` is tracked. A Sonar project key for this repo is **Unknown**.

## Security observations (from the tree, not a penetration test)

- `src/aws-config.js` is committed. Pool ids and the API URL are therefore in git history. Values are omitted here.
- `Login.js` initial state includes an email address and a password literal. Values omitted. **Requires Confirmation** and removal if unintentional.
- `isLoggedIn` trusts `localStorage`. Any script that can set `roles` to a JSON array of role names changes which routes render. API calls still need a Cognito session for Amplify to sign them. **Inferred** split between UI gating and API gating.
- RSA id numbers and additional ids are copied into `localStorage` (`IDNumbers`) and are not cleared on logout.
- Register and login error popups surface `error.message` from Cognito.
- No CSRF token is visible; the API is a bearer-style Amplify call. The API's authorizer is **Unknown**.
- Leaflet 1.7.1 CSS is loaded from `unpkg.com`. The link tag includes an integrity attribute. No map component uses it.

## Development and testing

| Item | Evidence |
|---|---|
| One automated test | `src/App.test.js` renders `<App />` into a detached div and unmounts it. It does not sign in or call the API |
| Test command | `yarn test` / `react-scripts test` (Jest via CRA). This document did not run it |
| Storybook | One story file, no config directory |
| Lint | `eslintConfig.extends` = `react-app`. No custom rules file |
| Format | `yarn pretty` |
| CI | No `bitbucket-pipelines.yml`, GitHub workflow, Dockerfile, or compose file |
| Hosting | **Unknown**. No deploy script |

`install:clean` uses `rm -rf` and `npm` even though the lockfile is Yarn. **Implemented** script. It will not run as written in Windows `cmd`.

## Deployment and infrastructure

**Unknown / Requires Confirmation.** Nothing in the repo names a CloudFront distribution, an S3 website bucket for the bundle, a domain, or a pipeline. The API URL path in `aws-config.js` includes a stage segment `prod`. That shows the client pointing at a stage called `prod`. It does not prove the stage is still deployed.

## Dependencies the product behaviour needs outside this repo

| Dependency | Why |
|---|---|
| Cognito user pool and app client from `aws-config.js` | Every auth screen |
| API Gateway (or compatible) URL in that file, implementing the paths in the HTTP API section | Users, calendar, profile, registration linking |
| Whatever computes `strRole` | Route filtering after login |
| S3 bucket `unity-lite-files` and the identity pool | Only if something outside this revision starts calling Amplify Storage. This revision does not |

The Lambda source, if it exists, is a different repository. **Unknown** which one.

## Discrepancies to keep visible

| Topic | Documentation or comment | Code at `afdeab6` |
|---|---|---|
| Soft UI status | README TODO: "everything to do with Soft-ui" and "styling" | Theme and Sui components are in the tree; many style commits in October 2021 |
| Product name | README "Unity - Soft UI"; title UnityLite; brand Unity Soft; package `role-based-access-control` | All four exist |
| Legal entity on register | "Paymyfines.com" | Shell says Unity Soft; profile company says Silicon Overdrive |
| MFA flag | Comment: set true when Cognito MFA is on | Constant `true` opens email `confirmSignUp` |
| Session | Amplify `mandatorySignIn: true` | Guest routes render without a session |
| Update-registration body | — | `/register` sends the field object. `/updateregistration` is wrapped in an extra `body` key |
| Details response | — | Login expects `result`/`payload`; other screens expect `body` |
| Role value | Filter `JSON.parse`s `roles` | Login stores `strRole` without `JSON.stringify` |
| Config children | `Configer` maps `children` | Router does not pass `children` |
| Users EDIT | Button labelled EDIT | Target `/app/user/:id` is not a route |
| Profile save | Button "Update Profile" | No submit handler |
| Storage | Amplify Storage configured | No `Storage` call |
| Service worker | CRA file can register | `unregister()` is what runs |
| Storybook | npm scripts | No `.storybook` |
| Backend | README: Amplify / lambda | No Lambda in this repo |
