# Business rules — unity-lite-v2

Evidence date: 2026-09-30. Revision: `master` `46f8a1f` (2022-05-26).

No business-rules document existed in the repository or in `silicon_ark/unity-lite-v2/` before this file. Nothing in the README states a commercial rule, a pricing rule, or an approval rule.

Rules below are labelled:

- **Documented** — written in the README, a UI string, or a code comment.
- **Implemented** — enforced by the code that runs.
- **Inferred** — a reasonable reading of that code, not executed against the live API for this document.

Where the server might enforce something the client does not show, the rule is **Unknown / Requires Confirmation**.

## Identity and access

### BR-001 — Five role names

**Documented** and **Implemented**. `src/config/Roles.js` lists `SUPER_ADMIN`, `ADMIN`, `MANAGER`, `CUSTOMER`, and `GUEST`, and the comment says they are placeholder roles that can be replaced.

The user form offers the same five strings in a multi-select (`src/components/User.js`). That selection is not saved.

### BR-002 — A `roles` localStorage key means signed in

**Documented** in the comment on `isLoggedIn` ("This app assume if local storage have roles it means user is authenticated") and **Implemented** in `src/utils/index.js`. The comment also says to update the logic. Cognito is not consulted on each navigation.

### BR-003 — Who may open which screen

**Implemented** in `src/config/PrivateRoutesConfig.js` and `getAllowedRoutes`.

| Screen | Allowed role strings |
|---|---|
| Calendar, Booking, Task list, Kanban, Users, User | Any visitor who has a `roles` key, including a stored `GUEST`, because these routes set no `permission` |
| Config, and through it Staff and Cron Jobs | `SUPER_ADMIN`, `ADMIN`, `MANAGER` |
| Dashboard | `SUPER_ADMIN`, `ADMIN` |
| Profile | `SUPER_ADMIN`, `ADMIN`, `MANAGER`, `CUSTOMER` |

A route is kept when the intersection of its `permission` array and the parsed `roles` value is non-empty. Missing or empty `permission` keeps the route.

`JSON.parse` is applied to `localStorage.roles`. Login writes `body.strRole` with `setItem` and does not `JSON.stringify` an array. **Inferred:** the private shell only renders if `strRole` is already a JSON array string. The API's actual format is **Unknown / Requires Confirmation**.

### BR-004 — Public pages are for visitors without a `roles` key

**Implemented** in `src/routes/Auth.js`. If the key is present, every path outside `/app` redirects to `/app`. Login, register, forgot password, and the landing page are then unreachable until logout.

The comment in that file calls the check temporary.

### BR-005 — Logout is local

**Implemented** in `TopNav.js`. Logout deletes `roles` and navigates to `/`. It does not delete `userDetails` and does not call `Auth.signOut()`.

**Inferred:** a later calendar load can still see the previous `userID` if some other code set `roles` again without rewriting `userDetails`. No such code path was found.

### BR-006 — Login does not check the typed value

**Implemented** in `Login.js`. There is no required-field check, no email format check, and no minimum length. The change handlers do not copy the input's value into state. The button is always enabled (the `disabled={!strEmail.length}` expression is commented out).

The initial email and password are literals in the file. They are omitted from this document.

### BR-007 — A failed sign-in still navigates to `/app`

**Implemented**. `history.push('/app')` is outside the success path's exclusive branch: it runs after the try/catch. If `roles` was not stored, `PrivateRoutes` sends the browser back to `/`.

### BR-008 — Uuid lookup failure is treated as a body

**Implemented** in `signInWithEmailAndPassword`: an exception from `API.get` returns `{ result: "Api Error" }` rather than throwing. The caller then reads `.strRole` and `.UserID` on that object.

There is no rule in the client for "unknown Cognito user" versus "known user". If element `[0]` is missing, reading `.strRole` throws, the outer catch logs it, and the app still navigates to `/app`. **Inferred**.

### BR-009 — No self-registration and no password reset

**Implemented**. `/register` and `/forgot-password` do not call Amplify Auth. **Inferred:** accounts are created somewhere outside this UI. Where, is **Unknown / Requires Confirmation**.

## Calendar

### BR-010 — Events are loaded for the signed-in user and the visible range

**Implemented** in `Calendar.js`. The request body is `userID` from `userDetails`, plus `dtStartDate` and `dtEndDate` from FullCalendar's `datesSet` range (start and end strings, which include the leading and trailing days of the month view).

Whether the server returns only that user's events is **Unknown / Requires Confirmation**. The client sends the id and renders whatever array comes back.

### BR-011 — A new event needs a non-empty title

**Implemented**. `window.prompt` must return a truthy string. Cancel or an empty string does not call `addEvent`. No other fields are asked. Description (`txtNotes`) is not collected in the prompt. The create payload still sends `txtNotes` from `item.description`, which the prompt path does not set.

### BR-012 — The creator stamped on a new event is the stored user

