# PRD — formulys-frontend

Evidence date: 2026-10-14.

Source: `git@bitbucket.org:overdrive/formulys-frontend.git`, `main` at `e34274c` (2023-12-21, Jason Wandrag, "Initial boilerplate push").

There is no prior PRD in the source repository. Silicon Ark had no `formulys-frontend/` directory before this file. `README.md` is the Vite template and does not state requirements. Requirements below are recovered from the React source and `package.json`. Provenance is labelled.

`src/store/authStore.js` does not parse. It is not imported. Behaviour of the running graph is what `main.jsx`, `App.jsx`, the pages, `LoginForm`, and `SidebarNav` implement. The app was not executed in a browser during this inspection.

## Product purpose

**Documented:** the HTML title is "Vite + React". The login and sidebar images use alt text "Simple Flow". The package name is `formulys-frontend`. Nothing else in git states a product purpose.

**Implemented.** An unauthenticated visitor can open a side navigation and a set of placeholder pages, or open `/login` and submit a username and password that are printed to the console.

**Inferred.** The nav labels and the unused Form.io login sketch are the start of a SimFlow-style process client. Silicon Ark `formulys_simpleflow` later implements a working client with overlapping names. This repository does not say it is that product.

**Unknown / Requires Confirmation:** product owner, customer, live URL, and whether this tree is still the intended front end.

## Users and roles

| Actor | Evidence | Status |
|---|---|---|
| Anyone who can open the site | No login check on any route in `App.jsx` | **Implemented**. There is no session |
| Person on the login form | `LoginForm` collects username and password | **Implemented**. Submit does not authenticate |
| Registered user, admin, or role | No role field, no guard, no user record in the mounted UI | **Not implemented** |

`authStore` would keep `user` and `jwt` in memory if something imported it and the file parsed. Nothing does. Provenance of roles: **Unknown**. None are named in this repository.

## Systems the product talks to

| System | Direction | Trigger | Data | Status |
|---|---|---|---|---|
| Browser console | Page → console | Login submit | `{ username, password }` via `console.log` | **Implemented** |
| Form.io `https://rzkiqpzlxxtfqjl.form.io` | Would be browser → Form.io | `authStore.login` | `POST /user/login` with JSON `{ data: { email, password } }`, read header `x-jwt-token` and JSON body | **Present and unused**. The module does not parse and is not imported. The mounted login form does not call it |

No other host, database, queue, FTP target, or pipeline is in the tree.

The Form.io host string is the same host recorded for `formulys_simpleflow` and `pestelite_html`. This file calls `/user/login`. `formulys_simpleflow` posts to a form named `simflowlogin`. Whether they share one Form.io project on purpose is **Unknown / Requires Confirmation**.

## Routes

Defined in `src/App.jsx`. `SidebarNav` is rendered by `App` for every path except `/login`, using `window.location.pathname` inside `App`'s render. `App` does not call `useLocation`. `useNavigate` is imported and unused, so a client-side navigation does not by itself re-render `App`. Provenance of the hide-on-login check: **Implemented** for the first paint of a full page load. Provenance of the sidebar staying in sync after an in-app navigation: **Inferred** as unreliable, and not runtime-tested.

| Path | Screen | Nav label | What the screen shows |
|---|---|---|---|
| `/` | `Home` | Dashboard | The text `Home` |
| `/process-hub` | `ProcessHub` | Process Hub | The text `ProcessHub` |
| `/tasklist` | `Tasklist` | Tasklist | The text `Tasklist` |
| `/notifications` | `Notification` | Notifications | The text `Notification` |
| `/messages` | `Message` | Messages | The text `Message` |
| `/profile` | `Profile` | My Profile | The text `Profile` |
| `/settings` | `Settings` | Settings | The text `Settings` |
| `/login` | `Login` → `LoginForm` | No nav link | Username, password, Login button, logo |
| any other path | `NotFound` | Sidebar still rendered | The text `404 Page Not Found` |

