# Business rules — siliconreact

Evidence date: 2026-10-03. Source: `git@bitbucket.org:overdrive/siliconreact.git`, `master` at `96fd3b0` (2023-03-24).

No business-rules document exists in the repository. Rules below are taken from code. Each one is marked **Implemented** or **Inferred**. Nothing here is a confirmed written policy.

The password checked by the credentials provider is a source literal. It is not copied into this file.

## Identity

**BR-001 — One accepted login.** `authorize` rejects the attempt unless the submitted email equals `johndoe@gmail.com` and the submitted password equals the password literal in `pages/api/auth/[...nextauth].ts`.

- Provenance: **Implemented**.
- There is no user directory, hash, or lockout.

**BR-002 — Failure message.** A rejected attempt throws `Error('Invalid Credentials')`.

- Provenance: **Implemented** in the provider.
- The login page does not render that message. It logs the `signIn` result. Provenance: **Implemented**.

**BR-003 — Session user is a fixed record.** A successful check returns `id` `123`, first name John, last name Doe, name John Doe, email `test@gmail.com`, and role `admin`. The submitted email is not copied onto the session.

- Provenance: **Implemented**.
- **Inferred:** this is stub data. Whether the email mismatch and the admin role are intentional is **Unknown / Requires Confirmation**.

**BR-004 — Role is not enforced.** `role` is set and never read. `/home` and `/users` only test `useSession().status`.

- Provenance: **Implemented**.

**BR-005 — Session strategy is JWT.** `session.strategy` is `'jwt'`. No database adapter is configured. No `maxAge` is set.

- Provenance: **Implemented**.
- How long the JWT lives is the NextAuth library default for version 4.20.1, not a value chosen in this repo. **Unknown** as a business duration.

## Login form

**BR-006 — Email is required and must look like an email.** Empty email: "Required". Otherwise the value must match `/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i` or the error is "Invalid email address".

- Provenance: **Implemented** (`lib/validate.ts`).
- **Inferred constraint:** a top-level domain longer than four characters fails this check. The expression is case-insensitive.

**BR-007 — Password is required and must not contain a space.** Empty password: "Required". If `password.includes(" ")`, the error is "Invalid Password". No length, character-class, or confirmation rule is applied on login.

- Provenance: **Implemented**.

**BR-008 — Validation feedback is a red border.** The error string is not shown. The border turns red only when the field has an error and has been touched.

- Provenance: **Implemented** (`pages/auth/login.tsx`).

**BR-009 — Remember me does not change sign-in.** The checkbox updates `isChecked`. `signIn` receives email, password, `redirect: false`, and `callbackUrl: "/home"` only.

- Provenance: **Implemented**.

**BR-010 — Successful sign-in goes to the callback URL.** The client pushes `res.url` only when `res.ok` is true. The callback URL passed in is `/home`.

- Provenance: **Implemented**.

## Page access

**BR-011 — Home and users are for an authenticated session.** When `status === "unauthenticated"`, the page calls `Router.replace("/")`.

- Provenance: **Implemented**.
- The check is a client effect. The pages are not blocked by Next.js middleware. **Inferred:** a request can still download the page shell before the redirect.

**BR-012 — Other session states show "loading".** Only `status === "authenticated"` renders the welcome content. The string `loading` is the fallback, including while `status` is `"loading"`.

- Provenance: **Implemented**.

**BR-013 — Sign-out is available on home.** The button calls `signOut()` with no options.

- Provenance: **Implemented**.

**BR-014 — These routes do not require a session.** `/`, `/auth/login`, `/signup`, `/forgotpassword`, `/landing`, and `/api/hello` do not call `useSession` or a server auth helper.

- Provenance: **Implemented**.

**BR-015 — The old `/login` route is gone.** `pages/login/index.tsx` was removed in `dc7d03c`.

- Provenance: **Implemented**.

## Signup and reset

**BR-016 — Signup does not create an account.** `onSubmit` logs `values`. The text fields are not connected to Formik, so the logged object stays at the initial empty strings. There is no request and no persistence.

- Provenance: **Implemented**.

**BR-017 — Confirm password is not a rule.** `confirmPassword: ""` is an initial Formik value. There is no field and no comparison.

- Provenance: **Implemented** absence. **Inferred:** a confirm-password rule was started and not finished.

**BR-018 — Reset password does not reset a password.** The button handler logs `"sent email"`. The email input is not read.

- Provenance: **Implemented**.

## Presentation rules visible in the UI

**BR-019 — Product name on the landing screen.** The heading is "Welcome To Silicon React".

- Provenance: **Implemented** (`pages/landing/index.tsx`). This heading is not on `/` after the routing change.

**BR-020 — Copyright credit.** Login, signup, and forgot-password show "Copyright @ Silicon Overdrive" plus the current year, linking to `https://www.overdrive.co.za/`.

- Provenance: **Implemented**. The wording "Copyright @" is the string in the component.

**BR-021 — Document language is English.** `<Html lang="en">`.

- Provenance: **Implemented**.

## What is not a rule

- No password policy beyond BR-007.
- No account lockout, rate limit, captcha, or second factor.
- No tenant, company, or permission matrix.
- No rule that signup fields must match the login validator. Signup does not use `login_validate`.
- The MUI `required` props on signup and forgot-password fields are present in the JSX. Browser-native required behaviour was not executed in this investigation. Do not treat it as a tested rule.

## Human confirmation

- Confirm that BR-001 is a stub and must not be treated as the real authentication policy.
- Confirm whether BR-003's admin role and the two different emails were placeholders.
- Confirm whether signup, password reset, and the users page are still wanted. The code does not implement them, and the only plan text is the commit message "still to populate" on the users page.