**Implemented**. `strFirstUser` is `userDetails.userName` and `refSysUserID` is `userDetails.userID` at create time. The client does not compare those fields on later edit or delete. Any signed-in visitor who can see an event can drag it or confirm-delete it. A server-side owner check is **Unknown / Requires Confirmation**.

### BR-013 — Delete asks for confirmation

**Documented** in the sidebar ("Click an event to delete it") and **Implemented** with `window.confirm` and the event title. Dismissing the confirm leaves the event.

### BR-014 — A failed write undoes the on-screen edit

**Implemented**. Add, change, and remove catch errors, log them, and call `revert()` on the FullCalendar info object. The user is not shown the error text.

### BR-015 — Weekends are shown unless toggled off

**Implemented**. Initial state shows weekends. The checkbox flips `weekendsVisible`. The choice is not stored.

### BR-016 — New event ids are a local counter until the server responds

**Implemented** in `event-utils.js`. `createEventId` returns an incrementing string starting at 0 for the page lifetime. After a successful add, the client sets `event.id` from `body.id`. If `body.id` is absent, the id becomes whatever that read returns. **Unknown** what the server puts in `body.id`.

## Users

### BR-017 — The user table is the `getusers/1` payload

**Implemented**. One call, path segment `1` fixed in source. No paging, no search, no role filter on the client. The meaning of `1` is **Unknown / Requires Confirmation**.

### BR-018 — EDIT does not save

**Implemented**. The user form's Update Profile button does not call the API. Company is disabled and the visible default is "Silicon Overdrive". First name, last name, and address all display `strUser`. City, country, and postal code all display `strLocation`. **Inferred:** the form is not a reliable editor of separate name or address fields.

The role multi-select does not write `strRole` back.

### BR-019 — There is no client rule that hides users by role

**Implemented**. Anyone who can open `/app/users` (any stored role, because the route has no `permission`) loads the same path. Whether the API scopes the rows is **Unknown / Requires Confirmation**.

## Tasks, dashboard, and other screens

### BR-020 — The task list is two fixed examples

**Implemented** in `Tasklist.js`. The rows are not loaded or saved. One row names "SAWIS" ("Work on Language changes for SAWIS"). No code defines what SAWIS is. Treating it as a customer or a product is **Unknown / Requires Confirmation**. It is a string in sample data.

### BR-021 — Dashboard numbers are not operational metrics

**Implemented** in `Dashboard.js`. The cards show `150GB`, `$ 1,345`, `23`, and `+45K`, and the charts are titled "Users Behavior", "Email Statistics", and "2017 Sales", all with arrays written in the file. They are not computed from the API. **Inferred:** they must not be read as live capacity, revenue, or error counts.

The dashboard task rows repeat the conference-contract sentence used on the task list. Edit and remove do nothing.

### BR-022 — Booking, kanban, profile, staff, and cron jobs have no domain rules

**Implemented**. Those components render a title (kanban also links to `/login`). No validation, no status machine, no schedule. `Kanban_data.json` is not shown.

Config's on-screen title is "Developer Tools / Examples" (`Configer.js`). **Inferred** from that title: Staff and Cron Jobs are examples, not an HR or scheduler product. The README does not say this.

### BR-023 — Profile permission is wider than the screen

**Implemented**. `CUSTOMER` may open Profile. The screen does not show that user's `userDetails`. There is no rule that a customer sees only their own profile, because the screen has no data.

## Data handling

### BR-024 — Calendar field mapping

**Implemented** in `transformToDB` / `transformToReact`:

| Client | API field |
|---|---|
| `id` | `CalendarIDitem` |
| `title` | `txtDescription` |
| `description` | `txtNotes` |
| `start` | `dtStartDate` |
| `end` | `dtEndDate` |
| `strFirstUser` | `strFirstUser` |
| `refSysUserID` | `refSysUserID` |

No other calendar fields are mapped. Time zone conversion is whatever FullCalendar and the API strings already are. **Unknown** whether the API expects UTC.

### BR-025 — User fields the list displays

**Implemented** accessors: `strUser`, `strTel`, `strJobTitle`, `strRole`, `strEmail`, `strLocation`, and `UserID` on the EDIT link. The login path reads `strRole`, `UserID`, and `strUser` from the uuid response. The edit load expects the same style of object from `getdetails`.

### BR-026 — Attachment size

**Implemented** constant only. `MAX_ATTACHMENT_SIZE` is 5000000 in `src/aws-config.js`. No upload uses it. A 5 MB business rule is **not** enforced by a screen in this tree.

## What this document does not claim

- Pricing, tax, invoicing, or a booking policy. The booking screen has no fields.
- An approval chain for events or users.
- That `GUEST` is a product role rather than a leftover placeholder. The comment says placeholder. The route table never grants `GUEST` a named permission.
- That the sample dashboard or the SAWIS task row is a requirement. They are hardcoded strings.
- Server-side retention, audit, or tenancy. Not visible in this client.