There is no `/register` route. `src/pages/Register.jsx` and `src/components/forms/RegisterForm.jsx` are not imported by `App` or by any page. A request for `/register` matches `*` and shows the 404 page. Provenance: **Implemented**.

`Home.jsx` imports `SidebarNav` and does not render it. The sidebar the user sees comes from `App`. Provenance: **Implemented** unused import.

## Major workflows

### WF-1 — Open the shell

**Implemented** in `src/main.jsx` and `src/App.jsx`.

Trigger: load any routed path.

Inputs: the URL path.

Behaviour: React mounts `BrowserRouter` in `StrictMode`, renders `SidebarNav` unless the path is `/login`, then renders the matching page. Pages other than login and 404 return a single text node. No data is fetched.

Output: the placeholder text, or the login form.

Error conditions: an unknown path renders `NotFound`. There is no error boundary in the tree.

### WF-2 — Submit login

**Implemented** in `src/components/forms/LoginForm.jsx`.

Trigger: submit the form.

Inputs: username (text, HTML `required`), password (password, HTML `required`).

Behaviour: `preventDefault`, `console.log("Login clicked with:", { username, password })`, then set both fields back to empty strings. `authStore` is not imported. No navigation follows a submit.

Output: a console line, an empty form, the user remains on `/login`.

Validation: the browser's built-in `required` check. Empty submit does not reach `handleSubmit`. There is no format check, no error message in the page, and no check of a server response.

Error conditions: none are handled. A failed `console.log` is not anticipated by the code.

### WF-3 — Form.io login sketched in the store

**Present and unused** in `src/store/authStore.js` and `src/lib/constants.js`.

The store is not on the running graph. If a later change imported it, the module would fail to parse before `login` could run. The intended call, read from the source as written:

- Trigger: `login({ email, password })`.
- Request: `POST ${BASE_URL}/user/login` with `Content-type: application/json; charset=UTF-8` and body `JSON.stringify({ data: { email, password } })`.
- `BASE_URL` is not declared in this file. `constants.js` assigns `const BASE_URL = "https://rzkiqpzlxxtfqjl.form.io"` and does not export it. Nothing imports `constants.js`.
- On success of `fetch`: read `x-jwt-token` from the response headers, `await res.json()` into `user`, `set({ user, jwt })`. `res.ok` is not checked.
- On throw: `console.error("Error in login: ", error.message)`. State is left unchanged.
- `logout` is written as `set({ user: null, jwt, null })`, which is not valid JavaScript.

Provenance: **Implemented** as source text that the bundler cannot load. It is not a working workflow.

## Functional requirements

### FR-001 — Boot the SPA

Requirement: loading `index.html` mounts the React tree into `#root` inside `React.StrictMode` and `BrowserRouter`.

Who: anyone who opens the page.

Trigger: document load. The script is `/src/main.jsx`.

Inputs: none.

Expected behaviour: `App` renders.

Outputs: the shell described in the routes table.

Validation: none.

Error conditions: if `#root` is missing, `document.getElementById('root')` is null and `createRoot` throws. That case is not handled.

Dependencies: React 18, Vite, `react-router-dom`.

Evidence: `index.html`, `src/main.jsx`.

Implementation: Implemented.

Confidence: High.

### FR-002 — Side navigation

Requirement: a left column lists links to Dashboard, Process Hub, Tasklist, Notifications, Messages, My Profile, and Settings, plus the logo image.

Who: anyone on a path other than `/login` at the time `App` renders.

Trigger: `App` render.

Inputs: `window.location.pathname`.

Expected behaviour: `SidebarNav` when the path is not exactly `/login`; otherwise no sidebar. Links use `react-router-dom` `Link` to `/`, `/process-hub`, `/tasklist`, `/notifications`, `/messages`, `/profile`, `/settings`. There is no Login link and no Logout control.

Outputs: the nav column (`max-w-[300px]`, full viewport height, white background, shadow).

Validation: none.

Error conditions: none in this component.

Dependencies: `src/assets/images/logo.png`.

