# Technical documentation — unity-lite-v2

Evidence date: 2026-09-30. Revision: `master` `46f8a1f` (2022-05-26, author `liamkleyn_od`, subject "Copy Unity Lite v1"). 95 tracked files. Default branch `master`. No other branches.

Credential values are omitted. The login form's initial email and password literals are omitted. Region, bucket name, endpoint name, and the attachment-size constant are taken from source because they are not secrets by themselves. Pool ids and the API Gateway host stay in `src/aws-config.js` only.

## What this repository is

A Create React App client. The README (`README.md`) titles it "Unity - Lite" and describes it as "Unity with out styling and redux components", using Amplify / lambda. `package.json` name is `role-based-access-control`, version `0.1.0`, `private: true`.

The browser title is UnityLite. The nav wordmark is UnityLite. The manifest name is still the CRA sample.

There is no Redux, no server, and no database in this tree. Domain calls go to an external API named `unity`.

## Repository layout

```text
unity-lite-v2/
  package.json
  package-lock.json
  yarn.lock
  jsconfig.json                 baseUrl ./src
  .prettierrc.json              tabs, single quotes, always arrow parens
  .gitignore                    node_modules, dist, logs, IDE, media. Does not list .env
  README.md
  public/
    index.html                  title UnityLite, CDN Bootstrap, W3.CSS, Raleway
    manifest.json               CRA sample name
  src/
    index.js                    Amplify.configure, render, serviceWorker.unregister
    aws-config.js               region, bucket, API host, Cognito ids, MAX_ATTACHMENT_SIZE
    App.js                      fluid container around Routes
    App.test.js                 one smoke render
    serviceWorker.js            CRA helper, not registered
    routes/                     public/private split, MapAllowedRoutes
    config/                     Roles, PrivateRoutesConfig
    utils/                      isLoggedIn, getAllowedRoutes, history
    components/                 screens, unityRequests, vendored pivot files
    assets/                     logo.svg, loading-bubbles.svg, nucleo-icons.svg
```

No `Dockerfile`, `bitbucket-pipelines.yml`, `serverless.yml`, SAM template, `.env`, or `sonar-project.properties` is tracked.

The onboarding issue (captured 2026-09-28 from the scan host) listed `sonar-project.properties` and `sonarqube_scan.bat` beside `package.json`. `git ls-files` at `46f8a1f` does not contain them. **Unknown / Requires Confirmation** whether the scan host has untracked copies.

## Runtime and toolchain

| Item | Value | Evidence |
|---|---|---|
| UI | React 16.8.6, React DOM 16.8.6 | `package.json` |
| Build | `react-scripts` 3.0.1 (`start`, `build`, `test`, `eject`) | `package.json` |
| Router | `react-router-dom` 5.2.0, history via `createBrowserHistory` from `history` | `src/routes/index.js`, `src/utils/history.js` |
| `history` package | Imported. Not a direct dependency | May resolve through `react-router-dom`. **Unknown** on a strict install |
| UI kit | `react-bootstrap` 1.0.0-beta.10, `bootstrap` 4.3.1, plus CDN CSS | `package.json`, `public/index.html` |
| Auth and API | `aws-amplify` 3.3.21 | `package.json`, `src/index.js` |
| Calendar | `@fullcalendar/react` 5.5.0, daygrid 5.5.0, timegrid 5.5.1, interaction 5.5.0 | `Calendar.js` |
| Charts | `chartist` 0.11.4, `react-chartist` 0.14.4 | `Dashboard.js` |
| Tables | `react-table` 7.6.3 | `Users.js` |
| Module paths | `jsconfig.json` `baseUrl` `./src`, so imports like `routes`, `config`, `utils`, `components` | `jsconfig.json` |
| Format | `yarn pretty` runs Prettier with tabs and single quotes on `src/**/*.js` | `package.json`, `.prettierrc.json` |
| Tests | `react-scripts test`. One file `src/App.test.js` renders and unmounts `App` | Not executed for this document |
| Storybook | Scripts on port 6006. Storybook 5.2.1 devDependencies. No `.storybook` config | Scripts would not start as committed |
| Lockfiles | Both `package-lock.json` and `yarn.lock` tracked. README says `yarn install` / `yarn start` | Which file is authoritative is **Unknown / Requires Confirmation** |

Node version is not pinned. No `.nvmrc`, `engines` field, or pipeline image.

`Tasklist.js` imports `react-icon-checkbox` and `react-icons/bs`, which are not dependencies. `Pivot.js` imports `react-dropzone` and `papaparse`, which are not dependencies. `Pivot.js` is not on a route. `Tasklist.js` is.

## Application structure

`src/index.js` calls `Amplify.configure` then `ReactDOM.render(<App />, #root)`.

`App` renders `routes/index.js` inside a fluid container.