Evidence: `src/App.jsx`, `src/components/navigation/SidebarNav.jsx`.

Implementation: Implemented. Re-render on client-side route change is not wired to location. See the routes section.

Confidence: High for the first paint. Medium for in-app navigations, because that path was not executed.

### FR-003 — Placeholder pages

Requirement: each routed area other than login and 404 shows its component name (Home shows `Home`).

Who: anyone who opens the path. No role check.

Trigger: navigation to that path.

Inputs: the URL.

Expected behaviour: a `div` containing only that text. No lists, forms, or remote data.

Outputs: the text node.

Validation: none.

Error conditions: none.

Evidence: `src/pages/Home.jsx`, `ProcessHub.jsx`, `Tasklist.jsx`, `Notification.jsx`, `Message.jsx`, `Profile.jsx`, `Settings.jsx`.

Implementation: Implemented.

Confidence: High.

### FR-004 — Login form

Requirement: `/login` shows a form with username, password, a Login button, and the logo.

Who: anyone who opens `/login`.

Trigger: route match, then form submit.

Inputs: username, password. Both `required`.

Expected behaviour: as WF-2. The form is centred, max width 400px, grey background `#ebebeb`, border `#dad9d9`.

Outputs: console log, cleared fields.

Validation: HTML `required` only.

Error conditions: no in-page error state.

Evidence: `src/pages/Login.jsx`, `src/components/forms/LoginForm.jsx`.

Implementation: Implemented. It does not authenticate.

Confidence: High.

### FR-005 — Unknown paths

Requirement: a path that matches no route shows `404 Page Not Found`.

Who: anyone.

Trigger: React Router `path="*"`.

Inputs: the URL.

Expected behaviour: the 404 text. `App` still applies the sidebar rule, so a full load of an unknown path other than `/login` includes the sidebar.

Outputs: the text node.

Evidence: `src/pages/NotFound.jsx`, `src/App.jsx`.

Implementation: Implemented.

Confidence: High.

### FR-006 — Register placeholders

Requirement: none. The files exist and are not routed.

Evidence: `src/pages/Register.jsx` returns `Register`. `src/components/forms/RegisterForm.jsx` returns `RegisterForm`. No import sites.

Implementation: Present and unused. A product requirement to register a user was not found.

Confidence: High that they are unused. The intended product rule is **Unknown / Requires Confirmation**.

### FR-007 — Auth store

Requirement: none on the running graph.

The source text describes WF-3. Treat that as **Inferred** intent, not as a requirement the product meets.

Evidence: `src/store/authStore.js`, `src/lib/constants.js`. Grep of `*.js`, `*.jsx`, `*.css`, `*.html`, and `*.md` shows no import of `authStore` or `constants.js`.

Implementation: Present and unused. The store file is not valid JavaScript.

Confidence: High.

## Data the UI expects

The mounted UI stores two React state fields on the login form: `username` and `password`, both strings, initial value `""`. They are discarded after submit except for the console log.

No `localStorage`, cookie, database, or server payload is read by a mounted module.

The unused store names two pieces of state: `user` (JSON body of the login response, initial `null`) and `jwt` (value of header `x-jwt-token`, initial `null`). The login argument it destructures is `{ email, password }`, which does not match the login form's `username` field. Provenance of that mismatch: **Implemented** in two files that are not connected.

No schema for `user` is defined in this repository.

## Constraints

- The package is `private: true`. There is no publish configuration.
- `vite.config.js` is the default React plugin. No `base`, proxy, or port override.
- Styling is Tailwind (`src/index.css` directives) plus a full-page background image `src/assets/images/background.png`. `src/App.css` is imported by `App.jsx` and is an empty file.
- No environment variable is read. `import.meta.env` does not appear.
- The app was not run, so layout in a real browser was not confirmed.

## Not verified

- `npm install`, `npm run dev`, `npm run build`, and `npm run lint` were not executed.
- Whether the logo or background image is the same artwork later committed to `formulys_simpleflow` was not compared byte for byte.
- Whether a host outside git still serves this build.