`Routes` uses a custom browser history (`utils/history.js`) and a switch:

- `path="/app"` → `PrivateRoutes`
- `path=""` → `Auth` (matches everything else)

`Auth` (`src/routes/Auth.js`): `isLoggedIn()` ? `<Redirect to="/app" />` : `<PublicRoutes />`.

`PublicRoutes`: `/forgot-password`, `/register`, `/login`, empty path → `LandingPage`.

`PrivateRoutes`: if not logged in, `<Redirect to="/" />`. Else `TopNav` plus `MapAllowedRoutes` with `basePath="/app"` and `isAddNotFound`.

`MapAllowedRoutes` builds `path={`${match.path}${route.path}`}` and spreads the remaining route props (`exact` where set). It strips `component`, `children`, `title`, and `permission` so they are not passed to `<Route>`. Unknown paths render `NotFound` when `isAddNotFound` is set. Config's inner `MapAllowedRoutes` does not set that flag.

`Configer` is the only screen that receives `children` and mounts a nested `MapAllowedRoutes` at `/app/configer`.

## Auth

Amplify Auth config (`src/index.js`):

- `mandatorySignIn: true`
- `region`, `userPoolId`, `identityPoolId`, `userPoolWebClientId` from `awsconfig.cognito`
- Region value in `src/aws-config.js`: `eu-west-1`

Sign-in (`Login.js`): `Auth.signIn(email, password)`. Username used for the API is `response.username`. The access token is read and discarded. Nothing in this file writes `localStorage.jwt_access_token`.

There is no `Auth.signUp`, `Auth.confirmSignUp`, `Auth.forgotPassword`, `Auth.currentAuthenticatedUser` check on navigation, or `Auth.signOut`.

`unityRequests` calls `Auth.currentSession()` and ignores the result. Later `API.post` / `API.get` rely on Amplify's default credentials. **Inferred**.

Signed-in routing uses only `localStorage.roles` (`utils/index.js`).

Logout removes that key only (`TopNav.js`).

## API

Endpoint name `unity`. Region `eu-west-1`. URL host is in `src/aws-config.js` (omitted here).

Helper `src/components/unityRequests.js`:

- Default action `"post"` → `API.post("unity", path, { body: vars })`.
- Action `"get"` → `API.get("unity", path, vars)`. No caller passes `"get"`.
- `Auth.currentSession()` is called and not awaited. The promise is stored in `user` and never read. **Implemented** as written.

| Caller | Method as coded | Path | Body or notes |
|---|---|---|---|
| `Login.js` (direct `API.get`, not the helper) | GET | `/unity/uuid/{username}` | Expects `JSON.parse(body)[0]` with `strRole`, `UserID`, `strUser` |
| `Calendar.js` | POST | `/unity/getcalendarevents/` | `{ userID, dtStartDate, dtEndDate }` |
| `Calendar.js` | POST | `/unity/addcalendarevent/` | DB field mapping; reads `body.id` |
| `Calendar.js` | POST | `/unity/updatecalendarevent/` | Same mapping |
| `Calendar.js` | POST | `/unity/removecalendarevent/` | Same mapping |
| `Users.js`, `Quotes.js` | POST | `/unity/getusers/1` | No body argument (`vars` defaults to `{}`) |
| `User.js` | POST | `/unity/getdetails` | `{ id }` |

The handler implementation is not in this repository. The README names Lambda. Which function, stage behaviour, and error JSON are **Unknown / Requires Confirmation**.

Shared field names, client side:

- User: `strUser`, `strEmail`, `strTel`, `strJobTitle`, `strRole`, `strLocation`, `UserID`.
- Calendar: `CalendarIDitem`, `txtDescription`, `txtNotes`, `dtStartDate`, `dtEndDate`, `strFirstUser`, `refSysUserID`.

## Storage

Amplify Storage (`src/index.js`):

- `region` `eu-west-1`
- `bucket` `unity-lite-files`
- `identityPoolId` from the Cognito block

`MAX_ATTACHMENT_SIZE` is `5000000` (`src/aws-config.js`). No file reads it. No `Storage.get`, `Storage.put`, or `Storage.remove` call exists under `src/`.

Browser storage that the app does use:

| Key | Writer | Reader | Contents |
|---|---|---|---|
| `roles` | `Login.js` `setItem('roles', body.strRole)` | `isLoggedIn`, `getAllowedRoutes` (`JSON.parse`) | Not JSON.stringified by the writer |
| `userDetails` | `Login.js` | `getUserDetails` | JSON `{ userID, userName }` |

Logout deletes `roles` only.

## Routing and roles

`Roles.js` exports the five strings. `PrivateRoutesConfig.js` is the route table consumed by `PrivateRoutes`. The export list in `components/index.js` also includes `Quotes`, which the route table does not mount. `Timesheet.js` is not exported and not mounted.

`getAllowedRoutes` (`utils/index.js`):

```text
permission missing        → keep
permission empty array    → keep
else                      → keep if lodash.intersection(permission, JSON.parse(roles)) is non-empty
```

`intersection` treats a string as an array of characters, so a parsed JSON string `"ADMIN"` would not match the permission `"ADMIN"` as a role name. A parsed array `["ADMIN"]` would. **Inferred** from lodash's behaviour and the call site. Not executed here.

## Background work, queues, monitoring

No worker, cron runtime, queue client, or metrics SDK is in the repository. The Cron Jobs screen is a jumbotron title (`CronJobs.js`).

No logging library. Failures use `console.log`. Login's commented `console.log(body.strRole)` is inside a comment.

No Sonar project file is tracked. See the scan-host note above.

## Security

Observations from the tree, not a penetration test:

- Cognito pool ids, app client id, identity pool id, and the API Gateway URL are committed in `src/aws-config.js`.
- Email and password initial state are committed in `src/components/Login.js`.
- The access token is read into a local variable and not sent to `console.log` in the current code. It is also not stored by this file.
- Logout does not revoke the Cognito session.
- Route protection is the presence of `localStorage.roles`, which any script on the origin can set.
- User list and calendar calls have no extra client-side authorisation header beyond Amplify defaults.
- `User.js` and `Dashboard.js` embed a fixed lyric as sample copy. It is not loaded from a user record.
- CDN stylesheets are loaded from `maxcdn.bootstrapcdn.com`, `www.w3schools.com`, and `fonts.googleapis.com` without Subresource Integrity on the W3.CSS and font links. The Bootstrap link has an `integrity` attribute.
- No captcha, no rate-limit client, and no CSRF token were found. The API is called with Amplify, which uses the Cognito session rather than a cookie CSRF scheme. **Inferred** from the absence of those calls.

## Development and testing

README:

```text
yarn install
yarn start
```

Scripts also include `build`, `test`, `eject`, `pretty`, `storybook`, `build-storybook`.

`src/App.test.js` renders `<App />` into a detached div and unmounts it. It does not assert text. It was not run for this document. Whether it passes given the Amplify import and the missing Tasklist packages (Tasklist is imported through the route table, which `App` loads) is **Unknown / Requires Confirmation**.

Story files exist for `NotFound` and `JumbotronWrapper`. There is no `.storybook` directory, so `yarn storybook` has no config to load.

No Cypress, Selenium, or TestSprite config is in the tree.

## Deployment

No hosting config, environment split, or build artefact is committed. `serviceWorker.unregister()` means a production `build` does not install an offline worker unless a later change calls `register()`.

Where a bundle is served, if anywhere, is **Unknown / Requires Confirmation**.

## Relationship to other repositories

Documented in Silicon Ark, not re-cloned for this file:

- `unity-soft-ui` uses the same package name `role-based-access-control`, the same bucket name `unity-lite-files`, and the same path strings `/unity/getcalendarevents/`, `/unity/uuid/`, and `/unity/getusers/1`. Its inspected tip is a Soft UI shell (`main` `afdeab6`, 2022-01-24). This tree is an unstyled Bootstrap shell whose tip (`46f8a1f`, 2022-05-26) says it was copied from Unity Lite v1. The git histories are not the same.
- `unity-skeleton` is a Fuse React client with a different role model (hard-coded `superuser`).
- `unityNodejsApi` is a 2019 Lambda (`unityAuth`) aimed at `us-east-2`. This client's API region in config is `eu-west-1`. Nothing in this tree names `unityAuth`.

Whether the Gateway host and the Cognito pool match `unity-soft-ui` is **Unknown / Requires Confirmation**.

## Discrepancies

| Topic | A | B |
|---|---|---|
| Product name | README "Unity - Lite"; title UnityLite; package `role-based-access-control`; manifest "React App" | All four exist |
| "Without styling" | README | Bootstrap, W3.CSS, `Dashboard.css`, `Calendar.css`, and nucleo icons are in the tree |
| Child routes | TODO in `PrivateRoutesConfig.js` says to add them | `Configer.js` already renders Staff and Cron Jobs as children |
| Public routes when logged in | TODO in `Auth.js` | Redirect to `/app` is already implemented |
| Sonar files | Listed on the scan host at task creation | Not in git at `46f8a1f` |
| Kanban | `react-trello` dependency and `Kanban_data.json` | `Kanban.js` is a title and a login link |
| User save | Form button "Update Profile" | No submit handler and no update path |
| Avatar | `require(".../faces/placeholder.png")` | File not tracked |
| Task list | Routed screen | Imports packages that are not in `package.json` |
| `unity-soft-ui` | Same package name and overlapping API paths | Separate repository, separate history, Soft UI shell |
